@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,399 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { spawnSync } from 'child_process';
4
- import { armor } from 'age-encryption';
5
- import { getUserAgentsDir } from '../state.js';
6
- import { getCliLaunch } from '../cli-entry.js';
7
- import { atomicWriteFileSync, withFileLock } from '../fs-atomic.js';
8
- import { deleteKeychainToken, getKeychainToken, setKeychainToken, } from './index.js';
9
- const VAULT_FILE_NAME = 'vault.age';
10
- const VAULT_SESSION_ITEM = 'agents-cli.vault.session';
11
- export const VAULT_SESSION_TTL_MS = 8 * 60 * 60 * 1000;
12
- export const VAULT_SCRYPT_WORK_FACTOR = 18;
13
- const VAULT_LOCK_STALE_MS = 120_000;
14
- const VAULT_LOCK_ACQUIRE_TIMEOUT_MS = 180_000;
15
- let overrideVaultPath = null;
16
- let vaultDataCache = null;
17
- let ageOperationCountForTest = 0;
18
- let ageHelperLaunchForTest = null;
19
- export function vaultPath() {
20
- return overrideVaultPath ?? process.env.AGENTS_VAULT_PATH ?? path.join(getUserAgentsDir(), VAULT_FILE_NAME);
21
- }
22
- export function vaultExists() {
23
- return fs.existsSync(vaultPath());
24
- }
25
- export function _setVaultPathForTest(filePath) {
26
- overrideVaultPath = filePath;
27
- clearVaultDataCache();
28
- }
29
- export function _clearVaultDataCacheForTest() {
30
- clearVaultDataCache();
31
- }
32
- export function _resetVaultAgeOperationCountForTest() {
33
- ageOperationCountForTest = 0;
34
- }
35
- export function _getVaultAgeOperationCountForTest() {
36
- return ageOperationCountForTest;
37
- }
38
- export function _setVaultAgeHelperLaunchForTest(launch) {
39
- ageHelperLaunchForTest = launch;
40
- }
41
- function emptyVault() {
42
- return { v: 1, bundles: {} };
43
- }
44
- function parseVault(raw) {
45
- let parsed;
46
- try {
47
- parsed = JSON.parse(raw);
48
- }
49
- catch {
50
- throw new Error('Vault content is malformed.');
51
- }
52
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
53
- throw new Error('Vault content has an invalid shape.');
54
- }
55
- const obj = parsed;
56
- if (obj.v !== 1 || !obj.bundles || typeof obj.bundles !== 'object' || Array.isArray(obj.bundles)) {
57
- throw new Error('Vault content has an invalid shape.');
58
- }
59
- const bundles = {};
60
- for (const [name, record] of Object.entries(obj.bundles)) {
61
- if (!record || typeof record !== 'object' || Array.isArray(record)) {
62
- throw new Error(`Vault bundle '${name}' has an invalid shape.`);
63
- }
64
- const rec = record;
65
- if (rec.metadata !== undefined && typeof rec.metadata !== 'string') {
66
- throw new Error(`Vault bundle '${name}' metadata is invalid.`);
67
- }
68
- if (!rec.keys || typeof rec.keys !== 'object' || Array.isArray(rec.keys)) {
69
- throw new Error(`Vault bundle '${name}' keys are invalid.`);
70
- }
71
- const keys = {};
72
- for (const [key, value] of Object.entries(rec.keys)) {
73
- if (typeof value !== 'string')
74
- throw new Error(`Vault key '${name}.${key}' is invalid.`);
75
- keys[key] = value;
76
- }
77
- bundles[name] = { metadata: rec.metadata, keys };
78
- }
79
- return { v: 1, bundles };
80
- }
81
- function runAgeSync(input) {
82
- ageOperationCountForTest++;
83
- const launch = ageHelperLaunchForTest ?? getCliLaunch(['__vault-age-helper']);
84
- const child = spawnSync(launch.command, launch.args, {
85
- input: JSON.stringify(input),
86
- encoding: 'utf-8',
87
- stdio: ['pipe', 'pipe', 'pipe'],
88
- });
89
- if (child.status !== 0) {
90
- const msg = child.stderr.trim();
91
- throw new Error(msg || child.error?.message || 'age operation failed');
92
- }
93
- return child.stdout;
94
- }
95
- export function encrypt(key, json) {
96
- return runAgeSync({
97
- action: 'encrypt',
98
- passphrase: key.passphrase,
99
- plaintext: JSON.stringify(json),
100
- scryptWorkFactor: VAULT_SCRYPT_WORK_FACTOR,
101
- });
102
- }
103
- export function decrypt(key, blob) {
104
- try {
105
- // Validate armor in-process so malformed files fail before spawning.
106
- armor.decode(blob);
107
- const plaintext = runAgeSync({
108
- action: 'decrypt',
109
- passphrase: key.passphrase,
110
- blob,
111
- });
112
- return parseVault(plaintext);
113
- }
114
- catch (err) {
115
- throw new Error(`Failed to decrypt vault. Wrong password or tampered vault file. (${err.message})`);
116
- }
117
- }
118
- function vaultFileStat(file) {
119
- const stat = fs.statSync(file);
120
- return { mtimeMs: stat.mtimeMs, size: stat.size };
121
- }
122
- function sameVaultFileStat(a, b) {
123
- return a.mtimeMs === b.mtimeMs && a.size === b.size;
124
- }
125
- function clearVaultDataCache() {
126
- vaultDataCache = null;
127
- }
128
- function cacheVaultData(file, key, data) {
129
- vaultDataCache = {
130
- file,
131
- passphrase: key.passphrase,
132
- stat: vaultFileStat(file),
133
- data,
134
- };
135
- }
136
- function vaultAlreadyExistsError(file) {
137
- return new Error(`Vault file already exists: ${file}. Use --force to replace it.`);
138
- }
139
- export function createVault(password, opts = {}) {
140
- if (!password)
141
- throw new Error('Password is required.');
142
- const file = vaultPath();
143
- if (!opts.overwrite && fs.existsSync(file))
144
- throw vaultAlreadyExistsError(file);
145
- fs.mkdirSync(path.dirname(file), { recursive: true });
146
- const key = { passphrase: password };
147
- const data = emptyVault();
148
- const blob = encrypt(key, data);
149
- try {
150
- fs.writeFileSync(file, blob, { mode: 0o600, flag: opts.overwrite ? 'w' : 'wx' });
151
- }
152
- catch (err) {
153
- if (err.code === 'EEXIST')
154
- throw vaultAlreadyExistsError(file);
155
- throw err;
156
- }
157
- cacheVaultData(file, key, data);
158
- cacheVaultKey(key);
159
- return key;
160
- }
161
- export function joinVault(password, sourcePath, opts = {}) {
162
- if (!password)
163
- throw new Error('Password is required.');
164
- const source = path.resolve(sourcePath);
165
- const dest = vaultPath();
166
- if (!opts.overwrite && fs.existsSync(dest))
167
- throw vaultAlreadyExistsError(dest);
168
- const blob = fs.readFileSync(source, 'utf-8');
169
- const key = { passphrase: password };
170
- const data = decrypt(key, blob);
171
- fs.mkdirSync(path.dirname(dest), { recursive: true });
172
- try {
173
- fs.copyFileSync(source, dest, opts.overwrite ? 0 : fs.constants.COPYFILE_EXCL);
174
- }
175
- catch (err) {
176
- if (err.code === 'EEXIST')
177
- throw vaultAlreadyExistsError(dest);
178
- throw err;
179
- }
180
- fs.chmodSync(dest, 0o600);
181
- cacheVaultData(dest, key, data);
182
- cacheVaultKey(key);
183
- return key;
184
- }
185
- export function unlock(password) {
186
- if (!password)
187
- throw new Error('Password is required.');
188
- const file = vaultPath();
189
- if (!fs.existsSync(file))
190
- throw new Error(`Vault file not found: ${file}`);
191
- const key = { passphrase: password };
192
- const data = decrypt(key, fs.readFileSync(file, 'utf-8'));
193
- cacheVaultData(file, key, data);
194
- cacheVaultKey(key);
195
- return key;
196
- }
197
- export function cacheVaultKey(key, ttlMs = VAULT_SESSION_TTL_MS) {
198
- const session = {
199
- v: 1,
200
- passphrase: key.passphrase,
201
- expiresAt: Date.now() + ttlMs,
202
- };
203
- setKeychainToken(VAULT_SESSION_ITEM, JSON.stringify(session), { noAcl: true });
204
- }
205
- export function clearVaultKey() {
206
- clearVaultDataCache();
207
- deleteKeychainToken(VAULT_SESSION_ITEM);
208
- }
209
- export function getVaultSession() {
210
- let raw;
211
- try {
212
- // Written no-ACL (cacheVaultKey) — the vault session probe runs inside bundleBackend
213
- // for EVERY bundle op, headless included, so it must stay silent.
214
- raw = getKeychainToken(VAULT_SESSION_ITEM, { silentNoAcl: true });
215
- }
216
- catch {
217
- return { loggedIn: false };
218
- }
219
- let parsed;
220
- try {
221
- parsed = JSON.parse(raw);
222
- }
223
- catch {
224
- clearVaultKey();
225
- return { loggedIn: false };
226
- }
227
- if (parsed.v !== 1 || typeof parsed.passphrase !== 'string' || typeof parsed.expiresAt !== 'number') {
228
- clearVaultKey();
229
- return { loggedIn: false };
230
- }
231
- if (parsed.expiresAt <= Date.now()) {
232
- clearVaultKey();
233
- return { loggedIn: false, expiresAt: parsed.expiresAt };
234
- }
235
- return { loggedIn: true, key: { passphrase: parsed.passphrase }, expiresAt: parsed.expiresAt };
236
- }
237
- function requireVaultKey() {
238
- const session = getVaultSession();
239
- if (!session.loggedIn) {
240
- throw new Error('Synced secrets locked. Run: agents secrets vault unlock');
241
- }
242
- return session.key;
243
- }
244
- function parseVaultItem(item) {
245
- const metaPrefix = 'agents-cli.bundles.';
246
- const keyPrefix = 'agents-cli.secrets.';
247
- if (item.startsWith(metaPrefix)) {
248
- return { kind: 'meta', bundle: item.slice(metaPrefix.length) };
249
- }
250
- if (item.startsWith(keyPrefix)) {
251
- const rest = item.slice(keyPrefix.length);
252
- const dot = rest.lastIndexOf('.');
253
- if (dot <= 0 || dot >= rest.length - 1)
254
- return null;
255
- return { kind: 'key', bundle: rest.slice(0, dot), key: rest.slice(dot + 1) };
256
- }
257
- return null;
258
- }
259
- function vaultMissingError(file) {
260
- return new Error(`Vault file is missing: ${file}. A vault was created but the file is gone` +
261
- ' (a sync conflict, an undownloaded placeholder, or an accidental move/delete).' +
262
- ' Restore it before writing, or run: agents secrets vault unlock --create --force to start over.');
263
- }
264
- function readVaultData() {
265
- const file = vaultPath();
266
- if (!fs.existsSync(file)) {
267
- // A live session means a vault was created/joined/unlocked, so the file
268
- // must exist. If it is gone, refuse rather than silently starting from an
269
- // empty vault (which a subsequent write would persist, destroying data).
270
- if (getVaultSession().loggedIn)
271
- throw vaultMissingError(file);
272
- return emptyVault();
273
- }
274
- const key = requireVaultKey();
275
- const stat = vaultFileStat(file);
276
- if (vaultDataCache &&
277
- vaultDataCache.file === file &&
278
- vaultDataCache.passphrase === key.passphrase &&
279
- sameVaultFileStat(vaultDataCache.stat, stat)) {
280
- return vaultDataCache.data;
281
- }
282
- const data = decrypt(key, fs.readFileSync(file, 'utf-8'));
283
- vaultDataCache = { file, passphrase: key.passphrase, stat, data };
284
- return data;
285
- }
286
- function writeVaultData(data) {
287
- const file = vaultPath();
288
- const key = requireVaultKey();
289
- fs.mkdirSync(path.dirname(file), { recursive: true });
290
- atomicWriteFileSync(file, encrypt(key, data), { encoding: 'utf-8', mode: 0o600 });
291
- cacheVaultData(file, key, data);
292
- }
293
- function withVaultMutation(mutate) {
294
- const file = vaultPath();
295
- requireVaultKey();
296
- if (!fs.existsSync(file))
297
- throw vaultMissingError(file);
298
- return withFileLock(file, () => {
299
- const data = readVaultData();
300
- const { changed, result } = mutate(data);
301
- if (changed)
302
- writeVaultData(data);
303
- return result;
304
- }, { staleMs: VAULT_LOCK_STALE_MS, acquireTimeoutMs: VAULT_LOCK_ACQUIRE_TIMEOUT_MS });
305
- }
306
- export function vaultHasItem(item) {
307
- const parsed = parseVaultItem(item);
308
- if (!parsed)
309
- return false;
310
- const data = readVaultData();
311
- const bundle = data.bundles[parsed.bundle];
312
- if (!bundle)
313
- return false;
314
- return parsed.kind === 'meta' ? bundle.metadata !== undefined : parsed.key in bundle.keys;
315
- }
316
- export function vaultGetItem(item) {
317
- const parsed = parseVaultItem(item);
318
- if (!parsed)
319
- throw new Error(`Vault item '${item}' is invalid.`);
320
- const data = readVaultData();
321
- const bundle = data.bundles[parsed.bundle];
322
- const value = parsed.kind === 'meta' ? bundle?.metadata : bundle?.keys[parsed.key];
323
- if (value === undefined)
324
- throw new Error(`Vault item '${item}' not found.`);
325
- return value;
326
- }
327
- export function vaultGetItems(items) {
328
- const data = readVaultData();
329
- const out = new Map();
330
- for (const item of items) {
331
- const parsed = parseVaultItem(item);
332
- if (!parsed)
333
- continue;
334
- const bundle = data.bundles[parsed.bundle];
335
- const value = parsed.kind === 'meta' ? bundle?.metadata : bundle?.keys[parsed.key];
336
- if (value !== undefined)
337
- out.set(item, value);
338
- }
339
- return out;
340
- }
341
- export function vaultSetItem(item, value) {
342
- vaultSetItems(new Map([[item, value]]));
343
- }
344
- export function vaultSetItems(items) {
345
- if (items.size === 0)
346
- return;
347
- withVaultMutation((data) => {
348
- for (const [item, value] of items) {
349
- const parsed = parseVaultItem(item);
350
- if (!parsed)
351
- throw new Error(`Vault item '${item}' is invalid.`);
352
- const bundle = data.bundles[parsed.bundle] ?? { keys: {} };
353
- if (parsed.kind === 'meta')
354
- bundle.metadata = value;
355
- else
356
- bundle.keys[parsed.key] = value;
357
- data.bundles[parsed.bundle] = bundle;
358
- }
359
- return { changed: true, result: undefined };
360
- });
361
- }
362
- export function vaultDeleteItem(item) {
363
- const parsed = parseVaultItem(item);
364
- if (!parsed)
365
- return false;
366
- return withVaultMutation((data) => {
367
- const bundle = data.bundles[parsed.bundle];
368
- if (!bundle)
369
- return { changed: false, result: false };
370
- let deleted = false;
371
- if (parsed.kind === 'meta') {
372
- deleted = bundle.metadata !== undefined;
373
- delete bundle.metadata;
374
- }
375
- else {
376
- deleted = parsed.key in bundle.keys;
377
- delete bundle.keys[parsed.key];
378
- }
379
- if (bundle.metadata === undefined && Object.keys(bundle.keys).length === 0) {
380
- delete data.bundles[parsed.bundle];
381
- }
382
- return { changed: deleted, result: deleted };
383
- });
384
- }
385
- export function vaultListItems(prefix) {
386
- const data = readVaultData();
387
- const out = [];
388
- for (const [bundleName, bundle] of Object.entries(data.bundles)) {
389
- const meta = `agents-cli.bundles.${bundleName}`;
390
- if (bundle.metadata !== undefined && meta.startsWith(prefix))
391
- out.push(meta);
392
- for (const key of Object.keys(bundle.keys)) {
393
- const item = `agents-cli.secrets.${bundleName}.${key}`;
394
- if (item.startsWith(prefix))
395
- out.push(item);
396
- }
397
- }
398
- return out.sort();
399
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * Windows secret storage via Windows Credential Manager (wincred).
3
- *
4
- * Primary backend: the Credential Manager `advapi32` API (CredReadW /
5
- * CredWriteW / CredDeleteW / CredEnumerateW), reached through a static
6
- * PowerShell script that P/Invokes the C# shim below. PowerShell (Windows
7
- * PowerShell 5.1) ships with every supported Windows, so there is no separate
8
- * install step. Items are stored as CRED_TYPE_GENERIC with
9
- * CRED_PERSIST_LOCAL_MACHINE — device-local, matching the biometry-bound model
10
- * on macOS (src/lib/secrets/index.ts).
11
- *
12
- * Zero injection surface: the PS script is a single STATIC constant. All
13
- * dynamic data rides in the child ENV (target name, list prefix) or STDIN (the
14
- * secret value) — nothing is string-interpolated into the script. The child is
15
- * spawned with a spawnSync ARGV ARRAY (`-EncodedCommand <base64>`), never a
16
- * shell string.
17
- *
18
- * Headless fallback: when Credential Manager is unreachable (no logon session —
19
- * ERROR_NO_SUCH_LOGON_SESSION 1312 — or powershell.exe missing from PATH), we
20
- * transparently switch to the AES-256-GCM encrypted-file store in
21
- * ./filestore.ts, exactly like the Linux locked-collection fallback. The
22
- * decision is cached per process; one stderr line is emitted the first time.
23
- *
24
- * Item names are stored VERBATIM as the credential TargetName
25
- * (`agents-cli.bundles.<name>` / `agents-cli.secrets.<bundle>.<key>` — the
26
- * scheme shared with the file store, see ./filestore.ts) so `list` returns item
27
- * names directly.
28
- */
29
- import type { KeychainBackend } from './index.js';
30
- import { type NativeImportReport } from './fallback.js';
31
- export { encryptForFallback, decryptForFallback, fileBackend, type EncFile, } from './filestore.js';
32
- /**
33
- * CRED_MAX_CREDENTIAL_BLOB_SIZE — Credential Manager rejects a generic
34
- * credential blob larger than 2560 bytes with an opaque CredWrite failure. We
35
- * guard against it in `set` with a clear message. Only pathologically large
36
- * bundle metadata could hit this; such an item should live in a file-backed
37
- * bundle (AGENTS_SECRETS_PASSPHRASE) instead.
38
- */
39
- export declare const CRED_MAX_CREDENTIAL_BLOB_SIZE = 2560;
40
- /**
41
- * True when secret operations currently route to the encrypted-file store
42
- * instead of Windows Credential Manager. Mirrors linux.ts:usesFileFallback so
43
- * `listBundles()` doesn't double-count file-backed bundles under the fallback.
44
- */
45
- export declare function usesFileFallback(): boolean;
46
- export declare function hasCredManToken(item: string): boolean;
47
- export declare function getCredManToken(item: string): string;
48
- export declare function setCredManToken(item: string, value: string): void;
49
- export declare function deleteCredManToken(item: string): boolean;
50
- export declare function listCredManItems(prefix: string): string[];
51
- /**
52
- * Parse the target names printed by the `list` op (one per line), keeping only
53
- * those starting with `prefix` and deduping. Same contract as
54
- * parseSecretToolItems (linux.ts). Exported for tests.
55
- */
56
- export declare function parseWindowsCredList(output: string, prefix: string): string[];
57
- /**
58
- * Copy agents-cli credentials from Credential Manager into the file store (the
59
- * `import-keyring` backend for Windows). Requires a reachable store; items
60
- * already in the file store are left untouched.
61
- */
62
- export declare function importNativeCredManItems(prefix: string, commit: boolean): NativeImportReport;
63
- /**
64
- * KeychainBackend implementation for Windows. Routes through Windows Credential
65
- * Manager (via PowerShell P/Invoke) with a transparent encrypted-file fallback
66
- * when the credential store is unreachable.
67
- */
68
- export declare const windowsBackend: KeychainBackend;
69
- /**
70
- * Test-only: reset module state so independent test cases don't bleed
71
- * availability / fallback decisions across each other. Pass `forceAvailable` to
72
- * pin the powershell-availability probe (skips the real spawn); pass `fileDir`
73
- * to redirect the encrypted-file store to a temp dir. File-store state lives in
74
- * ./filestore.ts and is reset there.
75
- */
76
- export declare function _resetForTest(opts?: {
77
- fileDir?: string | null;
78
- forceFileFallback?: boolean;
79
- passphrase?: string | null;
80
- forceAvailable?: boolean | null;
81
- }): void;