@byok-sdk/client 0.3.0 → 0.4.1

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 (41) hide show
  1. package/README.md +14 -1
  2. package/dist/adapters/claude/claude-adapter.d.ts +4 -20
  3. package/dist/adapters/claude/events.d.ts +3 -0
  4. package/dist/adapters/claude/process-client.d.ts +15 -1
  5. package/dist/adapters/codex/codex-adapter.d.ts +4 -16
  6. package/dist/adapters/codex/process-runner.d.ts +9 -1
  7. package/dist/adapters/index.d.ts +3 -1
  8. package/dist/adapters/index.js +1057 -261
  9. package/dist/adapters/index.js.map +1 -1
  10. package/dist/adapters/pi/pi-adapter.d.ts +3 -16
  11. package/dist/adapters/pi/resolve-bin.d.ts +1 -1
  12. package/dist/adapters/pi/rpc-client.d.ts +15 -1
  13. package/dist/adapters/process-tree.d.ts +60 -0
  14. package/dist/adapters/taskkill-pid-set.d.ts +34 -0
  15. package/dist/bin/audit-log.d.ts +12 -0
  16. package/dist/bin/byok-agent.js +1452 -507
  17. package/dist/bin/byok-agent.js.map +1 -1
  18. package/dist/bin/byok-approval-mcp.js.map +1 -1
  19. package/dist/bin/commands/workspaces.d.ts +11 -0
  20. package/dist/bin/format.d.ts +13 -0
  21. package/dist/bin/runtime-probe.d.ts +1 -1
  22. package/dist/bin/tasks-view.d.ts +13 -0
  23. package/dist/daemon/approvals.d.ts +2 -2
  24. package/dist/daemon/connection-manager.d.ts +15 -17
  25. package/dist/daemon/control-server.d.ts +18 -1
  26. package/dist/daemon/create-daemon.d.ts +2 -2
  27. package/dist/daemon/daemon-owner.d.ts +4 -2
  28. package/dist/daemon/environment.d.ts +9 -9
  29. package/dist/daemon/git-workspace.d.ts +21 -0
  30. package/dist/daemon/long-poll-transport.d.ts +6 -0
  31. package/dist/daemon/observer.d.ts +13 -0
  32. package/dist/daemon/presence-publisher.d.ts +29 -0
  33. package/dist/daemon/runtime-capabilities.d.ts +1 -1
  34. package/dist/daemon/task-runner.d.ts +34 -40
  35. package/dist/daemon/ws-transport.d.ts +3 -1
  36. package/dist/index.d.ts +4 -2
  37. package/dist/index.js +1413 -455
  38. package/dist/index.js.map +1 -1
  39. package/dist/runtime-failure.d.ts +64 -0
  40. package/dist/types.d.ts +100 -73
  41. package/package.json +14 -14
@@ -0,0 +1,64 @@
1
+ /** Closed lifecycle phases for failures after an offer has been admitted. */
2
+ export type RuntimeFailurePhase = 'start' | 'run';
3
+ /** Closed semantic axis. Retryability is explicit and is never inferred from this field. */
4
+ export type RuntimeFailureCategory = 'semantic' | 'infrastructure' | 'authority';
5
+ /** The adapter's explicit retry judgment consumed by TaskRunner. */
6
+ export type RuntimeRetryDisposition = 'retryable' | 'non-retryable';
7
+ /** Disposal is deliberately separate from start/run retryability authority. */
8
+ export type RuntimeDisposalStage = 'signal' | 'quiescence' | 'cleanup';
9
+ export interface RuntimeDisposalFailureInput {
10
+ stage: RuntimeDisposalStage;
11
+ /** Audit-safe operational reason. It must not contain task instructions or provider credentials. */
12
+ reason: string;
13
+ }
14
+ export interface RuntimeExecutionFailureInput {
15
+ phase: RuntimeFailurePhase;
16
+ category: RuntimeFailureCategory;
17
+ retry: RuntimeRetryDisposition;
18
+ /** Stable operator-facing reason. Provider diagnostics may be included, but are never parsed by TaskRunner. */
19
+ reason: string;
20
+ }
21
+ /**
22
+ * Expected failure of an owned runtime-resource disposal barrier. This never
23
+ * carries task retryability: semantic terminal authority may already have
24
+ * been published when disposal begins.
25
+ */
26
+ export declare class RuntimeDisposalFailure extends Error {
27
+ readonly stage: RuntimeDisposalStage;
28
+ constructor(input: RuntimeDisposalFailureInput, options?: ErrorOptions);
29
+ }
30
+ export declare function isRuntimeDisposalFailure(value: unknown): value is RuntimeDisposalFailure;
31
+ /**
32
+ * The only expected post-admission failure value accepted from a runtime
33
+ * adapter. Diagnostic AgentEvents remain observability; this value alone is
34
+ * terminal control authority.
35
+ */
36
+ export declare class RuntimeExecutionFailure extends Error {
37
+ readonly phase: RuntimeFailurePhase;
38
+ readonly category: RuntimeFailureCategory;
39
+ readonly retry: RuntimeRetryDisposition;
40
+ constructor(input: RuntimeExecutionFailureInput, options?: ErrorOptions);
41
+ }
42
+ export declare function isRuntimeExecutionFailure(value: unknown): value is RuntimeExecutionFailure;
43
+ export interface RuntimeFailureProjection {
44
+ reason: string;
45
+ retryable: boolean;
46
+ }
47
+ /**
48
+ * Exhaustive wire projection for a valid typed failure. A failure from the
49
+ * wrong phase is an invalid adapter state and must be handled as an untyped
50
+ * contract violation by the caller.
51
+ */
52
+ export declare function projectRuntimeExecutionFailure(failure: RuntimeExecutionFailure): RuntimeFailureProjection;
53
+ export declare const RUNTIME_ADAPTER_CONTRACT_VIOLATION_REASON: Readonly<{
54
+ start: string;
55
+ run: string;
56
+ }>;
57
+ /**
58
+ * Validate an adapter boundary. Unknown values and typed failures reported
59
+ * for the wrong phase fail closed; their source value is returned only as a
60
+ * local diagnostic cause and never influences wire semantics.
61
+ */
62
+ export declare function projectRuntimeBoundaryFailure(value: unknown, expectedPhase: RuntimeFailurePhase): RuntimeFailureProjection & {
63
+ contractViolation: boolean;
64
+ };
package/dist/types.d.ts CHANGED
@@ -17,14 +17,14 @@ export interface RuntimeDetectResult {
17
17
  }
18
18
  /** What a runtime adapter can do, advertised so the daemon can pick/validate adapters. */
19
19
  export interface RuntimeCapabilities {
20
- steer: boolean;
21
- resume: boolean;
20
+ readonly steer: boolean;
21
+ readonly resume: boolean;
22
22
  /**
23
23
  * Whether this adapter can project task-scoped, locally configured MCP
24
24
  * servers into the runtime without accepting executable definitions from
25
25
  * the remote task. Omission is fail-closed and means unsupported.
26
26
  */
27
- mcpToolsets?: boolean;
27
+ readonly mcpToolsets?: boolean;
28
28
  /**
29
29
  * Whether this adapter can genuinely pause a running session on
30
30
  * `needs_approval` and resume it from an out-of-band decision — i.e.
@@ -38,9 +38,9 @@ export interface RuntimeCapabilities {
38
38
  * declare it fails to compile rather than silently defaulting to a claim
39
39
  * it cannot back.
40
40
  */
41
- approvalInteractive: boolean;
41
+ readonly approvalInteractive: boolean;
42
42
  /** Subset of {@link PermissionPolicy}'s `mode` values this adapter can express without widening. */
43
- permissionModes: string[];
43
+ readonly permissionModes: readonly string[];
44
44
  }
45
45
  /** One local stdio MCP server definition. Remote task payloads can never supply this shape. */
46
46
  export interface McpStdioServerConfig {
@@ -53,8 +53,8 @@ export interface McpToolsetConfig {
53
53
  }
54
54
  /**
55
55
  * M4 Phase 3: the out-of-band approval channel `TaskRunner` (`daemon/
56
- * task-runner.ts`) hands to an adapter's `start()` via `TaskContext
57
- * .approvalChannel`, for a runtime whose approval mechanism genuinely needs
56
+ * task-runner.ts`) hands to a prepared operation's `start()` via
57
+ * `RuntimeOperationStartInput.approvalChannel`, for a runtime whose approval mechanism genuinely needs
58
58
  * to reach back into the daemon from OUTSIDE the adapter's own process — the
59
59
  * claude adapter's concrete case: `claude`'s `--permission-prompt-tool`
60
60
  * resolves a pending permission entirely inside a SEPARATE MCP-server child
@@ -85,30 +85,6 @@ export interface ApprovalChannel {
85
85
  /** Resolve the single currently-pending out-of-band approval for this task. Rejects if none is pending right now. */
86
86
  resolve(approved: boolean, reason?: string): Promise<void>;
87
87
  }
88
- /**
89
- * Per-task execution context handed to {@link RuntimeAdapter.start}. `policy`
90
- * is the already fail-closed-checked *effective* policy (offer policy merged
91
- * against the daemon's configured ceiling) — the adapter must obey this, not
92
- * whatever the raw task offer's own `policy` field said.
93
- */
94
- export interface TaskContext {
95
- workspaceDir: string;
96
- policy: PermissionPolicy;
97
- env: NodeJS.ProcessEnv;
98
- /**
99
- * MCP servers resolved from this device's local registry for this task.
100
- * The wire carries only logical toolset ids; command/args never originate
101
- * from the SaaS task and are never copied into the task instruction.
102
- */
103
- mcpServers?: Readonly<Record<string, McpStdioServerConfig>>;
104
- /** Prepared local checkpoint repository metadata; absent for legacy plain workspaces. */
105
- gitWorkspace?: {
106
- workspaceId: string;
107
- baseline?: string;
108
- };
109
- /** M4 Phase 3 — see {@link ApprovalChannel}. Optional/adapter-agnostic: unset for every adapter that never requests an out-of-band approval. */
110
- approvalChannel?: ApprovalChannel;
111
- }
112
88
  /**
113
89
  * A running (or resumable) unit of work on a runtime. One `Session` maps to
114
90
  * one underlying runtime process/session for the lifetime of a task.
@@ -124,7 +100,12 @@ export interface Session {
124
100
  followUp(task: TaskOfferPayload): Promise<void>;
125
101
  /** Best-effort abort of the current turn (used for `task.cancel`). */
126
102
  interrupt(): Promise<void>;
127
- /** Tear down the underlying runtime process/session. Idempotent. */
103
+ /**
104
+ * Bounded, idempotent disposal receipt. Resolution proves every
105
+ * adapter-owned process and task-scoped resource is quiescent. Expected
106
+ * failure rejects with `RuntimeDisposalFailure` and never changes task
107
+ * semantics.
108
+ */
128
109
  close(): Promise<void>;
129
110
  /**
130
111
  * Resolve a session paused on `needs_approval` (protocol §5). The
@@ -142,58 +123,104 @@ export interface Session {
142
123
  resolveApproval(approved: boolean, reason?: string): Promise<void>;
143
124
  }
144
125
  /**
145
- * Uniform seam every concrete runtime (pi now; claude/codex in M2) implements.
126
+ * Immutable runtime facts shared by discovery and one prepared operation.
146
127
  *
147
- * Credential-isolation rule: an adapter spawns only the runtime's official
148
- * binary. It never reads, proxies, or forwards that runtime's own credential
149
- * storage (OAuth tokens, API keys on disk, `~/.claude`, `~/.codex`, `~/.pi`
150
- * auth state, etc). Presence checks are limited to environment variable
151
- * *names* (see {@link RuntimeDetectResult.authPresent}).
152
- *
153
- * M5: separately, {@link RuntimeAdapter.environmentRequirements} below
154
- * declares which environment variable NAMES (never values inspected here
155
- * either) this adapter's runtime needs forwarded into its own spawned
156
- * process — see that method's own doc comment and `daemon/environment.ts`.
128
+ * The SDK snapshots this value before each offer and never consults adapter
129
+ * capability authority again during admission, claim, environment projection,
130
+ * or start. Credential declarations are names only, never values.
131
+ */
132
+ export interface RuntimeAdapterDescriptor {
133
+ readonly id: string;
134
+ readonly capabilities: RuntimeCapabilities;
135
+ readonly environmentRequirements: RuntimeEnvironmentRequirements;
136
+ /** Explicit opt-in to authoritative `task.offer.dispatchSelection` semantics. */
137
+ readonly supportsDispatchSelection: boolean;
138
+ }
139
+ /** The pure input to one adapter admission decision. It contains no credential values or workspace resources. */
140
+ export interface RuntimeAdapterPrepareInput {
141
+ offer: TaskOfferPayload;
142
+ policy: PermissionPolicy;
143
+ descriptor: RuntimeAdapterDescriptor;
144
+ requiredToolsetIds: readonly string[];
145
+ /** Locally resolved MCP authority; available for pure admission validation only. */
146
+ mcpServers?: Readonly<Record<string, McpStdioServerConfig>>;
147
+ }
148
+ /** A permanent or currently-unavailable pre-claim admission rejection. */
149
+ export interface RuntimeAdapterRejectedOperation {
150
+ kind: 'reject';
151
+ reason: string;
152
+ retryable: boolean;
153
+ }
154
+ /** The side-effect-free adapter decision made before TaskRunner claims an offer. */
155
+ export interface RuntimeAdapterPreparedOperation {
156
+ kind: 'prepared';
157
+ operation: PreparedRuntimeOperation;
158
+ }
159
+ export type RuntimeAdapterPrepareResult = RuntimeAdapterRejectedOperation | RuntimeAdapterPreparedOperation;
160
+ /**
161
+ * Credential-free immutable identity for one admitted runtime operation.
162
+ * It can be emitted, compared, and passed to a prepared operation, but never
163
+ * serializes environment values or credential material.
164
+ */
165
+ export interface RuntimeOperationManifest {
166
+ readonly taskId: string;
167
+ /** Selected runtime id; lane/provider/model, when present, live only in `dispatchSelection`. */
168
+ readonly runtimeId: string;
169
+ readonly descriptor: RuntimeAdapterDescriptor;
170
+ readonly policy: PermissionPolicy;
171
+ readonly requiredToolsetIds: readonly string[];
172
+ /** The credential-free runtime/lane/provider/model authority for this operation. */
173
+ readonly dispatchSelection?: TaskOfferPayload['dispatchSelection'];
174
+ readonly sessionRef?: string;
175
+ readonly workspace: {
176
+ readonly workspaceDir: string;
177
+ readonly workspaceId?: string;
178
+ readonly baseline?: string;
179
+ };
180
+ /** Names are audit-safe; credential values intentionally never enter the manifest. */
181
+ readonly forwardedEnvironmentNames: readonly string[];
182
+ }
183
+ /** Runtime resources only available after TaskRunner has sealed the manifest and claimed the task. */
184
+ export interface RuntimeOperationStartInput {
185
+ readonly manifest: RuntimeOperationManifest;
186
+ readonly instruction: string;
187
+ readonly env: NodeJS.ProcessEnv;
188
+ /** Local MCP authority resolved from logical wire ids. */
189
+ readonly mcpServers?: Readonly<Record<string, McpStdioServerConfig>>;
190
+ /** Optional, adapter-agnostic out-of-band approval channel. */
191
+ readonly approvalChannel?: ApprovalChannel;
192
+ }
193
+ /** A pinned provider/runtime decision. `start()` receives resources only, never a raw offer. */
194
+ export interface PreparedRuntimeOperation {
195
+ start(input: RuntimeOperationStartInput): Promise<Session>;
196
+ }
197
+ /**
198
+ * Uniform public adapter seam. `prepare()` is required and must not spawn,
199
+ * create temp files, mutate a workspace, allocate a session id, or read a
200
+ * credential value. There is intentionally no direct `RuntimeAdapter.start`.
157
201
  */
158
202
  export interface RuntimeAdapter {
159
- id: string;
160
- /**
161
- * Explicit opt-in to the authoritative `task.offer.dispatchSelection`
162
- * contract. A custom adapter using a built-in runtime id must set this only
163
- * when it validates and pins the exact lane/provider/model semantics; the
164
- * daemon will otherwise withhold the connection-level capability so a
165
- * server rejects the offer before sending it.
166
- */
167
- readonly supportsDispatchSelection?: true;
203
+ readonly descriptor: RuntimeAdapterDescriptor;
168
204
  detect(): Promise<RuntimeDetectResult>;
169
- capabilities(): RuntimeCapabilities;
170
- start(task: TaskOfferPayload, ctx: TaskContext): Promise<Session>;
171
- /**
172
- * M5: declares which environment variable names (exact, or `*`-suffixed
173
- * prefix) this runtime's own CLI needs beyond the always-included
174
- * platform baseline (`daemon/environment.ts`'s `buildRuntimeEnv`) —
175
- * `task-runner.ts` builds each task's `TaskContext.env` from this instead
176
- * of ever handing a spawned agent the daemon's raw `process.env` again.
177
- * Optional and fail-closed by omission: an adapter that doesn't implement
178
- * this gets the platform baseline ONLY, never an implicit "everything."
179
- */
180
- environmentRequirements?(): RuntimeEnvironmentRequirements;
205
+ prepare(input: RuntimeAdapterPrepareInput): Promise<RuntimeAdapterPrepareResult>;
181
206
  }
207
+ /** Copy then deeply freeze descriptor authority so callers cannot retain a mutable source reference. */
208
+ export declare function freezeRuntimeAdapterDescriptor(descriptor: RuntimeAdapterDescriptor): RuntimeAdapterDescriptor;
209
+ /** Copy then freeze the complete safe operation authority just before claim. */
210
+ export declare function sealRuntimeOperationManifest(manifest: RuntimeOperationManifest): RuntimeOperationManifest;
182
211
  /**
183
- * Thrown by `RuntimeAdapter.start` when the task can never succeed on this
184
- * adapter as offered an unsupported `PermissionPolicy` (fail-closed) or an
185
- * instruction shape the adapter can't handle (e.g. a blob-ref in M0) as
186
- * opposed to a transient/environmental failure (spawn error, missing
187
- * credentials) that might succeed on a later retry. The daemon uses this
188
- * distinction to set `task.fail`'s `retryable` flag correctly instead of
189
- * treating every `start()` failure the same way.
212
+ * Thrown by a prepared operation's `start()` when an already admitted task
213
+ * cannot continue because an internal invariant was violated. Permanent
214
+ * offer semantics are rejected by `RuntimeAdapter.prepare()` before claim;
215
+ * this class remains for post-claim operational/session failures whose
216
+ * retryability is already part of the frozen task behavior.
190
217
  */
191
218
  export declare class PolicyUnsupportedError extends Error {
192
219
  constructor(message: string);
193
220
  }
194
221
  /**
195
222
  * Thrown by {@link Session.steer} on an adapter whose runtime has no
196
- * mid-turn steering channel at all (`capabilities().steer === false`) — a
223
+ * mid-turn steering channel at all (`descriptor.capabilities.steer === false`) — a
197
224
  * permanent property of the runtime, never a transient failure. Typed
198
225
  * rather than a bare `Error` so the daemon can classify an inbound
199
226
  * `task.steer` for such a runtime as non-retryable (record + ack, cursor
@@ -201,7 +228,7 @@ export declare class PolicyUnsupportedError extends Error {
201
228
  * on message strings.
202
229
  */
203
230
  export declare class SteerUnsupportedError extends Error {
204
- /** The `RuntimeAdapter.id` that cannot steer (e.g. `claude`, `codex`). */
231
+ /** The `RuntimeAdapter.descriptor.id` that cannot steer (e.g. `claude`, `codex`). */
205
232
  readonly runtimeId: string;
206
233
  constructor(runtimeId: string, message: string);
207
234
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byok-sdk/client",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "BYOK SDK client daemon: runs on the end user's machine, pairs with a SaaS server, and drives a local coding-agent runtime",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "homepage": "https://github.com/Ancienttwo/byok-sdk#readme",
16
16
  "engines": {
17
- "node": ">=22.19.0"
17
+ "node": ">=22.22.0"
18
18
  },
19
19
  "sideEffects": false,
20
20
  "main": "./dist/index.js",
@@ -43,17 +43,6 @@
43
43
  "publishConfig": {
44
44
  "access": "public"
45
45
  },
46
- "dependencies": {
47
- "@earendil-works/pi-coding-agent": "0.84.1",
48
- "ws": "^8.21.1",
49
- "@byok-sdk/core": "0.3.0",
50
- "@byok-sdk/protocol": "0.3.0"
51
- },
52
- "devDependencies": {
53
- "@types/ws": "^8.18.1",
54
- "@hono/node-server": "^2.0.10",
55
- "@byok-sdk/server": "0.3.0"
56
- },
57
46
  "scripts": {
58
47
  "build": "tsup && tsc -p tsconfig.build.json && node scripts/check-adapters-entry.mjs",
59
48
  "dev": "tsup --watch",
@@ -64,5 +53,16 @@
64
53
  "audit:adapter-task-smoke": "node scripts/adapter-task-smoke.mjs",
65
54
  "audit:credentials": "node scripts/linux-credential-audit.mjs",
66
55
  "clean": "rm -rf dist"
56
+ },
57
+ "dependencies": {
58
+ "@earendil-works/pi-coding-agent": "0.84.1",
59
+ "@byok-sdk/core": "0.4.0",
60
+ "@byok-sdk/protocol": "0.4.0",
61
+ "ws": "^8.21.1"
62
+ },
63
+ "devDependencies": {
64
+ "@types/ws": "^8.18.1",
65
+ "@byok-sdk/server": "0.4.0",
66
+ "@hono/node-server": "^2.0.10"
67
67
  }
68
- }
68
+ }