@stigmer/runner 3.0.9-dev.20260615153829 → 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 +16 -3
- package/dist/activities/execute-deep-agent/hitl.js +11 -3
- 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 +393 -33
- 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 +17 -5
- package/dist/activities/execute-deep-agent/status-builder.js +44 -3
- 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 +32 -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 +284 -0
- package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +14 -36
- 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 +91 -10
- 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 +23 -7
- package/src/activities/execute-deep-agent/index.ts +463 -40
- 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 +63 -8
- 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 +36 -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
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor adapter over the harness-agnostic capture-mode orchestration
|
|
3
|
+
* ({@link ../../shared/filereview/capture.js}).
|
|
4
|
+
*
|
|
5
|
+
* The substrate (git snapshot/restore) and the orchestration (baseline/candidate/
|
|
6
|
+
* reconcile authoring) live in `shared/filereview/` so the Cursor and deep-agent
|
|
7
|
+
* harnesses author IDENTICAL ledger entries. This adapter binds the Cursor
|
|
8
|
+
* specifics:
|
|
9
|
+
* - `harnessId = "cursor"` (stamped on the BASELINE payload the projection reads);
|
|
10
|
+
* - the Cursor gate files written into the workspace, excluded from the captured
|
|
11
|
+
* diff (`CURSOR_RUNNER_OWNED_PATHS`);
|
|
12
|
+
* - stamping the streamed file-edit transcript rows that flowed this turn with
|
|
13
|
+
* the change set id (`stampFlowedFileEditRows`) — the rows stay visible as
|
|
14
|
+
* observational/audit records at their transcript positions, while
|
|
15
|
+
* `file_change_sets` remains the single DECISION surface.
|
|
16
|
+
*
|
|
17
|
+
* The three turn-boundary functions keep their original signatures so the
|
|
18
|
+
* activity wiring (index.ts) and the cutover tests are unchanged.
|
|
19
|
+
*/
|
|
20
|
+
import { readFile } from "node:fs/promises";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { FileCaptureClass } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
23
|
+
import { approvalCategory } from "./approval-policy.js";
|
|
24
|
+
import { toolIdentity, primaryToken } from "./approval-state.js";
|
|
25
|
+
import { readCasObservations } from "./cas-observations.js";
|
|
26
|
+
import { contentDigest } from "../../shared/file-tools.js";
|
|
27
|
+
import { isToolCallRowHidden, stampFileEditRow } from "../../shared/tool-row.js";
|
|
28
|
+
import { applyCaptureDecisions as sharedApplyCaptureDecisions, captureBaselineToLedger as sharedCaptureBaselineToLedger, captureCandidateToLedger as sharedCaptureCandidateToLedger, } from "../../shared/filereview/capture.js";
|
|
29
|
+
import { hasCandidateCaptured } from "../../shared/filereview/events.js";
|
|
30
|
+
import { partitionIgnoredPathsBySecret } from "../../shared/filereview/secret-paths.js";
|
|
31
|
+
import { casBlobReader } from "../../shared/filereview/cas-substrate.js";
|
|
32
|
+
/** The harness id the projection reads from the BASELINE payload (load-bearing). */
|
|
33
|
+
const HARNESS_ID = "cursor";
|
|
34
|
+
/**
|
|
35
|
+
* Workspace-relative paths the Cursor gate writes into the repo. They are excluded
|
|
36
|
+
* from capture so a turn's diff never shows the gate's own machinery. (The
|
|
37
|
+
* workspace-scoped gate dir and SDK state live under `~/.stigmer` / the
|
|
38
|
+
* git-excluded `.stigmer`, so they need no exclusion here.)
|
|
39
|
+
*/
|
|
40
|
+
const CURSOR_RUNNER_OWNED_PATHS = [
|
|
41
|
+
".cursor/hooks.json",
|
|
42
|
+
".cursor/rules/stigmer-tool-approval.mdc",
|
|
43
|
+
];
|
|
44
|
+
// `deriveCaptureMode` is the single capture-vs-deny-gate decision, now shared by
|
|
45
|
+
// BOTH harnesses from `shared/filereview/capture.ts`. Re-exported here so existing
|
|
46
|
+
// Cursor imports (index.ts, the deny-gate-exact-apply seam test) keep resolving
|
|
47
|
+
// from this adapter.
|
|
48
|
+
export { deriveCaptureMode } from "../../shared/filereview/capture.js";
|
|
49
|
+
/**
|
|
50
|
+
* Turn start: pin the pre-turn working tree behind the baseline ref and author
|
|
51
|
+
* BASELINE_CAPTURED (harnessId "cursor"). Returns the baseline tree sha for the
|
|
52
|
+
* turn-end diff.
|
|
53
|
+
*/
|
|
54
|
+
export function captureBaselineToLedger(opts) {
|
|
55
|
+
return sharedCaptureBaselineToLedger({
|
|
56
|
+
...opts,
|
|
57
|
+
harnessId: HARNESS_ID,
|
|
58
|
+
excludePaths: CURSOR_RUNNER_OWNED_PATHS,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Turn end: capture the change set + author CANDIDATE_CAPTURED, then stamp the
|
|
63
|
+
* streamed file-edit rows that flowed this turn with the change set id — the
|
|
64
|
+
* rows stay visible in place as observational records while `file_change_sets`
|
|
65
|
+
* remains the single decision surface. The working tree is LEFT applied
|
|
66
|
+
* (Cursor parity).
|
|
67
|
+
*
|
|
68
|
+
* The change set is HYBRID (git tree) or CAS-only (non-git): the hook-staged
|
|
69
|
+
* writes from the cas-observations sidecar this turn ({@link readCasObservations})
|
|
70
|
+
* — the Cursor analog of deep-agent's `buildCasTurnCaptures` — composed with the
|
|
71
|
+
* git-tracked diff when `gitWorkspace`. Non-secret staged paths become
|
|
72
|
+
* `GIT_IGNORED_CAPTURED` (git tree) or `NON_GIT_CAS` (non-git) CAS captures
|
|
73
|
+
* (before-bytes from the sidecar, after-bytes re-read from disk);
|
|
74
|
+
* secret-blocked paths become content-less `DIFF_UNREVIEWABLE` entries. The
|
|
75
|
+
* boundary re-runs {@link partitionIgnoredPathsBySecret} as a fail-closed
|
|
76
|
+
* backstop, so a secret that ever slipped into the captured set still has its
|
|
77
|
+
* bytes withheld from durable storage.
|
|
78
|
+
*
|
|
79
|
+
* `deniedTokens` are the identities the hook gated this turn (shell/MCP, or a
|
|
80
|
+
* gitignored delete). A streamed file-edit row whose identity is in that set is
|
|
81
|
+
* left for the deny-gate reconcile path — it did NOT flow. A flowed gitignored
|
|
82
|
+
* write is NOT in that set (the hook allowed it), so it is stamped like any
|
|
83
|
+
* other flowed edit and its captured delta surfaces as a CAS entry in the set.
|
|
84
|
+
*
|
|
85
|
+
* `hitlDir`/`storage` are omitted only by callers with no artifact storage
|
|
86
|
+
* (captureIgnored off); the CAS half is then skipped and this is a git-only
|
|
87
|
+
* capture exactly as before.
|
|
88
|
+
*
|
|
89
|
+
* Mutates `messages` and `status` in place. Returns the captured git changes.
|
|
90
|
+
*/
|
|
91
|
+
export async function captureTurnToLedger(opts) {
|
|
92
|
+
const { status, gitRoot, executionId, changeSetId, baselineTree, messages, deniedTokens, hitlDir, storage, priorSubAgentToolCallIds, commandProvenance } = opts;
|
|
93
|
+
const gitWorkspace = opts.gitWorkspace ?? true;
|
|
94
|
+
// The CAS substrate class for this turn's staged writes: gitignored paths in a
|
|
95
|
+
// git tree, all touched paths in a non-git workspace.
|
|
96
|
+
const casCaptureClass = gitWorkspace
|
|
97
|
+
? FileCaptureClass.GIT_IGNORED_CAPTURED
|
|
98
|
+
: FileCaptureClass.NON_GIT_CAS;
|
|
99
|
+
const { casCaptures, unreviewablePaths } = await buildCasTurnCaptures(gitRoot, hitlDir, storage, casCaptureClass);
|
|
100
|
+
const changes = await sharedCaptureCandidateToLedger({
|
|
101
|
+
status,
|
|
102
|
+
gitRoot,
|
|
103
|
+
executionId,
|
|
104
|
+
changeSetId,
|
|
105
|
+
baselineTree,
|
|
106
|
+
harnessId: HARNESS_ID,
|
|
107
|
+
excludePaths: CURSOR_RUNNER_OWNED_PATHS,
|
|
108
|
+
casCaptures,
|
|
109
|
+
storage,
|
|
110
|
+
unreviewablePaths,
|
|
111
|
+
unreviewableCaptureClass: casCaptureClass,
|
|
112
|
+
gitWorkspace,
|
|
113
|
+
commandProvenance,
|
|
114
|
+
});
|
|
115
|
+
// Observational rows: the reviewable diff lives on the file_review ledger
|
|
116
|
+
// (projected to file_change_sets); the streamed file-edit rows that flowed
|
|
117
|
+
// this turn stay visible in place, stamped with the change set id so clients
|
|
118
|
+
// badge them and anchor the decision surface. Denied (gitignored-delete/
|
|
119
|
+
// shell) rows stay on the deny-gate path. Gated on an authored CANDIDATE —
|
|
120
|
+
// a no-op turn (every edit reverted before the boundary) authors no event,
|
|
121
|
+
// and a row must never reference a change set that does not exist.
|
|
122
|
+
if (hasCandidateCaptured(status, changeSetId)) {
|
|
123
|
+
stampFlowedFileEditRows(messages, deniedTokens, changeSetId);
|
|
124
|
+
// Sub-agent edit rows fold their files into the SAME parent turn set, so they
|
|
125
|
+
// carry the same change set id. Walked separately (they live under
|
|
126
|
+
// subAgentExecutions, not the top-level transcript) and scoped to this turn
|
|
127
|
+
// via the pre-turn snapshot of seeded sub-agent tool-call ids.
|
|
128
|
+
for (const sa of status.subAgentExecutions) {
|
|
129
|
+
stampFlowedFileEditRows(sa.messages, deniedTokens, changeSetId, priorSubAgentToolCallIds);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return changes;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Compose this turn's CAS captures from the sidecar the hook staged, mirroring
|
|
136
|
+
* deep-agent's `buildCasTurnCaptures`: for each non-secret observed path, the
|
|
137
|
+
* before-bytes come from the sidecar and the after-bytes are re-read from disk now
|
|
138
|
+
* (`null` = the file was removed after the write). Secret-blocked paths are
|
|
139
|
+
* returned as `unreviewablePaths`. The secret partition is re-run as a
|
|
140
|
+
* fail-closed backstop over the observed set. `captureClass` labels each captured
|
|
141
|
+
* path's provenance (GIT_IGNORED_CAPTURED for a git tree's ignored paths,
|
|
142
|
+
* NON_GIT_CAS for a non-git workspace).
|
|
143
|
+
*
|
|
144
|
+
* Returns empty when the harness has no storage (captureIgnored off) or the
|
|
145
|
+
* sidecar is empty — leaving the shared capture unchanged.
|
|
146
|
+
*/
|
|
147
|
+
async function buildCasTurnCaptures(gitRoot, hitlDir, storage, captureClass) {
|
|
148
|
+
if (!hitlDir || !storage)
|
|
149
|
+
return { casCaptures: [], unreviewablePaths: [] };
|
|
150
|
+
const { captured, secretPaths } = await readCasObservations(hitlDir);
|
|
151
|
+
const beforeByPath = new Map(captured.map((c) => [c.path, c.before]));
|
|
152
|
+
const { capturablePaths, unreviewablePaths } = partitionIgnoredPathsBySecret(beforeByPath.keys(), new Set(secretPaths));
|
|
153
|
+
const casCaptures = [];
|
|
154
|
+
for (const relPath of capturablePaths) {
|
|
155
|
+
const after = await readFileOrNull(join(gitRoot, relPath));
|
|
156
|
+
casCaptures.push({
|
|
157
|
+
path: relPath,
|
|
158
|
+
before: beforeByPath.get(relPath) ?? null,
|
|
159
|
+
after,
|
|
160
|
+
captureClass,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return { casCaptures, unreviewablePaths: [...unreviewablePaths] };
|
|
164
|
+
}
|
|
165
|
+
/** Raw bytes of a file, or `null` when it does not exist (an ADD-then-removed). */
|
|
166
|
+
async function readFileOrNull(absolutePath) {
|
|
167
|
+
try {
|
|
168
|
+
return await readFile(absolutePath);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Resume: reconcile the working tree to the change set's DECIDED decisions
|
|
176
|
+
* (keep approved "after" bytes, snap rejected/undecided back to baseline,
|
|
177
|
+
* hash-verified), author RECONCILED / FAILED, and release the refs. Delegates to
|
|
178
|
+
* the shared orchestration with the Cursor harness id + exclude paths.
|
|
179
|
+
*
|
|
180
|
+
* `storage` threads the CAS blob store + reader so gitignored (CAS) files in the
|
|
181
|
+
* change set reconcile from the durable manifest — approved after-blobs written
|
|
182
|
+
* (hash-verified), rejected files snapped back to their before-blobs. Omit for a
|
|
183
|
+
* git-only harness/turn; the shared CAS branch is then skipped. The read path is
|
|
184
|
+
* the same one `exact-apply` already uses (`ArtifactStorage.download`).
|
|
185
|
+
*/
|
|
186
|
+
export function applyCaptureDecisions(opts) {
|
|
187
|
+
const { storage, ...rest } = opts;
|
|
188
|
+
return sharedApplyCaptureDecisions({
|
|
189
|
+
...rest,
|
|
190
|
+
harnessId: HARNESS_ID,
|
|
191
|
+
excludePaths: CURSOR_RUNNER_OWNED_PATHS,
|
|
192
|
+
storage,
|
|
193
|
+
readBlob: storage ? casBlobReader(storage) : undefined,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
// Cursor-specific presentation
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
/**
|
|
200
|
+
* Stamp every streamed file-edit row (category write/delete) that flowed this
|
|
201
|
+
* turn with the change set id, so the row stays visible as an observational
|
|
202
|
+
* record and clients can badge it / anchor the decision surface. Skips:
|
|
203
|
+
* - already-stamped rows — the stamp is the idempotency AND cross-turn guard:
|
|
204
|
+
* a resume seeds prior turns' rows into this transcript, and re-stamping
|
|
205
|
+
* them with this turn's id would mis-attribute them ({@link stampFileEditRow});
|
|
206
|
+
* - legacy hidden rows (sessions persisted before stamping existed) — they
|
|
207
|
+
* belong to an earlier turn's change set, not this one;
|
|
208
|
+
* - denied identities (the deny-gate reconcile path owns those rows);
|
|
209
|
+
* - tool-call ids in `skipToolCallIds` — used for sub-agent rows, which lack
|
|
210
|
+
* the already-stamped/hidden shields the top-level transcript has, to scope
|
|
211
|
+
* the stamp to rows created this turn (the seeded prior sub-agents' ids).
|
|
212
|
+
*/
|
|
213
|
+
function stampFlowedFileEditRows(messages, deniedTokens, changeSetId, skipToolCallIds) {
|
|
214
|
+
for (const msg of messages) {
|
|
215
|
+
for (const tc of msg.toolCalls) {
|
|
216
|
+
if (tc.fileChangeSetId)
|
|
217
|
+
continue;
|
|
218
|
+
if (skipToolCallIds?.has(tc.id))
|
|
219
|
+
continue;
|
|
220
|
+
if (isToolCallRowHidden(tc))
|
|
221
|
+
continue;
|
|
222
|
+
const category = approvalCategory(tc.name);
|
|
223
|
+
if (category !== "write" && category !== "delete")
|
|
224
|
+
continue;
|
|
225
|
+
const args = (tc.args ?? {});
|
|
226
|
+
const id = toolIdentity(tc.name, tc.mcpServerSlug, args);
|
|
227
|
+
const token = primaryToken(id.key, id.salient, contentDigest(args));
|
|
228
|
+
if (deniedTokens.has(token))
|
|
229
|
+
continue; // denied -> reconcile path owns it
|
|
230
|
+
stampFileEditRow(tc, changeSetId);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=capture-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-flow.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/capture-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,8DAA8D,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjF,OAAO,EACL,qBAAqB,IAAI,2BAA2B,EACpD,uBAAuB,IAAI,6BAA6B,EACxD,wBAAwB,IAAI,8BAA8B,GAE3D,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EAAE,aAAa,EAAuB,MAAM,0CAA0C,CAAC;AAM9F,oFAAoF;AACpF,MAAM,UAAU,GAAG,QAAQ,CAAC;AAE5B;;;;;GAKG;AACH,MAAM,yBAAyB,GAAsB;IACnD,oBAAoB;IACpB,yCAAyC;CAC1C,CAAC;AAEF,iFAAiF;AACjF,mFAAmF;AACnF,gFAAgF;AAChF,qBAAqB;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEvE;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAOvC;IACC,OAAO,6BAA6B,CAAC;QACnC,GAAG,IAAI;QACP,SAAS,EAAE,UAAU;QACrB,YAAY,EAAE,yBAAyB;KACxC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IA+BzC;IACC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC;IAChK,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;IAE/C,+EAA+E;IAC/E,sDAAsD;IACtD,MAAM,eAAe,GAAG,YAAY;QAClC,CAAC,CAAC,gBAAgB,CAAC,oBAAoB;QACvC,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC;IACjC,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,MAAM,oBAAoB,CACnE,OAAO,EACP,OAAO,EACP,OAAO,EACP,eAAe,CAChB,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAAC;QACnD,MAAM;QACN,OAAO;QACP,WAAW;QACX,WAAW;QACX,YAAY;QACZ,SAAS,EAAE,UAAU;QACrB,YAAY,EAAE,yBAAyB;QACvC,WAAW;QACX,OAAO;QACP,iBAAiB;QACjB,wBAAwB,EAAE,eAAe;QACzC,YAAY;QACZ,iBAAiB;KAClB,CAAC,CAAC;IAEH,0EAA0E;IAC1E,2EAA2E;IAC3E,6EAA6E;IAC7E,yEAAyE;IACzE,2EAA2E;IAC3E,2EAA2E;IAC3E,mEAAmE;IACnE,IAAI,oBAAoB,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC;QAC9C,uBAAuB,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;QAC7D,8EAA8E;QAC9E,mEAAmE;QACnE,4EAA4E;QAC5E,+DAA+D;QAC/D,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAC3C,uBAAuB,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,wBAAwB,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,KAAK,UAAU,oBAAoB,CACjC,OAAe,EACf,OAA2B,EAC3B,OAAoC,EACpC,YAA8B;IAE9B,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAC;IAE5E,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACrE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAU,CAAC,CAAC,CAAC;IAC/E,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,GAAG,6BAA6B,CAC1E,YAAY,CAAC,IAAI,EAAE,EACnB,IAAI,GAAG,CAAC,WAAW,CAAC,CACrB,CAAC;IAEF,MAAM,WAAW,GAAqB,EAAE,CAAC;IACzC,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3D,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI;YACzC,KAAK;YACL,YAAY;SACb,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC,GAAG,iBAAiB,CAAC,EAAE,CAAC;AACpE,CAAC;AAED,mFAAmF;AACnF,KAAK,UAAU,cAAc,CAAC,YAAoB;IAChD,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAYrC;IACC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAClC,OAAO,2BAA2B,CAAC;QACjC,GAAG,IAAI;QACP,SAAS,EAAE,UAAU;QACrB,YAAY,EAAE,yBAAyB;QACvC,OAAO;QACP,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;KACvD,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,SAAS,uBAAuB,CAC9B,QAAiC,EACjC,YAAiC,EACjC,WAAmB,EACnB,eAAqC;IAErC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;YAC/B,IAAI,EAAE,CAAC,eAAe;gBAAE,SAAS;YACjC,IAAI,eAAe,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAAE,SAAS;YAC1C,IAAI,mBAAmB,CAAC,EAAE,CAAC;gBAAE,SAAS;YACtC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,QAAQ;gBAAE,SAAS;YAC5D,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC;YACxD,MAAM,EAAE,GAAG,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YACzD,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;YACpE,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,SAAS,CAAC,mCAAmC;YAC1E,gBAAgB,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Cursor harness's disk-backed observer for gitignored file writes — the
|
|
3
|
+
* out-of-process analog of the deep-agent `CasCaptureFilesystemBackend`
|
|
4
|
+
* ({@link ../execute-deep-agent/cas-capture-backend.js}).
|
|
5
|
+
*
|
|
6
|
+
* Deep-agent runs the agent in-process, so it records a gitignored file's
|
|
7
|
+
* pre-turn bytes in an in-memory `CasBeforeMap` at the mutation point (before
|
|
8
|
+
* `super.write`). Cursor runs the agent as an EXTERNAL CLI subprocess whose only
|
|
9
|
+
* pre-write interception is the generated preToolUse bash hook — and each hook
|
|
10
|
+
* invocation is a FRESH, EPHEMERAL process that cannot hold in-memory state
|
|
11
|
+
* across writes. So Cursor's before-map must be DISK-BACKED: the hook stages each
|
|
12
|
+
* first-touched gitignored path into a per-turn "cas-observations" sidecar, and
|
|
13
|
+
* the runner reads it back at the turn boundary.
|
|
14
|
+
*
|
|
15
|
+
* The sidecar lives under the session HITL directory
|
|
16
|
+
* (`~/.stigmer/sessions/{id}/hitl/cas-observations/`), OUTSIDE the user's
|
|
17
|
+
* workspace — so staged before-bytes and secret markers never land in the repo,
|
|
18
|
+
* cannot pollute the captured git diff, and are never pushed. It is reset every
|
|
19
|
+
* turn (alongside the denial ledger) and consumed within the same activity
|
|
20
|
+
* invocation that produced it; resume reconciles from the durable CAS manifest,
|
|
21
|
+
* never this scratch. A Temporal retry re-runs the reset and re-observes.
|
|
22
|
+
*
|
|
23
|
+
* ONE MODULE OWNS THE ON-DISK FORMAT. Both sides live here so they cannot drift:
|
|
24
|
+
* - the READER ({@link readCasObservations}) the runner boundary calls;
|
|
25
|
+
* - the WRITER-SCRIPT GENERATOR ({@link buildObservationStagingScript}) whose
|
|
26
|
+
* output the hook embeds and runs on the runner's own Node binary. The writer
|
|
27
|
+
* classifies secrets from the SAME {@link isSecretLikePath} pattern arrays the
|
|
28
|
+
* boundary backstop uses (`shared/filereview/secret-paths.ts`), reconstructed
|
|
29
|
+
* as byte-identical `RegExp`s — no bash-regex, no divergence.
|
|
30
|
+
*
|
|
31
|
+
* Each observed path becomes one entry:
|
|
32
|
+
* - `captured` — a non-secret gitignored write/edit: `{path, kind, existed}`
|
|
33
|
+
* metadata plus a `.blob` of the pre-turn bytes (omitted for an ADD, where the
|
|
34
|
+
* file did not exist). First-touch-wins via atomic exclusive-create, so
|
|
35
|
+
* repeated edits to one path keep the true pre-turn before.
|
|
36
|
+
* - `secret` — a secret-like gitignored path the hook hard-blocked (denied,
|
|
37
|
+
* nothing written): `{path, kind}` only. The boundary authors it as a
|
|
38
|
+
* content-less `DIFF_UNREVIEWABLE` change; its bytes never reach storage.
|
|
39
|
+
*
|
|
40
|
+
* @since File-Change HITL Redesign (Cursor CAS parity — DD-18)
|
|
41
|
+
*/
|
|
42
|
+
/** Sidecar directory name under the session HITL dir. */
|
|
43
|
+
export declare const CAS_OBSERVATIONS_DIRNAME = "cas-observations";
|
|
44
|
+
/** Absolute path of the per-turn cas-observations sidecar dir. */
|
|
45
|
+
export declare function casObservationsDir(hitlDir: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Truncate the cas-observations sidecar to empty for a fresh turn, returning its
|
|
48
|
+
* path. Called every turn alongside {@link resetDenialLedger} so the boundary
|
|
49
|
+
* only ever reads observations produced by the current run — deterministic across
|
|
50
|
+
* HITL reinvocations and Temporal activity retries.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resetCasObservations(hitlDir: string): Promise<string>;
|
|
53
|
+
/** One non-secret gitignored path the hook staged this turn. */
|
|
54
|
+
export interface CasObservationCapture {
|
|
55
|
+
/** Workspace-root-relative path. */
|
|
56
|
+
readonly path: string;
|
|
57
|
+
/** Pre-turn bytes; `null` when the file did not exist before (an ADD). */
|
|
58
|
+
readonly before: Uint8Array | null;
|
|
59
|
+
}
|
|
60
|
+
/** The turn's staged gitignored observations, split by the hook's secret gate. */
|
|
61
|
+
export interface CasObservations {
|
|
62
|
+
/** Non-secret paths to capture into CAS (before-bytes in hand). */
|
|
63
|
+
readonly captured: CasObservationCapture[];
|
|
64
|
+
/** Secret-like paths the hook hard-blocked (path-only; bytes withheld). */
|
|
65
|
+
readonly secretPaths: string[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read the cas-observations sidecar the hook wrote during the turn. Missing dir →
|
|
69
|
+
* no observations. Malformed/partial entries are tolerated and skipped (the hook
|
|
70
|
+
* writes the blob before the metadata marker, so a present marker implies a
|
|
71
|
+
* complete blob; a marker whose blob is unexpectedly missing is skipped rather
|
|
72
|
+
* than mis-captured). Entries are returned in a deterministic (sorted) order.
|
|
73
|
+
*/
|
|
74
|
+
export declare function readCasObservations(hitlDir: string): Promise<CasObservations>;
|
|
75
|
+
/**
|
|
76
|
+
* Build the standalone Node.js script the hook runs to observe a single
|
|
77
|
+
* gitignored write — the disk-backed mirror of `CasCaptureFilesystemBackend`'s
|
|
78
|
+
* `recordBefore` plus the DD-E secret gate.
|
|
79
|
+
*
|
|
80
|
+
* Invoked as `printf %s "$SALIENT" | node -e '<this>' <workspaceRoot> <obsDir>`
|
|
81
|
+
* — the (arbitrary) salient path arrives on stdin so no argv escaping is needed;
|
|
82
|
+
* the two absolute paths ride argv. Prints one token on stdout for the hook:
|
|
83
|
+
* - `captured` — non-secret: staged the pre-turn bytes (first-touch-wins), the
|
|
84
|
+
* hook then ALLOWS the write to flow;
|
|
85
|
+
* - `secret` — secret-like: recorded a content-less marker, the hook then
|
|
86
|
+
* DENIES with the security message (nothing is written);
|
|
87
|
+
* - `error` — the path escaped the workspace or a filesystem error occurred,
|
|
88
|
+
* the hook then fails closed (deny).
|
|
89
|
+
*
|
|
90
|
+
* The secret classifier is generated from the SAME
|
|
91
|
+
* {@link SECRET_BASENAME_PATTERNS}/{@link SECRET_PATH_PATTERNS} the boundary
|
|
92
|
+
* backstop uses, so the hook-side and boundary-side classifications agree by
|
|
93
|
+
* construction (a table test locks the equivalence). Authored as a
|
|
94
|
+
* single-quoted-bash string, so the JS must contain no single quotes.
|
|
95
|
+
*/
|
|
96
|
+
export declare function buildObservationStagingScript(): string;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Cursor harness's disk-backed observer for gitignored file writes — the
|
|
3
|
+
* out-of-process analog of the deep-agent `CasCaptureFilesystemBackend`
|
|
4
|
+
* ({@link ../execute-deep-agent/cas-capture-backend.js}).
|
|
5
|
+
*
|
|
6
|
+
* Deep-agent runs the agent in-process, so it records a gitignored file's
|
|
7
|
+
* pre-turn bytes in an in-memory `CasBeforeMap` at the mutation point (before
|
|
8
|
+
* `super.write`). Cursor runs the agent as an EXTERNAL CLI subprocess whose only
|
|
9
|
+
* pre-write interception is the generated preToolUse bash hook — and each hook
|
|
10
|
+
* invocation is a FRESH, EPHEMERAL process that cannot hold in-memory state
|
|
11
|
+
* across writes. So Cursor's before-map must be DISK-BACKED: the hook stages each
|
|
12
|
+
* first-touched gitignored path into a per-turn "cas-observations" sidecar, and
|
|
13
|
+
* the runner reads it back at the turn boundary.
|
|
14
|
+
*
|
|
15
|
+
* The sidecar lives under the session HITL directory
|
|
16
|
+
* (`~/.stigmer/sessions/{id}/hitl/cas-observations/`), OUTSIDE the user's
|
|
17
|
+
* workspace — so staged before-bytes and secret markers never land in the repo,
|
|
18
|
+
* cannot pollute the captured git diff, and are never pushed. It is reset every
|
|
19
|
+
* turn (alongside the denial ledger) and consumed within the same activity
|
|
20
|
+
* invocation that produced it; resume reconciles from the durable CAS manifest,
|
|
21
|
+
* never this scratch. A Temporal retry re-runs the reset and re-observes.
|
|
22
|
+
*
|
|
23
|
+
* ONE MODULE OWNS THE ON-DISK FORMAT. Both sides live here so they cannot drift:
|
|
24
|
+
* - the READER ({@link readCasObservations}) the runner boundary calls;
|
|
25
|
+
* - the WRITER-SCRIPT GENERATOR ({@link buildObservationStagingScript}) whose
|
|
26
|
+
* output the hook embeds and runs on the runner's own Node binary. The writer
|
|
27
|
+
* classifies secrets from the SAME {@link isSecretLikePath} pattern arrays the
|
|
28
|
+
* boundary backstop uses (`shared/filereview/secret-paths.ts`), reconstructed
|
|
29
|
+
* as byte-identical `RegExp`s — no bash-regex, no divergence.
|
|
30
|
+
*
|
|
31
|
+
* Each observed path becomes one entry:
|
|
32
|
+
* - `captured` — a non-secret gitignored write/edit: `{path, kind, existed}`
|
|
33
|
+
* metadata plus a `.blob` of the pre-turn bytes (omitted for an ADD, where the
|
|
34
|
+
* file did not exist). First-touch-wins via atomic exclusive-create, so
|
|
35
|
+
* repeated edits to one path keep the true pre-turn before.
|
|
36
|
+
* - `secret` — a secret-like gitignored path the hook hard-blocked (denied,
|
|
37
|
+
* nothing written): `{path, kind}` only. The boundary authors it as a
|
|
38
|
+
* content-less `DIFF_UNREVIEWABLE` change; its bytes never reach storage.
|
|
39
|
+
*
|
|
40
|
+
* @since File-Change HITL Redesign (Cursor CAS parity — DD-18)
|
|
41
|
+
*/
|
|
42
|
+
import { readFile, readdir, rm, mkdir } from "node:fs/promises";
|
|
43
|
+
import { join } from "node:path";
|
|
44
|
+
import { SECRET_BASENAME_PATTERNS, SECRET_PATH_PATTERNS } from "../../shared/filereview/secret-paths.js";
|
|
45
|
+
/** Sidecar directory name under the session HITL dir. */
|
|
46
|
+
export const CAS_OBSERVATIONS_DIRNAME = "cas-observations";
|
|
47
|
+
/** Suffix of the per-path metadata file (also the atomic first-touch marker). */
|
|
48
|
+
const META_SUFFIX = ".meta.json";
|
|
49
|
+
/** Suffix of the per-path pre-turn bytes blob (present only for a MODIFY). */
|
|
50
|
+
const BLOB_SUFFIX = ".blob";
|
|
51
|
+
/** Absolute path of the per-turn cas-observations sidecar dir. */
|
|
52
|
+
export function casObservationsDir(hitlDir) {
|
|
53
|
+
return join(hitlDir, CAS_OBSERVATIONS_DIRNAME);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Truncate the cas-observations sidecar to empty for a fresh turn, returning its
|
|
57
|
+
* path. Called every turn alongside {@link resetDenialLedger} so the boundary
|
|
58
|
+
* only ever reads observations produced by the current run — deterministic across
|
|
59
|
+
* HITL reinvocations and Temporal activity retries.
|
|
60
|
+
*/
|
|
61
|
+
export async function resetCasObservations(hitlDir) {
|
|
62
|
+
const dir = casObservationsDir(hitlDir);
|
|
63
|
+
await rm(dir, { recursive: true, force: true });
|
|
64
|
+
await mkdir(dir, { recursive: true });
|
|
65
|
+
return dir;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read the cas-observations sidecar the hook wrote during the turn. Missing dir →
|
|
69
|
+
* no observations. Malformed/partial entries are tolerated and skipped (the hook
|
|
70
|
+
* writes the blob before the metadata marker, so a present marker implies a
|
|
71
|
+
* complete blob; a marker whose blob is unexpectedly missing is skipped rather
|
|
72
|
+
* than mis-captured). Entries are returned in a deterministic (sorted) order.
|
|
73
|
+
*/
|
|
74
|
+
export async function readCasObservations(hitlDir) {
|
|
75
|
+
const dir = casObservationsDir(hitlDir);
|
|
76
|
+
let names;
|
|
77
|
+
try {
|
|
78
|
+
names = await readdir(dir);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return { captured: [], secretPaths: [] };
|
|
82
|
+
}
|
|
83
|
+
const captured = [];
|
|
84
|
+
const secretPaths = [];
|
|
85
|
+
for (const name of names.sort()) {
|
|
86
|
+
if (!name.endsWith(META_SUFFIX))
|
|
87
|
+
continue;
|
|
88
|
+
let meta;
|
|
89
|
+
try {
|
|
90
|
+
meta = JSON.parse(await readFile(join(dir, name), "utf-8"));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
continue; // partial/garbled marker — tolerate
|
|
94
|
+
}
|
|
95
|
+
if (!meta || typeof meta.path !== "string" || !meta.path)
|
|
96
|
+
continue;
|
|
97
|
+
if (meta.kind === "secret") {
|
|
98
|
+
secretPaths.push(meta.path);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (meta.kind === "captured") {
|
|
102
|
+
let before = null;
|
|
103
|
+
if (meta.existed === true) {
|
|
104
|
+
const blobPath = join(dir, name.slice(0, -META_SUFFIX.length) + BLOB_SUFFIX);
|
|
105
|
+
try {
|
|
106
|
+
before = await readFile(blobPath);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
continue; // marker present but blob missing (mid-hook crash) — skip
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
captured.push({ path: meta.path, before });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return { captured, secretPaths };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Emit a JS `RegExp` constructor byte-identical to a source pattern, safe to
|
|
119
|
+
* embed inside a single-quoted bash string (JSON.stringify emits double quotes;
|
|
120
|
+
* these patterns contain no single quotes).
|
|
121
|
+
*/
|
|
122
|
+
function regexLiteral(re) {
|
|
123
|
+
return `new RegExp(${JSON.stringify(re.source)},${JSON.stringify(re.flags)})`;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build the standalone Node.js script the hook runs to observe a single
|
|
127
|
+
* gitignored write — the disk-backed mirror of `CasCaptureFilesystemBackend`'s
|
|
128
|
+
* `recordBefore` plus the DD-E secret gate.
|
|
129
|
+
*
|
|
130
|
+
* Invoked as `printf %s "$SALIENT" | node -e '<this>' <workspaceRoot> <obsDir>`
|
|
131
|
+
* — the (arbitrary) salient path arrives on stdin so no argv escaping is needed;
|
|
132
|
+
* the two absolute paths ride argv. Prints one token on stdout for the hook:
|
|
133
|
+
* - `captured` — non-secret: staged the pre-turn bytes (first-touch-wins), the
|
|
134
|
+
* hook then ALLOWS the write to flow;
|
|
135
|
+
* - `secret` — secret-like: recorded a content-less marker, the hook then
|
|
136
|
+
* DENIES with the security message (nothing is written);
|
|
137
|
+
* - `error` — the path escaped the workspace or a filesystem error occurred,
|
|
138
|
+
* the hook then fails closed (deny).
|
|
139
|
+
*
|
|
140
|
+
* The secret classifier is generated from the SAME
|
|
141
|
+
* {@link SECRET_BASENAME_PATTERNS}/{@link SECRET_PATH_PATTERNS} the boundary
|
|
142
|
+
* backstop uses, so the hook-side and boundary-side classifications agree by
|
|
143
|
+
* construction (a table test locks the equivalence). Authored as a
|
|
144
|
+
* single-quoted-bash string, so the JS must contain no single quotes.
|
|
145
|
+
*/
|
|
146
|
+
export function buildObservationStagingScript() {
|
|
147
|
+
const base = SECRET_BASENAME_PATTERNS.map(regexLiteral).join(",");
|
|
148
|
+
const pathPatterns = SECRET_PATH_PATTERNS.map(regexLiteral).join(",");
|
|
149
|
+
const metaSuffix = JSON.stringify(META_SUFFIX);
|
|
150
|
+
const blobSuffix = JSON.stringify(BLOB_SUFFIX);
|
|
151
|
+
return [
|
|
152
|
+
`const fs=require("fs");const path=require("path");const crypto=require("crypto");`,
|
|
153
|
+
`const wsRoot=process.argv[1]||"";const obsDir=process.argv[2]||"";`,
|
|
154
|
+
`let salient="";try{salient=fs.readFileSync(0,"utf8");}catch(e){salient="";}`,
|
|
155
|
+
`if(!salient||!obsDir){process.stdout.write("error");process.exit(0);}`,
|
|
156
|
+
// Workspace-relative key, git-consistent: an absolute salient stays put, a
|
|
157
|
+
// relative one resolves against the workspace root. A path that escapes the
|
|
158
|
+
// workspace is treated as an error (fail closed) — it should never be flagged
|
|
159
|
+
// gitignored by `git check-ignore -C <root>` in the first place.
|
|
160
|
+
`const abs=path.resolve(wsRoot,salient);`,
|
|
161
|
+
`let rel=path.relative(wsRoot,abs).split(path.sep).join("/");`,
|
|
162
|
+
`if(!rel||rel===".."||rel.startsWith("../")){process.stdout.write("error");process.exit(0);}`,
|
|
163
|
+
// --- secret classifier: byte-identical mirror of isSecretLikePath ---
|
|
164
|
+
`const baseName=(p)=>{const n=p.replace(/\\\\/g,"/");const i=n.lastIndexOf("/");return i>=0?n.slice(i+1):n;};`,
|
|
165
|
+
`const BASE=[${base}];const PATHP=[${pathPatterns}];`,
|
|
166
|
+
`const isSecret=(p)=>{if(!p)return true;const nm=p.replace(/\\\\/g,"/");const b=baseName(nm).toLowerCase();for(const r of BASE){if(r.test(b))return true;}const lp=nm.toLowerCase();for(const r of PATHP){if(r.test(lp))return true;}return false;};`,
|
|
167
|
+
`const key=crypto.createHash("sha256").update(rel,"utf8").digest("hex");`,
|
|
168
|
+
`const metaPath=path.join(obsDir,key+${metaSuffix});const blobPath=path.join(obsDir,key+${blobSuffix});`,
|
|
169
|
+
`try{fs.mkdirSync(obsDir,{recursive:true});}catch(e){}`,
|
|
170
|
+
// Secret: record a content-less marker (idempotent) and signal a hard-block.
|
|
171
|
+
`if(isSecret(rel)){try{fs.writeFileSync(metaPath,JSON.stringify({path:rel,kind:"secret"}),{flag:"wx"});}catch(e){}process.stdout.write("secret");process.exit(0);}`,
|
|
172
|
+
// Non-secret: first-touch-wins. A prior marker means this path is already
|
|
173
|
+
// observed (a later edit) — leave the true pre-turn before intact.
|
|
174
|
+
`if(fs.existsSync(metaPath)){process.stdout.write("captured");process.exit(0);}`,
|
|
175
|
+
// Read the pre-turn bytes NOW (the write has not applied — this is preToolUse
|
|
176
|
+
// and the first touch). Missing file = an ADD (before is null).
|
|
177
|
+
`let existed=false;let before=null;try{before=fs.readFileSync(abs);existed=true;}catch(e){existed=false;}`,
|
|
178
|
+
// Write the blob BEFORE the marker, so a present marker always implies a
|
|
179
|
+
// complete blob. The wx marker is the atomic commit + first-touch lock.
|
|
180
|
+
`try{if(existed){fs.writeFileSync(blobPath,before);}fs.writeFileSync(metaPath,JSON.stringify({path:rel,kind:"captured",existed:existed}),{flag:"wx"});}catch(e){if(e&&e.code==="EEXIST"){process.stdout.write("captured");process.exit(0);}process.stdout.write("error");process.exit(0);}`,
|
|
181
|
+
`process.stdout.write("captured");`,
|
|
182
|
+
].join("");
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=cas-observations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cas-observations.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/cas-observations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approved-command turn provenance (DD-28): the runner-owned qualification for
|
|
3
|
+
* the auto-keep policy.
|
|
4
|
+
*
|
|
5
|
+
* A turn whose ONLY mutation source was shell commands the human had already
|
|
6
|
+
* authorized should not re-gate its file effects at the turn-boundary review —
|
|
7
|
+
* the user consented to the command, and the command's file effects are the
|
|
8
|
+
* consented outcome. The server cannot derive this itself (tool calls carry no
|
|
9
|
+
* turn marker), so the runner — the only component that owns turn scoping —
|
|
10
|
+
* derives the facts here and attaches them to the CANDIDATE_CAPTURED event as
|
|
11
|
+
* {@link TurnCommandProvenance}.
|
|
12
|
+
*
|
|
13
|
+
* TRUST BOUNDARY. This module asserts turn FACTS (which tools ran this turn),
|
|
14
|
+
* the same trust level as the captured bytes themselves. It never asserts
|
|
15
|
+
* CONSENT: `consentToolCallIds` merely POINT at transcript rows whose
|
|
16
|
+
* `approval_action` was authored by the server's SubmitApproval (and is
|
|
17
|
+
* preserved against runner writes) — the backend re-verifies every claimed row
|
|
18
|
+
* against that server-owned record before authoring the policy decision, so a
|
|
19
|
+
* runner cannot mint authorization it was never given.
|
|
20
|
+
*
|
|
21
|
+
* FAIL-CLOSED. Every uncertainty disqualifies (returns undefined → the set
|
|
22
|
+
* reviews manually, exactly as before DD-28): a file-tool call, an MCP tool, a
|
|
23
|
+
* sub-agent delegation, an unrecognized tool name, or an executed shell command
|
|
24
|
+
* with no provable consent source. Being conservative here costs only an extra
|
|
25
|
+
* review; being permissive would silently waive one.
|
|
26
|
+
*/
|
|
27
|
+
import type { AgentMessage } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
28
|
+
import type { TurnCommandProvenance } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
29
|
+
export interface CommandProvenanceInputs {
|
|
30
|
+
/**
|
|
31
|
+
* The full transcript at capture time. Turn scoping is positional: messages
|
|
32
|
+
* from index {@link turnStartIndex} onward were produced by THIS turn's
|
|
33
|
+
* stream; everything before was seeded from prior turns. Lease consent rows
|
|
34
|
+
* (APPROVE_ALL) are looked up across the WHOLE transcript — a lease is
|
|
35
|
+
* run-lifetime, its granting row usually lives in a prior turn.
|
|
36
|
+
*/
|
|
37
|
+
readonly messages: readonly AgentMessage[];
|
|
38
|
+
/** Index of the first message created by this turn's stream. */
|
|
39
|
+
readonly turnStartIndex: number;
|
|
40
|
+
/**
|
|
41
|
+
* Identity tokens the hook denied THIS turn (the denial ledger). A denied
|
|
42
|
+
* shell row never executed — it is this turn's pending gate, not a mutation
|
|
43
|
+
* source — so it neither needs consent nor disqualifies.
|
|
44
|
+
*/
|
|
45
|
+
readonly deniedTokens: ReadonlySet<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Grant token → the tool-call id of the approval row that minted the grant
|
|
48
|
+
* (the row carrying the server-authored approval_action). An executed shell
|
|
49
|
+
* command whose identity token is a key here was authorized by that
|
|
50
|
+
* per-command approval.
|
|
51
|
+
*/
|
|
52
|
+
readonly grantTokenToConsentId: ReadonlyMap<string, string>;
|
|
53
|
+
/** True when the pre-armed spec.auto_approve_all bypassed the gate. */
|
|
54
|
+
readonly globalBypass: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Derive the {@link TurnCommandProvenance} for the turn, or undefined when the
|
|
58
|
+
* turn does not qualify (any non-shell mutation-capable call, any unknown tool,
|
|
59
|
+
* any executed command without a provable consent source, or no executed
|
|
60
|
+
* consented command at all).
|
|
61
|
+
*/
|
|
62
|
+
export declare function deriveTurnCommandProvenance(inputs: CommandProvenanceInputs): TurnCommandProvenance | undefined;
|