@intutic/gate 1.10.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.
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/actions.d.ts +86 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +239 -0
- package/dist/actions.js.map +1 -0
- package/dist/client.d.ts +94 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +207 -0
- package/dist/client.js.map +1 -0
- package/dist/dsh.d.ts +162 -0
- package/dist/dsh.d.ts.map +1 -0
- package/dist/dsh.js +189 -0
- package/dist/dsh.js.map +1 -0
- package/dist/errors.d.ts +41 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/eve.d.ts +425 -0
- package/dist/eve.d.ts.map +1 -0
- package/dist/eve.js +378 -0
- package/dist/eve.js.map +1 -0
- package/dist/gate.d.ts +113 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +274 -0
- package/dist/gate.js.map +1 -0
- package/dist/harness.d.ts +482 -0
- package/dist/harness.d.ts.map +1 -0
- package/dist/harness.js +504 -0
- package/dist/harness.js.map +1 -0
- package/dist/headers.d.ts +26 -0
- package/dist/headers.d.ts.map +1 -0
- package/dist/headers.js +30 -0
- package/dist/headers.js.map +1 -0
- package/dist/imagecheck.d.ts +93 -0
- package/dist/imagecheck.d.ts.map +1 -0
- package/dist/imagecheck.js +286 -0
- package/dist/imagecheck.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/managedAgents.d.ts +375 -0
- package/dist/managedAgents.d.ts.map +1 -0
- package/dist/managedAgents.js +446 -0
- package/dist/managedAgents.js.map +1 -0
- package/dist/mastra.d.ts +175 -0
- package/dist/mastra.d.ts.map +1 -0
- package/dist/mastra.js +161 -0
- package/dist/mastra.js.map +1 -0
- package/dist/openai.d.ts +392 -0
- package/dist/openai.d.ts.map +1 -0
- package/dist/openai.js +658 -0
- package/dist/openai.js.map +1 -0
- package/dist/shlex.d.ts +16 -0
- package/dist/shlex.d.ts.map +1 -0
- package/dist/shlex.js +78 -0
- package/dist/shlex.js.map +1 -0
- package/dist/snapshot.d.ts +111 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +243 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/soprules.d.ts +88 -0
- package/dist/soprules.d.ts.map +1 -0
- package/dist/soprules.js +176 -0
- package/dist/soprules.js.map +1 -0
- package/dist/trueforge.d.ts +191 -0
- package/dist/trueforge.d.ts.map +1 -0
- package/dist/trueforge.js +184 -0
- package/dist/trueforge.js.map +1 -0
- package/dist/vercel.d.ts +174 -0
- package/dist/vercel.d.ts.map +1 -0
- package/dist/vercel.js +157 -0
- package/dist/vercel.js.map +1 -0
- package/dist/workflow.d.ts +209 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +254 -0
- package/dist/workflow.js.map +1 -0
- package/dist/wrapTools.d.ts +68 -0
- package/dist/wrapTools.d.ts.map +1 -0
- package/dist/wrapTools.js +95 -0
- package/dist/wrapTools.js.map +1 -0
- package/package.json +123 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ai-sdk/harness` adapter: `intuticApprovalResponder()`, `intuticSubmitApprovals()`,
|
|
3
|
+
* `intuticStaticApprovals()`, `recommendedHarnessSettings()`, and
|
|
4
|
+
* `intuticSandboxBootstrap()`.
|
|
5
|
+
*
|
|
6
|
+
* `@intutic/gate/harness` — the same idea `vercel.ts` implements for the base
|
|
7
|
+
* `ai` package (wrap the framework's own veto point around this package's
|
|
8
|
+
* `Gate.guard()`), reshaped for Vercel's sandboxed coding-agent runtime,
|
|
9
|
+
* whose veto surface is materially different from `generateText`'s.
|
|
10
|
+
*
|
|
11
|
+
* ## Confirmed against a real install
|
|
12
|
+
*
|
|
13
|
+
* `@ai-sdk/harness@1.0.75` (plus `@ai-sdk/harness-claude-code@1.0.78` and
|
|
14
|
+
* `@ai-sdk/harness-grok-build@1.0.12`) were installed and their shipped
|
|
15
|
+
* `.d.ts`/compiled source read directly (not inferred from docs alone):
|
|
16
|
+
*
|
|
17
|
+
* 1. **The `toolApproval` setting is STATIC.** `HarnessAgentSettings.toolApproval`
|
|
18
|
+
* is `HarnessAgentToolApprovalConfiguration = Readonly<Record<string,
|
|
19
|
+
* ToolApprovalStatus>>` (`dist/agent/index.d.ts`), whose own doc comment says
|
|
20
|
+
* it mirrors "AI SDK `toolApproval` object configuration for host-executed
|
|
21
|
+
* tools, **without callback support**". `vercel.ts`'s callback-shaped
|
|
22
|
+
* `intuticToolApproval()` therefore does NOT apply here — there is no place
|
|
23
|
+
* to hang a function. Per-call gating instead goes through the approval
|
|
24
|
+
* FLOW: mark tools `'user-approval'` (see {@link intuticStaticApprovals}),
|
|
25
|
+
* let the turn pause, and answer each pending approval with the gate
|
|
26
|
+
* (see {@link intuticApprovalResponder}).
|
|
27
|
+
* 2. **The portable answer path is continuation-based.**
|
|
28
|
+
* `HarnessAgentToolApprovalContinuation` carries `{ approvalResponse,
|
|
29
|
+
* toolCall }`; `continueTurn`/`continueGenerate`/`continueStream` accept
|
|
30
|
+
* `toolApprovalContinuations` (dist/agent/index.d.ts). The adapter-session
|
|
31
|
+
* method `session.submitToolApproval?({approvalId, approved, reason})` is
|
|
32
|
+
* OPTIONAL (`dist/index.d.ts` — `HarnessV1PromptControl`), and support
|
|
33
|
+
* genuinely varies per adapter: `@ai-sdk/harness-claude-code@1.0.78`
|
|
34
|
+
* implements it; `@ai-sdk/harness-grok-build@1.0.12` does not (zero
|
|
35
|
+
* occurrences in its shipped dist). This module therefore builds the
|
|
36
|
+
* responder on the continuation path and treats `submitToolApproval` as an
|
|
37
|
+
* optimization when present ({@link intuticSubmitApprovals}).
|
|
38
|
+
* 3. **Built-in sandbox tools are NOT governed by `toolApproval` at all.**
|
|
39
|
+
* They are governed only by `permissionMode: 'allow-reads' | 'allow-edits'
|
|
40
|
+
* | 'allow-all'`, which **defaults to `'allow-all'`** — the shipped doc
|
|
41
|
+
* comment says so verbatim: "Defaults to `'allow-all'`, preserving the
|
|
42
|
+
* existing bypass-permissions behavior unless users opt in." A HarnessAgent
|
|
43
|
+
* with default settings runs read/write/edit/bash/glob/grep in the sandbox
|
|
44
|
+
* with no approval step this gate could hook.
|
|
45
|
+
* {@link recommendedHarnessSettings} exists to steer callers off that
|
|
46
|
+
* default.
|
|
47
|
+
* 4. **Execution is server-side, in a sandbox.** The agent's tools run inside
|
|
48
|
+
* a microVM (`@ai-sdk/sandbox-vercel` and friends), NOT on the machine
|
|
49
|
+
* where the Intutic proxy runs — the laptop proxy cannot see sandbox
|
|
50
|
+
* egress. The only egress control available at this layer is the sandbox's
|
|
51
|
+
* own `HarnessV1NetworkPolicy` (`{mode:'allow-all'|'deny-all'} | {mode:
|
|
52
|
+
* 'custom', allowedHosts/allowedCIDRs/deniedCIDRs}`), applied via the
|
|
53
|
+
* sandbox session's optional `setNetworkPolicy?.()`. That is coarse
|
|
54
|
+
* host-level filtering, not Intutic DLP — stated plainly in
|
|
55
|
+
* `apps/docs/integrations/ai-sdk-harness.md` rather than oversold.
|
|
56
|
+
*
|
|
57
|
+
* ## What this module does NOT import
|
|
58
|
+
*
|
|
59
|
+
* Deliberately no runtime dependency on `@ai-sdk/harness` — the structural
|
|
60
|
+
* types below capture only the shapes this adapter touches, matching the
|
|
61
|
+
* convention `vercel.ts`/`mastra.ts`/`dsh.ts` established. The real package
|
|
62
|
+
* is a devDependency used by `__tests__/harness.test.ts` to (a) structurally
|
|
63
|
+
* check these types against the shipped ones and (b) run this responder's
|
|
64
|
+
* output through the REAL `collectHarnessAgentToolApprovalContinuations`
|
|
65
|
+
* machinery.
|
|
66
|
+
*
|
|
67
|
+
* @module
|
|
68
|
+
*/
|
|
69
|
+
import { type Gate, type ToolInput } from './gate.js';
|
|
70
|
+
/** Structural copy of `ai`'s `ToolApprovalResponse` prompt part (re-exported
|
|
71
|
+
* from `@ai-sdk/provider-utils@5.0.27` — confirmed field-for-field). This is
|
|
72
|
+
* the part a `role: 'tool'` message carries to answer an approval request. */
|
|
73
|
+
export interface HarnessToolApprovalResponse {
|
|
74
|
+
type: 'tool-approval-response';
|
|
75
|
+
approvalId: string;
|
|
76
|
+
approved: boolean;
|
|
77
|
+
reason?: string;
|
|
78
|
+
providerExecuted?: boolean;
|
|
79
|
+
}
|
|
80
|
+
/** Structural copy of the `toolCall` member of `@ai-sdk/harness`'s
|
|
81
|
+
* `HarnessAgentToolApprovalContinuation` (dist/agent/index.d.ts). */
|
|
82
|
+
export interface HarnessToolCallPart {
|
|
83
|
+
readonly type: 'tool-call';
|
|
84
|
+
readonly toolCallId: string;
|
|
85
|
+
readonly toolName: string;
|
|
86
|
+
readonly input: unknown;
|
|
87
|
+
readonly providerExecuted?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/** Structural copy of `@ai-sdk/harness`'s `HarnessAgentToolApprovalContinuation`
|
|
90
|
+
* — the element type of the `toolApprovalContinuations` array
|
|
91
|
+
* `continueGenerate`/`continueStream` accept. */
|
|
92
|
+
export interface HarnessToolApprovalContinuation {
|
|
93
|
+
readonly approvalResponse: HarnessToolApprovalResponse;
|
|
94
|
+
readonly toolCall: HarnessToolCallPart;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* One pending tool-approval request, in the shape this responder consumes.
|
|
98
|
+
*
|
|
99
|
+
* Covers BOTH places a HarnessAgent surfaces one:
|
|
100
|
+
*
|
|
101
|
+
* - the `tool-approval-request` stream/message parts of a running turn
|
|
102
|
+
* (paired with their `tool-call` parts — `input` is the parsed value), and
|
|
103
|
+
* - `HarnessAgentPendingToolApproval` rows from a suspended session, where
|
|
104
|
+
* `input` is a JSON **string** (confirmed: `HarnessV1PendingToolApproval.
|
|
105
|
+
* input: string` in `@ai-sdk/harness@1.0.75`'s dist/index.d.ts). String
|
|
106
|
+
* inputs are JSON-parsed before the gate evaluates them — see
|
|
107
|
+
* {@link renderHarnessToolInput}.
|
|
108
|
+
*/
|
|
109
|
+
export interface HarnessApprovalRequest {
|
|
110
|
+
readonly approvalId: string;
|
|
111
|
+
readonly toolCallId: string;
|
|
112
|
+
readonly toolName: string;
|
|
113
|
+
/** Parsed input object, or the JSON string a pending-approval row carries. */
|
|
114
|
+
readonly input: unknown;
|
|
115
|
+
readonly providerExecuted?: boolean;
|
|
116
|
+
}
|
|
117
|
+
/** Structural copy of `@ai-sdk/harness`'s `HarnessV1PermissionMode`. */
|
|
118
|
+
export type HarnessPermissionMode = 'allow-reads' | 'allow-edits' | 'allow-all';
|
|
119
|
+
/** Structural copy of `@ai-sdk/harness`'s `HarnessV1NetworkPolicy`. The two
|
|
120
|
+
* `custom` branches of the real union each require at least one allow field;
|
|
121
|
+
* this single structural branch keeps both optional and relies on the test
|
|
122
|
+
* suite's assignability check against the real (stricter) type for the
|
|
123
|
+
* values this module itself constructs. */
|
|
124
|
+
export type HarnessNetworkPolicy = {
|
|
125
|
+
mode: 'allow-all';
|
|
126
|
+
} | {
|
|
127
|
+
mode: 'deny-all';
|
|
128
|
+
} | {
|
|
129
|
+
mode: 'custom';
|
|
130
|
+
allowedHosts?: readonly string[];
|
|
131
|
+
allowedCIDRs?: readonly string[];
|
|
132
|
+
deniedCIDRs?: readonly string[];
|
|
133
|
+
};
|
|
134
|
+
/** The slice of `@ai-sdk/harness`'s adapter-session control surface this
|
|
135
|
+
* module touches — `submitToolApproval` is OPTIONAL in the real
|
|
136
|
+
* `HarnessV1PromptControl` too, and per-adapter support varies (see module
|
|
137
|
+
* doc point 2). */
|
|
138
|
+
export interface HarnessSessionLike {
|
|
139
|
+
submitToolApproval?(input: {
|
|
140
|
+
approvalId: string;
|
|
141
|
+
approved: boolean;
|
|
142
|
+
reason?: string;
|
|
143
|
+
}): PromiseLike<void>;
|
|
144
|
+
}
|
|
145
|
+
export interface IntuticApprovalResponderOptions {
|
|
146
|
+
/** Overrides the process-wide installed gate (`install(new Gate(...))`). */
|
|
147
|
+
gate?: Gate;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Render a pending approval's `input` as the `tool_input` object
|
|
151
|
+
* {@link Gate.guard} evaluates.
|
|
152
|
+
*
|
|
153
|
+
* Mirrors `dsh.ts`'s `renderDshToolInput`, plus one harness-specific case: a
|
|
154
|
+
* `HarnessAgentPendingToolApproval` carries its input as a JSON **string**,
|
|
155
|
+
* so strings are parsed first. A string that does not parse (or parses to a
|
|
156
|
+
* non-object) falls back to `{ args: [...] }` so the gate still has
|
|
157
|
+
* something to evaluate rather than throwing on a shape it does not
|
|
158
|
+
* recognise.
|
|
159
|
+
*/
|
|
160
|
+
export declare function renderHarnessToolInput(input: unknown): ToolInput;
|
|
161
|
+
/**
|
|
162
|
+
* Build an approval responder: a function that evaluates each pending
|
|
163
|
+
* tool-approval request via `Gate.guard()` and produces the
|
|
164
|
+
* `toolApprovalContinuations` array for the continue-turn call —
|
|
165
|
+
* `agent.continueGenerate({ session, toolApprovalContinuations })` /
|
|
166
|
+
* `continueStream(...)`:
|
|
167
|
+
*
|
|
168
|
+
* ```ts
|
|
169
|
+
* import { HarnessAgent } from '@ai-sdk/harness/agent'
|
|
170
|
+
* import { Gate, install } from '@intutic/gate'
|
|
171
|
+
* import {
|
|
172
|
+
* intuticApprovalResponder,
|
|
173
|
+
* intuticStaticApprovals,
|
|
174
|
+
* recommendedHarnessSettings,
|
|
175
|
+
* } from '@intutic/gate/harness'
|
|
176
|
+
*
|
|
177
|
+
* install(new Gate({ workspaceId: process.env.INTUTIC_WORKSPACE_ID }))
|
|
178
|
+
*
|
|
179
|
+
* const agent = new HarnessAgent({
|
|
180
|
+
* harness,
|
|
181
|
+
* sandbox,
|
|
182
|
+
* tools,
|
|
183
|
+
* ...recommendedHarnessSettings(), // permissionMode: 'allow-edits'
|
|
184
|
+
* toolApproval: intuticStaticApprovals(tools), // every custom tool -> 'user-approval'
|
|
185
|
+
* })
|
|
186
|
+
*
|
|
187
|
+
* const respond = intuticApprovalResponder()
|
|
188
|
+
* // ...run a turn; when it pauses awaiting approval, collect the pending
|
|
189
|
+
* // tool-approval requests (stream parts or suspended-session rows), then:
|
|
190
|
+
* const toolApprovalContinuations = await respond(pendingApprovals)
|
|
191
|
+
* await agent.continueGenerate({ session, toolApprovalContinuations })
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* Decision mapping, per request:
|
|
195
|
+
*
|
|
196
|
+
* - gate allows -> `approved: true`
|
|
197
|
+
* - `IntuticGateRefusal` -> `approved: false`, `reason` = the
|
|
198
|
+
* `[Intutic Governance] BLOCKED: ...` message (the runtime submits an
|
|
199
|
+
* `execution-denied` result to the model in place of a tool result)
|
|
200
|
+
* - any OTHER throw -> `approved: false` with a "gate crashed"
|
|
201
|
+
* reason — **fail closed**, same posture as `dsh.ts`'s listener: this
|
|
202
|
+
* responder's output is a decision list consumed by a paused turn, and a
|
|
203
|
+
* deny is deliverable and auditable where an escaped throw could leave
|
|
204
|
+
* the turn suspended with no answer at all.
|
|
205
|
+
*
|
|
206
|
+
* Requires a `Gate` — either passed via `{ gate }`, or installed process-wide
|
|
207
|
+
* with `install(new Gate(...))`. A call with neither rejects before
|
|
208
|
+
* evaluating anything, refusing to answer approvals unguarded.
|
|
209
|
+
*/
|
|
210
|
+
export declare function intuticApprovalResponder(opts?: IntuticApprovalResponderOptions): (requests: readonly HarnessApprovalRequest[]) => Promise<HarnessToolApprovalContinuation[]>;
|
|
211
|
+
export interface IntuticSubmitApprovalsResult {
|
|
212
|
+
/** The evaluated decisions, always produced — pass these to
|
|
213
|
+
* `continueGenerate`/`continueStream` when `submitted` is false. */
|
|
214
|
+
continuations: HarnessToolApprovalContinuation[];
|
|
215
|
+
/** True when the session supported `submitToolApproval` and every decision
|
|
216
|
+
* was delivered through it; false when the caller must use the
|
|
217
|
+
* continuation path instead. */
|
|
218
|
+
submitted: boolean;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Evaluate pending approvals and deliver the decisions through
|
|
222
|
+
* `session.submitToolApproval` when the adapter supports it.
|
|
223
|
+
*
|
|
224
|
+
* `submitToolApproval` is an OPTIONAL adapter-session method and per-adapter
|
|
225
|
+
* support varies (`harness-claude-code` implements it, `harness-grok-build`
|
|
226
|
+
* does not — see module doc point 2). This helper treats it as an
|
|
227
|
+
* optimization: when present, every decision is submitted directly (the turn
|
|
228
|
+
* resumes in place); when absent, nothing is submitted and the caller passes
|
|
229
|
+
* the returned `continuations` to `continueGenerate`/`continueStream` — the
|
|
230
|
+
* portable path — instead. Either way the SAME evaluated decisions are
|
|
231
|
+
* returned, so the caller never re-runs the gate for one delivery mechanism
|
|
232
|
+
* vs. the other.
|
|
233
|
+
*/
|
|
234
|
+
export declare function intuticSubmitApprovals(session: HarnessSessionLike, requests: readonly HarnessApprovalRequest[], opts?: IntuticApprovalResponderOptions): Promise<IntuticSubmitApprovalsResult>;
|
|
235
|
+
export interface IntuticStaticApprovalsOptions {
|
|
236
|
+
/** Tool names to mark `'denied'` unconditionally instead of
|
|
237
|
+
* `'user-approval'` — for tools that should never run under this agent
|
|
238
|
+
* regardless of what the gate would say about a specific call. */
|
|
239
|
+
deny?: readonly string[];
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Build the static `toolApproval` record for `HarnessAgentSettings`.
|
|
243
|
+
*
|
|
244
|
+
* The record shape is `Readonly<Record<string, ToolApprovalStatus>>` — STATIC
|
|
245
|
+
* per-tool statuses "without callback support" (the shipped doc comment's own
|
|
246
|
+
* words), so a per-call gate function cannot be expressed here at all. What a
|
|
247
|
+
* static record CAN express is deny-by-default **routing**: every listed tool
|
|
248
|
+
* is marked `'user-approval'`, which pauses the turn on every call to it, and
|
|
249
|
+
* {@link intuticApprovalResponder} then answers each pause with a real
|
|
250
|
+
* per-call `Gate.guard()` verdict. `'denied'` is deliberately NOT the default
|
|
251
|
+
* here — it would refuse every call to the tool unconditionally, without the
|
|
252
|
+
* gate ever seeing the arguments; use `{ deny: [...] }` for tools where that
|
|
253
|
+
* is actually what you want.
|
|
254
|
+
*
|
|
255
|
+
* Two scope limits, stated plainly:
|
|
256
|
+
*
|
|
257
|
+
* - This covers CUSTOM host-executed tools only. Built-in sandbox tools
|
|
258
|
+
* (read/write/edit/bash/...) never consult `toolApproval` — they are
|
|
259
|
+
* governed solely by `permissionMode`, which defaults to `'allow-all'`.
|
|
260
|
+
* See {@link recommendedHarnessSettings}.
|
|
261
|
+
* - A tool absent from this record has status `undefined` =
|
|
262
|
+
* "not-applicable" and runs WITHOUT any approval pause. Pass the same
|
|
263
|
+
* `tools` record you give the agent (or every tool name), not a subset.
|
|
264
|
+
*/
|
|
265
|
+
export declare function intuticStaticApprovals(tools: readonly string[] | Record<string, unknown>, opts?: IntuticStaticApprovalsOptions): Readonly<Record<string, 'user-approval' | 'denied'>>;
|
|
266
|
+
export interface RecommendedHarnessSettingsOptions {
|
|
267
|
+
/** `'allow-reads'` is stricter (built-ins can read but not write); the
|
|
268
|
+
* default recommendation is `'allow-edits'` (read + write inside the
|
|
269
|
+
* sandbox, but not the unrestricted `'allow-all'` the framework itself
|
|
270
|
+
* defaults to). `'allow-all'` is deliberately not accepted here — asking
|
|
271
|
+
* this function for the framework's own bypass default would make the
|
|
272
|
+
* helper's name a lie. */
|
|
273
|
+
permissionMode?: 'allow-reads' | 'allow-edits';
|
|
274
|
+
/** Hosts sandbox egress should be limited to. When omitted, the
|
|
275
|
+
* recommended policy is `{ mode: 'deny-all' }` — deny-by-default until
|
|
276
|
+
* the caller decides what the sandbox legitimately needs to reach. */
|
|
277
|
+
allowedHosts?: readonly string[];
|
|
278
|
+
/**
|
|
279
|
+
* Whether to also recommend excluding the sandbox's native `bash` builtin
|
|
280
|
+
* from the tool set entirely, via `HarnessAgentSettings.inactiveTools`.
|
|
281
|
+
* Defaults to `true` — see {@link RecommendedHarnessSettings.inactiveTools}
|
|
282
|
+
* for what this does and does not guarantee (TD-415).
|
|
283
|
+
*/
|
|
284
|
+
filterBash?: boolean;
|
|
285
|
+
}
|
|
286
|
+
/** The exact policy shapes {@link recommendedHarnessSettings} constructs —
|
|
287
|
+
* narrower than {@link HarnessNetworkPolicy} so the value is assignable to
|
|
288
|
+
* the REAL `HarnessV1NetworkPolicy` union (whose `custom` branches each
|
|
289
|
+
* require an allow field) without a cast; the test suite pins that
|
|
290
|
+
* assignability against the shipped type. */
|
|
291
|
+
export type RecommendedNetworkPolicy = {
|
|
292
|
+
mode: 'deny-all';
|
|
293
|
+
} | {
|
|
294
|
+
mode: 'custom';
|
|
295
|
+
allowedHosts: readonly string[];
|
|
296
|
+
deniedCIDRs: readonly string[];
|
|
297
|
+
};
|
|
298
|
+
export interface RecommendedHarnessSettings {
|
|
299
|
+
/** Spread into `HarnessAgentSettings`. */
|
|
300
|
+
permissionMode: 'allow-reads' | 'allow-edits';
|
|
301
|
+
/**
|
|
302
|
+
* NOT a `HarnessAgentSettings` field — apply it to the sandbox session via
|
|
303
|
+
* its optional `setNetworkPolicy?.()` (e.g. from `sandboxConfig.onSession`),
|
|
304
|
+
* or configure the equivalent on the sandbox provider. Optional-call it:
|
|
305
|
+
* providers without a local enforcement primitive omit the method, and a
|
|
306
|
+
* missing implementation means NO egress policy is applied at all — check
|
|
307
|
+
* for `undefined` and treat that as an uncovered surface, not a silent ok.
|
|
308
|
+
*/
|
|
309
|
+
networkPolicy: RecommendedNetworkPolicy;
|
|
310
|
+
/**
|
|
311
|
+
* Spread into `HarnessAgentSettings.inactiveTools` — `undefined` when
|
|
312
|
+
* `filterBash: false` was passed. TD-415, resolved with a corrected
|
|
313
|
+
* understanding: `HarnessV1BuiltinToolFiltering` (the same package's own
|
|
314
|
+
* type, `dist/index.d.ts`/`dist/agent/index.d.ts`) genuinely CAN drop
|
|
315
|
+
* `bash` at config time, confirmed against real shipped `dist/index.js`
|
|
316
|
+
* for both harnesses TD-417 discusses (not just their `.d.ts` — the
|
|
317
|
+
* behaviour lives in compiled logic no type file states):
|
|
318
|
+
*
|
|
319
|
+
* - `@ai-sdk/harness-claude-code@1.0.78` sets BOTH
|
|
320
|
+
* `supportsBuiltinToolApprovals: true` AND
|
|
321
|
+
* `supportsBuiltinToolFiltering: true` on its adapter object, and its
|
|
322
|
+
* `doStart`/`doContinueTurn` forward `builtinToolFiltering` verbatim
|
|
323
|
+
* onto the bridge `start`/`continue` message — true native exclusion,
|
|
324
|
+
* enforced by the wrapped Claude Agent SDK inside the sandbox itself,
|
|
325
|
+
* not merely a framework-side veto. `bash` never becomes callable.
|
|
326
|
+
* - `@ai-sdk/harness-grok-build@1.0.12` sets neither flag directly, but
|
|
327
|
+
* is built on `@ai-sdk/harness-acp@1.0.13` (its exact pinned
|
|
328
|
+
* dependency, confirmed via `npm pack`), which sets
|
|
329
|
+
* `supportsBuiltinToolApprovals: true` (and
|
|
330
|
+
* `supportsBuiltinToolFiltering: false`) — so Grok Build gets the
|
|
331
|
+
* FRAMEWORK's own fallback instead: `@ai-sdk/harness/agent`'s compiled
|
|
332
|
+
* `resolveHarnessAgentToolFiltering` (`dist/agent/index.js`) routes
|
|
333
|
+
* every inactive-builtin call through the approval path and
|
|
334
|
+
* auto-denies it before execution. Different mechanism, same practical
|
|
335
|
+
* outcome — `bash` is still never executed.
|
|
336
|
+
* - Confirmed further: if an adapter supported NEITHER flag, the
|
|
337
|
+
* framework does not silently ignore `inactiveTools` for a builtin —
|
|
338
|
+
* `HarnessAgent`'s constructor throws `HarnessCapabilityUnsupportedError`
|
|
339
|
+
* (`dist/agent/index.js`) rather than accepting a setting it cannot
|
|
340
|
+
* honour. So this recommendation is never a silent no-op for any
|
|
341
|
+
* adapter that accepts it at all.
|
|
342
|
+
*
|
|
343
|
+
* What this does NOT close: TD-415's original per-call gap. This is a
|
|
344
|
+
* coarse, all-or-nothing exclusion decided once at session-construction
|
|
345
|
+
* time — never a `Gate.guard()`-evaluated verdict per call, and a
|
|
346
|
+
* workspace that genuinely needs `bash` available cannot use this
|
|
347
|
+
* filtering and is back to the original `permissionMode` gap for it.
|
|
348
|
+
*/
|
|
349
|
+
inactiveTools?: readonly ['bash'];
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* The settings posture this integration recommends, as a value callers can
|
|
353
|
+
* spread/apply rather than prose they have to transcribe:
|
|
354
|
+
*
|
|
355
|
+
* - `permissionMode: 'allow-edits'` (or `'allow-reads'`) — because the
|
|
356
|
+
* framework's own default is `'allow-all'`, under which built-in sandbox
|
|
357
|
+
* tools (including `bash`) run with no approval surface this gate can
|
|
358
|
+
* reach. There is no per-call gate for built-ins at ANY permissionMode;
|
|
359
|
+
* the mode itself is the entire control, which is why steering it off
|
|
360
|
+
* `'allow-all'` matters.
|
|
361
|
+
* - a `networkPolicy` for the sandbox — `{ mode: 'deny-all' }` by default,
|
|
362
|
+
* or a `custom` allow-list (with the cloud-metadata CIDR denied) when
|
|
363
|
+
* `allowedHosts` is given. This is the honest egress-governance story for
|
|
364
|
+
* server-side sandbox execution: the Intutic proxy on the developer's
|
|
365
|
+
* machine never sees sandbox traffic, and host-level filtering is what
|
|
366
|
+
* the sandbox layer actually offers. It is coarse — no DLP, no
|
|
367
|
+
* per-request policy — and the integration docs say so.
|
|
368
|
+
*/
|
|
369
|
+
export declare function recommendedHarnessSettings(opts?: RecommendedHarnessSettingsOptions): RecommendedHarnessSettings;
|
|
370
|
+
/** Structural copy of `@ai-sdk/provider-utils`'s `SandboxSession`, narrowed
|
|
371
|
+
* to the one method {@link intuticSandboxBootstrap}'s `onBootstrap` calls.
|
|
372
|
+
* Confirmed field-for-field against `@ai-sdk/provider-utils@5.0.27`'s
|
|
373
|
+
* shipped `dist/index.d.ts` (`WriteFileOptions<string>` plus its own
|
|
374
|
+
* `encoding` addition on `writeTextFile`). */
|
|
375
|
+
export interface SandboxWriteSession {
|
|
376
|
+
writeTextFile(options: {
|
|
377
|
+
path: string;
|
|
378
|
+
content: string;
|
|
379
|
+
encoding?: string;
|
|
380
|
+
}): PromiseLike<void>;
|
|
381
|
+
}
|
|
382
|
+
/** Structural copy of `@ai-sdk/harness/agent`'s
|
|
383
|
+
* `HarnessAgentSandboxConfig['onBootstrap']` parameter shape
|
|
384
|
+
* (`dist/agent/index.d.ts`), narrowed to the fields this module reads. */
|
|
385
|
+
export interface SandboxBootstrapCallbackOptions {
|
|
386
|
+
readonly session: SandboxWriteSession;
|
|
387
|
+
readonly workDir: string;
|
|
388
|
+
readonly abortSignal?: AbortSignal;
|
|
389
|
+
}
|
|
390
|
+
export interface IntuticSandboxBootstrap {
|
|
391
|
+
/** Pass through unchanged to `HarnessAgentSettings.sandboxConfig.bootstrapHash`
|
|
392
|
+
* — required alongside `onBootstrap` by the real type. Deterministic: the
|
|
393
|
+
* same options always produce the same hash, and a snapshot-capable
|
|
394
|
+
* sandbox provider uses it to decide whether `onBootstrap` needs to run
|
|
395
|
+
* again. Computed the same way `snapshot.ts` computes the policy-snapshot
|
|
396
|
+
* digest — `createHash('sha256')` over the recipe content, this module's
|
|
397
|
+
* own existing hashing convention, not a new one. */
|
|
398
|
+
readonly bootstrapHash: string;
|
|
399
|
+
/** Pass through unchanged to `HarnessAgentSettings.sandboxConfig.onBootstrap`. */
|
|
400
|
+
readonly onBootstrap: (opts: SandboxBootstrapCallbackOptions) => Promise<void>;
|
|
401
|
+
}
|
|
402
|
+
export interface IntuticSandboxBootstrapOptions {
|
|
403
|
+
/**
|
|
404
|
+
* Compiled `.rules` text — the SAME artifact format `snapshot.ts` reads
|
|
405
|
+
* (`~/.intutic/hooks/policy-snapshot.rules` on a laptop). Copy the file
|
|
406
|
+
* content in, e.g. by reading it from the host running the orchestrator
|
|
407
|
+
* code before constructing this bootstrap. Omit to ship a hook script that
|
|
408
|
+
* loads zero rules (still present as a channel, evaluating nothing) —
|
|
409
|
+
* never silently skipped, so a missing snapshot shows up as an empty file
|
|
410
|
+
* inside the sandbox rather than a missing one.
|
|
411
|
+
*/
|
|
412
|
+
policySnapshotRules?: string;
|
|
413
|
+
/** Embedded in the recipe hash only (so a workspace switch invalidates a
|
|
414
|
+
* cached snapshot) — this module does not otherwise use it, matching
|
|
415
|
+
* `snapshot.ts`'s reader, which also treats workspace id as an integrity
|
|
416
|
+
* check rather than a lookup key. */
|
|
417
|
+
workspaceId?: string;
|
|
418
|
+
/** Directory inside the sandbox (relative to `workDir`) the hook script
|
|
419
|
+
* and its rules file are written under. Defaults to `.intutic/hooks`,
|
|
420
|
+
* the same relative location the laptop writer uses. */
|
|
421
|
+
bootstrapDir?: string;
|
|
422
|
+
}
|
|
423
|
+
declare function sandboxJoin(workDir: string, relative: string): string;
|
|
424
|
+
/**
|
|
425
|
+
* Self-contained (zero-`require`) hand-port of `snapshot.ts`'s
|
|
426
|
+
* `normalise`/`evaluate` — Tier A1 only. See the module-level comment above
|
|
427
|
+
* for what this deliberately does and does not cover, and
|
|
428
|
+
* `__tests__/harness.test.ts` for the behavioural-parity check against the
|
|
429
|
+
* real `snapshot.evaluate()` this port is pinned to.
|
|
430
|
+
*
|
|
431
|
+
* Contract matches the laptop's `claude-code-check.js`
|
|
432
|
+
* (`services/sync-daemon/src/harness/claudeCodeHooks.ts`) deliberately:
|
|
433
|
+
* Claude Code's PreToolUse hook stdin carries `{tool_name, tool_input,
|
|
434
|
+
* session_id}` (this reads both the snake_case and camelCase field names,
|
|
435
|
+
* same as the laptop script); exit `2` blocks the call, exit `0` allows it;
|
|
436
|
+
* any parse/read error fails CLOSED (exit `2`), the same posture
|
|
437
|
+
* `emitJsFailClosedPrelude` documents for the laptop's version.
|
|
438
|
+
*/
|
|
439
|
+
declare function renderSandboxGateScript(rulesFileName: string): string;
|
|
440
|
+
/**
|
|
441
|
+
* Compiles the `.claude/settings.json` content that registers the generated
|
|
442
|
+
* hook script — same matcher set and hook shape as the laptop writer's
|
|
443
|
+
* `hookEntry()` (`services/sync-daemon/src/harness/claudeCodeHooks.ts`):
|
|
444
|
+
* `Bash`, `Edit`, `Write`, `MultiEdit`, and `mcp__.*`.
|
|
445
|
+
*/
|
|
446
|
+
declare function renderSandboxClaudeSettings(hookScriptSandboxPath: string): string;
|
|
447
|
+
/**
|
|
448
|
+
* Builds `{ bootstrapHash, onBootstrap }` for
|
|
449
|
+
* `HarnessAgentSettings.sandboxConfig` — the channel TD-417 identified as
|
|
450
|
+
* existing but unused:
|
|
451
|
+
*
|
|
452
|
+
* ```ts
|
|
453
|
+
* import { HarnessAgent } from '@ai-sdk/harness/agent'
|
|
454
|
+
* import { intuticSandboxBootstrap, recommendedHarnessSettings } from '@intutic/gate/harness'
|
|
455
|
+
*
|
|
456
|
+
* const agent = new HarnessAgent({
|
|
457
|
+
* harness,
|
|
458
|
+
* sandbox,
|
|
459
|
+
* ...recommendedHarnessSettings(),
|
|
460
|
+
* sandboxConfig: intuticSandboxBootstrap({
|
|
461
|
+
* policySnapshotRules: fs.readFileSync(snapshotPath(), 'utf-8'),
|
|
462
|
+
* workspaceId: process.env.INTUTIC_WORKSPACE_ID,
|
|
463
|
+
* }),
|
|
464
|
+
* })
|
|
465
|
+
* ```
|
|
466
|
+
*
|
|
467
|
+
* Writes two files under `<workDir>/<bootstrapDir>` (default
|
|
468
|
+
* `.intutic/hooks`) — the rules text verbatim, and a self-contained hook
|
|
469
|
+
* script implementing Tier A1 against it (see
|
|
470
|
+
* {@link renderSandboxGateScript}) — plus `.claude/settings.json` at
|
|
471
|
+
* `<workDir>/.claude/settings.json` registering that script as a
|
|
472
|
+
* `PreToolUse` hook. See the module-level comment above this section for
|
|
473
|
+
* what this does and does not cover, and why.
|
|
474
|
+
*/
|
|
475
|
+
export declare function intuticSandboxBootstrap(opts?: IntuticSandboxBootstrapOptions): IntuticSandboxBootstrap;
|
|
476
|
+
export declare const _internal: {
|
|
477
|
+
renderSandboxGateScript: typeof renderSandboxGateScript;
|
|
478
|
+
renderSandboxClaudeSettings: typeof renderSandboxClaudeSettings;
|
|
479
|
+
sandboxJoin: typeof sandboxJoin;
|
|
480
|
+
};
|
|
481
|
+
export {};
|
|
482
|
+
//# sourceMappingURL=harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"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"}
|