@phnx-labs/agents-cli 1.22.57 → 1.22.59
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.
- package/CHANGELOG.md +294 -0
- package/README.md +29 -0
- package/dist/bootstrap.js +39 -1
- package/dist/commands/accounts.js +7 -3
- package/dist/commands/apply.js +10 -2
- package/dist/commands/fork.d.ts +23 -10
- package/dist/commands/fork.js +115 -58
- package/dist/commands/monitors.js +198 -23
- package/dist/commands/prune.js +5 -3
- package/dist/commands/routines.d.ts +8 -0
- package/dist/commands/routines.js +57 -3
- package/dist/commands/routines.test-fixture.js +5 -0
- package/dist/commands/send.d.ts +2 -1
- package/dist/commands/send.js +7 -5
- package/dist/commands/sessions-picker.d.ts +11 -0
- package/dist/commands/sessions-picker.js +16 -0
- package/dist/commands/sessions-stats.js +37 -5
- package/dist/commands/sessions.js +40 -5
- package/dist/commands/share.d.ts +14 -0
- package/dist/commands/share.js +43 -2
- package/dist/commands/ssh.js +12 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/sync.js +83 -7
- package/dist/commands/traces.js +7 -0
- package/dist/commands/versions.js +12 -4
- package/dist/commands/view.js +7 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -1
- package/dist/lib/account-registry.d.ts +5 -1
- package/dist/lib/account-registry.js +47 -14
- package/dist/lib/accounting/capacity.d.ts +18 -7
- package/dist/lib/accounting/capacity.js +19 -8
- package/dist/lib/accounting/usage-sync.d.ts +29 -1
- package/dist/lib/accounting/usage-sync.js +76 -2
- package/dist/lib/accounting/usage.js +7 -1
- package/dist/lib/auth-mint.d.ts +11 -1
- package/dist/lib/auth-mint.js +21 -6
- package/dist/lib/auto-pull-worker.js +7 -2
- package/dist/lib/browser/ipc.d.ts +8 -0
- package/dist/lib/browser/ipc.js +87 -0
- package/dist/lib/browser/service.d.ts +19 -0
- package/dist/lib/browser/service.js +96 -11
- package/dist/lib/browser/sessions-list.js +10 -1
- package/dist/lib/cloud/rush.d.ts +7 -0
- package/dist/lib/cloud/rush.js +29 -1
- package/dist/lib/daemon/daemon.d.ts +22 -0
- package/dist/lib/daemon/daemon.js +39 -0
- package/dist/lib/daemon/runner.d.ts +3 -0
- package/dist/lib/daemon/runner.js +86 -45
- package/dist/lib/daemon/session-index-service.js +9 -1
- package/dist/lib/daemon/usage-sync-service.d.ts +3 -3
- package/dist/lib/daemon/usage-sync-service.js +14 -8
- package/dist/lib/daemon-services.js +1 -1
- package/dist/lib/daemon-ticks.d.ts +15 -0
- package/dist/lib/daemon-ticks.js +26 -0
- package/dist/lib/device-config.d.ts +5 -1
- package/dist/lib/device-config.js +2 -2
- package/dist/lib/devices/connect.d.ts +17 -8
- package/dist/lib/devices/connect.js +31 -14
- package/dist/lib/devices/health.js +5 -1
- package/dist/lib/devices/pool.d.ts +25 -2
- package/dist/lib/devices/pool.js +32 -2
- package/dist/lib/devices/stats-cache.d.ts +0 -6
- package/dist/lib/devices/stats-cache.js +2 -9
- package/dist/lib/doctor-diff.d.ts +14 -0
- package/dist/lib/doctor-diff.js +120 -9
- package/dist/lib/fleet/manifest.d.ts +17 -0
- package/dist/lib/fleet/manifest.js +26 -0
- package/dist/lib/git.d.ts +38 -0
- package/dist/lib/git.js +58 -0
- package/dist/lib/hooks/install.d.ts +27 -11
- package/dist/lib/hooks/install.js +42 -17
- package/dist/lib/hosts/ready.d.ts +8 -0
- package/dist/lib/hosts/ready.js +13 -2
- package/dist/lib/hosts/reconnect.d.ts +52 -203
- package/dist/lib/hosts/reconnect.js +64 -284
- package/dist/lib/installations/migrate.d.ts +6 -120
- package/dist/lib/installations/migrate.js +27 -259
- package/dist/lib/installations/shims.d.ts +13 -95
- package/dist/lib/installations/shims.js +22 -139
- package/dist/lib/installations/store.js +1 -1
- package/dist/lib/installations/versions.d.ts +43 -133
- package/dist/lib/installations/versions.js +94 -206
- package/dist/lib/monitors/config.d.ts +71 -3
- package/dist/lib/monitors/config.js +100 -12
- package/dist/lib/monitors/pid-watch.d.ts +35 -0
- package/dist/lib/monitors/pid-watch.js +45 -0
- package/dist/lib/monitors/remote.d.ts +18 -0
- package/dist/lib/monitors/remote.js +11 -0
- package/dist/lib/permissions.js +7 -2
- package/dist/lib/plugins/plugins.d.ts +17 -3
- package/dist/lib/plugins/plugins.js +84 -9
- package/dist/lib/plugins/skills.d.ts +8 -1
- package/dist/lib/plugins/skills.js +18 -2
- package/dist/lib/pty-server.d.ts +14 -0
- package/dist/lib/pty-server.js +49 -5
- package/dist/lib/refresh.d.ts +9 -0
- package/dist/lib/refresh.js +3 -1
- package/dist/lib/routine-readiness.d.ts +15 -1
- package/dist/lib/routine-readiness.js +41 -0
- package/dist/lib/sandbox.d.ts +4 -1
- package/dist/lib/sandbox.js +30 -1
- package/dist/lib/secrets/agent.d.ts +80 -225
- package/dist/lib/secrets/agent.js +139 -401
- package/dist/lib/secrets/bundles.d.ts +73 -222
- package/dist/lib/secrets/bundles.js +168 -467
- package/dist/lib/secrets/drivers/rush.js +5 -0
- package/dist/lib/secrets/reaper.d.ts +28 -70
- package/dist/lib/secrets/reaper.js +30 -85
- package/dist/lib/secrets/remote.d.ts +42 -129
- package/dist/lib/secrets/remote.js +55 -173
- package/dist/lib/self-heal/checks/install-staging.d.ts +4 -0
- package/dist/lib/self-heal/checks/install-staging.js +96 -0
- package/dist/lib/self-heal/registry.js +2 -0
- package/dist/lib/self-heal/types.d.ts +1 -1
- package/dist/lib/self-update.d.ts +65 -0
- package/dist/lib/self-update.js +138 -0
- package/dist/lib/session/active.d.ts +13 -1
- package/dist/lib/session/active.js +2 -0
- package/dist/lib/session/cloud.js +5 -0
- package/dist/lib/session/db.d.ts +51 -6
- package/dist/lib/session/db.js +266 -20
- package/dist/lib/session/fork.d.ts +45 -26
- package/dist/lib/session/fork.js +32 -95
- package/dist/lib/session/tool-calls.d.ts +43 -1
- package/dist/lib/session/tool-calls.js +74 -44
- package/dist/lib/session/tool-store.d.ts +33 -2
- package/dist/lib/session/tool-store.js +56 -3
- package/dist/lib/smart-launch.d.ts +6 -0
- package/dist/lib/smart-launch.js +5 -2
- package/dist/lib/staleness/writers/plugins.js +5 -2
- package/dist/lib/staleness/writers/sources.d.ts +5 -0
- package/dist/lib/staleness/writers/sources.js +2 -1
- package/dist/lib/staleness/writers/subagents.js +13 -3
- package/dist/lib/state.d.ts +7 -4
- package/dist/lib/state.js +7 -4
- package/dist/lib/subagents.js +8 -2
- package/dist/lib/sync-status.d.ts +22 -0
- package/dist/lib/sync-status.js +27 -0
- package/dist/lib/sync-umbrella.d.ts +9 -0
- package/dist/lib/sync-umbrella.js +21 -2
- package/dist/lib/teams/scheduler.d.ts +10 -0
- package/dist/lib/teams/scheduler.js +8 -0
- package/dist/lib/traces/insights.d.ts +47 -14
- package/dist/lib/traces/insights.js +92 -21
- package/dist/lib/traces/phenotype.d.ts +23 -3
- package/dist/lib/traces/phenotype.js +72 -24
- package/dist/lib/traces/sync.d.ts +128 -6
- package/dist/lib/traces/sync.js +294 -35
- package/dist/lib/traces/worker-template.js +154 -1
- package/dist/lib/view-types.d.ts +12 -0
- package/package.json +2 -2
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The secrets-agent:
|
|
3
|
-
*
|
|
4
|
-
* their own prompt.
|
|
2
|
+
* The secrets-agent: an in-memory broker that holds resolved bundle env after one
|
|
3
|
+
* Touch ID unlock, so concurrent agents don't each prompt.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* is the ssh-agent answer: `agents secrets unlock <bundle>` decrypts the bundle
|
|
11
|
-
* once (one prompt), ships the resolved env here, and every later read returns
|
|
12
|
-
* from memory over a user-only Unix socket — no prompt.
|
|
13
|
-
*
|
|
14
|
-
* Security model (deliberate): while a bundle is unlocked, any same-user
|
|
15
|
-
* process that can reach the socket reads it silently. That's strictly the same
|
|
16
|
-
* trust boundary the keychain already concedes (docs/secrets.md: the ACL is
|
|
17
|
-
* user-presence, not code-identity — any same-user process can pop the prompt
|
|
18
|
-
* and read), minus the visible prompt. We bound it with: explicit per-bundle
|
|
19
|
-
* opt-in (nothing is held unless you `unlock` it), an absolute TTL (~7d), an
|
|
20
|
-
* auto-wipe on sleep / logout, and `agents secrets lock`. A bare screen-lock is
|
|
21
|
-
* NOT a wipe (the login password already gates it). Nothing ever touches disk.
|
|
22
|
-
*
|
|
23
|
-
* macOS only: Linux libsecret has no biometry prompt, so there's nothing to
|
|
24
|
-
* deduplicate — every entry point here no-ops off darwin.
|
|
5
|
+
* Security model: while unlocked, any same-user process reaching the socket can
|
|
6
|
+
* read it silently — the same trust boundary the keychain already concedes. We
|
|
7
|
+
* bound it with per-bundle opt-in, a TTL (~7d), auto-wipe on sleep/logout, and
|
|
8
|
+
* explicit lock. Nothing touches disk. Off-darwin the broker is unused.
|
|
25
9
|
*/
|
|
26
10
|
import * as net from 'net';
|
|
27
11
|
import type { SecretsBundle } from './bundles.js';
|
|
@@ -31,63 +15,33 @@ export { GLOBAL_HARNESS, bundleScopeChain };
|
|
|
31
15
|
/** Default lifetime of an unlocked bundle when `--ttl` is not given. */
|
|
32
16
|
export declare const DEFAULT_TTL_MS: number;
|
|
33
17
|
/**
|
|
34
|
-
* Whether the secrets broker service is enabled in
|
|
35
|
-
* Off-darwin this is irrelevant (the broker is never used), but the helper is
|
|
36
|
-
* kept synchronous and safe everywhere so callers can fail loud without a prompt.
|
|
18
|
+
* Whether the secrets broker service is enabled in daemon service config.
|
|
37
19
|
*/
|
|
38
20
|
export declare function isSecretsBrokerEnabled(): boolean;
|
|
39
21
|
/**
|
|
40
22
|
* Reserved store-key prefix for the `secrets list` metadata snapshot cache.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* `secrets list` within the hold window read metadata without a Touch ID
|
|
45
|
-
* prompt. Keyed by the name-set hash so adding/removing/renaming a bundle
|
|
46
|
-
* changes the key and misses the cache automatically — no active invalidation.
|
|
47
|
-
* The '!' sentinel can never collide with a real bundle name
|
|
48
|
-
* (BUNDLE_NAME_PATTERN requires an alphanumeric first char) and is safe as
|
|
49
|
-
* spawnSync argv (unlike a NUL byte); `status` hides these entries.
|
|
23
|
+
* Keyed by a hash of the keychain name-set; adding/removing/renaming a bundle
|
|
24
|
+
* changes the key and invalidates passively. The '!' sentinel cannot collide
|
|
25
|
+
* with a real bundle name and is safe as argv.
|
|
50
26
|
*/
|
|
51
27
|
export declare const META_CACHE_PREFIX = "!meta:";
|
|
52
28
|
export { SYNC_GET_CMD, SYNC_PING_CMD, SYNC_LOCK_CMD } from './sync-commands.js';
|
|
53
29
|
/**
|
|
54
|
-
* Decide whether a persistent broker should
|
|
55
|
-
* code
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* restart until the cache is idle (TTL-expired / slept) means an
|
|
59
|
-
* in-place `npm i -g` never wipes a hot cache — the new code is adopted at the
|
|
60
|
-
* next quiet moment instead. See #435: rapid repeated upgrades wiped a hot
|
|
61
|
-
* cache on every bump and produced a recurring Touch ID storm.
|
|
30
|
+
* Decide whether a persistent broker should exit so launchd relaunches it on
|
|
31
|
+
* freshly-installed code. Only when the store is empty: exiting with held
|
|
32
|
+
* bundles would force a re-prompt. Deferring protects against rapid upgrades
|
|
33
|
+
* wiping the hot cache (#435).
|
|
62
34
|
*/
|
|
63
35
|
export declare function shouldSelfHealForUpgrade(persistent: boolean, storeSize: number, runningVersion: string, onDiskVersion: string): boolean;
|
|
64
36
|
/**
|
|
65
|
-
* Client-side twin
|
|
66
|
-
*
|
|
67
|
-
* on-disk version. Only while it holds NO real unlocks — tearing down a hot
|
|
68
|
-
* broker wipes every held bundle, so the next read of each one re-prompts for
|
|
69
|
-
* Touch ID. On a machine where installed versions churn (dev builds stamp a
|
|
70
|
-
* fresh 0.0.0-dev.<sha> on every install; an npm copy and a dev copy invoke in
|
|
71
|
-
* turn), an unguarded teardown produced a rolling Touch ID storm — the exact
|
|
72
|
-
* failure #435 fixed on the server side. A hot, protocol-compatible broker
|
|
73
|
-
* keeps serving; its own sweep adopts the new code at the next quiet moment.
|
|
37
|
+
* Client-side twin: may only tear down a version-skewed broker when it holds
|
|
38
|
+
* no real unlocks, otherwise every held bundle re-prompts (#435).
|
|
74
39
|
*/
|
|
75
40
|
export declare function shouldTeardownVersionSkewedBroker(realHeldBundles: number): boolean;
|
|
76
41
|
/**
|
|
77
|
-
* Whether a
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* unlocks. teardownStaleBroker() recognizes only the standalone broker's
|
|
81
|
-
* pidPath() O_EXCL claim (the daemon writes ownerPath(), never pidPath()), so
|
|
82
|
-
* evicting a daemon-hosted broker unlinks its socket WITHOUT stopping the daemon;
|
|
83
|
-
* the daemon then keeps hostedBroker != null and shouldTakeOverBroker() refuses
|
|
84
|
-
* to re-host, orphaning its broker until the daemon restarts while every reader
|
|
85
|
-
* falls onto cold one-off brokers that re-prompt Touch ID — the storm. Deferring
|
|
86
|
-
* is safe: daemon code-version upgrades are handled by postinstall.js restarting
|
|
87
|
-
* it, and agentPing() already gated on PROTOCOL_VERSION, so a code-skewed daemon
|
|
88
|
-
* broker is still wire-compatible. Only when NO daemon owns the broker (churning
|
|
89
|
-
* dev installs with a dead/absent daemon — the case #435's client twin was built
|
|
90
|
-
* for) does the zero-held-bundles teardown apply, exactly as before.
|
|
42
|
+
* Whether a client may evict a version-skewed broker. A daemon-hosted broker
|
|
43
|
+
* must never be client-evicted: the daemon owns the socket via ownerPath(), so
|
|
44
|
+
* unlinking it would orphan the broker until daemon restart (#435).
|
|
91
45
|
*/
|
|
92
46
|
export declare function shouldClientEvictSkewedBroker(daemonRunning: boolean, realHeldBundles: number): boolean;
|
|
93
47
|
export interface StoredBundle {
|
|
@@ -110,28 +64,21 @@ export interface AgentStatusEntry {
|
|
|
110
64
|
/** Public accessor for the broker's socket path — `agents daemon status`/`services` reads it for display. */
|
|
111
65
|
export declare function secretsBrokerSocketPath(): string;
|
|
112
66
|
/**
|
|
113
|
-
* Read the current broker capability token
|
|
114
|
-
* read
|
|
115
|
-
* restart mints a new token, so a stale read simply fails authorization and the
|
|
116
|
-
* caller falls back to a direct keychain read (soft, never a hard error).
|
|
67
|
+
* Read the current broker capability token. A restart mints a new token, so a
|
|
68
|
+
* stale read fails soft and the caller falls back to a direct keychain read.
|
|
117
69
|
*/
|
|
118
70
|
export declare function readAgentToken(): string | null;
|
|
119
71
|
/** True if a legacy standalone-broker launchd plist is still installed. */
|
|
120
72
|
export declare function secretsAgentServiceInstalled(): boolean;
|
|
121
73
|
/**
|
|
122
|
-
* Retire the legacy standalone
|
|
123
|
-
*
|
|
124
|
-
* daemon owns the broker socket. Idempotent and best-effort — a no-op when no
|
|
125
|
-
* legacy plist is present. Does NOT wipe held bundles: the booted-out process's
|
|
126
|
-
* memory is gone anyway, and the daemon-hosted broker starts fresh.
|
|
74
|
+
* Retire the legacy standalone launchd service so the daemon owns the socket.
|
|
75
|
+
* Idempotent; does not wipe held bundles.
|
|
127
76
|
*/
|
|
128
77
|
export declare function retireLegacySecretsAgentService(): void;
|
|
129
78
|
/**
|
|
130
|
-
* Stop the persistent broker for `agents secrets stop`: wipe
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* the always-on backbone, and stopping it would take down unrelated background
|
|
134
|
-
* work (routines, browser IPC, session-sync).
|
|
79
|
+
* Stop the persistent broker for `agents secrets stop`: wipe held bundles, then
|
|
80
|
+
* retire any legacy standalone service. The daemon-hosted broker itself is left
|
|
81
|
+
* running because it backs unrelated background work.
|
|
135
82
|
*/
|
|
136
83
|
export declare function uninstallSecretsAgentService(): Promise<void>;
|
|
137
84
|
export type Request = {
|
|
@@ -199,73 +146,47 @@ export type Response = {
|
|
|
199
146
|
error: string;
|
|
200
147
|
};
|
|
201
148
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* Mutates `store` in place; returns the wire response.
|
|
206
|
-
*/
|
|
207
|
-
/**
|
|
208
|
-
* Count of real unlocked bundles in the store, excluding the internal
|
|
209
|
-
* `secrets list` metadata cache. Used to decide broker "warmth" for self-heal
|
|
210
|
-
* and idle-exit: a metadata-only store must read as empty so a disposable list
|
|
211
|
-
* cache never blocks an upgrade restart (#435) or an idle one-off broker from
|
|
212
|
-
* exiting. Pure + exported for unit testing.
|
|
149
|
+
* Count of real unlocked bundles, excluding the internal `secrets list` metadata
|
|
150
|
+
* cache. A metadata-only store must read as empty so it doesn't block upgrade
|
|
151
|
+
* self-heal or idle-exit (#435). Exported for tests.
|
|
213
152
|
*/
|
|
214
153
|
export declare function realBundleCount(store: Map<string, StoredBundle>): number;
|
|
215
154
|
export declare function scopedBundleKey(name: string, harness: string): string;
|
|
155
|
+
/** Pure request handler over the in-memory store. Exported for tests. */
|
|
216
156
|
export declare function handleAgentRequest(store: Map<string, StoredBundle>, req: Request, now?: number, evictedAt?: Map<string, number>): Response;
|
|
217
157
|
/**
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* password, and with the ~7d hold, re-authing after every lock would defeat the
|
|
222
|
-
* point. Logout needs no line — it tears down the launchd session and kills the
|
|
223
|
-
* broker outright. Pure + exported so the LOCK-survives / SLEEP-wipes contract
|
|
224
|
-
* has direct regression coverage (the inline stdout handler isn't unit-testable).
|
|
158
|
+
* Wipe the in-memory store only on SLEEP, not screen-lock (already gated by the
|
|
159
|
+
* login password). Exported for regression coverage of the LOCK-survives /
|
|
160
|
+
* SLEEP-wipes contract.
|
|
225
161
|
*/
|
|
226
162
|
export declare function shouldWipeOnWatchEvent(chunk: string): boolean;
|
|
227
163
|
/**
|
|
228
|
-
* Authorization gate
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* 0700 agent dir and so is readable only by the UID that owns the broker.
|
|
233
|
-
*
|
|
234
|
-
* Fail closed: a missing/empty expected token (no token file) rejects every
|
|
235
|
-
* command but ping. `ping` stays unauthenticated — it exposes only the protocol
|
|
236
|
-
* and cli version, and clients need it to detect a reachable broker before they
|
|
237
|
-
* have any reason to read the token. Pure + exported for direct unit testing.
|
|
164
|
+
* Authorization gate: every request except `ping` must carry the per-broker
|
|
165
|
+
* capability token from the 0600 token file. `ping` stays unauthenticated so
|
|
166
|
+
* clients can probe reachability before reading the token. Fail closed. Exported
|
|
167
|
+
* for tests.
|
|
238
168
|
*/
|
|
239
169
|
export declare function isRequestAuthorized(req: Request, expectedToken: string | null): boolean;
|
|
240
170
|
type BrokerConnectionHandler = (conn: net.Socket) => void;
|
|
241
171
|
/**
|
|
242
|
-
* Build the socket `connection` handler shared by
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* resolves the currently-expected capability token per request so a token
|
|
246
|
-
* rotation on broker restart is picked up without rebuilding the handler.
|
|
172
|
+
* Build the socket `connection` handler shared by standalone and daemon-hosted
|
|
173
|
+
* brokers. Newline-framed JSON in, one response line out, with per-request token
|
|
174
|
+
* lookup so rotation on restart is picked up.
|
|
247
175
|
*/
|
|
248
176
|
export declare function makeConnectionHandler(handle: (req: Request) => Response, token: () => string | null): BrokerConnectionHandler;
|
|
249
177
|
/**
|
|
250
|
-
* Whether a live process still owns the broker pid file.
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* single-threaded, so a big `get` or the rehydrate at startup can blow the
|
|
254
|
-
* 700ms ping budget while the process is perfectly healthy. Treating that as
|
|
255
|
-
* death let a starting broker unlink a live socket and rebind, leaving the old
|
|
256
|
-
* process alive holding every unlocked bundle in RAM that no client could reach
|
|
257
|
-
* any more (observed live: two brokers, one socket path, two kernel sockets).
|
|
258
|
-
* The pid file is the second, independent liveness signal that makes the reclaim
|
|
178
|
+
* Whether a live process still owns the broker pid file. A single missed ping
|
|
179
|
+
* isn't proof of death: the single-threaded broker can blow the ping budget
|
|
180
|
+
* while healthy. The pid file is the second liveness signal that makes reclaim
|
|
259
181
|
* safe.
|
|
260
182
|
*/
|
|
261
|
-
/** Drop our ownership record
|
|
262
|
-
* successor that already claimed the socket. */
|
|
183
|
+
/** Drop our ownership record only if it is still ours. */
|
|
263
184
|
export declare function releaseBrokerPid(): void;
|
|
264
185
|
export declare function brokerPidAlive(): boolean;
|
|
265
186
|
/**
|
|
266
|
-
* Run the broker in the foreground. Spawned
|
|
267
|
-
* `agents secrets _agent-run`.
|
|
268
|
-
*
|
|
187
|
+
* Run the standalone broker in the foreground. Spawned by ensureAgentRunning via
|
|
188
|
+
* `agents secrets _agent-run`. Serves the socket, sweeps expired entries, wipes
|
|
189
|
+
* on sleep, and self-exits when idle.
|
|
269
190
|
*/
|
|
270
191
|
export declare function runSecretsAgent(opts?: {
|
|
271
192
|
service?: boolean;
|
|
@@ -273,72 +194,35 @@ export declare function runSecretsAgent(opts?: {
|
|
|
273
194
|
close(): void | Promise<void>;
|
|
274
195
|
} | null>;
|
|
275
196
|
/**
|
|
276
|
-
* Host the secrets broker inside the always-on daemon (#416).
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* keeps working through the versioned protocol — but it is daemon-safe:
|
|
281
|
-
*
|
|
282
|
-
* - no pid-file single-instance guard (the daemon owns the instance);
|
|
283
|
-
* - no `process.exit`, no SIGTERM/SIGINT handlers, no self-heal/idle-exit
|
|
284
|
-
* (those would kill the daemon — the daemon is the always-on backbone and
|
|
285
|
-
* manages its own version/lifecycle). The sweep only TTL-evicts.
|
|
286
|
-
*
|
|
287
|
-
* The caller (`runDaemon`) normally invokes this only when no broker answers
|
|
288
|
-
* its initial ping. Binding still arbitrates ownership through the same shared
|
|
289
|
-
* path as the standalone service: a live owner wins, while only an unreachable
|
|
290
|
-
* stale socket is reclaimed. Returns a handle the daemon closes on shutdown,
|
|
291
|
-
* or null off-darwin (nothing to broker without biometry).
|
|
197
|
+
* Host the secrets broker inside the always-on daemon (#416). Serves the same
|
|
198
|
+
* socket/protocol as the standalone broker, but daemon-safe: no pid-file guard,
|
|
199
|
+
* no process.exit/SIG handlers, no self-heal/idle-exit (the daemon owns the
|
|
200
|
+
* lifecycle). Returns null off-darwin.
|
|
292
201
|
*/
|
|
293
202
|
export declare function startHostedBroker(): Promise<{
|
|
294
203
|
close(): void | Promise<void>;
|
|
295
204
|
} | null>;
|
|
296
205
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* be held — a successor bind could race EADDRINUSE against a half-closed server
|
|
300
|
-
* (RUSH-2421). Pure side-effect helper; never throws.
|
|
206
|
+
* Wait for net.Server.close()'s 'close' event (or a bounded timeout) so a
|
|
207
|
+
* successor bind doesn't race a half-closed socket (RUSH-2421).
|
|
301
208
|
*/
|
|
302
209
|
export declare function closeServerBounded(server: net.Server, timeoutMs?: number): Promise<void>;
|
|
303
|
-
/**
|
|
304
|
-
* never-unlocked path stays a single stat. */
|
|
210
|
+
/** Cheap socket-existence check so the never-unlocked path stays a single stat. */
|
|
305
211
|
export declare function agentSocketExists(): boolean;
|
|
306
212
|
/**
|
|
307
|
-
* Spawn one of the `__secrets-*` sync clients
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* **bun-compiled Mach-O**, where `process.execPath` is the CLI binary itself —
|
|
313
|
-
* so the spawn became `agents -e <program> …`, which commander rejects with
|
|
314
|
-
* `error: unknown option '-e'` and a non-zero exit. Every sync client then took
|
|
315
|
-
* its own failure path (`agentGetSync` → null, `agentReachableSync` → false,
|
|
316
|
-
* `agentEvictSync` → no-op), which reads as "broker down" and falls through to
|
|
317
|
-
* a real keychain read. Net effect on the standalone binary: the broker cache
|
|
318
|
-
* was never hit, so the `daily` policy's one-prompt-per-7d never applied and
|
|
319
|
-
* every bundle read re-popped Touch ID.
|
|
320
|
-
*
|
|
321
|
-
* Same defect class as the broker-launch bug fixed in 1.20.56 (see cliSpawn's
|
|
322
|
-
* doc comment); these three sites were simply never converted. Routing them
|
|
323
|
-
* through `getCliLaunch` fixes both install shapes at once and keeps a single
|
|
324
|
-
* code path.
|
|
325
|
-
*
|
|
326
|
-
* The subcommands are top-level `__secrets-*` tokens intercepted in index.ts
|
|
327
|
-
* BEFORE commander and before the CLI's startup work, exactly like
|
|
328
|
-
* `__daemon-run` and `__vault-age-helper`. That is load-bearing, not cosmetic:
|
|
329
|
-
* a normal command path runs `checkForUpdates()` and `spawnDetachedSync()` on
|
|
330
|
-
* every invocation (index.ts), so registering these as ordinary hidden
|
|
331
|
-
* subcommands would fire an update check and spawn a detached background sync
|
|
332
|
-
* on every cache hit — turning the hot read path into a process fork storm.
|
|
213
|
+
* Spawn one of the `__secrets-*` sync clients via `getCliLaunch`. The old
|
|
214
|
+
* `process.execPath -e` pattern broke on the bun-compiled Mach-O binary
|
|
215
|
+
* (1.20.53); routing through getCliLaunch fixes both install shapes. The
|
|
216
|
+
* subcommands are intercepted in index.ts before commander/startup so a cache
|
|
217
|
+
* hit doesn't fork detached syncs or run update checks.
|
|
333
218
|
*/
|
|
334
219
|
export declare function syncClientLaunch(sub: string[], agentsBin?: string): {
|
|
335
220
|
command: string;
|
|
336
221
|
args: string[];
|
|
337
222
|
};
|
|
338
223
|
/**
|
|
339
|
-
* Synchronous read for the hot path. Returns
|
|
340
|
-
*
|
|
341
|
-
* (soft — caller falls through to the real keychain). macOS only.
|
|
224
|
+
* Synchronous read for the hot path. Returns null on any failure so the caller
|
|
225
|
+
* falls through to the real keychain. macOS only.
|
|
342
226
|
*/
|
|
343
227
|
export declare function agentGetSync(name: string, harness?: string): {
|
|
344
228
|
bundle: SecretsBundle;
|
|
@@ -346,70 +230,41 @@ export declare function agentGetSync(name: string, harness?: string): {
|
|
|
346
230
|
lease?: SecretLease;
|
|
347
231
|
} | null;
|
|
348
232
|
/**
|
|
349
|
-
* Last non-empty line of a child's stdout — the payload line.
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* only ever emit its own JSON. The replacement boots the real CLI, so anything
|
|
353
|
-
* the CLI prints on the way up shares that stream. Today the known chatter (the
|
|
354
|
-
* `~/.agents/ is N commits behind` notice) correctly goes to stderr, but a
|
|
355
|
-
* single future stdout write anywhere in startup would make `JSON.parse` throw
|
|
356
|
-
* and turn every cache hit back into a silent miss — i.e. quietly reintroduce
|
|
357
|
-
* the Touch-ID-on-every-read bug this fix closes, with no failing test to catch
|
|
358
|
-
* it. Anchoring on the last line makes the payload the terminator of the
|
|
359
|
-
* stream rather than the whole of it, so preceding chatter is inert.
|
|
233
|
+
* Last non-empty line of a child's stdout — the payload line. Anchors on the
|
|
234
|
+
* terminator so any future CLI startup chatter on stdout doesn't break JSON.parse
|
|
235
|
+
* and silently turn cache hits into misses.
|
|
360
236
|
*/
|
|
361
237
|
export declare function lastLine(stdout: string): string;
|
|
362
238
|
/**
|
|
363
|
-
* Synchronous liveness check: is a broker actually
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* OOM, version-skew teardown) must NOT drag a foreground read through the
|
|
367
|
-
* worker's 20s cold-start budget. A stale socket refuses instantly, so this is
|
|
368
|
-
* fast in both the alive and dead cases. macOS only.
|
|
239
|
+
* Synchronous liveness check: is a broker actually listening? Gates the
|
|
240
|
+
* synchronous warm path so a stale socket doesn't drag a foreground read
|
|
241
|
+
* through a cold-start. macOS only.
|
|
369
242
|
*/
|
|
370
243
|
export declare function agentReachableSync(): boolean;
|
|
371
244
|
/**
|
|
372
|
-
* Synchronously evict one bundle
|
|
373
|
-
*
|
|
374
|
-
* keeps serving the pre-write snapshot for up to the ~7d hold — the next read
|
|
375
|
-
* re-resolves from the keychain (one prompt) and re-caches fresh values.
|
|
376
|
-
* Best-effort: no broker, no socket, or any failure is a silent no-op.
|
|
377
|
-
* macOS only.
|
|
245
|
+
* Synchronously evict one bundle after a mutating write so the broker doesn't
|
|
246
|
+
* serve a stale snapshot for the hold window. Best-effort silent no-op. macOS only.
|
|
378
247
|
*/
|
|
379
248
|
export declare function agentEvictSync(name: string): void;
|
|
380
|
-
/** Body of `__secrets-get <name>`.
|
|
381
|
-
* cache hit. Exit 0 = hit, 3 = miss or broker down. */
|
|
249
|
+
/** Body of `__secrets-get <name>`. Exit 0 = hit, 3 = miss/down. */
|
|
382
250
|
export declare function runAgentGetSync(name: string, harness?: string): Promise<number>;
|
|
383
|
-
/** Body of `__secrets-ping`. Exit 0 =
|
|
384
|
-
*
|
|
385
|
-
* PROTOCOL_VERSION: this only decides whether the auto-cache may take the
|
|
386
|
-
* synchronous warm path, and a version-skewed broker still answers reads. That
|
|
387
|
-
* matches the inline program this replaced. */
|
|
251
|
+
/** Body of `__secrets-ping`. Exit 0 = listening broker, 3 = nothing there.
|
|
252
|
+
* Does not gate on PROTOCOL_VERSION so version-skewed brokers still answer reads. */
|
|
388
253
|
export declare function runAgentPingSync(): Promise<number>;
|
|
389
254
|
/** Body of `__secrets-lock <name>`. Best-effort evict; exit 0 even when no
|
|
390
|
-
* broker answers
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
* An empty name is refused rather than forwarded: the broker treats a nameless
|
|
394
|
-
* lock as lock-ALL (handleAgentRequest), so a bare `__secrets-lock` would wipe
|
|
395
|
-
* every held bundle and re-prompt Touch ID for each. That was unreachable while
|
|
396
|
-
* this was an inline `node -e` string; as a top-level argv token it is one typo
|
|
397
|
-
* away, and agentEvictSync only ever locks by name. */
|
|
255
|
+
* broker answers. An empty name is refused to avoid accidentally locking ALL
|
|
256
|
+
* bundles. */
|
|
398
257
|
export declare function runAgentLockSync(name: string): Promise<number>;
|
|
399
258
|
/**
|
|
400
|
-
* Read the cached `secrets list` metadata snapshot for
|
|
401
|
-
* name-set hash
|
|
402
|
-
*
|
|
403
|
-
* the cache key: a changed name-set (bundle added/removed/renamed) yields a
|
|
404
|
-
* different key and therefore a clean miss, so the stale set is never served.
|
|
259
|
+
* Read the cached `secrets list` metadata snapshot for a keychain name-set hash.
|
|
260
|
+
* Reuses agentGetSync. The name-set hash is the cache key, so add/remove/rename
|
|
261
|
+
* yields a clean miss.
|
|
405
262
|
*/
|
|
406
263
|
export declare function agentGetMetaSync(nameSetHash: string): SecretsBundle[] | null;
|
|
407
264
|
/**
|
|
408
|
-
* Fire-and-forget: populate the broker with a
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
* reserved META_CACHE_PREFIX key; the snapshot travels over stdin to the
|
|
412
|
-
* detached worker (never argv/disk), same as value caching. macOS only.
|
|
265
|
+
* Fire-and-forget: populate the broker with a metadata snapshot so the next
|
|
266
|
+
* `secrets list` within the hold window is prompt-free. Stored under a reserved
|
|
267
|
+
* META_CACHE_PREFIX key; snapshot travels over stdin. macOS only.
|
|
413
268
|
*/
|
|
414
269
|
export declare function agentAutoLoadMetaSync(nameSetHash: string, bundles: SecretsBundle[], ttlMs: number): void;
|
|
415
270
|
/** True unless `secrets.agent.auto` is explicitly disabled in agents.yaml. The
|