diff --git a/agterm/Info.plist b/agterm/Info.plist index 27397a45..17d851ce 100644 --- a/agterm/Info.plist +++ b/agterm/Info.plist @@ -50,18 +50,28 @@ Command-line tools you run inside agterm (for example, ffmpeg capturing video) request camera access through agterm. NSContactsUsageDescription Command-line tools you run inside agterm request access to your contacts through agterm. + NSDesktopFolderUsageDescription + Command-line tools you run inside agterm request access to your Desktop folder through agterm. + NSDocumentsFolderUsageDescription + Command-line tools you run inside agterm request access to your Documents folder through agterm. + NSDownloadsFolderUsageDescription + Command-line tools you run inside agterm request access to your Downloads folder through agterm. NSLocalNetworkUsageDescription Command-line tools you run inside agterm (for example, connecting to a .local host) request local network access through agterm. NSLocationUsageDescription Command-line tools you run inside agterm request your location through agterm. NSMicrophoneUsageDescription Command-line tools you run inside agterm (for example, voice dictation in Claude Code) request microphone access through agterm. + NSNetworkVolumesUsageDescription + Command-line tools you run inside agterm request access to files on network volumes through agterm. NSPhotoLibraryUsageDescription Command-line tools you run inside agterm (for example, osxphotos) request access to your photo library through agterm. NSRemindersFullAccessUsageDescription Command-line tools you run inside agterm request access to your reminders through agterm. NSRemindersUsageDescription Command-line tools you run inside agterm request access to your reminders through agterm. + NSRemovableVolumesUsageDescription + Command-line tools you run inside agterm request access to files on removable volumes through agterm. NSSpeechRecognitionUsageDescription Command-line tools you run inside agterm request speech recognition through agterm. NSSystemAdministrationUsageDescription diff --git a/agtermCore/Sources/agtermCore/AgentHooksInstall.swift b/agtermCore/Sources/agtermCore/AgentHooksInstall.swift index 3dc8bbf3..97f6a797 100644 --- a/agtermCore/Sources/agtermCore/AgentHooksInstall.swift +++ b/agtermCore/Sources/agtermCore/AgentHooksInstall.swift @@ -15,7 +15,7 @@ public enum AgentHooksInstall { /// The bundled Pi extension's path relative to the agent-status package, and its destination filename. public static let piExtensionRelativePath = "pi/agterm-status.ts" - public static let piExtensionName = "agterm-status.ts" + static let piExtensionName = "agterm-status.ts" /// Ownership sentinel in the bundled Pi extension: a reinstall refuses to overwrite an unmarked same-named /// extension, preserving a user-authored integration. @@ -23,7 +23,7 @@ public enum AgentHooksInstall { /// The bundled OpenCode plugin's path relative to the agent-status package, and its destination filename. public static let opencodePluginRelativePath = "opencode/agterm-status.js" - public static let opencodePluginName = "agterm-status.js" + static let opencodePluginName = "agterm-status.js" /// Ownership sentinel in the bundled OpenCode plugin, same policy as `piExtensionMarker`. Named `*Plugin*` /// (not `*Extension*`) because OpenCode's host term is plugin — a deliberate divergence from `piExtension*`. @@ -36,8 +36,8 @@ public enum AgentHooksInstall { /// Marker lines bracketing the agterm-managed block in a shell rc file; the opening marker is also the /// idempotency probe (present → already installed). - public static let rcMarkerBegin = "# >>> agterm agent-status >>>" - public static let rcMarkerEnd = "# <<< agterm agent-status <<<" + static let rcMarkerBegin = "# >>> agterm agent-status >>>" + static let rcMarkerEnd = "# <<< agterm agent-status <<<" /// The Claude Code hook events the merge installs, paired with the state (plus flags) each maps to. /// `UserPromptSubmit` and `PostToolUse` both set `active` — the latter after every tool run, so the status @@ -64,7 +64,7 @@ public enum AgentHooksInstall { ] /// The destination directory for Pi's auto-discovered global extensions. - public static func piExtensionDirectory(home: String) -> String { + static func piExtensionDirectory(home: String) -> String { home + "/.pi/agent/extensions" } @@ -81,7 +81,7 @@ public enum AgentHooksInstall { } /// The destination directory for OpenCode's auto-discovered global plugins. - public static func opencodePluginDirectory(home: String) -> String { + static func opencodePluginDirectory(home: String) -> String { home + "/.config/opencode/plugins" } @@ -286,11 +286,11 @@ public enum AgentHooksInstall { /// the absolute wrapper-script path the installed hooks invoke (`/agterm-agent-status.sh`); the /// caller's hook entry appends the state. - public static func wrapperPath(scriptDir: String) -> String { + static func wrapperPath(scriptDir: String) -> String { scriptDir + "/" + wrapperName } - public static func codexWrapperPath(scriptDir: String) -> String { + static func codexWrapperPath(scriptDir: String) -> String { scriptDir + "/" + codexWrapperName } @@ -299,7 +299,7 @@ public enum AgentHooksInstall { /// merge declines, and nothing checks the two against each other. /// The wrapper's absolute path is baked into each command — shell-quoted (so a path with spaces stays one /// token) inside a TOML basic string — so the hook fires without the CLI on PATH. - public static func codexHooksBlock(scriptDir: String) -> String { + static func codexHooksBlock(scriptDir: String) -> String { let wrapper = shellQuote(codexWrapperPath(scriptDir: scriptDir)) return codexHooks.map { hook in """ diff --git a/agtermCore/Sources/agtermCore/ConfigPaths.swift b/agtermCore/Sources/agtermCore/ConfigPaths.swift index 6a8d16c8..9040e125 100644 --- a/agtermCore/Sources/agtermCore/ConfigPaths.swift +++ b/agtermCore/Sources/agtermCore/ConfigPaths.swift @@ -74,7 +74,7 @@ public enum ConfigPaths { # Examples: # # command "Open in Zed" cmd+shift+e open -a Zed "$AGT_SESSION_PWD" - # command "Lazygit" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --socket "$AGT_SOCKET" + # command "Lazygit" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --target "$AGT_SESSION_ID" --socket "$AGT_SOCKET" # command "Deploy" ./deploy.sh # # global-hotkey diff --git a/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift b/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift index df070b8d..55466bef 100644 --- a/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift +++ b/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift @@ -37,7 +37,7 @@ struct ConfigPathsTests { #expect(starter.contains("command \"\" [chord] ")) #expect(starter.contains("single chord OR a leader like `ctrl+a>g`")) #expect(starter.contains("command \"Open in Zed\" cmd+shift+e open -a Zed \"$AGT_SESSION_PWD\"")) - #expect(starter.contains("command \"Lazygit\" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --socket \"$AGT_SOCKET\"")) + #expect(starter.contains("command \"Lazygit\" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --target \"$AGT_SESSION_ID\" --socket \"$AGT_SOCKET\"")) #expect(starter.contains("command \"Deploy\" ./deploy.sh")) #expect(starter.contains("ctrl+shift+p")) #expect(!starter.contains("super")) diff --git a/docs/backlog/codex-wrapper-path-is-public-with-no-consumer.md b/docs/backlog/codex-wrapper-path-is-public-with-no-consumer.md deleted file mode 100644 index 98603c98..00000000 --- a/docs/backlog/codex-wrapper-path-is-public-with-no-consumer.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -worth: later -where: agtermCore/Sources/agtermCore/AgentHooksInstall.swift:293 -added: 2026-08-19 ---- -# codexWrapperPath is public with nothing outside the module calling it - -`codexWrapperPath(scriptDir:)` is `public` but its only caller is `codexHooksBlock` at `:303`, in the same -file. `internal` would serve it. Contrast `codexWrapperName` two lines up, whose `public` is earned by -`agterm/AgentHooksInstaller.swift:136`. - -Against the standing rule that visibility is private by default and exported only when used outside the -package. Nothing is broken; the cost is that a reader has to grep to learn which of the two neighbouring -symbols is an app-target contract and which is not. - -Worth doing whenever something else touches this file, and worth checking the rest of the enum's public -surface in the same pass rather than tightening one symbol alone. - -Surfaced reviewing PR #461. diff --git a/docs/backlog/no-folder-usage-strings-in-info-plist.md b/docs/backlog/no-folder-usage-strings-in-info-plist.md deleted file mode 100644 index 73d8130c..00000000 --- a/docs/backlog/no-folder-usage-strings-in-info-plist.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -worth: later -where: agterm/Info.plist:37 -added: 2026-08-20 ---- -# Info.plist declares no usage string for the protected folders - -The sixteen `NSxxxUsageDescription` strings cover the entitlement-gated services and none of the -Files & Folders family. macOS defines an optional string per protected folder — -`NSDesktopFolderUsageDescription`, `NSDocumentsFolderUsageDescription`, -`NSDownloadsFolderUsageDescription`, `NSNetworkVolumesUsageDescription`, -`NSRemovableVolumesUsageDescription` — and with none present it falls back to its own copy, measured in -`TCC.framework/Versions/A/Resources/Localizable.loctable` as -`REQUEST_ACCESS_SERVICE_kTCCServiceSystemPolicyDownloadsFolder` = `“%@” would like to access -files in your Downloads folder.` So the user is asked why agterm wants his Downloads and told nothing. - -Every other family already explains hosted-CLI responsibility in its string, so the same pattern applies: -"Command-line tools you run inside agterm may request access to your Downloads folder through agterm." -WezTerm ships two of these written for exactly that case; Ghostty, kitty and iTerm2 ship none. - -Deferred because it fixes nothing. The strings are not a gate — agterm can obtain these grants today -without them — so this repairs no denial and adds no access, and the only change is five pieces of prompt -copy. It also cannot be proven by CI, which pins the entitlement set and asserts nothing about -`Info.plist`: confirming the custom text actually renders needs a signed build and a fresh TCC state by -hand. Surfaced investigating #468, where the missing strings turned out not to be the cause. diff --git a/docs/backlog/seeded-lazygit-example-omits-target.md b/docs/backlog/seeded-lazygit-example-omits-target.md deleted file mode 100644 index 286e563e..00000000 --- a/docs/backlog/seeded-lazygit-example-omits-target.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -worth: later -where: agtermCore/Sources/agtermCore/ConfigPaths.swift:77 -added: 2026-08-20 ---- -# the seeded Lazygit example omits --target and can open its overlay elsewhere - -The starter `keymap.conf` ships: - -``` -command "Lazygit" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --socket "$AGT_SOCKET" -``` - -`TargetOptions.target` defaults to `active` (`agtermCore/Sources/agtermctlKit/Commands.swift:69`), and `active` -is resolved when the request reaches the server, not when the chord built its context. The custom command is -spawned detached and fire-and-forget (`agterm/Commands/CustomCommandRunner.swift:336`), so a session or window -switch between the keypress and delivery opens the overlay over whatever is selected by then. The command -reference already tells automated callers to pin it (`site/commands.html:379`), and a custom command has the -stable `$AGT_SESSION_ID` for exactly this. - -The fix is one flag: `--target "$AGT_SESSION_ID"`. The line is otherwise valid — `overlay open` does not -require a size flag, so omitting `--size-percent` correctly gives a full-size overlay. - -Worth doing because the `#extend` lesson now sends new users to **File ▸ Edit Keymap…**, where they read this -example next to the docs' pinned one and get two different answers. Kept out of the docs change (#PR) because -touching `ConfigPaths.swift` pulls in the full Swift gate run for a one-line seed-text improvement, and no -existing user is blocked by it. - -Found by codex while reviewing the paste lines in the `#extend` lesson.