@stigmer/runner 3.15.3-dev.20260914121148 → 3.16.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/README.md +2 -1
- package/dist/.build-fingerprint +1 -1
- package/dist/__test-utils__/approval-contract/types.d.ts +1 -1
- package/dist/__test-utils__/hermetic-activity.d.ts +61 -7
- package/dist/__test-utils__/hermetic-activity.js +100 -9
- package/dist/__test-utils__/hermetic-activity.js.map +1 -1
- package/dist/__test-utils__/model-registry-fixture.d.ts +22 -3
- package/dist/__test-utils__/model-registry-fixture.js +22 -7
- package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +2 -2
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +2 -2
- package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +61 -0
- package/dist/activities/execute-cursor/__test-utils__/fold.js +94 -0
- package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -0
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +1 -1
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +47 -12
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +41 -10
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +15 -6
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +17 -4
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
- package/dist/activities/execute-cursor/adapter.d.ts +4 -4
- package/dist/activities/execute-cursor/adapter.js +4 -4
- package/dist/activities/execute-cursor/approval-policy.d.ts +10 -10
- package/dist/activities/execute-cursor/approval-policy.js +12 -23
- package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +35 -1
- package/dist/activities/execute-cursor/approval-state.js +65 -0
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/{message-translator.d.ts → boundary-rows.d.ts} +45 -341
- package/dist/activities/execute-cursor/boundary-rows.js +1018 -0
- package/dist/activities/execute-cursor/boundary-rows.js.map +1 -0
- package/dist/activities/execute-cursor/cursor-capabilities.d.ts +1 -1
- package/dist/activities/execute-cursor/cursor-capabilities.js +1 -1
- package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +33 -14
- package/dist/activities/execute-cursor/cursor-event-recorder.js +43 -21
- package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +3 -3
- package/dist/activities/execute-cursor/prompt-builder.js +4 -4
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/service-tier.js +1 -2
- package/dist/activities/execute-cursor/service-tier.js.map +1 -1
- package/dist/activities/execute-cursor/sub-agent-steps.d.ts +79 -0
- package/dist/activities/execute-cursor/sub-agent-steps.js +180 -0
- package/dist/activities/execute-cursor/sub-agent-steps.js.map +1 -0
- package/dist/activities/execute-cursor/tool-result.d.ts +49 -0
- package/dist/activities/execute-cursor/tool-result.js +130 -0
- package/dist/activities/execute-cursor/tool-result.js.map +1 -0
- package/dist/activities/execute-cursor/translator.d.ts +178 -0
- package/dist/activities/execute-cursor/translator.js +485 -0
- package/dist/activities/execute-cursor/translator.js.map +1 -0
- package/dist/activities/execute-cursor/turn-boundary.d.ts +15 -5
- package/dist/activities/execute-cursor/turn-boundary.js +10 -14
- package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
- package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
- package/dist/activities/execute-cursor/turn-settle.js +47 -34
- package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
- package/dist/activities/execute-cursor/turn-setup.d.ts +2 -2
- package/dist/activities/execute-cursor/turn-setup.js +5 -5
- package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
- package/dist/activities/execute-cursor/turn-stream.d.ts +23 -14
- package/dist/activities/execute-cursor/turn-stream.js +41 -28
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-cursor/turn.d.ts +4 -4
- package/dist/activities/execute-cursor/turn.js +5 -5
- package/dist/activities/execute-cursor/usage-pricing.d.ts +2 -2
- package/dist/activities/execute-cursor/usage-pricing.js +2 -2
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +2 -2
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +2 -2
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +16 -11
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -10
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +2 -3
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +2 -3
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +12 -3
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +18 -4
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +10 -1
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +24 -11
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -1
- package/dist/activities/execute-deep-agent/adapter.d.ts +1 -1
- package/dist/activities/execute-deep-agent/adapter.js +1 -1
- package/dist/activities/execute-deep-agent/approval-file-change.d.ts +19 -19
- package/dist/activities/execute-deep-agent/approval-file-change.js +16 -15
- package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +2 -2
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +2 -2
- package/dist/activities/execute-deep-agent/hitl.d.ts +2 -2
- package/dist/activities/execute-deep-agent/hitl.js +2 -2
- package/dist/activities/execute-deep-agent/inline-publisher.d.ts +13 -3
- package/dist/activities/execute-deep-agent/inline-publisher.js +3 -3
- package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +3 -3
- package/dist/activities/execute-deep-agent/prompt-builder.js +6 -7
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +16 -8
- package/dist/activities/execute-deep-agent/streaming-side-effects.js +20 -33
- package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +3 -3
- package/dist/activities/execute-deep-agent/subagent-transformer.js +1 -1
- package/dist/activities/execute-deep-agent/translator.d.ts +134 -0
- package/dist/activities/execute-deep-agent/translator.js +418 -0
- package/dist/activities/execute-deep-agent/translator.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn-settle.d.ts +13 -7
- package/dist/activities/execute-deep-agent/turn-settle.js +34 -45
- package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-setup.d.ts +8 -8
- package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
- package/dist/activities/execute-deep-agent/turn-stream.d.ts +13 -10
- package/dist/activities/execute-deep-agent/turn-stream.js +44 -41
- package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn.d.ts +3 -3
- package/dist/activities/execute-deep-agent/turn.js +3 -3
- package/dist/activities/generate-session-subject.d.ts +25 -4
- package/dist/activities/generate-session-subject.js +17 -7
- package/dist/activities/generate-session-subject.js.map +1 -1
- package/dist/client/stigmer-client.d.ts +17 -6
- package/dist/client/stigmer-client.js +47 -14
- package/dist/client/stigmer-client.js.map +1 -1
- package/dist/config.d.ts +6 -3
- package/dist/config.js +4 -1
- package/dist/config.js.map +1 -1
- package/dist/harness/approval-decisions.d.ts +1 -1
- package/dist/harness/approval-decisions.js +1 -1
- package/dist/harness/capabilities.d.ts +21 -11
- package/dist/harness/capabilities.js +2 -2
- package/dist/harness/capture.d.ts +4 -4
- package/dist/harness/capture.js +4 -4
- package/dist/harness/persist-chokepoint.d.ts +3 -3
- package/dist/harness/persist-chokepoint.js +3 -3
- package/dist/harness/registry.d.ts +2 -2
- package/dist/harness/registry.js +2 -2
- package/dist/harness/run-turn.d.ts +6 -4
- package/dist/harness/run-turn.js +31 -9
- package/dist/harness/run-turn.js.map +1 -1
- package/dist/harness/stop-controller.d.ts +1 -1
- package/dist/harness/stop-controller.js +1 -1
- package/dist/harness/terminal-table.d.ts +7 -7
- package/dist/harness/terminal-table.js +7 -7
- package/dist/harness/transcript/builder.d.ts +182 -0
- package/dist/harness/transcript/builder.js +693 -0
- package/dist/harness/transcript/builder.js.map +1 -0
- package/dist/harness/transcript/events.d.ts +218 -0
- package/dist/harness/transcript/events.js +50 -0
- package/dist/harness/transcript/events.js.map +1 -0
- package/dist/harness/transcript/state.d.ts +110 -0
- package/dist/harness/transcript/state.js +148 -0
- package/dist/harness/transcript/state.js.map +1 -0
- package/dist/harness/turn-context.d.ts +54 -38
- package/dist/harness/turn-context.js +42 -43
- package/dist/harness/turn-context.js.map +1 -1
- package/dist/harness/types.d.ts +63 -22
- package/dist/harness/types.js +12 -11
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage-accumulator.d.ts +2 -2
- package/dist/harness/usage-accumulator.js +2 -2
- package/dist/harness-adapters.d.ts +5 -4
- package/dist/harness-adapters.js +5 -4
- package/dist/harness-adapters.js.map +1 -1
- package/dist/interceptors/run-credential-activity.d.ts +28 -0
- package/dist/interceptors/run-credential-activity.js +56 -0
- package/dist/interceptors/run-credential-activity.js.map +1 -0
- package/dist/middleware/approval-gate.d.ts +6 -0
- package/dist/middleware/approval-gate.js +7 -57
- package/dist/middleware/approval-gate.js.map +1 -1
- package/dist/middleware/cost-advisory.d.ts +3 -3
- package/dist/middleware/cost-advisory.js +3 -3
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/runner-manager.js +10 -4
- package/dist/runner-manager.js.map +1 -1
- package/dist/shared/activity-input.d.ts +9 -0
- package/dist/shared/activity-input.js +17 -0
- package/dist/shared/activity-input.js.map +1 -1
- package/dist/shared/approval-policy.d.ts +53 -0
- package/dist/shared/approval-policy.js +76 -0
- package/dist/shared/approval-policy.js.map +1 -1
- package/dist/shared/args-preview.d.ts +45 -22
- package/dist/shared/args-preview.js +51 -41
- package/dist/shared/args-preview.js.map +1 -1
- package/dist/shared/attachment-resolver.d.ts +4 -4
- package/dist/shared/attachment-resolver.js +4 -4
- package/dist/shared/attachment-zip.d.ts +2 -2
- package/dist/shared/attachment-zip.js +2 -2
- package/dist/shared/channel-attachment.d.ts +8 -5
- package/dist/shared/channel-attachment.js +10 -6
- package/dist/shared/channel-attachment.js.map +1 -1
- package/dist/shared/cost-guard.d.ts +2 -2
- package/dist/shared/cost-guard.js +2 -2
- package/dist/shared/exact-apply.d.ts +1 -1
- package/dist/shared/exact-apply.js +1 -1
- package/dist/shared/execution-context.d.ts +2 -2
- package/dist/shared/execution-context.js +2 -2
- package/dist/shared/extract-structured-output.d.ts +2 -2
- package/dist/shared/extract-structured-output.js +2 -2
- package/dist/shared/filereview/cas-touched.d.ts +2 -2
- package/dist/shared/filereview/cas-touched.js +2 -2
- package/dist/shared/filereview/progress.d.ts +13 -0
- package/dist/shared/filereview/progress.js +13 -0
- package/dist/shared/filereview/progress.js.map +1 -1
- package/dist/shared/heartbeat.d.ts +1 -1
- package/dist/shared/heartbeat.js +1 -1
- package/dist/shared/llm-backend.d.ts +0 -4
- package/dist/shared/llm-backend.js +0 -4
- package/dist/shared/llm-backend.js.map +1 -1
- package/dist/shared/memory-attachment.d.ts +16 -9
- package/dist/shared/memory-attachment.js +18 -10
- package/dist/shared/memory-attachment.js.map +1 -1
- package/dist/shared/model-error.d.ts +1 -2
- package/dist/shared/model-error.js +1 -2
- package/dist/shared/model-error.js.map +1 -1
- package/dist/shared/persist-decision.d.ts +18 -24
- package/dist/shared/persist-decision.js +19 -11
- package/dist/shared/persist-decision.js.map +1 -1
- package/dist/shared/prompt-sections.d.ts +4 -4
- package/dist/shared/prompt-sections.js +4 -4
- package/dist/shared/run-credential-store.d.ts +32 -0
- package/dist/shared/run-credential-store.js +39 -0
- package/dist/shared/run-credential-store.js.map +1 -0
- package/dist/shared/run-credential.d.ts +61 -0
- package/dist/shared/run-credential.js +68 -0
- package/dist/shared/run-credential.js.map +1 -0
- package/dist/shared/skill-resolver.d.ts +3 -3
- package/dist/shared/skill-resolver.js +3 -3
- package/dist/shared/status-offload.d.ts +1 -1
- package/dist/shared/status-offload.js +2 -2
- package/dist/shared/status-offload.js.map +1 -1
- package/dist/shared/streaming-scheduler.d.ts +2 -7
- package/dist/shared/streaming-scheduler.js +6 -14
- package/dist/shared/streaming-scheduler.js.map +1 -1
- package/dist/shared/subagent-rows.d.ts +2 -2
- package/dist/shared/subagent-rows.js +2 -2
- package/dist/shared/synthesized-attachment.d.ts +30 -3
- package/dist/shared/synthesized-attachment.js +26 -0
- package/dist/shared/synthesized-attachment.js.map +1 -1
- package/dist/shared/todos.d.ts +3 -3
- package/dist/shared/todos.js +3 -3
- package/dist/shared/tool-row.d.ts +19 -1
- package/dist/shared/tool-row.js +36 -2
- package/dist/shared/tool-row.js.map +1 -1
- package/dist/shared/worker-shutdown.d.ts +1 -1
- package/dist/shared/worker-shutdown.js +1 -1
- package/dist/shared/workspace/session-provision.d.ts +1 -1
- package/dist/shared/workspace/session-provision.js +1 -1
- package/dist/shared/workspace/sources/empty.d.ts +1 -1
- package/dist/shared/workspace/sources/empty.js +1 -2
- package/dist/shared/workspace/sources/empty.js.map +1 -1
- package/dist/shared/workspace/sources/git.js +4 -4
- package/dist/shared/workspace/sources/git.js.map +1 -1
- package/dist/shared/workspace/sources/local-path.js +6 -6
- package/dist/shared/workspace/sources/local-path.js.map +1 -1
- package/dist/shared/workspace/stigmer-link.d.ts +1 -1
- package/dist/shared/workspace/stigmer-link.js +1 -1
- package/dist/shared/workspace/types.d.ts +2 -5
- package/dist/shared/workspace/types.js +0 -6
- package/dist/shared/workspace/types.js.map +1 -1
- package/dist/shared/workspace/writeback-coordinator.d.ts +17 -4
- package/dist/shared/workspace/writeback-coordinator.js +7 -9
- package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
- package/dist/worker.js +10 -3
- package/dist/worker.js.map +1 -1
- package/dist/workflow-source.d.ts +10 -0
- package/dist/workflow-source.js +12 -0
- package/dist/workflow-source.js.map +1 -1
- package/dist/workflows/execute-from-execution.d.ts +15 -0
- package/dist/workflows/execute-from-execution.js +11 -0
- package/dist/workflows/execute-from-execution.js.map +1 -1
- package/dist/workflows/index.d.ts +5 -3
- package/dist/workflows/index.js +5 -3
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/interceptors/run-credential.d.ts +34 -0
- package/dist/workflows/interceptors/run-credential.js +71 -0
- package/dist/workflows/interceptors/run-credential.js.map +1 -0
- package/package.json +4 -4
- package/src/__test-utils__/__tests__/execution-record-barrier.test.ts +70 -0
- package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +35 -1
- package/src/__test-utils__/approval-contract/contract.ts +1 -1
- package/src/__test-utils__/approval-contract/types.ts +1 -1
- package/src/__test-utils__/harness-boot-order-child.ts +1 -1
- package/src/__test-utils__/harness-contract/contract.ts +8 -8
- package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
- package/src/__test-utils__/harness-contract/runtime-contract.ts +52 -16
- package/src/__test-utils__/harness-contract/scripted-adapter.ts +47 -43
- package/src/__test-utils__/hermetic-activity.ts +113 -9
- package/src/__test-utils__/model-registry-fixture.ts +31 -7
- package/src/__test-utils__/module-specifiers.ts +32 -3
- package/src/__tests__/harness-boot-order.test.ts +1 -1
- package/src/__tests__/harness-contract.test.ts +1 -1
- package/src/__tests__/run-credential-e2e.test.ts +233 -0
- package/src/__tests__/run-credential-registration.test.ts +80 -0
- package/src/__tests__/runner-manager.test.ts +1 -1
- package/src/activities/__tests__/generate-session-subject-wire.test.ts +119 -0
- package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +1 -1
- package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +2 -2
- package/src/activities/execute-cursor/__test-utils__/fold.ts +116 -0
- package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +1 -1
- package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +67 -17
- package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +19 -5
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/approval-state.test.ts +14 -21
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +3 -3
- package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/cursor-event-recorder.test.ts +142 -0
- package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +19 -8
- package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +10 -8
- package/src/activities/execute-cursor/__tests__/cursor-transcript-live.test.ts +298 -0
- package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +4 -2
- package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/mcp-tool-call.status.json +71 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-task-note.status.json +73 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +78 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +72 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +72 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/sub-agent-delegation.status.json +109 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/thinking-turn.status.json +78 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/todo-write.status.json +119 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-error.status.json +68 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-only-step.status.json +67 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +7 -7
- package/src/activities/execute-cursor/__tests__/hermetic/mcp-tool-call.test.ts +146 -0
- package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +5 -5
- package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/hermetic/sdk-task-note.test.ts +122 -0
- package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +276 -0
- package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +8 -8
- package/src/activities/execute-cursor/__tests__/hermetic/sub-agent-delegation.test.ts +196 -0
- package/src/activities/execute-cursor/__tests__/hermetic/thinking-turn.test.ts +145 -0
- package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/todo-write.test.ts +165 -0
- package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +3 -3
- package/src/activities/execute-cursor/__tests__/hermetic/tool-error.test.ts +138 -0
- package/src/activities/execute-cursor/__tests__/hermetic/tool-only-step.test.ts +130 -0
- package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +13 -1
- package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +2 -2
- package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +43 -60
- package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +23 -28
- package/src/activities/execute-cursor/__tests__/hook-script.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +5 -5
- package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +11 -13
- package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +8 -11
- package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +8 -22
- package/src/activities/execute-cursor/__tests__/translator.test.ts +594 -0
- package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +8 -5
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +87 -63
- package/src/activities/execute-cursor/adapter.ts +4 -4
- package/src/activities/execute-cursor/approval-policy.ts +12 -24
- package/src/activities/execute-cursor/approval-state.ts +66 -1
- package/src/activities/execute-cursor/boundary-rows.ts +1132 -0
- package/src/activities/execute-cursor/cursor-capabilities.ts +1 -1
- package/src/activities/execute-cursor/cursor-event-recorder.ts +57 -28
- package/src/activities/execute-cursor/fetch-interceptor.ts +1 -1
- package/src/activities/execute-cursor/http2-interceptor.ts +1 -1
- package/src/activities/execute-cursor/prompt-builder.ts +6 -6
- package/src/activities/execute-cursor/service-tier.ts +1 -2
- package/src/activities/execute-cursor/sub-agent-steps.ts +188 -0
- package/src/activities/execute-cursor/tool-result.ts +128 -0
- package/src/activities/execute-cursor/translator.ts +541 -0
- package/src/activities/execute-cursor/turn-boundary.ts +21 -14
- package/src/activities/execute-cursor/turn-settle.ts +46 -34
- package/src/activities/execute-cursor/turn-setup.ts +5 -5
- package/src/activities/execute-cursor/turn-stream.ts +49 -46
- package/src/activities/execute-cursor/turn.ts +5 -5
- package/src/activities/execute-cursor/usage-pricing.ts +2 -2
- package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +2 -2
- package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +23 -11
- package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +1 -1
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +2 -3
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +25 -4
- package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +25 -11
- package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +6 -17
- package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +25 -8
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +2 -7
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +4 -14
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +4 -7
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +2 -9
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +2 -9
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +109 -76
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +2 -10
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +2 -10
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +3 -6
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/write-todos.status.json +92 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +3 -3
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +9 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +3 -3
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +3 -3
- package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +7 -6
- package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +10 -11
- package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +4 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +9 -8
- package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +21 -13
- package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +2 -2
- package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +7 -7
- package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +28 -12
- package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +21 -21
- package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/write-todos.test.ts +160 -0
- package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +35 -30
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +3 -4
- package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +12 -10
- package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +13 -3
- package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +26 -18
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/{subagent-tracker.test.ts → translator-subagents.test.ts} +76 -57
- package/src/activities/execute-deep-agent/__tests__/{v3-status-builder.test.ts → translator-through-builder.test.ts} +213 -299
- package/src/activities/execute-deep-agent/__tests__/translator.test.ts +505 -0
- package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +11 -29
- package/src/activities/execute-deep-agent/adapter.ts +1 -1
- package/src/activities/execute-deep-agent/approval-file-change.ts +20 -22
- package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +2 -2
- package/src/activities/execute-deep-agent/hitl.ts +2 -2
- package/src/activities/execute-deep-agent/inline-publisher.ts +16 -5
- package/src/activities/execute-deep-agent/prompt-builder.ts +6 -7
- package/src/activities/execute-deep-agent/streaming-side-effects.ts +22 -31
- package/src/activities/execute-deep-agent/subagent-transformer.ts +3 -3
- package/src/activities/execute-deep-agent/translator.ts +463 -0
- package/src/activities/execute-deep-agent/turn-settle.ts +35 -43
- package/src/activities/execute-deep-agent/turn-setup.ts +8 -8
- package/src/activities/execute-deep-agent/turn-stream.ts +53 -51
- package/src/activities/execute-deep-agent/turn.ts +3 -3
- package/src/activities/generate-session-subject.ts +29 -4
- package/src/client/__tests__/stigmer-client.test.ts +92 -0
- package/src/client/stigmer-client.ts +48 -14
- package/src/config.ts +6 -3
- package/src/harness/README.md +335 -0
- package/src/harness/__tests__/approval-decisions.test.ts +2 -2
- package/src/harness/__tests__/capture.test.ts +3 -3
- package/src/harness/__tests__/import-direction.test.ts +3 -2
- package/src/harness/__tests__/mount-skills.test.ts +4 -1
- package/src/harness/__tests__/readme-index.test.ts +339 -0
- package/src/harness/__tests__/run-turn.test.ts +131 -6
- package/src/harness/__tests__/transcript-is-engine-free.test.ts +83 -0
- package/src/harness/__tests__/transcript-writers.test.ts +191 -0
- package/src/harness/__tests__/turn-attachments-vision.test.ts +5 -2
- package/src/harness/__tests__/turn-context.test.ts +5 -5
- package/src/harness/approval-decisions.ts +1 -1
- package/src/harness/capabilities.ts +21 -11
- package/src/harness/capture.ts +4 -4
- package/src/harness/persist-chokepoint.ts +3 -3
- package/src/harness/registry.ts +2 -2
- package/src/harness/run-turn.ts +33 -9
- package/src/harness/stop-controller.ts +1 -1
- package/src/harness/terminal-table.ts +7 -7
- package/src/harness/transcript/__tests__/builder.test.ts +975 -0
- package/src/harness/transcript/__tests__/state.test.ts +143 -0
- package/src/harness/transcript/builder.ts +755 -0
- package/src/harness/transcript/events.ts +262 -0
- package/src/harness/transcript/state.ts +167 -0
- package/src/harness/turn-context.ts +61 -46
- package/src/harness/types.ts +64 -22
- package/src/harness/usage-accumulator.ts +2 -2
- package/src/harness-adapters.ts +5 -4
- package/src/interceptors/__tests__/run-credential-activity.test.ts +133 -0
- package/src/interceptors/run-credential-activity.ts +67 -0
- package/src/middleware/__tests__/cost-advisory.test.ts +2 -2
- package/src/middleware/approval-gate.ts +7 -74
- package/src/middleware/cost-advisory.ts +3 -3
- package/src/middleware/index.ts +1 -1
- package/src/runner-manager.ts +14 -4
- package/src/shared/__tests__/approval-policy.test.ts +45 -0
- package/src/shared/__tests__/args-preview.test.ts +40 -20
- package/src/shared/__tests__/attachment-naming.test.ts +1 -1
- package/src/shared/__tests__/attachment-resolver.test.ts +5 -5
- package/src/shared/__tests__/attachment-zip.test.ts +1 -1
- package/src/shared/__tests__/blueprint-resolver.test.ts +1 -1
- package/src/shared/__tests__/channel-attachment.test.ts +12 -0
- package/src/shared/__tests__/cost-guard.test.ts +1 -1
- package/src/shared/__tests__/exact-apply.test.ts +2 -1
- package/src/shared/__tests__/memory-attachment.test.ts +17 -0
- package/src/shared/__tests__/persist-decision.test.ts +19 -33
- package/src/shared/__tests__/prompt-sections.test.ts +1 -1
- package/src/shared/__tests__/run-credential.test.ts +111 -0
- package/src/shared/__tests__/stamp-flowed-rows.test.ts +1 -1
- package/src/shared/__tests__/status-offload.test.ts +1 -1
- package/src/shared/__tests__/streaming-scheduler.test.ts +8 -9
- package/src/shared/__tests__/todos.test.ts +1 -1
- package/src/shared/__tests__/tool-row.test.ts +1 -1
- package/src/shared/activity-input.ts +21 -0
- package/src/shared/approval-policy.ts +95 -0
- package/src/shared/args-preview.ts +51 -42
- package/src/shared/attachment-resolver.ts +4 -4
- package/src/shared/attachment-zip.ts +2 -2
- package/src/shared/channel-attachment.ts +14 -6
- package/src/shared/cost-guard.ts +2 -2
- package/src/shared/exact-apply.ts +1 -1
- package/src/shared/execution-context.ts +2 -2
- package/src/shared/extract-structured-output.ts +2 -2
- package/src/shared/filereview/__tests__/capture.test.ts +9 -5
- package/src/shared/filereview/__tests__/git-substrate.test.ts +4 -1
- package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +3 -3
- package/src/shared/filereview/cas-touched.ts +2 -2
- package/src/shared/filereview/progress.ts +13 -0
- package/src/shared/heartbeat.ts +1 -1
- package/src/shared/llm-backend.ts +0 -4
- package/src/shared/memory-attachment.ts +22 -10
- package/src/shared/model-error.ts +1 -2
- package/src/shared/persist-decision.ts +19 -28
- package/src/shared/prompt-sections.ts +4 -4
- package/src/shared/run-credential-store.ts +45 -0
- package/src/shared/run-credential.ts +70 -0
- package/src/shared/skill-resolver.ts +3 -3
- package/src/shared/status-offload.ts +2 -2
- package/src/shared/streaming-scheduler.ts +8 -13
- package/src/shared/subagent-rows.ts +2 -2
- package/src/shared/synthesized-attachment.ts +38 -3
- package/src/shared/todos.ts +3 -3
- package/src/shared/tool-row.ts +38 -2
- package/src/shared/worker-shutdown.ts +1 -1
- package/src/shared/workspace/__tests__/git-source.test.ts +3 -3
- package/src/shared/workspace/__tests__/provisioner.test.ts +5 -5
- package/src/shared/workspace/__tests__/session-provision.test.ts +2 -2
- package/src/shared/workspace/__tests__/writeback-coordinator.integration.test.ts +8 -9
- package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +25 -25
- package/src/shared/workspace/provisioner.ts +1 -1
- package/src/shared/workspace/session-provision.ts +1 -1
- package/src/shared/workspace/sources/empty.ts +2 -2
- package/src/shared/workspace/sources/git.ts +3 -4
- package/src/shared/workspace/sources/local-path.ts +5 -6
- package/src/shared/workspace/stigmer-link.ts +1 -1
- package/src/shared/workspace/types.ts +2 -5
- package/src/shared/workspace/writeback-coordinator.ts +23 -12
- package/src/worker.ts +15 -3
- package/src/workflow-source.ts +15 -0
- package/src/workflows/__tests__/run-credential-interceptor.test.ts +178 -0
- package/src/workflows/execute-from-execution.ts +17 -0
- package/src/workflows/index.ts +5 -3
- package/src/workflows/interceptors/run-credential.ts +101 -0
- package/dist/activities/execute-cursor/delta-enricher.d.ts +0 -87
- package/dist/activities/execute-cursor/delta-enricher.js +0 -265
- package/dist/activities/execute-cursor/delta-enricher.js.map +0 -1
- package/dist/activities/execute-cursor/message-translator.js +0 -2040
- package/dist/activities/execute-cursor/message-translator.js.map +0 -1
- package/dist/activities/execute-cursor/todo-tracker.d.ts +0 -40
- package/dist/activities/execute-cursor/todo-tracker.js +0 -80
- package/dist/activities/execute-cursor/todo-tracker.js.map +0 -1
- package/dist/activities/execute-deep-agent/execution-state.d.ts +0 -54
- package/dist/activities/execute-deep-agent/execution-state.js +0 -68
- package/dist/activities/execute-deep-agent/execution-state.js.map +0 -1
- package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +0 -65
- package/dist/activities/execute-deep-agent/status-builder-shared.js +0 -90
- package/dist/activities/execute-deep-agent/status-builder-shared.js.map +0 -1
- package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +0 -113
- package/dist/activities/execute-deep-agent/subagent-tracker.js +0 -400
- package/dist/activities/execute-deep-agent/subagent-tracker.js.map +0 -1
- package/dist/activities/execute-deep-agent/v3-events.d.ts +0 -102
- package/dist/activities/execute-deep-agent/v3-events.js +0 -35
- package/dist/activities/execute-deep-agent/v3-events.js.map +0 -1
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +0 -15
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +0 -235
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +0 -1
- package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +0 -111
- package/dist/activities/execute-deep-agent/v3-status-builder.js +0 -457
- package/dist/activities/execute-deep-agent/v3-status-builder.js.map +0 -1
- package/dist/shared/execution-status-writer.d.ts +0 -31
- package/dist/shared/execution-status-writer.js +0 -43
- package/dist/shared/execution-status-writer.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +0 -310
- package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -1033
- package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +0 -498
- package/src/activities/execute-cursor/delta-enricher.ts +0 -307
- package/src/activities/execute-cursor/message-translator.ts +0 -2319
- package/src/activities/execute-cursor/todo-tracker.ts +0 -91
- package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -148
- package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -154
- package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +0 -47
- package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +0 -324
- package/src/activities/execute-deep-agent/execution-state.ts +0 -78
- package/src/activities/execute-deep-agent/status-builder-shared.ts +0 -142
- package/src/activities/execute-deep-agent/subagent-tracker.ts +0 -479
- package/src/activities/execute-deep-agent/v3-events.ts +0 -153
- package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +0 -264
- package/src/activities/execute-deep-agent/v3-status-builder.ts +0 -565
- package/src/shared/execution-status-writer.ts +0 -56
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hermetic golden: an UNGATED tool call that FAILS — a `read` the SDK streams
|
|
3
|
+
* as `running` and then `error` with the failure text as its result — through
|
|
4
|
+
* the whole `ExecuteCursor` activity.
|
|
5
|
+
*
|
|
6
|
+
* Invariant pinned: the error event folds onto the same row
|
|
7
|
+
* (the builder's `tool_error` upsert) as FAILED, with the failure text
|
|
8
|
+
* in `error` and `result` EMPTY, `completedAt` stamped, no approval fields (a
|
|
9
|
+
* read-only built-in is not gated, and the text is not Cursor's hook-block
|
|
10
|
+
* copy, so the boundary's #205 pass leaves it alone), and the turn still ends
|
|
11
|
+
* COMPLETED: a failed read is the model's problem to route around, not the
|
|
12
|
+
* turn's.
|
|
13
|
+
*
|
|
14
|
+
* Moved 2026-09-14 (#1097), one line: until then the accumulator
|
|
15
|
+
* wrote the failure text to BOTH `error` and `result`. Native writes `error`
|
|
16
|
+
* alone, as do this harness's own sub-agent rows, and every reader shows
|
|
17
|
+
* `error || result`; the duplicate's one behavioral reader was the twin
|
|
18
|
+
* collapse's `carriesOwnChange`, which took a hook-denied shell for a row
|
|
19
|
+
* carrying its own output. `startedAt` was already
|
|
20
|
+
* present because the `running` event came first.
|
|
21
|
+
*
|
|
22
|
+
* Why this net exists: the one FAILED row among the seventeen Cursor goldens
|
|
23
|
+
* is the gate's own case (`unattributed-hook-block`); the ordinary tool
|
|
24
|
+
* failure — the fold #1097 rewrote — had no end-to-end net.
|
|
25
|
+
*
|
|
26
|
+
* Regenerate ONLY after a deliberate behavior change:
|
|
27
|
+
* npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
31
|
+
import { toJson } from "@bufbuild/protobuf";
|
|
32
|
+
import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
33
|
+
import { ExecutionPhase, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
34
|
+
|
|
35
|
+
vi.mock("@cursor/sdk", async () =>
|
|
36
|
+
(await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
|
|
37
|
+
);
|
|
38
|
+
vi.mock("../../../../client/stigmer-client.js", async () =>
|
|
39
|
+
(await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
import {
|
|
43
|
+
ScriptedClock,
|
|
44
|
+
createHermeticEnvironment,
|
|
45
|
+
type HermeticEnvironment,
|
|
46
|
+
} from "../../../../__test-utils__/hermetic-activity.js";
|
|
47
|
+
import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
|
|
48
|
+
import {
|
|
49
|
+
FIXTURE,
|
|
50
|
+
SDK_CATALOG,
|
|
51
|
+
beginCursorScenario,
|
|
52
|
+
cursorExecutionRecord,
|
|
53
|
+
runCursorTurn,
|
|
54
|
+
} from "../../__test-utils__/hermetic-cursor.js";
|
|
55
|
+
import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
|
|
56
|
+
|
|
57
|
+
const AGENT_ID = "agent-hermetic-toolerror-0001";
|
|
58
|
+
const RUN_ID = "run-hermetic-toolerror-0001";
|
|
59
|
+
const CALL_ID = "call-hermetic-toolerror-read-0001";
|
|
60
|
+
const USER_MESSAGE = "What is in MISSING.md?";
|
|
61
|
+
const TEXT_BEFORE = "Let me read it.";
|
|
62
|
+
const READ_ARGS = { path: "MISSING.md" };
|
|
63
|
+
const READ_ERROR = "ENOENT: no such file or directory, open 'MISSING.md'";
|
|
64
|
+
const TEXT_AFTER = "There is no MISSING.md in this workspace.";
|
|
65
|
+
|
|
66
|
+
describe("ExecuteCursor hermetic — an ungated tool call that fails", () => {
|
|
67
|
+
let env: HermeticEnvironment;
|
|
68
|
+
let registry: ReturnType<typeof stubRegistryFetch>;
|
|
69
|
+
const clock = new ScriptedClock();
|
|
70
|
+
|
|
71
|
+
beforeAll(() => {
|
|
72
|
+
env = createHermeticEnvironment();
|
|
73
|
+
registry = stubRegistryFetch();
|
|
74
|
+
clock.install();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
afterAll(() => {
|
|
78
|
+
clock.uninstall();
|
|
79
|
+
registry.restore();
|
|
80
|
+
env.dispose();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("folds running -> error into one FAILED row carrying the failure text and completes", async () => {
|
|
84
|
+
// ── Arrange ──────────────────────────────────────────────────────────────
|
|
85
|
+
const ev = sdkEvents(AGENT_ID, RUN_ID);
|
|
86
|
+
const agent = new ScriptedCursorAgent({
|
|
87
|
+
agentId: AGENT_ID,
|
|
88
|
+
runIds: [RUN_ID],
|
|
89
|
+
observeStep: () => clock.tick(),
|
|
90
|
+
turns: [
|
|
91
|
+
[
|
|
92
|
+
step.event(ev.init()),
|
|
93
|
+
step.event(ev.assistant(TEXT_BEFORE)),
|
|
94
|
+
step.event(ev.toolCall(CALL_ID, "read", "running", READ_ARGS)),
|
|
95
|
+
step.event(ev.toolCall(CALL_ID, "read", "error", READ_ARGS, READ_ERROR)),
|
|
96
|
+
step.event(ev.assistant(TEXT_AFTER)),
|
|
97
|
+
step.turnEnded({ inputTokens: 1_900, outputTokens: 70, cacheReadTokens: 0, cacheWriteTokens: 0 }),
|
|
98
|
+
step.finished({ result: TEXT_AFTER, model: { id: FIXTURE.model, params: [] } }),
|
|
99
|
+
],
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
const record = cursorExecutionRecord({ message: USER_MESSAGE });
|
|
103
|
+
const scenario = beginCursorScenario({
|
|
104
|
+
env,
|
|
105
|
+
clock,
|
|
106
|
+
record,
|
|
107
|
+
sdk: { agents: [agent], catalog: SDK_CATALOG },
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// ── Act ──────────────────────────────────────────────────────────────────
|
|
111
|
+
const invocation = await runCursorTurn(scenario);
|
|
112
|
+
|
|
113
|
+
// ── Assert: a failed read does not fail the turn ─────────────────────────
|
|
114
|
+
expect(invocation.outcome.kind).toBe("returned");
|
|
115
|
+
expect((invocation.outcome as { value: Record<string, unknown> }).value.phase).toBe("EXECUTION_COMPLETED");
|
|
116
|
+
expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
|
|
117
|
+
|
|
118
|
+
// ── Assert: the one FAILED row ───────────────────────────────────────────
|
|
119
|
+
const rows = record.toolCalls();
|
|
120
|
+
expect(rows, "running + error fold into ONE row").toHaveLength(1);
|
|
121
|
+
const row = rows[0];
|
|
122
|
+
expect(row.id).toBe(CALL_ID);
|
|
123
|
+
expect(row.status).toBe(ToolCallStatus.TOOL_CALL_FAILED);
|
|
124
|
+
expect(row.error, "the failure text is the error").toBe(READ_ERROR);
|
|
125
|
+
expect(row.result, "and only the error").toBe("");
|
|
126
|
+
expect(row.requiresApproval, "an ordinary failure is not an approval gate").toBe(false);
|
|
127
|
+
expect(row.approvalRequestedAt).toBe("");
|
|
128
|
+
expect(row.startedAt < row.completedAt).toBe(true);
|
|
129
|
+
|
|
130
|
+
// ── Assert: hermeticity ──────────────────────────────────────────────────
|
|
131
|
+
expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
|
|
132
|
+
|
|
133
|
+
// ── Assert: the golden ───────────────────────────────────────────────────
|
|
134
|
+
const final = record.lastFullStatus!;
|
|
135
|
+
const json = JSON.stringify(toJson(AgentExecutionStatusSchema, final), null, 2) + "\n";
|
|
136
|
+
await expect(json).toMatchFileSnapshot("./goldens/tool-error.status.json");
|
|
137
|
+
});
|
|
138
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hermetic golden: a turn whose FIRST event after `init` is a tool call — no
|
|
3
|
+
* assistant text proposed it — through the whole `ExecuteCursor` activity.
|
|
4
|
+
*
|
|
5
|
+
* Invariant pinned: a tool call with no AI message before it in
|
|
6
|
+
* its scope gets an EMPTY AI message created to carry its row
|
|
7
|
+
* (the builder's AI-message boundary), and the assistant text
|
|
8
|
+
* that follows the tool opens a new message. So: AI(`""` + the read row),
|
|
9
|
+
* AI(A1). This is the same shape the native builder produces for a model turn
|
|
10
|
+
* that proposes tools without text (`ensureAiMessageForToolCall`), which is
|
|
11
|
+
* why the canonical builder can serve both.
|
|
12
|
+
*
|
|
13
|
+
* Predicted for the swap to the shared builder (2026-09-14): NO move.
|
|
14
|
+
* The boundary rule ("the scope's current AI message, lazily created empty when
|
|
15
|
+
* the scope's latest model run had no text") produces exactly this transcript.
|
|
16
|
+
*
|
|
17
|
+
* Why this net exists: `tool-call.status.json` pins text→tool→text; nothing
|
|
18
|
+
* pinned a tool with no proposing text before this net.
|
|
19
|
+
*
|
|
20
|
+
* Regenerate ONLY after a deliberate behavior change:
|
|
21
|
+
* npx vitest run src/activities/execute-cursor/__tests__/hermetic -u
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
25
|
+
import { toJson } from "@bufbuild/protobuf";
|
|
26
|
+
import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
27
|
+
import { ExecutionPhase, MessageType, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
28
|
+
|
|
29
|
+
vi.mock("@cursor/sdk", async () =>
|
|
30
|
+
(await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule(),
|
|
31
|
+
);
|
|
32
|
+
vi.mock("../../../../client/stigmer-client.js", async () =>
|
|
33
|
+
(await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
import {
|
|
37
|
+
ScriptedClock,
|
|
38
|
+
createHermeticEnvironment,
|
|
39
|
+
type HermeticEnvironment,
|
|
40
|
+
} from "../../../../__test-utils__/hermetic-activity.js";
|
|
41
|
+
import { ScriptedCursorAgent, sdkEvents, step } from "../../__test-utils__/scripted-agent.js";
|
|
42
|
+
import {
|
|
43
|
+
FIXTURE,
|
|
44
|
+
SDK_CATALOG,
|
|
45
|
+
beginCursorScenario,
|
|
46
|
+
cursorExecutionRecord,
|
|
47
|
+
runCursorTurn,
|
|
48
|
+
} from "../../__test-utils__/hermetic-cursor.js";
|
|
49
|
+
import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
|
|
50
|
+
|
|
51
|
+
const AGENT_ID = "agent-hermetic-toolonly-0001";
|
|
52
|
+
const RUN_ID = "run-hermetic-toolonly-0001";
|
|
53
|
+
const CALL_ID = "call-hermetic-toolonly-read-0001";
|
|
54
|
+
const USER_MESSAGE = "What is in README.md?";
|
|
55
|
+
const READ_ARGS = { path: "README.md" };
|
|
56
|
+
const READ_RESULT = "# Hermetic\n\nA fixture readme.\n";
|
|
57
|
+
const ASSISTANT_TEXT = "README.md holds a one-line fixture description.";
|
|
58
|
+
|
|
59
|
+
describe("ExecuteCursor hermetic — a tool call with no proposing text", () => {
|
|
60
|
+
let env: HermeticEnvironment;
|
|
61
|
+
let registry: ReturnType<typeof stubRegistryFetch>;
|
|
62
|
+
const clock = new ScriptedClock();
|
|
63
|
+
|
|
64
|
+
beforeAll(() => {
|
|
65
|
+
env = createHermeticEnvironment();
|
|
66
|
+
registry = stubRegistryFetch();
|
|
67
|
+
clock.install();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterAll(() => {
|
|
71
|
+
clock.uninstall();
|
|
72
|
+
registry.restore();
|
|
73
|
+
env.dispose();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("creates an empty AI message for the row and a new one for the text that follows", async () => {
|
|
77
|
+
// ── Arrange ──────────────────────────────────────────────────────────────
|
|
78
|
+
const ev = sdkEvents(AGENT_ID, RUN_ID);
|
|
79
|
+
const agent = new ScriptedCursorAgent({
|
|
80
|
+
agentId: AGENT_ID,
|
|
81
|
+
runIds: [RUN_ID],
|
|
82
|
+
observeStep: () => clock.tick(),
|
|
83
|
+
turns: [
|
|
84
|
+
[
|
|
85
|
+
step.event(ev.init()),
|
|
86
|
+
step.event(ev.toolCall(CALL_ID, "read", "running", READ_ARGS)),
|
|
87
|
+
step.event(ev.toolCall(CALL_ID, "read", "completed", READ_ARGS, READ_RESULT)),
|
|
88
|
+
step.event(ev.assistant(ASSISTANT_TEXT)),
|
|
89
|
+
step.turnEnded({ inputTokens: 1_800, outputTokens: 60, cacheReadTokens: 0, cacheWriteTokens: 0 }),
|
|
90
|
+
step.finished({ result: ASSISTANT_TEXT, model: { id: FIXTURE.model, params: [] } }),
|
|
91
|
+
],
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
const record = cursorExecutionRecord({ message: USER_MESSAGE });
|
|
95
|
+
const scenario = beginCursorScenario({
|
|
96
|
+
env,
|
|
97
|
+
clock,
|
|
98
|
+
record,
|
|
99
|
+
sdk: { agents: [agent], catalog: SDK_CATALOG },
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ── Act ──────────────────────────────────────────────────────────────────
|
|
103
|
+
const invocation = await runCursorTurn(scenario);
|
|
104
|
+
|
|
105
|
+
// ── Assert: outcome ──────────────────────────────────────────────────────
|
|
106
|
+
expect(invocation.outcome.kind).toBe("returned");
|
|
107
|
+
expect((invocation.outcome as { value: Record<string, unknown> }).value.phase).toBe("EXECUTION_COMPLETED");
|
|
108
|
+
expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
|
|
109
|
+
|
|
110
|
+
// ── Assert: the transcript ───────────────────────────────────────────────
|
|
111
|
+
const final = record.lastFullStatus!;
|
|
112
|
+
expect(
|
|
113
|
+
final.messages.map((m) => [m.type, m.content, m.toolCalls.map((tc) => tc.id)]),
|
|
114
|
+
"an empty AI message carries the row; the text after the tool is a new message",
|
|
115
|
+
).toEqual([
|
|
116
|
+
[MessageType.MESSAGE_AI, "", [CALL_ID]],
|
|
117
|
+
[MessageType.MESSAGE_AI, ASSISTANT_TEXT, []],
|
|
118
|
+
]);
|
|
119
|
+
const row = record.toolCalls()[0];
|
|
120
|
+
expect(row.status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
|
|
121
|
+
expect(row.result).toBe(READ_RESULT);
|
|
122
|
+
|
|
123
|
+
// ── Assert: hermeticity ──────────────────────────────────────────────────
|
|
124
|
+
expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
|
|
125
|
+
|
|
126
|
+
// ── Assert: the golden ───────────────────────────────────────────────────
|
|
127
|
+
const json = JSON.stringify(toJson(AgentExecutionStatusSchema, final), null, 2) + "\n";
|
|
128
|
+
await expect(json).toMatchFileSnapshot("./goldens/tool-only-step.status.json");
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -21,6 +21,18 @@
|
|
|
21
21
|
* Engine disposition on this arm, today: the handle is `close()`d, not parked
|
|
22
22
|
* (index.ts `enterUnattributedHookBlockFailure`).
|
|
23
23
|
*
|
|
24
|
+
* Moved 2026-09-14 (#1097), one line: the FAILED row — built from
|
|
25
|
+
* a single `status: "error"` event with no `running` before it — carries
|
|
26
|
+
* `startedAt`, equal to its `completedAt`: the instant the runner first
|
|
27
|
+
* learned of the call. Until then a completed-only event left the field unset,
|
|
28
|
+
* the one field the canonical builder stamps at every row's creation. This
|
|
29
|
+
* is the only Cursor golden that scripts a completed-only event (the three
|
|
30
|
+
* moves predicted for that rule were all this one).
|
|
31
|
+
*
|
|
32
|
+
* Moved again the same day (#1097), one line: the FAILED row's
|
|
33
|
+
* `result` no longer duplicates its `error` — the hook-block text lives in
|
|
34
|
+
* `error` alone, which is the field the #205 detector reads.
|
|
35
|
+
*
|
|
24
36
|
* Parent phase rows exercised beyond the earlier scenarios: the gate install's
|
|
25
37
|
* foreign-hook detection (`workspace-setup.ts` `mergeHooks`); the FAILED
|
|
26
38
|
* tool-call row built from a single `status: "error"` event; the boundary's
|
|
@@ -83,7 +95,7 @@ const USER_HOOKS_JSON =
|
|
|
83
95
|
JSON.stringify({ version: 1, hooks: { preToolUse: [{ command: FOREIGN_HOOK_COMMAND }] } }, null, 2) + "\n";
|
|
84
96
|
/**
|
|
85
97
|
* The error text Cursor stamps on a hook-blocked tool call
|
|
86
|
-
* (`
|
|
98
|
+
* (`boundary-rows.ts` HOOK_BLOCK_ERROR_MARKERS). The SDK has no structured
|
|
87
99
|
* "denied by hook" signal; this text is the only stream-side trace.
|
|
88
100
|
*/
|
|
89
101
|
const HOOK_BLOCK_ERROR = "blocked by a hook";
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* `Agent.create`, no `harness_state_id` bind, nothing streamed.
|
|
14
14
|
*
|
|
15
15
|
* Why this is the one terminal arm WITHOUT a file golden (owner ruling,
|
|
16
|
-
* 2026-09-11,
|
|
16
|
+
* 2026-09-11, #1070): the wire copy embeds the absolute
|
|
17
17
|
* workspace path, which is a per-run temp directory and differs between macOS
|
|
18
|
-
* and CI. The
|
|
18
|
+
* and CI. The hermetic driver's rule (#1048) is to control a volatile source at its origin
|
|
19
19
|
* or escalate — never redact — so this scenario pins every byte the path does
|
|
20
20
|
* not touch with explicit assertions and builds the expected message with the
|
|
21
21
|
* SAME error class over the real resolved path.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @regression file-hitl-phase0 — pins
|
|
2
|
+
* @regression file-hitl-phase0 — pins four rules of the file-edit gate: one
|
|
3
|
+
* approval gate per turn (a distinct co-pending sibling defers to SKIPPED);
|
|
4
|
+
* decisions bind to the active turn's ledger, never a stale one; the executed
|
|
5
|
+
* capture supersedes the model's proposal; the hook-captured input is
|
|
6
|
+
* authoritative over the streamed snapshot.
|
|
3
7
|
*
|
|
4
8
|
* Unit tests for the Cursor-harness HITL denial-ledger flow.
|
|
5
9
|
*
|
|
@@ -61,11 +65,12 @@ import {
|
|
|
61
65
|
reconcileDeniedToolCalls,
|
|
62
66
|
clearProvisionalPostDenialNarration,
|
|
63
67
|
collapseRedundantToolCallTwins,
|
|
64
|
-
toolCallIdentityToken,
|
|
65
68
|
detectUnattributedHookBlocks,
|
|
66
69
|
stampUnattendedSkippedToolCalls,
|
|
67
70
|
HOOK_BLOCK_ERROR_MARKERS,
|
|
68
|
-
} from "../
|
|
71
|
+
} from "../boundary-rows.js";
|
|
72
|
+
import { builderOver } from "../__test-utils__/fold.js";
|
|
73
|
+
import { toolCallIdentityToken } from "../approval-state.js";
|
|
69
74
|
import { mockWorkspaceBackend } from "../../../__test-utils__/mock-workspace.js";
|
|
70
75
|
import type { WorkspaceBackend } from "../../../shared/workspace/types.js";
|
|
71
76
|
import { generateHookScript } from "../hook-script.js";
|
|
@@ -240,7 +245,7 @@ describe("reconcileDeniedToolCalls", () => {
|
|
|
240
245
|
});
|
|
241
246
|
const messages = [aiMessageWith([tc])];
|
|
242
247
|
|
|
243
|
-
const reconciled = await reconcileDeniedToolCalls(messages, [
|
|
248
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
|
|
244
249
|
{ toolName: "Write", token: grantToken("write", "gated.txt") },
|
|
245
250
|
]);
|
|
246
251
|
|
|
@@ -279,7 +284,7 @@ describe("reconcileDeniedToolCalls", () => {
|
|
|
279
284
|
]);
|
|
280
285
|
|
|
281
286
|
// MCP tools are keyed name-only (their name is consistent across layers).
|
|
282
|
-
await reconcileDeniedToolCalls(messages, [
|
|
287
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages), [
|
|
283
288
|
{ toolName: "apply_x", token: grantToken("apply_x", "") },
|
|
284
289
|
], policies);
|
|
285
290
|
|
|
@@ -302,7 +307,7 @@ describe("reconcileDeniedToolCalls", () => {
|
|
|
302
307
|
});
|
|
303
308
|
const messages = [aiMessageWith([denied, allowed])];
|
|
304
309
|
|
|
305
|
-
const reconciled = await reconcileDeniedToolCalls(messages, [
|
|
310
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
|
|
306
311
|
{ toolName: "Write", token: grantToken("write", "gated.txt") },
|
|
307
312
|
]);
|
|
308
313
|
|
|
@@ -323,7 +328,7 @@ describe("reconcileDeniedToolCalls", () => {
|
|
|
323
328
|
const second = toolCall({ id: "c2", name: "edit", args: { path: "gated.txt" } });
|
|
324
329
|
const messages = [aiMessageWith([first, second])];
|
|
325
330
|
|
|
326
|
-
const reconciled = await reconcileDeniedToolCalls(messages, [
|
|
331
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
|
|
327
332
|
{ toolName: "Write", token: grantToken("write", "gated.txt") },
|
|
328
333
|
]);
|
|
329
334
|
|
|
@@ -344,7 +349,7 @@ describe("reconcileDeniedToolCalls", () => {
|
|
|
344
349
|
it("synthesizes a WAITING_APPROVAL tool call when a denial produced no stream event", async () => {
|
|
345
350
|
const messages = [aiMessageWith([])];
|
|
346
351
|
|
|
347
|
-
const reconciled = await reconcileDeniedToolCalls(messages, [
|
|
352
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
|
|
348
353
|
{ toolName: "Shell", token: grantToken("shell", "rm -rf build") },
|
|
349
354
|
]);
|
|
350
355
|
|
|
@@ -363,7 +368,7 @@ describe("reconcileDeniedToolCalls", () => {
|
|
|
363
368
|
it("is a no-op when the ledger is empty", async () => {
|
|
364
369
|
const tc = toolCall({ id: "c1", status: ToolCallStatus.TOOL_CALL_COMPLETED });
|
|
365
370
|
const messages = [aiMessageWith([tc])];
|
|
366
|
-
expect(await reconcileDeniedToolCalls(messages, [])).toEqual([]);
|
|
371
|
+
expect(await reconcileDeniedToolCalls(messages, builderOver(messages), [])).toEqual([]);
|
|
367
372
|
expect(tc.status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
|
|
368
373
|
});
|
|
369
374
|
});
|
|
@@ -391,8 +396,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
|
|
|
391
396
|
});
|
|
392
397
|
const messages = [aiMessageWith([gate, twin])];
|
|
393
398
|
|
|
394
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
395
|
-
messages,
|
|
399
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
396
400
|
[{ toolName: "Write", token: grantToken("write", "notes.md") }],
|
|
397
401
|
undefined,
|
|
398
402
|
rootBackend(),
|
|
@@ -432,8 +436,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
|
|
|
432
436
|
});
|
|
433
437
|
const messages = [aiMessageWith([gate, twin])];
|
|
434
438
|
|
|
435
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
436
|
-
messages,
|
|
439
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
437
440
|
[{ toolName: "Shell", token: grantToken("shell", "rm -rf build") }],
|
|
438
441
|
undefined,
|
|
439
442
|
rootBackend(),
|
|
@@ -470,8 +473,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
|
|
|
470
473
|
});
|
|
471
474
|
const messages = [aiMessageWith([gateA, gateB])];
|
|
472
475
|
|
|
473
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
474
|
-
messages,
|
|
476
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
475
477
|
[
|
|
476
478
|
// The hook records the content-exact token for an edit (its primary token).
|
|
477
479
|
{ toolName: "Write", token: toolCallIdentityToken(gateA) },
|
|
@@ -508,8 +510,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
|
|
|
508
510
|
});
|
|
509
511
|
const messages = [aiMessageWith([gate, twin])];
|
|
510
512
|
|
|
511
|
-
await reconcileDeniedToolCalls(
|
|
512
|
-
messages,
|
|
513
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
513
514
|
[{ toolName: "Write", token: grantToken("write", "notes.md") }],
|
|
514
515
|
undefined,
|
|
515
516
|
rootBackend(),
|
|
@@ -552,8 +553,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
|
|
|
552
553
|
});
|
|
553
554
|
const messages = [aiMessageWith([edit, shell])];
|
|
554
555
|
|
|
555
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
556
|
-
messages,
|
|
556
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
557
557
|
[
|
|
558
558
|
{ toolName: "Write", token: grantToken("write", "notes.md") },
|
|
559
559
|
{ toolName: "Shell", token: grantToken("shell", "cat > notes.md") },
|
|
@@ -595,8 +595,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
|
|
|
595
595
|
});
|
|
596
596
|
const messages = [aiMessageWith([edit]), aiMessageWith([shell])];
|
|
597
597
|
|
|
598
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
599
|
-
messages,
|
|
598
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
600
599
|
[
|
|
601
600
|
{ toolName: "Write", token: grantToken("write", "notes.md") },
|
|
602
601
|
{ toolName: "Shell", token: grantToken("shell", "cat > notes.md") },
|
|
@@ -631,8 +630,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
|
|
|
631
630
|
});
|
|
632
631
|
const messages = [aiMessageWith([shell, edit])];
|
|
633
632
|
|
|
634
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
635
|
-
messages,
|
|
633
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
636
634
|
[
|
|
637
635
|
{ toolName: "Shell", token: toolCallIdentityToken(shell) },
|
|
638
636
|
{ toolName: "Write", token: toolCallIdentityToken(edit) },
|
|
@@ -666,8 +664,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
|
|
|
666
664
|
});
|
|
667
665
|
const messages = [aiMessageWith([mcp, edit])];
|
|
668
666
|
|
|
669
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
670
|
-
messages,
|
|
667
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
671
668
|
[
|
|
672
669
|
{ toolName: "fetch", token: toolCallIdentityToken(mcp) },
|
|
673
670
|
{ toolName: "Write", token: toolCallIdentityToken(edit) },
|
|
@@ -692,8 +689,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
|
|
|
692
689
|
});
|
|
693
690
|
const messages = [aiMessageWith([edit])];
|
|
694
691
|
|
|
695
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
696
|
-
messages,
|
|
692
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
697
693
|
[{ toolName: "Write", token: grantToken("write", "notes.md") }],
|
|
698
694
|
undefined,
|
|
699
695
|
rootBackend(),
|
|
@@ -725,8 +721,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
|
|
|
725
721
|
});
|
|
726
722
|
const messages = [aiMessageWith([edit, shell])];
|
|
727
723
|
|
|
728
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
729
|
-
messages,
|
|
724
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
730
725
|
[
|
|
731
726
|
{ toolName: "Write", token: grantToken("write", "notes.md") },
|
|
732
727
|
{ toolName: "Shell", token: grantToken("shell", "cat > notes.md") },
|
|
@@ -801,8 +796,7 @@ describe("reconcileDeniedToolCalls — interrupted non-terminal rows (raced work
|
|
|
801
796
|
];
|
|
802
797
|
|
|
803
798
|
// Only the anchor's denial is in the ledger — the workaround's raced it.
|
|
804
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
805
|
-
messages,
|
|
799
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
806
800
|
[{ toolName: "Shell", token: toolCallIdentityToken(anchor) }],
|
|
807
801
|
undefined,
|
|
808
802
|
rootBackend(),
|
|
@@ -848,8 +842,7 @@ describe("reconcileDeniedToolCalls — interrupted non-terminal rows (raced work
|
|
|
848
842
|
create(AgentMessageSchema, { type: MessageType.MESSAGE_AI, content: "trailing reaction" }),
|
|
849
843
|
];
|
|
850
844
|
|
|
851
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
852
|
-
messages,
|
|
845
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
853
846
|
[{ toolName: "Shell", token: toolCallIdentityToken(anchor) }],
|
|
854
847
|
undefined,
|
|
855
848
|
rootBackend(),
|
|
@@ -1066,8 +1059,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
|
|
|
1066
1059
|
});
|
|
1067
1060
|
const messages = [aiMessageWith([tc])];
|
|
1068
1061
|
|
|
1069
|
-
await reconcileDeniedToolCalls(
|
|
1070
|
-
messages,
|
|
1062
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1071
1063
|
[{
|
|
1072
1064
|
toolName: "Write",
|
|
1073
1065
|
token: grantToken("write", "src/new.ts"),
|
|
@@ -1097,8 +1089,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
|
|
|
1097
1089
|
});
|
|
1098
1090
|
const messages = [aiMessageWith([tc])];
|
|
1099
1091
|
|
|
1100
|
-
await reconcileDeniedToolCalls(
|
|
1101
|
-
messages,
|
|
1092
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1102
1093
|
[{
|
|
1103
1094
|
toolName: "Write",
|
|
1104
1095
|
token: grantToken("write", ".env"),
|
|
@@ -1122,8 +1113,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
|
|
|
1122
1113
|
});
|
|
1123
1114
|
const messages = [aiMessageWith([tc])];
|
|
1124
1115
|
|
|
1125
|
-
await reconcileDeniedToolCalls(
|
|
1126
|
-
messages,
|
|
1116
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1127
1117
|
[{
|
|
1128
1118
|
toolName: "StrReplace",
|
|
1129
1119
|
token: grantToken("write", "src/app.ts"),
|
|
@@ -1147,8 +1137,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
|
|
|
1147
1137
|
});
|
|
1148
1138
|
const messages = [aiMessageWith([tc])];
|
|
1149
1139
|
|
|
1150
|
-
await reconcileDeniedToolCalls(
|
|
1151
|
-
messages,
|
|
1140
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1152
1141
|
[{
|
|
1153
1142
|
toolName: "EditNotebook",
|
|
1154
1143
|
token: grantToken("write", "nb.ipynb"),
|
|
@@ -1170,8 +1159,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
|
|
|
1170
1159
|
});
|
|
1171
1160
|
const messages = [aiMessageWith([tc])];
|
|
1172
1161
|
|
|
1173
|
-
await reconcileDeniedToolCalls(
|
|
1174
|
-
messages,
|
|
1162
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1175
1163
|
[{
|
|
1176
1164
|
toolName: "Shell",
|
|
1177
1165
|
token: grantToken("shell", "rm -rf build"),
|
|
@@ -1190,8 +1178,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
|
|
|
1190
1178
|
// proposed content from the captured input, not a bare {path}.
|
|
1191
1179
|
const messages = [aiMessageWith([])];
|
|
1192
1180
|
|
|
1193
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
1194
|
-
messages,
|
|
1181
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1195
1182
|
[{
|
|
1196
1183
|
toolName: "Write",
|
|
1197
1184
|
token: grantToken("write", "ghost.md"),
|
|
@@ -1217,8 +1204,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
|
|
|
1217
1204
|
});
|
|
1218
1205
|
const messages = [aiMessageWith([tc])];
|
|
1219
1206
|
|
|
1220
|
-
await reconcileDeniedToolCalls(
|
|
1221
|
-
messages,
|
|
1207
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1222
1208
|
[{
|
|
1223
1209
|
toolName: "Write",
|
|
1224
1210
|
token: grantToken("write", "big.ts"),
|
|
@@ -1259,8 +1245,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
|
|
|
1259
1245
|
});
|
|
1260
1246
|
const messages = [aiMessageWith([streamed])];
|
|
1261
1247
|
|
|
1262
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
1263
|
-
messages,
|
|
1248
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1264
1249
|
[{ toolName: "Write", token: grantToken("write", "/root/notes.md") }],
|
|
1265
1250
|
undefined,
|
|
1266
1251
|
rootBackend(),
|
|
@@ -1288,8 +1273,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
|
|
|
1288
1273
|
});
|
|
1289
1274
|
const messages = [aiMessageWith([streamed])];
|
|
1290
1275
|
|
|
1291
|
-
await reconcileDeniedToolCalls(
|
|
1292
|
-
messages,
|
|
1276
|
+
await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1293
1277
|
[{ toolName: "Write", token: grantToken("write", "/root/src/app.ts") }],
|
|
1294
1278
|
undefined,
|
|
1295
1279
|
rootBackend(),
|
|
@@ -1304,8 +1288,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
|
|
|
1304
1288
|
// The genuine no-stream-event denial (rare) must still surface a gate.
|
|
1305
1289
|
const messages = [aiMessageWith([])];
|
|
1306
1290
|
|
|
1307
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
1308
|
-
messages,
|
|
1291
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1309
1292
|
[{ toolName: "Write", token: grantToken("write", "/root/ghost.md") }],
|
|
1310
1293
|
undefined,
|
|
1311
1294
|
rootBackend(),
|
|
@@ -1327,8 +1310,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
|
|
|
1327
1310
|
});
|
|
1328
1311
|
const messages = [aiMessageWith([streamed])];
|
|
1329
1312
|
|
|
1330
|
-
const reconciled = await reconcileDeniedToolCalls(
|
|
1331
|
-
messages,
|
|
1313
|
+
const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
|
|
1332
1314
|
[{ toolName: "Write", token: grantToken("write", "/root/notes.md") }],
|
|
1333
1315
|
undefined,
|
|
1334
1316
|
rootBackend(),
|
|
@@ -1566,7 +1548,7 @@ describe("first-denial stop contract", () => {
|
|
|
1566
1548
|
expect(messages.some((m) => m.content.includes("try the shell"))).toBe(false);
|
|
1567
1549
|
|
|
1568
1550
|
// Phase 12 reconcile + redact on the stopped transcript yields the clean shape.
|
|
1569
|
-
const denied = await reconcileDeniedToolCalls(messages, await readDenialLedger(ws));
|
|
1551
|
+
const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), await readDenialLedger(ws));
|
|
1570
1552
|
expect(denied).toHaveLength(1);
|
|
1571
1553
|
expect(edit.status).toBe(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
|
|
1572
1554
|
const redacted = clearProvisionalPostDenialNarration(messages, denied);
|
|
@@ -1610,7 +1592,8 @@ describe("first-denial stop contract", () => {
|
|
|
1610
1592
|
expect(cancelled).toBe(false);
|
|
1611
1593
|
expect(consumed).toBe(3); // the whole turn is consumed
|
|
1612
1594
|
// And the boundary reconcile manufactures no gate from it either.
|
|
1613
|
-
const
|
|
1595
|
+
const messages: AgentMessage[] = [];
|
|
1596
|
+
const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), await readDenialLedger(ws));
|
|
1614
1597
|
expect(denied).toEqual([]);
|
|
1615
1598
|
});
|
|
1616
1599
|
|
|
@@ -1641,7 +1624,7 @@ describe("first-denial stop contract", () => {
|
|
|
1641
1624
|
|
|
1642
1625
|
// Phase 12 on the stopped transcript: the anchor gates, and the one raced
|
|
1643
1626
|
// reaction message is blanked by the trim backstop.
|
|
1644
|
-
const denied = await reconcileDeniedToolCalls(messages, await readDenialLedger(ws), undefined, rootBackend());
|
|
1627
|
+
const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), await readDenialLedger(ws), undefined, rootBackend());
|
|
1645
1628
|
expect(denied).toHaveLength(1);
|
|
1646
1629
|
expect(shell.status).toBe(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
|
|
1647
1630
|
const redacted = clearProvisionalPostDenialNarration(messages, denied);
|
|
@@ -1812,7 +1795,7 @@ describe("reconcileDeniedToolCalls — non-approval kinds never gate", () => {
|
|
|
1812
1795
|
error: "blocked by a hook", args: { path: ".env" },
|
|
1813
1796
|
});
|
|
1814
1797
|
const messages = [aiMessageWith([secretRow])];
|
|
1815
|
-
const denied = await reconcileDeniedToolCalls(messages, [
|
|
1798
|
+
const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), [
|
|
1816
1799
|
{ toolName: "Write", token: toolCallIdentityToken(secretRow), kind: "secret" },
|
|
1817
1800
|
{ toolName: "Write", token: grantToken("write", "app.log"), kind: "capture-error" },
|
|
1818
1801
|
{ toolName: "Shell", token: grantToken("shell", "make"), kind: "fail-closed" },
|
|
@@ -1834,7 +1817,7 @@ describe("reconcileDeniedToolCalls — non-approval kinds never gate", () => {
|
|
|
1834
1817
|
error: "blocked by a hook", args: { path: ".env" },
|
|
1835
1818
|
});
|
|
1836
1819
|
const messages = [aiMessageWith([gated, secretRow])];
|
|
1837
|
-
const denied = await reconcileDeniedToolCalls(messages, [
|
|
1820
|
+
const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), [
|
|
1838
1821
|
// Ledger order puts the secret FIRST: the anchor must still be the first
|
|
1839
1822
|
// APPROVAL entry, never a non-approval kind.
|
|
1840
1823
|
{ toolName: "Write", token: toolCallIdentityToken(secretRow), kind: "secret" },
|