@stigmer/runner 3.15.3-dev.20260914100347 → 3.15.3-dev.20260916211208
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 +1 -0
- 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 +14 -11
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
- 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 +52 -14
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +46 -12
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +21 -28
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -11
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +70 -26
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +82 -32
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
- package/dist/activities/execute-cursor/adapter.d.ts +8 -7
- package/dist/activities/execute-cursor/adapter.js +13 -9
- package/dist/activities/execute-cursor/adapter.js.map +1 -1
- 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/sdk-warmup.d.ts +15 -6
- package/dist/activities/execute-cursor/sdk-warmup.js +15 -6
- package/dist/activities/execute-cursor/sdk-warmup.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/session-lifecycle.d.ts +38 -59
- package/dist/activities/execute-cursor/session-lifecycle.js +59 -96
- package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
- package/dist/activities/execute-cursor/session-store.d.ts +100 -0
- package/dist/activities/execute-cursor/session-store.js +157 -0
- package/dist/activities/execute-cursor/session-store.js.map +1 -0
- 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/config.d.ts +2 -2
- 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/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 +1 -1
- package/dist/runner-manager.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-vision.d.ts +2 -1
- package/dist/shared/attachment-vision.js.map +1 -1
- package/dist/shared/attachment-zip.d.ts +2 -2
- package/dist/shared/attachment-zip.js +2 -2
- 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/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/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/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/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/package.json +5 -5
- 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__/runner-manager.test.ts +1 -1
- package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +32 -8
- package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +12 -10
- 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 +72 -19
- package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +35 -29
- package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +94 -38
- 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-baseurl-routing.test.ts +10 -8
- 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 +24 -12
- package/src/activities/execute-cursor/__tests__/cursor-generate-image-live.test.ts +7 -2
- package/src/activities/execute-cursor/__tests__/cursor-hook-protocol-live.test.ts +163 -0
- package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +23 -20
- 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 +5 -2
- package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +5 -2
- 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 +10 -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 +8 -5
- package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +6 -2
- package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +4 -1
- package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +6 -2
- 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 +12 -9
- 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 +4 -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 +7 -4
- 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 +17 -2
- package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -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__/session-lifecycle.test.ts +86 -58
- package/src/activities/execute-cursor/__tests__/session-store.test.ts +220 -0
- 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 +13 -9
- 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/sdk-warmup.ts +15 -6
- package/src/activities/execute-cursor/service-tier.ts +1 -2
- package/src/activities/execute-cursor/session-lifecycle.ts +63 -109
- package/src/activities/execute-cursor/session-store.ts +187 -0
- 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/config.ts +2 -2
- 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/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 +1 -1
- 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__/cost-guard.test.ts +1 -1
- package/src/shared/__tests__/exact-apply.test.ts +2 -1
- package/src/shared/__tests__/persist-decision.test.ts +19 -33
- package/src/shared/__tests__/prompt-sections.test.ts +1 -1
- 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/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-vision.ts +2 -1
- package/src/shared/attachment-zip.ts +2 -2
- 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/heartbeat.ts +1 -1
- package/src/shared/llm-backend.ts +0 -4
- 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/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/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/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
|
@@ -11,12 +11,15 @@
|
|
|
11
11
|
* registry the harness reads at setup, the Cursor `Config` slice, and the
|
|
12
12
|
* per-scenario reset of the harness's module-level caches.
|
|
13
13
|
*
|
|
14
|
-
* What the
|
|
15
|
-
* hoisted by vitest and so cannot live here
|
|
14
|
+
* What the three `vi.mock` calls a scenario file must carry look like — they
|
|
15
|
+
* are hoisted by vitest and so cannot live here (the SDK's sqlite entry is a
|
|
16
|
+
* separate module id, so it is doubled separately; `scripted-sdk.ts`):
|
|
16
17
|
*
|
|
17
18
|
* ```ts
|
|
18
19
|
* vi.mock("@cursor/sdk", async () =>
|
|
19
20
|
* (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule());
|
|
21
|
+
* vi.mock("@cursor/sdk/sqlite", async () =>
|
|
22
|
+
* (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSqliteModule());
|
|
20
23
|
* vi.mock("../../../../client/stigmer-client.js", async () =>
|
|
21
24
|
* (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule());
|
|
22
25
|
* ```
|
|
@@ -39,6 +42,18 @@
|
|
|
39
42
|
* the SDK double (`ScriptedSdkOptions`); an SDK-side cancel or a mid-stream
|
|
40
43
|
* wedge as an `effect` step on the run. Nothing here is a switch in production
|
|
41
44
|
* code — every knob is a value the production path already reads.
|
|
45
|
+
*
|
|
46
|
+
* Two postures, two entries, one turn runner. `beginCursorScenario` is the
|
|
47
|
+
* hermetic posture: the SDK doubled by the scenario file's `vi.mock`, the
|
|
48
|
+
* clock scripted, goldens byte-stable. `beginLiveCursorScenario` is the live
|
|
49
|
+
* posture (#1097's live-run gate): the scenario file mocks ONLY the
|
|
50
|
+
* client, the real `@cursor/sdk` runs under the real activity on the real
|
|
51
|
+
* clock with a real member key, and what the activity persists is read back
|
|
52
|
+
* from the same record. A live scenario therefore has no `sdk` and no `clock`
|
|
53
|
+
* — the type says which posture a file is in — and `runCursorTurn` reads only
|
|
54
|
+
* what both have. The registry fixture's `live` pass-through and the
|
|
55
|
+
* environment's `eventRecordingDir` are the live posture's two other
|
|
56
|
+
* seams, each on the module that owns the concern.
|
|
42
57
|
*/
|
|
43
58
|
|
|
44
59
|
import { execFileSync } from "node:child_process";
|
|
@@ -213,20 +228,27 @@ export function resetCursorModuleState(): void {
|
|
|
213
228
|
_resetRegistryCache();
|
|
214
229
|
}
|
|
215
230
|
|
|
216
|
-
|
|
231
|
+
/** What both postures share: the environment, the record the activity persists into, the runner's `Config`. */
|
|
232
|
+
export interface CursorScenarioBase {
|
|
217
233
|
readonly env: HermeticEnvironment;
|
|
218
|
-
readonly clock: ScriptedClock;
|
|
219
234
|
readonly record: ExecutionRecord;
|
|
220
|
-
readonly sdk: ScriptedCursorSdk;
|
|
221
235
|
/** The runner this scenario runs on: the OSS posture plus the scenario's knobs. */
|
|
222
236
|
readonly config: Config;
|
|
223
237
|
}
|
|
224
238
|
|
|
225
|
-
|
|
226
|
-
|
|
239
|
+
/** The hermetic posture: the SDK double and the scripted clock beside the shared three. */
|
|
240
|
+
export interface CursorScenario extends CursorScenarioBase {
|
|
227
241
|
readonly clock: ScriptedClock;
|
|
242
|
+
readonly sdk: ScriptedCursorSdk;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** The live posture (header): the shared three and nothing doubled but the client. */
|
|
246
|
+
export type LiveCursorScenario = CursorScenarioBase;
|
|
247
|
+
|
|
248
|
+
/** The options both postures take. */
|
|
249
|
+
interface CursorScenarioBaseOptions {
|
|
250
|
+
readonly env: HermeticEnvironment;
|
|
228
251
|
readonly record: ExecutionRecord;
|
|
229
|
-
readonly sdk: ScriptedSdkOptions;
|
|
230
252
|
/**
|
|
231
253
|
* Control-plane facets the scenario opts INTO, or faults it injects, over
|
|
232
254
|
* the record's everyday answers (`ExecutionRecord.client`): a rejecting
|
|
@@ -242,21 +264,50 @@ export interface CursorScenarioOptions {
|
|
|
242
264
|
readonly config?: Partial<Config>;
|
|
243
265
|
}
|
|
244
266
|
|
|
245
|
-
|
|
246
|
-
|
|
267
|
+
export interface CursorScenarioOptions extends CursorScenarioBaseOptions {
|
|
268
|
+
readonly clock: ScriptedClock;
|
|
269
|
+
readonly sdk: ScriptedSdkOptions;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface LiveCursorScenarioOptions extends CursorScenarioBaseOptions {
|
|
273
|
+
/** The real member key the real SDK authenticates with; becomes `config.cursorApiKey`. */
|
|
274
|
+
readonly apiKey: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* What every scenario begins with: the harness caches dropped, the record
|
|
279
|
+
* bound as the control plane the activity will talk to, the OSS `Config`
|
|
280
|
+
* over the environment with the scenario's knobs laid on top.
|
|
281
|
+
*/
|
|
282
|
+
function beginScenarioBase(options: CursorScenarioBaseOptions): CursorScenarioBase {
|
|
247
283
|
resetCursorModuleState();
|
|
248
|
-
const sdk = new ScriptedCursorSdk(options.sdk);
|
|
249
|
-
bindScriptedSdk(sdk);
|
|
250
284
|
bindHermeticClient(options.record.client(options.clientOverrides));
|
|
251
285
|
return {
|
|
252
286
|
env: options.env,
|
|
253
|
-
clock: options.clock,
|
|
254
287
|
record: options.record,
|
|
255
|
-
sdk,
|
|
256
288
|
config: { ...hermeticCursorConfig(options.env), ...options.config },
|
|
257
289
|
};
|
|
258
290
|
}
|
|
259
291
|
|
|
292
|
+
/** Bind the record and the SDK double for a hermetic scenario; resets the harness caches first. */
|
|
293
|
+
export function beginCursorScenario(options: CursorScenarioOptions): CursorScenario {
|
|
294
|
+
const base = beginScenarioBase(options);
|
|
295
|
+
const sdk = new ScriptedCursorSdk(options.sdk);
|
|
296
|
+
bindScriptedSdk(sdk);
|
|
297
|
+
return { ...base, clock: options.clock, sdk };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Bind the record for a live scenario; resets the harness caches first. No
|
|
302
|
+
* SDK double is built or bound — the scenario file must NOT mock `@cursor/sdk`
|
|
303
|
+
* — and no clock is installed. The key lands on the `Config` exactly where
|
|
304
|
+
* the OSS runner's direct mode reads it (`turn-setup.ts`, `config.cursorApiKey`).
|
|
305
|
+
*/
|
|
306
|
+
export function beginLiveCursorScenario(options: LiveCursorScenarioOptions): LiveCursorScenario {
|
|
307
|
+
const base = beginScenarioBase(options);
|
|
308
|
+
return { ...base, config: { ...base.config, cursorApiKey: options.apiKey } };
|
|
309
|
+
}
|
|
310
|
+
|
|
260
311
|
export interface CursorTurnOptions {
|
|
261
312
|
/** Empty for a first invocation; the agent id for a HITL reinvocation. */
|
|
262
313
|
readonly threadId?: string;
|
|
@@ -266,13 +317,15 @@ export interface CursorTurnOptions {
|
|
|
266
317
|
}
|
|
267
318
|
|
|
268
319
|
/**
|
|
269
|
-
* Run ONE `ExecuteCursor` invocation for the scenario: the
|
|
270
|
-
* adapter under the real turn runtime, as the composition roots
|
|
271
|
-
* Built per invocation (the registry constructs its client, which
|
|
272
|
-
* bound at `
|
|
320
|
+
* Run ONE `ExecuteCursor` invocation for the scenario — either posture: the
|
|
321
|
+
* real Cursor adapter under the real turn runtime, as the composition roots
|
|
322
|
+
* wire them. Built per invocation (the registry constructs its client, which
|
|
323
|
+
* is the one bound at `begin*CursorScenario`; the adapter boots on the
|
|
324
|
+
* scenario's config). Reads only the record and the config, which both
|
|
325
|
+
* postures have.
|
|
273
326
|
*/
|
|
274
327
|
export async function runCursorTurn(
|
|
275
|
-
scenario:
|
|
328
|
+
scenario: CursorScenarioBase,
|
|
276
329
|
options: CursorTurnOptions = {},
|
|
277
330
|
): Promise<ActivityInvocation> {
|
|
278
331
|
// Imported lazily so the scenario file's `vi.mock` declarations are in
|
|
@@ -15,7 +15,12 @@
|
|
|
15
15
|
* So a turn is a SCRIPT of ordered steps, one of four kinds:
|
|
16
16
|
*
|
|
17
17
|
* - `event(SDKMessage)` — yielded from `stream()`
|
|
18
|
-
* - `delta(update)` — fired through `onDelta
|
|
18
|
+
* - `delta(update)` — fired through `onDelta`: any `InteractionUpdate`
|
|
19
|
+
* (the `turn-ended` usage the loop prices; the
|
|
20
|
+
* tool-call timings, shell output and completion
|
|
21
|
+
* status the transcript folds — #1097 widened
|
|
22
|
+
* the step from `turn-ended` alone so the delta
|
|
23
|
+
* channel has an end-to-end net)
|
|
19
24
|
* - `effect(fn)` — the side effect the SDK would have performed
|
|
20
25
|
* (run the real hook, write a workspace file,
|
|
21
26
|
* cancel the activity from the outside)
|
|
@@ -24,16 +29,12 @@
|
|
|
24
29
|
* The same shape as the native harness's `__test-utils__/scripted-model.ts`
|
|
25
30
|
* (`ScriptStep`, driven in order), applied to the SDK's event surface.
|
|
26
31
|
*
|
|
27
|
-
* Typing: `SDKMessage`, `Run`, `RunResult
|
|
28
|
-
* types (`@cursor/sdk` 1.0.
|
|
29
|
-
* `
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* code too (`turn-stream.ts`, `delta-enricher.ts` read it untyped). The one
|
|
34
|
-
* delta this double emits, the `turn-ended` usage, is therefore typed HERE
|
|
35
|
-
* ({@link TurnEndedUsageDelta}) against what `turn-stream.ts` reads from it,
|
|
36
|
-
* and that gap is recorded in the entry's findings rather than papered over.
|
|
32
|
+
* Typing: `SDKMessage`, `Run`, `RunResult`, `SDKAgent` and the delta channel's
|
|
33
|
+
* `InteractionUpdate` are the SDK's own types (`@cursor/sdk` 1.0.31, concrete
|
|
34
|
+
* in `messages.d.ts` / `run.d.ts` / `agent.d.ts` / the vendored `delta-types`),
|
|
35
|
+
* so a script that drifts from the real event shape fails `tsc`. (At 1.0.13
|
|
36
|
+
* the delta types resolved to `any` and the one delta this double emitted was
|
|
37
|
+
* typed locally; stigmer/stigmer#1053 closed that gap.)
|
|
37
38
|
*
|
|
38
39
|
* Cancellation: `run.cancel()` is how the harness stops a turn (first denial,
|
|
39
40
|
* cost cap, stall). The double honours it the way the SDK does — the stream
|
|
@@ -50,6 +51,9 @@
|
|
|
50
51
|
*/
|
|
51
52
|
|
|
52
53
|
import type {
|
|
54
|
+
AgentUsage,
|
|
55
|
+
GetUsageOptions,
|
|
56
|
+
InteractionUpdate,
|
|
53
57
|
ModelSelection,
|
|
54
58
|
Run,
|
|
55
59
|
RunOperation,
|
|
@@ -59,6 +63,7 @@ import type {
|
|
|
59
63
|
SDKMessage,
|
|
60
64
|
SDKUserMessage,
|
|
61
65
|
SendOptions,
|
|
66
|
+
TurnEndedUpdate,
|
|
62
67
|
} from "@cursor/sdk";
|
|
63
68
|
import type { ConversationTurn } from "@cursor/sdk";
|
|
64
69
|
|
|
@@ -66,21 +71,6 @@ import type { ConversationTurn } from "@cursor/sdk";
|
|
|
66
71
|
// Script steps
|
|
67
72
|
// ---------------------------------------------------------------------------
|
|
68
73
|
|
|
69
|
-
/**
|
|
70
|
-
* The `turn-ended` delta as `turn-stream.ts` reads it (`update.type ===
|
|
71
|
-
* "turn-ended" && update.usage` -> `usageAccumulator.addTurn(update.usage)`).
|
|
72
|
-
* See the module header for why this is typed locally.
|
|
73
|
-
*/
|
|
74
|
-
export interface TurnEndedUsageDelta {
|
|
75
|
-
readonly type: "turn-ended";
|
|
76
|
-
readonly usage: {
|
|
77
|
-
readonly inputTokens?: number;
|
|
78
|
-
readonly outputTokens?: number;
|
|
79
|
-
readonly cacheWriteTokens?: number;
|
|
80
|
-
readonly cacheReadTokens?: number;
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
74
|
/** What an `effect` step can reach: the run it is part of. */
|
|
85
75
|
export interface EffectContext {
|
|
86
76
|
readonly run: ScriptedRun;
|
|
@@ -89,7 +79,7 @@ export interface EffectContext {
|
|
|
89
79
|
|
|
90
80
|
export type ScriptStep =
|
|
91
81
|
| { readonly kind: "event"; readonly event: SDKMessage }
|
|
92
|
-
| { readonly kind: "delta"; readonly update:
|
|
82
|
+
| { readonly kind: "delta"; readonly update: InteractionUpdate }
|
|
93
83
|
| { readonly kind: "effect"; readonly label: string; readonly run: (ctx: EffectContext) => void | Promise<void> }
|
|
94
84
|
| { readonly kind: "result"; readonly result: Omit<RunResult, "id"> };
|
|
95
85
|
|
|
@@ -101,7 +91,12 @@ export const step = {
|
|
|
101
91
|
event(event: SDKMessage): ScriptStep {
|
|
102
92
|
return { kind: "event", event };
|
|
103
93
|
},
|
|
104
|
-
|
|
94
|
+
/** Any delta the SDK fires through `onDelta` between stream events: tool-call timings, shell output, a completion's status. */
|
|
95
|
+
delta(update: InteractionUpdate): ScriptStep {
|
|
96
|
+
return { kind: "delta", update };
|
|
97
|
+
},
|
|
98
|
+
/** The `turn-ended` delta `turn-stream.ts` prices; the SDK's shape, all four counts stated. */
|
|
99
|
+
turnEnded(usage: NonNullable<TurnEndedUpdate["usage"]>): ScriptStep {
|
|
105
100
|
return { kind: "delta", update: { type: "turn-ended", usage } };
|
|
106
101
|
},
|
|
107
102
|
effect(label: string, run: (ctx: EffectContext) => void | Promise<void>): ScriptStep {
|
|
@@ -145,6 +140,10 @@ export function sdkEvents(agentId: string, runId: string) {
|
|
|
145
140
|
status(status: "CREATING" | "RUNNING" | "FINISHED" | "ERROR" | "CANCELLED" | "EXPIRED", message?: string): SDKMessage {
|
|
146
141
|
return { type: "status", ...base, status, message };
|
|
147
142
|
},
|
|
143
|
+
/** The SDK's `task` event: a status line about the run in the agent's own voice, which the transcript shows as a SYSTEM message. */
|
|
144
|
+
task(text: string, status?: string): SDKMessage {
|
|
145
|
+
return { type: "task", ...base, text, status };
|
|
146
|
+
},
|
|
148
147
|
};
|
|
149
148
|
}
|
|
150
149
|
|
|
@@ -224,7 +223,7 @@ export class ScriptedRun implements Run {
|
|
|
224
223
|
yield s.event;
|
|
225
224
|
break;
|
|
226
225
|
case "delta":
|
|
227
|
-
await this.onDelta?.({ update: s.update
|
|
226
|
+
await this.onDelta?.({ update: s.update });
|
|
228
227
|
break;
|
|
229
228
|
case "effect":
|
|
230
229
|
await s.run({ run: this, agent: this.agent });
|
|
@@ -365,4 +364,11 @@ export class ScriptedCursorAgent implements SDKAgent {
|
|
|
365
364
|
async downloadArtifact(_path: string): Promise<Buffer> {
|
|
366
365
|
throw new Error("ScriptedCursorAgent: artifacts are not part of the scripted surface");
|
|
367
366
|
}
|
|
367
|
+
|
|
368
|
+
async getUsage(_options?: GetUsageOptions): Promise<AgentUsage> {
|
|
369
|
+
// The harness prices the `turn-ended` delta itself (`usage-pricing.ts`) and
|
|
370
|
+
// never asks the SDK for billed usage; a call here is a test bug, like a
|
|
371
|
+
// `send()` with no script.
|
|
372
|
+
throw new Error("ScriptedCursorAgent: getUsage() is not part of the scripted surface");
|
|
373
|
+
}
|
|
368
374
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The `@cursor/sdk` module a hermetic `ExecuteCursor` run imports — every
|
|
3
|
-
* runtime surface the activity path touches, backed by scripted agents
|
|
3
|
+
* runtime surface the activity path touches, backed by scripted agents — and
|
|
4
|
+
* the `@cursor/sdk/sqlite` module beside it, backed by a store that holds
|
|
5
|
+
* nothing.
|
|
4
6
|
*
|
|
5
|
-
* The activity reaches the SDK at
|
|
7
|
+
* The activity reaches the SDK at four runtime sites and nowhere else:
|
|
6
8
|
*
|
|
7
|
-
* - `session-lifecycle.ts`: `Agent.create(options)`, `Agent.resume(id, options)
|
|
8
|
-
*
|
|
9
|
+
* - `session-lifecycle.ts`: `Agent.create(options)`, `Agent.resume(id, options)`
|
|
10
|
+
* — the agent handle.
|
|
11
|
+
* - `session-store.ts`: `SqliteLocalAgentStore.open({ workspaceRef, stateRoot })`
|
|
12
|
+
* from `@cursor/sdk/sqlite` — the session's store the handle is created and
|
|
13
|
+
* resumed over (`local.store`).
|
|
9
14
|
* - `service-tier.ts`: `Cursor.models.list({ apiKey })` — the catalog the
|
|
10
15
|
* variant params (`fast`, `thinking`) are pinned from.
|
|
11
16
|
* - `index.ts` outer catch: `import("@cursor/sdk")` for `CursorSdkError`, the
|
|
@@ -13,35 +18,42 @@
|
|
|
13
18
|
*
|
|
14
19
|
* Neither the SDK nor the client is injectable into the activity (the real
|
|
15
20
|
* seam arrives with the harness contract; parent Q1/Q2), so — exactly as the
|
|
16
|
-
* native activity tests already do for their boundary modules — the
|
|
17
|
-
* substituted with `vi.mock`. Three existing tests each mock ONE of these
|
|
21
|
+
* native activity tests already do for their boundary modules — the modules
|
|
22
|
+
* are substituted with `vi.mock`. Three existing tests each mock ONE of these
|
|
18
23
|
* surfaces (`session-lifecycle.test.ts`, `service-tier.test.ts`,
|
|
19
|
-
* `sdk-warmup.test.ts`); a whole-activity run needs all
|
|
20
|
-
* what this module is.
|
|
24
|
+
* `sdk-warmup.test.ts`); a whole-activity run needs all of them at once, which
|
|
25
|
+
* is what this module is.
|
|
21
26
|
*
|
|
22
|
-
* `vi.mock` is hoisted and must appear in the test file
|
|
23
|
-
*
|
|
24
|
-
*
|
|
27
|
+
* `vi.mock` is hoisted and must appear in the test file, once per module id
|
|
28
|
+
* (a subpath is its own module id, so `@cursor/sdk/sqlite` needs its own
|
|
29
|
+
* `vi.mock`); the factories `await import()` this module and return
|
|
30
|
+
* {@link scriptedCursorSdkModule} and {@link scriptedCursorSqliteModule}. The
|
|
31
|
+
* modules' statics read the {@link ScriptedCursorSdk} bound for the current
|
|
25
32
|
* scenario ({@link bindScriptedSdk}), so one test file can run several
|
|
26
|
-
* scenarios with different agents against the same mocked
|
|
33
|
+
* scenarios with different agents against the same mocked modules.
|
|
27
34
|
*
|
|
28
35
|
* Resolution rules a scenario declares, mirroring what the real SDK does:
|
|
29
36
|
* - `Agent.create` hands out the agent declared for the session it is asked
|
|
30
|
-
* for (`
|
|
31
|
-
* the harness contract kit runs several sessions concurrently on
|
|
32
|
-
* adapter, and the order their creates arrive in is real I/O timing),
|
|
33
|
-
* the NEXT unclaimed agent in `agents` (turn 1 of a fresh session; the
|
|
34
|
-
* agent of a poisoned-handle recovery) — unless the scenario declared
|
|
35
|
-
* `createFailure`, which the FIRST create throws instead (the SDK refusing
|
|
37
|
+
* for (`agentForWorkspaceRef`, when the scenario resolves agents per
|
|
38
|
+
* session — the harness contract kit runs several sessions concurrently on
|
|
39
|
+
* one adapter, and the order their creates arrive in is real I/O timing),
|
|
40
|
+
* else the NEXT unclaimed agent in `agents` (turn 1 of a fresh session; the
|
|
41
|
+
* fresh agent of a poisoned-handle recovery) — unless the scenario declared
|
|
42
|
+
* a `createFailure`, which the FIRST create throws instead (the SDK refusing
|
|
36
43
|
* to mint an agent: a 401 on the key, a validation error).
|
|
37
44
|
* - `Agent.resume(id)` hands back the agent with that id if the scenario
|
|
38
45
|
* declared it (in `agents` or `resumableAgents`, or handed out for a
|
|
39
46
|
* session), else throws — `resolveAgent` then falls back to `create`, which
|
|
40
47
|
* is the production shape of a lost handle.
|
|
41
48
|
* - `Cursor.models.list` answers the scenario's catalog.
|
|
49
|
+
* - `SqliteLocalAgentStore.open` hands out a {@link ScriptedLocalAgentStore}
|
|
50
|
+
* carrying the ref and root it was asked for, and records the open; its
|
|
51
|
+
* `dispose()` is recorded too, so a scenario can assert the adapter's
|
|
52
|
+
* session-store lifetime (`releaseSession`, `shutdown`).
|
|
42
53
|
*/
|
|
43
54
|
|
|
44
55
|
import type { AgentOptions, ModelListItem, SDKAgent } from "@cursor/sdk";
|
|
56
|
+
import type { SqliteLocalAgentStore, SqliteLocalAgentStoreOptions } from "@cursor/sdk/sqlite";
|
|
45
57
|
import type { ScriptedCursorAgent } from "./scripted-agent.js";
|
|
46
58
|
|
|
47
59
|
export interface ScriptedSdkOptions {
|
|
@@ -50,12 +62,12 @@ export interface ScriptedSdkOptions {
|
|
|
50
62
|
/**
|
|
51
63
|
* The agent `Agent.create` hands out for the session the create names,
|
|
52
64
|
* consulted before the ordered list. The SDK's create options carry the
|
|
53
|
-
* session as `
|
|
54
|
-
* `
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* every create, so a scenario may mint the session's
|
|
58
|
-
* learns of the session.
|
|
65
|
+
* session as the store's `workspaceRef` (`local.store`, opened by
|
|
66
|
+
* `session-store.ts`: `stigmer-session:<sessionId>`), so the resolver is
|
|
67
|
+
* keyed by that ref — a scenario computes the ref the same way the adapter
|
|
68
|
+
* does (`resolveSessionStoreLocation`). `undefined` falls through to the
|
|
69
|
+
* list. Consulted live on every create, so a scenario may mint the session's
|
|
70
|
+
* agent only when it learns of the session.
|
|
59
71
|
*/
|
|
60
72
|
readonly agentForWorkspaceRef?: (workspaceRef: string) => ScriptedCursorAgent | undefined;
|
|
61
73
|
/**
|
|
@@ -82,21 +94,46 @@ export interface RecordedResolution {
|
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
/**
|
|
85
|
-
* The
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
97
|
+
* The session a create names: the `workspaceRef` of the store it passes as
|
|
98
|
+
* `local.store`. In a hermetic run that store is the one this module's sqlite
|
|
99
|
+
* double opened; anything else (a test that mocks `@cursor/sdk` with its own
|
|
100
|
+
* stub and passes no store) names no session and falls through to the list.
|
|
89
101
|
*/
|
|
90
102
|
function workspaceRefOf(options: AgentOptions): string | undefined {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
const store = options.local?.store;
|
|
104
|
+
return store instanceof ScriptedLocalAgentStore ? store.workspaceRef : undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The `@cursor/sdk/sqlite` store the adapter opens per session, holding
|
|
109
|
+
* nothing: the scripted agents carry their own state, so the store only has
|
|
110
|
+
* to be the thing `Agent.create` / `Agent.resume` are handed and the thing
|
|
111
|
+
* `releaseSession` / `shutdown` dispose. `open` and `dispose` are recorded on
|
|
112
|
+
* the bound {@link ScriptedCursorSdk} for lifetime assertions.
|
|
113
|
+
*/
|
|
114
|
+
export class ScriptedLocalAgentStore {
|
|
115
|
+
disposeCalls = 0;
|
|
116
|
+
|
|
117
|
+
constructor(
|
|
118
|
+
readonly workspaceRef: string,
|
|
119
|
+
readonly stateRoot: string,
|
|
120
|
+
) {}
|
|
121
|
+
|
|
122
|
+
static async open(options: SqliteLocalAgentStoreOptions): Promise<ScriptedLocalAgentStore> {
|
|
123
|
+
const store = new ScriptedLocalAgentStore(options.workspaceRef, options.stateRoot ?? "");
|
|
124
|
+
current().stores.push(store);
|
|
125
|
+
return store;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async dispose(): Promise<void> {
|
|
129
|
+
this.disposeCalls++;
|
|
130
|
+
}
|
|
95
131
|
}
|
|
96
132
|
|
|
97
133
|
export class ScriptedCursorSdk {
|
|
98
134
|
readonly resolutions: RecordedResolution[] = [];
|
|
99
|
-
|
|
135
|
+
/** Every store `SqliteLocalAgentStore.open` handed out, in order. */
|
|
136
|
+
readonly stores: ScriptedLocalAgentStore[] = [];
|
|
100
137
|
private nextCreate = 0;
|
|
101
138
|
private createFailurePending: boolean;
|
|
102
139
|
private readonly byId = new Map<string, ScriptedCursorAgent>();
|
|
@@ -145,10 +182,6 @@ export class ScriptedCursorSdk {
|
|
|
145
182
|
return agent;
|
|
146
183
|
}
|
|
147
184
|
|
|
148
|
-
archive(agentId: string): void {
|
|
149
|
-
this.archived.push(agentId);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
185
|
listModels(): readonly ModelListItem[] {
|
|
153
186
|
return this.options.catalog;
|
|
154
187
|
}
|
|
@@ -242,7 +275,6 @@ export function scriptedCursorSdkModule(): Record<string, unknown> {
|
|
|
242
275
|
create: async (options: AgentOptions): Promise<SDKAgent> => current().create(options),
|
|
243
276
|
resume: async (agentId: string, options?: Partial<AgentOptions>): Promise<SDKAgent> =>
|
|
244
277
|
current().resume(agentId, options),
|
|
245
|
-
archive: async (agentId: string): Promise<void> => current().archive(agentId),
|
|
246
278
|
},
|
|
247
279
|
Cursor: {
|
|
248
280
|
models: {
|
|
@@ -252,3 +284,27 @@ export function scriptedCursorSdkModule(): Record<string, unknown> {
|
|
|
252
284
|
CursorSdkError: ScriptedCursorSdkError,
|
|
253
285
|
};
|
|
254
286
|
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The factory a test passes to `vi.mock("@cursor/sdk/sqlite", ...)`, beside
|
|
290
|
+
* the one above:
|
|
291
|
+
*
|
|
292
|
+
* ```ts
|
|
293
|
+
* vi.mock("@cursor/sdk/sqlite", async () =>
|
|
294
|
+
* (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSqliteModule(),
|
|
295
|
+
* );
|
|
296
|
+
* ```
|
|
297
|
+
*
|
|
298
|
+
* The one export the runner reads from that entry (`session-store.ts`). The
|
|
299
|
+
* class is exported under the SDK's name so `session-store.ts`'s dynamic
|
|
300
|
+
* import destructures it unchanged; its type is the SDK's, which is why
|
|
301
|
+
* {@link ScriptedLocalAgentStore} carries `workspaceRef`, `stateRoot` and
|
|
302
|
+
* `dispose()` — the members the runner touches — and nothing else.
|
|
303
|
+
*/
|
|
304
|
+
export function scriptedCursorSqliteModule(): Record<string, unknown> {
|
|
305
|
+
return {
|
|
306
|
+
SqliteLocalAgentStore: ScriptedLocalAgentStore satisfies {
|
|
307
|
+
open(options: SqliteLocalAgentStoreOptions): Promise<Pick<SqliteLocalAgentStore, "workspaceRef" | "stateRoot" | "dispose">>;
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @regression file-hitl-phase0 — pins
|
|
2
|
+
* @regression file-hitl-phase0 — pins content-exact approval identity: approving
|
|
3
|
+
* one edit never lets a DIFFERENT edit to the same path ride the grant.
|
|
3
4
|
*
|
|
4
5
|
* Unit tests for the Cursor-harness HITL approval gate logic.
|
|
5
6
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @regression file-hitl-phase0 — pins
|
|
2
|
+
* @regression file-hitl-phase0 — pins content-exact approval identity: approving
|
|
3
|
+
* one edit never lets a DIFFERENT edit to the same path ride the grant.
|
|
3
4
|
*
|
|
4
5
|
* Resume-grant identity round-trip — the H1 lock.
|
|
5
6
|
*
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
* - the resume grant via {@link buildApprovalGrants} -> parseArgs(argsPreview)
|
|
22
23
|
* (the JSON-string preview only).
|
|
23
24
|
* They agree today only because both derive from the same stream `event.args`.
|
|
24
|
-
* This suite drives the REAL stream path (
|
|
25
|
+
* This suite drives the REAL stream path (the translator into the builder) so any
|
|
25
26
|
* future change that lets the dual path diverge fails here, loudly, per category.
|
|
26
27
|
*
|
|
27
28
|
* Deterministic; no Cursor API key, no bash. The hook-side half of the equality
|
|
@@ -42,11 +43,9 @@ import {
|
|
|
42
43
|
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
43
44
|
import type { SDKMessage } from "@cursor/sdk";
|
|
44
45
|
|
|
45
|
-
import {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
toolCallIdentityToken,
|
|
49
|
-
} from "../message-translator.js";
|
|
46
|
+
import { reconcileDeniedToolCalls } from "../boundary-rows.js";
|
|
47
|
+
import { builderOver, foldCursorEvents } from "../__test-utils__/fold.js";
|
|
48
|
+
import { toolCallIdentityToken } from "../approval-state.js";
|
|
50
49
|
import {
|
|
51
50
|
buildApprovalGrants,
|
|
52
51
|
buildApprovalState,
|
|
@@ -96,7 +95,7 @@ function mcpEvent(
|
|
|
96
95
|
* and return the two identities that must be equal: the token the hook recorded
|
|
97
96
|
* when it denied the gated call, and the grant token a resume mints after the
|
|
98
97
|
* user approves it. Mirrors the activity's real sequence:
|
|
99
|
-
*
|
|
98
|
+
* translator + builder (stream) -> deny overlay (reconcileDeniedToolCalls) ->
|
|
100
99
|
* persist APPROVE -> reconstructAdjudicatedApprovals -> buildApprovalGrants.
|
|
101
100
|
*/
|
|
102
101
|
async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Promise<{
|
|
@@ -105,7 +104,7 @@ async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Pro
|
|
|
105
104
|
resumeStateToken: string | undefined;
|
|
106
105
|
grant: ApprovalGrant;
|
|
107
106
|
}> {
|
|
108
|
-
const tc =
|
|
107
|
+
const tc = foldCursorEvents([event]).rows()[0];
|
|
109
108
|
|
|
110
109
|
// The gated turn: the hook denies the call, recording its identity token. The
|
|
111
110
|
// runner's overlay (reconcileDeniedToolCalls) flips the same call to
|
|
@@ -120,7 +119,8 @@ async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Pro
|
|
|
120
119
|
toolCalls: [tc],
|
|
121
120
|
});
|
|
122
121
|
const ledger: DeniedLedgerEntry[] = [{ toolName: tc.name, token: denialToken }];
|
|
123
|
-
const
|
|
122
|
+
const messages: AgentMessage[] = [msg];
|
|
123
|
+
const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), ledger);
|
|
124
124
|
expect(denied, "the overlay must match the denial token and surface the gate").toHaveLength(1);
|
|
125
125
|
|
|
126
126
|
// The user approves; the backend persists the decision on the tool call.
|
|
@@ -130,7 +130,6 @@ async function roundTrip(event: Extract<SDKMessage, { type: "tool_call" }>): Pro
|
|
|
130
130
|
// transcript (pending_approvals is already cleared by this point) and mint the
|
|
131
131
|
// grants the next turn's hook reads. The content digest threads through so the
|
|
132
132
|
// grant reproduces the content-exact denial identity.
|
|
133
|
-
const messages: AgentMessage[] = [msg];
|
|
134
133
|
const { pendingApprovals, decisions, contentDigests } = reconstructAdjudicatedApprovals(messages);
|
|
135
134
|
const grants = buildApprovalGrants(pendingApprovals, decisions, contentDigests);
|
|
136
135
|
expect(grants, "an approved tool must yield exactly one grant").toHaveLength(1);
|
|
@@ -234,12 +233,8 @@ describe("Cursor resume-grant identity round-trip (H1 lock)", () => {
|
|
|
234
233
|
// The exact bug this change fixes: approving the rename must NOT authorize
|
|
235
234
|
// the TODO edit. They share a path (same coarse token) but differ in content,
|
|
236
235
|
// so the content-exact identity distinguishes them.
|
|
237
|
-
const rename =
|
|
238
|
-
|
|
239
|
-
);
|
|
240
|
-
const todo = buildToolCallProto(
|
|
241
|
-
builtInEvent("c2", "edit", { path: "/work/notes.md", old_string: "", new_string: "## TODO\n" }),
|
|
242
|
-
);
|
|
236
|
+
const rename = foldCursorEvents([builtInEvent("c1", "edit", { path: "/work/notes.md", old_string: "Planton Cloud", new_string: "Planton" })]).rows()[0];
|
|
237
|
+
const todo = foldCursorEvents([builtInEvent("c2", "edit", { path: "/work/notes.md", old_string: "", new_string: "## TODO\n" })]).rows()[0];
|
|
243
238
|
const renameToken = toolCallIdentityToken(rename);
|
|
244
239
|
const todoToken = toolCallIdentityToken(todo);
|
|
245
240
|
|
|
@@ -252,9 +247,7 @@ describe("Cursor resume-grant identity round-trip (H1 lock)", () => {
|
|
|
252
247
|
);
|
|
253
248
|
// Re-issuing the SAME rename content reproduces its identity (identical
|
|
254
249
|
// re-attempt is allowed; a drifted one re-gates).
|
|
255
|
-
const renameAgain =
|
|
256
|
-
builtInEvent("c3", "edit", { path: "/work/notes.md", old_string: "Planton Cloud", new_string: "Planton" }),
|
|
257
|
-
);
|
|
250
|
+
const renameAgain = foldCursorEvents([builtInEvent("c3", "edit", { path: "/work/notes.md", old_string: "Planton Cloud", new_string: "Planton" })]).rows()[0];
|
|
258
251
|
expect(toolCallIdentityToken(renameAgain)).toBe(renameToken);
|
|
259
252
|
});
|
|
260
253
|
|
|
@@ -263,7 +256,7 @@ describe("Cursor resume-grant identity round-trip (H1 lock)", () => {
|
|
|
263
256
|
event: Extract<SDKMessage, { type: "tool_call" }>,
|
|
264
257
|
action: ApprovalAction,
|
|
265
258
|
): AgentMessage {
|
|
266
|
-
const tc =
|
|
259
|
+
const tc = foldCursorEvents([event]).rows()[0];
|
|
267
260
|
tc.status = ToolCallStatus.TOOL_CALL_WAITING_APPROVAL;
|
|
268
261
|
tc.requiresApproval = true;
|
|
269
262
|
tc.approvalAction = action;
|
|
@@ -544,7 +544,7 @@ describe("attachments on a resumed turn (T04 — the mid-session WhatsApp case)"
|
|
|
544
544
|
],
|
|
545
545
|
}),
|
|
546
546
|
);
|
|
547
|
-
// The size precedes the disclosure (the shared line,
|
|
547
|
+
// The size precedes the disclosure (the shared line, since #1096).
|
|
548
548
|
expect(prompt).toContain(
|
|
549
549
|
"- `.stigmer/inputs/report-2.pdf` (1024 bytes) (renamed from duplicate 'report.pdf')",
|
|
550
550
|
);
|
|
@@ -778,8 +778,8 @@ describe("buildReinvocationPrompt", () => {
|
|
|
778
778
|
expect(prompt).toContain("Continue the rest of the task");
|
|
779
779
|
});
|
|
780
780
|
|
|
781
|
-
it("names a REJECTED action as a refusal, apart from the skipped ones, and still continues the task (stigmer#197
|
|
782
|
-
// A REJECT denies the tool and the run continues; before
|
|
781
|
+
it("names a REJECTED action as a refusal, apart from the skipped ones, and still continues the task (stigmer#197)", () => {
|
|
782
|
+
// A REJECT denies the tool and the run continues; before #1096 the
|
|
783
783
|
// runtime failed the reinvocation before this prompt was ever built, so
|
|
784
784
|
// the prompt had no REJECT arm.
|
|
785
785
|
const decisions = new Map<string, ApprovalAction>([
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @regression file-hitl-phase0 — pins
|
|
2
|
+
* @regression file-hitl-phase0 — pins content-exact approval identity: approving
|
|
3
|
+
* one edit never lets a DIFFERENT edit to the same path ride the grant.
|
|
3
4
|
*
|
|
4
5
|
* Slice D — the Cursor grant token / fingerprint as the substrate-coarsened
|
|
5
6
|
* projection of the shared canonical action.
|