@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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/dist/actions.d.ts +86 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +239 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/client.d.ts +94 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +207 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/dsh.d.ts +162 -0
  12. package/dist/dsh.d.ts.map +1 -0
  13. package/dist/dsh.js +189 -0
  14. package/dist/dsh.js.map +1 -0
  15. package/dist/errors.d.ts +41 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +53 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/eve.d.ts +425 -0
  20. package/dist/eve.d.ts.map +1 -0
  21. package/dist/eve.js +378 -0
  22. package/dist/eve.js.map +1 -0
  23. package/dist/gate.d.ts +113 -0
  24. package/dist/gate.d.ts.map +1 -0
  25. package/dist/gate.js +274 -0
  26. package/dist/gate.js.map +1 -0
  27. package/dist/harness.d.ts +482 -0
  28. package/dist/harness.d.ts.map +1 -0
  29. package/dist/harness.js +504 -0
  30. package/dist/harness.js.map +1 -0
  31. package/dist/headers.d.ts +26 -0
  32. package/dist/headers.d.ts.map +1 -0
  33. package/dist/headers.js +30 -0
  34. package/dist/headers.js.map +1 -0
  35. package/dist/imagecheck.d.ts +93 -0
  36. package/dist/imagecheck.d.ts.map +1 -0
  37. package/dist/imagecheck.js +286 -0
  38. package/dist/imagecheck.js.map +1 -0
  39. package/dist/index.d.ts +26 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +19 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/managedAgents.d.ts +375 -0
  44. package/dist/managedAgents.d.ts.map +1 -0
  45. package/dist/managedAgents.js +446 -0
  46. package/dist/managedAgents.js.map +1 -0
  47. package/dist/mastra.d.ts +175 -0
  48. package/dist/mastra.d.ts.map +1 -0
  49. package/dist/mastra.js +161 -0
  50. package/dist/mastra.js.map +1 -0
  51. package/dist/openai.d.ts +392 -0
  52. package/dist/openai.d.ts.map +1 -0
  53. package/dist/openai.js +658 -0
  54. package/dist/openai.js.map +1 -0
  55. package/dist/shlex.d.ts +16 -0
  56. package/dist/shlex.d.ts.map +1 -0
  57. package/dist/shlex.js +78 -0
  58. package/dist/shlex.js.map +1 -0
  59. package/dist/snapshot.d.ts +111 -0
  60. package/dist/snapshot.d.ts.map +1 -0
  61. package/dist/snapshot.js +243 -0
  62. package/dist/snapshot.js.map +1 -0
  63. package/dist/soprules.d.ts +88 -0
  64. package/dist/soprules.d.ts.map +1 -0
  65. package/dist/soprules.js +176 -0
  66. package/dist/soprules.js.map +1 -0
  67. package/dist/trueforge.d.ts +191 -0
  68. package/dist/trueforge.d.ts.map +1 -0
  69. package/dist/trueforge.js +184 -0
  70. package/dist/trueforge.js.map +1 -0
  71. package/dist/vercel.d.ts +174 -0
  72. package/dist/vercel.d.ts.map +1 -0
  73. package/dist/vercel.js +157 -0
  74. package/dist/vercel.js.map +1 -0
  75. package/dist/workflow.d.ts +209 -0
  76. package/dist/workflow.d.ts.map +1 -0
  77. package/dist/workflow.js +254 -0
  78. package/dist/workflow.js.map +1 -0
  79. package/dist/wrapTools.d.ts +68 -0
  80. package/dist/wrapTools.d.ts.map +1 -0
  81. package/dist/wrapTools.js +95 -0
  82. package/dist/wrapTools.js.map +1 -0
  83. package/package.json +123 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Intutic Community
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,261 @@
1
+ # @intutic/gate
2
+
3
+ Pre-execution tool gate for JS/TS agent frameworks without a shipped Intutic
4
+ harness. Port of the Python SDK's gate subpackage
5
+ (`packages/intutic-clawde/intutic_clawde/gate/`) — see that package for the
6
+ canonical description of the enforcement contract this one mirrors.
7
+
8
+ This package is the **core** library plus framework-specific adapters built
9
+ on top of it: `@intutic/gate/dsh` (a Cordis plugin for DeepSeek's "dsh"
10
+ harness), `@intutic/gate/mastra` (`intuticHooks()` on Mastra's
11
+ `beforeToolCall`), `@intutic/gate/vercel` (`intuticToolApproval()` on the
12
+ `ai` package's `toolApproval`), `@intutic/gate/openai` (the OpenAI Agents SDK
13
+ for TypeScript — see below), `@intutic/gate/eve` (`intuticApproval()` on
14
+ eve's per-tool/per-connection `approval` policy surface — Vercel's
15
+ filesystem-first durable-agent framework, a pre-1.0 **Preview** product),
16
+ `@intutic/gate/harness` (Vercel's `@ai-sdk/harness` sandboxed coding-agent
17
+ runtime), `@intutic/gate/workflow` (Vercel's `@ai-sdk/workflow` durable
18
+ workflow agents), and `@intutic/gate/managed-agents` (Anthropic's Managed
19
+ Agents — a session-confirmation responder, not a hook, since Anthropic hosts
20
+ the tool-call loop; see below). LangChain.js has no dedicated adapter planned
21
+ and instead uses the generic `wrapTool`/`wrapTools` helper directly.
22
+
23
+ ## Quick start
24
+
25
+ ```ts
26
+ import { Gate, GateClient, install, wrapTools } from '@intutic/gate'
27
+
28
+ const gate = new Gate(
29
+ { workspaceId: process.env.INTUTIC_WORKSPACE_ID },
30
+ GateClient.fromEnv({ harness: 'my-framework' }),
31
+ )
32
+ install(gate) // process-wide default; wrapTool()/wrapTools() pick it up
33
+
34
+ const guardedTools = wrapTools(myTools) // array or {name: tool} record
35
+ ```
36
+
37
+ On a refused call, the wrapped tool throws `IntuticGateRefusal` (message
38
+ prefixed `[Intutic Governance] BLOCKED:`) BEFORE the real implementation
39
+ runs — this package's throw-based refusal contract, the same one
40
+ `services/sync-daemon/src/harness/gateBody.ts`'s emitted gates and
41
+ `packages/mcp-proxy/src/policy.ts` use elsewhere in this repo's gate
42
+ vocabulary.
43
+
44
+ ## Public API surface
45
+
46
+ | Export | From | What it is |
47
+ |---|---|---|
48
+ | `Gate`, `GateConfig` | `gate.ts` | The four-tier evaluator. `new Gate(cfg, client?)`, `await gate.guard(toolName, toolInput)`. |
49
+ | `install(gate)`, `active()` | `gate.ts` | Process-wide default gate, so wrapped tools don't need the instance threaded through every call site. |
50
+ | `IntuticGateRefusal`, `GateError`, `GateConnectionError` | `errors.ts` | Thrown on refusal. `.reason`, `.code`, `.incidentId` carry the structured verdict; `.message` carries the `[Intutic Governance] BLOCKED: ...` text. |
51
+ | `GateClient` | `client.ts` | Control-plane client (`hookGate`, `emit`, `GateClient.fromEnv(...)`). |
52
+ | `wrapTool(fn \| tool, opts?)`, `wrapTools(list \| record, gate?)` | `wrapTools.ts` | Generic wrapping for a plain async function or an `{ execute, ... }`-shaped tool object. **This is the integration point for any JS framework without a dedicated adapter — LangChain.js included.** |
53
+ | `intuticHeaders(opts?)` | `headers.ts` | Headers for a proxy-pointed HTTP/OpenAI-compatible client (`x-session-id`, `x-workspace-id`, `x-intutic-harness`). |
54
+ | `loadSnapshot`, `evaluate`, `Snapshot`, `guardDisabledFromEnv` | `snapshot.ts` | Tier A1: reads `~/.intutic/hooks/policy-snapshot.rules`. |
55
+ | `parseRules`, `firstMatch`, `fetchRules`, `SopRule` | `soprules.ts` | Tier A3: SOP-authored `WHERE`-clause rules. |
56
+ | `checkCommand`, `checkImages`, `checkWrittenManifest`, `ImageVerdict` | `imagecheck.ts` | Tier A2: container-image provenance on deploy commands. |
57
+ | `classify`, `isDeploy`, `isTest`, `touchesInfra` | `actions.ts` | Command classifier shared by A2's deploy trigger. |
58
+
59
+ ### A note for sibling adapter phases
60
+
61
+ `Gate.guard()` is **async** (`Promise<void>`), unlike the Python SDK's
62
+ synchronous `Gate.guard()` — the network-backed tiers (SOP-rule fetch,
63
+ `POST /hook-gate`) use `fetch` here rather than Python's blocking
64
+ `urllib.request`. Every adapter built on this package must `await` it.
65
+
66
+ ### What Tier A1 does and does not cover
67
+
68
+ Like the Python SDK it ports, this package's snapshot reader (Tier A1) reads
69
+ **only** `~/.intutic/hooks/policy-snapshot.rules`. It does **not** separately
70
+ compile in the "static floor" patterns
71
+ (`services/sync-daemon/src/harness/protectedPaths.ts`'s
72
+ `staticFloorPatterns()` — the bypass/secret-content/skill-surface pattern
73
+ tables) the way the shipped shell/JS gate emitters do (`INTUTIC_FLOOR`,
74
+ concatenated ahead of the snapshot's own rules in `gateBody.ts`'s
75
+ `intuticGate()`). Only what actually flows through the `.rules` file —
76
+ SOP-authored rules, the destructive-command tier, and the tier-promoted
77
+ skill-surface rules — is enforced by Tier A1 here. This gap already exists in
78
+ `intutic_clawde`; it is preserved, not introduced, by this port. See
79
+ `src/__tests__/fidelity.test.ts` for exactly which parts of the shipped
80
+ contract Tier A1 DOES reproduce, verified against the real pattern tables.
81
+
82
+ ## `@intutic/gate/openai` — OpenAI Agents SDK (TypeScript)
83
+
84
+ The adapter for `@openai/agents` (the TypeScript twin of the Python SDK's
85
+ `intutic_clawde.gate.adapters.openai_agents`). The SDK's documented per-tool
86
+ veto point is a **tool input guardrail** (`@openai/agents-core` >= 0.3.8):
87
+ the runner executes guardrails before the tool body, and a
88
+ `rejectContent` result skips the tool and hands the message to the model.
89
+
90
+ ```ts
91
+ import { Agent, run } from '@openai/agents'
92
+ import { installOpenAiGate, wrapAgent } from '@intutic/gate/openai'
93
+
94
+ installOpenAiGate({ workspaceId: process.env.INTUTIC_WORKSPACE_ID })
95
+
96
+ const agent = wrapAgent(new Agent({ name: 'ops', tools, mcpServers }))
97
+ const result = await run(agent, prompt)
98
+ ```
99
+
100
+ * `intuticToolGuardrail()` — the raw guardrail, attachable via
101
+ `tool({ inputGuardrails: [...] })`. Refusal → `rejectContent` with the
102
+ `[Intutic Governance] BLOCKED: ...` message; unexpected gate crash →
103
+ `rejectContent` too (fail closed).
104
+ * `wrapTools(tools)` / `wrapAgent(agent)` — inject the guardrail into every
105
+ `FunctionTool`, **including `mcpServers`-derived tools** (`wrapAgent`
106
+ patches `getAllTools`, the only place those ever appear — mapping over
107
+ `agent.tools` misses them); rewrite `hostedMcpTool` entries to
108
+ `require_approval: 'always'` plus an Intutic `on_approval`; install a
109
+ composed gate-driven `onApproval` on local `shellTool`/`applyPatchTool`;
110
+ and gate `computerTool` through its `needsApproval` predicate (refusal →
111
+ pending interruption your code must reject — the SDK has no auto-reject
112
+ hook for computer actions).
113
+ * `installOpenAiGate()` — builds + `install()`s a `Gate` and, by default,
114
+ sets `OPENAI_AGENTS_DISABLE_TRACING=1`: the SDK's tracing exporter posts
115
+ tool inputs/outputs to a **hardcoded** `api.openai.com/v1/traces/ingest`
116
+ that ignores `OPENAI_BASE_URL` (a DLP leak around the proxy). Pass
117
+ `{ tracingExport: 'keep' }` only once the exporter endpoint is re-pointed.
118
+ * Truly hosted tools (`webSearchTool`, `fileSearchTool`,
119
+ `codeInterpreterTool`, image generation, hosted-environment `shellTool`)
120
+ execute server-side at OpenAI — **no client-side hook exists**; they pass
121
+ through unwrapped, stated plainly rather than pretended otherwise.
122
+
123
+ LLM egress: the underlying `openai` client honours `OPENAI_BASE_URL`, so a
124
+ sourced `.env.intutic` routes chat traffic through the Intutic proxy with
125
+ zero code. See `apps/docs/integrations/openai-agents.md` for the full
126
+ operator-facing version (guardrail-vs-approval ordering, realtime coverage,
127
+ minimum versions).
128
+
129
+ ## `@intutic/gate/harness` — Vercel `@ai-sdk/harness` (sandboxed coding agents)
130
+
131
+ `HarnessAgent` runs coding-agent runtimes (Claude Code, Grok Build, ...)
132
+ **server-side, in Vercel Sandbox microVMs** — a materially different execution
133
+ model from every other adapter in this package, and its veto surface differs
134
+ to match. Confirmed against `@ai-sdk/harness@1.0.75` (a devDependency,
135
+ type-checked and exercised in `src/__tests__/harness.test.ts`):
136
+
137
+ - The `toolApproval` setting is a **static** `Readonly<Record<string,
138
+ ToolApprovalStatus>>` — "without callback support" (the shipped doc's own
139
+ words). Per-call gating therefore routes through the tool-approval **flow**:
140
+ `intuticStaticApprovals(tools)` marks every custom tool `'user-approval'`
141
+ (pausing each call), and `intuticApprovalResponder()` answers each pause
142
+ with a real `Gate.guard()` verdict, producing the
143
+ `toolApprovalContinuations` array for `continueGenerate`/`continueStream`.
144
+ `intuticSubmitApprovals(session, ...)` uses the optional
145
+ `session.submitToolApproval` instead when the adapter implements it
146
+ (harness-claude-code does; harness-grok-build does not).
147
+ - **Built-in sandbox tools (read/write/edit/bash/...) never consult
148
+ `toolApproval`.** They are governed only by `permissionMode`, which
149
+ **defaults to `'allow-all'`**. `recommendedHarnessSettings()` returns the
150
+ posture this integration recommends instead (`'allow-edits'`, plus a
151
+ sandbox `networkPolicy` — deny-all, or a host allow-list — plus
152
+ `inactiveTools: ['bash']` by default, dropping `bash` from the tool set
153
+ entirely rather than merely gating it; opt out with `filterBash: false`)
154
+ — because the laptop Intutic proxy never sees sandbox egress, host-level
155
+ network policy is the only egress control available there, and it is
156
+ coarse (no DLP).
157
+ - **`intuticSandboxBootstrap()`** injects a Tier A1 (policy-snapshot)
158
+ `PreToolUse` hook + `.claude/settings.json` directly into the sandbox
159
+ filesystem via `HarnessAgentSettings.sandboxConfig.onBootstrap` — the only
160
+ way to put anything resembling the native Intutic gate inside the
161
+ microVM. Claude Code only; a strict subset of a laptop gate (no SOP tier,
162
+ review-hold, or event draining — those need a live control-plane
163
+ connection a bootstrap function can't have). Spread its output into
164
+ `sandboxConfig` alongside `recommendedHarnessSettings()`. See TD-417 and
165
+ `apps/docs/integrations/ai-sdk-harness.md` for what has and hasn't been
166
+ live-verified.
167
+
168
+ ## `@intutic/gate/workflow` — Vercel `@ai-sdk/workflow` (durable workflow agents)
169
+
170
+ `WorkflowAgent` has **zero approval fields** (confirmed against
171
+ `@ai-sdk/workflow@1.0.69`); its veto surface is per-tool `needsApproval`,
172
+ which pauses a call **durably** (a human can approve hours later).
173
+ `intuticNeedsApproval(toolName)` builds that function from `Gate.guard()`;
174
+ `withIntuticApproval(tools)` attaches it to a whole record, composing with any
175
+ `needsApproval` a tool already declares.
176
+
177
+ The durable runtime **retries** thrown errors — and its retry/abort decision
178
+ duck-types on `error.name === 'FatalError'` (`FatalError.is()`, confirmed
179
+ against `workflow@4.8.3`'s real machinery, because workflows run in a separate
180
+ `vm` realm where `instanceof` fails). A plain `IntuticGateRefusal` thrown from
181
+ `needsApproval` would be retried toward max attempts — a governance denial
182
+ replayed on a timer. This adapter therefore throws `IntuticWorkflowRefusal`:
183
+ still an `IntuticGateRefusal` (message, `.reason`/`.code`/`.incidentId`
184
+ intact) but with `name = 'FatalError'`, so a denial **aborts** instead of
185
+ retry-looping. On allow it resolves `false` (no human pause) or `true` (with
186
+ `{ onAllow: 'human' }` — gate allows AND a human still approves).
187
+ `wrapWorkflowTools()` is the execute-level variant: `wrapTools` semantics with
188
+ the throw contract converted to the fatal shape.
189
+
190
+ ## `@intutic/gate/managed-agents` — Anthropic Managed Agents (session responder)
191
+
192
+ Anthropic hosts the tool-call loop for a Managed Agents session — your process
193
+ never executes a call directly, so there is no hook to attach. Instead your
194
+ backend answers session events. `evaluated_permission: "ask"` on an
195
+ `agent.tool_use`/`agent.mcp_tool_use` event (e.g. a tool configured
196
+ `always_ask`) **pauses the session** until a `user.tool_confirmation` event
197
+ arrives — a real, documented pre-execution veto ("Denied tools do not run.").
198
+ `IntuticSessionConfirmer` answers those pauses with a `Gate.guard()` verdict,
199
+ via polling, a webhook (`session.requires_action`), or a live stream. A tool
200
+ configured `always_allow` never pauses and is therefore never seen by
201
+ Intutic at all — see TD-425.
202
+
203
+ `agent.custom_tool_use` (your own tools) has no pause concept — it is gated
204
+ at the point YOUR code executes it instead, via
205
+ `wrapManagedAgentsCustomTool`/`wrapManagedAgentsCustomTools` (the
206
+ `BetaRunnableTool.run()` shape, not `.execute` — the generic `wrapTools()`
207
+ does not apply here). See `apps/docs/integrations/anthropic-managed-agents.md`
208
+ for the full operator-facing version, including the self-hosted
209
+ `EnvironmentWorker` coverage story and the Python-side custom-tool decorator
210
+ ordering gotcha (TD-427).
211
+
212
+ ## Subpath convention
213
+
214
+ Eight adapters exist today, one source file each: `@intutic/gate/dsh`
215
+ (`src/dsh.ts` — a Cordis plugin; see its module doc for the veto contract and
216
+ `services/sync-daemon/src/harness/dshHooks.ts` for profile registration),
217
+ `@intutic/gate/mastra` (`src/mastra.ts`), `@intutic/gate/vercel`
218
+ (`src/vercel.ts`), `@intutic/gate/openai` (`src/openai.ts` — see above),
219
+ `@intutic/gate/eve` (`src/eve.ts` — approval policies for eve's
220
+ per-tool/per-connection `approval` surface, plus the observe-only
221
+ `intuticAuditHooks()`; verified against a pinned `eve@0.39.1` install — a
222
+ pre-1.0 Preview product, see its module doc and TD-410), `@intutic/gate/harness`
223
+ (`src/harness.ts` — see above), `@intutic/gate/workflow` (`src/workflow.ts`
224
+ — see above), and `@intutic/gate/managed-agents` (`src/managedAgents.ts` — see
225
+ above). Later adapter phases follow the SAME convention (also
226
+ `services/sync-daemon`'s existing subpath convention — see that package's
227
+ `package.json`):
228
+
229
+ 1. One source file per adapter: `src/vercel.ts`, `src/mastra.ts`,
230
+ `src/dsh.ts`, `src/harness.ts`, `src/workflow.ts`, `src/managedAgents.ts`.
231
+ 2. An `exports` entry per adapter in `package.json`:
232
+ ```json
233
+ "./vercel": { "import": "./dist/vercel.js", "types": "./dist/vercel.d.ts" }
234
+ ```
235
+ 3. A matching `typesVersions` entry so editors resolve types from source
236
+ pre-build:
237
+ ```json
238
+ "typesVersions": { "*": { "vercel": ["src/vercel.ts"] } }
239
+ ```
240
+ 4. Each adapter file imports from `./gate.js`, `./errors.js`, etc. (this
241
+ package's core, already built) rather than re-implementing any tier —
242
+ the whole point of splitting core from adapters is that the four-tier
243
+ evaluation logic lives in exactly one place.
244
+
245
+ No stub files are checked in for future adapters; the `exports` map above
246
+ documents the shape they should take rather than pre-committing to file
247
+ names a later phase might want to change.
248
+
249
+ ## Fidelity suite
250
+
251
+ `src/__tests__/fidelity.test.ts` builds a synthetic `.rules` snapshot from a
252
+ point-in-time copy of the REAL pattern tables in
253
+ `services/sync-daemon/src/harness/protectedPaths.ts`
254
+ (`src/__tests__/fixtures/protectedPathsFixtures.ts` — see that file's header
255
+ for why it is a copy rather than a live cross-package import, and how to
256
+ re-sync it) and asserts `evaluate()` reproduces the same block/warn/shadow
257
+ verdict as each pattern's own `matches`/`notMatches` fixtures, for every
258
+ pattern whose `subject` a `.rules` file can actually carry (`command`,
259
+ `target`, `tool`, `any` — `content`-subject patterns, i.e.
260
+ `SECRET_CONTENT_PATTERNS`, are out of scope: they never reach the snapshot
261
+ channel in the first place, matching the Python SDK's own limitation).
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Port of the proxy's command classifier.
3
+ *
4
+ * Source of truth: `packages/proxy/src/plugins/anomaly/actions.rs`, by way of
5
+ * `packages/intutic-clawde/intutic_clawde/gate/actions.py` (the Python SDK's
6
+ * own transliteration, which this file mirrors line for line rather than
7
+ * re-deriving from the Rust — see that module's docstring for why: two
8
+ * independent readings of the Rust drift, one faithful copy of the Python
9
+ * reading does not).
10
+ *
11
+ * The proxy synthesises abstract `action:` tokens from tool calls and
12
+ * evaluates ordering rules over them. A pre-execution gate has to reach the
13
+ * SAME verdict the proxy would, one turn earlier — if the two disagree, the
14
+ * gate either blocks something the proxy would allow, or waves through
15
+ * something the proxy then refuses.
16
+ *
17
+ * Note the trailing spaces in `'update '`, `'truncate '` and `'curl -d '` —
18
+ * they are load-bearing and must survive editing.
19
+ */
20
+ export declare const ACTION_PREFIX = "action:";
21
+ /** Commands that put code or artefacts somewhere real. */
22
+ export declare const DEPLOY_PATTERNS: readonly string[];
23
+ /** Commands that publish a package or a release to the outside world. */
24
+ export declare const PUBLISH_PATTERNS: readonly string[];
25
+ /** Commands that cut a release. */
26
+ export declare const RELEASE_PATTERNS: readonly string[];
27
+ /** Commands that run a test suite. */
28
+ export declare const TEST_PATTERNS: readonly string[];
29
+ /** Commands that send data somewhere over the network. */
30
+ export declare const HTTP_POST_PATTERNS: readonly string[];
31
+ /** Commands that write to a database. */
32
+ export declare const DB_WRITE_PATTERNS: readonly string[];
33
+ /**
34
+ * Path fragments that indicate credential material.
35
+ *
36
+ * `kubeconfig` and `service-account` are in here, so any command mentioning
37
+ * either synthesises `action:secret_read`.
38
+ */
39
+ export declare const SECRET_PATH_FRAGMENTS: readonly string[];
40
+ /** Path fragments that indicate personal data leaving the system. */
41
+ export declare const PII_PATH_FRAGMENTS: readonly string[];
42
+ /** Tool names harnesses use for "run a shell command". */
43
+ export declare const SHELL_TOOLS: readonly string[];
44
+ /** Tool names harnesses use for "read a file". */
45
+ export declare const READ_TOOLS: readonly string[];
46
+ /** Tool names harnesses use for "fetch a URL". */
47
+ export declare const FETCH_TOOLS: readonly string[];
48
+ /**
49
+ * Path fragments that indicate infrastructure-as-code.
50
+ * Source: `packages/proxy/src/manifest.rs:280` (`INFRA_PATH_FRAGMENTS`).
51
+ * Used to decide when a WRITE deserves an image-integrity check.
52
+ */
53
+ export declare const INFRA_PATH_FRAGMENTS: readonly string[];
54
+ /**
55
+ * Concatenate the string-ish values of a tool's arguments, lowercased.
56
+ *
57
+ * Which key holds the command varies by harness (`command`, `cmd`, `script`,
58
+ * `file_path`, `path`, `url`), and a new harness will invent another. Reading
59
+ * every string value means an unknown key still classifies correctly.
60
+ *
61
+ * Mirrors the Python/Rust exactly, including the leading space before each
62
+ * nested value — spacing changes which patterns can straddle a value
63
+ * boundary.
64
+ */
65
+ export declare function flattenInput(value: unknown): string;
66
+ export declare function matchesAny(haystack: string, patterns: readonly string[]): boolean;
67
+ /**
68
+ * Match a tool name against a group.
69
+ *
70
+ * `endsWith` is what lets namespaced names like `mcp__sh__bash` classify.
71
+ */
72
+ export declare function toolIs(name: string, group: readonly string[]): boolean;
73
+ /**
74
+ * Classify one tool call into the abstract actions it performs.
75
+ *
76
+ * Returns prefixed tokens (`action:deploy`, ...) in the order the Rust/Python
77
+ * emit them. Order matters: the ordering detectors read position in the
78
+ * sequence.
79
+ */
80
+ export declare function classify(toolName: string, toolInput: unknown): string[];
81
+ /** True when this call would deploy — the trigger for the image check. */
82
+ export declare function isDeploy(toolName: string, toolInput: unknown): boolean;
83
+ export declare function isTest(toolName: string, toolInput: unknown): boolean;
84
+ /** True when a written path is infrastructure-as-code. */
85
+ export declare function touchesInfra(path: string | null | undefined): boolean;
86
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,aAAa,YAAY,CAAA;AAEtC,0DAA0D;AAC1D,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAe5C,CAAA;AAED,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAS7C,CAAA;AAED,mCAAmC;AACnC,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAO7C,CAAA;AAED,sCAAsC;AACtC,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAqB1C,CAAA;AAED,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAO/C,CAAA;AAED,yCAAyC;AACzC,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAO9C,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAclD,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAO/C,CAAA;AAED,0DAA0D;AAC1D,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAQxC,CAAA;AAED,kDAAkD;AAClD,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAAqD,CAAA;AAE7F,kDAAkD;AAClD,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAAmE,CAAA;AAE5G;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EASjD,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUnD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAGtE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,EAAE,CAoBvE;AAED,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAEtE;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAEpE;AAED,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAErE"}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Port of the proxy's command classifier.
3
+ *
4
+ * Source of truth: `packages/proxy/src/plugins/anomaly/actions.rs`, by way of
5
+ * `packages/intutic-clawde/intutic_clawde/gate/actions.py` (the Python SDK's
6
+ * own transliteration, which this file mirrors line for line rather than
7
+ * re-deriving from the Rust — see that module's docstring for why: two
8
+ * independent readings of the Rust drift, one faithful copy of the Python
9
+ * reading does not).
10
+ *
11
+ * The proxy synthesises abstract `action:` tokens from tool calls and
12
+ * evaluates ordering rules over them. A pre-execution gate has to reach the
13
+ * SAME verdict the proxy would, one turn earlier — if the two disagree, the
14
+ * gate either blocks something the proxy would allow, or waves through
15
+ * something the proxy then refuses.
16
+ *
17
+ * Note the trailing spaces in `'update '`, `'truncate '` and `'curl -d '` —
18
+ * they are load-bearing and must survive editing.
19
+ */
20
+ export const ACTION_PREFIX = 'action:';
21
+ /** Commands that put code or artefacts somewhere real. */
22
+ export const DEPLOY_PATTERNS = [
23
+ 'git push',
24
+ 'kubectl apply',
25
+ 'kubectl rollout',
26
+ 'helm upgrade',
27
+ 'helm install',
28
+ 'terraform apply',
29
+ 'docker push',
30
+ 'serverless deploy',
31
+ 'fly deploy',
32
+ 'vercel deploy',
33
+ 'gcloud run deploy',
34
+ 'aws deploy',
35
+ 'aws s3 sync',
36
+ 'eb deploy',
37
+ ];
38
+ /** Commands that publish a package or a release to the outside world. */
39
+ export const PUBLISH_PATTERNS = [
40
+ 'npm publish',
41
+ 'pnpm publish',
42
+ 'yarn publish',
43
+ 'cargo publish',
44
+ 'twine upload',
45
+ 'poetry publish',
46
+ 'gem push',
47
+ 'docker manifest push',
48
+ ];
49
+ /** Commands that cut a release. */
50
+ export const RELEASE_PATTERNS = [
51
+ 'gh release create',
52
+ 'git tag',
53
+ 'npm version',
54
+ 'cargo release',
55
+ 'goreleaser release',
56
+ 'semantic-release',
57
+ ];
58
+ /** Commands that run a test suite. */
59
+ export const TEST_PATTERNS = [
60
+ 'npm test',
61
+ 'npm run test',
62
+ 'pnpm test',
63
+ 'pnpm run test',
64
+ 'yarn test',
65
+ 'cargo test',
66
+ 'go test',
67
+ 'pytest',
68
+ 'python -m pytest',
69
+ 'vitest',
70
+ 'jest',
71
+ 'mocha',
72
+ 'rspec',
73
+ 'phpunit',
74
+ 'make test',
75
+ 'gradle test',
76
+ 'mvn test',
77
+ 'dotnet test',
78
+ 'bazel test',
79
+ 'tox',
80
+ ];
81
+ /** Commands that send data somewhere over the network. */
82
+ export const HTTP_POST_PATTERNS = [
83
+ 'curl -x post',
84
+ 'curl --request post',
85
+ 'curl -d ',
86
+ 'curl --data',
87
+ 'wget --post',
88
+ 'http post',
89
+ ];
90
+ /** Commands that write to a database. */
91
+ export const DB_WRITE_PATTERNS = [
92
+ 'insert into',
93
+ 'update ',
94
+ 'delete from',
95
+ 'drop table',
96
+ 'truncate ',
97
+ 'alter table',
98
+ ];
99
+ /**
100
+ * Path fragments that indicate credential material.
101
+ *
102
+ * `kubeconfig` and `service-account` are in here, so any command mentioning
103
+ * either synthesises `action:secret_read`.
104
+ */
105
+ export const SECRET_PATH_FRAGMENTS = [
106
+ '.env',
107
+ 'credentials',
108
+ 'id_rsa',
109
+ 'id_ed25519',
110
+ '.pem',
111
+ '.p12',
112
+ '.pfx',
113
+ 'secrets.',
114
+ '.netrc',
115
+ '.aws/',
116
+ '.ssh/',
117
+ 'kubeconfig',
118
+ 'service-account',
119
+ ];
120
+ /** Path fragments that indicate personal data leaving the system. */
121
+ export const PII_PATH_FRAGMENTS = [
122
+ 'customer',
123
+ 'users.csv',
124
+ 'pii',
125
+ 'personal',
126
+ 'gdpr',
127
+ 'payroll',
128
+ ];
129
+ /** Tool names harnesses use for "run a shell command". */
130
+ export const SHELL_TOOLS = [
131
+ 'bash',
132
+ 'shell',
133
+ 'run_command',
134
+ 'runcommand',
135
+ 'terminal',
136
+ 'execute',
137
+ 'exec',
138
+ ];
139
+ /** Tool names harnesses use for "read a file". */
140
+ export const READ_TOOLS = ['read', 'readfile', 'view', 'cat', 'open_file'];
141
+ /** Tool names harnesses use for "fetch a URL". */
142
+ export const FETCH_TOOLS = ['webfetch', 'fetch', 'http_request', 'browser', 'web_search'];
143
+ /**
144
+ * Path fragments that indicate infrastructure-as-code.
145
+ * Source: `packages/proxy/src/manifest.rs:280` (`INFRA_PATH_FRAGMENTS`).
146
+ * Used to decide when a WRITE deserves an image-integrity check.
147
+ */
148
+ export const INFRA_PATH_FRAGMENTS = [
149
+ 'terraform',
150
+ '.tf',
151
+ 'k8s/',
152
+ 'kubernetes/',
153
+ 'helm/',
154
+ 'dockerfile',
155
+ 'docker-compose',
156
+ '.tfstate',
157
+ ];
158
+ /**
159
+ * Concatenate the string-ish values of a tool's arguments, lowercased.
160
+ *
161
+ * Which key holds the command varies by harness (`command`, `cmd`, `script`,
162
+ * `file_path`, `path`, `url`), and a new harness will invent another. Reading
163
+ * every string value means an unknown key still classifies correctly.
164
+ *
165
+ * Mirrors the Python/Rust exactly, including the leading space before each
166
+ * nested value — spacing changes which patterns can straddle a value
167
+ * boundary.
168
+ */
169
+ export function flattenInput(value) {
170
+ if (typeof value === 'string')
171
+ return value.toLowerCase();
172
+ if (Array.isArray(value))
173
+ return value.map((v) => ' ' + flattenInput(v)).join('');
174
+ if (value !== null && typeof value === 'object') {
175
+ return Object.values(value)
176
+ .map((v) => ' ' + flattenInput(v))
177
+ .join('');
178
+ }
179
+ // Numbers, booleans and null/undefined contribute nothing.
180
+ return '';
181
+ }
182
+ export function matchesAny(haystack, patterns) {
183
+ return patterns.some((p) => haystack.includes(p));
184
+ }
185
+ /**
186
+ * Match a tool name against a group.
187
+ *
188
+ * `endsWith` is what lets namespaced names like `mcp__sh__bash` classify.
189
+ */
190
+ export function toolIs(name, group) {
191
+ const lower = name.toLowerCase();
192
+ return group.some((t) => lower === t || lower.endsWith(t));
193
+ }
194
+ /**
195
+ * Classify one tool call into the abstract actions it performs.
196
+ *
197
+ * Returns prefixed tokens (`action:deploy`, ...) in the order the Rust/Python
198
+ * emit them. Order matters: the ordering detectors read position in the
199
+ * sequence.
200
+ */
201
+ export function classify(toolName, toolInput) {
202
+ const args = flattenInput(toolInput);
203
+ const actions = [];
204
+ if (toolIs(toolName, SHELL_TOOLS)) {
205
+ // Tests first: `make test && git push` is both, and the ordering rule
206
+ // needs the test to be seen as having happened before the deploy.
207
+ if (matchesAny(args, TEST_PATTERNS))
208
+ actions.push('run_tests');
209
+ if (matchesAny(args, DEPLOY_PATTERNS))
210
+ actions.push('deploy');
211
+ if (matchesAny(args, PUBLISH_PATTERNS))
212
+ actions.push('publish');
213
+ if (matchesAny(args, RELEASE_PATTERNS))
214
+ actions.push('release');
215
+ // Source before sink, so that (secret_read -> http_post) can still fire
216
+ // on a single command that does both.
217
+ if (matchesAny(args, SECRET_PATH_FRAGMENTS))
218
+ actions.push('secret_read');
219
+ if (matchesAny(args, PII_PATH_FRAGMENTS))
220
+ actions.push('pii_export');
221
+ if (matchesAny(args, HTTP_POST_PATTERNS))
222
+ actions.push('http_post');
223
+ if (matchesAny(args, DB_WRITE_PATTERNS))
224
+ actions.push('db_write');
225
+ }
226
+ return actions.map((a) => ACTION_PREFIX + a);
227
+ }
228
+ /** True when this call would deploy — the trigger for the image check. */
229
+ export function isDeploy(toolName, toolInput) {
230
+ return classify(toolName, toolInput).includes(ACTION_PREFIX + 'deploy');
231
+ }
232
+ export function isTest(toolName, toolInput) {
233
+ return classify(toolName, toolInput).includes(ACTION_PREFIX + 'run_tests');
234
+ }
235
+ /** True when a written path is infrastructure-as-code. */
236
+ export function touchesInfra(path) {
237
+ return matchesAny((path ?? '').toLowerCase(), INFRA_PATH_FRAGMENTS);
238
+ }
239
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}