@hraness/xcb 0.9.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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/MANAGED-CODEX.md +213 -0
  3. package/README.md +555 -0
  4. package/dist/accounts.d.ts +46 -0
  5. package/dist/broker-descriptors.d.ts +5 -0
  6. package/dist/broker.d.ts +62 -0
  7. package/dist/browser-session.d.ts +161 -0
  8. package/dist/canonical-json.d.ts +2 -0
  9. package/dist/capabilities.d.ts +72 -0
  10. package/dist/claude-api-models.d.ts +24 -0
  11. package/dist/claude-api-transport.d.ts +5 -0
  12. package/dist/claude-api.d.ts +23 -0
  13. package/dist/claude-credentials.d.ts +13 -0
  14. package/dist/claude-options.d.ts +10 -0
  15. package/dist/claude-sdk.d.ts +48 -0
  16. package/dist/claude-task-adapter.d.ts +65 -0
  17. package/dist/cli.js +4190 -0
  18. package/dist/codex-account-process.d.ts +149 -0
  19. package/dist/codex-account-transport.d.ts +39 -0
  20. package/dist/codex-account.d.ts +126 -0
  21. package/dist/codex-config.d.ts +53 -0
  22. package/dist/codex-host.d.ts +40 -0
  23. package/dist/codex-managed-baseline.d.ts +5 -0
  24. package/dist/codex-managed-catalog.d.ts +32 -0
  25. package/dist/codex-managed-config.d.ts +93 -0
  26. package/dist/codex-managed-ledger.d.ts +37 -0
  27. package/dist/codex-managed-session.d.ts +62 -0
  28. package/dist/codex-managed-task-adapter.d.ts +21 -0
  29. package/dist/codex-process.d.ts +67 -0
  30. package/dist/codex-protocol-manifest.d.ts +27 -0
  31. package/dist/codex-relay.d.ts +80 -0
  32. package/dist/codex-scratch.d.ts +36 -0
  33. package/dist/codex-session.d.ts +44 -0
  34. package/dist/codex-task-adapter.d.ts +24 -0
  35. package/dist/codex-task-process.d.ts +21 -0
  36. package/dist/devin-acp.d.ts +105 -0
  37. package/dist/devin-adapter.d.ts +44 -0
  38. package/dist/devin-client.d.ts +36 -0
  39. package/dist/devin-mcp.d.ts +28 -0
  40. package/dist/egress-bridge.d.ts +35 -0
  41. package/dist/egress-client.d.ts +66 -0
  42. package/dist/index-kg2gx694.js +7217 -0
  43. package/dist/index.d.ts +58 -0
  44. package/dist/index.js +3455 -0
  45. package/dist/judge.d.ts +121 -0
  46. package/dist/loopback-server.d.ts +17 -0
  47. package/dist/managed-account.d.ts +176 -0
  48. package/dist/models.d.ts +23 -0
  49. package/dist/os-sandbox.d.ts +168 -0
  50. package/dist/private-file.d.ts +215 -0
  51. package/dist/process-port.d.ts +44 -0
  52. package/dist/process-write.d.ts +13 -0
  53. package/dist/provider-process.d.ts +26 -0
  54. package/dist/public-web.d.ts +21 -0
  55. package/dist/router.d.ts +43 -0
  56. package/dist/runtime.d.ts +90 -0
  57. package/dist/sqlite-port.d.ts +29 -0
  58. package/dist/task-runtime.d.ts +150 -0
  59. package/dist/validation.d.ts +6 -0
  60. package/package.json +70 -0
  61. package/sandbox/loopback-forwarder.cjs +172 -0
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Provider-neutral judgment port ("jev-style"): one fast request answers a
3
+ * batch of typed questions against one state object. A `Judge` is a routing,
4
+ * classification, and continuation helper — never an execution or custody
5
+ * boundary. Every consumer keeps a deterministic path when no judge is
6
+ * configured or a call fails, and bounds what it sends.
7
+ *
8
+ * Question kinds mirror the System One wire shape so additional backends can
9
+ * implement the same port: `noul` (yes/no probability), `choice` (pick one of
10
+ * labelled options with confidence), and `score` (score against criteria).
11
+ */
12
+ export type JudgeState = string | object;
13
+ export interface NoulQuestion {
14
+ type: "noul";
15
+ instructions: string;
16
+ criteria?: {
17
+ true?: string;
18
+ false?: string;
19
+ };
20
+ }
21
+ export interface ChoiceQuestion {
22
+ type: "choice";
23
+ instructions: string;
24
+ criteria: Record<string, string | null>;
25
+ }
26
+ export interface ScoreQuestion {
27
+ type: "score";
28
+ instructions: string;
29
+ criteria: string[];
30
+ }
31
+ export type JudgeQuestion = NoulQuestion | ChoiceQuestion | ScoreQuestion;
32
+ export type JudgeQuestions = Record<string, JudgeQuestion>;
33
+ export interface NoulAnswer {
34
+ type: "noul";
35
+ noul: number;
36
+ }
37
+ export interface ChoiceAnswer {
38
+ type: "choice";
39
+ choice: string;
40
+ confidence: number;
41
+ probabilities: Record<string, number>;
42
+ }
43
+ export interface ScoreAnswer {
44
+ type: "score";
45
+ score: number;
46
+ confidence: number;
47
+ probabilities: Record<string, number>;
48
+ }
49
+ export type JudgeAnswer = NoulAnswer | ChoiceAnswer | ScoreAnswer;
50
+ export interface JudgeAnswers {
51
+ answers: Record<string, JudgeAnswer>;
52
+ model?: string;
53
+ usage?: {
54
+ input_tokens?: number;
55
+ output_tokens?: number;
56
+ };
57
+ }
58
+ /** Anything that can answer a batch of judgment questions. */
59
+ export interface Judge {
60
+ ask(state: JudgeState, questions: JudgeQuestions): Promise<JudgeAnswers>;
61
+ }
62
+ export declare const SYSTEM_ONE_URL = "https://api.typesafe.ai/v1/systemone";
63
+ export declare const DEFAULT_JUDGE_MODEL = "jev-latest";
64
+ export declare const JUDGE_TOKEN_FILE = "jev-api-token";
65
+ export declare const JUDGE_KEY_ENV = "XCB_JEV_API_KEY";
66
+ export declare const JUDGE_KEY_VENDOR_ENV = "TYPESAFE_API_KEY";
67
+ export declare const JUDGE_URL_ENV = "XCB_JEV_URL";
68
+ export declare const JUDGE_MODEL_ENV = "XCB_JEV_MODEL";
69
+ export declare const MAX_JUDGE_STATE_BYTES: number;
70
+ export declare const MAX_JUDGE_QUESTIONS = 64;
71
+ export declare const MAX_JUDGE_INSTRUCTION_BYTES: number;
72
+ /** Validates a question batch before it reaches any backend. */
73
+ export declare function checkJudgeQuestions(questions: JudgeQuestions): JudgeQuestions;
74
+ /** Validates the serialized state before it reaches any backend. */
75
+ export declare function checkJudgeState(state: JudgeState): JudgeState;
76
+ /** Validates a System One response body; throws on anything malformed. */
77
+ export declare function parseJudgeResponse(status: number, body: string): JudgeAnswers;
78
+ /** Validates a complete response against the exact questions that were sent. */
79
+ export declare function checkJudgeAnswers(questions: JudgeQuestions, response: JudgeAnswers): JudgeAnswers;
80
+ /** Where a resolved judge key came from; `status` reports it, secrets never print. */
81
+ export type JudgeKeySource = "env" | "vault";
82
+ /** One HTTPS endpoint the judge may call; only `https` with a clean authority. */
83
+ export declare function parseJudgeEndpoint(url: string): URL;
84
+ export interface SystemOneOptions {
85
+ /** The API key. Never logged or persisted by the client. */
86
+ token: string;
87
+ /** Defaults to `jev-latest`. */
88
+ model?: string;
89
+ /** Defaults to the System One endpoint. */
90
+ endpoint?: string;
91
+ /** Injectable transport for tests; defaults to global `fetch`. */
92
+ fetch?: typeof fetch;
93
+ /** Request timeout in ms; defaults to 15000. */
94
+ timeoutMs?: number;
95
+ }
96
+ /** The TypeSafe System One backend: a `Judge` over one bounded HTTPS POST. */
97
+ export declare function createSystemOneJudge(options: SystemOneOptions): Judge;
98
+ /** Stores a judge key in the private state root; refuses to clobber. */
99
+ export declare function storeJudgeKey(stateRoot: string, key: string | Uint8Array): Promise<void>;
100
+ /** Removes the vaulted judge key; returns whether a file was removed. */
101
+ export declare function removeJudgeKey(stateRoot: string): Promise<boolean>;
102
+ export declare function hasJudgeKey(stateRoot: string): Promise<boolean>;
103
+ /** Resolves the effective judge key: environment first, then the vault file. */
104
+ export declare function resolveJudgeKey(stateRoot: string, env?: (name: string) => string | undefined): Promise<{
105
+ token: string;
106
+ source: JudgeKeySource;
107
+ } | null>;
108
+ export interface ResolveJudgeOptions {
109
+ /** Private state root holding the vault file. */
110
+ stateRoot: string;
111
+ /** The judge extension gate; resolution returns null when false. */
112
+ enabled: boolean;
113
+ model?: string;
114
+ endpoint?: string;
115
+ env?: (name: string) => string | undefined;
116
+ fetch?: typeof fetch;
117
+ }
118
+ /** Prevents the vaulted System One key from being redirected to another origin. */
119
+ export declare function checkJudgeKeyTarget(source: JudgeKeySource, endpoint?: string): void;
120
+ /** Resolves a ready judge when enabled and keyed; null for either absence. */
121
+ export declare function resolveJudge(options: ResolveJudgeOptions): Promise<Judge | null>;
@@ -0,0 +1,17 @@
1
+ export interface LoopbackServer {
2
+ readonly port: number;
3
+ readonly pendingRequests: number;
4
+ stop(immediate?: boolean): Promise<void>;
5
+ }
6
+ export type LoopbackServerOptions = Readonly<{
7
+ hostname: string;
8
+ /** When set, listen on this unix socket path instead of a TCP port —
9
+ * the host-side half of an in-namespace service forward. `port` reports
10
+ * 0; the caller owns the advertised reachability story. */
11
+ unixSocket?: string;
12
+ idleTimeoutMs?: number;
13
+ maxRequestBodyBytes?: number;
14
+ fetch(request: Request): Response | Promise<Response>;
15
+ error(error: unknown): Response;
16
+ }>;
17
+ export declare function createLoopbackServer(options: LoopbackServerOptions): Promise<LoopbackServer>;
@@ -0,0 +1,176 @@
1
+ import type { AccountLeaseStore } from "./accounts.ts";
2
+ import type { BrowserSessionBinding } from "./browser-session.ts";
3
+ import { type AgentProvider } from "./validation.ts";
4
+ /**
5
+ * Provider-neutral managed-account custody. This module owns the custody
6
+ * discipline every provider controller shares — the account lease, the exact
7
+ * binding (`provider`, `accountId`, `owner`, lease and process generations),
8
+ * the serialized state machine, unresolved-login recovery and the joined-close
9
+ * barrier. It is not an execution or authentication qualification: admitting a
10
+ * provider's runtime, its login transport and its usage surface remain
11
+ * separate host evidence.
12
+ *
13
+ * Provider-owned semantics stay behind `ManagedAccountSemantics`: the neutral
14
+ * controller never parses a provider account payload, chooses plan labels or
15
+ * guesses challenge shapes. The transport is a closed port — account reads,
16
+ * login lifecycle, logout and close only; no raw RPC, token export or turn
17
+ * method exists here.
18
+ */
19
+ export type ManagedAccountState = "unchecked" | "signed-out" | "signing-in" | "signed-in" | "unavailable" | "recovery-required" | "closed";
20
+ export type ManagedAccountBinding = Readonly<{
21
+ provider: AgentProvider;
22
+ accountId: string;
23
+ owner: string;
24
+ leaseGeneration: number;
25
+ processGeneration: number;
26
+ }>;
27
+ /** How a login is driven. `provider-native` selects a provider-owned variant
28
+ * (Codex `chatgpt`/`chatgptDeviceCode`, Devin web login); `browser-session`
29
+ * drives sign-in inside the caller's per-account browser custody session —
30
+ * the session binding must equal the account's provider, accountId and owner
31
+ * so one account's cookie jar can never authenticate another. */
32
+ export type ManagedAccountLoginMethod = Readonly<{
33
+ type: "provider-native";
34
+ method: string;
35
+ }> | Readonly<{
36
+ type: "browser-session";
37
+ session: BrowserSessionBinding;
38
+ }>;
39
+ export type ManagedAccountLoginChallenge = Readonly<{
40
+ type: "provider-native";
41
+ method: string;
42
+ loginId: string;
43
+ fields: Readonly<Record<string, string>>;
44
+ }> | Readonly<{
45
+ type: "browser-session";
46
+ loginId: string;
47
+ session: BrowserSessionBinding;
48
+ navigationUrl: string;
49
+ }>;
50
+ /** Neutral projection the provider semantics maps its account payload onto.
51
+ * `state` is the only claim the controller interprets; `planLabel`/`detail`
52
+ * are bounded display text and never authority. */
53
+ export type ManagedAccountProjection = Readonly<{
54
+ state: "signed-out" | "signing-in" | "signed-in" | "unavailable";
55
+ planLabel?: string;
56
+ detail?: string;
57
+ }>;
58
+ export type ManagedAccountSnapshot = Readonly<{
59
+ provider: AgentProvider;
60
+ accountId: string;
61
+ state: ManagedAccountState;
62
+ accountGeneration: number;
63
+ processGeneration: number;
64
+ pendingLoginId: string | null;
65
+ planLabel?: string;
66
+ detail?: string;
67
+ }>;
68
+ export type ManagedAccountRequest = Readonly<{
69
+ binding: ManagedAccountBinding;
70
+ accountGeneration: number;
71
+ signal: AbortSignal;
72
+ deadlineMs: number;
73
+ }>;
74
+ export type ManagedAccountResponse = Readonly<{
75
+ binding: ManagedAccountBinding;
76
+ accountGeneration: number;
77
+ value: unknown;
78
+ }>;
79
+ export type ManagedAccountEvent = Readonly<{
80
+ binding: ManagedAccountBinding;
81
+ type: "account-updated" | "login-completed" | "disconnected";
82
+ loginId?: string | null;
83
+ success?: boolean;
84
+ }>;
85
+ export type ManagedAccountCloseReceipt = Readonly<{
86
+ binding: ManagedAccountBinding;
87
+ processExited: boolean;
88
+ processGroupStopped: boolean;
89
+ stdoutEnded: boolean;
90
+ stderrEnded: boolean;
91
+ writesSettled: boolean;
92
+ requestsSettled: boolean;
93
+ notificationsSettled: boolean;
94
+ }>;
95
+ /** Trusted implementation owns initialize, runtime/schema admission,
96
+ * credential custody and process custody. There is deliberately no raw RPC,
97
+ * token export or turn method. Return the handle before asynchronous launch,
98
+ * so close can join failed launches. A transport may implement extra
99
+ * provider-owned reads internally; they still run inside this fence. */
100
+ export interface ManagedAccountTransport {
101
+ accountRead(request: ManagedAccountRequest): Promise<ManagedAccountResponse>;
102
+ startLogin(request: ManagedAccountRequest & {
103
+ method: ManagedAccountLoginMethod;
104
+ }): Promise<ManagedAccountResponse>;
105
+ cancelLogin(request: ManagedAccountRequest & {
106
+ loginId: string;
107
+ }): Promise<ManagedAccountResponse>;
108
+ logout(request: ManagedAccountRequest): Promise<ManagedAccountResponse>;
109
+ close(request: {
110
+ binding: ManagedAccountBinding;
111
+ deadlineMs: number;
112
+ }): Promise<ManagedAccountCloseReceipt>;
113
+ }
114
+ /** Provider-owned interpretation. Runs inside the controller's serialized,
115
+ * generation-fenced operation; must throw on any payload it does not fully
116
+ * admit rather than coerce. The controller itself owns the closed challenge
117
+ * envelope and cancel-status enum — the only provider-specific
118
+ * interpretation is the account payload's projection onto the neutral
119
+ * readiness state. */
120
+ export interface ManagedAccountSemantics {
121
+ /** Map the transport's accountRead payload to a neutral projection. May
122
+ * issue further provider reads through the same fenced transport (paged
123
+ * model catalogs, quota detail) before returning. */
124
+ projectAccount(value: unknown, request: ManagedAccountRequest, transport: ManagedAccountTransport): Promise<ManagedAccountProjection>;
125
+ }
126
+ /** Bounded, read-only usage/quota observation. Windows are provider-named
127
+ * labels with optional utilization; `rawSha256` binds the provider's exact
128
+ * response as evidence without carrying it — quota bytes never enter custody
129
+ * journals, receipts or logs. A missing reader means the provider has no
130
+ * admitted usage surface; it is not a zero-usage claim. */
131
+ export type ManagedAccountUsageWindow = Readonly<{
132
+ label: string;
133
+ usedPercent: number | null;
134
+ resetsAt: number | null;
135
+ }>;
136
+ export type ManagedAccountUsage = Readonly<{
137
+ binding: ManagedAccountBinding;
138
+ observedAt: number;
139
+ planLabel: string | null;
140
+ windows: readonly ManagedAccountUsageWindow[];
141
+ rawSha256: string;
142
+ }>;
143
+ export interface ManagedAccountUsageReader {
144
+ readUsage(request: ManagedAccountRequest): Promise<ManagedAccountUsage>;
145
+ }
146
+ export type ManagedAccountOptions = Readonly<{
147
+ provider: AgentProvider;
148
+ accountId: string;
149
+ owner: string;
150
+ processGeneration: number;
151
+ leases: AccountLeaseStore;
152
+ transportFactory: (binding: ManagedAccountBinding, onEvent: (event: ManagedAccountEvent) => void) => ManagedAccountTransport;
153
+ semantics: ManagedAccountSemantics;
154
+ usageReader?: ManagedAccountUsageReader;
155
+ now?: () => number;
156
+ operationTimeoutMs?: number;
157
+ closeTimeoutMs?: number;
158
+ }>;
159
+ export interface ManagedAccountController {
160
+ readonly binding: () => ManagedAccountBinding | undefined;
161
+ snapshot(): ManagedAccountSnapshot;
162
+ check(signal?: AbortSignal): Promise<ManagedAccountSnapshot>;
163
+ startLogin(method: ManagedAccountLoginMethod, signal?: AbortSignal): Promise<ManagedAccountLoginChallenge>;
164
+ cancelLogin(loginId: string, signal?: AbortSignal): Promise<Readonly<{
165
+ status: "canceled" | "notFound";
166
+ }>>;
167
+ logout(signal?: AbortSignal): Promise<ManagedAccountSnapshot>;
168
+ /** Bounded quota observation through the admitted reader; `null` when the
169
+ * provider has none. Never extends custody or refreshes credentials. */
170
+ readUsage(signal?: AbortSignal): Promise<ManagedAccountUsage | null>;
171
+ close(): Promise<Readonly<{
172
+ released: boolean;
173
+ state: "closed" | "recovery-required";
174
+ }>>;
175
+ }
176
+ export declare function createManagedAccountController(options: ManagedAccountOptions): ManagedAccountController;
@@ -0,0 +1,23 @@
1
+ import { type AgentProvider } from "./validation.ts";
2
+ export type ModelEntry = Readonly<{
3
+ id: string;
4
+ inputUsdPerMillion: number;
5
+ outputUsdPerMillion: number;
6
+ supportsStructuredOutput: boolean;
7
+ available: boolean;
8
+ classifierEligible: boolean;
9
+ }>;
10
+ export type ModelCatalog = Readonly<{
11
+ provider: AgentProvider;
12
+ observedAt: number;
13
+ models: readonly ModelEntry[];
14
+ }>;
15
+ /** Host-supplied catalog; no invented model identifiers or unobserved availability. */
16
+ export declare function selectClassifierModel(value: unknown, now: number, maxAgeMs?: number): ModelEntry;
17
+ export type Classification = Readonly<{
18
+ respond: boolean;
19
+ confidence: number;
20
+ reason: "requested" | "helpful" | "human_active" | "not_needed" | "uncertain";
21
+ }>;
22
+ /** Strict JSON only: prose, fenced JSON, unknown fields and contradictory decisions fail closed. */
23
+ export declare function parseClassification(value: unknown): Classification;
@@ -0,0 +1,168 @@
1
+ import { type BoundedProviderProcessFactory } from "./provider-process.ts";
2
+ /**
3
+ * OS-confinement port for provider processes. A backend turns a closed launch
4
+ * spec into a plan: a canonical policy artifact, its digest, the wrapper
5
+ * executable the child actually spawns, and a pure `wrap()` that rewrites one
6
+ * invocation onto the admitted policy. Planning is asynchronous so backends
7
+ * can re-verify their own admitted artifacts; wrapping is synchronous so it
8
+ * can run inside provider SDKs that spawn from a sync callback.
9
+ *
10
+ * Custody stays with the caller: bounded stdio, detached process groups,
11
+ * SIGTERM/SIGKILL escalation and join evidence are unchanged underneath every
12
+ * backend. A plan proves policy construction and artifact admission only — it
13
+ * is not proof that the kernel enforced the policy. Kernel-boundary evidence
14
+ * belongs to `qualification/` probes, and every receipt keeps
15
+ * `productionQualified: false` until a host supplies it.
16
+ *
17
+ * - `seatbelt` (darwin): the caller supplies reviewed SBPL policy text through
18
+ * `generateProfile`; the plan wraps argv as `/usr/bin/sandbox-exec -f
19
+ * <policyPath> <executable> <args...>` byte-identically to the launchers this
20
+ * port replaces. Environment passes through — callers already close it.
21
+ * - `bwrap` (linux): bubblewrap builds a private rootfs from per-file
22
+ * `--ro-bind` entries, `--bind` for the writable scratch/account roots,
23
+ * `--unshare-all`, `--new-session`, `--die-with-parent`, `--clearenv` +
24
+ * `--setenv`. Only `network: "denied"` is plannable: bwrap cannot express
25
+ * per-destination egress, and a unix-socket proxy bridge is a separate
26
+ * qualification. The wrapper binary is itself an admitted artifact whose
27
+ * SHA-256 is re-verified from a checked descriptor at plan time.
28
+ * `--setenv` values are visible in the wrapper's own command line, so a
29
+ * forwarder plan may instead declare `envFile`: `wrap()` then persists
30
+ * the closed env into the writable scratch (mode 0600) and emits no
31
+ * `--setenv` at all — the forwarder reads, deletes, and injects the
32
+ * pairs only into the supervised child's environment.
33
+ */
34
+ export type OsSandboxNetworkPolicy = "denied" | "loopback" | "provider-tcp443-dns";
35
+ export type OsSandboxBackendName = "seatbelt" | "bwrap";
36
+ /** The platform the *admitted runtime* targets — host admission evidence, not
37
+ * `process.platform`. A backend refuses a spec whose platform it cannot
38
+ * enforce; synthetic custody tests exercise the real launch path on any host. */
39
+ export type OsSandboxPlatform = "darwin" | "linux";
40
+ export type OsSandboxSpec = Readonly<{
41
+ platform: OsSandboxPlatform;
42
+ /** Absolute canonical path of the in-sandbox executable (the admitted run
43
+ * snapshot), bound read-only and executable. */
44
+ executable: string;
45
+ /** Per-run private writable root (home/tmp/work). */
46
+ scratch: string;
47
+ /** Persistent private writable root holding account credentials. */
48
+ accountHome?: string;
49
+ /** Extra absolute file literals admitted read-only inside the sandbox
50
+ * (admitted library closure, fixed config). Never directories unless the
51
+ * backend documents subpath semantics. */
52
+ readOnlyPaths?: readonly string[];
53
+ /** Extra absolute paths admitted read-write inside the sandbox beyond
54
+ * scratch/accountHome — e.g. the consumer workspace for providers whose own
55
+ * filesystem tools write directly rather than through a host broker. Paths
56
+ * must not contain or enclose the executable (unless a `protectedPaths`
57
+ * entry re-covers it), each other, scratch, accountHome, policyPath, the
58
+ * egress socket, or forwarder artifacts. */
59
+ readWritePaths?: readonly string[];
60
+ /** Read-only re-covers mounted *after* the writable binds, so a path nested
61
+ * inside a writable root stays immutable (e.g. a provider's install tree
62
+ * inside its writable state root). On seatbelt these emit deny-write
63
+ * rules; on bwrap they are later ro binds that shadow the rw parent. Every
64
+ * entry must sit inside a writable root. */
65
+ protectedPaths?: readonly string[];
66
+ /** Masked subtrees nested inside a writable root: contents stay reachable
67
+ * on the host but are invisible inside the sandbox (e.g. credential stores
68
+ * that happen to sit under a workspace bound read-write). On seatbelt
69
+ * these emit deny read+write rules; on bwrap they are tmpfs mounts that
70
+ * shadow the bound subtree. Every entry must sit inside a writable root
71
+ * and must never cover the executable. */
72
+ hiddenPaths?: readonly string[];
73
+ network: OsSandboxNetworkPolicy;
74
+ /** Canonical absolute path of a host-side egress-bridge unix socket,
75
+ * bind-mounted read-write. Required iff `network` is
76
+ * `"provider-tcp443-dns"` on a bwrap plan; refused by seatbelt, whose
77
+ * profile carries egress internally. */
78
+ egressSocket?: string;
79
+ /** Optional in-namespace CONNECT forwarder for stock binaries that do not
80
+ * consume the bridge socket natively: an admitted JS runtime plus the
81
+ * admitted forwarder script are bound read-only and become the namespace
82
+ * entry point — `runtime script <socket> <port> <lo|- > <env|- > <svc|- > -- <executable> <args>`.
83
+ * The forwarder binds `127.0.0.1:<port>` and launches the child with
84
+ * standard proxy variables, so the plan env needs no proxy keys. Requires
85
+ * `egressSocket`; refused by seatbelt.
86
+ * `envFile` is an optional absolute path inside the writable scratch or
87
+ * account root: when set, `wrap()` writes the invocation env there
88
+ * (mode 0600) and the forwarder injects it into the child, keeping every
89
+ * value — secret or not — out of the wrapper's command line.
90
+ * `service` is an optional second listener: the forwarder binds
91
+ * `127.0.0.1:<service.port>` inside the namespace and pipes each accepted
92
+ * connection to `service.socket`, a host-side unix socket bound into the
93
+ * namespace — the in-namespace consumption path for host services (the
94
+ * tool relay) that are not CONNECT egress. */
95
+ egressForward?: Readonly<{
96
+ runtime: string;
97
+ script: string;
98
+ port: number;
99
+ envFile?: string;
100
+ service?: Readonly<{
101
+ socket: string;
102
+ port: number;
103
+ }>;
104
+ }>;
105
+ /** Absolute path of the durable policy artifact the caller persists
106
+ * (`sandbox.sb`, `sandbox.json`). Identity flows into custody journals. */
107
+ policyPath: string;
108
+ }>;
109
+ export type OsSandboxWrapInput = Readonly<{
110
+ args: readonly string[];
111
+ env: Readonly<Record<string, string>>;
112
+ cwd: string;
113
+ }>;
114
+ export type OsSandboxPlan = Readonly<{
115
+ backend: OsSandboxBackendName;
116
+ /** Canonical policy bytes: SBPL text on seatbelt, canonical plan JSON on
117
+ * bwrap. The caller persists this verbatim at `spec.policyPath`. */
118
+ policy: string;
119
+ policySha256: string;
120
+ /** The wrapper executable the child process spawns. */
121
+ executable: string;
122
+ wrap(input: OsSandboxWrapInput): {
123
+ args: readonly string[];
124
+ env: Readonly<Record<string, string>>;
125
+ };
126
+ }>;
127
+ export interface OsSandboxBackend {
128
+ readonly name: OsSandboxBackendName;
129
+ plan(spec: OsSandboxSpec): Promise<OsSandboxPlan>;
130
+ }
131
+ /** Re-verifies an admitted executable from a checked descriptor: owner,
132
+ * file identity, size bound, no-follow canonical path, and exact SHA-256.
133
+ * The owner may be the current user or root — a root-owned system tool like
134
+ * a distribution `bwrap` is at least as tamper-evident as a user-owned file.
135
+ * Any mutation or relabel is `OS_SANDBOX_EXECUTABLE_CHANGED`; a missing or
136
+ * non-file path is `OS_SANDBOX_EXECUTABLE_INVALID`. */
137
+ export declare function verifyOsSandboxExecutable(executablePath: string, sha256: string, sizeLimit: bigint): Promise<void>;
138
+ /** Pure seatbelt planning: the wrapper argv and artifact identity for an
139
+ * already-reviewed SBPL profile. Exported so tests can pin the exact spawn
140
+ * contract on any platform; `createSeatbeltOsSandbox` adds the darwin
141
+ * platform gate and generator ownership. */
142
+ export declare function planSeatbeltPolicy(input: OsSandboxSpec, policy: string): OsSandboxPlan;
143
+ /** Pure bwrap planning: canonical policy JSON plus wrapper argv for an
144
+ * already-validated spec. Exported so tests can pin the exact contract on any
145
+ * platform; `createBwrapOsSandbox` adds the linux platform gate, the
146
+ * `network: "denied"` bound, and wrapper-artifact re-verification. */
147
+ export declare function planBwrapPolicy(input: OsSandboxSpec, wrapperExecutable: string): OsSandboxPlan;
148
+ /** macOS seatbelt backend. The SBPL policy text is host-owned admission input
149
+ * — the port owns wrapping, canonical identity and the durable-artifact
150
+ * contract. `/usr/bin/sandbox-exec` is a fixed literal: PATH cannot inject. */
151
+ export declare function createSeatbeltOsSandbox(options: Readonly<{
152
+ /** Reviewed policy generator. Receives the validated spec; returns exact
153
+ * SBPL text. The generator, not this port, owns rule semantics. */
154
+ generateProfile(spec: OsSandboxSpec): string;
155
+ }>): OsSandboxBackend;
156
+ /** Linux bubblewrap backend, offline policy only. The wrapper binary is a
157
+ * second admitted artifact, re-verified at plan time. */
158
+ export declare function createBwrapOsSandbox(options: Readonly<{
159
+ /** Absolute canonical path of the admitted `bwrap` binary. */
160
+ executable: string;
161
+ /** SHA-256 of the admitted `bwrap` bytes. */
162
+ sha256: string;
163
+ }>): OsSandboxBackend;
164
+ /** Composes an admitted plan onto the unchanged bounded-provider custody:
165
+ * argv/env are rewritten, stdout/stderr bounds, detached group custody and
166
+ * join semantics are untouched. The returned factory stays synchronous so it
167
+ * can run inside provider SDKs that spawn from a sync callback. */
168
+ export declare function createSandboxedProviderProcessFactory(plan: OsSandboxPlan): BoundedProviderProcessFactory;