@phnx-labs/agents-cli 1.22.47 → 1.22.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/CHANGELOG.md +503 -17
  2. package/README.md +76 -32
  3. package/dist/bootstrap.js +4 -2
  4. package/dist/cli/command-registry.d.ts +1 -0
  5. package/dist/cli/command-registry.js +2 -0
  6. package/dist/commands/accounts.d.ts +58 -0
  7. package/dist/commands/accounts.js +201 -39
  8. package/dist/commands/artifacts.js +7 -6
  9. package/dist/commands/attach.js +1 -1
  10. package/dist/commands/browser.js +501 -103
  11. package/dist/commands/config.d.ts +0 -1
  12. package/dist/commands/config.js +0 -20
  13. package/dist/commands/daemon-test-harness.d.ts +42 -0
  14. package/dist/commands/daemon-test-harness.js +90 -0
  15. package/dist/commands/daemon.d.ts +21 -0
  16. package/dist/commands/daemon.js +147 -12
  17. package/dist/commands/device-config-test-harness.d.ts +11 -0
  18. package/dist/commands/device-config-test-harness.js +59 -0
  19. package/dist/commands/exec.js +76 -16
  20. package/dist/commands/focus.d.ts +14 -0
  21. package/dist/commands/focus.js +48 -5
  22. package/dist/commands/go.d.ts +3 -0
  23. package/dist/commands/go.js +16 -3
  24. package/dist/commands/inspect.js +2 -2
  25. package/dist/commands/lease.d.ts +1 -1
  26. package/dist/commands/lease.js +4 -3
  27. package/dist/commands/mailboxes.js +4 -3
  28. package/dist/commands/menubar.js +11 -4
  29. package/dist/commands/projects.d.ts +16 -1
  30. package/dist/commands/projects.js +58 -64
  31. package/dist/commands/resume.js +1 -1
  32. package/dist/commands/route.js +4 -4
  33. package/dist/commands/routines.js +3 -2
  34. package/dist/commands/run-broadcast.d.ts +1 -1
  35. package/dist/commands/run-broadcast.js +1 -1
  36. package/dist/commands/sessions-picker.d.ts +22 -0
  37. package/dist/commands/sessions-picker.js +48 -9
  38. package/dist/commands/sessions-trace.js +1 -1
  39. package/dist/commands/sessions.js +1 -0
  40. package/dist/commands/setup-secrets.js +23 -0
  41. package/dist/commands/share.d.ts +20 -5
  42. package/dist/commands/share.js +158 -53
  43. package/dist/commands/ssh.js +54 -7
  44. package/dist/commands/teams.d.ts +12 -0
  45. package/dist/commands/teams.js +44 -67
  46. package/dist/commands/traces.d.ts +2 -0
  47. package/dist/commands/traces.js +188 -0
  48. package/dist/commands/view.d.ts +1 -1
  49. package/dist/commands/view.js +17 -34
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.js +5 -0
  52. package/dist/lib/account-provider-registry.d.ts +9 -0
  53. package/dist/lib/account-provider-registry.js +20 -0
  54. package/dist/lib/accounting/account-pool-collect.d.ts +34 -0
  55. package/dist/lib/accounting/account-pool-collect.js +71 -0
  56. package/dist/lib/accounting/account-pool.d.ts +46 -0
  57. package/dist/lib/accounting/account-pool.js +33 -0
  58. package/dist/lib/accounting/capacity.d.ts +24 -0
  59. package/dist/lib/accounting/capacity.js +30 -0
  60. package/dist/lib/accounting/rotate.d.ts +11 -18
  61. package/dist/lib/accounting/rotate.js +6 -24
  62. package/dist/lib/accounting/usage.d.ts +14 -3
  63. package/dist/lib/accounting/usage.js +64 -18
  64. package/dist/lib/agent-spec/agents.js +11 -9
  65. package/dist/lib/browser/drivers/ssh.d.ts +16 -2
  66. package/dist/lib/browser/drivers/ssh.js +36 -9
  67. package/dist/lib/browser/ipc.js +8 -3
  68. package/dist/lib/browser/profiles.d.ts +35 -101
  69. package/dist/lib/browser/profiles.js +130 -301
  70. package/dist/lib/browser/registry.d.ts +39 -0
  71. package/dist/lib/browser/registry.js +149 -0
  72. package/dist/lib/browser/remote-control.d.ts +8 -6
  73. package/dist/lib/browser/remote-control.js +8 -6
  74. package/dist/lib/browser/resolve-target.d.ts +68 -0
  75. package/dist/lib/browser/resolve-target.js +250 -0
  76. package/dist/lib/browser/runtime-state.d.ts +40 -16
  77. package/dist/lib/browser/runtime-state.js +92 -25
  78. package/dist/lib/browser/service.d.ts +28 -9
  79. package/dist/lib/browser/service.js +139 -62
  80. package/dist/lib/browser/task-index.d.ts +70 -0
  81. package/dist/lib/browser/task-index.js +180 -0
  82. package/dist/lib/byok-usage.js +2 -2
  83. package/dist/lib/claude-statusline.d.ts +29 -0
  84. package/dist/lib/claude-statusline.js +139 -0
  85. package/dist/lib/cloud/host.d.ts +1 -1
  86. package/dist/lib/cloud/host.js +1 -1
  87. package/dist/lib/cloud/rush.js +1 -1
  88. package/dist/lib/computer/computer-rpc.js +2 -2
  89. package/dist/lib/computer/download.d.ts +15 -15
  90. package/dist/lib/computer/download.js +35 -98
  91. package/dist/lib/computer/ssh-tunnel.d.ts +0 -3
  92. package/dist/lib/computer/ssh-tunnel.js +12 -22
  93. package/dist/lib/config-keys.d.ts +2 -8
  94. package/dist/lib/config-keys.js +2 -13
  95. package/dist/lib/crabbox/cli.d.ts +1 -1
  96. package/dist/lib/crabbox/cli.js +2 -2
  97. package/dist/lib/crabbox/lease.d.ts +9 -0
  98. package/dist/lib/crabbox/lease.js +70 -15
  99. package/dist/lib/crabbox/runtimes.js +1 -1
  100. package/dist/lib/daemon/account-state-daemon-service.d.ts +16 -0
  101. package/dist/lib/daemon/account-state-daemon-service.js +26 -0
  102. package/dist/lib/daemon/browser-ipc-service.d.ts +20 -0
  103. package/dist/lib/daemon/browser-ipc-service.js +46 -0
  104. package/dist/lib/daemon/daemon.d.ts +3 -0
  105. package/dist/lib/daemon/daemon.js +212 -444
  106. package/dist/lib/daemon/device-probe-service.d.ts +26 -0
  107. package/dist/lib/daemon/device-probe-service.js +47 -0
  108. package/dist/lib/daemon/keychain-reap-service.d.ts +17 -0
  109. package/dist/lib/daemon/keychain-reap-service.js +32 -0
  110. package/dist/lib/daemon/monitor-engine-service.d.ts +22 -0
  111. package/dist/lib/daemon/monitor-engine-service.js +29 -0
  112. package/dist/lib/daemon/secrets-broker-service.d.ts +20 -0
  113. package/dist/lib/daemon/secrets-broker-service.js +66 -0
  114. package/dist/lib/daemon/self-heal-service.d.ts +27 -0
  115. package/dist/lib/daemon/self-heal-service.js +48 -0
  116. package/dist/lib/daemon/service.d.ts +102 -0
  117. package/dist/lib/daemon/service.js +98 -0
  118. package/dist/lib/daemon/session-index-service.d.ts +22 -0
  119. package/dist/lib/daemon/session-index-service.js +40 -0
  120. package/dist/lib/daemon/state-dir-check-service.d.ts +43 -0
  121. package/dist/lib/daemon/state-dir-check-service.js +63 -0
  122. package/dist/lib/daemon/supervisor.d.ts +87 -0
  123. package/dist/lib/daemon/supervisor.js +298 -0
  124. package/dist/lib/daemon/watchdog-service.d.ts +19 -0
  125. package/dist/lib/daemon/watchdog-service.js +40 -0
  126. package/dist/lib/daemon-health.d.ts +15 -0
  127. package/dist/lib/daemon-health.js +29 -5
  128. package/dist/lib/daemon-services.d.ts +8 -1
  129. package/dist/lib/daemon-services.js +55 -0
  130. package/dist/lib/daemon-ticks.d.ts +13 -2
  131. package/dist/lib/daemon-ticks.js +20 -18
  132. package/dist/lib/device-config.d.ts +0 -2
  133. package/dist/lib/device-config.js +1 -23
  134. package/dist/lib/devices/registry.d.ts +1 -1
  135. package/dist/lib/devices/registry.js +1 -1
  136. package/dist/lib/devices/stats-cache.d.ts +20 -0
  137. package/dist/lib/devices/stats-cache.js +49 -5
  138. package/dist/lib/devices/worker-pick.d.ts +48 -0
  139. package/dist/lib/devices/worker-pick.js +113 -0
  140. package/dist/lib/exec.d.ts +67 -13
  141. package/dist/lib/exec.js +85 -29
  142. package/dist/lib/harness/adapters/cursor.js +8 -11
  143. package/dist/lib/helper-download.d.ts +108 -0
  144. package/dist/lib/helper-download.js +194 -0
  145. package/dist/lib/helper-versions.d.ts +52 -0
  146. package/dist/lib/helper-versions.js +58 -0
  147. package/dist/lib/hooks/cache.js +11 -0
  148. package/dist/lib/hooks/install.js +2 -2
  149. package/dist/lib/hosts/credentials.d.ts +1 -1
  150. package/dist/lib/hosts/credentials.js +1 -1
  151. package/dist/lib/hosts/dispatch.d.ts +7 -1
  152. package/dist/lib/hosts/dispatch.js +24 -5
  153. package/dist/lib/hosts/passthrough.d.ts +8 -15
  154. package/dist/lib/hosts/passthrough.js +19 -16
  155. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  156. package/dist/lib/hosts/providers/devices.js +1 -1
  157. package/dist/lib/hosts/reconnect.d.ts +179 -21
  158. package/dist/lib/hosts/reconnect.js +266 -45
  159. package/dist/lib/installations/migrate.d.ts +4 -5
  160. package/dist/lib/installations/migrate.js +6 -7
  161. package/dist/lib/installations/shims.d.ts +1 -1
  162. package/dist/lib/installations/shims.js +23 -13
  163. package/dist/lib/installations/store.js +6 -3
  164. package/dist/lib/installations/versions.js +73 -48
  165. package/dist/lib/linear-autoclose.d.ts +1 -1
  166. package/dist/lib/linear-autoclose.js +1 -1
  167. package/dist/lib/loop.d.ts +2 -2
  168. package/dist/lib/loop.js +1 -1
  169. package/dist/lib/menubar/download-menubar.d.ts +47 -0
  170. package/dist/lib/menubar/download-menubar.js +60 -0
  171. package/dist/lib/menubar/install-menubar.d.ts +31 -7
  172. package/dist/lib/menubar/install-menubar.js +79 -21
  173. package/dist/lib/menubar/notify-desktop.d.ts +3 -3
  174. package/dist/lib/menubar/notify-desktop.js +6 -6
  175. package/dist/lib/model-tiers.d.ts +1 -1
  176. package/dist/lib/project-probe.d.ts +1 -1
  177. package/dist/lib/project-probe.js +1 -1
  178. package/dist/lib/project-pull.d.ts +1 -1
  179. package/dist/lib/project-pull.js +2 -2
  180. package/dist/lib/projects.d.ts +1 -1
  181. package/dist/lib/projects.js +1 -1
  182. package/dist/lib/sandbox.js +6 -7
  183. package/dist/lib/secrets/download-keychain.d.ts +47 -0
  184. package/dist/lib/secrets/download-keychain.js +70 -0
  185. package/dist/lib/secrets/install-helper.d.ts +20 -1
  186. package/dist/lib/secrets/install-helper.js +44 -3
  187. package/dist/lib/session/active.js +17 -1
  188. package/dist/lib/session/db.d.ts +11 -1
  189. package/dist/lib/session/db.js +138 -6
  190. package/dist/lib/session/discover.d.ts +21 -1
  191. package/dist/lib/session/discover.js +33 -5
  192. package/dist/lib/session/highlights.d.ts +49 -1
  193. package/dist/lib/session/highlights.js +95 -0
  194. package/dist/lib/session/host-link.d.ts +16 -2
  195. package/dist/lib/session/host-link.js +7 -1
  196. package/dist/lib/session/parse.js +33 -1
  197. package/dist/lib/session/remote/remote-list.d.ts +9 -0
  198. package/dist/lib/session/remote/remote-list.js +19 -2
  199. package/dist/lib/session/remote/watch.js +11 -2
  200. package/dist/lib/session/session-cache.d.ts +53 -0
  201. package/dist/lib/session/session-cache.js +88 -0
  202. package/dist/lib/session/state.js +1 -1
  203. package/dist/lib/session/tool-calls.d.ts +2 -0
  204. package/dist/lib/session/tool-calls.js +1 -1
  205. package/dist/lib/session/trajectory-html.d.ts +5 -1
  206. package/dist/lib/session/trajectory-html.js +42 -22
  207. package/dist/lib/session/trajectory-text.js +9 -2
  208. package/dist/lib/session/trajectory.js +53 -4
  209. package/dist/lib/session/types.d.ts +15 -0
  210. package/dist/lib/sha256-asset.d.ts +26 -0
  211. package/dist/lib/sha256-asset.js +41 -0
  212. package/dist/lib/share/backend.d.ts +95 -0
  213. package/dist/lib/share/backend.js +139 -0
  214. package/dist/lib/share/delete.d.ts +6 -2
  215. package/dist/lib/share/delete.js +8 -9
  216. package/dist/lib/share/html.d.ts +22 -0
  217. package/dist/lib/share/html.js +88 -0
  218. package/dist/lib/share/provision.d.ts +18 -4
  219. package/dist/lib/share/provision.js +38 -4
  220. package/dist/lib/share/publish.d.ts +44 -15
  221. package/dist/lib/share/publish.js +58 -26
  222. package/dist/lib/share/worker-template.js +402 -25
  223. package/dist/lib/sqlite.js +16 -3
  224. package/dist/lib/ssh-exec.d.ts +65 -0
  225. package/dist/lib/ssh-exec.js +120 -4
  226. package/dist/lib/startup/command-registry.js +1 -1
  227. package/dist/lib/startup/dev-build.js +3 -3
  228. package/dist/lib/state.d.ts +1 -1
  229. package/dist/lib/state.js +7 -3
  230. package/dist/lib/subagents-registry.js +1 -1
  231. package/dist/lib/teams/agents.d.ts +14 -12
  232. package/dist/lib/teams/agents.js +188 -73
  233. package/dist/lib/teams/api.d.ts +6 -1
  234. package/dist/lib/teams/api.js +2 -0
  235. package/dist/lib/teams/scheduler.d.ts +7 -0
  236. package/dist/lib/teams/scheduler.js +26 -8
  237. package/dist/lib/terminal/index.d.ts +1 -1
  238. package/dist/lib/terminal/types.d.ts +1 -1
  239. package/dist/lib/terminal/types.js +1 -1
  240. package/dist/lib/tmux/orphan-reap.js +1 -1
  241. package/dist/lib/tmux/session.js +31 -0
  242. package/dist/lib/traces/backend.d.ts +29 -0
  243. package/dist/lib/traces/backend.js +46 -0
  244. package/dist/lib/traces/classify.d.ts +52 -0
  245. package/dist/lib/traces/classify.js +72 -0
  246. package/dist/lib/traces/config.d.ts +10 -0
  247. package/dist/lib/traces/config.js +2 -0
  248. package/dist/lib/traces/provision.d.ts +19 -0
  249. package/dist/lib/traces/provision.js +30 -0
  250. package/dist/lib/traces/sync.d.ts +150 -0
  251. package/dist/lib/traces/sync.js +459 -0
  252. package/dist/lib/traces/worker-template.d.ts +4 -0
  253. package/dist/lib/traces/worker-template.js +159 -0
  254. package/dist/lib/types.d.ts +18 -19
  255. package/dist/lib/types.js +14 -0
  256. package/dist/lib/usage-refresh.d.ts +1 -1
  257. package/dist/lib/usage-refresh.js +11 -8
  258. package/dist/lib/workflows.d.ts +1 -1
  259. package/package.json +4 -6
  260. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  261. package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +0 -24
  262. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  263. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  264. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +0 -128
  265. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  266. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -26
  267. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  268. package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
  269. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +0 -135
  270. package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
  271. package/dist/lib/usage-fleet.d.ts +0 -32
  272. package/dist/lib/usage-fleet.js +0 -125
@@ -34,7 +34,7 @@ import { discoverPermissionGroups, getActivePermissionPresetName, readPermission
34
34
  import { parseMcpConfigForScan, isProjectMcpTrusted } from '../mcp.js';
35
35
  import { createVersionedAlias, removeVersionedAlias, switchConfigSymlink, getConfigSymlinkVersion, ensureClaudeInsideSymlink, assertIsolationBoundary, isIsolationProtected, } from './shims.js';
36
36
  import { importInstallScriptBinary } from '../import.js';
37
- import { createInstallation, getBinaryPath, getCliVersionFromPath, getGlobalDefault, getIsolatedDefault, getLiveVersion, getVersionDir, getVersionHomePath, invalidateInstalledVersionsCache, invalidateLiveVersionCache, isGlobalBinaryAgent, isVersionInstalled, isVersionIsolated, listInstalledVersions, pickCanonicalGlobalBinaryVersion, resolveVersion, } from './store.js';
37
+ import { createInstallation, getBinaryPath, getCliVersionFromPath, getGlobalDefault, getIsolatedDefault, getLiveVersion, getVersionDir, getVersionHomePath, invalidateInstalledVersionsCache, invalidateLiveVersionCache, isGlobalBinaryAgent, isVersionInstalled, isVersionIsolated, listInstalledVersions, pickCanonicalGlobalBinaryVersion, resolveGrokFallbackBinary, resolveVersion, } from './store.js';
38
38
  export * from './store.js';
39
39
  import { INSTALLATION_RECORD_FILE } from './types.js';
40
40
  import { composeWin32CommandLine } from '../platform/index.js';
@@ -52,6 +52,7 @@ import { getWriter, getDetector } from '../staleness/registry.js';
52
52
  import { syncMemoryToVersionHome } from '../memory.js';
53
53
  import { listPluginSkillNames, resolveCommandSource, resolveSkillSource } from '../staleness/writers/sources.js';
54
54
  import { syncProjectResourcesToAgent } from '../project-resources.js';
55
+ import { installClaudeStatusLine } from '../claude-statusline.js';
55
56
  /** Promisified exec for running shell commands. */
56
57
  const execAsync = promisify(exec);
57
58
  const execFileAsync = promisify(execFile);
@@ -120,6 +121,17 @@ function sourceMapFromWorkflows(cwd) {
120
121
  .filter(d => d.isDirectory() && fs.existsSync(path.join(dir, d.name, 'WORKFLOW.md')))
121
122
  .map(d => d.name));
122
123
  }
124
+ // A plugin is a directory whose marker is `.claude-plugin/plugin.json`. Attribute
125
+ // each to the layer it actually resolves from (system / user / project / extra) —
126
+ // the same first-wins resolution the plugins staleness checker uses. Hardcoding
127
+ // 'user' here made a `system:*` selection expand to zero plugins, so
128
+ // `agents sync <agent> system` silently skipped system-layer plugins like `swarm`
129
+ // (RUSH-3207).
130
+ function sourceMapFromPlugins(cwd) {
131
+ return sourceMapFromLayeredDirectory(cwd, ['plugins'], (dir) => fs.readdirSync(dir, { withFileTypes: true })
132
+ .filter(d => d.isDirectory() && fs.existsSync(path.join(dir, d.name, '.claude-plugin', 'plugin.json')))
133
+ .map(d => d.name));
134
+ }
123
135
  function sourceMapFromPluginSkills(plugins, activePluginNames, cwd) {
124
136
  const sourceRank = new Map([
125
137
  ['user', 0],
@@ -1020,9 +1032,9 @@ export function setIsolatedDefault(agent, version) {
1020
1032
  /**
1021
1033
  * Move any `grok-<installedVersion>-...` binary (and its generic platform
1022
1034
  * copy) found directly under `sourceDownloads` into `targetDownloads`.
1023
- * Returns true if the versioned binary was moved.
1035
+ * Returns true if the versioned binary was transferred.
1024
1036
  */
1025
- function tryMoveGrokDownloads(sourceDownloads, targetDownloads, installedVersion) {
1037
+ function transferGrokDownloads(sourceDownloads, targetDownloads, copy) {
1026
1038
  if (!fs.existsSync(sourceDownloads))
1027
1039
  return false;
1028
1040
  if (path.resolve(sourceDownloads) === path.resolve(targetDownloads))
@@ -1030,42 +1042,36 @@ function tryMoveGrokDownloads(sourceDownloads, targetDownloads, installedVersion
1030
1042
  const entries = fs.readdirSync(sourceDownloads).filter((e) => e.startsWith('grok-'));
1031
1043
  if (entries.length === 0)
1032
1044
  return false;
1033
- const escapedVersion = installedVersion.replace(/\./g, '\\.');
1034
- const versionedPattern = new RegExp(`^grok-${escapedVersion}-`);
1035
- const movedPaths = [];
1036
- // Move the versioned binary first — only create the target dir once we
1037
- // know there is something to move into it.
1038
- for (const entry of entries) {
1039
- if (!versionedPattern.test(entry))
1040
- continue;
1041
- const src = path.join(sourceDownloads, entry);
1042
- const dst = path.join(targetDownloads, entry);
1043
- if (fs.existsSync(dst))
1044
- continue;
1045
- try {
1046
- fs.mkdirSync(targetDownloads, { recursive: true });
1047
- fs.renameSync(src, dst);
1048
- movedPaths.push(dst);
1049
- }
1050
- catch {
1051
- /* ignore per-file failures */
1052
- }
1045
+ const realBinary = resolveGrokFallbackBinary(sourceDownloads);
1046
+ if (!realBinary)
1047
+ return false;
1048
+ const transferred = path.join(targetDownloads, path.basename(realBinary));
1049
+ try {
1050
+ fs.mkdirSync(targetDownloads, { recursive: true });
1051
+ if (copy)
1052
+ fs.copyFileSync(realBinary, transferred);
1053
+ else
1054
+ fs.renameSync(realBinary, transferred);
1053
1055
  }
1054
- if (movedPaths.length === 0)
1056
+ catch {
1055
1057
  return false;
1058
+ }
1056
1059
  // The installer also creates a generic platform binary (e.g. grok-macos-aarch64)
1057
1060
  // that is a copy of the versioned binary. Move it too if its size matches.
1058
- const movedSize = fs.statSync(movedPaths[0]).size;
1061
+ const movedSize = fs.statSync(transferred).size;
1059
1062
  for (const entry of entries) {
1060
- if (versionedPattern.test(entry))
1061
- continue; // already handled
1063
+ if (entry === path.basename(realBinary))
1064
+ continue;
1062
1065
  const src = path.join(sourceDownloads, entry);
1063
1066
  const dst = path.join(targetDownloads, entry);
1064
1067
  if (fs.existsSync(dst))
1065
1068
  continue;
1066
1069
  try {
1067
1070
  if (fs.statSync(src).size === movedSize) {
1068
- fs.renameSync(src, dst);
1071
+ if (copy)
1072
+ fs.copyFileSync(src, dst);
1073
+ else
1074
+ fs.renameSync(src, dst);
1069
1075
  }
1070
1076
  }
1071
1077
  catch {
@@ -1087,7 +1093,7 @@ function tryMoveGrokDownloads(sourceDownloads, targetDownloads, installedVersion
1087
1093
  * whatever version was default at the time), sweep every other installed
1088
1094
  * grok version home for the missing file before giving up.
1089
1095
  */
1090
- function relocateGrokBinaryToVersionHome(installedVersion) {
1096
+ function relocateGrokBinaryToVersionHome(installationLabel, copyExisting) {
1091
1097
  const hostGrokLink = path.join(getHomeDir(), agentConfigDirName('grok'));
1092
1098
  let sourceDownloads;
1093
1099
  try {
@@ -1096,16 +1102,16 @@ function relocateGrokBinaryToVersionHome(installedVersion) {
1096
1102
  catch {
1097
1103
  sourceDownloads = path.join(hostGrokLink, 'downloads');
1098
1104
  }
1099
- const targetDownloads = path.join(getVersionHomePath('grok', installedVersion), agentConfigDirName('grok'), 'downloads');
1100
- if (tryMoveGrokDownloads(sourceDownloads, targetDownloads, installedVersion))
1105
+ const targetDownloads = path.join(getVersionHomePath('grok', installationLabel), agentConfigDirName('grok'), 'downloads');
1106
+ if (transferGrokDownloads(sourceDownloads, targetDownloads, copyExisting))
1101
1107
  return;
1102
1108
  for (const version of listInstalledVersions('grok')) {
1103
- if (version === installedVersion)
1109
+ if (version === installationLabel)
1104
1110
  continue;
1105
1111
  const candidate = path.join(getVersionHomePath('grok', version), agentConfigDirName('grok'), 'downloads');
1106
1112
  if (path.resolve(candidate) === path.resolve(sourceDownloads))
1107
1113
  continue; // already tried
1108
- if (tryMoveGrokDownloads(candidate, targetDownloads, installedVersion))
1114
+ if (transferGrokDownloads(candidate, targetDownloads, copyExisting))
1109
1115
  return;
1110
1116
  }
1111
1117
  }
@@ -1146,6 +1152,7 @@ async function checkGrokAccountCollision(installedVersion) {
1146
1152
  */
1147
1153
  export async function installVersion(agent, version, onProgress, opts) {
1148
1154
  const agentConfig = AGENTS[agent];
1155
+ const requestedLabel = version;
1149
1156
  if (isAgentHardDeprecated(agent)) {
1150
1157
  return { success: false, installedVersion: version, error: hardDeprecationError(agent) };
1151
1158
  }
@@ -1177,7 +1184,7 @@ export async function installVersion(agent, version, onProgress, opts) {
1177
1184
  }
1178
1185
  version = 'latest';
1179
1186
  }
1180
- let installedVersion = version;
1187
+ let releaseVersion = version;
1181
1188
  try {
1182
1189
  if (runInstaller) {
1183
1190
  const script = agentConfig.installScript.replaceAll('VERSION', version);
@@ -1206,13 +1213,19 @@ export async function installVersion(agent, version, onProgress, opts) {
1206
1213
  error: `${agentConfig.name} installed but its version could not be determined after several attempts.`,
1207
1214
  };
1208
1215
  }
1209
- installedVersion = probed;
1216
+ releaseVersion = probed;
1210
1217
  // Fold any stale literal `latest` dir from an earlier probe-failed
1211
1218
  // install into the real version so it stops shadowing `agents view`.
1212
- await reconcileStaleLatestDir(agent, installedVersion);
1219
+ await reconcileStaleLatestDir(agent, releaseVersion);
1213
1220
  }
1221
+ // Self-updating installers always fetch the current vendor release, but a
1222
+ // concrete requested token is still the stable installation/account slot.
1223
+ // Keeping the two strings separate lets several homes carry the same
1224
+ // release without sharing credentials. `latest` remains the convenient
1225
+ // release-named slot; concrete tokens remain exactly addressable.
1226
+ const installationLabel = requestedLabel === 'latest' ? releaseVersion : requestedLabel;
1214
1227
  if (agent === 'grok') {
1215
- await checkGrokAccountCollision(installedVersion);
1228
+ await checkGrokAccountCollision(installationLabel);
1216
1229
  }
1217
1230
  onProgress?.(`${agentConfig.name} installed. Setting up agents-cli version home for isolation...`);
1218
1231
  }
@@ -1221,14 +1234,15 @@ export async function installVersion(agent, version, onProgress, opts) {
1221
1234
  return { success: false, installedVersion: version, error: `${agentConfig.name} installer failed: ${err.message}` };
1222
1235
  }
1223
1236
  ensureAgentsDir();
1224
- const versionDir = getVersionDir(agent, installedVersion);
1237
+ const installationLabel = requestedLabel === 'latest' ? releaseVersion : requestedLabel;
1238
+ const versionDir = getVersionDir(agent, installationLabel);
1225
1239
  fs.mkdirSync(versionDir, { recursive: true });
1226
1240
  fs.mkdirSync(path.join(versionDir, 'home'), { recursive: true });
1227
1241
  // Grok's installer drops the binary into ~/.grok/downloads, which currently
1228
1242
  // resolves to the PREVIOUS default home. Move it into the target version home
1229
1243
  // so version isolation is correct.
1230
1244
  if (agent === 'grok') {
1231
- relocateGrokBinaryToVersionHome(installedVersion);
1245
+ relocateGrokBinaryToVersionHome(installationLabel, !runInstaller);
1232
1246
  }
1233
1247
  // Symlink the installed binary into the version's node_modules/.bin so
1234
1248
  // listInstalledVersions (which checks getBinaryPath) sees this version as
@@ -1253,26 +1267,26 @@ export async function installVersion(agent, version, onProgress, opts) {
1253
1267
  // that exec-loops forever).
1254
1268
  const installedBinary = findInPath(agentConfig.cliCommand);
1255
1269
  if (installedBinary) {
1256
- importInstallScriptBinary({ agentId: agent, npmPackage: agentConfig.npmPackage, cliCommand: agentConfig.cliCommand }, installedVersion, installedBinary, versionDir);
1270
+ importInstallScriptBinary({ agentId: agent, npmPackage: agentConfig.npmPackage, cliCommand: agentConfig.cliCommand }, installationLabel, installedBinary, versionDir);
1257
1271
  }
1258
1272
  /* If null: binary missing from PATH (install script failed silently) or
1259
1273
  only our shim is present. Leave the version dir empty so getBinaryPath
1260
1274
  correctly reports it uninstalled. */
1261
1275
  }
1262
- createVersionedAlias(agent, installedVersion);
1276
+ createVersionedAlias(agent, installationLabel);
1263
1277
  // Freeze this installation's identity. The dir name is its stable label from
1264
1278
  // here on; the release it carries is recorded separately so `agents update`
1265
1279
  // can move the release without invalidating any reference to the label.
1266
- createInstallation(agent, installedVersion, installedVersion);
1267
- const trackerInstall = await installSessionTrackerHook(agent, installedVersion);
1280
+ createInstallation(agent, installationLabel, releaseVersion);
1281
+ const trackerInstall = await installSessionTrackerHook(agent, installationLabel);
1268
1282
  if (!trackerInstall.installed && trackerInstall.error) {
1269
- console.warn(`agents: SessionStart hook not installed for ${agent}@${installedVersion}: ${trackerInstall.error}`);
1283
+ console.warn(`agents: SessionStart hook not installed for ${agent}@${installationLabel}: ${trackerInstall.error}`);
1270
1284
  }
1271
1285
  // The self-updating binary just changed on disk — drop the cached
1272
1286
  // `--version` so `agents view` reflects the freshly-installed release.
1273
1287
  invalidateLiveVersionCache(agent);
1274
- emit('version.install', { agent, version: installedVersion });
1275
- return { success: true, installedVersion };
1288
+ emit('version.install', { agent, version: installationLabel });
1289
+ return { success: true, installedVersion: installationLabel };
1276
1290
  }
1277
1291
  // Resolve the `latest`/`oldest` aliases to a concrete npm version up front so
1278
1292
  // the rest of the install path treats them as an ordinary pinned install.
@@ -2185,8 +2199,13 @@ function resourceSourceMap(kind, cwd, available) {
2185
2199
  }
2186
2200
  case 'mcp':
2187
2201
  return new Map(getScopedMcpResources(cwd).map(r => [r.name, r.scope]));
2188
- case 'plugins':
2189
- return new Map(available.plugins.map(n => [n, 'user']));
2202
+ case 'plugins': {
2203
+ const sources = sourceMapFromPlugins(cwd);
2204
+ return new Map(available.plugins.flatMap((n) => {
2205
+ const source = sources.get(n);
2206
+ return source ? [[n, source]] : [];
2207
+ }));
2208
+ }
2190
2209
  case 'workflows': {
2191
2210
  const sources = sourceMapFromWorkflows(cwd);
2192
2211
  return new Map(available.workflows.flatMap((n) => {
@@ -2359,6 +2378,12 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
2359
2378
  console.warn(`agents: SessionStart hook not installed for ${agent}@${version}: ${trackerResult.error}`);
2360
2379
  }
2361
2380
  }
2381
+ if (agent === 'claude') {
2382
+ const statusLine = installClaudeStatusLine(versionHome);
2383
+ if (statusLine.error) {
2384
+ console.warn(`agents: Claude status line not installed for ${agent}@${version}: ${statusLine.error}`);
2385
+ }
2386
+ }
2362
2387
  // Fast guard BEFORE getAvailableResources / pattern expansion /
2363
2388
  // ensureVersionResourcePatterns. Guard needs only loadManifest + isStale
2364
2389
  // (~6 ms); the work that used to sit ahead of it was ~12.5 ms of the 21.5 ms
@@ -7,7 +7,7 @@
7
7
  * routine YAML's `command:` shell script so the routine stays self-contained
8
8
  * and independent of the CLI build.
9
9
  *
10
- * @see apps/cli/routines/linear-autoclose.yml
10
+ * @see cli/routines/linear-autoclose.yml
11
11
  */
12
12
  /**
13
13
  * Subset of `gh pr view --json state,mergedAt` output that drives the
@@ -7,7 +7,7 @@
7
7
  * routine YAML's `command:` shell script so the routine stays self-contained
8
8
  * and independent of the CLI build.
9
9
  *
10
- * @see apps/cli/routines/linear-autoclose.yml
10
+ * @see cli/routines/linear-autoclose.yml
11
11
  */
12
12
  /**
13
13
  * Pure decision: returns true when the PR has been merged and its linked
@@ -6,7 +6,7 @@
6
6
  * can spawn subagents freely). Every guard — `max_iterations`, `budget`, the
7
7
  * `until: signal` condition, SIGINT/SIGTERM — lives OUTSIDE the agent, so the
8
8
  * agent cannot vote past a kill-switch (the standard answer to runaway-loop and
9
- * runaway-cost failure modes; see docs/entrypoints-and-loops.md).
9
+ * runaway-cost failure modes; see docs/execution.md).
10
10
  *
11
11
  * Structure mirrors the teams supervisor (`runSupervisor` in teams/supervisor.ts):
12
12
  * a bounded for-loop with a hard cap, a SIGINT/SIGTERM trap that flips a stop
@@ -21,7 +21,7 @@
21
21
  import type { AgentId } from './types.js';
22
22
  import type { ExecOptions } from './exec.js';
23
23
  import { type Checkpoint } from './checkpoint.js';
24
- /** Loop block config (docs/entrypoints-and-loops.md → "The loop block"). */
24
+ /** Loop block config; see docs/execution.md. */
25
25
  export interface LoopConfig {
26
26
  /** Stop condition. `signal` reads loop-signal.json; absence is fail-closed. */
27
27
  until?: 'signal';
package/dist/lib/loop.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * can spawn subagents freely). Every guard — `max_iterations`, `budget`, the
7
7
  * `until: signal` condition, SIGINT/SIGTERM — lives OUTSIDE the agent, so the
8
8
  * agent cannot vote past a kill-switch (the standard answer to runaway-loop and
9
- * runaway-cost failure modes; see docs/entrypoints-and-loops.md).
9
+ * runaway-cost failure modes; see docs/execution.md).
10
10
  *
11
11
  * Structure mirrors the teams supervisor (`runSupervisor` in teams/supervisor.ts):
12
12
  * a bounded for-loop with a hard cap, a SIGINT/SIGTERM trap that flips a stop
@@ -0,0 +1,47 @@
1
+ /**
2
+ * On-demand download + verification of the macOS menu-bar helper
3
+ * ("MenubarHelper.app").
4
+ *
5
+ * Mirrors the ComputerHelper download model (`../computer/download.ts`): the
6
+ * helper ships as a signed + notarized `.app` zipped as a GitHub release asset
7
+ * on the helper's own `menubar/v<x.y.z>` tag, NOT the CLI's tag (see
8
+ * `helper-versions.ts`). A fresh `npm i -g` machine whose tarball lacks a
9
+ * bundled copy fetches the asset for the pinned helper version, verifies its
10
+ * sha256 + code signature before install.
11
+ *
12
+ * The one difference — and the reason this is not the ComputerHelper spec — is
13
+ * the DESIGNATED-REQUIREMENT pin. macOS keys the menu bar's Accessibility (TCC)
14
+ * grant to the bundle's designated requirement (bundle id
15
+ * `com.phnx-labs.agents-menubar` + Developer ID Team `2HTP252L87`), and
16
+ * re-validates each new version against it. A downloaded bundle whose DR drops
17
+ * either pin would silently revoke the user's grant, so `MENUBAR_HELPER_SPEC`
18
+ * sets `expectedBundleId` and the shared `verifyHelperApp` enforces the DR
19
+ * before the bundle is ever installed. This matches the release-time gate in
20
+ * `scripts/verify-menubar-helper.sh`.
21
+ */
22
+ import { type HelperSpec } from '../helper-download.js';
23
+ /** The zipped `.app` release asset name. */
24
+ export declare const MENUBAR_HELPER_ASSET = "MenubarHelper.app.zip";
25
+ /** The bundle directory name once extracted. */
26
+ export declare const MENUBAR_HELPER_APP_NAME = "MenubarHelper.app";
27
+ /** The bundle id the Accessibility grant (and thus the designated requirement)
28
+ * is keyed to — the same value `install-menubar.ts`'s `SERVICE_LABEL_BASE` and
29
+ * `scripts/verify-menubar-helper.sh` pin. */
30
+ export declare const MENUBAR_HELPER_BUNDLE_ID = "com.phnx-labs.agents-menubar";
31
+ /** MenubarHelper identity + verification policy — DR-pinned (see docblock). */
32
+ export declare const MENUBAR_HELPER_SPEC: HelperSpec;
33
+ /** Release-asset URLs for the menu-bar helper zip + its checksum at `v<version>`. */
34
+ export declare function menubarHelperAssetUrls(version: string): {
35
+ zip: string;
36
+ sha256: string;
37
+ };
38
+ /** Cache dir for the downloaded menu-bar helper, one subdir per release tag. */
39
+ export declare function menubarHelperCacheDir(version: string): string;
40
+ /** Verify a menu-bar helper `.app`: codesign + Team + DR pin + notarization. */
41
+ export declare function verifyMenubarHelper(appPath: string): void;
42
+ /**
43
+ * Download the menu-bar helper release asset for `version`, verify sha256 +
44
+ * signature + DR pin, and return the path to the extracted `MenubarHelper.app`
45
+ * in the cache. A missing asset is a hard error naming the exact tag.
46
+ */
47
+ export declare function downloadMenubarHelperApp(version: string): Promise<string>;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * On-demand download + verification of the macOS menu-bar helper
3
+ * ("MenubarHelper.app").
4
+ *
5
+ * Mirrors the ComputerHelper download model (`../computer/download.ts`): the
6
+ * helper ships as a signed + notarized `.app` zipped as a GitHub release asset
7
+ * on the helper's own `menubar/v<x.y.z>` tag, NOT the CLI's tag (see
8
+ * `helper-versions.ts`). A fresh `npm i -g` machine whose tarball lacks a
9
+ * bundled copy fetches the asset for the pinned helper version, verifies its
10
+ * sha256 + code signature before install.
11
+ *
12
+ * The one difference — and the reason this is not the ComputerHelper spec — is
13
+ * the DESIGNATED-REQUIREMENT pin. macOS keys the menu bar's Accessibility (TCC)
14
+ * grant to the bundle's designated requirement (bundle id
15
+ * `com.phnx-labs.agents-menubar` + Developer ID Team `2HTP252L87`), and
16
+ * re-validates each new version against it. A downloaded bundle whose DR drops
17
+ * either pin would silently revoke the user's grant, so `MENUBAR_HELPER_SPEC`
18
+ * sets `expectedBundleId` and the shared `verifyHelperApp` enforces the DR
19
+ * before the bundle is ever installed. This matches the release-time gate in
20
+ * `scripts/verify-menubar-helper.sh`.
21
+ */
22
+ import { EXPECTED_TEAM_ID, downloadHelperApp, helperAssetUrls, helperCacheDir, verifyHelperApp, } from '../helper-download.js';
23
+ /** The zipped `.app` release asset name. */
24
+ export const MENUBAR_HELPER_ASSET = 'MenubarHelper.app.zip';
25
+ /** The bundle directory name once extracted. */
26
+ export const MENUBAR_HELPER_APP_NAME = 'MenubarHelper.app';
27
+ /** The bundle id the Accessibility grant (and thus the designated requirement)
28
+ * is keyed to — the same value `install-menubar.ts`'s `SERVICE_LABEL_BASE` and
29
+ * `scripts/verify-menubar-helper.sh` pin. */
30
+ export const MENUBAR_HELPER_BUNDLE_ID = 'com.phnx-labs.agents-menubar';
31
+ /** MenubarHelper identity + verification policy — DR-pinned (see docblock). */
32
+ export const MENUBAR_HELPER_SPEC = {
33
+ helper: 'menubar',
34
+ assetName: MENUBAR_HELPER_ASSET,
35
+ appName: MENUBAR_HELPER_APP_NAME,
36
+ cacheSubdir: ['menubar', 'mac-helper'],
37
+ expectedTeamId: EXPECTED_TEAM_ID,
38
+ expectedBundleId: MENUBAR_HELPER_BUNDLE_ID,
39
+ localBuildHint: 'menubar/scripts/build.sh release, then cp -R menubar/dist/MenubarHelper.app bin/MenubarHelper.app',
40
+ };
41
+ /** Release-asset URLs for the menu-bar helper zip + its checksum at `v<version>`. */
42
+ export function menubarHelperAssetUrls(version) {
43
+ return helperAssetUrls(MENUBAR_HELPER_SPEC, version);
44
+ }
45
+ /** Cache dir for the downloaded menu-bar helper, one subdir per release tag. */
46
+ export function menubarHelperCacheDir(version) {
47
+ return helperCacheDir(MENUBAR_HELPER_SPEC, version);
48
+ }
49
+ /** Verify a menu-bar helper `.app`: codesign + Team + DR pin + notarization. */
50
+ export function verifyMenubarHelper(appPath) {
51
+ verifyHelperApp(appPath, MENUBAR_HELPER_SPEC);
52
+ }
53
+ /**
54
+ * Download the menu-bar helper release asset for `version`, verify sha256 +
55
+ * signature + DR pin, and return the path to the extracted `MenubarHelper.app`
56
+ * in the cache. A missing asset is a hard error naming the exact tag.
57
+ */
58
+ export function downloadMenubarHelperApp(version) {
59
+ return downloadHelperApp(MENUBAR_HELPER_SPEC, version);
60
+ }
@@ -14,6 +14,20 @@
14
14
  * migration (`installMenubarLaunchAgent` in migrate.ts) honors, so a disabled
15
15
  * menu bar never silently comes back on the next release.
16
16
  */
17
+ /**
18
+ * The bundled executable's basename (RUSH-3101) — what launchd execs directly
19
+ * inside `Contents/MacOS/`, bypassing LaunchServices name resolution. Before
20
+ * this it was `MenubarHelper`, so that raw Mach-O basename is exactly what
21
+ * macOS showed in System Settings > Privacy & Security > Accessibility and in
22
+ * the "would like to control this computer" prompt. Renaming this constant
23
+ * alone does NOT touch the bundle id, Team ID, or designated requirement
24
+ * (`SERVICE_LABEL_BASE`, `MENUBAR_HELPER_BUNDLE_ID` in download-menubar.ts) —
25
+ * those are what keep the existing Accessibility grant alive across upgrades.
26
+ * Every basename-matching check reads this constant rather than re-deriving
27
+ * the string; the Swift side has its own equal in
28
+ * `menubar/Sources/MenubarHelper/HelperIdentity.swift`.
29
+ */
30
+ export declare const MENUBAR_HELPER_EXECUTABLE_NAME = "AGI Menu";
17
31
  /**
18
32
  * launchd Label for this process's helper — the production identifier for a
19
33
  * real invocation, namespaced under a redirected HOME (RUSH-2639). launchd
@@ -22,9 +36,9 @@
22
36
  */
23
37
  export declare function serviceLabel(): string;
24
38
  /**
25
- * Absolute path to the installed MenubarHelper executable if it exists on disk,
26
- * else null. The desktop notifier (notify-desktop.ts) routes daemon
27
- * notifications through this one-shot (`MenubarHelper --notify ...`) so they
39
+ * Absolute path to the installed menu-bar helper executable if it exists on
40
+ * disk, else null. The desktop notifier (notify-desktop.ts) routes daemon
41
+ * notifications through this one-shot (`"AGI Menu" --notify ...`) so they
28
42
  * carry the agents-cli mark rather than the generic osascript icon. Null on
29
43
  * non-darwin or when the helper is not installed (menu bar disabled, a Linux
30
44
  * package, or a dev checkout without a built bundle).
@@ -61,6 +75,7 @@ export declare function hasDeveloperIdSignature(appPath: string): boolean;
61
75
  */
62
76
  export declare function ensureMenubarAppInstalled(opts?: {
63
77
  forceReinstall?: boolean;
78
+ sourceAppPath?: string;
64
79
  }): string | null;
65
80
  export declare function generateServicePlist(execPath: string): string;
66
81
  /**
@@ -106,11 +121,20 @@ export declare function restartMenubarHelperAfterSwap(uid: number, ownProcesses:
106
121
  * Install + start the menu-bar helper as a launchd user service (idempotent).
107
122
  * Clears the sticky opt-out, installs the .app, writes the plist, and
108
123
  * bootstraps it into the GUI domain. Returns false on non-darwin or when no
109
- * helper bundle ships with this install.
124
+ * helper bundle can be resolved for this install.
125
+ *
126
+ * ASYNC and download-capable: this is the EXPLICIT user-initiated path
127
+ * (`agents menubar enable`). When no bundled/local `.app` ships (a fresh
128
+ * `npm i -g` machine whose tarball lacks the bundle), it fetches the signed +
129
+ * notarized release asset for the running CLI version — verified (sha256 +
130
+ * codesign + Team + designated-requirement pin + notarization) before install
131
+ * — and starts the service from that cached copy. The startup self-heal never
132
+ * routes here: it calls `startMenubarServiceFromSource` and stays sync +
133
+ * network-free, no-opping when no local source exists.
110
134
  */
111
135
  export declare function enableMenubarService(opts?: {
112
136
  clearOptOut?: boolean;
113
- }): boolean;
137
+ }): Promise<boolean>;
114
138
  /**
115
139
  * Pure staleness decision (no I/O) so the truth table is unit-testable. The
116
140
  * installed service is stale when the helper binary is gone, or when it was
@@ -296,7 +320,7 @@ export declare function processesToEnd(status: Pick<MenubarStatus, 'instances' |
296
320
  * 4. login item — write the plist (RunAtLoad + KeepAlive) and bootstrap it
297
321
  * 5. single — verify exactly one helper came back up
298
322
  */
299
- export declare function runMenubarSetup(): SetupResult;
323
+ export declare function runMenubarSetup(): Promise<SetupResult>;
300
324
  /** A live MenubarHelper process: its pid and the executable it is running. */
301
325
  export interface MenubarProcess {
302
326
  pid: number;
@@ -320,7 +344,7 @@ export interface MenubarProcess {
320
344
  *
321
345
  * Identity comes from `comm` (the resolved executable), never from a substring
322
346
  * of the command line: matching the latter flags any shell that merely mentions
323
- * MenubarHelper. `command` is consulted only to drop `--notify` one-shots.
347
+ * the helper's name. `command` is consulted only to drop `--notify` one-shots.
324
348
  */
325
349
  export declare function classifyMenubarProcesses(commOutput: string, commandOutput: string, installedExec: string): {
326
350
  own: MenubarProcess[];