@phnx-labs/agents-cli 1.22.83 → 1.22.85

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 (291) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +80 -53
  3. package/dist/bootstrap.d.ts +7 -6
  4. package/dist/bootstrap.js +20 -27
  5. package/dist/cli/command-registry.js +5 -1
  6. package/dist/commands/accounts.d.ts +6 -13
  7. package/dist/commands/accounts.js +330 -143
  8. package/dist/commands/apply.js +1 -1
  9. package/dist/commands/auth-mint.d.ts +7 -3
  10. package/dist/commands/auth-mint.js +21 -9
  11. package/dist/commands/auth.js +2 -3
  12. package/dist/commands/browser.js +10 -10
  13. package/dist/commands/daemon.d.ts +7 -3
  14. package/dist/commands/daemon.js +40 -25
  15. package/dist/commands/doctor.js +28 -2
  16. package/dist/commands/exec.js +87 -39
  17. package/dist/commands/fleet-capture.js +21 -2
  18. package/dist/commands/harness-wizard.js +2 -2
  19. package/dist/commands/lease.js +7 -12
  20. package/dist/commands/profiles.d.ts +2 -2
  21. package/dist/commands/profiles.js +20 -13
  22. package/dist/commands/repo.js +3 -3
  23. package/dist/commands/run-account-picker.d.ts +3 -3
  24. package/dist/commands/run-account-picker.js +29 -30
  25. package/dist/commands/secrets-passthrough.d.ts +20 -0
  26. package/dist/commands/secrets-passthrough.js +43 -0
  27. package/dist/commands/sessions-trace.d.ts +11 -0
  28. package/dist/commands/sessions-trace.js +71 -0
  29. package/dist/commands/setup-accounts.d.ts +3 -2
  30. package/dist/commands/setup-accounts.js +4 -4
  31. package/dist/commands/setup-secrets.d.ts +16 -21
  32. package/dist/commands/setup-secrets.js +43 -224
  33. package/dist/commands/ssh.js +2 -2
  34. package/dist/commands/sync.js +1 -1
  35. package/dist/commands/update.d.ts +10 -0
  36. package/dist/commands/update.js +43 -40
  37. package/dist/commands/versions.d.ts +11 -11
  38. package/dist/commands/versions.js +131 -83
  39. package/dist/commands/view.d.ts +1 -9
  40. package/dist/commands/view.js +41 -55
  41. package/dist/commands/webhook.js +5 -5
  42. package/dist/commands/workflows.js +2 -1
  43. package/dist/index.d.ts +12 -12
  44. package/dist/index.js +13 -42
  45. package/dist/lib/account-capabilities.d.ts +1 -1
  46. package/dist/lib/account-capabilities.js +1 -1
  47. package/dist/lib/account-catalog.d.ts +121 -6
  48. package/dist/lib/account-catalog.js +421 -7
  49. package/dist/lib/account-registry.d.ts +8 -30
  50. package/dist/lib/account-registry.js +36 -79
  51. package/dist/lib/account-schema.d.ts +1 -1
  52. package/dist/lib/account-schema.js +1 -1
  53. package/dist/lib/accounting/account-pool-collect.js +16 -4
  54. package/dist/lib/accounting/rotate.d.ts +20 -7
  55. package/dist/lib/accounting/rotate.js +89 -13
  56. package/dist/lib/accounting/usage.js +11 -16
  57. package/dist/lib/accounts/add.d.ts +138 -0
  58. package/dist/lib/accounts/add.js +651 -0
  59. package/dist/lib/accounts/migrate.d.ts +117 -0
  60. package/dist/lib/accounts/migrate.js +536 -0
  61. package/dist/lib/accounts/slots.d.ts +13 -0
  62. package/dist/lib/accounts/slots.js +100 -0
  63. package/dist/lib/agent-spec/agents.d.ts +16 -0
  64. package/dist/lib/agent-spec/agents.js +32 -4
  65. package/dist/lib/app-bundle-install.js +5 -4
  66. package/dist/lib/auth-health.d.ts +3 -0
  67. package/dist/lib/auth-health.js +11 -0
  68. package/dist/lib/auth-mint.d.ts +52 -16
  69. package/dist/lib/auth-mint.js +117 -39
  70. package/dist/lib/browser/chrome.d.ts +1 -1
  71. package/dist/lib/browser/chrome.js +5 -5
  72. package/dist/lib/byok-usage.js +3 -3
  73. package/dist/lib/claude-account-token.d.ts +47 -3
  74. package/dist/lib/claude-account-token.js +172 -50
  75. package/dist/lib/cloud/antigravity.js +4 -4
  76. package/dist/lib/cloud/cursor.js +4 -4
  77. package/dist/lib/crabbox/cli.d.ts +1 -1
  78. package/dist/lib/crabbox/cli.js +6 -6
  79. package/dist/lib/crabbox/runtimes.d.ts +3 -3
  80. package/dist/lib/crabbox/runtimes.js +5 -5
  81. package/dist/lib/daemon/account-state-daemon-service.d.ts +37 -1
  82. package/dist/lib/daemon/account-state-daemon-service.js +199 -3
  83. package/dist/lib/daemon/auth-sync-service.js +28 -1
  84. package/dist/lib/daemon/daemon.d.ts +6 -16
  85. package/dist/lib/daemon/daemon.js +52 -97
  86. package/dist/lib/daemon/daemon.test-fixture.d.ts +7 -9
  87. package/dist/lib/daemon/daemon.test-fixture.js +22 -40
  88. package/dist/lib/daemon/harness-update-service.d.ts +1 -1
  89. package/dist/lib/daemon/harness-update-service.js +1 -1
  90. package/dist/lib/daemon/runner.d.ts +15 -3
  91. package/dist/lib/daemon/runner.js +49 -24
  92. package/dist/lib/daemon-health.d.ts +1 -2
  93. package/dist/lib/daemon-health.js +7 -6
  94. package/dist/lib/daemon-services.d.ts +1 -1
  95. package/dist/lib/daemon-services.js +1 -11
  96. package/dist/lib/daemon-ticks.js +23 -2
  97. package/dist/lib/daemon-webhooks.d.ts +8 -7
  98. package/dist/lib/daemon-webhooks.js +10 -9
  99. package/dist/lib/device-config.js +1 -1
  100. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  101. package/dist/lib/devices/harness-inventory.d.ts +39 -0
  102. package/dist/lib/devices/harness-inventory.js +126 -4
  103. package/dist/lib/doctor-diff.js +2 -1
  104. package/dist/lib/exec-account-home.d.ts +38 -0
  105. package/dist/lib/exec-account-home.js +164 -0
  106. package/dist/lib/exec.d.ts +30 -0
  107. package/dist/lib/exec.js +101 -31
  108. package/dist/lib/feed/activity-stream.d.ts +60 -0
  109. package/dist/lib/feed/activity-stream.js +271 -0
  110. package/dist/lib/feed/activity.d.ts +7 -0
  111. package/dist/lib/feed/activity.js +10 -4
  112. package/dist/lib/feed/watch.d.ts +9 -3
  113. package/dist/lib/feed/watch.js +72 -36
  114. package/dist/lib/fleet/apply.d.ts +2 -2
  115. package/dist/lib/fleet/apply.js +4 -4
  116. package/dist/lib/fleet/auth-sync.js +4 -3
  117. package/dist/lib/fleet-shared-repo-sync.js +6 -9
  118. package/dist/lib/fleet-shared-state.d.ts +6 -0
  119. package/dist/lib/harness/adapter.d.ts +7 -7
  120. package/dist/lib/harness/adapter.js +10 -6
  121. package/dist/lib/harness/adapters/grok.js +8 -3
  122. package/dist/lib/harness/adapters/muse.js +1 -1
  123. package/dist/lib/harness/adapters/opencode.js +12 -3
  124. package/dist/lib/harness-auth-capabilities.d.ts +61 -0
  125. package/dist/lib/harness-auth-capabilities.js +52 -0
  126. package/dist/lib/helper-versions.d.ts +6 -4
  127. package/dist/lib/helper-versions.js +5 -4
  128. package/dist/lib/hosts/credential-transport.d.ts +10 -0
  129. package/dist/lib/hosts/credential-transport.js +37 -0
  130. package/dist/lib/hosts/dispatch.d.ts +7 -0
  131. package/dist/lib/hosts/dispatch.js +13 -6
  132. package/dist/lib/identity/client.d.ts +3 -3
  133. package/dist/lib/identity/client.js +3 -3
  134. package/dist/lib/installations/index.d.ts +1 -1
  135. package/dist/lib/installations/index.js +1 -1
  136. package/dist/lib/installations/migrate.js +9 -0
  137. package/dist/lib/installations/resolve.js +1 -1
  138. package/dist/lib/installations/shims.d.ts +15 -0
  139. package/dist/lib/installations/shims.js +69 -0
  140. package/dist/lib/installations/store.d.ts +43 -0
  141. package/dist/lib/installations/store.js +75 -7
  142. package/dist/lib/installations/versions.js +1 -1
  143. package/dist/lib/menubar/install-menubar.d.ts +3 -3
  144. package/dist/lib/menubar/install-menubar.js +3 -3
  145. package/dist/lib/native-accounts.d.ts +35 -0
  146. package/dist/lib/native-accounts.js +41 -0
  147. package/dist/lib/net-close.d.ts +11 -0
  148. package/dist/lib/net-close.js +25 -0
  149. package/dist/lib/openclaw-keychain.js +27 -1
  150. package/dist/lib/profiles.js +22 -9
  151. package/dist/lib/project-resources.js +1 -1
  152. package/dist/lib/reserved-stores.d.ts +53 -0
  153. package/dist/lib/reserved-stores.js +120 -0
  154. package/dist/lib/secrets-client.d.ts +191 -0
  155. package/dist/lib/secrets-client.js +710 -0
  156. package/dist/lib/secrets-policy.d.ts +222 -0
  157. package/dist/lib/secrets-policy.js +483 -0
  158. package/dist/lib/secrets-types.d.ts +188 -0
  159. package/dist/lib/secrets-types.js +24 -0
  160. package/dist/lib/service-manifest.js +3 -4
  161. package/dist/lib/session/active.d.ts +38 -4
  162. package/dist/lib/session/active.js +36 -4
  163. package/dist/lib/session/bash-command.js +10 -0
  164. package/dist/lib/session/db.d.ts +65 -2
  165. package/dist/lib/session/db.js +178 -18
  166. package/dist/lib/session/mirror.d.ts +5 -0
  167. package/dist/lib/session/mirror.js +166 -0
  168. package/dist/lib/session/parse.d.ts +49 -0
  169. package/dist/lib/session/parse.js +324 -30
  170. package/dist/lib/session/prompt.d.ts +93 -2
  171. package/dist/lib/session/prompt.js +266 -15
  172. package/dist/lib/session/remote/peer-stream.d.ts +47 -0
  173. package/dist/lib/session/remote/peer-stream.js +142 -0
  174. package/dist/lib/session/remote/watch.d.ts +1 -1
  175. package/dist/lib/session/remote/watch.js +41 -42
  176. package/dist/lib/session/session-cache.d.ts +9 -0
  177. package/dist/lib/session/session-cache.js +40 -2
  178. package/dist/lib/session/sync/config.js +2 -2
  179. package/dist/lib/session/timeline-pass.d.ts +129 -0
  180. package/dist/lib/session/timeline-pass.js +323 -0
  181. package/dist/lib/session/timeline.d.ts +182 -0
  182. package/dist/lib/session/timeline.js +636 -0
  183. package/dist/lib/session/types.d.ts +155 -1
  184. package/dist/lib/sha256-asset.d.ts +11 -16
  185. package/dist/lib/sha256-asset.js +11 -16
  186. package/dist/lib/share/config.js +14 -5
  187. package/dist/lib/signin-badge.d.ts +26 -0
  188. package/dist/lib/signin-badge.js +42 -0
  189. package/dist/lib/staleness/detectors/workflows.js +3 -105
  190. package/dist/lib/staleness/writers/workflows.js +2 -1
  191. package/dist/lib/state.d.ts +7 -4
  192. package/dist/lib/state.js +18 -7
  193. package/dist/lib/summarizer/pass.d.ts +2 -0
  194. package/dist/lib/summarizer/pass.js +14 -1
  195. package/dist/lib/summarizer/summarize.d.ts +7 -0
  196. package/dist/lib/summarizer/summarize.js +3 -0
  197. package/dist/lib/sync-umbrella.js +2 -2
  198. package/dist/lib/teams/agents.js +1 -1
  199. package/dist/lib/types.d.ts +74 -33
  200. package/dist/lib/view-types.d.ts +6 -3
  201. package/dist/lib/workflows-registry.d.ts +71 -0
  202. package/dist/lib/workflows-registry.js +280 -0
  203. package/dist/lib/workflows.d.ts +21 -21
  204. package/dist/lib/workflows.js +12 -327
  205. package/package.json +2 -3
  206. package/scripts/postinstall.js +4 -29
  207. package/dist/commands/secrets-import.d.ts +0 -18
  208. package/dist/commands/secrets-import.js +0 -74
  209. package/dist/commands/secrets-migrate.d.ts +0 -25
  210. package/dist/commands/secrets-migrate.js +0 -334
  211. package/dist/commands/secrets-rotate-passphrase.d.ts +0 -17
  212. package/dist/commands/secrets-rotate-passphrase.js +0 -96
  213. package/dist/commands/secrets-sync.d.ts +0 -11
  214. package/dist/commands/secrets-sync.js +0 -153
  215. package/dist/commands/secrets-vault.d.ts +0 -10
  216. package/dist/commands/secrets-vault.js +0 -130
  217. package/dist/commands/secrets.d.ts +0 -212
  218. package/dist/commands/secrets.js +0 -3030
  219. package/dist/lib/accounts/connect.d.ts +0 -170
  220. package/dist/lib/accounts/connect.js +0 -383
  221. package/dist/lib/daemon/keychain-reap-service.d.ts +0 -17
  222. package/dist/lib/daemon/keychain-reap-service.js +0 -32
  223. package/dist/lib/daemon/secrets-broker-service.d.ts +0 -21
  224. package/dist/lib/daemon/secrets-broker-service.js +0 -51
  225. package/dist/lib/secrets/agent.d.ts +0 -358
  226. package/dist/lib/secrets/agent.js +0 -1291
  227. package/dist/lib/secrets/audit.d.ts +0 -46
  228. package/dist/lib/secrets/audit.js +0 -101
  229. package/dist/lib/secrets/bundles.d.ts +0 -290
  230. package/dist/lib/secrets/bundles.js +0 -1547
  231. package/dist/lib/secrets/download-keychain.d.ts +0 -47
  232. package/dist/lib/secrets/download-keychain.js +0 -70
  233. package/dist/lib/secrets/drivers/rush.d.ts +0 -14
  234. package/dist/lib/secrets/drivers/rush.js +0 -90
  235. package/dist/lib/secrets/fallback.d.ts +0 -48
  236. package/dist/lib/secrets/fallback.js +0 -48
  237. package/dist/lib/secrets/filestore.d.ts +0 -222
  238. package/dist/lib/secrets/filestore.js +0 -1099
  239. package/dist/lib/secrets/headless.d.ts +0 -43
  240. package/dist/lib/secrets/headless.js +0 -56
  241. package/dist/lib/secrets/icloud-import.d.ts +0 -79
  242. package/dist/lib/secrets/icloud-import.js +0 -206
  243. package/dist/lib/secrets/index.d.ts +0 -451
  244. package/dist/lib/secrets/index.js +0 -1568
  245. package/dist/lib/secrets/install-helper.d.ts +0 -72
  246. package/dist/lib/secrets/install-helper.js +0 -245
  247. package/dist/lib/secrets/lease.d.ts +0 -25
  248. package/dist/lib/secrets/lease.js +0 -44
  249. package/dist/lib/secrets/linux.d.ts +0 -77
  250. package/dist/lib/secrets/linux.js +0 -393
  251. package/dist/lib/secrets/list-filter.d.ts +0 -109
  252. package/dist/lib/secrets/list-filter.js +0 -261
  253. package/dist/lib/secrets/mcp.d.ts +0 -93
  254. package/dist/lib/secrets/mcp.js +0 -211
  255. package/dist/lib/secrets/profiles.d.ts +0 -10
  256. package/dist/lib/secrets/profiles.js +0 -13
  257. package/dist/lib/secrets/push.d.ts +0 -133
  258. package/dist/lib/secrets/push.js +0 -273
  259. package/dist/lib/secrets/rc-hygiene.d.ts +0 -63
  260. package/dist/lib/secrets/rc-hygiene.js +0 -143
  261. package/dist/lib/secrets/read-backoff.d.ts +0 -27
  262. package/dist/lib/secrets/read-backoff.js +0 -64
  263. package/dist/lib/secrets/reaper.d.ts +0 -90
  264. package/dist/lib/secrets/reaper.js +0 -243
  265. package/dist/lib/secrets/remote.d.ts +0 -152
  266. package/dist/lib/secrets/remote.js +0 -344
  267. package/dist/lib/secrets/reserved-sync.d.ts +0 -66
  268. package/dist/lib/secrets/reserved-sync.js +0 -147
  269. package/dist/lib/secrets/scope.d.ts +0 -26
  270. package/dist/lib/secrets/scope.js +0 -29
  271. package/dist/lib/secrets/session-store.d.ts +0 -107
  272. package/dist/lib/secrets/session-store.js +0 -342
  273. package/dist/lib/secrets/sync-backend.d.ts +0 -48
  274. package/dist/lib/secrets/sync-backend.js +0 -13
  275. package/dist/lib/secrets/sync-commands.d.ts +0 -21
  276. package/dist/lib/secrets/sync-commands.js +0 -21
  277. package/dist/lib/secrets/sync.d.ts +0 -48
  278. package/dist/lib/secrets/sync.js +0 -237
  279. package/dist/lib/secrets/unlock-hints.d.ts +0 -27
  280. package/dist/lib/secrets/unlock-hints.js +0 -36
  281. package/dist/lib/secrets/usage-db.d.ts +0 -46
  282. package/dist/lib/secrets/usage-db.js +0 -96
  283. package/dist/lib/secrets/vault-age-helper.d.ts +0 -1
  284. package/dist/lib/secrets/vault-age-helper.js +0 -34
  285. package/dist/lib/secrets/vault.d.ts +0 -49
  286. package/dist/lib/secrets/vault.js +0 -399
  287. package/dist/lib/secrets/windows.d.ts +0 -81
  288. package/dist/lib/secrets/windows.js +0 -556
  289. package/scripts/install-helper.js +0 -97
  290. /package/dist/lib/{secrets/sync-passphrase.d.ts → sync-passphrase.d.ts} +0 -0
  291. /package/dist/lib/{secrets/sync-passphrase.js → sync-passphrase.js} +0 -0
@@ -1,47 +0,0 @@
1
- /**
2
- * On-demand download + verification of the macOS keychain broker helper
3
- * ("Agents CLI.app").
4
- *
5
- * Mirrors the ComputerHelper / MenubarHelper download model
6
- * (`../helper-download.ts`): the helper ships as a signed + notarized `.app`
7
- * zipped as a GitHub release asset on the helper's own `keychain/v<x.y.z>` tag,
8
- * NOT the CLI's tag (see `helper-versions.ts`). A fresh `npm i -g`
9
- * machine whose tarball lacks a bundled copy fetches the asset for the running
10
- * CLI version, verifies its sha256 + code signature before install.
11
- *
12
- * Unlike the menu-bar helper, the keychain helper pins NO designated
13
- * requirement (no `expectedBundleId`). The menu-bar `expectedBundleId` exists
14
- * because macOS keys the Accessibility (TCC) grant to the bundle's designated
15
- * requirement, so a substituted bundle whose DR does not pin (id, team) would
16
- * silently revoke that upgrade-stable grant. The keychain helper has no such
17
- * DR-keyed grant to protect: its items are gated by the access-group
18
- * entitlement (`keychain-helper.swift` → `kSecAttrAccessGroup`, the
19
- * `keychain-access-groups` entitlement) plus a biometry `SecAccessControl`
20
- * (user presence) — NOT a `SecTrustedApplication` ACL keyed to a bundle-id/DR.
21
- * The release-time gate `scripts/verify-keychain-helper.sh` correspondingly
22
- * pins the executable's sha256, not a designated requirement. So Team +
23
- * notarization is the verification boundary here, exactly like ComputerHelper.
24
- */
25
- import { type HelperSpec } from '../helper-download.js';
26
- /** The zipped `.app` release asset name (the bundle name has a space). */
27
- export declare const KEYCHAIN_HELPER_ASSET = "Agents_CLI.app.zip";
28
- /** The bundle directory name once extracted. */
29
- export declare const KEYCHAIN_HELPER_APP_NAME = "Agents CLI.app";
30
- /** Keychain-helper identity + verification policy — Team + notarization only,
31
- * no DR pin (see docblock). */
32
- export declare const KEYCHAIN_HELPER_SPEC: HelperSpec;
33
- /** Release-asset URLs for the keychain helper zip + its checksum at `v<version>`. */
34
- export declare function keychainHelperAssetUrls(version: string): {
35
- zip: string;
36
- sha256: string;
37
- };
38
- /** Cache dir for the downloaded keychain helper, one subdir per release tag. */
39
- export declare function keychainHelperCacheDir(version: string): string;
40
- /** Verify a keychain helper `.app`: codesign + Team + notarization (no DR pin). */
41
- export declare function verifyKeychainHelper(appPath: string): void;
42
- /**
43
- * Download the keychain helper release asset for `version`, verify sha256 +
44
- * signature, and return the path to the extracted `Agents CLI.app` in the
45
- * cache. A missing asset is a hard error naming the exact tag.
46
- */
47
- export declare function downloadKeychainHelperApp(version: string): Promise<string>;
@@ -1,70 +0,0 @@
1
- /**
2
- * On-demand download + verification of the macOS keychain broker helper
3
- * ("Agents CLI.app").
4
- *
5
- * Mirrors the ComputerHelper / MenubarHelper download model
6
- * (`../helper-download.ts`): the helper ships as a signed + notarized `.app`
7
- * zipped as a GitHub release asset on the helper's own `keychain/v<x.y.z>` tag,
8
- * NOT the CLI's tag (see `helper-versions.ts`). A fresh `npm i -g`
9
- * machine whose tarball lacks a bundled copy fetches the asset for the running
10
- * CLI version, verifies its sha256 + code signature before install.
11
- *
12
- * Unlike the menu-bar helper, the keychain helper pins NO designated
13
- * requirement (no `expectedBundleId`). The menu-bar `expectedBundleId` exists
14
- * because macOS keys the Accessibility (TCC) grant to the bundle's designated
15
- * requirement, so a substituted bundle whose DR does not pin (id, team) would
16
- * silently revoke that upgrade-stable grant. The keychain helper has no such
17
- * DR-keyed grant to protect: its items are gated by the access-group
18
- * entitlement (`keychain-helper.swift` → `kSecAttrAccessGroup`, the
19
- * `keychain-access-groups` entitlement) plus a biometry `SecAccessControl`
20
- * (user presence) — NOT a `SecTrustedApplication` ACL keyed to a bundle-id/DR.
21
- * The release-time gate `scripts/verify-keychain-helper.sh` correspondingly
22
- * pins the executable's sha256, not a designated requirement. So Team +
23
- * notarization is the verification boundary here, exactly like ComputerHelper.
24
- */
25
- import { EXPECTED_TEAM_ID, downloadHelperApp, helperAssetUrls, helperCacheDir, verifyHelperApp, } from '../helper-download.js';
26
- /** The zipped `.app` release asset name (the bundle name has a space). */
27
- // Underscore, and NOT a space. GitHub rewrites a space in a release-asset name
28
- // to a dot on upload, so an asset staged as `Agents CLI.app.zip` is SERVED as
29
- // `Agents.CLI.app.zip` and a client asking for the spaced name 404s forever --
30
- // which is exactly what shipped. The fix is to CHOOSE a name GitHub leaves
31
- // alone rather than to mirror its rewrite: `Agents.CLI.app.zip` would work by
32
- // matching an artifact of that behavior, and would silently break if the
33
- // normalization rule ever changed. Underscores are preserved verbatim (verified
34
- // against a real upload).
35
- //
36
- // The bundle DIRECTORY inside the zip keeps its space (`appName` below) -- that
37
- // is the on-disk bundle name macOS and the TCC grant key on, and it is unchanged.
38
- export const KEYCHAIN_HELPER_ASSET = 'Agents_CLI.app.zip';
39
- /** The bundle directory name once extracted. */
40
- export const KEYCHAIN_HELPER_APP_NAME = 'Agents CLI.app';
41
- /** Keychain-helper identity + verification policy — Team + notarization only,
42
- * no DR pin (see docblock). */
43
- export const KEYCHAIN_HELPER_SPEC = {
44
- helper: 'keychain',
45
- assetName: KEYCHAIN_HELPER_ASSET,
46
- appName: KEYCHAIN_HELPER_APP_NAME,
47
- cacheSubdir: ['secrets', 'mac-helper'],
48
- expectedTeamId: EXPECTED_TEAM_ID,
49
- localBuildHint: 'cli/scripts/build-keychain-helper.sh',
50
- };
51
- /** Release-asset URLs for the keychain helper zip + its checksum at `v<version>`. */
52
- export function keychainHelperAssetUrls(version) {
53
- return helperAssetUrls(KEYCHAIN_HELPER_SPEC, version);
54
- }
55
- /** Cache dir for the downloaded keychain helper, one subdir per release tag. */
56
- export function keychainHelperCacheDir(version) {
57
- return helperCacheDir(KEYCHAIN_HELPER_SPEC, version);
58
- }
59
- /** Verify a keychain helper `.app`: codesign + Team + notarization (no DR pin). */
60
- export function verifyKeychainHelper(appPath) {
61
- verifyHelperApp(appPath, KEYCHAIN_HELPER_SPEC);
62
- }
63
- /**
64
- * Download the keychain helper release asset for `version`, verify sha256 +
65
- * signature, and return the path to the extracted `Agents CLI.app` in the
66
- * cache. A missing asset is a hard error naming the exact tag.
67
- */
68
- export function downloadKeychainHelperApp(version) {
69
- return downloadHelperApp(KEYCHAIN_HELPER_SPEC, version);
70
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Rush `SyncBackend` driver — the original (and currently default) transport
3
- * for `agents secrets push/pull`. Talks to api.prix.dev and authenticates with
4
- * the session token written by `rush login` (`~/.rush/user.yaml`).
5
- *
6
- * This is the ONE place in the secrets module allowed to reference Rush
7
- * (api.prix.dev / ~/.rush). It is an opt-in driver kept for backwards
8
- * compatibility with bundles already pushed to Rush; `sync.ts` selects it as
9
- * the default but the transport seam (`SyncBackend`) lets other backends drop
10
- * in without touching the crypto or push/pull logic.
11
- */
12
- import type { SyncBackend } from '../sync-backend.js';
13
- /** The Rush transport. Plaintext never reaches here — only ciphertext envelopes. */
14
- export declare const rushSyncBackend: SyncBackend;
@@ -1,90 +0,0 @@
1
- /**
2
- * Rush `SyncBackend` driver — the original (and currently default) transport
3
- * for `agents secrets push/pull`. Talks to api.prix.dev and authenticates with
4
- * the session token written by `rush login` (`~/.rush/user.yaml`).
5
- *
6
- * This is the ONE place in the secrets module allowed to reference Rush
7
- * (api.prix.dev / ~/.rush). It is an opt-in driver kept for backwards
8
- * compatibility with bundles already pushed to Rush; `sync.ts` selects it as
9
- * the default but the transport seam (`SyncBackend`) lets other backends drop
10
- * in without touching the crypto or push/pull logic.
11
- */
12
- import * as fs from 'fs';
13
- import * as os from 'os';
14
- import * as path from 'path';
15
- import * as yaml from 'yaml';
16
- import { isRushSessionExpired } from '../../rush-session.js';
17
- const PROXY_BASE = 'https://api.prix.dev';
18
- const USER_YAML = path.join(os.homedir(), '.rush', 'user.yaml');
19
- const BUNDLE_ENDPOINT = '/api/v1/secrets/bundles';
20
- function readRushToken() {
21
- if (!fs.existsSync(USER_YAML)) {
22
- throw new Error('Not logged in to Rush. Run `rush login` first.');
23
- }
24
- const raw = fs.readFileSync(USER_YAML, 'utf-8');
25
- const data = yaml.parse(raw);
26
- const token = data?.session?.access_token;
27
- if (!token) {
28
- throw new Error('No session token in ~/.rush/user.yaml. Run `rush login` first.');
29
- }
30
- const expiresAt = data.session?.expires_at;
31
- if (isRushSessionExpired(expiresAt)) {
32
- const expiredAt = new Date(expiresAt).toISOString();
33
- throw new Error(`Rush session expired at ${expiredAt}. Run \`rush login\` to refresh.`);
34
- }
35
- return token;
36
- }
37
- async function api(method, endpoint, body) {
38
- const token = readRushToken();
39
- const url = endpoint.startsWith('http') ? endpoint : `${PROXY_BASE}${endpoint}`;
40
- return fetch(url, {
41
- method,
42
- headers: {
43
- Authorization: `Bearer ${token}`,
44
- 'Content-Type': 'application/json',
45
- },
46
- body: body === undefined ? undefined : JSON.stringify(body),
47
- });
48
- }
49
- function bundlePath(name) {
50
- return `${BUNDLE_ENDPOINT}/${encodeURIComponent(name)}`;
51
- }
52
- /** The Rush transport. Plaintext never reaches here — only ciphertext envelopes. */
53
- export const rushSyncBackend = {
54
- async putEnvelope(name, payload) {
55
- const res = await api('PUT', bundlePath(name), payload);
56
- if (!res.ok) {
57
- const body = await res.text().catch(() => '');
58
- throw new Error(`Push failed (${res.status} ${res.statusText}): ${body}`);
59
- }
60
- },
61
- async getEnvelope(name) {
62
- const res = await api('GET', bundlePath(name));
63
- if (res.status === 404)
64
- return null;
65
- if (!res.ok) {
66
- const body = await res.text().catch(() => '');
67
- throw new Error(`Pull failed (${res.status} ${res.statusText}): ${body}`);
68
- }
69
- return await res.json();
70
- },
71
- async deleteEnvelope(name) {
72
- const res = await api('DELETE', bundlePath(name));
73
- if (res.status === 404)
74
- return false;
75
- if (!res.ok) {
76
- const body = await res.text().catch(() => '');
77
- throw new Error(`Delete failed (${res.status} ${res.statusText}): ${body}`);
78
- }
79
- return true;
80
- },
81
- async listEnvelopes() {
82
- const res = await api('GET', BUNDLE_ENDPOINT);
83
- if (!res.ok) {
84
- const body = await res.text().catch(() => '');
85
- throw new Error(`List failed (${res.status} ${res.statusText}): ${body}`);
86
- }
87
- const data = await res.json();
88
- return data.bundles ?? [];
89
- },
90
- };
@@ -1,48 +0,0 @@
1
- /**
2
- * Shared helpers for the Linux/Windows encrypted-file fallback.
3
- *
4
- * When the native credential store (GNOME Keyring / Windows Credential Manager)
5
- * is unreachable, both backends route to the AES-256-GCM file store. The routing
6
- * is "sticky": once any item is on disk, every op stays on the file store. That
7
- * is correct for perf, but on its own it would silently *shadow* secrets that
8
- * still live in the native store — reads for them would return empty with no
9
- * hint. This module centralizes the two pieces that keep that from being silent:
10
- *
11
- * 1. `noteNativeShadow()` — a one-time stderr notice, emitted when a read
12
- * falls through to the native store (found something shadowed, or hit a
13
- * locked/unreachable store), pointing at `agents secrets import-keyring`.
14
- * 2. The result types for that import command.
15
- *
16
- * macOS has no file fallback (see ./index.ts) and uses `migrate-acl` /
17
- * `migrate-orphans` for its own invisible-item classes, so none of this runs
18
- * there.
19
- */
20
- export type NativeImportStatus = 'imported' | 'would-import' | 'exists' | 'failed';
21
- export interface NativeImportResult {
22
- item: string;
23
- status: NativeImportStatus;
24
- detail?: string;
25
- }
26
- /**
27
- * Outcome of an `import-keyring` run. `available` is false when no native
28
- * tooling exists (no `secret-tool` / no `powershell.exe`); `locked` is true when
29
- * the native store exists but is locked/unreachable, so nothing could be read.
30
- */
31
- export interface NativeImportReport {
32
- available: boolean;
33
- locked: boolean;
34
- results: NativeImportResult[];
35
- }
36
- /**
37
- * Emit a one-time stderr notice that the file fallback is masking the native
38
- * credential store. Both backends share the copy so the guidance is identical.
39
- *
40
- * 'shadowed' — a secret was just read from the native store that isn't in the
41
- * file store. It works, but each read pays a native lookup and it
42
- * won't survive the store locking; suggest migrating it.
43
- * 'locked' — the native store is locked/unreachable, so its secrets can't be
44
- * read in this session at all; the user must unlock, then migrate.
45
- */
46
- export declare function noteNativeShadow(kind: 'shadowed' | 'locked', fileDir: string): void;
47
- /** Test-only: clear the one-time notice guard between cases. */
48
- export declare function _resetFallbackNoticeForTest(): void;
@@ -1,48 +0,0 @@
1
- /**
2
- * Shared helpers for the Linux/Windows encrypted-file fallback.
3
- *
4
- * When the native credential store (GNOME Keyring / Windows Credential Manager)
5
- * is unreachable, both backends route to the AES-256-GCM file store. The routing
6
- * is "sticky": once any item is on disk, every op stays on the file store. That
7
- * is correct for perf, but on its own it would silently *shadow* secrets that
8
- * still live in the native store — reads for them would return empty with no
9
- * hint. This module centralizes the two pieces that keep that from being silent:
10
- *
11
- * 1. `noteNativeShadow()` — a one-time stderr notice, emitted when a read
12
- * falls through to the native store (found something shadowed, or hit a
13
- * locked/unreachable store), pointing at `agents secrets import-keyring`.
14
- * 2. The result types for that import command.
15
- *
16
- * macOS has no file fallback (see ./index.ts) and uses `migrate-acl` /
17
- * `migrate-orphans` for its own invisible-item classes, so none of this runs
18
- * there.
19
- */
20
- let noticeEmitted = false;
21
- /**
22
- * Emit a one-time stderr notice that the file fallback is masking the native
23
- * credential store. Both backends share the copy so the guidance is identical.
24
- *
25
- * 'shadowed' — a secret was just read from the native store that isn't in the
26
- * file store. It works, but each read pays a native lookup and it
27
- * won't survive the store locking; suggest migrating it.
28
- * 'locked' — the native store is locked/unreachable, so its secrets can't be
29
- * read in this session at all; the user must unlock, then migrate.
30
- */
31
- export function noteNativeShadow(kind, fileDir) {
32
- if (noticeEmitted)
33
- return;
34
- noticeEmitted = true;
35
- if (kind === 'locked') {
36
- process.stderr.write(`[agents] the native credential store is locked/unreachable — secrets stored there are not ` +
37
- `readable in this session. Unlock it, then run \`agents secrets import-keyring\` to migrate ` +
38
- `them into the encrypted file store at ${fileDir}.\n`);
39
- }
40
- else {
41
- process.stderr.write(`[agents] read a secret from the native credential store that is not in the file store at ` +
42
- `${fileDir}. Run \`agents secrets import-keyring\` to migrate it so it stays readable headless.\n`);
43
- }
44
- }
45
- /** Test-only: clear the one-time notice guard between cases. */
46
- export function _resetFallbackNoticeForTest() {
47
- noticeEmitted = false;
48
- }
@@ -1,222 +0,0 @@
1
- /**
2
- * Passphrase-encrypted file store for secrets — platform-neutral.
3
- *
4
- * An AES-256-GCM encrypted-file store under `~/.agents/.cache/secrets/`. The
5
- * encryption key is scrypt-derived from a passphrase read from
6
- * `AGENTS_SECRETS_PASSPHRASE` (preferred) or a machine-local key the store
7
- * auto-provisions on first use. One `<item>.enc` JSON file per item, mode 0600.
8
- *
9
- * Two callers, one policy: the store silently auto-provisions a stable
10
- * machine-local key (a 0600 file under `~/.agents/.secrets-key/`) on EVERY
11
- * platform, so it works out of the box with no passphrase to set or remember and
12
- * never pops a prompt or Touch ID sheet.
13
- * - Linux (src/lib/secrets/linux.ts): the headless fallback when the default
14
- * Secret Service collection is locked.
15
- * - macOS/Windows file-backed bundles (src/lib/secrets/bundles.ts): an explicit,
16
- * opt-in non-biometry backend for headless/remote runs.
17
- * Set AGENTS_SECRETS_PASSPHRASE to opt into a key held off disk instead (e.g. to
18
- * share one bundle's ciphertext across boxes under a common key).
19
- *
20
- * The item-name scheme is shared with the keychain backend so a file-backed
21
- * item and its keychain twin carry identical names:
22
- * `agents-cli.bundles.<name>` and `agents-cli.secrets.<bundle>.<key>`.
23
- */
24
- import type { KeychainBackend } from './index.js';
25
- export declare function fileDir(): string;
26
- /** True if a machine-local passphrase has already been provisioned. */
27
- export declare function machinePassphraseExists(): boolean;
28
- /**
29
- * Resolve the passphrase for the encrypted file store.
30
- *
31
- * Order: AGENTS_SECRETS_PASSPHRASE > previously-provisioned machine-local key >
32
- * legacy co-located key > a freshly auto-provisioned machine-local key. It NEVER
33
- * prompts, and never fails for WANT of a passphrase — the file store must work on
34
- * every platform (macOS included) without the user setting, typing, or
35
- * remembering one. (It can still throw if provisioning cannot write the key file
36
- * at all; that is a disk/permissions failure, not a missing passphrase.) Provisioning
37
- * writes a 0600 key file (encryption-at-rest, same posture as an SSH key); set
38
- * AGENTS_SECRETS_PASSPHRASE to opt into an off-disk key.
39
- */
40
- export declare function getPassphrase(): string;
41
- /** Encrypted-file on-disk shape. Exported for tests. */
42
- export interface EncFile {
43
- salt: string;
44
- iv: string;
45
- authTag: string;
46
- ciphertext: string;
47
- }
48
- /** Encrypt plaintext under a passphrase using AES-256-GCM with a random
49
- * scrypt salt and a random 96-bit IV. Exported for tests. */
50
- export declare function encryptForFallback(plaintext: string, passphrase: string): EncFile;
51
- /** Decrypt an EncFile under a passphrase. Throws on wrong key or tampered
52
- * ciphertext (auth-tag mismatch). Exported for tests. */
53
- export declare function decryptForFallback(enc: EncFile, passphrase: string): string;
54
- /** Absolute path of one encrypted file-store item. No read or decrypt occurs. */
55
- export declare function fileStoreItemPath(item: string): string;
56
- declare function fileHas(item: string): boolean;
57
- declare function fileGet(item: string): string;
58
- declare function fileGetBatch(items: string[]): Map<string, string>;
59
- declare function fileSet(item: string, value: string): void;
60
- declare function fileDelete(item: string): boolean;
61
- declare function fileList(prefix: string): string[];
62
- /** True if the fallback dir has any committed encrypted items. */
63
- export declare function fileStoreHasItems(): boolean;
64
- /** Low-level file-store ops, exported so callers (linux fallback, macOS
65
- * file-backed bundles) can opt into or out of passphrase auto-provision. */
66
- export declare const fileStore: {
67
- has: typeof fileHas;
68
- get: typeof fileGet;
69
- getBatch: typeof fileGetBatch;
70
- set: typeof fileSet;
71
- delete: typeof fileDelete;
72
- list: typeof fileList;
73
- };
74
- /** File-only KeychainBackend (exported for tests; the Linux backend uses these
75
- * ops with auto-provision allowed). */
76
- export declare const fileBackend: KeychainBackend;
77
- /** Resolved passphrase directory (exported for integration tests). */
78
- export declare function resolvePassphraseDir(): string;
79
- /**
80
- * Path of the machine-local passphrase file that currently holds the file-store
81
- * key, or null if none is provisioned. Prefers the canonical #479 location and
82
- * falls back to the legacy co-located path, mirroring `readMachinePassphrase`.
83
- */
84
- export declare function machinePassphraseSourcePath(): string | null;
85
- /** Outcome of a `rotatePassphrase` run. Carries no secret material. */
86
- export interface RotatePassphraseReport {
87
- /** True when nothing was written (report-only). */
88
- dryRun: boolean;
89
- /** True when the store was re-encrypted and the key file swapped. */
90
- committed: boolean;
91
- /** Encrypted items that decrypt under the current key and were (or would be) re-keyed. */
92
- bundleCount: number;
93
- /** `.enc` files that do NOT decrypt under the current key — left untouched, never re-keyed. */
94
- skipped: string[];
95
- /** Every re-keyed item round-tripped (decrypt) under the new key before any swap. */
96
- roundTripOk: boolean;
97
- /** The machine-local passphrase file that was (or would be) rewritten in place. */
98
- keyFilePath: string;
99
- /**
100
- * A previous rotation had left artifacts on disk and they were healed before
101
- * this rotation proceeded. This happens under `--dry-run` too — recovery is how
102
- * a crashed store becomes readable again without re-keying it — and is the only
103
- * thing a dry run writes.
104
- */
105
- recoveredInterruptedRotation: boolean;
106
- }
107
- /**
108
- * Recover from a rotation that was interrupted mid-swap on a prior run, so the
109
- * store is always left in a single, self-consistent, readable state.
110
- *
111
- * Recovery is CONTENT-aware, not presence-aware, and it classifies the WHOLE
112
- * store, not just one item. The mere existence of the store dir and the key file
113
- * does not prove they match (RUSH-1975 data-loss window): on the non-co-located
114
- * key path the swap is four renames, and a crash after the store swap
115
- * (`stageDir`->`dir`) but before the key swap (`keyTmp`->`keyPath`) finishes
116
- * leaves a NEW-key store next to the OLD key file, both present. A presence check
117
- * would see "both here" and wrongly sweep the only copies of the old ciphertext
118
- * (`<dir>.rotate-old-*`) and the new key (`<key>.rotate-new`), permanently
119
- * orphaning every secret. So we probe the actual ciphertext with `classifyStore`,
120
- * which distinguishes a store that opens fully under one key ('all') from one that
121
- * is MIXED — some items under the live key, others under the incoming key ('some',
122
- * e.g. after a mid-swap crash contaminated by a later `secrets set`):
123
- *
124
- * 1. The live key opens EVERY non-orphan item ('all') → rotation complete and
125
- * consistent (or never interrupted); sweeping the `.rotate-*` artifacts is safe —
126
- * unless a `<dir>.rotate-old-*` backup still holds `.enc` items absent from the
127
- * live dir. That means the live dir is not the post-swap store but a fresh dir an
128
- * interstitial `secrets set` created after a crash in the move-aside window left
129
- * the store dir absent, so the backup is the only copy of those items → REFUSE.
130
- * 2. Else, if `<key>.rotate-new` opens every non-orphan item ('all'), the crash
131
- * landed after the store swap but before the key swap finished → finish the
132
- * rotation forward by installing `.rotate-new` as the live key, then sweep.
133
- * 3. Else, if neither key opens any item, roll back: restore the
134
- * `<dir>.rotate-old-*` backup over `dir` and `<key>.rotate-oldkey` over the key
135
- * file — but only once the backup is proven to open fully under the old key.
136
- * 4. If a key opens SOME but not all items ('some'), the store is MIXED — an
137
- * interrupted rotation contaminated by a later write, with live data under two
138
- * keys at once. Sweeping would delete the only copy of one of those keys, so we
139
- * REFUSE: throw an actionable error and preserve every recovery artifact for
140
- * out-of-band repair. Likewise, if neither forward nor rollback can be proven,
141
- * leave every artifact in place — a leftover temp dir is recoverable, deleting
142
- * the only copy of a key or ciphertext is not.
143
- *
144
- * A phase-marker / journal file was considered and deliberately skipped: the
145
- * AES-256-GCM auth tag already makes the decrypt probe an authoritative,
146
- * self-validating record of which key matches the store. A separate marker would
147
- * be a second source of truth that can disagree with reality — its own write has
148
- * crash windows, and a stale marker misleads — so it would weaken, not strengthen,
149
- * this guarantee. Idempotent; a no-op when no rotation artifacts are present.
150
- * Callers run this under the store lock (see `withStoreLock`).
151
- */
152
- /**
153
- * Whether a previous rotation left artifacts on disk — i.e. whether
154
- * {@link recoverInterruptedRotation} would do any work. Read-only, so `--dry-run`
155
- * can report a pending recovery without performing (and thus writing) one.
156
- */
157
- export declare function hasInterruptedRotationArtifacts(keyPath: string): boolean;
158
- /**
159
- * Rotate the machine-local file-store passphrase: decrypt every `.enc` item
160
- * under the current key and re-encrypt it under a freshly generated one, then
161
- * swap both the ciphertext and the key file atomically.
162
- *
163
- * Safety contract (RUSH-1975):
164
- * - Verify before writing: every re-keyed item must round-trip decrypt under
165
- * the new key, and the re-keyed count must reconcile with the source, or the
166
- * run aborts having written nothing.
167
- * - Atomic: the new store is staged in a sibling temp dir, fsync'd, then swapped
168
- * into place by directory rename; the new key file is fsync'd and swapped the
169
- * same way. A crash before the swap leaves the old store and old key fully
170
- * intact and readable; a crash inside the swap self-heals on the next run
171
- * (see `recoverInterruptedRotation`). No half-re-keyed store is ever exposed.
172
- * - No plaintext (secret value or passphrase) is ever written to disk, argv, or
173
- * a log — only ciphertext is staged, and the new key lands only in the 0600
174
- * key file.
175
- * - Items that do not decrypt under the current key (orphan caches, stale test
176
- * artifacts written under another key) are copied through verbatim, never
177
- * re-keyed, and reported in `skipped`.
178
- *
179
- * `newPassphrase` and the `on*` callbacks are test seams. `newPassphrase` pins the
180
- * generated key so a test can assert the swap. `onStagedBeforeCommit` fires after
181
- * staging but before any swap (a crash here leaves the old store fully intact).
182
- * `onStoreSwappedBeforeKeySwap` fires after the store swap but before the key swap
183
- * begins (Window A: NEW-key store beside the OLD key file). `onKeyBackedUpBeforeNewKey`
184
- * fires after the old key is moved aside but before the new key lands (Window B: NEW
185
- * store, key file absent). Each throws to simulate a mid-swap crash at that exact
186
- * point, and next-run recovery must heal it without data loss. `tamperStaged` forces
187
- * a staged item to fail its round-trip check, exercising the verify-before-swap abort.
188
- */
189
- export interface RotatePassphraseOpts {
190
- dryRun?: boolean;
191
- newPassphrase?: string;
192
- onStagedBeforeCommit?: () => void;
193
- onStoreMovedAsideBeforeSwap?: () => void;
194
- onStoreSwappedBeforeKeySwap?: (heartbeat: () => void) => void;
195
- onKeyBackedUpBeforeNewKey?: () => void;
196
- tamperStaged?: boolean;
197
- }
198
- /**
199
- * Rotate under the exclusive store lock, so no `secrets set`/`delete` and no
200
- * second rotation can interleave with the swap (see `withStoreLock`). The whole
201
- * run — recovery, verify, swap — holds the lock; it is released on return or throw.
202
- */
203
- export declare function rotatePassphrase(opts?: RotatePassphraseOpts): RotatePassphraseReport;
204
- /** Test-only: reset module state (file dir + cached passphrase). */
205
- export declare function _resetFileStoreForTest(opts?: {
206
- fileDir?: string | null;
207
- passphraseDir?: string | null;
208
- passphrase?: string | null;
209
- }): void;
210
- /** Test-only: flush the in-memory metadata cache to disk now. Production flushes
211
- * once at process exit; a test needs the on-disk copy mid-run to simulate the
212
- * next `agents` process reading it. */
213
- export declare function _flushMetaCacheForTest(): void;
214
- /** Test-only: shorten the store-lock acquire timeout so a contended-lock assertion
215
- * fails fast instead of waiting out the 30s production budget. */
216
- export declare function _setFileStoreLockTimeoutForTest(ms: number | null): void;
217
- /** Test-only: shrink the store-lock stale window so a heartbeat/steal assertion runs
218
- * in milliseconds instead of the 5s production window. */
219
- export declare function _setFileStoreLockStaleMsForTest(ms: number | null): void;
220
- /** Test-only: the cross-process store-lock target (sibling of the store dir). */
221
- export declare function _fileStoreLockPathForTest(): string;
222
- export {};