@stigmer/runner 3.0.3 → 3.0.4

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":"f39ecbdabee6cf8e","builtAt":"2026-06-10T07:04:09.007Z","fileCount":192}
1
+ {"hash":"af9f8d2d84cef6db","builtAt":"2026-06-10T08:56:06.851Z","fileCount":192}
@@ -16,12 +16,20 @@
16
16
  * so its ledger is the authoritative record of what was gated this turn
17
17
  * 5. Returns { "permission": "allow" } or { "permission": "deny" } on stdout
18
18
  *
19
- * The script is self-contained (no Node.js required) for portability. It uses
20
- * bash + grep/cut for lightweight JSON field extraction. All policy decisions
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).
19
+ * Identity extraction runs on the SAME Node.js binary as the runner (its
20
+ * absolute path process.execPath is baked into the script at generation
21
+ * time), because the identity token must be byte-identical to the one the
22
+ * runner computes from the parsed stream event. The original grep/cut
23
+ * extraction is kept only as a best-effort fallback if that binary cannot run:
24
+ * grep's `"command":"[^"]*"` truncates at the first JSON-escaped quote, so for
25
+ * a shell command like `printf '%s' "x" > file` the fallback token will NOT
26
+ * match the runner's — the call is still denied (the gate holds) but the
27
+ * denial cannot be overlaid onto the real streamed tool call and a grant for
28
+ * it will not match on reinvocation. All policy decisions are pre-computed by
29
+ * the runner into the state file (and into this generated script); the hook
30
+ * only performs mechanical field extraction and string lookups — the policy
31
+ * itself is authored once in TypeScript (approval-policy.ts /
32
+ * approval-state.ts).
25
33
  *
26
34
  * Cross-taxonomy identity (the crux):
27
35
  * The preToolUse hook and the SDK event stream name the same operation
@@ -16,12 +16,20 @@
16
16
  * so its ledger is the authoritative record of what was gated this turn
17
17
  * 5. Returns { "permission": "allow" } or { "permission": "deny" } on stdout
18
18
  *
19
- * The script is self-contained (no Node.js required) for portability. It uses
20
- * bash + grep/cut for lightweight JSON field extraction. All policy decisions
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).
19
+ * Identity extraction runs on the SAME Node.js binary as the runner (its
20
+ * absolute path process.execPath is baked into the script at generation
21
+ * time), because the identity token must be byte-identical to the one the
22
+ * runner computes from the parsed stream event. The original grep/cut
23
+ * extraction is kept only as a best-effort fallback if that binary cannot run:
24
+ * grep's `"command":"[^"]*"` truncates at the first JSON-escaped quote, so for
25
+ * a shell command like `printf '%s' "x" > file` the fallback token will NOT
26
+ * match the runner's — the call is still denied (the gate holds) but the
27
+ * denial cannot be overlaid onto the real streamed tool call and a grant for
28
+ * it will not match on reinvocation. All policy decisions are pre-computed by
29
+ * the runner into the state file (and into this generated script); the hook
30
+ * only performs mechanical field extraction and string lookups — the policy
31
+ * itself is authored once in TypeScript (approval-policy.ts /
32
+ * approval-state.ts).
25
33
  *
26
34
  * Cross-taxonomy identity (the crux):
27
35
  * The preToolUse hook and the SDK event stream name the same operation
@@ -70,10 +78,41 @@ function buildCategoryCaseArms() {
70
78
  const arms = [];
71
79
  for (const [category, names] of byCategory) {
72
80
  const pattern = names.map((n) => `"${n}"`).join("|");
73
- arms.push(` ${pattern}) CATEGORY="${category}" ;;`);
81
+ arms.push(` ${pattern}) CATEGORY="${category}" ;;`);
74
82
  }
75
83
  return arms.join("\n");
76
84
  }
85
+ /**
86
+ * Build the inline Node.js identity extractor embedded in the hook script.
87
+ *
88
+ * Parses the hook's stdin JSON properly (the bash fallback's grep truncates
89
+ * string values at the first escaped quote) and emits four lines:
90
+ * tool_name, canonical category, identity token, and MCP name-token. The token
91
+ * encodings must stay byte-identical to grantToken() in approval-state.ts.
92
+ *
93
+ * Authored as a single-quoted bash string, so the JS must not contain single
94
+ * quotes. The category map and salient field list are baked from
95
+ * approval-policy.ts — the same source the runner uses — so the two sides can
96
+ * never disagree.
97
+ */
98
+ function buildNodeIdentityScript() {
99
+ const categoryMap = {};
100
+ for (const [name, category] of getBuiltInGatedCategories()) {
101
+ categoryMap[name] = category;
102
+ }
103
+ const categories = JSON.stringify(categoryMap);
104
+ const fields = JSON.stringify(SALIENT_ARG_FIELDS);
105
+ return [
106
+ `const t=JSON.parse(require("fs").readFileSync(0,"utf8"));`,
107
+ `const name=typeof t.tool_name==="string"?t.tool_name:"";`,
108
+ `const cat=(${categories})[name]||"";`,
109
+ `const a=(t.tool_input&&typeof t.tool_input==="object")?t.tool_input:{};`,
110
+ `let s="";`,
111
+ `for(const f of ${fields}){const v=a[f];if(typeof v==="string"&&v){s=v;break;}}`,
112
+ `const b=(x)=>Buffer.from(x,"utf8").toString("base64");`,
113
+ `process.stdout.write(name+"\\n"+cat+"\\n"+b(cat+"\\n"+s)+"\\n"+b(name+"\\n"));`,
114
+ ].join("");
115
+ }
77
116
  /**
78
117
  * Generates the bash hook script content.
79
118
  *
@@ -90,6 +129,7 @@ function buildCategoryCaseArms() {
90
129
  export function generateHookScript(stateFilePath, ledgerFilePath) {
91
130
  const salientFields = SALIENT_ARG_FIELDS.join(" ");
92
131
  const categoryCaseArms = buildCategoryCaseArms();
132
+ const nodeIdentityScript = buildNodeIdentityScript();
93
133
  return `#!/bin/bash
94
134
  # Stigmer HITL approval hook for Cursor preToolUse
95
135
  # Generated by cursor-runner — do not edit manually.
@@ -103,15 +143,45 @@ set -euo pipefail
103
143
 
104
144
  INPUT=$(cat)
105
145
 
106
- # Extract tool_name from the hook input JSON. The hook receives PascalCase names
107
- # (Write/Shell/Delete/Read/...). Every extraction ends with '|| true': under
108
- # 'set -e' a non-matching grep would otherwise abort the script and emit no
109
- # decision.
110
- TOOL_NAME=$(echo "$INPUT" | grep -o '"tool_name":"[^"]*"' | head -1 | cut -d'"' -f4 || true)
111
-
112
146
  STATE_FILE="${stateFilePath}"
113
147
  LEDGER_FILE="${ledgerFilePath}"
114
148
 
149
+ # --- Canonical identity: tool_name / category / identity token / MCP token ---
150
+ # Computed by the same Node.js binary that runs the cursor-runner (absolute path
151
+ # baked at generation time) so JSON string values — file paths and especially
152
+ # shell commands containing quotes, newlines, or unicode escapes — decode to the
153
+ # exact bytes the runner sees in the stream event. ELECTRON_RUN_AS_NODE makes
154
+ # the invocation safe when the runner is embedded in an Electron app (where
155
+ # process.execPath is the Electron binary).
156
+ NODE_BIN="${process.execPath}"
157
+ IDENTITY=$(printf '%s' "$INPUT" | ELECTRON_RUN_AS_NODE=1 "$NODE_BIN" -e '${nodeIdentityScript}' 2>/dev/null || true)
158
+ if [ -n "$IDENTITY" ]; then
159
+ TOOL_NAME=$(printf '%s\\n' "$IDENTITY" | sed -n 1p)
160
+ CATEGORY=$(printf '%s\\n' "$IDENTITY" | sed -n 2p)
161
+ TOKEN=$(printf '%s\\n' "$IDENTITY" | sed -n 3p)
162
+ MCP_TOKEN=$(printf '%s\\n' "$IDENTITY" | sed -n 4p)
163
+ else
164
+ # Fallback when the Node binary cannot run: grep/cut extraction. Best-effort
165
+ # only — '"field":"[^"]*"' truncates at the first JSON-escaped quote, so the
166
+ # token may not match the runner's for values containing escapes. Gating still
167
+ # holds (deny goes out); only denial correlation and grant precision degrade.
168
+ # Every extraction ends with '|| true': under 'set -e' a non-matching grep
169
+ # would otherwise abort the script and emit no decision.
170
+ TOOL_NAME=$(echo "$INPUT" | grep -o '"tool_name":"[^"]*"' | head -1 | cut -d'"' -f4 || true)
171
+ SALIENT=""
172
+ for field in ${salientFields}; do
173
+ v=$(echo "$INPUT" | grep -o "\\"$field\\":\\"[^\\"]*\\"" | head -1 | cut -d'"' -f4 || true)
174
+ if [ -n "$v" ]; then SALIENT="$v"; break; fi
175
+ done
176
+ CATEGORY=""
177
+ case "$TOOL_NAME" in
178
+ ${categoryCaseArms}
179
+ *) CATEGORY="" ;;
180
+ esac
181
+ TOKEN=$(printf '%s\\n%s' "$CATEGORY" "$SALIENT" | base64 | tr -d '\\n')
182
+ MCP_TOKEN=$(printf '%s\\n' "$TOOL_NAME" | base64 | tr -d '\\n')
183
+ fi
184
+
115
185
  # --- Failsafe: missing state file → deny (fail-closed) ---
116
186
  if [ ! -f "$STATE_FILE" ]; then
117
187
  echo '{"permission":"deny","agent_message":"${APPROVAL_REQUIRED_AGENT_MESSAGE}","user_message":"Tool requires approval: '"$TOOL_NAME"'"}'
@@ -126,22 +196,6 @@ if echo "$STATE" | grep -q '"autoApproveAll":true'; then
126
196
  exit 0
127
197
  fi
128
198
 
129
- # --- Salient resource value (file path / command), spanning both taxonomies'
130
- # arg field names (file_path here, path on the stream side). First match wins. ---
131
- SALIENT=""
132
- for field in ${salientFields}; do
133
- v=$(echo "$INPUT" | grep -o "\\"$field\\":\\"[^\\"]*\\"" | head -1 | cut -d'"' -f4 || true)
134
- if [ -n "$v" ]; then SALIENT="$v"; break; fi
135
- done
136
-
137
- # --- Canonical approval category for this hook tool_name (baked from
138
- # approval-policy.ts). Empty for non-gated tools. ---
139
- CATEGORY=""
140
- case "$TOOL_NAME" in
141
- ${categoryCaseArms}
142
- *) CATEGORY="" ;;
143
- esac
144
-
145
199
  # Append a denial record to the ledger. Best-effort: a ledger write failure must
146
200
  # never abort the decision (the deny still goes out on stdout). toolName is raw
147
201
  # for human-readable debugging; token drives correlation in the runner.
@@ -151,8 +205,6 @@ record_denial() {
151
205
 
152
206
  # --- 2. Gated built-in tools (category non-empty) ---
153
207
  if [ -n "$CATEGORY" ]; then
154
- # Canonical identity token: base64("$CATEGORY\\n$SALIENT").
155
- TOKEN=$(printf '%s\\n%s' "$CATEGORY" "$SALIENT" | base64 | tr -d '\\n')
156
208
  # Reinvocation grant: this exact resource was approved earlier → allow.
157
209
  if echo "$STATE" | grep -qF "\\"$TOKEN\\""; then
158
210
  echo '{"permission":"allow"}'
@@ -171,7 +223,6 @@ fi
171
223
  if echo "$STATE" | grep -q "\\"mcpToolPolicies\\"" && [ -n "$TOOL_NAME" ]; then
172
224
  TOOL_POLICY=$(echo "$STATE" | grep -o "\\"$TOOL_NAME\\":{[^}]*}" | head -1 || true)
173
225
  if [ -n "$TOOL_POLICY" ] && ! echo "$TOOL_POLICY" | grep -q '"requiresApproval":false'; then
174
- MCP_TOKEN=$(printf '%s\\n' "$TOOL_NAME" | base64 | tr -d '\\n')
175
226
  if echo "$STATE" | grep -qF "\\"$MCP_TOKEN\\""; then
176
227
  echo '{"permission":"allow"}'
177
228
  exit 0
@@ -1 +1 @@
1
- {"version":3,"file":"hook-script.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/hook-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAErF,MAAM,+BAA+B,GACnC,0EAA0E;IAC1E,6EAA6E;IAC7E,4EAA4E;IAC5E,sCAAsC,CAAC;AAEzC;;;;GAIG;AACH,SAAS,qBAAqB;IAC5B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,yBAAyB,EAAE,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,CAAC,OAAO,OAAO,eAAe,QAAQ,MAAM,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAqB,EAAE,cAAsB;IAC9E,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,gBAAgB,GAAG,qBAAqB,EAAE,CAAC;IACjD,OAAO;;;;;;;;;;;;;;;;;;;cAmBK,aAAa;eACZ,cAAc;;;;gDAImB,+BAA+B;;;;;;;;;;;;;;;eAehE,aAAa;;;;;;;;;EAS1B,gBAAgB;;;;;;;;;;;;;;;;;;;;;gDAqB8B,+BAA+B;;;;;;;;;;;;;;;;;;;;;;kDAsB7B,+BAA+B;;;;;;;;;;;CAWhF,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"hook-script.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/hook-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAErF,MAAM,+BAA+B,GACnC,0EAA0E;IAC1E,6EAA6E;IAC7E,4EAA4E;IAC5E,sCAAsC,CAAC;AAEzC;;;;GAIG;AACH,SAAS,qBAAqB;IAC5B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,yBAAyB,EAAE,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,CAAC,SAAS,OAAO,eAAe,QAAQ,MAAM,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,uBAAuB;IAC9B,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,yBAAyB,EAAE,EAAE,CAAC;QAC3D,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;IAC/B,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAClD,OAAO;QACL,2DAA2D;QAC3D,0DAA0D;QAC1D,cAAc,UAAU,cAAc;QACtC,yEAAyE;QACzE,WAAW;QACX,kBAAkB,MAAM,wDAAwD;QAChF,wDAAwD;QACxD,gFAAgF;KACjF,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAqB,EAAE,cAAsB;IAC9E,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,gBAAgB,GAAG,qBAAqB,EAAE,CAAC;IACjD,MAAM,kBAAkB,GAAG,uBAAuB,EAAE,CAAC;IACrD,OAAO;;;;;;;;;;;;;cAaK,aAAa;eACZ,cAAc;;;;;;;;;YASjB,OAAO,CAAC,QAAQ;2EAC+C,kBAAkB;;;;;;;;;;;;;;;iBAe5E,aAAa;;;;;;EAM5B,gBAAgB;;;;;;;;;gDAS8B,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;gDA2B/B,+BAA+B;;;;;;;;;;;;;;;;;;;;;kDAqB7B,+BAA+B;;;;;;;;;;;CAWhF,CAAC;AACF,CAAC"}
@@ -56,6 +56,15 @@ export interface ResumeAgentOptions {
56
56
  apiKey: string;
57
57
  agentId: string;
58
58
  sessionId: string;
59
+ /**
60
+ * Workspace directories — same as {@link CreateAgentOptions.workspaceDirs}.
61
+ * NOT persisted across Agent.resume(): without an explicit cwd the SDK falls
62
+ * back to process.cwd(), which both mis-roots the resumed agent and loads
63
+ * the "project" setting source (and therefore the HITL approval hook in
64
+ * .cursor/hooks.json) from the wrong directory — silently disabling the
65
+ * approval gate on every resumed turn.
66
+ */
67
+ workspaceDirs: string[];
59
68
  /** Durable workspace volume root; the SDK state store lives under it. */
60
69
  workspaceRootDir: string;
61
70
  model?: string;
@@ -129,6 +129,9 @@ export async function createAgent(options) {
129
129
  * propagate or fall back to a fresh agent with continuation context.
130
130
  */
131
131
  export async function resumeAgent(options) {
132
+ const cwd = options.workspaceDirs.length === 1
133
+ ? options.workspaceDirs[0]
134
+ : options.workspaceDirs;
132
135
  const platform = resolvePlatformOptions(options.sessionId, options.workspaceRootDir);
133
136
  console.log(`resumeAgent: agentId=${options.agentId}, sessionId=${options.sessionId}, ` +
134
137
  `workspaceRef=${platform.workspaceRef}, stateRoot=${platform.stateRoot}, ` +
@@ -136,9 +139,13 @@ export async function resumeAgent(options) {
136
139
  return Agent.resume(options.agentId, {
137
140
  apiKey: options.apiKey,
138
141
  model: options.model ? { id: options.model } : undefined,
139
- // settingSources are not persisted across resume, so the "project" source
140
- // (which loads the HITL approval hook) must be re-supplied every turn.
141
- local: { settingSources: [...LOCAL_SETTING_SOURCES] },
142
+ // Neither cwd nor settingSources survive Agent.resume(); both must be
143
+ // re-supplied every turn. Omitting cwd makes the SDK fall back to
144
+ // process.cwd(), which re-roots the agent in the runner's own working
145
+ // directory and loads the "project" setting source — the .cursor/hooks.json
146
+ // carrying the HITL approval hook — from that wrong directory, silently
147
+ // disabling the approval gate on every resumed turn.
148
+ local: { cwd, settingSources: [...LOCAL_SETTING_SOURCES] },
142
149
  mcpServers: options.mcpServers,
143
150
  agents: options.agents,
144
151
  platform,
@@ -222,6 +229,7 @@ export async function resolveAgent(harnessStateId, options, mode = "local") {
222
229
  apiKey: options.apiKey,
223
230
  agentId: harnessStateId,
224
231
  sessionId: options.sessionId,
232
+ workspaceDirs: options.workspaceDirs,
225
233
  workspaceRootDir: options.workspaceRootDir,
226
234
  model: options.model,
227
235
  mcpServers: options.mcpServers,
@@ -1 +1 @@
1
- {"version":3,"file":"session-lifecycle.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/session-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-lifecycle.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/session-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAIpC,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,oBAAoB,GAAG,2BAA2B,CAAC;AAEzD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,qBAAqB,GAAG,CAAC,SAAS,CAAU,CAAC;AAwGnD,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,sBAAsB,CACpC,SAAiB,EACjB,gBAAwB;IAExB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,8EAA8E;YAC9E,kFAAkF;YAClF,gFAAgF,CACjF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,iFAAiF;YACjF,gFAAgF,CACjF,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;IAC1E,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,OAAO;QACL,YAAY,EAAE,mBAAmB,SAAS,EAAE;QAC5C,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;QAC5C,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAE1B,MAAM,QAAQ,GAAG,sBAAsB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CACT,0BAA0B,OAAO,CAAC,SAAS,kBAAkB,QAAQ,CAAC,YAAY,IAAI;QACtF,aAAa,QAAQ,CAAC,SAAS,iBAAiB,OAAO,CAAC,GAAG,EAAE,EAAE,CAChE,CAAC;IAEF,OAAO,KAAK,CAAC,MAAM,CAAC;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE;QAC5B,KAAK,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,GAAG,qBAAqB,CAAC,EAAE;QAC1D,UAAU,EAAE,OAAO,CAAC,UAAiC;QACrD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ;KACT,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;QAC5C,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAE1B,MAAM,QAAQ,GAAG,sBAAsB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CACT,wBAAwB,OAAO,CAAC,OAAO,eAAe,OAAO,CAAC,SAAS,IAAI;QAC3E,gBAAgB,QAAQ,CAAC,YAAY,eAAe,QAAQ,CAAC,SAAS,IAAI;QAC1E,eAAe,OAAO,CAAC,GAAG,EAAE,EAAE,CAC/B,CAAC;IAEF,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE;QACnC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS;QACxD,sEAAsE;QACtE,kEAAkE;QAClE,sEAAsE;QACtE,4EAA4E;QAC5E,wEAAwE;QACxE,qDAAqD;QACrD,KAAK,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,GAAG,qBAAqB,CAAC,EAAE;QAC1D,UAAU,EAAE,OAAO,CAAC,UAAiC;QACrD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ;KACT,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgC;IACrE,OAAO,CAAC,GAAG,CACT,+BAA+B,OAAO,CAAC,SAAS,IAAI;QACpD,SAAS,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtD,CAAC;IAEF,OAAO,KAAK,CAAC,MAAM,CAAC;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS;QACxD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;QAC/B,UAAU,EAAE,OAAO,CAAC,UAAiC;QACrD,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgC;IACrE,OAAO,CAAC,GAAG,CACT,6BAA6B,OAAO,CAAC,OAAO,EAAE,CAC/C,CAAC;IAEF,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE;QACnC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS;QACxD,UAAU,EAAE,OAAO,CAAC,UAAiC;QACrD,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,cAAsB,EACtB,OAAqD,EACrD,OAA0B,OAAO;IAEjC,IAAI,cAAc,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,KAAK,OAAO;gBAC5B,CAAC,CAAC,MAAM,gBAAgB,CAAC;oBACrB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,OAAO,EAAE,cAAc;oBACvB,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;iBACvB,CAAC;gBACJ,CAAC,CAAC,MAAM,WAAW,CAAC;oBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,OAAO,EAAE,cAAc;oBACvB,SAAS,EAAG,OAA8B,CAAC,SAAS;oBACpD,aAAa,EAAG,OAA8B,CAAC,aAAa;oBAC5D,gBAAgB,EAAG,OAA8B,CAAC,gBAAgB;oBAClE,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;iBACvB,CAAC,CAAC;YAEP,OAAO;gBACL,KAAK;gBACL,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,KAAK;gBACZ,OAAO,EAAE,IAAI;gBACb,IAAI;gBACJ,MAAM,EAAE,sBAAsB;aAC/B,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,OAAO,CAAC,IAAI,CACV,mCAAmC,IAAI,WAAW,cAAc,KAAK;gBACrE,2CAA2C;gBAC3C,aAAa,OAAO,CAAC,SAAS,YAAY,MAAM,EAAE,CACnD,CAAC;YAEF,MAAM,KAAK,GAAG,IAAI,KAAK,OAAO;gBAC5B,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAkC,CAAC;gBAC5D,CAAC,CAAC,MAAM,WAAW,CAAC,OAA6B,CAAC,CAAC;YAErD,OAAO,CAAC,GAAG,CACT,0BAA0B,IAAI,kBAAkB;gBAChD,cAAc,cAAc,gBAAgB,KAAK,CAAC,OAAO,IAAI;gBAC7D,aAAa,OAAO,CAAC,SAAS,EAAE,CACjC,CAAC;YAEF,OAAO;gBACL,KAAK;gBACL,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,IAAI;gBACX,OAAO,EAAE,KAAK;gBACd,IAAI;gBACJ,MAAM,EAAE,8BAA8B;gBACtC,mBAAmB,EAAE,MAAM;aAC5B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,KAAK,OAAO;QAC5B,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAkC,CAAC;QAC5D,CAAC,CAAC,MAAM,WAAW,CAAC,OAA6B,CAAC,CAAC;IAErD,OAAO;QACL,KAAK;QACL,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,KAAK;QACd,IAAI;QACJ,MAAM,EAAE,yBAAyB;KAClC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,MAAc;IAChE,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CACV,kCAAkC,OAAO,GAAG,EAC5C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;IACJ,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/runner",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -84,7 +84,7 @@
84
84
  "@opentelemetry/resources": "^2.0.0",
85
85
  "@opentelemetry/sdk-trace-base": "^2.0.0",
86
86
  "@opentelemetry/sdk-trace-node": "^2.0.0",
87
- "@stigmer/protos": "3.0.3",
87
+ "@stigmer/protos": "3.0.4",
88
88
  "@temporalio/activity": "^1.11.0",
89
89
  "@temporalio/client": "^1.11.0",
90
90
  "@temporalio/common": "^1.11.0",
@@ -146,4 +146,59 @@ d("generated preToolUse hook", () => {
146
146
  const h = setup({ noStateFile: true });
147
147
  expect(h.decide(hookWrite("/x/a.txt")).permission).toBe("deny");
148
148
  });
149
+
150
+ // Regression: the original grep-based extraction truncated string values at
151
+ // the first JSON-escaped character, so a shell command containing double
152
+ // quotes (e.g. `printf '%s' 'x' > "file"`) produced a ledger token that never
153
+ // matched the runner's grantToken — the denied call stayed COMPLETED in the
154
+ // persisted messages and a grant for it was re-denied on reinvocation.
155
+ // (Observed live in TestCursorHarness_HITL_ResumedTurn_StillGated.)
156
+ it("records a byte-identical token for commands with quotes, escapes, and newlines", () => {
157
+ const commands = [
158
+ 'printf \'%s\' \'hello\' > "/tmp/a dir/resumed-gate.txt"',
159
+ 'echo "double \\"nested\\" quotes" && echo done',
160
+ "line1\nline2\twith\ttabs",
161
+ 'unicode: caf\u00e9 \u2014 emoji \u{1F600}',
162
+ ];
163
+ for (const command of commands) {
164
+ const h = setup({});
165
+ expect(h.decide(hookShell(command)).permission).toBe("deny");
166
+ const ledger = h.ledger();
167
+ expect(ledger).toHaveLength(1);
168
+ expect(ledger[0].token).toBe(grantToken("shell", command));
169
+ }
170
+ });
171
+
172
+ it("allows the exact granted shell command even when it contains quotes", () => {
173
+ const command = 'printf \'%s\' \'hello-resume\' > "/x/resumed-gate.txt"';
174
+ const id = toolIdentity("shell", "", { command });
175
+ const h = setup({ grants: [{ toolName: "shell", mcpServerSlug: "", key: id.key, salient: id.salient }] });
176
+
177
+ expect(h.decide(hookShell(command)).permission).toBe("allow");
178
+ // A different command is NOT covered by the grant -> still gated.
179
+ expect(h.decide(hookShell('rm -rf "/x"')).permission).toBe("deny");
180
+ });
181
+
182
+ it("still denies gated tools via the bash fallback when the Node binary is unavailable", () => {
183
+ const ws = mkdtempSync(join(tmpdir(), "hook-script-fallback-"));
184
+ tempDirs.push(ws);
185
+ const dir = join(ws, ".cursor", "hooks");
186
+ mkdirSync(dir, { recursive: true });
187
+ const statePath = join(dir, "state.json");
188
+ const ledgerPath = join(dir, "denials.jsonl");
189
+ const scriptPath = join(dir, "hook.sh");
190
+ // Break the baked Node path to force the grep/cut fallback.
191
+ const script = generateHookScript(statePath, ledgerPath)
192
+ .replace(`NODE_BIN="${process.execPath}"`, 'NODE_BIN="/nonexistent/node"');
193
+ writeFileSync(scriptPath, script, "utf-8");
194
+ writeFileSync(statePath, JSON.stringify(buildApprovalState(new Map(), false)), "utf-8");
195
+
196
+ const raw = execFileSync("bash", [scriptPath], {
197
+ input: JSON.stringify(hookWrite("/x/a.txt")),
198
+ }).toString();
199
+ expect(raw).toContain('"permission":"deny"');
200
+ const ledger = readFileSync(ledgerPath, "utf-8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
201
+ expect(ledger).toHaveLength(1);
202
+ expect(ledger[0].token).toBe(grantToken("write", "/x/a.txt"));
203
+ });
149
204
  });
@@ -7,12 +7,20 @@
7
7
  * collide. These invariants are correctness-critical, hence the explicit tests.
8
8
  */
9
9
 
10
- import { describe, it, expect, afterEach } from "vitest";
10
+ import { describe, it, expect, afterEach, vi } from "vitest";
11
11
  import { mkdtempSync, rmSync, existsSync } from "node:fs";
12
12
  import { tmpdir } from "node:os";
13
13
  import { join } from "node:path";
14
14
 
15
- import { resolvePlatformOptions } from "../session-lifecycle.js";
15
+ vi.mock("@cursor/sdk", () => ({
16
+ Agent: {
17
+ create: vi.fn(async () => ({ agentId: "agent-created" })),
18
+ resume: vi.fn(async () => ({ agentId: "agent-resumed" })),
19
+ },
20
+ }));
21
+
22
+ import { Agent } from "@cursor/sdk";
23
+ import { resolvePlatformOptions, createAgent, resumeAgent } from "../session-lifecycle.js";
16
24
 
17
25
  const tempRoots: string[] = [];
18
26
 
@@ -63,3 +71,66 @@ describe("resolvePlatformOptions", () => {
63
71
  expect(() => resolvePlatformOptions("ses-123", "")).toThrow(/workspaceRootDir is required/);
64
72
  });
65
73
  });
74
+
75
+ // ---------------------------------------------------------------------------
76
+ // Workspace binding across create/resume
77
+ //
78
+ // Regression: Agent.resume() does not persist local.cwd. When resumeAgent()
79
+ // omitted it, the SDK fell back to process.cwd() — re-rooting the resumed
80
+ // agent in the runner's own working directory and loading the "project"
81
+ // setting source (the .cursor/hooks.json carrying the HITL approval hook)
82
+ // from that wrong directory. Result: on every resumed turn, file edits and
83
+ // shell commands ran unguarded with no approval card (observed in production
84
+ // execution aex_01ktr5na07f5xtmn0dz3mfjtdp).
85
+ // ---------------------------------------------------------------------------
86
+
87
+ describe("workspace binding on create/resume", () => {
88
+ const baseOptions = {
89
+ apiKey: "key",
90
+ sessionId: "ses-cwd-test",
91
+ model: "gpt-test",
92
+ };
93
+
94
+ it("createAgent passes the single workspace dir as local.cwd", async () => {
95
+ const workspaceRootDir = freshWorkspaceRoot();
96
+ await createAgent({
97
+ ...baseOptions,
98
+ workspaceDirs: ["/work/repo-a"],
99
+ workspaceRootDir,
100
+ });
101
+
102
+ const callOptions = vi.mocked(Agent.create).mock.calls.at(-1)![0] as any;
103
+ expect(callOptions.local.cwd).toBe("/work/repo-a");
104
+ expect(callOptions.local.settingSources).toContain("project");
105
+ });
106
+
107
+ it("resumeAgent re-supplies local.cwd (not persisted by Agent.resume)", async () => {
108
+ const workspaceRootDir = freshWorkspaceRoot();
109
+ await resumeAgent({
110
+ ...baseOptions,
111
+ agentId: "agent-123",
112
+ workspaceDirs: ["/work/repo-a"],
113
+ workspaceRootDir,
114
+ });
115
+
116
+ const [agentId, callOptions] = vi.mocked(Agent.resume).mock.calls.at(-1)! as [string, any];
117
+ expect(agentId).toBe("agent-123");
118
+ // The load-bearing assertion: without cwd the SDK re-roots the agent at
119
+ // process.cwd() and the project HITL hook never loads on resumed turns.
120
+ expect(callOptions.local.cwd).toBe("/work/repo-a");
121
+ expect(callOptions.local.settingSources).toContain("project");
122
+ });
123
+
124
+ it("resumeAgent passes multiple workspace dirs as an array cwd", async () => {
125
+ const workspaceRootDir = freshWorkspaceRoot();
126
+ await resumeAgent({
127
+ ...baseOptions,
128
+ agentId: "agent-456",
129
+ workspaceDirs: ["/work/repo-a", "/work/repo-b"],
130
+ workspaceRootDir,
131
+ });
132
+
133
+ const callOptions = vi.mocked(Agent.resume).mock.calls.at(-1)![1] as any;
134
+ expect(callOptions.local.cwd).toEqual(["/work/repo-a", "/work/repo-b"]);
135
+ });
136
+ });
@@ -16,12 +16,20 @@
16
16
  * so its ledger is the authoritative record of what was gated this turn
17
17
  * 5. Returns { "permission": "allow" } or { "permission": "deny" } on stdout
18
18
  *
19
- * The script is self-contained (no Node.js required) for portability. It uses
20
- * bash + grep/cut for lightweight JSON field extraction. All policy decisions
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).
19
+ * Identity extraction runs on the SAME Node.js binary as the runner (its
20
+ * absolute path process.execPath is baked into the script at generation
21
+ * time), because the identity token must be byte-identical to the one the
22
+ * runner computes from the parsed stream event. The original grep/cut
23
+ * extraction is kept only as a best-effort fallback if that binary cannot run:
24
+ * grep's `"command":"[^"]*"` truncates at the first JSON-escaped quote, so for
25
+ * a shell command like `printf '%s' "x" > file` the fallback token will NOT
26
+ * match the runner's — the call is still denied (the gate holds) but the
27
+ * denial cannot be overlaid onto the real streamed tool call and a grant for
28
+ * it will not match on reinvocation. All policy decisions are pre-computed by
29
+ * the runner into the state file (and into this generated script); the hook
30
+ * only performs mechanical field extraction and string lookups — the policy
31
+ * itself is authored once in TypeScript (approval-policy.ts /
32
+ * approval-state.ts).
25
33
  *
26
34
  * Cross-taxonomy identity (the crux):
27
35
  * The preToolUse hook and the SDK event stream name the same operation
@@ -74,11 +82,43 @@ function buildCategoryCaseArms(): string {
74
82
  const arms: string[] = [];
75
83
  for (const [category, names] of byCategory) {
76
84
  const pattern = names.map((n) => `"${n}"`).join("|");
77
- arms.push(` ${pattern}) CATEGORY="${category}" ;;`);
85
+ arms.push(` ${pattern}) CATEGORY="${category}" ;;`);
78
86
  }
79
87
  return arms.join("\n");
80
88
  }
81
89
 
90
+ /**
91
+ * Build the inline Node.js identity extractor embedded in the hook script.
92
+ *
93
+ * Parses the hook's stdin JSON properly (the bash fallback's grep truncates
94
+ * string values at the first escaped quote) and emits four lines:
95
+ * tool_name, canonical category, identity token, and MCP name-token. The token
96
+ * encodings must stay byte-identical to grantToken() in approval-state.ts.
97
+ *
98
+ * Authored as a single-quoted bash string, so the JS must not contain single
99
+ * quotes. The category map and salient field list are baked from
100
+ * approval-policy.ts — the same source the runner uses — so the two sides can
101
+ * never disagree.
102
+ */
103
+ function buildNodeIdentityScript(): string {
104
+ const categoryMap: Record<string, string> = {};
105
+ for (const [name, category] of getBuiltInGatedCategories()) {
106
+ categoryMap[name] = category;
107
+ }
108
+ const categories = JSON.stringify(categoryMap);
109
+ const fields = JSON.stringify(SALIENT_ARG_FIELDS);
110
+ return [
111
+ `const t=JSON.parse(require("fs").readFileSync(0,"utf8"));`,
112
+ `const name=typeof t.tool_name==="string"?t.tool_name:"";`,
113
+ `const cat=(${categories})[name]||"";`,
114
+ `const a=(t.tool_input&&typeof t.tool_input==="object")?t.tool_input:{};`,
115
+ `let s="";`,
116
+ `for(const f of ${fields}){const v=a[f];if(typeof v==="string"&&v){s=v;break;}}`,
117
+ `const b=(x)=>Buffer.from(x,"utf8").toString("base64");`,
118
+ `process.stdout.write(name+"\\n"+cat+"\\n"+b(cat+"\\n"+s)+"\\n"+b(name+"\\n"));`,
119
+ ].join("");
120
+ }
121
+
82
122
  /**
83
123
  * Generates the bash hook script content.
84
124
  *
@@ -95,6 +135,7 @@ function buildCategoryCaseArms(): string {
95
135
  export function generateHookScript(stateFilePath: string, ledgerFilePath: string): string {
96
136
  const salientFields = SALIENT_ARG_FIELDS.join(" ");
97
137
  const categoryCaseArms = buildCategoryCaseArms();
138
+ const nodeIdentityScript = buildNodeIdentityScript();
98
139
  return `#!/bin/bash
99
140
  # Stigmer HITL approval hook for Cursor preToolUse
100
141
  # Generated by cursor-runner — do not edit manually.
@@ -108,15 +149,45 @@ set -euo pipefail
108
149
 
109
150
  INPUT=$(cat)
110
151
 
111
- # Extract tool_name from the hook input JSON. The hook receives PascalCase names
112
- # (Write/Shell/Delete/Read/...). Every extraction ends with '|| true': under
113
- # 'set -e' a non-matching grep would otherwise abort the script and emit no
114
- # decision.
115
- TOOL_NAME=$(echo "$INPUT" | grep -o '"tool_name":"[^"]*"' | head -1 | cut -d'"' -f4 || true)
116
-
117
152
  STATE_FILE="${stateFilePath}"
118
153
  LEDGER_FILE="${ledgerFilePath}"
119
154
 
155
+ # --- Canonical identity: tool_name / category / identity token / MCP token ---
156
+ # Computed by the same Node.js binary that runs the cursor-runner (absolute path
157
+ # baked at generation time) so JSON string values — file paths and especially
158
+ # shell commands containing quotes, newlines, or unicode escapes — decode to the
159
+ # exact bytes the runner sees in the stream event. ELECTRON_RUN_AS_NODE makes
160
+ # the invocation safe when the runner is embedded in an Electron app (where
161
+ # process.execPath is the Electron binary).
162
+ NODE_BIN="${process.execPath}"
163
+ IDENTITY=$(printf '%s' "$INPUT" | ELECTRON_RUN_AS_NODE=1 "$NODE_BIN" -e '${nodeIdentityScript}' 2>/dev/null || true)
164
+ if [ -n "$IDENTITY" ]; then
165
+ TOOL_NAME=$(printf '%s\\n' "$IDENTITY" | sed -n 1p)
166
+ CATEGORY=$(printf '%s\\n' "$IDENTITY" | sed -n 2p)
167
+ TOKEN=$(printf '%s\\n' "$IDENTITY" | sed -n 3p)
168
+ MCP_TOKEN=$(printf '%s\\n' "$IDENTITY" | sed -n 4p)
169
+ else
170
+ # Fallback when the Node binary cannot run: grep/cut extraction. Best-effort
171
+ # only — '"field":"[^"]*"' truncates at the first JSON-escaped quote, so the
172
+ # token may not match the runner's for values containing escapes. Gating still
173
+ # holds (deny goes out); only denial correlation and grant precision degrade.
174
+ # Every extraction ends with '|| true': under 'set -e' a non-matching grep
175
+ # would otherwise abort the script and emit no decision.
176
+ TOOL_NAME=$(echo "$INPUT" | grep -o '"tool_name":"[^"]*"' | head -1 | cut -d'"' -f4 || true)
177
+ SALIENT=""
178
+ for field in ${salientFields}; do
179
+ v=$(echo "$INPUT" | grep -o "\\"$field\\":\\"[^\\"]*\\"" | head -1 | cut -d'"' -f4 || true)
180
+ if [ -n "$v" ]; then SALIENT="$v"; break; fi
181
+ done
182
+ CATEGORY=""
183
+ case "$TOOL_NAME" in
184
+ ${categoryCaseArms}
185
+ *) CATEGORY="" ;;
186
+ esac
187
+ TOKEN=$(printf '%s\\n%s' "$CATEGORY" "$SALIENT" | base64 | tr -d '\\n')
188
+ MCP_TOKEN=$(printf '%s\\n' "$TOOL_NAME" | base64 | tr -d '\\n')
189
+ fi
190
+
120
191
  # --- Failsafe: missing state file → deny (fail-closed) ---
121
192
  if [ ! -f "$STATE_FILE" ]; then
122
193
  echo '{"permission":"deny","agent_message":"${APPROVAL_REQUIRED_AGENT_MESSAGE}","user_message":"Tool requires approval: '"$TOOL_NAME"'"}'
@@ -131,22 +202,6 @@ if echo "$STATE" | grep -q '"autoApproveAll":true'; then
131
202
  exit 0
132
203
  fi
133
204
 
134
- # --- Salient resource value (file path / command), spanning both taxonomies'
135
- # arg field names (file_path here, path on the stream side). First match wins. ---
136
- SALIENT=""
137
- for field in ${salientFields}; do
138
- v=$(echo "$INPUT" | grep -o "\\"$field\\":\\"[^\\"]*\\"" | head -1 | cut -d'"' -f4 || true)
139
- if [ -n "$v" ]; then SALIENT="$v"; break; fi
140
- done
141
-
142
- # --- Canonical approval category for this hook tool_name (baked from
143
- # approval-policy.ts). Empty for non-gated tools. ---
144
- CATEGORY=""
145
- case "$TOOL_NAME" in
146
- ${categoryCaseArms}
147
- *) CATEGORY="" ;;
148
- esac
149
-
150
205
  # Append a denial record to the ledger. Best-effort: a ledger write failure must
151
206
  # never abort the decision (the deny still goes out on stdout). toolName is raw
152
207
  # for human-readable debugging; token drives correlation in the runner.
@@ -156,8 +211,6 @@ record_denial() {
156
211
 
157
212
  # --- 2. Gated built-in tools (category non-empty) ---
158
213
  if [ -n "$CATEGORY" ]; then
159
- # Canonical identity token: base64("$CATEGORY\\n$SALIENT").
160
- TOKEN=$(printf '%s\\n%s' "$CATEGORY" "$SALIENT" | base64 | tr -d '\\n')
161
214
  # Reinvocation grant: this exact resource was approved earlier → allow.
162
215
  if echo "$STATE" | grep -qF "\\"$TOKEN\\""; then
163
216
  echo '{"permission":"allow"}'
@@ -176,7 +229,6 @@ fi
176
229
  if echo "$STATE" | grep -q "\\"mcpToolPolicies\\"" && [ -n "$TOOL_NAME" ]; then
177
230
  TOOL_POLICY=$(echo "$STATE" | grep -o "\\"$TOOL_NAME\\":{[^}]*}" | head -1 || true)
178
231
  if [ -n "$TOOL_POLICY" ] && ! echo "$TOOL_POLICY" | grep -q '"requiresApproval":false'; then
179
- MCP_TOKEN=$(printf '%s\\n' "$TOOL_NAME" | base64 | tr -d '\\n')
180
232
  if echo "$STATE" | grep -qF "\\"$MCP_TOKEN\\""; then
181
233
  echo '{"permission":"allow"}'
182
234
  exit 0
@@ -93,6 +93,15 @@ export interface ResumeAgentOptions {
93
93
  apiKey: string;
94
94
  agentId: string;
95
95
  sessionId: string;
96
+ /**
97
+ * Workspace directories — same as {@link CreateAgentOptions.workspaceDirs}.
98
+ * NOT persisted across Agent.resume(): without an explicit cwd the SDK falls
99
+ * back to process.cwd(), which both mis-roots the resumed agent and loads
100
+ * the "project" setting source (and therefore the HITL approval hook in
101
+ * .cursor/hooks.json) from the wrong directory — silently disabling the
102
+ * approval gate on every resumed turn.
103
+ */
104
+ workspaceDirs: string[];
96
105
  /** Durable workspace volume root; the SDK state store lives under it. */
97
106
  workspaceRootDir: string;
98
107
  model?: string;
@@ -244,6 +253,10 @@ export async function createAgent(options: CreateAgentOptions): Promise<SDKAgent
244
253
  * propagate or fall back to a fresh agent with continuation context.
245
254
  */
246
255
  export async function resumeAgent(options: ResumeAgentOptions): Promise<SDKAgent> {
256
+ const cwd = options.workspaceDirs.length === 1
257
+ ? options.workspaceDirs[0]
258
+ : options.workspaceDirs;
259
+
247
260
  const platform = resolvePlatformOptions(options.sessionId, options.workspaceRootDir);
248
261
  console.log(
249
262
  `resumeAgent: agentId=${options.agentId}, sessionId=${options.sessionId}, ` +
@@ -254,9 +267,13 @@ export async function resumeAgent(options: ResumeAgentOptions): Promise<SDKAgent
254
267
  return Agent.resume(options.agentId, {
255
268
  apiKey: options.apiKey,
256
269
  model: options.model ? { id: options.model } : undefined,
257
- // settingSources are not persisted across resume, so the "project" source
258
- // (which loads the HITL approval hook) must be re-supplied every turn.
259
- local: { settingSources: [...LOCAL_SETTING_SOURCES] },
270
+ // Neither cwd nor settingSources survive Agent.resume(); both must be
271
+ // re-supplied every turn. Omitting cwd makes the SDK fall back to
272
+ // process.cwd(), which re-roots the agent in the runner's own working
273
+ // directory and loads the "project" setting source — the .cursor/hooks.json
274
+ // carrying the HITL approval hook — from that wrong directory, silently
275
+ // disabling the approval gate on every resumed turn.
276
+ local: { cwd, settingSources: [...LOCAL_SETTING_SOURCES] },
260
277
  mcpServers: options.mcpServers as Record<string, any>,
261
278
  agents: options.agents,
262
279
  platform,
@@ -355,6 +372,7 @@ export async function resolveAgent(
355
372
  apiKey: options.apiKey,
356
373
  agentId: harnessStateId,
357
374
  sessionId: (options as CreateAgentOptions).sessionId,
375
+ workspaceDirs: (options as CreateAgentOptions).workspaceDirs,
358
376
  workspaceRootDir: (options as CreateAgentOptions).workspaceRootDir,
359
377
  model: options.model,
360
378
  mcpServers: options.mcpServers,