@intutic/gate 3.0.1 → 3.0.3

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 (2) hide show
  1. package/README.md +28 -8
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -53,8 +53,11 @@ plane's hook gate cannot be reached, answers non-2xx, or answers
53
53
  group policy, the MCP server registry, image provenance, promoted findings)
54
54
  could not complete, there is no verdict, and the call is refused with
55
55
  `HOOK_GATE`. Pass `failClosed: false` to let calls through during such an
56
- outage. A request the hook gate cannot read (HTTP 400, `INVALID_REQUEST`) is
57
- refused whatever `failClosed` says. intutic-clawde's `GateClient` behaves the
56
+ outage. A request the hook gate cannot read (HTTP 400, `INVALID_REQUEST`),
57
+ and a key that lacks the scope the hook gate needs (HTTP 403,
58
+ `INSUFFICIENT_SCOPE`), are refused whatever `failClosed` says. So is a call a
59
+ `plan_approval:` SOP gates when the session's plan cannot be read: rule
60
+ failures always fail closed. intutic-clawde's `GateClient` behaves the
58
61
  same way, held to it by `packages/shared-types/fixtures/hook-gate-response-vectors.json`.
59
62
 
60
63
  Each hook-gate answer names its decision (`decisionId`). The gate reports the
@@ -79,14 +82,19 @@ without a word. Both SDKs run
79
82
 
80
83
  | Export | From | What it is |
81
84
  |---|---|---|
82
- | `Gate`, `GateConfig` | `gate.ts` | The six-tier evaluator. `new Gate(cfg, client?)`, `await gate.guard(toolName, toolInput)`. |
85
+ | `Gate`, `GateConfig` | `gate.ts` | The eight-tier evaluator (A0, A1, R, M, A3, A2, D, B). `new Gate(cfg, client?)`, `await gate.guard(toolName, toolInput)`. |
86
+ | `Gate.recordOutcome(toolName, toolInput, outcome?)`, `ToolOutcome`, `toolOutcomeOf(result)` | `gate.ts`, `wrapTools.ts` | Records how a call that ran went (`{ exitCode, isError, output }`), per session, for Tier R. `toolOutcomeOf` reads one from a tool's return value. |
87
+ | `READ_ONLY_TOOLS` | `gate.ts` | Tool names that cannot change anything: they get the snapshot check but skip the SOP rules (A3) and the hook gate (B). |
88
+ | `CAN_EVALUATE_RULE_RECORDS`, `PLAN_CACHE_MS` | `gate.ts` | Whether this gate evaluates the snapshot's `@rule` records (Tier R; `true`), and how long it keeps a session's plan before reading it again (30,000 ms). |
83
89
  | `install(gate)`, `active()` | `gate.ts` | Process-wide default gate, so wrapped tools don't need the instance threaded through every call site. |
84
- | `IntuticGateRefusal`, `GateError`, `GateConnectionError` | `errors.ts` | Thrown on refusal. `.reason`, `.code` (a `GateRefusalCode`, listed in `GATE_REFUSAL_CODES`), `.incidentId` carry the structured verdict; `.message` carries the `[Intutic Governance] BLOCKED: ...` text. |
90
+ | `IntuticGateRefusal`, `GateError`, `GateConnectionError` | `errors.ts` | Thrown on refusal. `.reason`, `.code` (a `GateRefusalCode`, listed in `GATE_REFUSAL_CODES`), `.incidentId` carry the structured verdict; `.scope` (paths, tools, step, detector, rule) and `.evidence` say what the refusal concerns, so a retry can stay out of it (undefined when it names none, and in an OPAQUE workspace); `.message` carries the `[Intutic Governance] BLOCKED: ...` text. |
91
+ | `IntuticGateEscalation` | `errors.ts` | The `IntuticGateRefusal` (`code` `DECIDE_ESCALATED`) thrown when a decide rule could not decide the call; `.ruleId` names the rule. A caller that can ask its user asks with `.reason` and runs the call only on a yes. |
85
92
  | `IntuticGateHold` | `errors.ts` | The `IntuticGateRefusal` a hold rule throws (`code` `HELD`) after recording the hold for approval; `.holdId` names it. See `hold.ts`. |
86
93
  | `GateClient` | `client.ts` | Control-plane client (`hookGate`, `emit`, `localOnly`, `GateClient.fromEnv(...)`). |
87
94
  | `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.** |
88
95
  | `intuticHeaders(opts?)` | `headers.ts` | Headers for a proxy-pointed HTTP/OpenAI-compatible client (`x-session-id`, `x-workspace-id`, `x-intutic-harness`). |
89
- | `loadSnapshot`, `evaluate`, `Snapshot`, `guardDisabledFromEnv` | `snapshot.ts` | Tier A1: reads `~/.intutic/hooks/policy-snapshot.rules` (or the file `INTUTIC_SNAPSHOT_RULES` names). |
96
+ | `loadSnapshot`, `evaluate`, `Snapshot`, `guardDisabledFromEnv` | `snapshot.ts` | Tier A1: reads `~/.intutic/hooks/policy-snapshot.rules` (or the file `INTUTIC_SNAPSHOT_RULES` names). `evaluate` returns the deciding match, with the shadow and warn matches it passed in `advisories`. |
97
+ | `decide(state, questions, opts?)`, `DecideEngineError` | `decideApi.ts`, `decideEngine.ts` | Asks the self-hosted decide engine a few narrow questions about any text, outside a gate; throws `DecideEngineError` when the engine is not configured, its host is refused, or it cannot answer in time. See [Decide rules](https://docs.intutic.ai/guide/decide#in-your-own-agent-decide). |
90
98
  | `parseRules`, `firstMatch`, `fetchRules`, `fetchRegister`, `parseRegister`, `SopRule`, `SopRegister` | `soprules.ts` | Tier A3: SOP-authored `WHERE`-clause rules, and the register they come in (rules plus the workspace's intervention mode). |
91
99
  | `checkCommand`, `checkImages`, `checkWrittenManifest`, `ImageVerdict` | `imagecheck.ts` | Tier A2: container-image provenance on deploy commands. |
92
100
  | `McpRegistryRecord`, `McpAllowlistRecord` | `mcpRegistryRecord.ts` | Tier M: the snapshot's MCP server registry and allowlist (`Snapshot.mcpRegistry`, `Snapshot.mcpAllowlist`), decided as the hook gates and the MCP proxy decide them; a byte-identical copy of `@intutic/shared-types`' module. |
@@ -103,14 +111,23 @@ dropped, the SSO group policy still refuses, and every MCP call is refused with
103
111
  `POLICY_SNAPSHOT_UNVERIFIED`. A hand-written snapshot for a test needs the line
104
112
  too.
105
113
 
114
+ A SOP's `requires_before: action:run_tests[ok] -> …` is met only by a passing
115
+ test run this gate recorded for the session, with no file changed since.
116
+ `wrapTool` and `wrapTools` record every call they run. A caller that calls
117
+ `gate.guard()` itself must call `gate.recordOutcome(toolName, toolInput,
118
+ outcome)` after each call it runs, or the prerequisite is never met and the
119
+ gated tool is refused with `PREREQUISITE_UNMET`. With no session id
120
+ (`GateClient.sessionId`) nothing is recorded.
121
+
106
122
  Full reference: [Gate SDK](https://docs.intutic.ai/reference/gate-sdk). Every export, with its signature and defaults: [API reference](https://docs.intutic.ai/reference/sdk/gate/).
107
123
 
108
124
  ### A note for sibling adapter phases
109
125
 
110
126
  `Gate.guard()` is **async** (`Promise<void>`), unlike the Python SDK's
111
127
  synchronous `Gate.guard()` — the network-backed tiers (SOP-rule fetch,
112
- `POST /hook-gate`) use `fetch` here rather than Python's blocking
113
- `urllib.request`. Every adapter built on this package must `await` it.
128
+ `POST /hook-gate`) use `fetch` here rather than Python's blocking calls
129
+ (`urllib.request` for the SOP rules, `requests` for the hook gate). Every
130
+ adapter built on this package must `await` it.
114
131
 
115
132
  ### What Tier A1 does and does not cover
116
133
 
@@ -123,7 +140,10 @@ tables) the way the shipped shell/JS gate emitters do (`INTUTIC_FLOOR`,
123
140
  concatenated ahead of the snapshot's own rules in `gateBody.ts`'s
124
141
  `intuticGate()`). Only what actually flows through the `.rules` file —
125
142
  SOP-authored rules, the destructive-command tier, and the tier-promoted
126
- skill-surface rules — is enforced by Tier A1 here. This gap already exists in
143
+ skill-surface rules — is enforced by Tier A1 here. The same file also carries
144
+ the `@rule` and `@decide` records that Tiers R and D evaluate, each with a
145
+ fallback line that refuses its tools in a gate that cannot evaluate the
146
+ record; this gate skips a fallback line only when its record decoded. This gap already exists in
127
147
  `intutic_clawde`; it is preserved, not introduced, by this port. See
128
148
  `src/__tests__/fidelity.test.ts` for exactly which parts of the shipped
129
149
  contract Tier A1 DOES reproduce, verified against the real pattern tables.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intutic/gate",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Intutic pre-execution tool gate for JS/TS agent frameworks without a shipped Intutic harness (Mastra, the Vercel AI SDK, LangChain.js, dsh, and hand-rolled agent loops)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -112,7 +112,7 @@
112
112
  "vitest": "^4",
113
113
  "workflow": "^5.0.1",
114
114
  "zod": "^4.2.0",
115
- "@intutic/shared-types": "3.0.1"
115
+ "@intutic/shared-types": "3.0.3"
116
116
  },
117
117
  "engines": {
118
118
  "node": ">=18"