@stigmer/runner 3.0.2-dev.20260609093630 → 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.
@@ -1 +1 @@
1
- {"hash":"4971b259dfd933ca","builtAt":"2026-06-09T09:38:00.401Z","fileCount":192}
1
+ {"hash":"f39ecbdabee6cf8e","builtAt":"2026-06-10T07:04:09.007Z","fileCount":192}
@@ -26,36 +26,75 @@ export interface MergedToolPolicy {
26
26
  requiresApproval: boolean;
27
27
  approvalMessage: string;
28
28
  }
29
+ /**
30
+ * Canonical approval category for a gated tool, derived from EITHER taxonomy's
31
+ * name via the shared {@link classifyTool}.
32
+ *
33
+ * The hook (`Write`/`Shell`/`Delete`) and the stream (`edit`/`shell`/`delete`)
34
+ * name the same operation differently, so neither raw name is a stable
35
+ * cross-layer identity. The category collapses both onto one value so the denial
36
+ * ledger (recorded by the hook) correlates to the streamed tool call (read by
37
+ * the runner) and so an approval grant matches the agent's re-attempt on
38
+ * reinvocation regardless of which taxonomy named it. `FILE_WRITE` and
39
+ * `FILE_EDIT` both map to `write` because the Cursor hook reports every file
40
+ * mutation — create or edit — as `Write`.
41
+ *
42
+ * Returns undefined for non-gated tools (read-only built-ins, MCP tools, and
43
+ * anything `classifyTool` does not place in a mutating kind).
44
+ */
45
+ export type ApprovalCategory = "write" | "delete" | "shell";
46
+ export declare function approvalCategory(toolName: string): ApprovalCategory | undefined;
29
47
  /**
30
48
  * Top-level tool-argument fields, in priority order, that identify the specific
31
- * resource a built-in tool acts on. Used to render approval messages and to key
32
- * HITL approval grants (see approval-state.ts). Authored here once and injected
33
- * into the generated preToolUse hook script so the runner and the hook always
34
- * agree on which field to match.
49
+ * resource a built-in tool acts on. The list deliberately spans BOTH taxonomies'
50
+ * arg shapes: the hook input names a file `file_path` and the stream names it
51
+ * `path`; both name a shell command `command`. Extracting the same resource
52
+ * VALUE on both sides (the absolute path / the command string) is what lets the
53
+ * hook-recorded denial token equal the stream-computed token. Authored here once
54
+ * and injected into the generated preToolUse hook script so the runner and the
55
+ * hook never disagree on which field to match.
35
56
  */
36
- export declare const SALIENT_ARG_FIELDS: readonly ["path", "command", "target_notebook"];
57
+ export declare const SALIENT_ARG_FIELDS: readonly ["file_path", "path", "target_notebook", "command"];
37
58
  /**
38
59
  * Check whether a built-in (non-MCP) Cursor tool requires user approval.
39
60
  *
40
- * Only the explicitly gated, mutating/destructive tools require approval;
41
- * everything else (read-only built-ins, and at the hook layer auto-approved
42
- * MCP tools) is allowed. This "gate the dangerous set, allow the rest" model
43
- * mirrors the native harness's resolveToolApproval, which also defaults
44
- * unlisted tools to no-approval. It is deliberately fail-OPEN for unknown
45
- * tools: the merged MCP policy map carries only the tools that REQUIRE
46
- * approval, so a fail-closed default would wrongly deny every auto-approved
47
- * MCP tool, which the hook cannot distinguish from an unknown built-in by name.
61
+ * Resolved via {@link approvalCategory} so it answers correctly for BOTH
62
+ * taxonomies — the hook's `Write`/`Shell`/`Delete` and the stream's
63
+ * `edit`/`shell`/`delete` all return true. Only mutating/destructive tools are
64
+ * gated; everything else (read-only built-ins, and at the hook layer —
65
+ * auto-approved MCP tools) is allowed. This "gate the dangerous set, allow the
66
+ * rest" model mirrors the native harness's resolveToolApproval. It is
67
+ * deliberately fail-OPEN for unknown tools: the merged MCP policy map carries
68
+ * only the tools that REQUIRE approval, so a fail-closed default would wrongly
69
+ * deny every auto-approved MCP tool, which the hook cannot distinguish from an
70
+ * unknown built-in by name.
48
71
  */
49
72
  export declare function builtInRequiresApproval(toolName: string): boolean;
50
73
  /**
51
74
  * Returns the built-in tool names that require approval (the gated set the
52
75
  * preToolUse hook denies unless auto-approved or granted on reinvocation).
76
+ *
77
+ * These are HOOK-taxonomy names (PascalCase), because the hook matches its own
78
+ * `tool_name`. See {@link approvalCategory} for the cross-layer identity.
53
79
  */
54
80
  export declare function getBuiltInGatedList(): string[];
55
81
  /**
56
- * Approval-message template for a gated built-in tool, or undefined when the
57
- * tool is not a known gated built-in. Callers resolve the placeholders against
58
- * the tool args via resolveApprovalMessage.
82
+ * Returns the gated built-in tools as `(hookToolName, category)` pairs.
83
+ *
84
+ * Injected into the generated preToolUse hook so the bash script can map its
85
+ * incoming `tool_name` to the canonical category used for the denial/grant
86
+ * token — the same category the runner computes from the stream side via
87
+ * {@link approvalCategory}. Authoring it here keeps the mapping single-sourced;
88
+ * a gated built-in with no category would be a programming error, so it is
89
+ * filtered out (and would simply not be gated rather than crash the hook).
90
+ */
91
+ export declare function getBuiltInGatedCategories(): Array<[string, ApprovalCategory]>;
92
+ /**
93
+ * Approval-message template for a gated built-in tool (either taxonomy), or
94
+ * undefined when the tool is not gated. Resolved via {@link approvalCategory}
95
+ * so stream-side names (`edit`/`shell`/`delete`) and hook-side names
96
+ * (`Write`/`Shell`/`Delete`) both map to the same template. Callers resolve the
97
+ * placeholders against the tool args via resolveApprovalMessage.
59
98
  */
60
99
  export declare function getBuiltInApprovalMessage(toolName: string): string | undefined;
61
100
  /**
@@ -15,58 +15,120 @@
15
15
  * allows or denies the call. For built-in Cursor tools (Shell, Read, etc.),
16
16
  * a separate local policy applies.
17
17
  */
18
+ import { ToolKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
19
+ import { classifyTool } from "../../shared/tool-kind.js";
18
20
  /**
19
- * Built-in (non-MCP) Cursor tools that mutate the workspace or execute
20
- * commands. These require approval when auto_approve_all is false, mirroring
21
- * the native harness's DANGEROUS_PLATFORM_TOOLS (write/edit/create/delete/
22
- * execute/shell). Each value is an approval-message template resolved against
23
- * the tool args (see resolveApprovalMessage); its placeholder names the same
24
- * field the grant matcher keys on (path/command/target_notebook).
21
+ * Built-in Cursor tools the preToolUse hook gates, named as the hook receives
22
+ * them.
23
+ *
24
+ * Critical: the Cursor preToolUse hook and the SDK event stream use DIFFERENT
25
+ * tool taxonomies for the same operation. The hook's `tool_name` is PascalCase
26
+ * (`Write` for any file create/edit, `Shell`, `Delete`); the stream's
27
+ * `event.name` is lowercase (`edit`, `shell`, `delete`). This set is the HOOK
28
+ * taxonomy because it is consulted only to build the hook's gated set and its
29
+ * name->category mapping. Cross-layer correlation never compares these raw
30
+ * names — it uses {@link approvalCategory} (see below).
25
31
  */
26
- const BUILT_IN_GATED = new Map([
27
- ["Write", "Write file: {{args.path}}"],
28
- ["StrReplace", "Edit file: {{args.path}}"],
29
- ["EditNotebook", "Edit notebook: {{args.target_notebook}}"],
30
- ["Shell", "Run command: {{args.command}}"],
31
- ["Delete", "Delete: {{args.path}}"],
32
+ const BUILT_IN_GATED = new Set([
33
+ "Write",
34
+ "StrReplace",
35
+ "EditNotebook",
36
+ "Shell",
37
+ "Delete",
32
38
  ]);
39
+ export function approvalCategory(toolName) {
40
+ switch (classifyTool(toolName)) {
41
+ case ToolKind.FILE_WRITE:
42
+ case ToolKind.FILE_EDIT:
43
+ return "write";
44
+ case ToolKind.FILE_DELETE:
45
+ return "delete";
46
+ case ToolKind.SHELL:
47
+ return "shell";
48
+ default:
49
+ return undefined;
50
+ }
51
+ }
52
+ /**
53
+ * Human-readable approval-message template per canonical category. Keyed by
54
+ * category (not raw tool name) so a denial surfaced from either taxonomy renders
55
+ * the same message. Placeholders resolve against the tool args via
56
+ * {@link resolveApprovalMessage}; `{{args.path}}` and `{{args.command}}` are the
57
+ * stream-side field names (the runner builds the approval surface from the
58
+ * streamed tool call, whose args use `path`/`command`).
59
+ */
60
+ const CATEGORY_APPROVAL_MESSAGE = {
61
+ write: "Write file: {{args.path}}",
62
+ delete: "Delete: {{args.path}}",
63
+ shell: "Run command: {{args.command}}",
64
+ };
33
65
  /**
34
66
  * Top-level tool-argument fields, in priority order, that identify the specific
35
- * resource a built-in tool acts on. Used to render approval messages and to key
36
- * HITL approval grants (see approval-state.ts). Authored here once and injected
37
- * into the generated preToolUse hook script so the runner and the hook always
38
- * agree on which field to match.
67
+ * resource a built-in tool acts on. The list deliberately spans BOTH taxonomies'
68
+ * arg shapes: the hook input names a file `file_path` and the stream names it
69
+ * `path`; both name a shell command `command`. Extracting the same resource
70
+ * VALUE on both sides (the absolute path / the command string) is what lets the
71
+ * hook-recorded denial token equal the stream-computed token. Authored here once
72
+ * and injected into the generated preToolUse hook script so the runner and the
73
+ * hook never disagree on which field to match.
39
74
  */
40
- export const SALIENT_ARG_FIELDS = ["path", "command", "target_notebook"];
75
+ export const SALIENT_ARG_FIELDS = ["file_path", "path", "target_notebook", "command"];
41
76
  /**
42
77
  * Check whether a built-in (non-MCP) Cursor tool requires user approval.
43
78
  *
44
- * Only the explicitly gated, mutating/destructive tools require approval;
45
- * everything else (read-only built-ins, and at the hook layer auto-approved
46
- * MCP tools) is allowed. This "gate the dangerous set, allow the rest" model
47
- * mirrors the native harness's resolveToolApproval, which also defaults
48
- * unlisted tools to no-approval. It is deliberately fail-OPEN for unknown
49
- * tools: the merged MCP policy map carries only the tools that REQUIRE
50
- * approval, so a fail-closed default would wrongly deny every auto-approved
51
- * MCP tool, which the hook cannot distinguish from an unknown built-in by name.
79
+ * Resolved via {@link approvalCategory} so it answers correctly for BOTH
80
+ * taxonomies — the hook's `Write`/`Shell`/`Delete` and the stream's
81
+ * `edit`/`shell`/`delete` all return true. Only mutating/destructive tools are
82
+ * gated; everything else (read-only built-ins, and at the hook layer —
83
+ * auto-approved MCP tools) is allowed. This "gate the dangerous set, allow the
84
+ * rest" model mirrors the native harness's resolveToolApproval. It is
85
+ * deliberately fail-OPEN for unknown tools: the merged MCP policy map carries
86
+ * only the tools that REQUIRE approval, so a fail-closed default would wrongly
87
+ * deny every auto-approved MCP tool, which the hook cannot distinguish from an
88
+ * unknown built-in by name.
52
89
  */
53
90
  export function builtInRequiresApproval(toolName) {
54
- return BUILT_IN_GATED.has(toolName);
91
+ return approvalCategory(toolName) !== undefined;
55
92
  }
56
93
  /**
57
94
  * Returns the built-in tool names that require approval (the gated set the
58
95
  * preToolUse hook denies unless auto-approved or granted on reinvocation).
96
+ *
97
+ * These are HOOK-taxonomy names (PascalCase), because the hook matches its own
98
+ * `tool_name`. See {@link approvalCategory} for the cross-layer identity.
59
99
  */
60
100
  export function getBuiltInGatedList() {
61
- return [...BUILT_IN_GATED.keys()];
101
+ return [...BUILT_IN_GATED];
102
+ }
103
+ /**
104
+ * Returns the gated built-in tools as `(hookToolName, category)` pairs.
105
+ *
106
+ * Injected into the generated preToolUse hook so the bash script can map its
107
+ * incoming `tool_name` to the canonical category used for the denial/grant
108
+ * token — the same category the runner computes from the stream side via
109
+ * {@link approvalCategory}. Authoring it here keeps the mapping single-sourced;
110
+ * a gated built-in with no category would be a programming error, so it is
111
+ * filtered out (and would simply not be gated rather than crash the hook).
112
+ */
113
+ export function getBuiltInGatedCategories() {
114
+ const pairs = [];
115
+ for (const name of BUILT_IN_GATED) {
116
+ const category = approvalCategory(name);
117
+ if (category)
118
+ pairs.push([name, category]);
119
+ }
120
+ return pairs;
62
121
  }
63
122
  /**
64
- * Approval-message template for a gated built-in tool, or undefined when the
65
- * tool is not a known gated built-in. Callers resolve the placeholders against
66
- * the tool args via resolveApprovalMessage.
123
+ * Approval-message template for a gated built-in tool (either taxonomy), or
124
+ * undefined when the tool is not gated. Resolved via {@link approvalCategory}
125
+ * so stream-side names (`edit`/`shell`/`delete`) and hook-side names
126
+ * (`Write`/`Shell`/`Delete`) both map to the same template. Callers resolve the
127
+ * placeholders against the tool args via resolveApprovalMessage.
67
128
  */
68
129
  export function getBuiltInApprovalMessage(toolName) {
69
- return BUILT_IN_GATED.get(toolName);
130
+ const category = approvalCategory(toolName);
131
+ return category ? CATEGORY_APPROVAL_MESSAGE[category] : undefined;
70
132
  }
71
133
  /**
72
134
  * Extract the canonical "salient" argument value that identifies the resource a
@@ -1 +1 @@
1
- {"version":3,"file":"approval-policy.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/approval-policy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"approval-policy.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/approval-policy.ts"],"names":[],"mappings":"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"}
@@ -8,27 +8,29 @@
8
8
  * State file format (JSON):
9
9
  * {
10
10
  * "autoApproveAll": false,
11
- * "builtInGatedList": ["Write", "StrReplace", "Shell", ...],
12
11
  * "mcpToolPolicies": {
13
12
  * "apply_cloud_resource": { "requiresApproval": true, "message": "..." }
14
13
  * },
15
- * "approvedGrants": [{ "toolName": "Write", "mcpServerSlug": "", "argKey": "a.txt" }],
16
- * "approvedGrantTokens": ["V3JpdGUKYS50eHQ="]
14
+ * "approvedGrants": [{ "toolName": "edit", "mcpServerSlug": "", "key": "write", "salient": "a.txt" }],
15
+ * "approvedGrantTokens": ["d3JpdGUKYS50eHQ="]
17
16
  * }
18
17
  *
19
- * The hook gates only the explicitly dangerous set (builtInGatedList) and the
20
- * MCP tools that require approval (mcpToolPolicies, which by construction holds
21
- * only require-approval entries); every other tool is allowed. This mirrors the
22
- * native harness and avoids denying auto-approved MCP tools, which are absent
23
- * from the policy map and indistinguishable from unknown tools by name.
18
+ * The hook gates the dangerous built-in set and the MCP tools that require
19
+ * approval (mcpToolPolicies, which by construction holds only require-approval
20
+ * entries); every other tool is allowed. The gated built-in set and its
21
+ * name->category mapping are baked into the generated hook script (from
22
+ * approval-policy.ts), not carried in the state file only the dynamic inputs
23
+ * (autoApproveAll, mcpToolPolicies, approvedGrantTokens) live here. This mirrors
24
+ * the native harness and avoids denying auto-approved MCP tools, which are
25
+ * absent from the policy map and indistinguishable from unknown tools by name.
24
26
  *
25
27
  * Why grants instead of tool-call ids: a resumed Cursor agent re-issues the
26
28
  * approved tool with a BRAND NEW call id, so matching on the original call id
27
- * can never let the re-attempt through. Instead we grant by tool identity —
28
- * tool name plus a "salient" argument (the file path for Write, the command for
29
- * Shell, …; see extractArgKey). On reinvocation the hook allows a tool call
30
- * only if its (name, salient-arg) matches an approved grant; rejected/skipped
31
- * tools and any newly proposed dangerous tool are re-gated.
29
+ * can never let the re-attempt through. Instead we grant by canonical tool
30
+ * identity the approval category plus a "salient" resource value (the file
31
+ * path, the shell command; see {@link toolIdentity}). On reinvocation the hook
32
+ * allows a tool call only if its (category, salient) matches an approved grant;
33
+ * rejected/skipped tools and any newly proposed dangerous tool are re-gated.
32
34
  *
33
35
  * Tokens: the hook is a self-contained bash script, so it cannot parse an array
34
36
  * of grant objects. `approvedGrantTokens` is the flat, base64-encoded form of
@@ -55,47 +57,73 @@ export interface McpToolPolicyEntry {
55
57
  requiresApproval: boolean;
56
58
  message?: string;
57
59
  }
60
+ /**
61
+ * The canonical, taxonomy-agnostic identity of a tool call.
62
+ *
63
+ * The Cursor preToolUse hook and the SDK stream name the same operation
64
+ * differently (hook `Write`/`Shell`/`Delete`; stream `edit`/`shell`/`delete`),
65
+ * so the raw tool name cannot be a cross-layer identity. Instead:
66
+ * - `key` is the {@link approvalCategory} (`write`/`delete`/`shell`) for gated
67
+ * built-ins, and the tool name for MCP tools (whose name is consistent across
68
+ * layers). It is the part that survives the name divergence.
69
+ * - `salient` is the resource the tool acts on (the absolute file path or the
70
+ * shell command) — identical on both sides because it is the argument VALUE,
71
+ * not the field name. Empty for MCP tools, matched by `key` alone.
72
+ *
73
+ * The denial ledger (hook) and the stream reconciliation (runner) both reduce a
74
+ * tool call to this identity, so they correlate exactly; an approval grant uses
75
+ * the same identity so the agent's re-attempt is allowed on reinvocation even
76
+ * though it carries a fresh tool-call id and a different-taxonomy name.
77
+ */
78
+ export interface ToolIdentity {
79
+ key: string;
80
+ salient: string;
81
+ }
82
+ export declare function toolIdentity(toolName: string, mcpServerSlug: string, args: Record<string, unknown> | undefined): ToolIdentity;
58
83
  /**
59
84
  * The identity of an approved tool call, stable across agent resume.
60
85
  *
61
- * - argKey is the salient argument (path/command/…) for built-in tools; matched
62
- * exactly so only the approved resource is allowed through on the resumed turn.
63
- * - argKey is empty for MCP tools (and built-in tools with no salient field);
64
- * the grant then matches by name alone, since the user approved that tool.
86
+ * - `key`/`salient` are the canonical {@link ToolIdentity} the hook matches on.
87
+ * - `toolName`/`mcpServerSlug` are retained for readability, debugging, and the
88
+ * structured-vs-token cross-check (the two are always generated together).
65
89
  */
66
90
  export interface ApprovalGrant {
67
91
  toolName: string;
68
92
  mcpServerSlug: string;
69
- argKey: string;
93
+ key: string;
94
+ salient: string;
70
95
  }
71
96
  export interface ApprovalStateFile {
72
97
  autoApproveAll: boolean;
73
- builtInGatedList: string[];
74
98
  mcpToolPolicies: Record<string, McpToolPolicyEntry>;
75
99
  approvedGrants: ApprovalGrant[];
76
100
  approvedGrantTokens: string[];
77
101
  }
78
102
  /**
79
103
  * Compute the flat token the bash hook matches on. The hook recomputes the same
80
- * token from the incoming tool call (`base64(toolName \n salientArg)`), so the
81
- * encoding here must stay byte-identical to the hook script in hook-script.ts.
104
+ * token from the incoming tool call (`base64(key \n salient)` see
105
+ * {@link toolIdentity}), so the encoding here must stay byte-identical to the
106
+ * hook script in hook-script.ts.
82
107
  */
83
- export declare function grantToken(toolName: string, argKey: string): string;
108
+ export declare function grantToken(key: string, salient: string): string;
84
109
  /**
85
110
  * Build approval grants from the pending approvals the user adjudicated and
86
- * their decisions. Only APPROVE decisions produce grants. Built-in tools are
87
- * keyed by their salient argument; MCP tools are keyed by name only.
111
+ * their decisions. Only APPROVE / APPROVE_ALL decisions produce grants. Each
112
+ * grant carries the canonical {@link ToolIdentity} (category + salient resource)
113
+ * so the hook allows the exact approved resource on the resumed turn.
88
114
  */
89
115
  export declare function buildApprovalGrants(pendingApprovals: PendingApproval[], decisions: Map<string, ApprovalAction>): ApprovalGrant[];
90
116
  /**
91
117
  * Build the approval state file content from merged policies and any approval
92
118
  * grants from a previous HITL cycle.
93
119
  *
94
- * The state file drives the hook script's allow/deny decisions:
95
- * - builtInGatedList: dangerous built-in tools the hook denies (unless granted)
120
+ * The state file carries the hook script's DYNAMIC inputs:
96
121
  * - mcpToolPolicies: per-tool policy for MCP tools requiring approval
97
122
  * - approvedGrants / approvedGrantTokens: tools approved in the current HITL
98
123
  * cycle, allowed through on reinvocation
124
+ *
125
+ * The static gated built-in set and its category mapping are baked into the
126
+ * generated hook script (from approval-policy.ts), not carried here.
99
127
  */
100
128
  export declare function buildApprovalState(mergedPolicies: Map<string, MergedToolPolicy>, autoApproveAll: boolean, grants?: ApprovalGrant[]): ApprovalStateFile;
101
129
  /**
@@ -8,27 +8,29 @@
8
8
  * State file format (JSON):
9
9
  * {
10
10
  * "autoApproveAll": false,
11
- * "builtInGatedList": ["Write", "StrReplace", "Shell", ...],
12
11
  * "mcpToolPolicies": {
13
12
  * "apply_cloud_resource": { "requiresApproval": true, "message": "..." }
14
13
  * },
15
- * "approvedGrants": [{ "toolName": "Write", "mcpServerSlug": "", "argKey": "a.txt" }],
16
- * "approvedGrantTokens": ["V3JpdGUKYS50eHQ="]
14
+ * "approvedGrants": [{ "toolName": "edit", "mcpServerSlug": "", "key": "write", "salient": "a.txt" }],
15
+ * "approvedGrantTokens": ["d3JpdGUKYS50eHQ="]
17
16
  * }
18
17
  *
19
- * The hook gates only the explicitly dangerous set (builtInGatedList) and the
20
- * MCP tools that require approval (mcpToolPolicies, which by construction holds
21
- * only require-approval entries); every other tool is allowed. This mirrors the
22
- * native harness and avoids denying auto-approved MCP tools, which are absent
23
- * from the policy map and indistinguishable from unknown tools by name.
18
+ * The hook gates the dangerous built-in set and the MCP tools that require
19
+ * approval (mcpToolPolicies, which by construction holds only require-approval
20
+ * entries); every other tool is allowed. The gated built-in set and its
21
+ * name->category mapping are baked into the generated hook script (from
22
+ * approval-policy.ts), not carried in the state file only the dynamic inputs
23
+ * (autoApproveAll, mcpToolPolicies, approvedGrantTokens) live here. This mirrors
24
+ * the native harness and avoids denying auto-approved MCP tools, which are
25
+ * absent from the policy map and indistinguishable from unknown tools by name.
24
26
  *
25
27
  * Why grants instead of tool-call ids: a resumed Cursor agent re-issues the
26
28
  * approved tool with a BRAND NEW call id, so matching on the original call id
27
- * can never let the re-attempt through. Instead we grant by tool identity —
28
- * tool name plus a "salient" argument (the file path for Write, the command for
29
- * Shell, …; see extractArgKey). On reinvocation the hook allows a tool call
30
- * only if its (name, salient-arg) matches an approved grant; rejected/skipped
31
- * tools and any newly proposed dangerous tool are re-gated.
29
+ * can never let the re-attempt through. Instead we grant by canonical tool
30
+ * identity the approval category plus a "salient" resource value (the file
31
+ * path, the shell command; see {@link toolIdentity}). On reinvocation the hook
32
+ * allows a tool call only if its (category, salient) matches an approved grant;
33
+ * rejected/skipped tools and any newly proposed dangerous tool are re-gated.
32
34
  *
33
35
  * Tokens: the hook is a self-contained bash script, so it cannot parse an array
34
36
  * of grant objects. `approvedGrantTokens` is the flat, base64-encoded form of
@@ -52,19 +54,30 @@ import { join } from "node:path";
52
54
  import { create } from "@bufbuild/protobuf";
53
55
  import { ApprovalAction, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
54
56
  import { PendingApprovalSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
55
- import { getBuiltInGatedList, extractArgKey } from "./approval-policy.js";
57
+ import { extractArgKey, approvalCategory } from "./approval-policy.js";
58
+ export function toolIdentity(toolName, mcpServerSlug, args) {
59
+ if (mcpServerSlug) {
60
+ return { key: toolName, salient: "" };
61
+ }
62
+ const category = approvalCategory(toolName);
63
+ // A gated built-in keys on its category; an unknown/non-gated tool falls back
64
+ // to its own name (harmless — it is not gated, so it never enters the ledger).
65
+ return { key: category ?? toolName, salient: extractArgKey(args) };
66
+ }
56
67
  /**
57
68
  * Compute the flat token the bash hook matches on. The hook recomputes the same
58
- * token from the incoming tool call (`base64(toolName \n salientArg)`), so the
59
- * encoding here must stay byte-identical to the hook script in hook-script.ts.
69
+ * token from the incoming tool call (`base64(key \n salient)` see
70
+ * {@link toolIdentity}), so the encoding here must stay byte-identical to the
71
+ * hook script in hook-script.ts.
60
72
  */
61
- export function grantToken(toolName, argKey) {
62
- return Buffer.from(`${toolName}\n${argKey}`, "utf-8").toString("base64");
73
+ export function grantToken(key, salient) {
74
+ return Buffer.from(`${key}\n${salient}`, "utf-8").toString("base64");
63
75
  }
64
76
  /**
65
77
  * Build approval grants from the pending approvals the user adjudicated and
66
- * their decisions. Only APPROVE decisions produce grants. Built-in tools are
67
- * keyed by their salient argument; MCP tools are keyed by name only.
78
+ * their decisions. Only APPROVE / APPROVE_ALL decisions produce grants. Each
79
+ * grant carries the canonical {@link ToolIdentity} (category + salient resource)
80
+ * so the hook allows the exact approved resource on the resumed turn.
68
81
  */
69
82
  export function buildApprovalGrants(pendingApprovals, decisions) {
70
83
  const grants = [];
@@ -77,11 +90,12 @@ export function buildApprovalGrants(pendingApprovals, decisions) {
77
90
  const decision = decisions.get(pa.toolCallId);
78
91
  if (decision !== ApprovalAction.APPROVE && decision !== ApprovalAction.APPROVE_ALL)
79
92
  continue;
80
- const argKey = pa.mcpServerSlug ? "" : extractArgKey(parseArgs(pa.argsPreview));
93
+ const id = toolIdentity(pa.toolName, pa.mcpServerSlug, parseArgs(pa.argsPreview));
81
94
  grants.push({
82
95
  toolName: pa.toolName,
83
96
  mcpServerSlug: pa.mcpServerSlug,
84
- argKey,
97
+ key: id.key,
98
+ salient: id.salient,
85
99
  });
86
100
  }
87
101
  return grants;
@@ -101,11 +115,13 @@ function parseArgs(argsPreview) {
101
115
  * Build the approval state file content from merged policies and any approval
102
116
  * grants from a previous HITL cycle.
103
117
  *
104
- * The state file drives the hook script's allow/deny decisions:
105
- * - builtInGatedList: dangerous built-in tools the hook denies (unless granted)
118
+ * The state file carries the hook script's DYNAMIC inputs:
106
119
  * - mcpToolPolicies: per-tool policy for MCP tools requiring approval
107
120
  * - approvedGrants / approvedGrantTokens: tools approved in the current HITL
108
121
  * cycle, allowed through on reinvocation
122
+ *
123
+ * The static gated built-in set and its category mapping are baked into the
124
+ * generated hook script (from approval-policy.ts), not carried here.
109
125
  */
110
126
  export function buildApprovalState(mergedPolicies, autoApproveAll, grants) {
111
127
  const approvedGrants = grants ?? [];
@@ -118,10 +134,9 @@ export function buildApprovalState(mergedPolicies, autoApproveAll, grants) {
118
134
  }
119
135
  return {
120
136
  autoApproveAll,
121
- builtInGatedList: getBuiltInGatedList(),
122
137
  mcpToolPolicies,
123
138
  approvedGrants,
124
- approvedGrantTokens: approvedGrants.map((g) => grantToken(g.toolName, g.argKey)),
139
+ approvedGrantTokens: approvedGrants.map((g) => grantToken(g.key, g.salient)),
125
140
  };
126
141
  }
127
142
  const STATE_FILE_DIR = ".cursor/hooks";
@@ -1 +1 @@
1
- {"version":3,"file":"approval-state.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/approval-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"approval-state.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/approval-state.ts"],"names":[],"mappings":"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"}
@@ -18,30 +18,49 @@
18
18
  *
19
19
  * The script is self-contained (no Node.js required) for portability. It uses
20
20
  * bash + grep/cut for lightweight JSON field extraction. All policy decisions
21
- * are pre-computed by the runner into the state file; the hook only performs
22
- * mechanical field extraction and string lookups — the policy itself is
23
- * authored once in TypeScript (approval-policy.ts / approval-state.ts).
21
+ * are pre-computed by the runner into the state file (and into this generated
22
+ * script); the hook only performs mechanical field extraction and string
23
+ * lookups — the policy itself is authored once in TypeScript (approval-policy.ts
24
+ * / approval-state.ts).
25
+ *
26
+ * Cross-taxonomy identity (the crux):
27
+ * The preToolUse hook and the SDK event stream name the same operation
28
+ * differently — the hook receives PascalCase `tool_name` (`Write` for any file
29
+ * create/edit, `Shell`, `Delete`) while the stream emits lowercase `event.name`
30
+ * (`edit`, `shell`, `delete`). They also name the salient argument differently
31
+ * (`file_path` in the hook input vs `path` in the stream). So the hook and the
32
+ * runner cannot correlate on the raw name. Instead both reduce a tool call to a
33
+ * canonical identity — `base64(category \n salient)` — where `category` is the
34
+ * approval category (`write`/`delete`/`shell`, baked into the case statement
35
+ * below from approval-policy.ts) and `salient` is the resource VALUE (the file
36
+ * path or shell command), which is identical on both sides. The runner mirrors
37
+ * this exactly in approval-state.ts (toolIdentity + grantToken), so a denial
38
+ * recorded here correlates to the streamed tool call, and an approval grant
39
+ * matches the agent's re-attempt on reinvocation.
24
40
  *
25
41
  * Policy evaluation order (first match wins). The model is "gate the dangerous
26
42
  * set, allow the rest" — matching the native harness and avoiding denial of
27
43
  * auto-approved MCP tools (which are absent from mcpToolPolicies):
28
44
  * 1. autoApproveAll → allow
29
- * 2. Matches an approved grant token → allow (reinvocation after approval)
30
- * 3. Tool name in builtInGatedListdeny
31
- * 4. Tool name in mcpToolPolicies (require-approval) → deny
32
- * 5. Everything else (read-only built-ins, auto-approved MCP, unknown) → allow
45
+ * 2. Gated built-in (category non-empty):
46
+ * a. identity token in approvedGrantTokensallow (reinvocation grant)
47
+ * b. otherwise record denial, deny
48
+ * 3. MCP tool present in mcpToolPolicies (require-approval):
49
+ * a. name token in approvedGrantTokens → allow
50
+ * b. otherwise → record denial, deny
51
+ * 4. Everything else (read-only built-ins, auto-approved MCP, unknown) → allow
33
52
  */
34
53
  /**
35
54
  * Generates the bash hook script content.
36
55
  *
37
56
  * The script reads a JSON state file written by the cursor-runner before
38
57
  * each agent.send() call. The state file is the single source of truth
39
- * for all approval decisions.
58
+ * for the dynamic approval inputs (autoApproveAll, mcpToolPolicies,
59
+ * approvedGrantTokens). The static policy (which built-ins are gated and their
60
+ * categories, and which arg fields are salient) is baked into the script at
61
+ * generation time from approval-policy.ts.
40
62
  *
41
- * Approved grants are matched by a base64 token of `toolName \n salientArg`,
42
- * recomputed here from the incoming tool call. The salient-arg field list is
43
- * injected from SALIENT_ARG_FIELDS so the runner and the hook never disagree on
44
- * which argument identifies the resource. The encoding must stay byte-identical
63
+ * The identity token encoding (`base64(key \n salient)`) must stay byte-identical
45
64
  * to grantToken() in approval-state.ts.
46
65
  */
47
66
  export declare function generateHookScript(stateFilePath: string, ledgerFilePath: string): string;