@stigmer/runner 3.0.9-dev.20260616060535 → 3.1.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.
- package/dist/.build-fingerprint +1 -1
- package/dist/__test-utils__/approval-contract/types.d.ts +174 -0
- package/dist/__test-utils__/approval-contract/types.js +24 -0
- package/dist/__test-utils__/approval-contract/types.js.map +1 -0
- package/dist/activities/call-agent-status.d.ts +19 -1
- package/dist/activities/call-agent-status.js +64 -5
- package/dist/activities/call-agent-status.js.map +1 -1
- package/dist/activities/call-llm.js +19 -53
- package/dist/activities/call-llm.js.map +1 -1
- package/dist/activities/classify-tool-approvals.d.ts +24 -0
- package/dist/activities/classify-tool-approvals.js +69 -17
- package/dist/activities/classify-tool-approvals.js.map +1 -1
- package/dist/activities/discover-mcp-server.d.ts +7 -0
- package/dist/activities/discover-mcp-server.js +11 -1
- package/dist/activities/discover-mcp-server.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +140 -0
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +130 -0
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -0
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.d.ts +18 -0
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +123 -0
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -0
- package/dist/activities/execute-cursor/approval-policy.d.ts +17 -61
- package/dist/activities/execute-cursor/approval-policy.js +8 -120
- package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +219 -9
- package/dist/activities/execute-cursor/approval-state.js +233 -17
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/capture-flow.d.ts +127 -0
- package/dist/activities/execute-cursor/capture-flow.js +234 -0
- package/dist/activities/execute-cursor/capture-flow.js.map +1 -0
- package/dist/activities/execute-cursor/cas-observations.d.ts +96 -0
- package/dist/activities/execute-cursor/cas-observations.js +184 -0
- package/dist/activities/execute-cursor/cas-observations.js.map +1 -0
- package/dist/activities/execute-cursor/command-provenance.d.ts +62 -0
- package/dist/activities/execute-cursor/command-provenance.js +128 -0
- package/dist/activities/execute-cursor/command-provenance.js.map +1 -0
- package/dist/activities/execute-cursor/exact-apply.d.ts +110 -0
- package/dist/activities/execute-cursor/exact-apply.js +204 -0
- package/dist/activities/execute-cursor/exact-apply.js.map +1 -0
- package/dist/activities/execute-cursor/hook-script.d.ts +53 -24
- package/dist/activities/execute-cursor/hook-script.js +310 -47
- package/dist/activities/execute-cursor/hook-script.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +8 -1
- package/dist/activities/execute-cursor/index.js +500 -64
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/message-translator.d.ts +258 -11
- package/dist/activities/execute-cursor/message-translator.js +836 -90
- package/dist/activities/execute-cursor/message-translator.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +20 -23
- package/dist/activities/execute-cursor/prompt-builder.js +74 -15
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/workspace-setup.d.ts +17 -0
- package/dist/activities/execute-cursor/workspace-setup.js +212 -33
- package/dist/activities/execute-cursor/workspace-setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/gateway-substrate.d.ts +19 -0
- package/dist/activities/execute-deep-agent/__test-utils__/gateway-substrate.js +143 -0
- package/dist/activities/execute-deep-agent/__test-utils__/gateway-substrate.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +88 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +81 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -0
- package/dist/activities/execute-deep-agent/approval-file-change.d.ts +47 -0
- package/dist/activities/execute-deep-agent/approval-file-change.js +68 -0
- package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -0
- package/dist/activities/execute-deep-agent/attachment-injector.d.ts +8 -1
- package/dist/activities/execute-deep-agent/attachment-injector.js +7 -7
- package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.d.ts +42 -0
- package/dist/activities/execute-deep-agent/cas-capture-backend.js +47 -0
- package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.d.ts +79 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.js +112 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.js.map +1 -0
- package/dist/activities/execute-deep-agent/hitl.d.ts +10 -0
- package/dist/activities/execute-deep-agent/hitl.js +5 -1
- package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.d.ts +2 -1
- package/dist/activities/execute-deep-agent/index.js +370 -56
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/inline-publisher.d.ts +7 -1
- package/dist/activities/execute-deep-agent/inline-publisher.js +23 -2
- package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +53 -2
- package/dist/activities/execute-deep-agent/setup.js +149 -92
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.d.ts +36 -0
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.js +56 -0
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.js.map +1 -0
- package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +34 -1
- package/dist/activities/execute-deep-agent/status-builder-shared.js +26 -25
- package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -1
- package/dist/activities/execute-deep-agent/status-builder.d.ts +11 -5
- package/dist/activities/execute-deep-agent/status-builder.js +6 -2
- package/dist/activities/execute-deep-agent/status-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/streaming-side-effects.js +2 -19
- package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
- package/dist/activities/execute-deep-agent/streaming.js +3 -15
- package/dist/activities/execute-deep-agent/streaming.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +25 -7
- package/dist/activities/execute-deep-agent/subagent-transformer.js +23 -7
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +30 -3
- package/dist/activities/execute-deep-agent/subagent-wiring.js +29 -3
- package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
- package/dist/activities/execute-deep-agent/v3-status-builder.js +6 -2
- package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
- package/dist/claimcheck/payload-codec.js +9 -5
- package/dist/claimcheck/payload-codec.js.map +1 -1
- package/dist/client/stigmer-client.d.ts +2 -0
- package/dist/client/stigmer-client.js +2 -0
- package/dist/client/stigmer-client.js.map +1 -1
- package/dist/middleware/approval-gate.d.ts +85 -4
- package/dist/middleware/approval-gate.js +165 -38
- package/dist/middleware/approval-gate.js.map +1 -1
- package/dist/middleware/types.d.ts +2 -5
- package/dist/shared/activity-input.d.ts +43 -0
- package/dist/shared/activity-input.js +17 -0
- package/dist/shared/activity-input.js.map +1 -0
- package/dist/shared/approval-canonicalize.d.ts +19 -0
- package/dist/shared/approval-canonicalize.js +119 -0
- package/dist/shared/approval-canonicalize.js.map +1 -0
- package/dist/shared/approval-fingerprint.d.ts +106 -0
- package/dist/shared/approval-fingerprint.js +113 -0
- package/dist/shared/approval-fingerprint.js.map +1 -0
- package/dist/shared/approval-policy.d.ts +182 -12
- package/dist/shared/approval-policy.js +213 -27
- package/dist/shared/approval-policy.js.map +1 -1
- package/dist/shared/args-preview.d.ts +52 -0
- package/dist/shared/args-preview.js +93 -0
- package/dist/shared/args-preview.js.map +1 -0
- package/dist/shared/artifact-storage.d.ts +19 -1
- package/dist/shared/artifact-storage.js +48 -11
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/file-change.d.ts +44 -0
- package/dist/shared/file-change.js +57 -0
- package/dist/shared/file-change.js.map +1 -0
- package/dist/shared/file-tools.d.ts +107 -0
- package/dist/shared/file-tools.js +168 -0
- package/dist/shared/file-tools.js.map +1 -0
- package/dist/shared/filereview/capture.d.ts +202 -0
- package/dist/shared/filereview/capture.js +498 -0
- package/dist/shared/filereview/capture.js.map +1 -0
- package/dist/shared/filereview/cas-substrate.d.ts +190 -0
- package/dist/shared/filereview/cas-substrate.js +284 -0
- package/dist/shared/filereview/cas-substrate.js.map +1 -0
- package/dist/shared/filereview/digest.d.ts +40 -0
- package/dist/shared/filereview/digest.js +66 -0
- package/dist/shared/filereview/digest.js.map +1 -0
- package/dist/shared/filereview/events.d.ts +170 -0
- package/dist/shared/filereview/events.js +298 -0
- package/dist/shared/filereview/events.js.map +1 -0
- package/dist/shared/filereview/git-substrate.d.ts +175 -0
- package/dist/shared/filereview/git-substrate.js +439 -0
- package/dist/shared/filereview/git-substrate.js.map +1 -0
- package/dist/shared/filereview/index.d.ts +11 -0
- package/dist/shared/filereview/index.js +12 -0
- package/dist/shared/filereview/index.js.map +1 -0
- package/dist/shared/filereview/secret-paths.d.ts +63 -0
- package/dist/shared/filereview/secret-paths.js +105 -0
- package/dist/shared/filereview/secret-paths.js.map +1 -0
- package/dist/shared/fingerprint-secret.d.ts +26 -0
- package/dist/shared/fingerprint-secret.js +47 -0
- package/dist/shared/fingerprint-secret.js.map +1 -0
- package/dist/shared/model-client.d.ts +51 -0
- package/dist/shared/model-client.js +77 -0
- package/dist/shared/model-client.js.map +1 -0
- package/dist/shared/plan-artifact.js +0 -2
- package/dist/shared/plan-artifact.js.map +1 -1
- package/dist/shared/status-offload.d.ts +83 -9
- package/dist/shared/status-offload.js +399 -79
- package/dist/shared/status-offload.js.map +1 -1
- package/dist/shared/status.js +14 -1
- package/dist/shared/status.js.map +1 -1
- package/dist/shared/tool-kind.d.ts +19 -0
- package/dist/shared/tool-kind.js +13 -0
- package/dist/shared/tool-kind.js.map +1 -1
- package/dist/shared/tool-row.d.ts +88 -0
- package/dist/shared/tool-row.js +127 -0
- package/dist/shared/tool-row.js.map +1 -0
- package/dist/shared/workspace/platform-dir.d.ts +25 -0
- package/dist/shared/workspace/platform-dir.js +38 -2
- package/dist/shared/workspace/platform-dir.js.map +1 -1
- package/dist/workflows/call-agent-orchestrator.js +56 -7
- package/dist/workflows/call-agent-orchestrator.js.map +1 -1
- package/dist/workflows/connect-mcp-server.d.ts +50 -0
- package/dist/workflows/connect-mcp-server.js +136 -15
- package/dist/workflows/connect-mcp-server.js.map +1 -1
- package/dist/workflows/types.d.ts +8 -0
- package/package.json +2 -2
- package/src/__test-utils__/approval-contract/contract.ts +224 -0
- package/src/__test-utils__/approval-contract/types.ts +179 -0
- package/src/__test-utils__/fake-artifact-storage.ts +72 -0
- package/src/__tests__/approval-gateway-contract.test.ts +29 -0
- package/src/__tests__/claimcheck-codec.test.ts +16 -53
- package/src/__tests__/golden-e2e.test.ts +2 -0
- package/src/__tests__/runner-token-coordinator.test.ts +3 -3
- package/src/activities/__tests__/call-agent-status.test.ts +135 -0
- package/src/activities/__tests__/call-llm.test.ts +1 -1
- package/src/activities/__tests__/classify-tool-approvals.test.ts +208 -1
- package/src/activities/__tests__/discover-mcp-server.test.ts +30 -0
- package/src/activities/__tests__/workflow-event-activities.test.ts +2 -1
- package/src/activities/call-agent-status.ts +74 -4
- package/src/activities/call-llm.ts +18 -63
- package/src/activities/classify-tool-approvals.ts +101 -19
- package/src/activities/discover-mcp-server.ts +29 -1
- package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +216 -0
- package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +148 -0
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +41 -9
- package/src/activities/execute-cursor/__tests__/approval-state.test.ts +292 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +68 -1
- package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +1005 -0
- package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +187 -0
- package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +97 -0
- package/src/activities/execute-cursor/__tests__/command-provenance.test.ts +240 -0
- package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +203 -0
- package/src/activities/execute-cursor/__tests__/exact-apply.test.ts +375 -0
- package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +1294 -24
- package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +446 -0
- package/src/activities/execute-cursor/__tests__/hook-script.test.ts +384 -110
- package/src/activities/execute-cursor/__tests__/message-translator.test.ts +171 -25
- package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +189 -0
- package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +44 -23
- package/src/activities/execute-cursor/__tests__/workspace-setup.test.ts +190 -10
- package/src/activities/execute-cursor/approval-policy.ts +28 -159
- package/src/activities/execute-cursor/approval-state.ts +366 -18
- package/src/activities/execute-cursor/capture-flow.ts +323 -0
- package/src/activities/execute-cursor/cas-observations.ts +204 -0
- package/src/activities/execute-cursor/command-provenance.ts +168 -0
- package/src/activities/execute-cursor/exact-apply.ts +253 -0
- package/src/activities/execute-cursor/hook-script.ts +317 -51
- package/src/activities/execute-cursor/index.ts +575 -67
- package/src/activities/execute-cursor/message-translator.ts +963 -89
- package/src/activities/execute-cursor/prompt-builder.ts +80 -14
- package/src/activities/execute-cursor/workspace-setup.ts +257 -42
- package/src/activities/execute-deep-agent/__test-utils__/gateway-substrate.ts +180 -0
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +134 -0
- package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +84 -0
- package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +11 -24
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +64 -0
- package/src/activities/execute-deep-agent/__tests__/cas-capture-observer.test.ts +163 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +8 -5
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +342 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +2 -5
- package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +31 -13
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +349 -0
- package/src/activities/execute-deep-agent/__tests__/stamp-flowed-rows.test.ts +119 -0
- package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +12 -11
- package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +9 -9
- package/src/activities/execute-deep-agent/__tests__/subagent-approval-propagation.test.ts +160 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +213 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +3 -6
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +84 -1
- package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +4 -1
- package/src/activities/execute-deep-agent/approval-file-change.ts +80 -0
- package/src/activities/execute-deep-agent/attachment-injector.ts +20 -11
- package/src/activities/execute-deep-agent/cas-capture-backend.ts +66 -0
- package/src/activities/execute-deep-agent/cas-capture-observer.ts +125 -0
- package/src/activities/execute-deep-agent/hitl.ts +15 -1
- package/src/activities/execute-deep-agent/index.ts +434 -64
- package/src/activities/execute-deep-agent/inline-publisher.ts +27 -4
- package/src/activities/execute-deep-agent/setup.ts +223 -125
- package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +64 -0
- package/src/activities/execute-deep-agent/status-builder-shared.ts +62 -23
- package/src/activities/execute-deep-agent/status-builder.ts +19 -7
- package/src/activities/execute-deep-agent/streaming-side-effects.ts +2 -16
- package/src/activities/execute-deep-agent/streaming.ts +3 -13
- package/src/activities/execute-deep-agent/subagent-transformer.ts +53 -13
- package/src/activities/execute-deep-agent/subagent-wiring.ts +50 -3
- package/src/activities/execute-deep-agent/v3-status-builder.ts +8 -2
- package/src/claimcheck/payload-codec.ts +8 -8
- package/src/client/stigmer-client.ts +9 -1
- package/src/middleware/__tests__/approval-gate.test.ts +488 -4
- package/src/middleware/approval-gate.ts +247 -38
- package/src/middleware/types.ts +5 -5
- package/src/shared/__tests__/activity-input.test.ts +78 -0
- package/src/shared/__tests__/approval-canonicalize.test.ts +106 -0
- package/src/shared/__tests__/approval-fingerprint.test.ts +115 -0
- package/src/shared/__tests__/approval-policy.test.ts +274 -40
- package/src/shared/__tests__/args-preview.test.ts +78 -0
- package/src/shared/__tests__/artifact-storage-extended.test.ts +62 -10
- package/src/shared/__tests__/artifact-storage.test.ts +123 -11
- package/src/shared/__tests__/file-change.test.ts +85 -0
- package/src/shared/__tests__/file-tools.test.ts +90 -0
- package/src/shared/__tests__/fingerprint-secret.test.ts +51 -0
- package/src/shared/__tests__/lease-scope-corpus.test.ts +56 -0
- package/src/shared/__tests__/model-client.test.ts +162 -0
- package/src/shared/__tests__/plan-artifact.test.ts +11 -26
- package/src/shared/__tests__/policy-source-corpus.test.ts +58 -0
- package/src/shared/__tests__/status-offload.test.ts +573 -16
- package/src/shared/__tests__/status.test.ts +4 -5
- package/src/shared/__tests__/tool-kind.test.ts +24 -1
- package/src/shared/__tests__/tool-row.test.ts +221 -0
- package/src/shared/activity-input.ts +57 -0
- package/src/shared/approval-canonicalize.ts +159 -0
- package/src/shared/approval-fingerprint.ts +148 -0
- package/src/shared/approval-policy.ts +303 -27
- package/src/shared/args-preview.ts +98 -0
- package/src/shared/artifact-storage.ts +62 -11
- package/src/shared/checkpointer/__tests__/http-saver.test.ts +1 -2
- package/src/shared/file-change.ts +64 -0
- package/src/shared/file-tools.ts +169 -0
- package/src/shared/filereview/__tests__/capture.test.ts +856 -0
- package/src/shared/filereview/__tests__/cas-substrate.test.ts +404 -0
- package/src/shared/filereview/__tests__/digest.test.ts +100 -0
- package/src/shared/filereview/__tests__/events.test.ts +245 -0
- package/src/shared/filereview/__tests__/git-substrate.test.ts +362 -0
- package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +286 -0
- package/src/shared/filereview/__tests__/secret-paths.test.ts +121 -0
- package/src/shared/filereview/capture.ts +727 -0
- package/src/shared/filereview/cas-substrate.ts +401 -0
- package/src/shared/filereview/digest.ts +83 -0
- package/src/shared/filereview/events.ts +449 -0
- package/src/shared/filereview/git-substrate.ts +555 -0
- package/src/shared/filereview/index.ts +60 -0
- package/src/shared/filereview/secret-paths.ts +121 -0
- package/src/shared/fingerprint-secret.ts +53 -0
- package/src/shared/model-client.ts +122 -0
- package/src/shared/plan-artifact.ts +0 -2
- package/src/shared/status-offload.ts +433 -77
- package/src/shared/status.ts +13 -0
- package/src/shared/tool-kind.ts +33 -0
- package/src/shared/tool-row.ts +135 -0
- package/src/shared/workspace/platform-dir.ts +41 -2
- package/src/workflow-engine/__tests__/golden-execution.test.ts +35 -18
- package/src/workflow-engine/__tests__/tasks/try.test.ts +1 -1
- package/src/workflows/__tests__/connect-mcp-server.test.ts +304 -29
- package/src/workflows/call-agent-orchestrator.ts +53 -6
- package/src/workflows/connect-mcp-server.ts +179 -24
- package/src/workflows/types.ts +8 -0
|
@@ -16,46 +16,107 @@
|
|
|
16
16
|
* pausing again.
|
|
17
17
|
*
|
|
18
18
|
* Platform tool defaults: DeepAgents JS backend tools (read, write,
|
|
19
|
-
* edit, execute, etc.) are not covered by MCP policy chains.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* edit, execute, etc.) are not covered by MCP policy chains. Built-in tools
|
|
20
|
+
* are classified through the shared {@link toolApprovalCategory} — the single
|
|
21
|
+
* source of truth, shared with the Cursor deny-oracle hook — so read-only tools
|
|
22
|
+
* are auto-approved and every mutating tool (write/edit/delete/shell) is gated
|
|
23
|
+
* fail-CLOSED, by category rather than by a hand-maintained name list. An
|
|
24
|
+
* unrecognized mutating built-in (e.g. `bash`, `overwrite_file`) is therefore
|
|
25
|
+
* gated by what it does, not by whether someone remembered to list it.
|
|
26
|
+
*
|
|
27
|
+
* Gateway invariant (Phase 2): this middleware IS the in-process execution
|
|
28
|
+
* gateway for the deep-agent harness — `handler(request)` is the side effect. A
|
|
29
|
+
* side effect runs only with a backing authorization: either (a) the tool was
|
|
30
|
+
* auto-approved (policy/classifier cleared it, or auto-approve-all disabled the
|
|
31
|
+
* whole gate), or (b) the user explicitly approved THIS interrupted call. Every
|
|
32
|
+
* other outcome — skip, reject, or an unrecognized decision — returns a
|
|
33
|
+
* ToolMessage WITHOUT executing. There is no path from a model proposal to a
|
|
34
|
+
* side effect that skips an authorization.
|
|
35
|
+
*
|
|
36
|
+
* Shadow ExecutionReceipt: when the gateway lets a side effect through it emits a
|
|
37
|
+
* structured, non-persisted receipt (a `[hitl-gateway] receipt …` log carrying
|
|
38
|
+
* the action's HMAC fingerprint and the authorization source). This is an audit
|
|
39
|
+
* + uniformity signal only — no proto, no storage — mirroring the Phase-1 shadow
|
|
40
|
+
* discipline. On the deep-agent normal path the fingerprint match is guaranteed
|
|
41
|
+
* by LangGraph checkpoint replay (the resumed action equals the approved one), so
|
|
42
|
+
* the receipt is defense-in-depth here; the fingerprint earns real enforcement
|
|
43
|
+
* teeth in the out-of-process Cursor substrate.
|
|
22
44
|
*/
|
|
23
45
|
import { ToolMessage } from "@langchain/core/messages";
|
|
24
46
|
import { interrupt } from "@langchain/langgraph";
|
|
25
|
-
import { resolveApprovalMessage, } from "../shared/approval-policy.js";
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
["create_file", "Create file: {{args.path}}"],
|
|
40
|
-
["delete", "Delete: {{args.path}}"],
|
|
41
|
-
["delete_file", "Delete file: {{args.path}}"],
|
|
42
|
-
["execute", "Execute command: {{args.command}}"],
|
|
43
|
-
["shell", "Execute shell command: {{args.command}}"],
|
|
44
|
-
["str_replace_editor", "Edit file: {{args.path}}"],
|
|
45
|
-
]);
|
|
47
|
+
import { POLICY_ENGINE_VERSION, resolveApprovalMessage, } from "../shared/approval-policy.js";
|
|
48
|
+
import { toolApprovalCategory } from "../shared/tool-kind.js";
|
|
49
|
+
import { extractFilePath } from "../shared/file-tools.js";
|
|
50
|
+
import { isSecretLikePath } from "../shared/filereview/secret-paths.js";
|
|
51
|
+
import { computeApprovalFingerprint, } from "../shared/approval-fingerprint.js";
|
|
52
|
+
// Approval-message template per mutating category. Keyed by category (not raw
|
|
53
|
+
// tool name) so every alias of a mutation renders one message; placeholders
|
|
54
|
+
// resolve against the deep-agent stream arg shape (`path`/`command`). Mirrors
|
|
55
|
+
// the Cursor side's CATEGORY_APPROVAL_MESSAGE.
|
|
56
|
+
const CATEGORY_APPROVAL_MESSAGE = {
|
|
57
|
+
write: "Write file: {{args.path}}",
|
|
58
|
+
delete: "Delete: {{args.path}}",
|
|
59
|
+
shell: "Execute command: {{args.command}}",
|
|
60
|
+
};
|
|
46
61
|
export function createApprovalGateMiddleware(config) {
|
|
47
|
-
const { policies,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
const { policies, toolServerMap } = config;
|
|
63
|
+
const leasedCategories = config.leasedCategories ?? EMPTY_CATEGORY_SET;
|
|
64
|
+
// No global-bypass early return: a pre-armed spec.auto_approve_all means the
|
|
65
|
+
// gate is never even installed (setup.ts builds this config only when not
|
|
66
|
+
// global). Scoped leases keep the gate active so non-leased actions still gate.
|
|
51
67
|
return {
|
|
52
68
|
name: "ApprovalGateMiddleware",
|
|
53
69
|
async wrapToolCall(request, handler) {
|
|
54
70
|
const { toolCall } = request;
|
|
55
71
|
const toolName = toolCall.name;
|
|
56
72
|
const serverSlug = toolServerMap.get(toolName) ?? "";
|
|
57
|
-
const
|
|
73
|
+
const category = toolApprovalCategory(toolName);
|
|
74
|
+
// Capture mode (git workspaces): a git-tracked built-in file mutation flows
|
|
75
|
+
// during the turn and is reviewed post-hoc via the file_review ledger (the
|
|
76
|
+
// apply-then-review model). shell and MCP tools (serverSlug present) are
|
|
77
|
+
// never bypassed here.
|
|
78
|
+
if (config.fileCaptureMode &&
|
|
79
|
+
config.isCapturablePath &&
|
|
80
|
+
!serverSlug &&
|
|
81
|
+
(category === "write" || category === "delete")) {
|
|
82
|
+
const path = extractFilePath(toolCall.args);
|
|
83
|
+
if (path !== null) {
|
|
84
|
+
if (await config.isCapturablePath(path)) {
|
|
85
|
+
// Git-tracked: flows and is reviewed post-hoc by the git substrate.
|
|
86
|
+
emitExecutionReceipt(config, toolCall, serverSlug, category, "auto_approve", "file_capture");
|
|
87
|
+
return await handler(request);
|
|
88
|
+
}
|
|
89
|
+
// Gitignored path. Only the PARENT gate (captureIgnored) routes it into
|
|
90
|
+
// CAS capture; sub-agent gates fall through to the interrupt gate below,
|
|
91
|
+
// exactly as before (their backends are not CAS-observed).
|
|
92
|
+
if (config.captureIgnored) {
|
|
93
|
+
if (isSecretLikePath(path)) {
|
|
94
|
+
// DD-E fail-closed: a secret-like gitignored edit is NEVER applied
|
|
95
|
+
// and NEVER captured. Record it so the turn boundary authors a
|
|
96
|
+
// DIFF_UNREVIEWABLE entry (blocking approval); nothing is written.
|
|
97
|
+
config.recordBlockedSecret?.(path);
|
|
98
|
+
return new ToolMessage({
|
|
99
|
+
content: `Tool '${toolName}' was blocked for security: '${path}' matches a ` +
|
|
100
|
+
`secret-like path Stigmer will not capture for review. Nothing was written.`,
|
|
101
|
+
tool_call_id: toolCall.id,
|
|
102
|
+
name: toolName,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (category === "write") {
|
|
106
|
+
// Non-secret gitignored write/edit: flows (apply-then-review). The
|
|
107
|
+
// CAS observer already holds its before-bytes and the turn boundary
|
|
108
|
+
// captures it into CAS. (A gitignored delete has no backend capture
|
|
109
|
+
// path, so it falls through to the interrupt gate.)
|
|
110
|
+
emitExecutionReceipt(config, toolCall, serverSlug, category, "auto_approve", "file_capture");
|
|
111
|
+
return await handler(request);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const requirement = resolveToolApproval(toolName, serverSlug, toolCall.args, policies, leasedCategories);
|
|
58
117
|
if (!requirement.requiresApproval) {
|
|
118
|
+
// Backing authorization: the classifier/policy auto-approved this tool.
|
|
119
|
+
emitExecutionReceipt(config, toolCall, serverSlug, category, "auto_approve", requirement.source);
|
|
59
120
|
return await handler(request);
|
|
60
121
|
}
|
|
61
122
|
const approvalRequest = {
|
|
@@ -63,12 +124,18 @@ export function createApprovalGateMiddleware(config) {
|
|
|
63
124
|
tool_name: toolName,
|
|
64
125
|
mcp_server_slug: serverSlug,
|
|
65
126
|
message: requirement.message,
|
|
127
|
+
// Carry the gate's provenance verdict through the interrupt so the
|
|
128
|
+
// reinvocation that seeds the WAITING_APPROVAL tool call (index.ts) can
|
|
129
|
+
// persist ToolCall.approval_policy_source without re-deriving it.
|
|
130
|
+
policy_source: requirement.source,
|
|
66
131
|
};
|
|
67
132
|
const response = interrupt(approvalRequest);
|
|
68
133
|
const action = (typeof response === "object" && response !== null
|
|
69
134
|
? (response.action ?? "")
|
|
70
135
|
: "").toString().toLowerCase();
|
|
71
136
|
if (action === "approve") {
|
|
137
|
+
// Backing authorization: the user approved THIS interrupted call.
|
|
138
|
+
emitExecutionReceipt(config, toolCall, serverSlug, category, "approval", requirement.source);
|
|
72
139
|
return await handler(request);
|
|
73
140
|
}
|
|
74
141
|
if (action === "skip") {
|
|
@@ -98,28 +165,88 @@ export function createApprovalGateMiddleware(config) {
|
|
|
98
165
|
},
|
|
99
166
|
};
|
|
100
167
|
}
|
|
101
|
-
function resolveToolApproval(toolName, serverSlug, args, policies) {
|
|
168
|
+
function resolveToolApproval(toolName, serverSlug, args, policies, leasedCategories) {
|
|
102
169
|
if (serverSlug) {
|
|
170
|
+
// MCP tools stay governed by the connect-flow classifier + four-level policy
|
|
171
|
+
// chain. The policy map carries only the tools that REQUIRE approval, so an
|
|
172
|
+
// absent entry means the classifier already auto-approved it — fail-OPEN is
|
|
173
|
+
// correct here (a fail-closed default would re-gate everything the classifier
|
|
174
|
+
// cleared). This is deliberately NOT changed by the built-in fail-closed flip.
|
|
175
|
+
//
|
|
176
|
+
// A server-scoped lease surfaces here as an absent entry too: the leased
|
|
177
|
+
// server's tools are dropped from `policies` upstream (mergeApprovalPolicies),
|
|
178
|
+
// so a lease-cleared MCP tool takes this same auto-approve path. (Its shadow
|
|
179
|
+
// receipt therefore reads classifier_default rather than approval_lease; a
|
|
180
|
+
// faithful per-server lease provenance would need the lease set threaded here
|
|
181
|
+
// and is deferred with the rest of the persisted-receipt work.)
|
|
103
182
|
const key = `${serverSlug}/${toolName}`;
|
|
104
183
|
const policy = policies.get(key);
|
|
105
184
|
if (policy) {
|
|
106
185
|
return {
|
|
107
186
|
requiresApproval: policy.requiresApproval,
|
|
108
187
|
message: resolveApprovalMessage(policy.approvalMessage, toolName, args),
|
|
188
|
+
source: policy.source,
|
|
109
189
|
};
|
|
110
190
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return { requiresApproval: false, message: "" };
|
|
191
|
+
// Absent = cleared by the MCP four-level chain (classifier base) or by a
|
|
192
|
+
// server-scoped lease (dropped upstream).
|
|
193
|
+
return { requiresApproval: false, message: "", source: "classifier_default" };
|
|
115
194
|
}
|
|
116
|
-
|
|
117
|
-
|
|
195
|
+
// Built-in/platform tool: gate exactly the mutating categories via the shared
|
|
196
|
+
// classifier. Fail-CLOSED for the mutating set — any built-in classifyTool
|
|
197
|
+
// deems write/edit/delete/shell requires approval. Read-only and unclassified
|
|
198
|
+
// built-ins are not mutating, so they remain fail-open.
|
|
199
|
+
const category = toolApprovalCategory(toolName);
|
|
200
|
+
if (category) {
|
|
201
|
+
// Run-lifetime category lease: the user chose "approve all <category>"
|
|
202
|
+
// earlier in this run, so every built-in of that category is auto-approved
|
|
203
|
+
// for the rest of the run (the scoped successor to auto-approve-all).
|
|
204
|
+
if (leasedCategories.has(category)) {
|
|
205
|
+
return { requiresApproval: false, message: "", source: "approval_lease" };
|
|
206
|
+
}
|
|
118
207
|
return {
|
|
119
208
|
requiresApproval: true,
|
|
120
|
-
message: resolveApprovalMessage(
|
|
209
|
+
message: resolveApprovalMessage(CATEGORY_APPROVAL_MESSAGE[category], toolName, args),
|
|
210
|
+
source: "builtin_category",
|
|
121
211
|
};
|
|
122
212
|
}
|
|
123
|
-
return { requiresApproval: false, message: "" };
|
|
213
|
+
return { requiresApproval: false, message: "", source: "builtin_category" };
|
|
214
|
+
}
|
|
215
|
+
/** Shared empty set so a config without leases allocates nothing per call. */
|
|
216
|
+
const EMPTY_CATEGORY_SET = new Set();
|
|
217
|
+
/**
|
|
218
|
+
* Emit the shadow ExecutionReceipt when the gateway authorizes a side effect.
|
|
219
|
+
*
|
|
220
|
+
* Scope: only side-effecting actions are recorded — a mutating built-in (a
|
|
221
|
+
* non-empty {@link ToolApprovalCategory}) or any MCP tool (`serverSlug` present).
|
|
222
|
+
* Read-only built-ins are not side effects, so recording them would only dilute
|
|
223
|
+
* the signal. The receipt is a structured log carrying the action's HMAC
|
|
224
|
+
* fingerprint and the authorization source; it is never persisted and crosses no
|
|
225
|
+
* wire (no proto). The fingerprint is omitted (empty) when no per-execution key
|
|
226
|
+
* was supplied (tests / no-secret paths).
|
|
227
|
+
*/
|
|
228
|
+
function emitExecutionReceipt(config, toolCall, serverSlug, category, source, policySource) {
|
|
229
|
+
if (!category && !serverSlug)
|
|
230
|
+
return;
|
|
231
|
+
const fingerprint = config.fingerprintKey
|
|
232
|
+
? computeApprovalFingerprint(config.fingerprintKey, {
|
|
233
|
+
toolName: toolCall.name,
|
|
234
|
+
mcpServerSlug: serverSlug,
|
|
235
|
+
args: toolCall.args,
|
|
236
|
+
})
|
|
237
|
+
: "";
|
|
238
|
+
console.log("[hitl-gateway] receipt " +
|
|
239
|
+
JSON.stringify({
|
|
240
|
+
executionId: config.executionId ?? "",
|
|
241
|
+
toolCallId: toolCall.id,
|
|
242
|
+
toolName: toolCall.name,
|
|
243
|
+
mcpServerSlug: serverSlug,
|
|
244
|
+
category: category ?? "",
|
|
245
|
+
authorization: source,
|
|
246
|
+
policySource,
|
|
247
|
+
policyEngineVersion: POLICY_ENGINE_VERSION,
|
|
248
|
+
fingerprint,
|
|
249
|
+
substrate: "deep-agent",
|
|
250
|
+
}));
|
|
124
251
|
}
|
|
125
252
|
//# sourceMappingURL=approval-gate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-gate.js","sourceRoot":"","sources":["../../src/middleware/approval-gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"approval-gate.js","sourceRoot":"","sources":["../../src/middleware/approval-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAGL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAA6B,MAAM,wBAAwB,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EACL,0BAA0B,GAE3B,MAAM,mCAAmC,CAAC;AAsE3C,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,+CAA+C;AAC/C,MAAM,yBAAyB,GAAyC;IACtE,KAAK,EAAE,2BAA2B;IAClC,MAAM,EAAE,uBAAuB;IAC/B,KAAK,EAAE,mCAAmC;CAC3C,CAAC;AAEF,MAAM,UAAU,4BAA4B,CAC1C,MAA0B;IAE1B,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IAC3C,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,IAAI,kBAAkB,CAAC;IAEvE,6EAA6E;IAC7E,0EAA0E;IAC1E,gFAAgF;IAEhF,OAAO;QACL,IAAI,EAAE,wBAAwB;QAE9B,KAAK,CAAC,YAAY,CAAC,OAAwB,EAAE,OAAO;YAClD,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;YAC7B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;YAC/B,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;YAEhD,4EAA4E;YAC5E,2EAA2E;YAC3E,yEAAyE;YACzE,uBAAuB;YACvB,IACE,MAAM,CAAC,eAAe;gBACtB,MAAM,CAAC,gBAAgB;gBACvB,CAAC,UAAU;gBACX,CAAC,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,QAAQ,CAAC,EAC/C,CAAC;gBACD,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC5C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;oBAClB,IAAI,MAAM,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;wBACxC,oEAAoE;wBACpE,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;wBAC7F,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;oBAChC,CAAC;oBACD,wEAAwE;oBACxE,yEAAyE;oBACzE,2DAA2D;oBAC3D,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;wBAC1B,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;4BAC3B,mEAAmE;4BACnE,+DAA+D;4BAC/D,mEAAmE;4BACnE,MAAM,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,CAAC;4BACnC,OAAO,IAAI,WAAW,CAAC;gCACrB,OAAO,EACL,SAAS,QAAQ,gCAAgC,IAAI,cAAc;oCACnE,4EAA4E;gCAC9E,YAAY,EAAE,QAAQ,CAAC,EAAE;gCACzB,IAAI,EAAE,QAAQ;6BACf,CAAC,CAAC;wBACL,CAAC;wBACD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;4BACzB,mEAAmE;4BACnE,oEAAoE;4BACpE,oEAAoE;4BACpE,oDAAoD;4BACpD,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;4BAC7F,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;wBAChC,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,WAAW,GAAG,mBAAmB,CACrC,QAAQ,EACR,UAAU,EACV,QAAQ,CAAC,IAAI,EACb,QAAQ,EACR,gBAAgB,CACjB,CAAC;YAEF,IAAI,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC;gBAClC,wEAAwE;gBACxE,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;gBACjG,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;YAED,MAAM,eAAe,GAAG;gBACtB,YAAY,EAAE,QAAQ,CAAC,EAAE;gBACzB,SAAS,EAAE,QAAQ;gBACnB,eAAe,EAAE,UAAU;gBAC3B,OAAO,EAAE,WAAW,CAAC,OAAO;gBAC5B,mEAAmE;gBACnE,wEAAwE;gBACxE,kEAAkE;gBAClE,aAAa,EAAE,WAAW,CAAC,MAAM;aAClC,CAAC;YAEF,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAqB,CAAC;YAEhE,MAAM,MAAM,GAAG,CACb,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;gBAC/C,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;gBACzB,CAAC,CAAC,EAAE,CACP,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC;YAE3B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,kEAAkE;gBAClE,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;gBAC7F,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC;gBACvC,MAAM,WAAW,GAAG,OAAO;oBACzB,CAAC,CAAC,SAAS,QAAQ,0BAA0B,OAAO,0CAA0C;oBAC9F,CAAC,CAAC,SAAS,QAAQ,+DAA+D,CAAC;gBAErF,OAAO,IAAI,WAAW,CAAC;oBACrB,OAAO,EAAE,WAAW;oBACpB,YAAY,EAAE,QAAQ,CAAC,EAAE;oBACzB,IAAI,EAAE,QAAQ;iBACf,CAAC,CAAC;YACL,CAAC;YAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,kBAAkB,CAAC;gBACvD,OAAO,IAAI,WAAW,CAAC;oBACrB,OAAO,EAAE,SAAS,QAAQ,mBAAmB,OAAO,iCAAiC;oBACrF,YAAY,EAAE,QAAQ,CAAC,EAAE;oBACzB,IAAI,EAAE,QAAQ;iBACf,CAAC,CAAC;YACL,CAAC;YAED,OAAO,IAAI,WAAW,CAAC;gBACrB,OAAO,EAAE,SAAS,QAAQ,wCAAwC,MAAM,sBAAsB;gBAC9F,YAAY,EAAE,QAAQ,CAAC,EAAE;gBACzB,IAAI,EAAE,QAAQ;aACf,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC;AASD,SAAS,mBAAmB,CAC1B,QAAgB,EAChB,UAAkB,EAClB,IAA6B,EAC7B,QAA+C,EAC/C,gBAAmD;IAEnD,IAAI,UAAU,EAAE,CAAC;QACf,6EAA6E;QAC7E,4EAA4E;QAC5E,4EAA4E;QAC5E,8EAA8E;QAC9E,+EAA+E;QAC/E,EAAE;QACF,yEAAyE;QACzE,+EAA+E;QAC/E,6EAA6E;QAC7E,2EAA2E;QAC3E,8EAA8E;QAC9E,gEAAgE;QAChE,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO;gBACL,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,OAAO,EAAE,sBAAsB,CAAC,MAAM,CAAC,eAAe,EAAE,QAAQ,EAAE,IAAI,CAAC;gBACvE,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;QACJ,CAAC;QACD,yEAAyE;QACzE,0CAA0C;QAC1C,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAChF,CAAC;IAED,8EAA8E;IAC9E,2EAA2E;IAC3E,8EAA8E;IAC9E,wDAAwD;IACxD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,QAAQ,EAAE,CAAC;QACb,uEAAuE;QACvE,2EAA2E;QAC3E,sEAAsE;QACtE,IAAI,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnC,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QAC5E,CAAC;QACD,OAAO;YACL,gBAAgB,EAAE,IAAI;YACtB,OAAO,EAAE,sBAAsB,CAAC,yBAAyB,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC;YACpF,MAAM,EAAE,kBAAkB;SAC3B,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;AAC9E,CAAC;AAED,8EAA8E;AAC9E,MAAM,kBAAkB,GAAsC,IAAI,GAAG,EAAE,CAAC;AAIxE;;;;;;;;;;GAUG;AACH,SAAS,oBAAoB,CAC3B,MAA0B,EAC1B,QAAqE,EACrE,UAAkB,EAClB,QAA0C,EAC1C,MAA2B,EAC3B,YAA0B;IAE1B,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU;QAAE,OAAO;IAErC,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc;QACvC,CAAC,CAAC,0BAA0B,CAAC,MAAM,CAAC,cAAc,EAAE;YAChD,QAAQ,EAAE,QAAQ,CAAC,IAAI;YACvB,aAAa,EAAE,UAAU;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;SACpB,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,CAAC,GAAG,CACT,yBAAyB;QACzB,IAAI,CAAC,SAAS,CAAC;YACb,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;YACrC,UAAU,EAAE,QAAQ,CAAC,EAAE;YACvB,QAAQ,EAAE,QAAQ,CAAC,IAAI;YACvB,aAAa,EAAE,UAAU;YACzB,QAAQ,EAAE,QAAQ,IAAI,EAAE;YACxB,aAAa,EAAE,MAAM;YACrB,YAAY;YACZ,mBAAmB,EAAE,qBAAqB;YAC1C,WAAW;YACX,SAAS,EAAE,YAAY;SACxB,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -81,11 +81,8 @@ export interface CostCapConfig {
|
|
|
81
81
|
export interface OtelSpansConfig {
|
|
82
82
|
readonly toolServerMap: ReadonlyMap<string, string>;
|
|
83
83
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
readonly autoApproveAll: boolean;
|
|
87
|
-
readonly toolServerMap: ReadonlyMap<string, string>;
|
|
88
|
-
}
|
|
84
|
+
import type { ApprovalGateConfig } from "./approval-gate.js";
|
|
85
|
+
export type { ApprovalGateConfig };
|
|
89
86
|
/**
|
|
90
87
|
* Top-level configuration for buildMiddlewareStack().
|
|
91
88
|
* All sections are optional — the factory applies sensible defaults.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed Temporal activity input shared by ExecuteCursor and ExecuteDeepAgent.
|
|
3
|
+
*
|
|
4
|
+
* The Go and Java control planes now invoke these activities with a single
|
|
5
|
+
* object carrying snake_case keys (mirroring the polyglot workflow-input
|
|
6
|
+
* convention) instead of positional string args. This ends the prior drift
|
|
7
|
+
* where Go sent (executionId, threadId) and Java sent
|
|
8
|
+
* (executionId, threadId, invokerIdentityAccountId) while this single runner
|
|
9
|
+
* read only the first two positionally.
|
|
10
|
+
*
|
|
11
|
+
* TRANSITIONAL DUAL-SHAPE: the activity is MaximumAttempts=1 (a failed activity
|
|
12
|
+
* fails the execution with no retry), and the control plane and this runner
|
|
13
|
+
* deploy separately. To make the rollout order-independent, the runner accepts
|
|
14
|
+
* BOTH the new object and the legacy positional args. Deploy the runner first,
|
|
15
|
+
* then the control planes; once both are everywhere, drop the positional branch
|
|
16
|
+
* (and the `string` arms below).
|
|
17
|
+
*/
|
|
18
|
+
export interface ExecuteActivityInput {
|
|
19
|
+
readonly execution_id: string;
|
|
20
|
+
readonly thread_id: string;
|
|
21
|
+
/** Carried for cross-edition parity; the runner hydrates the invoker from the DB. */
|
|
22
|
+
readonly invoker_identity_account_id?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Monotonic HITL-cycle index within this execution: 0 on the first invocation,
|
|
25
|
+
* then the workflow's approvalCycle on each reinvocation. The Cursor producer
|
|
26
|
+
* mints its deterministic file-review change-set id ({@code executionId:turnSeq})
|
|
27
|
+
* from it. Absent on the legacy positional wire shape (defaults to 0).
|
|
28
|
+
*/
|
|
29
|
+
readonly turn_seq?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface NormalizedActivityInput {
|
|
32
|
+
readonly executionId: string;
|
|
33
|
+
readonly threadId: string;
|
|
34
|
+
/** HITL-cycle index for this invocation; 0 on the first turn / legacy wire shape. */
|
|
35
|
+
readonly turnSeq: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Normalizes either the new typed object or the legacy positional args into the
|
|
39
|
+
* `{ executionId, threadId, turnSeq }` the inner activity path consumes.
|
|
40
|
+
* `thread_id` is empty on a first invocation (new harness state) and `turn_seq`
|
|
41
|
+
* defaults to 0 (first turn, or the legacy positional shape that never carried it).
|
|
42
|
+
*/
|
|
43
|
+
export declare function normalizeActivityInput(arg0: ExecuteActivityInput | string | undefined, arg1?: string): NormalizedActivityInput;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes either the new typed object or the legacy positional args into the
|
|
3
|
+
* `{ executionId, threadId, turnSeq }` the inner activity path consumes.
|
|
4
|
+
* `thread_id` is empty on a first invocation (new harness state) and `turn_seq`
|
|
5
|
+
* defaults to 0 (first turn, or the legacy positional shape that never carried it).
|
|
6
|
+
*/
|
|
7
|
+
export function normalizeActivityInput(arg0, arg1) {
|
|
8
|
+
if (arg0 !== null && typeof arg0 === "object") {
|
|
9
|
+
return {
|
|
10
|
+
executionId: arg0.execution_id ?? "",
|
|
11
|
+
threadId: arg0.thread_id ?? "",
|
|
12
|
+
turnSeq: arg0.turn_seq ?? 0,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return { executionId: arg0 ?? "", threadId: arg1 ?? "", turnSeq: 0 };
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=activity-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-input.js","sourceRoot":"","sources":["../../src/shared/activity-input.ts"],"names":[],"mappings":"AAsCA;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAA+C,EAC/C,IAAa;IAEb,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,EAAE;YACpC,QAAQ,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;YAC9B,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,CAAC;SAC5B,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ToolActionInput {
|
|
2
|
+
toolName: string;
|
|
3
|
+
mcpServerSlug?: string;
|
|
4
|
+
paths?: string[];
|
|
5
|
+
shellCommand?: string;
|
|
6
|
+
args?: Record<string, unknown>;
|
|
7
|
+
secretKeys?: string[];
|
|
8
|
+
workspaceRoot?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CanonicalToolAction {
|
|
11
|
+
toolName: string;
|
|
12
|
+
mcpServerSlug: string;
|
|
13
|
+
paths: string[];
|
|
14
|
+
shellCommand: string;
|
|
15
|
+
args: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export declare function canonicalizeToolAction(input: ToolActionInput): CanonicalToolAction;
|
|
18
|
+
export declare function canonicalToolActionJson(input: ToolActionInput): string;
|
|
19
|
+
export declare function canonicalJson(value: unknown): string;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Deterministic canonicalization of a tool action into a byte-stable form.
|
|
2
|
+
// Domain: HITL approval. This is the cross-language contract the approval
|
|
3
|
+
// fingerprint (Phase 2) will hash; Phase 1 *defines and computes* it without
|
|
4
|
+
// hashing, so Go/Java/TS can be pinned to byte-identical output via the shared
|
|
5
|
+
// vector corpus (apis/testdata/hitl/canonicalization/).
|
|
6
|
+
//
|
|
7
|
+
// Why this exists: the March 2026 dedup bug was caused by hashing divergent
|
|
8
|
+
// representations of the same action (display args in one place, raw args in
|
|
9
|
+
// another). The fix is a single, explicit normalization pass — applied at ONE
|
|
10
|
+
// layer — that erases incidental differences (path separators, workspace
|
|
11
|
+
// location, shell whitespace, MCP slug case, secret values) before any hash.
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import { posix } from "node:path";
|
|
14
|
+
export function canonicalizeToolAction(input) {
|
|
15
|
+
return {
|
|
16
|
+
toolName: input.toolName.trim(),
|
|
17
|
+
// Slugs are case-insensitive identity; lowercase so "GitHub" == "github".
|
|
18
|
+
mcpServerSlug: (input.mcpServerSlug ?? "").trim().toLowerCase(),
|
|
19
|
+
paths: normalizePaths(input.paths ?? [], input.workspaceRoot),
|
|
20
|
+
shellCommand: normalizeShellCommand(input.shellCommand ?? ""),
|
|
21
|
+
args: redactSecrets(input.args ?? {}, new Set(input.secretKeys ?? [])),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// canonicalToolActionJson is the single entry point: normalize, then serialize
|
|
25
|
+
// to canonical JSON. The returned string is the byte-stable contract value.
|
|
26
|
+
export function canonicalToolActionJson(input) {
|
|
27
|
+
return canonicalJson(canonicalizeToolAction(input));
|
|
28
|
+
}
|
|
29
|
+
// canonicalJson serializes a value to RFC 8785-style canonical JSON: object keys
|
|
30
|
+
// sorted by UTF-16 code unit, no insignificant whitespace, UTF-8 output.
|
|
31
|
+
//
|
|
32
|
+
// The input domain is deliberately constrained to strings, booleans, null,
|
|
33
|
+
// integers, arrays, and plain objects — the shape of a normalized tool action.
|
|
34
|
+
// Non-integer numbers are rejected rather than implementing RFC 8785's full
|
|
35
|
+
// number-formatting algorithm, keeping this hand-rolled serializer small and
|
|
36
|
+
// provably cross-language without a third-party dependency. Revisit if the
|
|
37
|
+
// canonical domain ever needs floats.
|
|
38
|
+
export function canonicalJson(value) {
|
|
39
|
+
return serialize(value);
|
|
40
|
+
}
|
|
41
|
+
function serialize(v) {
|
|
42
|
+
if (v === null)
|
|
43
|
+
return "null";
|
|
44
|
+
switch (typeof v) {
|
|
45
|
+
case "boolean":
|
|
46
|
+
return v ? "true" : "false";
|
|
47
|
+
case "number":
|
|
48
|
+
if (!Number.isFinite(v))
|
|
49
|
+
throw new Error("canonicalJson: non-finite number");
|
|
50
|
+
if (!Number.isInteger(v)) {
|
|
51
|
+
throw new Error("canonicalJson: non-integer numbers are not part of the canonical contract");
|
|
52
|
+
}
|
|
53
|
+
return String(v);
|
|
54
|
+
case "string":
|
|
55
|
+
// JSON.stringify produces the same minimal escaping and raw UTF-8 for
|
|
56
|
+
// non-ASCII that RFC 8785 mandates for these inputs.
|
|
57
|
+
return JSON.stringify(v);
|
|
58
|
+
case "object":
|
|
59
|
+
if (Array.isArray(v))
|
|
60
|
+
return "[" + v.map(serialize).join(",") + "]";
|
|
61
|
+
return serializeObject(v);
|
|
62
|
+
default:
|
|
63
|
+
throw new Error(`canonicalJson: unsupported type ${typeof v}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function serializeObject(obj) {
|
|
67
|
+
// `undefined`-valued keys are dropped (they have no JSON representation);
|
|
68
|
+
// remaining keys are sorted by UTF-16 code unit, which is JS's default string
|
|
69
|
+
// ordering and matches RFC 8785.
|
|
70
|
+
const keys = Object.keys(obj)
|
|
71
|
+
.filter((k) => obj[k] !== undefined)
|
|
72
|
+
.sort(compareUtf16);
|
|
73
|
+
const parts = keys.map((k) => JSON.stringify(k) + ":" + serialize(obj[k]));
|
|
74
|
+
return "{" + parts.join(",") + "}";
|
|
75
|
+
}
|
|
76
|
+
function compareUtf16(a, b) {
|
|
77
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
78
|
+
}
|
|
79
|
+
function normalizePaths(paths, workspaceRoot) {
|
|
80
|
+
return paths.map((p) => normalizeOnePath(p, workspaceRoot)).sort(compareUtf16);
|
|
81
|
+
}
|
|
82
|
+
function normalizeOnePath(p, workspaceRoot) {
|
|
83
|
+
// Separator-normalize to forward slashes first so Windows and POSIX agree.
|
|
84
|
+
let s = p.replace(/\\/g, "/");
|
|
85
|
+
if (workspaceRoot) {
|
|
86
|
+
const root = workspaceRoot.replace(/\\/g, "/");
|
|
87
|
+
if (s === root) {
|
|
88
|
+
s = "";
|
|
89
|
+
}
|
|
90
|
+
else if (s.startsWith(root + "/")) {
|
|
91
|
+
s = s.slice(root.length + 1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Collapse `.`/`..` segments deterministically. posix.normalize("") -> ".".
|
|
95
|
+
return s === "" ? "" : posix.normalize(s);
|
|
96
|
+
}
|
|
97
|
+
function normalizeShellCommand(cmd) {
|
|
98
|
+
// Collapse runs of whitespace to a single space and trim. The argument VALUE
|
|
99
|
+
// (the command) is what matters; incidental spacing is not identity.
|
|
100
|
+
return cmd.replace(/\s+/g, " ").trim();
|
|
101
|
+
}
|
|
102
|
+
function redactSecrets(args, secretKeys) {
|
|
103
|
+
if (secretKeys.size === 0)
|
|
104
|
+
return args;
|
|
105
|
+
const out = {};
|
|
106
|
+
for (const [k, v] of Object.entries(args)) {
|
|
107
|
+
out[k] = secretKeys.has(k) ? redactValue(v) : v;
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
function redactValue(v) {
|
|
112
|
+
// Redact-but-stable: a SHA-256 digest keeps the canonical form stable across
|
|
113
|
+
// runs without ever placing the secret in cleartext. This is NOT the approval
|
|
114
|
+
// fingerprint — that is an HMAC keyed on a Stigmer secret, introduced in
|
|
115
|
+
// Phase 2. This digest is unkeyed redaction only.
|
|
116
|
+
const material = typeof v === "string" ? v : canonicalJson(v);
|
|
117
|
+
return "sha256:" + createHash("sha256").update(material, "utf8").digest("hex");
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=approval-canonicalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-canonicalize.js","sourceRoot":"","sources":["../../src/shared/approval-canonicalize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval fingerprint — the exact-match enforcement identity for the HITL Tool
|
|
3
|
+
* Execution Gateway (Phase 2).
|
|
4
|
+
*
|
|
5
|
+
* A fingerprint is `HMAC-SHA256(key, canonicalForm)` over a canonicalized tool
|
|
6
|
+
* action (see {@link file://./approval-canonicalize.ts}). It answers exactly one
|
|
7
|
+
* question at the moment of side effect: "is *this* action the one the user
|
|
8
|
+
* approved?" An approval is bound to the canonical identity of the action, not to
|
|
9
|
+
* the transient id of the proposing tool call, so a re-driven action that differs
|
|
10
|
+
* from what was approved is re-asked — never silently executed.
|
|
11
|
+
*
|
|
12
|
+
* Why HMAC and not a bare SHA-256 (binding canonical decision,
|
|
13
|
+
* design-decisions/approval-fingerprint-vs-march-rollback.md, Rule 4): the
|
|
14
|
+
* fingerprint is an authorization token, not a correlation key. Keying it under a
|
|
15
|
+
* Stigmer-held secret means a model (or a compromised workspace) cannot forge a
|
|
16
|
+
* value that the gateway will accept. In Phase 2 the fingerprint is
|
|
17
|
+
* recompute-and-compare at one trusted layer (no bearer token crosses a wire), so
|
|
18
|
+
* the anti-forgery property is forward-looking — it earns its keep when a lease
|
|
19
|
+
* later becomes a server-issued bearer token (Phase 7). We pay the small cost now
|
|
20
|
+
* to avoid a migration that re-keys every persisted approval later.
|
|
21
|
+
*
|
|
22
|
+
* Two fidelities share this one canonicalization core, because the two
|
|
23
|
+
* enforcement substrates differ (see the Phase-2 plan, "two enforcement
|
|
24
|
+
* substrates, not one"):
|
|
25
|
+
*
|
|
26
|
+
* - FULL ({@link computeApprovalFingerprint}) — HMAC over the full canonical
|
|
27
|
+
* action (tool + paths + shellCommand + args). Used by the in-process
|
|
28
|
+
* deep-agent gateway, where approve-time and execute-time observe the same
|
|
29
|
+
* arg shape (LangGraph checkpoint replay), so the action can be matched at
|
|
30
|
+
* full fidelity.
|
|
31
|
+
* - COARSE ({@link computeCoarseApprovalFingerprint}) — HMAC over
|
|
32
|
+
* (category, salient) only. Used by the out-of-process Cursor deny-oracle
|
|
33
|
+
* hook, whose stdin payload names the same action with a different taxonomy
|
|
34
|
+
* (`Write` vs `edit`, `file_path` vs `path`) and cannot reproduce the full
|
|
35
|
+
* args. The coarse projection is the documented, substrate-forced coarsening
|
|
36
|
+
* that lets the hook-side and stream-side fingerprints agree; it is the
|
|
37
|
+
* successor identity for execute-cursor's grant token.
|
|
38
|
+
*
|
|
39
|
+
* The fingerprint is enforcement-only and never a correlation key — correlation
|
|
40
|
+
* stays `approval_request_id` + `tool_call_id`.
|
|
41
|
+
*/
|
|
42
|
+
import { type BinaryLike } from "node:crypto";
|
|
43
|
+
import { type ToolActionInput } from "./approval-canonicalize.js";
|
|
44
|
+
/**
|
|
45
|
+
* Version tag prefixed to every fingerprint. Bumping it is the migration lever
|
|
46
|
+
* if the canonical form or the MAC primitive ever changes: an old lease and a
|
|
47
|
+
* new computation will not compare equal, so a version skew re-asks (safe) rather
|
|
48
|
+
* than silently mismatching. Keep in lockstep with the Go/Java editions.
|
|
49
|
+
*/
|
|
50
|
+
export declare const APPROVAL_FINGERPRINT_VERSION = "v1";
|
|
51
|
+
/** The HMAC key. Raw bytes (Buffer) in production; a UTF-8 string in tests. */
|
|
52
|
+
export type FingerprintKey = BinaryLike;
|
|
53
|
+
/**
|
|
54
|
+
* Full-fidelity fingerprint for the in-process deep-agent gateway. Distinct
|
|
55
|
+
* actions (different tool, paths, command, or args) yield distinct fingerprints;
|
|
56
|
+
* the same action is byte-stable across re-invocations.
|
|
57
|
+
*/
|
|
58
|
+
export declare function computeApprovalFingerprint(key: FingerprintKey, input: ToolActionInput): string;
|
|
59
|
+
/**
|
|
60
|
+
* The substrate-coarsened identity of a tool action — the only fidelity the
|
|
61
|
+
* Cursor deny-oracle hook can reproduce from its stdin payload.
|
|
62
|
+
*
|
|
63
|
+
* Mirrors execute-cursor's `toolIdentity` so the two converge on one definition:
|
|
64
|
+
* - `tool` is the cross-taxonomy {@link toolApprovalCategory} (`write`/`delete`/
|
|
65
|
+
* `shell`) for gated built-ins, the tool name for MCP tools (whose name is
|
|
66
|
+
* stable across layers), or the trimmed tool name for non-gated built-ins
|
|
67
|
+
* (never lease-matched, so the fallback is harmless).
|
|
68
|
+
* - `salient` is the single resource the action targets (a normalized path or the
|
|
69
|
+
* shell command), reusing the full form's normalization so one rule governs
|
|
70
|
+
* both fidelities. Empty for MCP tools, which are matched by `tool` alone.
|
|
71
|
+
*/
|
|
72
|
+
export interface CoarseToolIdentity {
|
|
73
|
+
tool: string;
|
|
74
|
+
mcpServerSlug: string;
|
|
75
|
+
salient: string;
|
|
76
|
+
}
|
|
77
|
+
export declare function coarseToolIdentity(input: ToolActionInput): CoarseToolIdentity;
|
|
78
|
+
/**
|
|
79
|
+
* Fingerprint an already-reduced {@link CoarseToolIdentity}. Split out from
|
|
80
|
+
* {@link computeCoarseApprovalFingerprint} so a substrate that has *already*
|
|
81
|
+
* reduced a tool call to its (tool, mcpServerSlug, salient) identity — the Cursor
|
|
82
|
+
* harness, whose hook and stream both key on a raw, un-normalized salient that
|
|
83
|
+
* the bash hook can reproduce without a workspace root — can fingerprint that
|
|
84
|
+
* exact identity through the one shared HMAC+canonical-JSON path, instead of
|
|
85
|
+
* re-deriving the salient via {@link canonicalizeToolAction} (which normalizes
|
|
86
|
+
* paths and would diverge from the hook's raw value).
|
|
87
|
+
*/
|
|
88
|
+
export declare function fingerprintCoarseIdentity(key: FingerprintKey, identity: CoarseToolIdentity): string;
|
|
89
|
+
/**
|
|
90
|
+
* Coarse fingerprint for the out-of-process Cursor hook. By construction, two
|
|
91
|
+
* actions that name the same operation in different taxonomies (`Write` vs
|
|
92
|
+
* `edit`) over the same resource collapse to one fingerprint — this is what makes
|
|
93
|
+
* the hook-side (deny/grant) and stream-side (reconciliation) values agree.
|
|
94
|
+
*/
|
|
95
|
+
export declare function computeCoarseApprovalFingerprint(key: FingerprintKey, input: ToolActionInput): string;
|
|
96
|
+
/**
|
|
97
|
+
* Derive the per-execution fingerprint key from a runner-held master secret.
|
|
98
|
+
*
|
|
99
|
+
* The key is scoped to one `execution_id`: stable across Temporal re-invocations
|
|
100
|
+
* of the same execution (the gateway approves on one invocation and enforces on
|
|
101
|
+
* the next), and isolated between executions so a fingerprint approved for one
|
|
102
|
+
* cannot be replayed against another. The master-secret source is wired when the
|
|
103
|
+
* gateway first consumes the fingerprint (Slices C/D); until then this is
|
|
104
|
+
* exercised only by tests against a fixed master secret.
|
|
105
|
+
*/
|
|
106
|
+
export declare function deriveExecutionFingerprintKey(masterSecret: FingerprintKey, executionId: string): Buffer;
|