@stigmer/runner 3.9.0 → 3.11.0

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 (270) hide show
  1. package/README.md +12 -1
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/activities/call-llm.js +9 -10
  4. package/dist/activities/call-llm.js.map +1 -1
  5. package/dist/activities/classify-tool-approvals.d.ts +2 -1
  6. package/dist/activities/classify-tool-approvals.js +28 -2
  7. package/dist/activities/classify-tool-approvals.js.map +1 -1
  8. package/dist/activities/discover-mcp-server.d.ts +32 -0
  9. package/dist/activities/discover-mcp-server.js +162 -27
  10. package/dist/activities/discover-mcp-server.js.map +1 -1
  11. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +8 -0
  12. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +1 -1
  13. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
  14. package/dist/activities/execute-cursor/approval-state.d.ts +28 -2
  15. package/dist/activities/execute-cursor/approval-state.js +7 -1
  16. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  17. package/dist/activities/execute-cursor/attachment-resolver.d.ts +14 -0
  18. package/dist/activities/execute-cursor/attachment-resolver.js +25 -4
  19. package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
  20. package/dist/activities/execute-cursor/blueprint-resolver.d.ts +1 -9
  21. package/dist/activities/execute-cursor/blueprint-resolver.js +6 -22
  22. package/dist/activities/execute-cursor/blueprint-resolver.js.map +1 -1
  23. package/dist/activities/execute-cursor/env-resolver.js +3 -1
  24. package/dist/activities/execute-cursor/env-resolver.js.map +1 -1
  25. package/dist/activities/execute-cursor/error-classifier.d.ts +40 -3
  26. package/dist/activities/execute-cursor/error-classifier.js +81 -3
  27. package/dist/activities/execute-cursor/error-classifier.js.map +1 -1
  28. package/dist/activities/execute-cursor/extract-structured-output.d.ts +29 -0
  29. package/dist/activities/execute-cursor/extract-structured-output.js +58 -0
  30. package/dist/activities/execute-cursor/extract-structured-output.js.map +1 -0
  31. package/dist/activities/execute-cursor/hook-script.d.ts +14 -3
  32. package/dist/activities/execute-cursor/hook-script.js +72 -10
  33. package/dist/activities/execute-cursor/hook-script.js.map +1 -1
  34. package/dist/activities/execute-cursor/index.d.ts +5 -1
  35. package/dist/activities/execute-cursor/index.js +59 -58
  36. package/dist/activities/execute-cursor/index.js.map +1 -1
  37. package/dist/activities/execute-cursor/mcp-resolver.d.ts +24 -1
  38. package/dist/activities/execute-cursor/mcp-resolver.js +5 -2
  39. package/dist/activities/execute-cursor/mcp-resolver.js.map +1 -1
  40. package/dist/activities/execute-cursor/prompt-builder.d.ts +18 -4
  41. package/dist/activities/execute-cursor/prompt-builder.js +12 -7
  42. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  43. package/dist/activities/execute-cursor/turn-stream.js +4 -1
  44. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  45. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +18 -1
  46. package/dist/activities/execute-deep-agent/attachment-injector.js +68 -23
  47. package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
  48. package/dist/activities/execute-deep-agent/environment.js +3 -1
  49. package/dist/activities/execute-deep-agent/environment.js.map +1 -1
  50. package/dist/activities/execute-deep-agent/index.js +15 -0
  51. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  52. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +7 -7
  53. package/dist/activities/execute-deep-agent/prompt-builder.js +8 -2
  54. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  55. package/dist/activities/execute-deep-agent/setup.d.ts +10 -0
  56. package/dist/activities/execute-deep-agent/setup.js +65 -26
  57. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  58. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +18 -1
  59. package/dist/activities/execute-deep-agent/subagent-transformer.js +8 -1
  60. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  61. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +11 -4
  62. package/dist/activities/execute-deep-agent/subagent-wiring.js +13 -4
  63. package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
  64. package/dist/activities/hydrate-workflow-execution.js +3 -1
  65. package/dist/activities/hydrate-workflow-execution.js.map +1 -1
  66. package/dist/activities/workflow-event-activities.d.ts +28 -10
  67. package/dist/activities/workflow-event-activities.js +87 -58
  68. package/dist/activities/workflow-event-activities.js.map +1 -1
  69. package/dist/claimcheck/payload-codec.js +21 -1
  70. package/dist/claimcheck/payload-codec.js.map +1 -1
  71. package/dist/client/stigmer-client.d.ts +9 -4
  72. package/dist/client/stigmer-client.js +28 -15
  73. package/dist/client/stigmer-client.js.map +1 -1
  74. package/dist/encryption/config.d.ts +32 -0
  75. package/dist/encryption/config.js +68 -0
  76. package/dist/encryption/config.js.map +1 -0
  77. package/dist/encryption/index.d.ts +3 -0
  78. package/dist/encryption/index.js +3 -0
  79. package/dist/encryption/index.js.map +1 -0
  80. package/dist/encryption/payload-codec.d.ts +41 -0
  81. package/dist/encryption/payload-codec.js +130 -0
  82. package/dist/encryption/payload-codec.js.map +1 -0
  83. package/dist/payload-codecs.d.ts +16 -0
  84. package/dist/payload-codecs.js +38 -0
  85. package/dist/payload-codecs.js.map +1 -0
  86. package/dist/preflight.d.ts +31 -0
  87. package/dist/preflight.js +43 -0
  88. package/dist/preflight.js.map +1 -1
  89. package/dist/runner-manager.js +5 -15
  90. package/dist/runner-manager.js.map +1 -1
  91. package/dist/runner.js +5 -16
  92. package/dist/runner.js.map +1 -1
  93. package/dist/shared/approval-policy.d.ts +9 -3
  94. package/dist/shared/approval-policy.js +15 -6
  95. package/dist/shared/approval-policy.js.map +1 -1
  96. package/dist/shared/attachment-naming.d.ts +53 -0
  97. package/dist/shared/attachment-naming.js +59 -0
  98. package/dist/shared/attachment-naming.js.map +1 -0
  99. package/dist/shared/attachment-vision.d.ts +43 -2
  100. package/dist/shared/attachment-vision.js +72 -6
  101. package/dist/shared/attachment-vision.js.map +1 -1
  102. package/dist/shared/caller-identity.d.ts +23 -2
  103. package/dist/shared/caller-identity.js +36 -5
  104. package/dist/shared/caller-identity.js.map +1 -1
  105. package/dist/shared/channel-attachment.js +1 -0
  106. package/dist/shared/channel-attachment.js.map +1 -1
  107. package/dist/shared/checkpointer/http-saver.d.ts +42 -1
  108. package/dist/shared/checkpointer/http-saver.js +96 -8
  109. package/dist/shared/checkpointer/http-saver.js.map +1 -1
  110. package/dist/shared/conversation-attachment.js +1 -0
  111. package/dist/shared/conversation-attachment.js.map +1 -1
  112. package/dist/shared/datastore-attachment.d.ts +50 -7
  113. package/dist/shared/datastore-attachment.js +93 -11
  114. package/dist/shared/datastore-attachment.js.map +1 -1
  115. package/dist/shared/http-retry.d.ts +43 -0
  116. package/dist/shared/http-retry.js +50 -0
  117. package/dist/shared/http-retry.js.map +1 -0
  118. package/dist/shared/llm-backend.d.ts +275 -0
  119. package/dist/shared/llm-backend.js +425 -0
  120. package/dist/shared/llm-backend.js.map +1 -0
  121. package/dist/shared/llm-proxy.d.ts +8 -0
  122. package/dist/shared/llm-proxy.js +15 -0
  123. package/dist/shared/llm-proxy.js.map +1 -1
  124. package/dist/shared/mcp-enabled-tools.d.ts +57 -0
  125. package/dist/shared/mcp-enabled-tools.js +86 -0
  126. package/dist/shared/mcp-enabled-tools.js.map +1 -0
  127. package/dist/shared/mcp-manager.d.ts +17 -2
  128. package/dist/shared/mcp-manager.js +37 -25
  129. package/dist/shared/mcp-manager.js.map +1 -1
  130. package/dist/shared/mcp-resolver.d.ts +39 -2
  131. package/dist/shared/mcp-resolver.js +38 -2
  132. package/dist/shared/mcp-resolver.js.map +1 -1
  133. package/dist/shared/model-client.d.ts +12 -5
  134. package/dist/shared/model-client.js +138 -18
  135. package/dist/shared/model-client.js.map +1 -1
  136. package/dist/shared/model-error.js +198 -5
  137. package/dist/shared/model-error.js.map +1 -1
  138. package/dist/shared/model-registry.d.ts +20 -2
  139. package/dist/shared/model-registry.js +37 -2
  140. package/dist/shared/model-registry.js.map +1 -1
  141. package/dist/shared/plan-mode-permissions.d.ts +26 -0
  142. package/dist/shared/plan-mode-permissions.js +28 -0
  143. package/dist/shared/plan-mode-permissions.js.map +1 -0
  144. package/dist/worker.d.ts +2 -1
  145. package/dist/worker.js +2 -4
  146. package/dist/worker.js.map +1 -1
  147. package/dist/workflow-engine/types.d.ts +18 -0
  148. package/dist/workflow-engine/types.js.map +1 -1
  149. package/dist/workflows/call-agent-orchestrator.d.ts +9 -0
  150. package/dist/workflows/call-agent-orchestrator.js +1 -0
  151. package/dist/workflows/call-agent-orchestrator.js.map +1 -1
  152. package/dist/workflows/connect-mcp-server.js +7 -0
  153. package/dist/workflows/connect-mcp-server.js.map +1 -1
  154. package/dist/workflows/engine-core.js +23 -2
  155. package/dist/workflows/engine-core.js.map +1 -1
  156. package/dist/workflows/execute-from-execution.d.ts +1 -1
  157. package/dist/workflows/execute-from-execution.js +11 -1
  158. package/dist/workflows/execute-from-execution.js.map +1 -1
  159. package/package.json +8 -2
  160. package/src/__tests__/claimcheck-codec.test.ts +36 -0
  161. package/src/__tests__/encryption-codec.test.ts +234 -0
  162. package/src/__tests__/fixtures/encrypted-payload-fixture.json +15 -0
  163. package/src/__tests__/history-encryption-e2e.test.ts +243 -0
  164. package/src/__tests__/preflight.test.ts +50 -2
  165. package/src/activities/__tests__/call-llm.test.ts +75 -0
  166. package/src/activities/__tests__/classify-tool-approvals.test.ts +117 -1
  167. package/src/activities/__tests__/discover-mcp-server.hang.test.ts +103 -0
  168. package/src/activities/__tests__/discover-mcp-server.test.ts +203 -0
  169. package/src/activities/__tests__/workflow-event-activities.test.ts +107 -8
  170. package/src/activities/call-llm.ts +9 -16
  171. package/src/activities/classify-tool-approvals.ts +34 -4
  172. package/src/activities/discover-mcp-server.ts +190 -32
  173. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +9 -0
  174. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +14 -0
  175. package/src/activities/execute-cursor/__tests__/attachment-resolver.test.ts +92 -0
  176. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +40 -14
  177. package/src/activities/execute-cursor/__tests__/error-classifier-extraction.test.ts +208 -0
  178. package/src/activities/execute-cursor/__tests__/extract-structured-output.test.ts +120 -0
  179. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +93 -0
  180. package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +125 -0
  181. package/src/activities/execute-cursor/__tests__/prompt-builder-delegation.test.ts +1 -1
  182. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +13 -0
  183. package/src/activities/execute-cursor/approval-state.ts +30 -1
  184. package/src/activities/execute-cursor/attachment-resolver.ts +38 -3
  185. package/src/activities/execute-cursor/blueprint-resolver.ts +7 -27
  186. package/src/activities/execute-cursor/env-resolver.ts +3 -1
  187. package/src/activities/execute-cursor/error-classifier.ts +91 -4
  188. package/src/activities/execute-cursor/extract-structured-output.ts +72 -0
  189. package/src/activities/execute-cursor/hook-script.ts +74 -10
  190. package/src/activities/execute-cursor/index.ts +63 -72
  191. package/src/activities/execute-cursor/mcp-resolver.ts +36 -2
  192. package/src/activities/execute-cursor/prompt-builder.ts +34 -9
  193. package/src/activities/execute-cursor/turn-stream.ts +5 -2
  194. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +132 -8
  195. package/src/activities/execute-deep-agent/__tests__/datastore-degradation.test.ts +104 -0
  196. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +2 -0
  197. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
  198. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
  199. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +34 -5
  200. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
  201. package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +173 -0
  202. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +12 -7
  203. package/src/activities/execute-deep-agent/attachment-injector.ts +94 -30
  204. package/src/activities/execute-deep-agent/environment.ts +3 -1
  205. package/src/activities/execute-deep-agent/index.ts +20 -0
  206. package/src/activities/execute-deep-agent/prompt-builder.ts +20 -10
  207. package/src/activities/execute-deep-agent/setup.ts +86 -31
  208. package/src/activities/execute-deep-agent/subagent-transformer.ts +23 -1
  209. package/src/activities/execute-deep-agent/subagent-wiring.ts +14 -4
  210. package/src/activities/hydrate-workflow-execution.ts +3 -1
  211. package/src/activities/workflow-event-activities.ts +96 -69
  212. package/src/claimcheck/payload-codec.ts +33 -1
  213. package/src/client/__tests__/stigmer-client.test.ts +8 -8
  214. package/src/client/stigmer-client.ts +32 -18
  215. package/src/encryption/config.ts +91 -0
  216. package/src/encryption/index.ts +3 -0
  217. package/src/encryption/payload-codec.ts +152 -0
  218. package/src/payload-codecs.ts +56 -0
  219. package/src/preflight.ts +45 -0
  220. package/src/runner-manager.ts +6 -24
  221. package/src/runner.ts +6 -25
  222. package/src/shared/__tests__/approval-policy.test.ts +82 -39
  223. package/src/shared/__tests__/attachment-naming.test.ts +159 -0
  224. package/src/shared/__tests__/attachment-vision.test.ts +97 -0
  225. package/src/shared/__tests__/bedrock-adapter.test.ts +213 -0
  226. package/src/shared/__tests__/bedrock-seam.test.ts +390 -0
  227. package/src/shared/__tests__/caller-identity.test.ts +25 -0
  228. package/src/shared/__tests__/channel-attachment.test.ts +1 -1
  229. package/src/shared/__tests__/connect-backfill.test.ts +1 -0
  230. package/src/shared/__tests__/conversation-attachment.test.ts +1 -1
  231. package/src/shared/__tests__/datastore-attachment.test.ts +129 -1
  232. package/src/shared/__tests__/foundry-adapter.test.ts +276 -0
  233. package/src/shared/__tests__/foundry-seam.test.ts +482 -0
  234. package/src/shared/__tests__/http-retry.test.ts +67 -0
  235. package/src/shared/__tests__/llm-backend.test.ts +616 -0
  236. package/src/shared/__tests__/mcp-enabled-tools.test.ts +86 -0
  237. package/src/shared/__tests__/mcp-manager.test.ts +170 -2
  238. package/src/shared/__tests__/mcp-resolver.test.ts +146 -3
  239. package/src/shared/__tests__/model-client.test.ts +154 -0
  240. package/src/shared/__tests__/model-error.test.ts +289 -1
  241. package/src/shared/__tests__/model-registry.test.ts +71 -0
  242. package/src/shared/__tests__/synthesized-attachment.test.ts +1 -0
  243. package/src/shared/__tests__/vertex-adapter.test.ts +169 -0
  244. package/src/shared/__tests__/vertex-seam.test.ts +295 -0
  245. package/src/shared/approval-policy.ts +14 -7
  246. package/src/shared/attachment-naming.ts +78 -0
  247. package/src/shared/attachment-vision.ts +92 -9
  248. package/src/shared/caller-identity.ts +40 -5
  249. package/src/shared/channel-attachment.ts +1 -0
  250. package/src/shared/checkpointer/__tests__/http-saver.test.ts +196 -1
  251. package/src/shared/checkpointer/http-saver.ts +117 -9
  252. package/src/shared/conversation-attachment.ts +1 -0
  253. package/src/shared/datastore-attachment.ts +106 -11
  254. package/src/shared/http-retry.ts +50 -0
  255. package/src/shared/llm-backend.ts +544 -0
  256. package/src/shared/llm-proxy.ts +15 -0
  257. package/src/shared/mcp-enabled-tools.ts +105 -0
  258. package/src/shared/mcp-manager.ts +43 -26
  259. package/src/shared/mcp-resolver.ts +73 -2
  260. package/src/shared/model-client.ts +161 -19
  261. package/src/shared/model-error.ts +222 -4
  262. package/src/shared/model-registry.ts +50 -2
  263. package/src/shared/plan-mode-permissions.ts +30 -0
  264. package/src/worker.ts +4 -5
  265. package/src/workflow-engine/types.ts +18 -0
  266. package/src/workflows/__tests__/execute-serverless-workflow.test.ts +68 -2
  267. package/src/workflows/call-agent-orchestrator.ts +10 -0
  268. package/src/workflows/connect-mcp-server.ts +7 -0
  269. package/src/workflows/engine-core.ts +23 -2
  270. package/src/workflows/execute-from-execution.ts +12 -2
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Tier-2 structured-output extraction for the Cursor harness.
3
+ *
4
+ * When tier-1 text extraction (shared/extract-json.ts) cannot find JSON in
5
+ * the agent's free-text response, this tier asks an economy-tier LLM to
6
+ * extract it via withStructuredOutput (function-calling), which guarantees
7
+ * schema-conformant output through the API's tool-use mechanism.
8
+ *
9
+ * Lives in its own module (rather than inside execute-cursor/index.ts) so
10
+ * the LangChain construction path stays out of the Cursor activity's module
11
+ * graph until a run actually needs tier 2 — index.ts imports this module
12
+ * lazily at the call site, mirroring its tier-1 import, which is what
13
+ * bundle-slim's deferred evaluation preserves.
14
+ */
15
+ import type { Config } from "../../config.js";
16
+ /**
17
+ * Extract structured data from an agent's free-text response using an
18
+ * economy-tier LLM with withStructuredOutput (function-calling).
19
+ *
20
+ * Construction (registry-id resolution, provider inference, proxy wiring) is
21
+ * delegated to the shared buildChatModel so the economy model's registry id
22
+ * is always resolved to a provider API id before the call.
23
+ *
24
+ * Throws when no LLM is reachable (no proxy and no credential path for the
25
+ * extraction model's provider) — the caller treats any throw here as "tier 2
26
+ * unavailable", logs it, and returns the agent's text without structured
27
+ * output, so the failure mode is a diagnosable log line, never a lost run.
28
+ */
29
+ export declare function extractStructuredOutput(agentResponse: string, schema: Record<string, unknown>, config: Config, primaryModel: string): Promise<unknown | null>;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Tier-2 structured-output extraction for the Cursor harness.
3
+ *
4
+ * When tier-1 text extraction (shared/extract-json.ts) cannot find JSON in
5
+ * the agent's free-text response, this tier asks an economy-tier LLM to
6
+ * extract it via withStructuredOutput (function-calling), which guarantees
7
+ * schema-conformant output through the API's tool-use mechanism.
8
+ *
9
+ * Lives in its own module (rather than inside execute-cursor/index.ts) so
10
+ * the LangChain construction path stays out of the Cursor activity's module
11
+ * graph until a run actually needs tier 2 — index.ts imports this module
12
+ * lazily at the call site, mirroring its tier-1 import, which is what
13
+ * bundle-slim's deferred evaluation preserves.
14
+ */
15
+ import { getEconomyModel } from "../../shared/model-registry.js";
16
+ import { buildChatModel } from "../../shared/model-client.js";
17
+ import { checkDirectCredentials } from "../../shared/llm-backend.js";
18
+ import { tryInferProvider } from "../../shared/llm-proxy.js";
19
+ import { jsonSchemaToZod } from "../../shared/json-schema-to-zod.js";
20
+ /**
21
+ * Extract structured data from an agent's free-text response using an
22
+ * economy-tier LLM with withStructuredOutput (function-calling).
23
+ *
24
+ * Construction (registry-id resolution, provider inference, proxy wiring) is
25
+ * delegated to the shared buildChatModel so the economy model's registry id
26
+ * is always resolved to a provider API id before the call.
27
+ *
28
+ * Throws when no LLM is reachable (no proxy and no credential path for the
29
+ * extraction model's provider) — the caller treats any throw here as "tier 2
30
+ * unavailable", logs it, and returns the agent's text without structured
31
+ * output, so the failure mode is a diagnosable log line, never a lost run.
32
+ */
33
+ export async function extractStructuredOutput(agentResponse, schema, config, primaryModel) {
34
+ const extractionModel = await getEconomyModel(primaryModel);
35
+ const proxyEndpoint = config.proxyEndpoint ?? undefined;
36
+ if (!proxyEndpoint) {
37
+ const provider = tryInferProvider(extractionModel);
38
+ const missing = provider === null ? null : checkDirectCredentials(provider);
39
+ if (missing !== null) {
40
+ throw new Error(`Structured-output extraction needs the ${provider} model ` +
41
+ `'${extractionModel}' but has no credential path. ${missing}`);
42
+ }
43
+ }
44
+ const { model: llm } = await buildChatModel({
45
+ modelName: extractionModel,
46
+ proxyEndpoint,
47
+ stigmerToken: config.stigmerToken ?? undefined,
48
+ maxTokens: 4096,
49
+ });
50
+ const zodSchema = jsonSchemaToZod(schema);
51
+ const structured = llm.withStructuredOutput(zodSchema);
52
+ const result = await structured.invoke([
53
+ { role: "system", content: "Extract the structured data from the agent's response. Return only the data that matches the schema." },
54
+ { role: "user", content: agentResponse },
55
+ ]);
56
+ return result ?? null;
57
+ }
58
+ //# sourceMappingURL=extract-structured-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-structured-output.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/extract-structured-output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAErE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,aAAqB,EACrB,MAA+B,EAC/B,MAAc,EACd,YAAoB;IAEpB,MAAM,eAAe,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;IAExD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,eAAe,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAC5E,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,0CAA0C,QAAQ,SAAS;gBAC3D,IAAI,eAAe,iCAAiC,OAAO,EAAE,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,MAAM,cAAc,CAAC;QAC1C,SAAS,EAAE,eAAe;QAC1B,aAAa;QACb,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,SAAS;QAC9C,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,GAAG,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAEvD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC;QACrC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,sGAAsG,EAAE;QACnI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE;KACzC,CAAC,CAAC;IAEH,OAAO,MAAM,IAAI,IAAI,CAAC;AACxB,CAAC"}
@@ -32,6 +32,8 @@
32
32
  * - "secret" — DD-26 secret hard-block: the agent continues, no pause.
33
33
  * - "capture-error" — CAS staging failed, write kept on the deny-gate.
34
34
  * - "fail-closed" — approval state file missing, everything gated denies.
35
+ * - "disabled" — enabled_tools manifest exclusion (issue #350): the
36
+ * agent continues, no pause, permanent for the run.
35
37
  * Only approval-kind records carry the captured tool_input: a secret write's
36
38
  * content must never be persisted (DD-26), a capture-error's content is
37
39
  * UNCLASSIFIED (the staging error means secret classification may never have
@@ -84,8 +86,16 @@
84
86
  * set, allow the rest" — matching the native harness and avoiding denial of
85
87
  * auto-approved MCP tools (which are absent from mcpToolPolicies):
86
88
  * 0. Scope guard: not the runner's own agent → allow (never touch the ledger)
87
- * 1. Missing state file → deny (fail-closed); autoApproveAll (the pre-armed
88
- * spec.auto_approve_all global bypass)allow
89
+ * 1. Missing state file → deny (fail-closed)
90
+ * 1a. beforeMCPExecution eventtool excluded by the server's
91
+ * mcpServerEnabledTools allow-list → record kind "disabled", deny.
92
+ * Deliberately BEFORE autoApproveAll and the grant checks: enabled_tools
93
+ * is a capability manifest, not an approval gate (issue #350) — no bypass
94
+ * may resurrect a disabled tool, and no human may be offered "approve" on
95
+ * one. Server-scoped via the payload's mcp_server_name; an absent slug in
96
+ * the map means unrestricted.
97
+ * 1b. autoApproveAll (the pre-armed spec.auto_approve_all global bypass) →
98
+ * allow
89
99
  * 2. beforeMCPExecution event → MCP tool present in mcpToolPolicies
90
100
  * (require-approval):
91
101
  * a. name token in approvedGrantTokens → allow (reinvocation grant)
@@ -117,7 +127,8 @@
117
127
  *
118
128
  * From the pointer the script reads the current turn's approval-state file (the
119
129
  * single source of truth for the dynamic inputs: autoApproveAll, leasedCategories,
120
- * mcpToolPolicies, approvedGrantTokens), denial ledger, and runner PID. The
130
+ * mcpToolPolicies, mcpServerEnabledTools, approvedGrantTokens), denial ledger,
131
+ * and runner PID. The
121
132
  * static policy (which built-ins are gated, their categories, the salient arg
122
133
  * fields) is baked at generation time from approval-policy.ts.
123
134
  *
@@ -32,6 +32,8 @@
32
32
  * - "secret" — DD-26 secret hard-block: the agent continues, no pause.
33
33
  * - "capture-error" — CAS staging failed, write kept on the deny-gate.
34
34
  * - "fail-closed" — approval state file missing, everything gated denies.
35
+ * - "disabled" — enabled_tools manifest exclusion (issue #350): the
36
+ * agent continues, no pause, permanent for the run.
35
37
  * Only approval-kind records carry the captured tool_input: a secret write's
36
38
  * content must never be persisted (DD-26), a capture-error's content is
37
39
  * UNCLASSIFIED (the staging error means secret classification may never have
@@ -84,8 +86,16 @@
84
86
  * set, allow the rest" — matching the native harness and avoiding denial of
85
87
  * auto-approved MCP tools (which are absent from mcpToolPolicies):
86
88
  * 0. Scope guard: not the runner's own agent → allow (never touch the ledger)
87
- * 1. Missing state file → deny (fail-closed); autoApproveAll (the pre-armed
88
- * spec.auto_approve_all global bypass)allow
89
+ * 1. Missing state file → deny (fail-closed)
90
+ * 1a. beforeMCPExecution eventtool excluded by the server's
91
+ * mcpServerEnabledTools allow-list → record kind "disabled", deny.
92
+ * Deliberately BEFORE autoApproveAll and the grant checks: enabled_tools
93
+ * is a capability manifest, not an approval gate (issue #350) — no bypass
94
+ * may resurrect a disabled tool, and no human may be offered "approve" on
95
+ * one. Server-scoped via the payload's mcp_server_name; an absent slug in
96
+ * the map means unrestricted.
97
+ * 1b. autoApproveAll (the pre-armed spec.auto_approve_all global bypass) →
98
+ * allow
89
99
  * 2. beforeMCPExecution event → MCP tool present in mcpToolPolicies
90
100
  * (require-approval):
91
101
  * a. name token in approvedGrantTokens → allow (reinvocation grant)
@@ -143,6 +153,21 @@ const SECRET_BLOCKED_AGENT_MESSAGE = "This file was blocked for security because
143
153
  "misconfiguration, so never tell the user to change Cursor settings or enable " +
144
154
  "hooks. Do not retry this write or attempt a workaround; the write will not be " +
145
155
  "applied. Continue with the rest of the task.";
156
+ // Shown to the model when an MCP tool call is denied because the agent's
157
+ // enabled_tools manifest excludes the tool (issue #350). Like
158
+ // SECRET_BLOCKED_AGENT_MESSAGE this must NOT promise a resume — the exclusion
159
+ // is permanent for the run and mode-independent (it is a capability manifest,
160
+ // not an approval, so nothing can be granted). Same embedding constraint
161
+ // (single-quoted bash echo of a JSON object): no double quotes, apostrophes,
162
+ // or backslashes.
163
+ const DISABLED_TOOL_AGENT_MESSAGE = "This tool is not enabled for this agent: the MCP server exposes it, but the " +
164
+ "agent manifest (enabled_tools) excludes it. This is the platform capability " +
165
+ "manifest working as intended — it is not an error and not a Cursor " +
166
+ "misconfiguration, so never tell the user to change Cursor settings or enable " +
167
+ "hooks. Do not retry this tool or attempt a workaround; it will stay " +
168
+ "unavailable for this entire run. Use a different tool or adapt your plan, " +
169
+ "and if the task cannot proceed without it, tell the user plainly what was " +
170
+ "unavailable.";
146
171
  /**
147
172
  * Build the bash `case` arms that map an incoming hook `tool_name` to its
148
173
  * canonical approval category. Generated from approval-policy.ts so the hook and
@@ -195,14 +220,17 @@ function buildContentDigestScript() {
195
220
  * Build the inline Node.js identity extractor embedded in the hook script.
196
221
  *
197
222
  * Parses the hook's stdin JSON properly (the bash fallback's grep truncates
198
- * string values at the first escaped quote) and emits SEVEN lines: tool_name,
223
+ * string values at the first escaped quote) and emits NINE lines: tool_name,
199
224
  * canonical category, coarse identity token, MCP name-token, hook_event_name
200
225
  * (the event discriminator: `preToolUse` for built-ins, `beforeMCPExecution`
201
226
  * for MCP), base64(JSON(tool_input)) — the authoritative pre-execution args the
202
- * runner overlays onto the gated tool call for the approval preview — and the
227
+ * runner overlays onto the gated tool call for the approval preview — the
203
228
  * CONTENT token (base64(category \n salient \n contentDigest), empty when the
204
- * tool has no edit content). The token encodings must stay byte-identical to
205
- * grantToken()/contentToken() in approval-state.ts.
229
+ * tool has no edit content), base64(salient), and mcp_server_name (the MCP
230
+ * server slug the beforeMCPExecution payload carries; empty for built-ins) —
231
+ * the server scope for the enabled_tools manifest arm. The token encodings
232
+ * must stay byte-identical to grantToken()/contentToken() in
233
+ * approval-state.ts.
206
234
  *
207
235
  * Authored as a single-quoted bash string, so the JS must not contain single
208
236
  * quotes. The category map, salient field list, and edit/content field lists are
@@ -233,6 +261,7 @@ function buildNodeIdentityScript() {
233
261
  // is "" for a non-edit tool, in which case the content token (line 7) is "".
234
262
  buildContentDigestScript(),
235
263
  `const ev=typeof t.hook_event_name==="string"?t.hook_event_name:"";`,
264
+ `const srv=typeof t.mcp_server_name==="string"?t.mcp_server_name:"";`,
236
265
  // Line 6 is base64(JSON(tool_input)): the AUTHORITATIVE pre-execution args
237
266
  // the runner overlays onto the gated tool call so the approval card can show
238
267
  // the proposed change before the user approves. Base64 keeps the bash side
@@ -241,8 +270,10 @@ function buildNodeIdentityScript() {
241
270
  // grant the runner authorizes for a file edit. Line 8 is base64(salient) —
242
271
  // the raw resource value (file path / command) capture mode needs to run
243
272
  // `git check-ignore` on a file path; base64 keeps newlines/quotes out of the
244
- // line-oriented bash parse.
245
- `process.stdout.write(name+"\\n"+cat+"\\n"+b(cat+"\\n"+s)+"\\n"+b(name+"\\n")+"\\n"+ev+"\\n"+b(JSON.stringify(a))+"\\n"+(dig?b(cat+"\\n"+s+"\\n"+dig):"")+"\\n"+b(s));`,
273
+ // line-oriented bash parse. Line 9 is mcp_server_name — the server scope
274
+ // the enabled_tools manifest arm matches against mcpServerEnabledTools
275
+ // (a bare slug, never quoted/escaped, so it rides as a plain line).
276
+ `process.stdout.write(name+"\\n"+cat+"\\n"+b(cat+"\\n"+s)+"\\n"+b(name+"\\n")+"\\n"+ev+"\\n"+b(JSON.stringify(a))+"\\n"+(dig?b(cat+"\\n"+s+"\\n"+dig):"")+"\\n"+b(s)+"\\n"+srv);`,
246
277
  ].join("");
247
278
  }
248
279
  /**
@@ -264,7 +295,8 @@ function buildNodeIdentityScript() {
264
295
  *
265
296
  * From the pointer the script reads the current turn's approval-state file (the
266
297
  * single source of truth for the dynamic inputs: autoApproveAll, leasedCategories,
267
- * mcpToolPolicies, approvedGrantTokens), denial ledger, and runner PID. The
298
+ * mcpToolPolicies, mcpServerEnabledTools, approvedGrantTokens), denial ledger,
299
+ * and runner PID. The
268
300
  * static policy (which built-ins are gated, their categories, the salient arg
269
301
  * fields) is baked at generation time from approval-policy.ts.
270
302
  *
@@ -425,6 +457,9 @@ if [ -n "$IDENTITY" ]; then
425
457
  # Raw salient (base64) — the file path / command. Capture mode decodes it to
426
458
  # run git check-ignore on a file path.
427
459
  SALIENT=$(printf '%s\\n' "$IDENTITY" | sed -n 8p | base64 -d 2>/dev/null || true)
460
+ # MCP server slug (beforeMCPExecution payloads only; empty for built-ins) —
461
+ # the server scope for the enabled_tools manifest arm.
462
+ MCP_SERVER=$(printf '%s\\n' "$IDENTITY" | sed -n 9p)
428
463
  else
429
464
  # Fallback when the Node binary cannot run: grep/cut extraction. Best-effort
430
465
  # only — '"field":"[^"]*"' truncates at the first JSON-escaped quote, so the
@@ -434,6 +469,10 @@ else
434
469
  # would otherwise abort the script and emit no decision.
435
470
  TOOL_NAME=$(echo "$INPUT" | grep -o '"tool_name":"[^"]*"' | head -1 | cut -d'"' -f4 || true)
436
471
  HOOK_EVENT=$(echo "$INPUT" | grep -o '"hook_event_name":"[^"]*"' | head -1 | cut -d'"' -f4 || true)
472
+ # Server slugs are plain identifiers (no JSON-escaped quotes), so the grep
473
+ # fallback extracts mcp_server_name reliably — the manifest arm keeps its
474
+ # full precision even without the Node binary.
475
+ MCP_SERVER=$(echo "$INPUT" | grep -o '"mcp_server_name":"[^"]*"' | head -1 | cut -d'"' -f4 || true)
437
476
  SALIENT=""
438
477
  for field in ${salientFields}; do
439
478
  v=$(echo "$INPUT" | grep -o "\\"$field\\":\\"[^\\"]*\\"" | head -1 | cut -d'"' -f4 || true)
@@ -573,7 +612,30 @@ if [ "$CAPTURE_IGNORED" = "true" ] && [ "$CATEGORY" = "write" ] && [ -n "$SALIEN
573
612
  fi
574
613
  fi
575
614
 
576
- # --- 1. Auto-approve all ---
615
+ # --- 1a. MCP capability manifest: enabled_tools (issue #350) ---
616
+ # Runs BEFORE the auto-approve-all shortcut and every grant check because
617
+ # enabled_tools is a capability manifest, not an approval gate: no bypass may
618
+ # resurrect a disabled tool and no human may be offered approval on one.
619
+ # mcpServerEnabledTools holds ONLY restricted servers (an absent slug means
620
+ # unrestricted, so this arm is inert for the common case). Matching is
621
+ # server-scoped via the payload's mcp_server_name — equal tool names on
622
+ # different servers cannot cross-grant — and the quoted-name membership check
623
+ # is exact, never a substring match. Kind "disabled": attributable,
624
+ # non-pausing (the model adapts, same consumer semantics as "secret"), and
625
+ # permanent for the run.
626
+ if [ "$HOOK_EVENT" = "beforeMCPExecution" ] && [ -n "$MCP_SERVER" ] && [ -n "$TOOL_NAME" ]; then
627
+ ENABLED_MAP=$(echo "$STATE" | grep -o '"mcpServerEnabledTools":{[^}]*}' | head -1 || true)
628
+ if [ -n "$ENABLED_MAP" ]; then
629
+ SERVER_ENABLED=$(echo "$ENABLED_MAP" | grep -o "\\"$MCP_SERVER\\":\\[[^]]*\\]" | head -1 || true)
630
+ if [ -n "$SERVER_ENABLED" ] && ! echo "$SERVER_ENABLED" | grep -qF "\\"$TOOL_NAME\\""; then
631
+ record_denial "$MCP_TOKEN" "disabled"
632
+ echo '{"permission":"deny","agent_message":"${DISABLED_TOOL_AGENT_MESSAGE}","user_message":"Tool not enabled for this agent: '"$TOOL_NAME"'"}'
633
+ exit 0
634
+ fi
635
+ fi
636
+ fi
637
+
638
+ # --- 1b. Auto-approve all ---
577
639
  if echo "$STATE" | grep -q '"autoApproveAll":true'; then
578
640
  echo '{"permission":"allow"}'
579
641
  exit 0
@@ -1 +1 @@
1
- {"version":3,"file":"hook-script.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/hook-script.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hook-script.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/hook-script.ts"],"names":[],"mappings":"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"}
@@ -52,7 +52,11 @@ export interface BuildPromptInput {
52
52
  subAgents: import("@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb").SubAgent[];
53
53
  workspaceDirs: string[];
54
54
  workspaceFileRefs: string[];
55
- attachmentPaths: string[];
55
+ /**
56
+ * This turn's resolved attachments for the `<input_files>` section —
57
+ * final paths plus duplicate-rename disclosure (attachment-resolver.ts).
58
+ */
59
+ attachments: import("./prompt-builder.js").AttachmentPromptEntry[];
56
60
  /**
57
61
  * Vision facts for the input-files section (T04): which attachments the
58
62
  * model sees inline and which degraded to path-only. PER-TURN like the
@@ -48,6 +48,7 @@ import { withholdSecretContentFromMessages } from "../../shared/tool-row.js";
48
48
  import { StallTimeoutError, formatStallFailure } from "../../shared/stall-watchdog.js";
49
49
  import { resolveUsableArtifactStorage, loadArtifactStorageConfig } from "../../shared/artifact-storage.js";
50
50
  import { CURSOR_VISION_PROFILE, VisionBudget, toCursorImages, } from "../../shared/attachment-vision.js";
51
+ import { getModelVisionCapability } from "../../shared/model-registry.js";
51
52
  import { publishPlanArtifact } from "../../shared/plan-artifact.js";
52
53
  import { DeltaEnricher } from "./delta-enricher.js";
53
54
  import { TodoTracker } from "./todo-tracker.js";
@@ -61,6 +62,7 @@ import { readChannelConversationId, synthesizeConversationAttachment, } from "..
61
62
  import { injectSynthesizedAttachment } from "../../shared/synthesized-attachment.js";
62
63
  import { mergeApprovalPolicies } from "./approval-policy.js";
63
64
  import { deriveActiveLeases, isUnattendedApprovalMode } from "../../shared/approval-policy.js";
65
+ import { enabledToolsBySlug } from "../../shared/mcp-enabled-tools.js";
64
66
  import { backfillMcpServersIfNeeded } from "./connect-backfill.js";
65
67
  import { resolveExecutionEnv } from "./env-resolver.js";
66
68
  import { resolveBlueprint } from "./blueprint-resolver.js";
@@ -95,7 +97,7 @@ import { StreamingUsageSummarySchema } from "@stigmer/protos/ai/stigmer/agentic/
95
97
  import { activityStarted, activityFinished } from "../../idle-watchdog.js";
96
98
  import { normalizeActivityInput } from "../../shared/activity-input.js";
97
99
  import { getCapturedRejection, clearCapturedRejection } from "./rejection-capture.js";
98
- import { synthesizeError, formatClassifiedError, shouldRetryWithFreshAgent } from "./error-classifier.js";
100
+ import { synthesizeError, formatClassifiedError, shouldRetryWithFreshAgent, extractRunErrorSources } from "./error-classifier.js";
99
101
  import { createAgent, createCloudAgent } from "./session-lifecycle.js";
100
102
  import { setMaxListeners } from "node:events";
101
103
  import { startHeartbeat } from "../../shared/heartbeat.js";
@@ -535,8 +537,20 @@ turnSeq) {
535
537
  // the messaging reach; undefined lets a cloud sandbox runner's
536
538
  // ambient session-scoped token or OSS's no-auth apply). The
537
539
  // attachment header falls back to the ambient credential where no
538
- // exchange happens.
539
- const exchangedRunnerToken = await client.acquireScopedRunnerToken({ agentExecutionId: executionId });
540
+ // exchange happens. Unlike the env read (which hard-fails on a broken
541
+ // exchange secrets are load-bearing there), this exchange is
542
+ // opportunistic: every consumer below degrades to an empty answer by
543
+ // contract, and the server refuses the ambient fallback safely, so a
544
+ // failed exchange must not kill the run.
545
+ let exchangedRunnerToken;
546
+ try {
547
+ exchangedRunnerToken =
548
+ await client.acquireScopedRunnerToken({ agentExecutionId: executionId });
549
+ }
550
+ catch (err) {
551
+ console.warn("[execute-cursor] Scoped-token exchange failed for attachment/discovery " +
552
+ `reads; degrading to the ambient credential: ${err instanceof Error ? err.message : err}`);
553
+ }
540
554
  const attachmentCredential = exchangedRunnerToken
541
555
  ?? config.stigmerTokenRef?.current
542
556
  ?? config.stigmerToken;
@@ -611,9 +625,10 @@ turnSeq) {
611
625
  // them as auto-approved); the global bypass empties the map entirely.
612
626
  const leases = deriveActiveLeases(execution);
613
627
  const globalBypass = leases.global;
614
- const agentOverrides = blueprint.mergedMcpServerUsages
615
- .flatMap((u) => u.toolApprovalOverrides ?? []);
616
- const mergedPolicies = mergeApprovalPolicies(mcpResolution.resolvedServers, agentOverrides, leases);
628
+ // Layer-3 overrides ride each resolved server from its merged usage —
629
+ // see ResolvedMcpServer.toolApprovalOverrides (issue #349) — so there
630
+ // is no separate override input to pass here.
631
+ const mergedPolicies = mergeApprovalPolicies(mcpResolution.resolvedServers, leases);
617
632
  heartbeat();
618
633
  // Phase 4c: Validate MCP server env health (diagnostic, non-blocking)
619
634
  const mcpWarnings = validateMcpServerEnv(mcpResolution.resolvedServers, blueprint.mergedMcpServerUsages, envVars);
@@ -635,7 +650,13 @@ turnSeq) {
635
650
  // artifactStorage resolved for status offload above. The vision budget
636
651
  // rides along so image attachments are selected for inline delivery while
637
652
  // their bytes are already in hand (attachment-vision.ts owns all policy).
638
- const visionBudget = new VisionBudget(CURSOR_VISION_PROFILE);
653
+ // The budget also carries the requested model's registry vision
654
+ // capability, looked up from the raw executionConfig name — full model
655
+ // validation (Phase 6) isn't needed for this, and ""/"default" (the Auto
656
+ // pool) resolves to unknown, which the policy treats as sighted.
657
+ const visionBudget = new VisionBudget(CURSOR_VISION_PROFILE, {
658
+ modelVision: await getModelVisionCapability(spec.executionConfig?.modelName ?? ""),
659
+ });
639
660
  const attachmentResults = await resolveAttachments(spec.attachments, {
640
661
  sessionId,
641
662
  primaryWorkspaceDir,
@@ -643,7 +664,10 @@ turnSeq) {
643
664
  storage: artifactStorage,
644
665
  visionBudget,
645
666
  });
646
- const attachmentPaths = attachmentResults.map((a) => a.relativePath);
667
+ const attachmentEntries = attachmentResults.map((a) => ({
668
+ path: a.relativePath,
669
+ ...(a.renamedFrom !== undefined ? { renamedFrom: a.renamedFrom } : {}),
670
+ }));
647
671
  // Vision facts, derived once from the single resolution result: the
648
672
  // images the model will see inline (in attachment order) and the ones
649
673
  // that degraded to path-only, disclosed in the prompt.
@@ -744,7 +768,12 @@ turnSeq) {
744
768
  // approval denials with the non-pausing "unattended" kind, so the
745
769
  // first-denial stop never fires and the turn boundary settles the denied
746
770
  // calls as SKIPPED instead of pausing a turn nobody can approve.
747
- const approvalState = buildApprovalState(mergedPolicies, globalBypass, leases.categories, approvalGrants, captureMode, captureIgnored, gitWorkspace, isUnattendedApprovalMode(execution));
771
+ const approvalState = buildApprovalState(mergedPolicies, globalBypass, leases.categories, approvalGrants, captureMode, captureIgnored, gitWorkspace, isUnattendedApprovalMode(execution),
772
+ // The enabled_tools capability manifest (issue #350): restricted
773
+ // servers' allow-lists, enforced by the hook's "disabled" arm ahead of
774
+ // every approval bypass. The Cursor SDK config cannot hide a server's
775
+ // tools, so this deny-at-call is the harness's enforcement.
776
+ enabledToolsBySlug(mcpResolution.resolvedServers));
748
777
  const hitlGate = await installHitlGate({
749
778
  workspaceRoot: primaryWorkspaceDir,
750
779
  hitlDir,
@@ -937,7 +966,7 @@ turnSeq) {
937
966
  subAgents: blueprint.subAgents,
938
967
  workspaceDirs: blueprint.workspaceDirs,
939
968
  workspaceFileRefs: spec.workspaceFileRefs ?? [],
940
- attachmentPaths,
969
+ attachments: attachmentEntries,
941
970
  vision: visionPromptInfo,
942
971
  pendingApprovals: adjudicatedApprovals,
943
972
  appliedToolCallIds,
@@ -1443,12 +1472,10 @@ turnSeq) {
1443
1472
  status.phase = ExecutionPhase.EXECUTION_COMPLETED;
1444
1473
  break;
1445
1474
  case "error": {
1446
- const resultAny = result;
1447
- const sdkError = result.result
1448
- ?? resultAny.error
1449
- ?? resultAny.message
1450
- ?? resultAny.reason;
1451
- const sdkErrorStr = sdkError ? String(sdkError) : undefined;
1475
+ // Shape-aware extraction, NOT String(): the result's error fields are
1476
+ // structured at runtime often enough that a bare coercion showed users
1477
+ // "[object Object]" and shadowed every fallback source below (oss#299).
1478
+ const runErrorSources = extractRunErrorSources(result);
1452
1479
  // The SDK frequently resolves run.wait() to a bare { status: "error" }
1453
1480
  // while the real reason (e.g. the original grpc-status 12 routing
1454
1481
  // failure) lives on the failing conversation turn. Capture it here so
@@ -1458,7 +1485,8 @@ turnSeq) {
1458
1485
  if (capturedRejection)
1459
1486
  clearCapturedRejection(executionId);
1460
1487
  const classified = synthesizeError({
1461
- sdkResultFields: sdkErrorStr,
1488
+ sdkError: runErrorSources.sdkError,
1489
+ sdkResultFields: runErrorSources.sdkResultFields,
1462
1490
  streamErrorMessage: turnState.streamErrorMessage,
1463
1491
  capturedRejection,
1464
1492
  conversationErrorText,
@@ -1501,7 +1529,7 @@ turnSeq) {
1501
1529
  subAgents: blueprint.subAgents,
1502
1530
  workspaceDirs: blueprint.workspaceDirs,
1503
1531
  workspaceFileRefs: spec.workspaceFileRefs ?? [],
1504
- attachmentPaths,
1532
+ attachments: attachmentEntries,
1505
1533
  vision: visionPromptInfo,
1506
1534
  pendingApprovals: adjudicatedApprovals,
1507
1535
  interactionMode,
@@ -1557,8 +1585,14 @@ turnSeq) {
1557
1585
  if (retryRejection)
1558
1586
  clearCapturedRejection(executionId);
1559
1587
  const retryConversationErrorText = await introspectConversation(retryRun, executionId);
1588
+ // Same shape-aware extraction as the primary error arm — the retry
1589
+ // previously String()-coerced result.result alone, so a structured
1590
+ // retry failure both read "[object Object]" and ignored the
1591
+ // error/message/reason fields the primary arm consults.
1592
+ const retryErrorSources = extractRunErrorSources(retryResult);
1560
1593
  const retryClassified = synthesizeError({
1561
- sdkResultFields: retryResult.result ? String(retryResult.result) : undefined,
1594
+ sdkError: retryErrorSources.sdkError,
1595
+ sdkResultFields: retryErrorSources.sdkResultFields,
1562
1596
  streamErrorMessage: turnState.streamErrorMessage,
1563
1597
  capturedRejection: retryRejection,
1564
1598
  conversationErrorText: retryConversationErrorText,
@@ -1654,6 +1688,7 @@ turnSeq) {
1654
1688
  console.log(`ExecuteCursor text extraction failed, trying LLM extraction: execution=${executionId}, ` +
1655
1689
  `finalTextLength=${finalText.length}`);
1656
1690
  try {
1691
+ const { extractStructuredOutput } = await import("./extract-structured-output.js");
1657
1692
  structuredOutput = await extractStructuredOutput(finalText, structuredOutputSchema, config, requestedModel);
1658
1693
  if (structuredOutput !== undefined) {
1659
1694
  console.log(`ExecuteCursor structured output extracted (LLM): execution=${executionId}`);
@@ -1942,40 +1977,6 @@ function seedCursorTranscriptFromExecution(status, execution) {
1942
1977
  }
1943
1978
  return persisted.subAgentExecutions.map((sub) => clone(SubAgentExecutionSchema, sub));
1944
1979
  }
1945
- // ---------------------------------------------------------------------------
1946
- // Structured Output Extraction (Cursor Harness Tier 2)
1947
- // ---------------------------------------------------------------------------
1948
- /**
1949
- * Extract structured data from an agent's free-text response using an
1950
- * economy-tier LLM with withStructuredOutput (function-calling).
1951
- * Guarantees schema-conformant JSON output via the API's tool-use mechanism.
1952
- *
1953
- * Construction (registry-id resolution, provider inference, proxy wiring) is
1954
- * delegated to the shared buildChatModel so the economy model's registry id is
1955
- * always resolved to a provider API id before the call.
1956
- */
1957
- async function extractStructuredOutput(agentResponse, schema, config, primaryModel) {
1958
- const { getEconomyModel } = await import("../../shared/model-registry.js");
1959
- const { buildChatModel } = await import("../../shared/model-client.js");
1960
- const extractionModel = await getEconomyModel(primaryModel);
1961
- const proxyEndpoint = config.proxyEndpoint ?? config.stigmerBackendEndpoint;
1962
- const { model: llm } = await buildChatModel({
1963
- modelName: extractionModel,
1964
- proxyEndpoint,
1965
- stigmerToken: config.stigmerToken ?? undefined,
1966
- maxTokens: 4096,
1967
- });
1968
- const zodSchema = jsonSchemaToZod(schema);
1969
- const structured = llm.withStructuredOutput(zodSchema);
1970
- const result = await structured.invoke([
1971
- { role: "system", content: "Extract the structured data from the agent's response. Return only the data that matches the schema." },
1972
- { role: "user", content: agentResponse },
1973
- ]);
1974
- return result ?? null;
1975
- }
1976
- // Re-export for use within this module; shared implementation eliminates
1977
- // the three duplicate converters that previously drifted independently.
1978
- import { jsonSchemaToZod } from "../../shared/json-schema-to-zod.js";
1979
1980
  /**
1980
1981
  * Select and build the appropriate prompt based on resolution reason and
1981
1982
  * HITL state.
@@ -2004,7 +2005,7 @@ export function isHitlReinvocation(approvalDecisions) {
2004
2005
  return approvalDecisions !== undefined && approvalDecisions.size > 0;
2005
2006
  }
2006
2007
  export function buildPrompt(input) {
2007
- const { resolution, approvalDecisions, instructions, userMessage, skills, subAgents, workspaceDirs, workspaceFileRefs, attachmentPaths, interactionMode, buildFromPlan, conversationCatchup, } = input;
2008
+ const { resolution, approvalDecisions, instructions, userMessage, skills, subAgents, workspaceDirs, workspaceFileRefs, attachments, interactionMode, buildFromPlan, conversationCatchup, } = input;
2008
2009
  // HITL reinvocation: the agent is resumed, so its native context carries the
2009
2010
  // prior conversation; the reinvocation prompt conveys the approval decisions
2010
2011
  // (and which approved writes the runner already exact-applied).
@@ -2028,9 +2029,9 @@ export function buildPrompt(input) {
2028
2029
  if (resolution.reason === "resumed_successfully") {
2029
2030
  const prefixes = [
2030
2031
  formatInteractionModePrefix(interactionMode),
2031
- formatImplementPlanSection(buildFromPlan, attachmentPaths),
2032
- attachmentPaths.length > 0
2033
- ? formatInputFiles(attachmentPaths, input.vision)
2032
+ formatImplementPlanSection(buildFromPlan, attachments),
2033
+ attachments.length > 0
2034
+ ? formatInputFiles(attachments, input.vision)
2034
2035
  : undefined,
2035
2036
  conversationCatchup !== undefined
2036
2037
  ? formatConversationCatchupSection(conversationCatchup)
@@ -2052,7 +2053,7 @@ export function buildPrompt(input) {
2052
2053
  subAgents,
2053
2054
  workspaceDirs,
2054
2055
  workspaceFileRefs,
2055
- attachmentPaths,
2056
+ attachments,
2056
2057
  vision: input.vision,
2057
2058
  interactionMode,
2058
2059
  buildFromPlan,