@phnx-labs/agents-cli 1.22.84 → 1.22.86

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 (259) 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/alias.js +7 -3
  9. package/dist/commands/apply.js +1 -1
  10. package/dist/commands/auth-mint.d.ts +7 -3
  11. package/dist/commands/auth-mint.js +21 -9
  12. package/dist/commands/auth.js +2 -3
  13. package/dist/commands/browser.js +10 -10
  14. package/dist/commands/daemon.d.ts +7 -3
  15. package/dist/commands/daemon.js +40 -25
  16. package/dist/commands/doctor.js +28 -2
  17. package/dist/commands/exec.js +87 -39
  18. package/dist/commands/fleet-capture.js +21 -2
  19. package/dist/commands/harness-wizard.js +2 -2
  20. package/dist/commands/lease.js +7 -12
  21. package/dist/commands/profiles.d.ts +2 -2
  22. package/dist/commands/profiles.js +20 -13
  23. package/dist/commands/repo.js +3 -3
  24. package/dist/commands/run-account-picker.d.ts +3 -3
  25. package/dist/commands/run-account-picker.js +29 -30
  26. package/dist/commands/secrets-passthrough.d.ts +20 -0
  27. package/dist/commands/secrets-passthrough.js +43 -0
  28. package/dist/commands/setup-accounts.d.ts +3 -2
  29. package/dist/commands/setup-accounts.js +4 -4
  30. package/dist/commands/setup-secrets.d.ts +16 -21
  31. package/dist/commands/setup-secrets.js +43 -224
  32. package/dist/commands/ssh.js +2 -2
  33. package/dist/commands/sync.js +1 -1
  34. package/dist/commands/update.d.ts +10 -0
  35. package/dist/commands/update.js +43 -40
  36. package/dist/commands/versions.d.ts +11 -11
  37. package/dist/commands/versions.js +131 -83
  38. package/dist/commands/view.d.ts +1 -9
  39. package/dist/commands/view.js +41 -55
  40. package/dist/commands/webhook.js +5 -5
  41. package/dist/commands/workflows.js +2 -1
  42. package/dist/index.d.ts +12 -12
  43. package/dist/index.js +13 -42
  44. package/dist/lib/account-capabilities.d.ts +1 -1
  45. package/dist/lib/account-capabilities.js +1 -1
  46. package/dist/lib/account-catalog.d.ts +121 -6
  47. package/dist/lib/account-catalog.js +421 -7
  48. package/dist/lib/account-registry.d.ts +8 -30
  49. package/dist/lib/account-registry.js +36 -79
  50. package/dist/lib/account-schema.d.ts +1 -1
  51. package/dist/lib/account-schema.js +1 -1
  52. package/dist/lib/accounting/account-pool-collect.js +16 -4
  53. package/dist/lib/accounting/rotate.d.ts +20 -7
  54. package/dist/lib/accounting/rotate.js +89 -13
  55. package/dist/lib/accounting/usage.js +11 -16
  56. package/dist/lib/accounts/add.d.ts +138 -0
  57. package/dist/lib/accounts/add.js +651 -0
  58. package/dist/lib/accounts/migrate.d.ts +117 -0
  59. package/dist/lib/accounts/migrate.js +536 -0
  60. package/dist/lib/accounts/slots.d.ts +13 -0
  61. package/dist/lib/accounts/slots.js +100 -0
  62. package/dist/lib/agent-spec/agents.d.ts +16 -0
  63. package/dist/lib/agent-spec/agents.js +38 -4
  64. package/dist/lib/app-bundle-install.js +5 -4
  65. package/dist/lib/auth-health.d.ts +3 -0
  66. package/dist/lib/auth-health.js +11 -0
  67. package/dist/lib/auth-mint.d.ts +52 -16
  68. package/dist/lib/auth-mint.js +117 -39
  69. package/dist/lib/browser/chrome.d.ts +1 -1
  70. package/dist/lib/browser/chrome.js +5 -5
  71. package/dist/lib/byok-usage.js +3 -3
  72. package/dist/lib/claude-account-token.d.ts +47 -3
  73. package/dist/lib/claude-account-token.js +172 -50
  74. package/dist/lib/cloud/antigravity.js +4 -4
  75. package/dist/lib/cloud/cursor.js +4 -4
  76. package/dist/lib/crabbox/cli.d.ts +1 -1
  77. package/dist/lib/crabbox/cli.js +6 -6
  78. package/dist/lib/crabbox/runtimes.d.ts +3 -3
  79. package/dist/lib/crabbox/runtimes.js +5 -5
  80. package/dist/lib/daemon/account-state-daemon-service.d.ts +37 -1
  81. package/dist/lib/daemon/account-state-daemon-service.js +199 -3
  82. package/dist/lib/daemon/auth-sync-service.js +32 -1
  83. package/dist/lib/daemon/daemon.d.ts +6 -16
  84. package/dist/lib/daemon/daemon.js +52 -97
  85. package/dist/lib/daemon/daemon.test-fixture.d.ts +7 -9
  86. package/dist/lib/daemon/daemon.test-fixture.js +22 -40
  87. package/dist/lib/daemon/harness-update-service.d.ts +1 -1
  88. package/dist/lib/daemon/harness-update-service.js +1 -1
  89. package/dist/lib/daemon/runner.d.ts +15 -3
  90. package/dist/lib/daemon/runner.js +49 -24
  91. package/dist/lib/daemon-health.d.ts +1 -2
  92. package/dist/lib/daemon-health.js +7 -6
  93. package/dist/lib/daemon-services.d.ts +1 -1
  94. package/dist/lib/daemon-services.js +1 -11
  95. package/dist/lib/daemon-webhooks.d.ts +8 -7
  96. package/dist/lib/daemon-webhooks.js +10 -9
  97. package/dist/lib/device-config.js +1 -1
  98. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  99. package/dist/lib/devices/harness-inventory.d.ts +39 -0
  100. package/dist/lib/devices/harness-inventory.js +126 -4
  101. package/dist/lib/doctor-diff.js +2 -1
  102. package/dist/lib/exec-account-home.d.ts +38 -0
  103. package/dist/lib/exec-account-home.js +164 -0
  104. package/dist/lib/exec.d.ts +30 -0
  105. package/dist/lib/exec.js +101 -31
  106. package/dist/lib/fleet/apply.d.ts +2 -2
  107. package/dist/lib/fleet/apply.js +4 -4
  108. package/dist/lib/fleet/auth-sync.js +4 -3
  109. package/dist/lib/fleet-shared-repo-sync.js +6 -9
  110. package/dist/lib/harness/adapter.d.ts +7 -7
  111. package/dist/lib/harness/adapter.js +10 -6
  112. package/dist/lib/harness/adapters/grok.js +8 -3
  113. package/dist/lib/harness/adapters/muse.js +1 -1
  114. package/dist/lib/harness/adapters/opencode.js +12 -3
  115. package/dist/lib/harness-auth-capabilities.d.ts +61 -0
  116. package/dist/lib/harness-auth-capabilities.js +52 -0
  117. package/dist/lib/helper-versions.d.ts +6 -4
  118. package/dist/lib/helper-versions.js +5 -4
  119. package/dist/lib/hosts/credential-transport.d.ts +10 -0
  120. package/dist/lib/hosts/credential-transport.js +37 -0
  121. package/dist/lib/hosts/dispatch.d.ts +7 -0
  122. package/dist/lib/hosts/dispatch.js +13 -6
  123. package/dist/lib/identity/client.d.ts +3 -3
  124. package/dist/lib/identity/client.js +3 -3
  125. package/dist/lib/installations/index.d.ts +1 -1
  126. package/dist/lib/installations/index.js +1 -1
  127. package/dist/lib/installations/migrate.js +9 -0
  128. package/dist/lib/installations/resolve.js +1 -1
  129. package/dist/lib/installations/shims.d.ts +21 -4
  130. package/dist/lib/installations/shims.js +86 -5
  131. package/dist/lib/installations/store.d.ts +43 -0
  132. package/dist/lib/installations/store.js +75 -7
  133. package/dist/lib/installations/versions.js +1 -1
  134. package/dist/lib/menubar/install-menubar.d.ts +3 -3
  135. package/dist/lib/menubar/install-menubar.js +3 -3
  136. package/dist/lib/native-accounts.d.ts +35 -0
  137. package/dist/lib/native-accounts.js +41 -0
  138. package/dist/lib/net-close.d.ts +11 -0
  139. package/dist/lib/net-close.js +25 -0
  140. package/dist/lib/openclaw-keychain.js +27 -1
  141. package/dist/lib/profiles.js +22 -9
  142. package/dist/lib/project-resources.js +1 -1
  143. package/dist/lib/reserved-stores.d.ts +53 -0
  144. package/dist/lib/reserved-stores.js +120 -0
  145. package/dist/lib/secrets-client.d.ts +199 -0
  146. package/dist/lib/secrets-client.js +718 -0
  147. package/dist/lib/secrets-policy.d.ts +235 -0
  148. package/dist/lib/secrets-policy.js +505 -0
  149. package/dist/lib/secrets-types.d.ts +188 -0
  150. package/dist/lib/secrets-types.js +24 -0
  151. package/dist/lib/self-heal/checks/shims.js +5 -3
  152. package/dist/lib/service-manifest.js +3 -4
  153. package/dist/lib/session/db.d.ts +18 -0
  154. package/dist/lib/session/db.js +47 -14
  155. package/dist/lib/session/sync/config.js +2 -2
  156. package/dist/lib/sha256-asset.d.ts +11 -16
  157. package/dist/lib/sha256-asset.js +11 -16
  158. package/dist/lib/share/config.js +14 -5
  159. package/dist/lib/signin-badge.d.ts +26 -0
  160. package/dist/lib/signin-badge.js +42 -0
  161. package/dist/lib/staleness/detectors/workflows.js +3 -105
  162. package/dist/lib/staleness/writers/workflows.js +2 -1
  163. package/dist/lib/state.d.ts +7 -4
  164. package/dist/lib/state.js +18 -7
  165. package/dist/lib/sync-umbrella.js +2 -2
  166. package/dist/lib/teams/agents.js +1 -1
  167. package/dist/lib/types.d.ts +74 -33
  168. package/dist/lib/view-types.d.ts +6 -3
  169. package/dist/lib/workflows-registry.d.ts +71 -0
  170. package/dist/lib/workflows-registry.js +280 -0
  171. package/dist/lib/workflows.d.ts +21 -21
  172. package/dist/lib/workflows.js +12 -327
  173. package/package.json +2 -3
  174. package/scripts/postinstall.js +35 -30
  175. package/dist/commands/secrets-import.d.ts +0 -18
  176. package/dist/commands/secrets-import.js +0 -74
  177. package/dist/commands/secrets-migrate.d.ts +0 -25
  178. package/dist/commands/secrets-migrate.js +0 -334
  179. package/dist/commands/secrets-rotate-passphrase.d.ts +0 -17
  180. package/dist/commands/secrets-rotate-passphrase.js +0 -96
  181. package/dist/commands/secrets-sync.d.ts +0 -11
  182. package/dist/commands/secrets-sync.js +0 -153
  183. package/dist/commands/secrets-vault.d.ts +0 -10
  184. package/dist/commands/secrets-vault.js +0 -130
  185. package/dist/commands/secrets.d.ts +0 -212
  186. package/dist/commands/secrets.js +0 -3030
  187. package/dist/lib/accounts/connect.d.ts +0 -176
  188. package/dist/lib/accounts/connect.js +0 -453
  189. package/dist/lib/daemon/keychain-reap-service.d.ts +0 -17
  190. package/dist/lib/daemon/keychain-reap-service.js +0 -32
  191. package/dist/lib/daemon/secrets-broker-service.d.ts +0 -21
  192. package/dist/lib/daemon/secrets-broker-service.js +0 -51
  193. package/dist/lib/secrets/agent.d.ts +0 -358
  194. package/dist/lib/secrets/agent.js +0 -1291
  195. package/dist/lib/secrets/audit.d.ts +0 -46
  196. package/dist/lib/secrets/audit.js +0 -101
  197. package/dist/lib/secrets/bundles.d.ts +0 -290
  198. package/dist/lib/secrets/bundles.js +0 -1547
  199. package/dist/lib/secrets/download-keychain.d.ts +0 -47
  200. package/dist/lib/secrets/download-keychain.js +0 -70
  201. package/dist/lib/secrets/drivers/rush.d.ts +0 -14
  202. package/dist/lib/secrets/drivers/rush.js +0 -90
  203. package/dist/lib/secrets/fallback.d.ts +0 -48
  204. package/dist/lib/secrets/fallback.js +0 -48
  205. package/dist/lib/secrets/filestore.d.ts +0 -222
  206. package/dist/lib/secrets/filestore.js +0 -1099
  207. package/dist/lib/secrets/headless.d.ts +0 -43
  208. package/dist/lib/secrets/headless.js +0 -56
  209. package/dist/lib/secrets/icloud-import.d.ts +0 -79
  210. package/dist/lib/secrets/icloud-import.js +0 -206
  211. package/dist/lib/secrets/index.d.ts +0 -451
  212. package/dist/lib/secrets/index.js +0 -1568
  213. package/dist/lib/secrets/install-helper.d.ts +0 -72
  214. package/dist/lib/secrets/install-helper.js +0 -245
  215. package/dist/lib/secrets/lease.d.ts +0 -25
  216. package/dist/lib/secrets/lease.js +0 -44
  217. package/dist/lib/secrets/linux.d.ts +0 -77
  218. package/dist/lib/secrets/linux.js +0 -393
  219. package/dist/lib/secrets/list-filter.d.ts +0 -109
  220. package/dist/lib/secrets/list-filter.js +0 -261
  221. package/dist/lib/secrets/mcp.d.ts +0 -93
  222. package/dist/lib/secrets/mcp.js +0 -211
  223. package/dist/lib/secrets/profiles.d.ts +0 -10
  224. package/dist/lib/secrets/profiles.js +0 -13
  225. package/dist/lib/secrets/push.d.ts +0 -133
  226. package/dist/lib/secrets/push.js +0 -273
  227. package/dist/lib/secrets/rc-hygiene.d.ts +0 -63
  228. package/dist/lib/secrets/rc-hygiene.js +0 -143
  229. package/dist/lib/secrets/read-backoff.d.ts +0 -27
  230. package/dist/lib/secrets/read-backoff.js +0 -64
  231. package/dist/lib/secrets/reaper.d.ts +0 -90
  232. package/dist/lib/secrets/reaper.js +0 -243
  233. package/dist/lib/secrets/remote.d.ts +0 -152
  234. package/dist/lib/secrets/remote.js +0 -344
  235. package/dist/lib/secrets/reserved-sync.d.ts +0 -66
  236. package/dist/lib/secrets/reserved-sync.js +0 -147
  237. package/dist/lib/secrets/scope.d.ts +0 -26
  238. package/dist/lib/secrets/scope.js +0 -29
  239. package/dist/lib/secrets/session-store.d.ts +0 -107
  240. package/dist/lib/secrets/session-store.js +0 -342
  241. package/dist/lib/secrets/sync-backend.d.ts +0 -48
  242. package/dist/lib/secrets/sync-backend.js +0 -13
  243. package/dist/lib/secrets/sync-commands.d.ts +0 -21
  244. package/dist/lib/secrets/sync-commands.js +0 -21
  245. package/dist/lib/secrets/sync.d.ts +0 -48
  246. package/dist/lib/secrets/sync.js +0 -237
  247. package/dist/lib/secrets/unlock-hints.d.ts +0 -27
  248. package/dist/lib/secrets/unlock-hints.js +0 -36
  249. package/dist/lib/secrets/usage-db.d.ts +0 -46
  250. package/dist/lib/secrets/usage-db.js +0 -96
  251. package/dist/lib/secrets/vault-age-helper.d.ts +0 -1
  252. package/dist/lib/secrets/vault-age-helper.js +0 -34
  253. package/dist/lib/secrets/vault.d.ts +0 -49
  254. package/dist/lib/secrets/vault.js +0 -399
  255. package/dist/lib/secrets/windows.d.ts +0 -81
  256. package/dist/lib/secrets/windows.js +0 -556
  257. package/scripts/install-helper.js +0 -97
  258. /package/dist/lib/{secrets/sync-passphrase.d.ts → sync-passphrase.d.ts} +0 -0
  259. /package/dist/lib/{secrets/sync-passphrase.js → sync-passphrase.js} +0 -0
@@ -11,8 +11,7 @@ import * as path from 'path';
11
11
  import * as yaml from 'yaml';
12
12
  import { capableAgents, supports } from './capabilities.js';
13
13
  import { getProjectAgentsDir, getSystemWorkflowsDir, getUserWorkflowsDir, getTrashWorkflowsDir, getEnabledExtraRepos, getPluginsDir, getSystemPluginsDir, getProjectPluginsDir, } from './state.js';
14
- import { listInstalledVersions, getVersionHomePath } from './installations/versions.js';
15
- import { dirsContentMatch, normalizeResourceContent } from './resource-content-diff.js';
14
+ import { listInstalledVersions } from './installations/versions.js';
16
15
  /**
17
16
  * Hard upper bound on items a single `for_each` expands, absent an explicit
18
17
  * `max_items`. A guard against a runaway producer spawning unbounded teammates
@@ -798,98 +797,9 @@ export function removeWorkflow(name) {
798
797
  * intentionally ignored. (Verified via strace of `agy`: it opens
799
798
  * `$HOME/.gemini/config/global_workflows/<name>.md` and never the version home.)
800
799
  */
801
- function antigravityWorkflowsDir() {
800
+ export function antigravityWorkflowsDir() {
802
801
  return path.join(process.env.HOME ?? os.homedir(), '.gemini', 'config', 'global_workflows');
803
802
  }
804
- function workflowTargetRoot(agent, versionHome) {
805
- if (agent === 'kimi')
806
- return path.join(versionHome, '.kimi-code', 'skills');
807
- if (agent === 'antigravity')
808
- return antigravityWorkflowsDir();
809
- if (agent === 'openclaw')
810
- return path.join(versionHome, '.openclaw', 'workflows');
811
- if (agent === 'grok')
812
- return path.join(versionHome, '.grok', 'workflows');
813
- return path.join(versionHome, 'workflows');
814
- }
815
- /** List workflow names synced into a specific agent version home. */
816
- export function listWorkflowsForAgent(agent, versionHome) {
817
- if (agent === 'kimi') {
818
- const skillsDir = workflowTargetRoot(agent, versionHome);
819
- if (!fs.existsSync(skillsDir))
820
- return [];
821
- return fs.readdirSync(skillsDir, { withFileTypes: true })
822
- .filter(d => d.isDirectory() && fs.existsSync(path.join(skillsDir, d.name, 'SKILL.md')))
823
- .filter(d => kimiWorkflowMarker(path.join(skillsDir, d.name, 'SKILL.md')) === d.name)
824
- .map(d => d.name);
825
- }
826
- if (agent === 'antigravity') {
827
- const dir = workflowTargetRoot(agent, versionHome);
828
- if (!fs.existsSync(dir))
829
- return [];
830
- try {
831
- return fs.readdirSync(dir, { withFileTypes: true })
832
- .filter(d => d.isFile() && d.name.endsWith('.md') && !d.name.startsWith('.'))
833
- .map(d => d.name.slice(0, -'.md'.length))
834
- .filter(base => antigravityWorkflowMarker(path.join(dir, `${base}.md`)) === base);
835
- }
836
- catch {
837
- return [];
838
- }
839
- }
840
- if (agent === 'goose') {
841
- const recipesDir = path.join(versionHome, '.config', 'goose', 'recipes');
842
- if (!fs.existsSync(recipesDir))
843
- return [];
844
- try {
845
- return fs.readdirSync(recipesDir, { withFileTypes: true })
846
- .filter(d => d.isFile() && d.name.endsWith('.yaml') && !d.name.startsWith('.'))
847
- .map(d => d.name.slice(0, -'.yaml'.length));
848
- }
849
- catch {
850
- return [];
851
- }
852
- }
853
- if (agent === 'openclaw') {
854
- const dir = workflowTargetRoot(agent, versionHome);
855
- if (!fs.existsSync(dir))
856
- return [];
857
- try {
858
- return fs.readdirSync(dir, { withFileTypes: true })
859
- .filter(d => d.isFile() && d.name.endsWith('.lobster') && !d.name.startsWith('.'))
860
- .map(d => d.name.slice(0, -'.lobster'.length))
861
- .filter(base => openclawWorkflowMarker(path.join(dir, `${base}.lobster`)) === base);
862
- }
863
- catch {
864
- return [];
865
- }
866
- }
867
- if (agent === 'grok') {
868
- const dir = workflowTargetRoot(agent, versionHome);
869
- if (!fs.existsSync(dir))
870
- return [];
871
- try {
872
- return fs.readdirSync(dir, { withFileTypes: true })
873
- .filter(d => d.isFile() && d.name.endsWith('.rhai') && !d.name.startsWith('.'))
874
- .map(d => d.name.slice(0, -'.rhai'.length))
875
- .filter(base => grokWorkflowMarker(path.join(dir, `${base}.rhai`)) === base);
876
- }
877
- catch {
878
- return [];
879
- }
880
- }
881
- const workflowsDir = workflowTargetRoot(agent, versionHome);
882
- if (!fs.existsSync(workflowsDir))
883
- return [];
884
- try {
885
- return fs.readdirSync(workflowsDir, { withFileTypes: true })
886
- .filter(d => d.isDirectory() && fs.existsSync(path.join(workflowsDir, d.name, 'WORKFLOW.md')))
887
- .map(d => d.name);
888
- }
889
- catch {
890
- return [];
891
- }
892
- }
893
803
  function parseSubrecipeFrontmatter(filePath) {
894
804
  const content = fs.readFileSync(filePath, 'utf-8');
895
805
  const lines = content.split('\n');
@@ -913,7 +823,7 @@ function parseSubrecipeFrontmatter(filePath) {
913
823
  body: lines.slice(endIndex + 2).join('\n').trim(),
914
824
  };
915
825
  }
916
- function selectedWorkflowSubagents(workflowPath, allowedAgents) {
826
+ export function selectedWorkflowSubagents(workflowPath, allowedAgents) {
917
827
  const subagentsDir = path.join(workflowPath, 'subagents');
918
828
  if (!fs.existsSync(subagentsDir))
919
829
  return [];
@@ -924,7 +834,7 @@ function selectedWorkflowSubagents(workflowPath, allowedAgents) {
924
834
  .filter(name => !allowed || allowed.has(name))
925
835
  .sort();
926
836
  }
927
- function writeGooseSubrecipe(workflowPath, subrecipeName, destDir) {
837
+ export function writeGooseSubrecipe(workflowPath, subrecipeName, destDir) {
928
838
  const sourcePath = path.join(workflowPath, 'subagents', `${subrecipeName}.md`);
929
839
  const parsed = parseSubrecipeFrontmatter(sourcePath);
930
840
  const body = parsed.body || parsed.description || subrecipeName;
@@ -939,12 +849,12 @@ function writeGooseSubrecipe(workflowPath, subrecipeName, destDir) {
939
849
  fs.writeFileSync(path.join(destDir, `${subrecipeName}.yaml`), yaml.stringify(recipe), 'utf-8');
940
850
  }
941
851
  /**
942
- * Render the main Goose recipe YAML for a workflow — the exact bytes
943
- * `syncWorkflowToGooseRecipe` writes to `<name>.yaml`. Extracted so the sync
944
- * writer and the doctor content-drift check (`workflowContentMatches`) render
945
- * from ONE source and can never disagree. Returns null on invalid frontmatter.
852
+ * Render the main Goose recipe YAML for a workflow — the exact bytes the Goose
853
+ * `WORKFLOW_TARGETS` entry writes to `<name>.yaml`. Extracted so the writer and
854
+ * the doctor content-drift check (`matches`) render from ONE source and can
855
+ * never disagree. Returns null on invalid frontmatter.
946
856
  */
947
- function renderGooseRecipeYaml(workflowPath, name) {
857
+ export function renderGooseRecipeYaml(workflowPath, name) {
948
858
  const frontmatter = parseWorkflowFrontmatter(workflowPath);
949
859
  if (!frontmatter)
950
860
  return null;
@@ -969,231 +879,6 @@ function renderGooseRecipeYaml(workflowPath, name) {
969
879
  }
970
880
  return yaml.stringify(recipe);
971
881
  }
972
- function syncWorkflowToGooseRecipe(workflowPath, name, versionHome) {
973
- const frontmatter = parseWorkflowFrontmatter(workflowPath);
974
- if (!frontmatter) {
975
- return { success: false, error: `Workflow '${name}' has invalid WORKFLOW.md frontmatter` };
976
- }
977
- const recipesDir = path.join(versionHome, '.config', 'goose', 'recipes');
978
- const recipePath = path.join(recipesDir, `${name}.yaml`);
979
- const subrecipesDir = path.join(recipesDir, `${name}.subrecipes`);
980
- const subagents = selectedWorkflowSubagents(workflowPath, frontmatter.allowedAgents);
981
- const recipeYaml = renderGooseRecipeYaml(workflowPath, name);
982
- if (recipeYaml == null) {
983
- return { success: false, error: `Workflow '${name}' has invalid WORKFLOW.md frontmatter` };
984
- }
985
- try {
986
- fs.mkdirSync(recipesDir, { recursive: true });
987
- if (fs.existsSync(subrecipesDir)) {
988
- fs.rmSync(subrecipesDir, { recursive: true, force: true });
989
- }
990
- for (const subagentName of subagents) {
991
- writeGooseSubrecipe(workflowPath, subagentName, subrecipesDir);
992
- }
993
- fs.writeFileSync(recipePath, recipeYaml, 'utf-8');
994
- return { success: true };
995
- }
996
- catch (err) {
997
- return { success: false, error: err.message };
998
- }
999
- }
1000
- /**
1001
- * True when workflow `name` materialized in `agent`'s version home byte-matches
1002
- * what the writer would produce NOW from `sourcePath` — the content-drift
1003
- * predicate `agents doctor` uses. Layout-aware per the same per-harness map the
1004
- * writer (`syncWorkflowToVersion`) and detector use: Claude/default copy the
1005
- * whole WORKFLOW.md tree (recursive dir compare); Kimi/Antigravity/OpenClaw/Grok
1006
- * render one transformed file; Goose renders a recipe YAML. Antigravity's target
1007
- * is the shared HOME-global dir, not a per-version path. Returns false when the
1008
- * home copy is absent (surfaced as `missing` at the name level, not here).
1009
- */
1010
- export function workflowContentMatches(agent, versionHome, name, sourcePath) {
1011
- const root = workflowTargetRoot(agent, versionHome);
1012
- const renderedMatches = (homePath, expected) => {
1013
- let actual;
1014
- try {
1015
- actual = fs.readFileSync(homePath, 'utf-8');
1016
- }
1017
- catch {
1018
- return false;
1019
- }
1020
- return normalizeResourceContent(actual) === normalizeResourceContent(expected);
1021
- };
1022
- switch (agent) {
1023
- case 'kimi':
1024
- return renderedMatches(path.join(root, name, 'SKILL.md'), transformWorkflowForKimi(sourcePath, name));
1025
- case 'antigravity':
1026
- return renderedMatches(path.join(root, `${name}.md`), transformWorkflowForAntigravity(sourcePath, name));
1027
- case 'openclaw':
1028
- return renderedMatches(path.join(root, `${name}.lobster`), transformWorkflowForOpenClaw(sourcePath, name));
1029
- case 'grok':
1030
- return renderedMatches(path.join(root, `${name}.rhai`), transformWorkflowForGrok(sourcePath, name));
1031
- case 'goose': {
1032
- const expected = renderGooseRecipeYaml(sourcePath, name);
1033
- if (expected == null)
1034
- return false;
1035
- return renderedMatches(path.join(versionHome, '.config', 'goose', 'recipes', `${name}.yaml`), expected);
1036
- }
1037
- default:
1038
- return dirsContentMatch(sourcePath, path.join(root, name));
1039
- }
1040
- }
1041
- /** Copy a workflow directory into a version home at {versionHome}/workflows/<name>/. */
1042
- export function syncWorkflowToVersion(workflowPath, name, agent, versionHome) {
1043
- if (agent === 'goose') {
1044
- return syncWorkflowToGooseRecipe(workflowPath, name, versionHome);
1045
- }
1046
- try {
1047
- if (agent === 'kimi') {
1048
- const targetDir = path.join(workflowTargetRoot(agent, versionHome), name);
1049
- const targetFile = path.join(targetDir, 'SKILL.md');
1050
- if (fs.existsSync(targetFile)) {
1051
- const marker = kimiWorkflowMarker(targetFile);
1052
- if (marker !== name) {
1053
- return { success: false, error: `Kimi skill '${name}' already exists and is not managed by agents-cli` };
1054
- }
1055
- }
1056
- fs.mkdirSync(targetDir, { recursive: true });
1057
- fs.writeFileSync(targetFile, transformWorkflowForKimi(workflowPath, name), 'utf-8');
1058
- return { success: true };
1059
- }
1060
- if (agent === 'antigravity') {
1061
- const targetDir = workflowTargetRoot(agent, versionHome);
1062
- const targetFile = path.join(targetDir, `${name}.md`);
1063
- if (fs.existsSync(targetFile)) {
1064
- const marker = antigravityWorkflowMarker(targetFile);
1065
- if (marker !== name) {
1066
- return { success: false, error: `Antigravity workflow '${name}' already exists and is not managed by agents-cli` };
1067
- }
1068
- }
1069
- fs.mkdirSync(targetDir, { recursive: true });
1070
- fs.writeFileSync(targetFile, transformWorkflowForAntigravity(workflowPath, name), 'utf-8');
1071
- return { success: true };
1072
- }
1073
- if (agent === 'openclaw') {
1074
- const targetDir = workflowTargetRoot(agent, versionHome);
1075
- const targetFile = path.join(targetDir, `${name}.lobster`);
1076
- if (fs.existsSync(targetFile)) {
1077
- const marker = openclawWorkflowMarker(targetFile);
1078
- if (marker !== name) {
1079
- return { success: false, error: `OpenClaw workflow '${name}' already exists and is not managed by agents-cli` };
1080
- }
1081
- }
1082
- fs.mkdirSync(targetDir, { recursive: true });
1083
- fs.writeFileSync(targetFile, transformWorkflowForOpenClaw(workflowPath, name), 'utf-8');
1084
- return { success: true };
1085
- }
1086
- if (agent === 'grok') {
1087
- const targetDir = workflowTargetRoot(agent, versionHome);
1088
- const targetFile = path.join(targetDir, `${name}.rhai`);
1089
- if (fs.existsSync(targetFile)) {
1090
- const marker = grokWorkflowMarker(targetFile);
1091
- if (marker !== name) {
1092
- return { success: false, error: `Grok workflow '${name}' already exists and is not managed by agents-cli` };
1093
- }
1094
- }
1095
- fs.mkdirSync(targetDir, { recursive: true });
1096
- fs.writeFileSync(targetFile, transformWorkflowForGrok(workflowPath, name), 'utf-8');
1097
- return { success: true };
1098
- }
1099
- const targetDir = path.join(workflowTargetRoot(agent, versionHome), name);
1100
- fs.mkdirSync(workflowTargetRoot(agent, versionHome), { recursive: true });
1101
- if (fs.existsSync(targetDir)) {
1102
- fs.rmSync(targetDir, { recursive: true, force: true });
1103
- }
1104
- fs.cpSync(workflowPath, targetDir, { recursive: true });
1105
- return { success: true };
1106
- }
1107
- catch (err) {
1108
- return { success: false, error: err.message };
1109
- }
1110
- }
1111
- /** Remove a workflow from a specific agent version home. */
1112
- export function removeWorkflowFromVersion(agent, version, name) {
1113
- const versionHome = getVersionHomePath(agent, version);
1114
- if (agent === 'antigravity') {
1115
- const targetFile = path.join(workflowTargetRoot(agent, versionHome), `${name}.md`);
1116
- if (!fs.existsSync(targetFile)) {
1117
- return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
1118
- }
1119
- if (antigravityWorkflowMarker(targetFile) !== name) {
1120
- return { success: false, error: `Antigravity workflow '${name}' is not managed by agents-cli` };
1121
- }
1122
- try {
1123
- fs.rmSync(targetFile, { force: true });
1124
- return { success: true };
1125
- }
1126
- catch (err) {
1127
- return { success: false, error: err.message };
1128
- }
1129
- }
1130
- if (agent === 'goose') {
1131
- const recipePath = path.join(versionHome, '.config', 'goose', 'recipes', `${name}.yaml`);
1132
- const subrecipesDir = path.join(versionHome, '.config', 'goose', 'recipes', `${name}.subrecipes`);
1133
- if (!fs.existsSync(recipePath) && !fs.existsSync(subrecipesDir)) {
1134
- return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
1135
- }
1136
- try {
1137
- if (fs.existsSync(recipePath))
1138
- fs.rmSync(recipePath, { force: true });
1139
- if (fs.existsSync(subrecipesDir))
1140
- fs.rmSync(subrecipesDir, { recursive: true, force: true });
1141
- return { success: true };
1142
- }
1143
- catch (err) {
1144
- return { success: false, error: err.message };
1145
- }
1146
- }
1147
- if (agent === 'openclaw') {
1148
- const targetFile = path.join(workflowTargetRoot(agent, versionHome), `${name}.lobster`);
1149
- if (!fs.existsSync(targetFile)) {
1150
- return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
1151
- }
1152
- if (openclawWorkflowMarker(targetFile) !== name) {
1153
- return { success: false, error: `OpenClaw workflow '${name}' is not managed by agents-cli` };
1154
- }
1155
- try {
1156
- fs.rmSync(targetFile, { force: true });
1157
- return { success: true };
1158
- }
1159
- catch (err) {
1160
- return { success: false, error: err.message };
1161
- }
1162
- }
1163
- if (agent === 'grok') {
1164
- const targetFile = path.join(workflowTargetRoot(agent, versionHome), `${name}.rhai`);
1165
- if (!fs.existsSync(targetFile)) {
1166
- return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
1167
- }
1168
- if (grokWorkflowMarker(targetFile) !== name) {
1169
- return { success: false, error: `Grok workflow '${name}' is not managed by agents-cli` };
1170
- }
1171
- try {
1172
- fs.rmSync(targetFile, { force: true });
1173
- return { success: true };
1174
- }
1175
- catch (err) {
1176
- return { success: false, error: err.message };
1177
- }
1178
- }
1179
- const targetPath = path.join(workflowTargetRoot(agent, versionHome), name);
1180
- if (!fs.existsSync(targetPath)) {
1181
- return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
1182
- }
1183
- try {
1184
- if (agent === 'kimi') {
1185
- const targetFile = path.join(targetPath, 'SKILL.md');
1186
- if (kimiWorkflowMarker(targetFile) !== name) {
1187
- return { success: false, error: `Kimi skill '${name}' is not managed by agents-cli` };
1188
- }
1189
- }
1190
- fs.rmSync(targetPath, { recursive: true, force: true });
1191
- return { success: true };
1192
- }
1193
- catch (err) {
1194
- return { success: false, error: err.message };
1195
- }
1196
- }
1197
882
  function parseSkillFrontmatter(filePath) {
1198
883
  const content = fs.readFileSync(filePath, 'utf-8');
1199
884
  const lines = content.split('\n');
@@ -1206,7 +891,7 @@ function parseSkillFrontmatter(filePath) {
1206
891
  const parsed = yaml.parse(frontmatter);
1207
892
  return parsed && typeof parsed === 'object' ? parsed : null;
1208
893
  }
1209
- function kimiWorkflowMarker(filePath) {
894
+ export function kimiWorkflowMarker(filePath) {
1210
895
  try {
1211
896
  const fm = parseSkillFrontmatter(filePath);
1212
897
  return fm?.type === 'flow' && typeof fm.agents_workflow === 'string' ? fm.agents_workflow : null;
@@ -1215,7 +900,7 @@ function kimiWorkflowMarker(filePath) {
1215
900
  return null;
1216
901
  }
1217
902
  }
1218
- function antigravityWorkflowMarker(filePath) {
903
+ export function antigravityWorkflowMarker(filePath) {
1219
904
  try {
1220
905
  const fm = parseSkillFrontmatter(filePath);
1221
906
  return typeof fm?.agents_workflow === 'string' ? fm.agents_workflow : null;
@@ -1224,7 +909,7 @@ function antigravityWorkflowMarker(filePath) {
1224
909
  return null;
1225
910
  }
1226
911
  }
1227
- function openclawWorkflowMarker(filePath) {
912
+ export function openclawWorkflowMarker(filePath) {
1228
913
  try {
1229
914
  const parsed = yaml.parse(fs.readFileSync(filePath, 'utf-8'));
1230
915
  if (!parsed || typeof parsed !== 'object' || !parsed.env || typeof parsed.env !== 'object' || Array.isArray(parsed.env)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phnx-labs/agents-cli",
3
- "version": "1.22.84",
3
+ "version": "1.22.86",
4
4
  "description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -43,7 +43,7 @@
43
43
  "url": "https://github.com/phnx-labs/agi-cli/issues"
44
44
  },
45
45
  "scripts": {
46
- "build": "tsc && rm -rf 'dist/lib/secrets/AgentsKeychain.app' 'dist/lib/secrets/Agents CLI.app' 'dist/lib/menubar/MenubarHelper.app' && ([ -f 'bin/agents-macos' ] && mkdir -p dist/bin && cp -f 'bin/agents-macos' 'dist/bin/agents' && chmod 755 'dist/bin/agents' || true)",
46
+ "build": "tsc && rm -rf 'dist/lib/menubar/MenubarHelper.app' && ([ -f 'bin/agents-macos' ] && mkdir -p dist/bin && cp -f 'bin/agents-macos' 'dist/bin/agents' && chmod 755 'dist/bin/agents' || true)",
47
47
  "build:bin": "scripts/build-bin.sh",
48
48
  "prepare": "npm run build",
49
49
  "prepack": "cp ../README.md README.md",
@@ -95,7 +95,6 @@
95
95
  "@xterm/headless": "6.0.0",
96
96
  "@zed-industries/agent-client-protocol": "0.4.5",
97
97
  "acorn": "8.18.0",
98
- "age-encryption": "0.3.0",
99
98
  "aws4fetch": "1.0.20",
100
99
  "chalk": "5.6.2",
101
100
  "commander": "15.0.0",
@@ -22,7 +22,6 @@ const AGENTS_JS_ENTRYPOINT = fileURLToPath(new URL('../dist/index.js', import.me
22
22
  // is what EDR (CrowdStrike Falcon) flags when an editor child spawns it (#315).
23
23
  const AGENTS_NATIVE_MACOS_BIN = fileURLToPath(new URL('../dist/bin/agents', import.meta.url));
24
24
  const AGENTS_BIN = resolveAgentsBin();
25
- const INSTALL_HELPER_SCRIPT = fileURLToPath(new URL('./install-helper.js', import.meta.url));
26
25
 
27
26
  function resolveAgentsBin() {
28
27
  if (process.platform !== 'darwin') return AGENTS_JS_ENTRYPOINT;
@@ -46,23 +45,44 @@ function resolveAgentsBin() {
46
45
  return AGENTS_JS_ENTRYPOINT;
47
46
  }
48
47
 
49
- function installKeychainHelper() {
50
- if (process.platform !== 'darwin') return;
51
- if (!fs.existsSync(INSTALL_HELPER_SCRIPT)) return;
52
- // Sub-process so a hard failure (codesign / spctl missing on a weird host)
53
- // can't take down the rest of postinstall. install-helper.js stays silent
54
- // on no-op and emits one stdout line on success.
55
- spawnSync(process.execPath, [INSTALL_HELPER_SCRIPT], { stdio: 'inherit' });
56
- }
57
-
58
48
  function shellQuote(value) {
59
49
  return `'${value.replace(/'/g, `'\\''`)}'`;
60
50
  }
61
51
 
62
52
  // Shorthands that delegate to the installed agents-cli entrypoint.
63
- const ALIASES = ['sessions', 'secrets', 'browser', 'pty', 'teams'];
53
+ const ALIASES = ['sessions', 'browser', 'pty', 'teams'];
54
+
55
+ // Aliases this script USED to write and must now remove on every install.
56
+ // `secrets`: the name belongs to the standalone `@phnx-labs/secrets-cli` binary
57
+ // (PHNX-3989); `agents secrets` is a passthrough to it, so an alias shim that
58
+ // `exec`s `agents secrets` can only re-enter the passthrough, and it shadows the
59
+ // real `secrets` bin because the shims dir sits first on PATH. The self-heal
60
+ // shim pass prunes it too, but that only runs from a daemon or a TTY session —
61
+ // postinstall is what every upgrade path actually executes, so it cleans up here.
62
+ const RETIRED_ALIASES = ['secrets'];
63
+
64
+ function removeRetiredAliasShims() {
65
+ for (const name of RETIRED_ALIASES) {
66
+ for (const file of [path.join(SHIMS_DIR, name), path.join(SHIMS_DIR, name + '.cmd')]) {
67
+ let content;
68
+ try {
69
+ content = fs.readFileSync(file, 'utf8');
70
+ } catch {
71
+ continue;
72
+ }
73
+ // Only ever remove OUR alias — the POSIX shim ends in `<name> "$@"`, the
74
+ // Windows companion in `<name> %*` — never an unrelated file someone placed
75
+ // under that name, and never a user's own `agents setup alias` shim, which
76
+ // is marked `# Alias shim:` (the same guard pruneOrphanedCommandShim keeps).
77
+ if (content.includes('# Alias shim:')) continue;
78
+ if (!content.includes(`${name} "$@"`) && !content.includes(`${name} %*`)) continue;
79
+ fs.rmSync(file, { force: true });
80
+ }
81
+ }
82
+ }
64
83
 
65
84
  function writeAliasShims() {
85
+ removeRetiredAliasShims();
66
86
  const written = [];
67
87
  for (const name of ALIASES) {
68
88
  const target = path.join(SHIMS_DIR, name);
@@ -93,7 +113,6 @@ const isGlobalInstall = process.env.npm_config_global || process.argv.includes('
93
113
  if (!isGlobalInstall) {
94
114
  // Still create user directories for local installs
95
115
  fs.mkdirSync(USER_DIR, { recursive: true, mode: 0o700 });
96
- installKeychainHelper();
97
116
  console.log(`
98
117
  agents-cli installed locally.
99
118
  To complete setup, run: npx agents setup
@@ -115,10 +134,6 @@ To complete setup, run: npx agents setup
115
134
  fs.mkdirSync(USER_DIR, { recursive: true, mode: 0o700 });
116
135
  fs.mkdirSync(SHIMS_DIR, { recursive: true });
117
136
 
118
- // Copy the signed macOS Keychain helper to a stable user path so its trusted-app
119
- // ACLs survive future npm publishes (which re-sign the bundle).
120
- installKeychainHelper();
121
-
122
137
  const shellName = path.basename(process.env.SHELL || '/bin/bash');
123
138
 
124
139
  function getShellRc() {
@@ -377,10 +392,12 @@ function retargetManagedLinksToNativeBin() {
377
392
  /**
378
393
  * Self-heal long-running processes onto the just-installed code (darwin + linux).
379
394
  *
380
- * The root cause behind stale-behavior bugs is a daemon/broker that keeps
395
+ * The root cause behind stale-behavior bugs is a daemon that keeps
381
396
  * running pre-upgrade code for days. An in-place `npm i -g` swaps the files but
382
397
  * not the running processes — so we bounce them here, the one moment we know the
383
- * code just changed. Always start (or restart) the supervised daemon so a fresh
398
+ * code just changed. (The secrets broker is not one of them — the standalone
399
+ * `secrets` CLI owns its own broker lifecycle, PHNX-3989.) Always start (or
400
+ * restart) the supervised daemon so a fresh
384
401
  * install gets launchd/systemd KeepAlive without waiting for routines add.
385
402
  * Best-effort and non-fatal: a failure must never break the install. Skipped in
386
403
  * CI and when AGENTS_NO_HEAL=1. Windows is out of scope (detached-only, no KeepAlive).
@@ -389,18 +406,6 @@ async function healLongRunningProcesses() {
389
406
  if (process.platform !== 'darwin' && process.platform !== 'linux') return;
390
407
  if (process.env.CI || process.env.AGENTS_NO_HEAL === '1') return;
391
408
 
392
- // Retire the legacy standalone secrets-agent service FIRST (#416 step 2) so
393
- // that when the daemon (re)starts below its coexistence guard sees no
394
- // standalone broker and hosts the broker socket itself. No-op if no legacy
395
- // plist is present; never blocks. Darwin-only in practice (launchd service).
396
- try {
397
- const a = await import('../dist/lib/secrets/agent.js');
398
- if (a.secretsAgentServiceInstalled?.()) {
399
- a.retireLegacySecretsAgentService?.();
400
- console.log(' Retired the standalone secrets-agent service — the daemon now hosts the broker.');
401
- }
402
- } catch { /* best effort */ }
403
-
404
409
  // Always (re)start so first install writes the LaunchAgent/systemd unit and
405
410
  // upgrades bounce onto the new binary — but honor daemon.enabled for cold
406
411
  // starts (SING-4a). If it was already running under a disable, stop and leave
@@ -1,18 +0,0 @@
1
- /**
2
- * `agents secrets import-keyring` — migrate agents-cli secrets out of the native
3
- * credential store (GNOME Keyring / Windows Credential Manager) and into the
4
- * encrypted file store.
5
- *
6
- * Why: on headless Linux/Windows the file store is the durable, passwordless
7
- * backend, but secrets written earlier (e.g. while a desktop keyring was
8
- * unlocked) can linger in the native store where a headless session can't reach
9
- * them. This is the Linux/Windows analogue of the macOS `migrate-acl` /
10
- * orphan sweep. Dry-run by default; `--commit` performs the copy.
11
- *
12
- * Requires the native store to be reachable/unlocked — a locked keyring can't be
13
- * read, so unlock it first (or the values are already only in the file store and
14
- * there is nothing to do).
15
- */
16
- import type { Command } from 'commander';
17
- /** Register `agents secrets import-keyring` on the parent secrets Command. */
18
- export declare function registerSecretsImportKeyringCommand(secrets: Command): void;
@@ -1,74 +0,0 @@
1
- /**
2
- * `agents secrets import-keyring` — migrate agents-cli secrets out of the native
3
- * credential store (GNOME Keyring / Windows Credential Manager) and into the
4
- * encrypted file store.
5
- *
6
- * Why: on headless Linux/Windows the file store is the durable, passwordless
7
- * backend, but secrets written earlier (e.g. while a desktop keyring was
8
- * unlocked) can linger in the native store where a headless session can't reach
9
- * them. This is the Linux/Windows analogue of the macOS `migrate-acl` /
10
- * orphan sweep. Dry-run by default; `--commit` performs the copy.
11
- *
12
- * Requires the native store to be reachable/unlocked — a locked keyring can't be
13
- * read, so unlock it first (or the values are already only in the file store and
14
- * there is nothing to do).
15
- */
16
- import chalk from 'chalk';
17
- import { importNativeItems } from '../lib/secrets/index.js';
18
- /** Register `agents secrets import-keyring` on the parent secrets Command. */
19
- export function registerSecretsImportKeyringCommand(secrets) {
20
- secrets
21
- .command('import-keyring')
22
- .description('Migrate agents-cli secrets from the OS keyring / Credential Manager into the encrypted file store (headless-safe). Dry-run by default.')
23
- .option('--commit', 'Perform the import (default is dry-run reporting only)')
24
- .option('--prefix <p>', 'Only import items beginning with PREFIX (default: all agents-cli items)')
25
- .action((opts) => {
26
- try {
27
- if (process.platform === 'darwin') {
28
- throw new Error('import-keyring is for the Linux/Windows file-store fallback. On macOS use `agents secrets migrate-acl`.');
29
- }
30
- const commit = !!opts.commit;
31
- const report = importNativeItems(opts.prefix ?? '', commit);
32
- if (!report.available) {
33
- console.log(chalk.gray('No native credential tooling found (secret-tool / PowerShell) — nothing to import.'));
34
- return;
35
- }
36
- if (report.locked) {
37
- console.error(chalk.yellow('The native credential store is locked/unreachable, so its secrets can\'t be read. ' +
38
- 'Unlock it and retry (a locked store can\'t be migrated).'));
39
- process.exit(1);
40
- }
41
- if (report.results.length === 0) {
42
- console.log(chalk.green('Nothing to import — no native secrets outside the file store.'));
43
- return;
44
- }
45
- const imported = report.results.filter((r) => r.status === 'imported' || r.status === 'would-import');
46
- const existing = report.results.filter((r) => r.status === 'exists');
47
- const failed = report.results.filter((r) => r.status === 'failed');
48
- for (const r of report.results) {
49
- if (r.status === 'imported')
50
- console.log(` ${chalk.green('imported')} ${r.item}`);
51
- else if (r.status === 'would-import')
52
- console.log(` ${chalk.cyan('would import')} ${r.item}`);
53
- else if (r.status === 'exists')
54
- console.log(` ${chalk.gray('exists')} ${r.item} ${chalk.gray('(already in file store)')}`);
55
- else
56
- console.log(` ${chalk.red('failed')} ${r.item} ${chalk.gray(r.detail ?? '')}`);
57
- }
58
- console.log();
59
- if (!commit) {
60
- console.log(chalk.gray(`Dry-run: ${imported.length} would be imported, ${existing.length} already present, ${failed.length} unreadable. Pass --commit to write.`));
61
- return;
62
- }
63
- if (failed.length > 0) {
64
- console.error(chalk.yellow(`Imported ${imported.length}; ${existing.length} already present; ${failed.length} failed.`));
65
- process.exit(1);
66
- }
67
- console.log(chalk.green(`Imported ${imported.length} secret(s) into the file store (${existing.length} already present).`));
68
- }
69
- catch (err) {
70
- console.error(chalk.red(err.message));
71
- process.exit(1);
72
- }
73
- });
74
- }
@@ -1,25 +0,0 @@
1
- /**
2
- * `agents secrets migrate-acl` — refresh existing keychain items so they pick
3
- * up the new SecAccess ACL written by the signed Agents CLI.app helper.
4
- *
5
- * Items created before 1.19.2 (or by `security add-generic-password` directly)
6
- * may carry the legacy "this-app-only" ACL that prompts the user for a
7
- * password on every read. Re-writing them through the helper bakes in the
8
- * empty trusted-app ACL that suppresses the prompt and lets the helper read
9
- * them under LocalAuthentication instead.
10
- *
11
- * Sequence per item:
12
- * 1. Read the current value (no auth prompt path — uses the unauthenticated
13
- * `security` CLI for non-sync items, helper `get` for sync items).
14
- * 2. Append (item, value, sync) to an encrypted backup before any writes.
15
- * 3. Delete + rewrite via the helper so macOS hands us a fresh ACL on the
16
- * new item.
17
- * 4. Read back via the helper to verify the value round-trips.
18
- *
19
- * `--dry-run` (default) reports the planned actions. `--commit` performs the
20
- * writes and produces the backup.
21
- */
22
- import type { Command } from 'commander';
23
- /** Register the keychain-migration commands (`migrate-acl`, `rekey`) on the
24
- * parent secrets Command. */
25
- export declare function registerSecretsMigrateAclCommand(secrets: Command): void;