@byok-sdk/client 0.1.0
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/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/adapters/claude/claude-adapter.d.ts +155 -0
- package/dist/adapters/claude/events.d.ts +91 -0
- package/dist/adapters/claude/permission-mapping.d.ts +142 -0
- package/dist/adapters/claude/process-client.d.ts +103 -0
- package/dist/adapters/claude/resolve-approval-mcp-bin.d.ts +45 -0
- package/dist/adapters/claude/resolve-bin.d.ts +27 -0
- package/dist/adapters/codex/codex-adapter.d.ts +97 -0
- package/dist/adapters/codex/events.d.ts +41 -0
- package/dist/adapters/codex/permission-mapping.d.ts +107 -0
- package/dist/adapters/codex/process-runner.d.ts +86 -0
- package/dist/adapters/codex/resolve-bin.d.ts +25 -0
- package/dist/adapters/pi/events.d.ts +58 -0
- package/dist/adapters/pi/permission-mapping.d.ts +46 -0
- package/dist/adapters/pi/pi-adapter.d.ts +29 -0
- package/dist/adapters/pi/resolve-bin.d.ts +44 -0
- package/dist/adapters/pi/rpc-client.d.ts +101 -0
- package/dist/bin/approval-mcp-server.d.ts +69 -0
- package/dist/bin/audit-log.d.ts +212 -0
- package/dist/bin/byok-agent.d.ts +2 -0
- package/dist/bin/byok-agent.js +12347 -0
- package/dist/bin/byok-agent.js.map +1 -0
- package/dist/bin/byok-approval-mcp.d.ts +2 -0
- package/dist/bin/byok-approval-mcp.js +498 -0
- package/dist/bin/byok-approval-mcp.js.map +1 -0
- package/dist/bin/commands/approvals.d.ts +31 -0
- package/dist/bin/commands/approve-reject.d.ts +29 -0
- package/dist/bin/commands/doctor.d.ts +15 -0
- package/dist/bin/commands/pair.d.ts +7 -0
- package/dist/bin/commands/runtimes.d.ts +7 -0
- package/dist/bin/commands/service.d.ts +54 -0
- package/dist/bin/commands/start.d.ts +21 -0
- package/dist/bin/commands/status.d.ts +25 -0
- package/dist/bin/commands/support-bundle.d.ts +7 -0
- package/dist/bin/commands/tasks.d.ts +27 -0
- package/dist/bin/commands/unpair.d.ts +124 -0
- package/dist/bin/commands/workspaces.d.ts +16 -0
- package/dist/bin/config.d.ts +41 -0
- package/dist/bin/control-client.d.ts +50 -0
- package/dist/bin/format.d.ts +67 -0
- package/dist/bin/runtime-probe.d.ts +34 -0
- package/dist/bin/tasks-view.d.ts +49 -0
- package/dist/daemon/approvals.d.ts +87 -0
- package/dist/daemon/auth-manager.d.ts +52 -0
- package/dist/daemon/blob-client.d.ts +22 -0
- package/dist/daemon/connection-manager.d.ts +502 -0
- package/dist/daemon/control-protocol.d.ts +299 -0
- package/dist/daemon/control-server.d.ts +61 -0
- package/dist/daemon/create-daemon.d.ts +364 -0
- package/dist/daemon/cursor-store.d.ts +30 -0
- package/dist/daemon/daemon-owner.d.ts +24 -0
- package/dist/daemon/deterministic-jitter.d.ts +20 -0
- package/dist/daemon/device-keys.d.ts +45 -0
- package/dist/daemon/device-proof-signer.d.ts +41 -0
- package/dist/daemon/environment.d.ts +96 -0
- package/dist/daemon/git-workspace-store.d.ts +49 -0
- package/dist/daemon/git-workspace.d.ts +80 -0
- package/dist/daemon/http-client.d.ts +8 -0
- package/dist/daemon/journal/journal.d.ts +342 -0
- package/dist/daemon/journal/sqlite-journal.d.ts +173 -0
- package/dist/daemon/journal/sqlite-support.d.ts +96 -0
- package/dist/daemon/journal/storage-policy.d.ts +368 -0
- package/dist/daemon/long-poll-transport.d.ts +142 -0
- package/dist/daemon/observer.d.ts +345 -0
- package/dist/daemon/operational-health.d.ts +87 -0
- package/dist/daemon/policy.d.ts +16 -0
- package/dist/daemon/progress-batcher.d.ts +31 -0
- package/dist/daemon/runtime-capabilities.d.ts +36 -0
- package/dist/daemon/session-workspace-store.d.ts +75 -0
- package/dist/daemon/store.d.ts +54 -0
- package/dist/daemon/task-runner.d.ts +862 -0
- package/dist/daemon/truth-memory-client.d.ts +94 -0
- package/dist/daemon/url.d.ts +60 -0
- package/dist/daemon/ws-transport.d.ts +110 -0
- package/dist/diagnostics/diagnostics.d.ts +114 -0
- package/dist/diagnostics/support-bundle.d.ts +81 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +10056 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/create-service-lifecycle.d.ts +59 -0
- package/dist/lifecycle/exec-runner.d.ts +141 -0
- package/dist/lifecycle/launchd.d.ts +55 -0
- package/dist/lifecycle/service-types.d.ts +177 -0
- package/dist/lifecycle/systemd.d.ts +46 -0
- package/dist/lifecycle/winsw.d.ts +64 -0
- package/dist/types.d.ts +178 -0
- package/dist/util/async-queue.d.ts +45 -0
- package/dist/util/atomic-write.d.ts +86 -0
- package/dist/util/secure-dir.d.ts +124 -0
- package/package.json +66 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import type { TaskState } from '@byok-sdk/protocol';
|
|
2
|
+
import type { ApprovalDecision, PendingApproval } from './approvals';
|
|
3
|
+
import type { StorageCategory } from './journal/journal';
|
|
4
|
+
import type { StoragePressureState } from './journal/storage-policy';
|
|
5
|
+
import type { OperationalHealthSnapshot } from './operational-health';
|
|
6
|
+
/**
|
|
7
|
+
* M4 Phase 2: shared local-IPC contract between the daemon's control server
|
|
8
|
+
* (`control-server.ts`) and the CLI's control client (`bin/control-client.ts`)
|
|
9
|
+
* — frame shapes, endpoint path/pipe-name derivation, and the HMAC handshake
|
|
10
|
+
* math. Both sides import from here so the two can never independently drift
|
|
11
|
+
* (e.g. a mismatched HMAC label string, or a socket path computed two
|
|
12
|
+
* slightly different ways).
|
|
13
|
+
*
|
|
14
|
+
* Transport: NDJSON (one JSON object per line) over a Unix domain socket
|
|
15
|
+
* (darwin/linux) or a Windows named pipe — both addressed by the same
|
|
16
|
+
* path-like string via Node's `net` module, so neither `control-server.ts`
|
|
17
|
+
* nor `bin/control-client.ts` needs to special-case the transport itself,
|
|
18
|
+
* only the path/pipe-name derivation below.
|
|
19
|
+
*/
|
|
20
|
+
export declare const CONTROL_PROTOCOL_VERSION = 1;
|
|
21
|
+
/** Handshake must complete within this long, on both sides — see each side's own timer. */
|
|
22
|
+
export declare const HANDSHAKE_TIMEOUT_MS = 3000;
|
|
23
|
+
/**
|
|
24
|
+
* The Unix domain socket path for a daemon rooted at `storeDir`. Prefers
|
|
25
|
+
* `<storeDir>/control.sock` (keeps every one of this daemon's local state
|
|
26
|
+
* files under one directory, which is already created+chmod'd 0700 by the
|
|
27
|
+
* time this matters — see `control-server.ts`'s `startControlServer`);
|
|
28
|
+
* falls back, whenever the natural path would risk exceeding {@link
|
|
29
|
+
* UNIX_SOCKET_PATH_SOFT_LIMIT}, to a short, deterministic path nested under
|
|
30
|
+
* a PER-DAEMON PRIVATE subdirectory of `os.tmpdir()` — derived from a hash
|
|
31
|
+
* of `storeDir` alone, so both the daemon and any CLI invocation pointed at
|
|
32
|
+
* the same `storeDir` independently compute the identical fallback path.
|
|
33
|
+
*
|
|
34
|
+
* Nested one level deep (rather than a bare `<hash>.sock` file directly in
|
|
35
|
+
* the shared, world-traversable `os.tmpdir()`) specifically so
|
|
36
|
+
* `control-server.ts`'s `bindControlEndpoint` can create+chmod that
|
|
37
|
+
* subdirectory 0700 BEFORE ever binding inside it — the directory's own
|
|
38
|
+
* mode gates traversal into it regardless of the socket file's own
|
|
39
|
+
* (briefly default-permissioned, until the post-bind `chmod`) mode, closing
|
|
40
|
+
* what would otherwise be a real window for another user on the same
|
|
41
|
+
* machine to reach a socket living directly in a shared tmpdir.
|
|
42
|
+
*/
|
|
43
|
+
export declare function controlSocketPath(storeDir: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* The Windows named pipe name for a daemon identified by `productId` +
|
|
46
|
+
* (`path.resolve`-normalized) `storeDir`. Named pipes have no filesystem
|
|
47
|
+
* path (no stale-file cleanup concern the way Unix sockets have — see
|
|
48
|
+
* `control-server.ts`), but DO share one flat namespace across the whole
|
|
49
|
+
* machine, so the name must be scoped to this exact daemon instance: two
|
|
50
|
+
* different products, or two different store directories (e.g. two agents
|
|
51
|
+
* of the same product — see `templates/service/README.md`'s "running
|
|
52
|
+
* multiple agents" section), must never collide. `storeDir` is resolved
|
|
53
|
+
* before hashing so a trivial path-form difference (trailing slash, etc.)
|
|
54
|
+
* between the two sides can't split the name.
|
|
55
|
+
*
|
|
56
|
+
* NOT keyed by the OS user: a WinSW-installed service runs the daemon under
|
|
57
|
+
* the Windows service account (e.g. `SYSTEM`) while the operator CLI runs
|
|
58
|
+
* as the interactive user, so both sides must derive the identical name
|
|
59
|
+
* from the same `storeDir` alone. Impostor servers are defeated by the
|
|
60
|
+
* mutual HMAC handshake below, not by pipe-name secrecy — keying by user
|
|
61
|
+
* was security theater that broke the service-account topology.
|
|
62
|
+
*/
|
|
63
|
+
export declare function controlPipeName(productId: string, storeDir: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Dispatches to {@link controlPipeName} on `win32`, {@link controlSocketPath}
|
|
66
|
+
* everywhere else. `platform` defaults to `process.platform`; overridable
|
|
67
|
+
* for tests exercising a specific platform's branch on any host (mirrors
|
|
68
|
+
* `lifecycle/create-service-lifecycle.ts`'s identical `platform` override —
|
|
69
|
+
* the REAL win32 named-pipe semantics can only be proven on actual Windows,
|
|
70
|
+
* which CI's `ipc-smoke` job does; this override just makes the PATH-CHOICE
|
|
71
|
+
* logic itself testable everywhere).
|
|
72
|
+
*/
|
|
73
|
+
export declare function controlEndpointPath(productId: string, storeDir: string, platform?: NodeJS.Platform): string;
|
|
74
|
+
/** Where the daemon writes its per-session control-auth token (see the handshake section below). Always a real file, even on Windows (pipes have no path of their own to piggyback secrets on). */
|
|
75
|
+
export declare function controlTokenPath(storeDir: string): string;
|
|
76
|
+
export declare function randomNonceHex(): string;
|
|
77
|
+
/** What the server proves to the client: it holds `token`, bound to the client's own nonce so a captured proof can't be replayed against a different handshake. */
|
|
78
|
+
export declare function computeServerProof(token: string, clientNonce: string): string;
|
|
79
|
+
/** What the client proves to the server, symmetrically, bound to the server's nonce. */
|
|
80
|
+
export declare function computeClientAuth(token: string, serverNonce: string): string;
|
|
81
|
+
/** Constant-time hex-string comparison (`crypto.timingSafeEqual` requires equal-length buffers; a length mismatch is itself a safe, immediate "not equal" — no early-exit on content). */
|
|
82
|
+
export declare function timingSafeEqualHex(a: string, b: string): boolean;
|
|
83
|
+
export interface ClientHello {
|
|
84
|
+
v: 1;
|
|
85
|
+
hello: 'client';
|
|
86
|
+
nonce: string;
|
|
87
|
+
}
|
|
88
|
+
export interface ServerHello {
|
|
89
|
+
v: 1;
|
|
90
|
+
hello: 'server';
|
|
91
|
+
proof: string;
|
|
92
|
+
nonce: string;
|
|
93
|
+
}
|
|
94
|
+
export interface ClientAuth {
|
|
95
|
+
v: 1;
|
|
96
|
+
auth: string;
|
|
97
|
+
}
|
|
98
|
+
export interface ServerReady {
|
|
99
|
+
v: 1;
|
|
100
|
+
ready: true;
|
|
101
|
+
}
|
|
102
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
103
|
+
export declare function parseClientHello(value: unknown): ClientHello | undefined;
|
|
104
|
+
export declare function parseServerHello(value: unknown): ServerHello | undefined;
|
|
105
|
+
export declare function parseClientAuth(value: unknown): ClientAuth | undefined;
|
|
106
|
+
export declare function parseServerReady(value: unknown): ServerReady | undefined;
|
|
107
|
+
export interface RawControlRequest {
|
|
108
|
+
/** Not narrowed to `1` here on purpose — an unexpected value is a `bad_version` RESPONSE, not a parse failure; see `control-server.ts`. */
|
|
109
|
+
v: unknown;
|
|
110
|
+
id: string;
|
|
111
|
+
method: string;
|
|
112
|
+
params?: unknown;
|
|
113
|
+
}
|
|
114
|
+
/** Loose shape check for an incoming request line: only `id`/`method` need to be well-formed for the server to be able to respond at all (including a `bad_version`/`unknown_method` response) — `v` is deliberately passed through unvalidated. */
|
|
115
|
+
export declare function parseRawControlRequest(value: unknown): RawControlRequest | undefined;
|
|
116
|
+
export interface ControlErrorShape {
|
|
117
|
+
code: string;
|
|
118
|
+
message: string;
|
|
119
|
+
}
|
|
120
|
+
export interface ControlResponseOk {
|
|
121
|
+
v: 1;
|
|
122
|
+
id: string;
|
|
123
|
+
ok: true;
|
|
124
|
+
result?: unknown;
|
|
125
|
+
/** Present (and `true`) only on the final frame of a streaming method — see `control-server.ts`'s dispatch. */
|
|
126
|
+
done?: true;
|
|
127
|
+
}
|
|
128
|
+
export interface ControlResponseErr {
|
|
129
|
+
v: 1;
|
|
130
|
+
id: string;
|
|
131
|
+
ok: false;
|
|
132
|
+
error: ControlErrorShape;
|
|
133
|
+
}
|
|
134
|
+
export type ControlResponse = ControlResponseOk | ControlResponseErr;
|
|
135
|
+
export interface ControlEventFrame {
|
|
136
|
+
v: 1;
|
|
137
|
+
id: string;
|
|
138
|
+
event: unknown;
|
|
139
|
+
}
|
|
140
|
+
export declare function encodeFrame(frame: unknown): string;
|
|
141
|
+
/** Thrown by a method handler to control the wire error `{code, message}` a caller sees — anything else thrown surfaces as a generic `internal_error`. See `control-server.ts`'s dispatch and `bin/control-client.ts`'s `request()` (which re-throws this same class on the client side). */
|
|
142
|
+
export declare class ControlError extends Error {
|
|
143
|
+
readonly code: string;
|
|
144
|
+
constructor(code: string, message: string);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Bound on a single NDJSON line's byte length. Every real frame this
|
|
148
|
+
* protocol ever sends (handshake frames, requests/responses/events) is well
|
|
149
|
+
* under this — it exists purely as a defensive cap against a misbehaving or
|
|
150
|
+
* hostile peer streaming an unterminated line forever to grow `pending`
|
|
151
|
+
* without bound. Exceeding it is a fail-closed condition: {@link
|
|
152
|
+
* NdjsonLineReader.push} throws, and every caller (`control-server.ts`,
|
|
153
|
+
* `bin/control-client.ts`) destroys the connection on that throw.
|
|
154
|
+
*/
|
|
155
|
+
export declare const MAX_LINE_BYTES: number;
|
|
156
|
+
/**
|
|
157
|
+
* Buffers raw socket bytes and yields complete lines. Splits on the raw byte
|
|
158
|
+
* `0x0a` BEFORE any UTF-8 decoding (mirrors `bin/audit-log.ts`'s
|
|
159
|
+
* `followAuditLog`) — `0x0A` can only ever appear as an actual newline in
|
|
160
|
+
* valid UTF-8, so this never risks decoding a multi-byte character that
|
|
161
|
+
* happened to straddle a chunk boundary.
|
|
162
|
+
*/
|
|
163
|
+
export declare class NdjsonLineReader {
|
|
164
|
+
private pending;
|
|
165
|
+
/** @throws if the still-unterminated remainder exceeds {@link MAX_LINE_BYTES} — see that constant's own doc comment. */
|
|
166
|
+
push(chunk: Buffer): string[];
|
|
167
|
+
}
|
|
168
|
+
export interface ControlActiveTask {
|
|
169
|
+
taskId: string;
|
|
170
|
+
state: TaskState;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* M4 Phase 4 (part B.3, observability): a cheap per-active-task queue-depth
|
|
174
|
+
* watermark for the `status` result. The IDEAL metric here would be each
|
|
175
|
+
* runtime adapter's own event-queue depth (`util/async-queue.ts`'s
|
|
176
|
+
* `AsyncQueue`) — but that queue lives inside each adapter's concrete
|
|
177
|
+
* `Session` implementation, and `Session.events` (`types.ts`) is typed only
|
|
178
|
+
* as a plain `AsyncIterable<AgentEvent>`, which has no queryable backlog
|
|
179
|
+
* size; reaching it would mean adding a new method to the `Session`
|
|
180
|
+
* interface AND implementing it in all three bundled adapters
|
|
181
|
+
* (pi/claude/codex), which is out of scope for this pass. This instead
|
|
182
|
+
* reflects two things `TaskRunner` already cheaply knows about the SAME
|
|
183
|
+
* task without any new plumbing: how much progress is buffered locally
|
|
184
|
+
* (not yet flushed as a `task.progress` batch), and how many out-of-band
|
|
185
|
+
* approval requests are currently in flight for it. See
|
|
186
|
+
* `task-runner.ts`'s `getQueueWatermarks` for how each field is computed.
|
|
187
|
+
*/
|
|
188
|
+
export interface TaskQueueWatermark {
|
|
189
|
+
taskId: string;
|
|
190
|
+
/** Events buffered in this task's `ProgressBatcher`, not yet flushed as a `task.progress` batch. */
|
|
191
|
+
progressBatcherPending: number;
|
|
192
|
+
/** Approval requests currently in flight for this task: 1 if one is actively dispatched (registered + `task.await_approval` sent) plus however many more are queued behind it (M4 Phase 4 fold-in — see `TaskRunner.requestApproval`). */
|
|
193
|
+
pendingApprovals: number;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* S3b (L-003): local storage usage and pressure, as the `status` method
|
|
197
|
+
* reports them (architecture §12.7.2.1).
|
|
198
|
+
*
|
|
199
|
+
* Named `storage*` throughout, NOT `watermark*`: {@link TaskQueueWatermark}
|
|
200
|
+
* above is a per-task progress-buffer depth and has nothing to do with disk.
|
|
201
|
+
* Two unrelated concepts sharing a name on one status result is how an
|
|
202
|
+
* operator reads the wrong number during an incident.
|
|
203
|
+
*
|
|
204
|
+
* Present only when a daemon actually runs a storage policy
|
|
205
|
+
* (`DaemonConfig.hostedJournal.storagePolicy`). Absent means "not measured",
|
|
206
|
+
* which is a different statement from "measured, and fine" — so it is an
|
|
207
|
+
* absent field rather than a zeroed one.
|
|
208
|
+
*/
|
|
209
|
+
export interface ControlStorageStatus {
|
|
210
|
+
/** §12.7.2.1's four states. `hard-pressure` declines new offers; `emergency` refuses to ack at all. */
|
|
211
|
+
pressureState: StoragePressureState;
|
|
212
|
+
/** `maxStoreBytes` — the budget `usedBytes` is measured against. */
|
|
213
|
+
budgetBytes: number;
|
|
214
|
+
/** Total across every category below, as of `measuredAt`. */
|
|
215
|
+
usedBytes: number;
|
|
216
|
+
/** Bytes available to this daemon on the store's filesystem — the free-space axis of the watermark, independent of the budget. */
|
|
217
|
+
freeBytes: number;
|
|
218
|
+
measuredAt: string;
|
|
219
|
+
/** The five §12.7.2.1 categories, always reported separately — a single total cannot drive a category-scoped cleanup order or a category-scoped never-delete list. */
|
|
220
|
+
categories: ControlStorageCategoryUsage[];
|
|
221
|
+
/** The most recent bounded WAL checkpoint + incremental vacuum, if one has run in this daemon's lifetime. */
|
|
222
|
+
lastCompaction?: ControlStorageCompaction;
|
|
223
|
+
}
|
|
224
|
+
export interface ControlStorageCategoryUsage {
|
|
225
|
+
category: StorageCategory;
|
|
226
|
+
bytes: number;
|
|
227
|
+
/** `true` when this is a host-reported or sampled figure rather than one measured off the filesystem. */
|
|
228
|
+
approximate: boolean;
|
|
229
|
+
}
|
|
230
|
+
export interface ControlStorageCompaction {
|
|
231
|
+
checkpointed: boolean;
|
|
232
|
+
walFramesRemaining: number;
|
|
233
|
+
pagesVacuumed: number;
|
|
234
|
+
durationMs: number;
|
|
235
|
+
at: string;
|
|
236
|
+
}
|
|
237
|
+
/** Result shape for the `status` method — see `create-daemon.ts`'s control-method wiring for how each field is sourced, and `bin/format.ts`'s `formatLiveStatusLines` for how the CLI renders it. */
|
|
238
|
+
export interface ControlStatusResult {
|
|
239
|
+
pid: number;
|
|
240
|
+
uptimeMs: number;
|
|
241
|
+
paired: boolean;
|
|
242
|
+
deviceId?: string;
|
|
243
|
+
/** The connection state machine's own current value (`ws-transport.ts`'s `ConnectionState`) — e.g. `'open'`, `'degraded'` (long-poll fallback), `'revoked'`, `'closed'`, `'connecting'`. */
|
|
244
|
+
transport: string;
|
|
245
|
+
activeTasks: ControlActiveTask[];
|
|
246
|
+
runtimeIds: string[];
|
|
247
|
+
/** M4 Phase 4 (part B.3): per-active-task queue watermarks — see {@link TaskQueueWatermark}. */
|
|
248
|
+
queueWatermarks: TaskQueueWatermark[];
|
|
249
|
+
/**
|
|
250
|
+
* Finding F4 (cross-model adversarial review): the actual pending
|
|
251
|
+
* approvals currently dispatched — the SAME entries `approvals.list`
|
|
252
|
+
* returns (`ApprovalRegistry.list()`), surfaced here too so a single
|
|
253
|
+
* `status` call can show an operator every `approvalId` they'd need to
|
|
254
|
+
* `approve`/`reject`, without a second control-socket round trip. This is
|
|
255
|
+
* `approvalsPending`'s own source list (`approvalsPending ===
|
|
256
|
+
* approvals.length`, always).
|
|
257
|
+
*/
|
|
258
|
+
approvals: PendingApproval[];
|
|
259
|
+
/** M4 Phase 4 (part B.3): total approvals currently DISPATCHED (registered) across the whole daemon — the same count `approvals.list` returns, surfaced here too for a one-call status view. */
|
|
260
|
+
approvalsPending: number;
|
|
261
|
+
/** S3b (L-003): local storage usage + pressure — see {@link ControlStorageStatus}. Absent unless a storage policy is configured. */
|
|
262
|
+
storage?: ControlStorageStatus;
|
|
263
|
+
/** Local lifecycle/retry budget. This is not the transport state above. */
|
|
264
|
+
operationalHealth: OperationalHealthSnapshot;
|
|
265
|
+
}
|
|
266
|
+
export interface ApprovalsListResult {
|
|
267
|
+
approvals: PendingApproval[];
|
|
268
|
+
}
|
|
269
|
+
export type { ApprovalDecision, PendingApproval } from './approvals';
|
|
270
|
+
export interface ApprovalsResolveParams {
|
|
271
|
+
approvalId: string;
|
|
272
|
+
decision: ApprovalDecision;
|
|
273
|
+
reason?: string;
|
|
274
|
+
}
|
|
275
|
+
export declare function parseApprovalsResolveParams(value: unknown): ApprovalsResolveParams | undefined;
|
|
276
|
+
/**
|
|
277
|
+
* M4 Phase 3: the control method `byok-approval-mcp` (`bin/byok-approval-mcp.ts`)
|
|
278
|
+
* calls FROM a claude-spawned MCP-server child process — a genuinely
|
|
279
|
+
* different OS process from the daemon, reachable only over this same
|
|
280
|
+
* control socket (see `../types.ts`'s `ApprovalChannel` doc comment for the
|
|
281
|
+
* full why). `taskId` correlates the request to an active task;
|
|
282
|
+
* `summary` is a short, human-readable description of the gated action
|
|
283
|
+
* (carried verbatim into the wire `task.await_approval.summary`).
|
|
284
|
+
*/
|
|
285
|
+
export interface ApprovalsRequestParams {
|
|
286
|
+
taskId: string;
|
|
287
|
+
summary: string;
|
|
288
|
+
}
|
|
289
|
+
export declare function parseApprovalsRequestParams(value: unknown): ApprovalsRequestParams | undefined;
|
|
290
|
+
/** Result of `approvals.request` — the outcome `byok-approval-mcp` translates into its own MCP `allow`/`deny` answer. */
|
|
291
|
+
export interface ApprovalsRequestResult {
|
|
292
|
+
approved: boolean;
|
|
293
|
+
reason?: string;
|
|
294
|
+
}
|
|
295
|
+
export type ShutdownReason = 'unpair' | 'operator';
|
|
296
|
+
export interface ShutdownParams {
|
|
297
|
+
reason?: ShutdownReason;
|
|
298
|
+
}
|
|
299
|
+
export declare function parseShutdownParams(value: unknown): ShutdownParams;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M4 Phase 2: the daemon-side local control socket — Unix domain socket
|
|
3
|
+
* (darwin/linux) or Windows named pipe, mutually authenticated by an
|
|
4
|
+
* HMAC handshake over a token that never crosses the wire (see
|
|
5
|
+
* `control-protocol.ts`), speaking a small NDJSON request/response(/event)
|
|
6
|
+
* RPC protocol. Transport-only and daemon-agnostic: `create-daemon.ts`
|
|
7
|
+
* supplies the actual method handlers (`status`, `tasks.subscribe`,
|
|
8
|
+
* `approvals.*`, `shutdown`) as a plain registry — this module knows
|
|
9
|
+
* nothing about `Daemon`/`TaskRunner` internals, which keeps it testable
|
|
10
|
+
* (and reusable) on its own.
|
|
11
|
+
*/
|
|
12
|
+
export declare class AnotherControlServerRunningError extends Error {
|
|
13
|
+
constructor(endpoint: string);
|
|
14
|
+
}
|
|
15
|
+
/** Default cap on simultaneous pre-handshake ("half-open") connections — see `startControlServer`'s own comment on why. */
|
|
16
|
+
export declare const MAX_HALF_OPEN_CONNECTIONS = 8;
|
|
17
|
+
export interface ControlMethodContext {
|
|
18
|
+
/** Emits one `event` frame for a streaming method's current request. */
|
|
19
|
+
emit: (event: unknown) => void;
|
|
20
|
+
/** Aborts once the client disconnects — a streaming handler must stop producing events and release whatever it subscribed to. */
|
|
21
|
+
signal: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
export type UnaryMethod = (params: unknown) => Promise<unknown> | unknown;
|
|
24
|
+
export type StreamMethod = (params: unknown, ctx: ControlMethodContext) => Promise<void>;
|
|
25
|
+
export interface ControlMethods {
|
|
26
|
+
unary: Record<string, UnaryMethod>;
|
|
27
|
+
stream: Record<string, StreamMethod>;
|
|
28
|
+
}
|
|
29
|
+
export interface ControlServerOptions {
|
|
30
|
+
storeDir: string;
|
|
31
|
+
productId: string;
|
|
32
|
+
methods: ControlMethods;
|
|
33
|
+
/** Test-only override — default `HANDSHAKE_TIMEOUT_MS` (3000ms). */
|
|
34
|
+
handshakeTimeoutMs?: number;
|
|
35
|
+
/** Test-only override — default `MAX_HALF_OPEN_CONNECTIONS` (8). */
|
|
36
|
+
maxHalfOpenConnections?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface ControlServerHandle {
|
|
39
|
+
/** The bound Unix socket path or Windows pipe name. */
|
|
40
|
+
endpoint: string;
|
|
41
|
+
/** Stops accepting new connections, destroys every open one, and removes the socket/token files (a Windows pipe leaves no file to remove). Idempotent. */
|
|
42
|
+
close(): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Binds the platform endpoint (Unix socket or Windows pipe — see
|
|
46
|
+
* `control-protocol.ts`) FIRST, and only once that succeeds generates and
|
|
47
|
+
* persists a fresh per-session token to `<storeDir>/control.token` (0600).
|
|
48
|
+
* This ordering matters: if a bind fails because ANOTHER daemon's control
|
|
49
|
+
* server already owns this endpoint (see
|
|
50
|
+
* {@link AnotherControlServerRunningError}), that other daemon's own token
|
|
51
|
+
* file must be left completely untouched — writing (and, on failure,
|
|
52
|
+
* deleting) a token before the bind attempt would corrupt or erase the
|
|
53
|
+
* still-running daemon's valid token out from under it.
|
|
54
|
+
*
|
|
55
|
+
* Throws {@link AnotherControlServerRunningError} if a live listener already
|
|
56
|
+
* owns this endpoint (fatal — the caller, `create-daemon.ts`, treats this as
|
|
57
|
+
* a hard startup failure); any OTHER bind failure propagates as a plain
|
|
58
|
+
* `Error` so the caller can decide to degrade instead (the control socket
|
|
59
|
+
* must never be allowed to brick the rest of the daemon).
|
|
60
|
+
*/
|
|
61
|
+
export declare function startControlServer(opts: ControlServerOptions): Promise<ControlServerHandle>;
|