@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,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins that `src/harness/README.md` resolves: every path it names exists and
|
|
3
|
+
* every symbol it names occurs in a file the same passage cites.
|
|
4
|
+
*
|
|
5
|
+
* Why it matters: the README is an index for someone adding a harness, not a
|
|
6
|
+
* restatement of the headers. An index earns its keep only while its entries
|
|
7
|
+
* point somewhere. A module renamed, a test moved, an export renamed — each
|
|
8
|
+
* turns a line of the guide into a false trail, and nothing in CI reads a
|
|
9
|
+
* `src/**` README (the docs link checker walks `docs/` only). This fence is
|
|
10
|
+
* the guide's one mechanical check; it is what lets the README carry file
|
|
11
|
+
* paths and export names at all.
|
|
12
|
+
*
|
|
13
|
+
* Two rules, both about resolution, neither about prose:
|
|
14
|
+
*
|
|
15
|
+
* 1. A backticked token that reads as a path (ends in a `/`, or is a file
|
|
16
|
+
* name with an extension, with or without a directory part) exists,
|
|
17
|
+
* resolved against `src/` (the base the runner's own headers cite each
|
|
18
|
+
* other from) or against the repository root (the base for everything
|
|
19
|
+
* outside the runner).
|
|
20
|
+
* 2. A backticked identifier occurs in the text of at least one FILE the
|
|
21
|
+
* same passage resolved under rule 1. A passage that names a symbol and
|
|
22
|
+
* cites no file is an offence: the index rule ("say where it lives") made
|
|
23
|
+
* mechanical. Hyphenated literals (`deep-agent`, `deny-and-retry`) count
|
|
24
|
+
* as identifiers so the wire words are checked too.
|
|
25
|
+
*
|
|
26
|
+
* A "passage" is a markdown block — one paragraph, one list item with its
|
|
27
|
+
* wrapped continuation lines, or one table row — because the repository's
|
|
28
|
+
* prettier wraps prose at 80 columns, so a line is not a unit of meaning.
|
|
29
|
+
* Fenced code blocks are blanked before the scan (they hold shell commands
|
|
30
|
+
* and search patterns, not references). Two token classes are exempt with
|
|
31
|
+
* a reason: a template (`activities/<harness>/adapter.ts`, contains `<`)
|
|
32
|
+
* names a shape, not a file; a package specifier (`@cursor/sdk`, starts
|
|
33
|
+
* with `@`) is resolved by npm, not by this tree.
|
|
34
|
+
*
|
|
35
|
+
* Hand-rolled over three regular expressions rather than a markdown parser:
|
|
36
|
+
* the README has three shapes and the runner has no markdown dependency.
|
|
37
|
+
* The fence shape is `import-direction.test.ts`'s: a sweep that reports what
|
|
38
|
+
* it visited beside what it found, a liveness guard that fails when the
|
|
39
|
+
* sweep saw nothing, and every offence named with its block's first line.
|
|
40
|
+
* What it never asserts: wording, section order, or that a header agrees
|
|
41
|
+
* with the README — the header wins that by rule, not by test.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import { describe, it, expect } from "vitest";
|
|
45
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
46
|
+
import { dirname, join, resolve } from "node:path";
|
|
47
|
+
import { fileURLToPath } from "node:url";
|
|
48
|
+
|
|
49
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
50
|
+
const README_PATH = join(HERE, "..", "README.md");
|
|
51
|
+
/** `src/`: the base the runner's headers cite each other from. */
|
|
52
|
+
const SRC_ROOT = resolve(HERE, "../..");
|
|
53
|
+
/** The repository root: `src/` → `runner/` → `services/` → `backend/` → root. */
|
|
54
|
+
const REPO_ROOT = resolve(SRC_ROOT, "../../../..");
|
|
55
|
+
|
|
56
|
+
// ── The scanner ──────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
/** One passage of the README: a paragraph, a list item with its continuation, or a table row. */
|
|
59
|
+
interface Block {
|
|
60
|
+
/** 1-based line of the block's first line in the README, for the offence message. */
|
|
61
|
+
readonly line: number;
|
|
62
|
+
readonly text: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Blank every fenced code block, keeping the line count so block line
|
|
67
|
+
* numbers still point into the real file.
|
|
68
|
+
*/
|
|
69
|
+
function stripFencedCode(markdown: string): string {
|
|
70
|
+
let inFence = false;
|
|
71
|
+
return markdown
|
|
72
|
+
.split("\n")
|
|
73
|
+
.map((line) => {
|
|
74
|
+
if (line.trimStart().startsWith("```")) {
|
|
75
|
+
inFence = !inFence;
|
|
76
|
+
return "";
|
|
77
|
+
}
|
|
78
|
+
return inFence ? "" : line;
|
|
79
|
+
})
|
|
80
|
+
.join("\n");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const BLOCK_START = /^(#{1,6}\s|[-*]\s|\d+\.\s|\|)/;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Split markdown into blocks. A blank line ends a block; a heading, a list
|
|
87
|
+
* marker or a table row starts one; any other non-blank line continues the
|
|
88
|
+
* current block (prettier indents a list item's wrapped lines, and a
|
|
89
|
+
* paragraph's lines are simply consecutive).
|
|
90
|
+
*/
|
|
91
|
+
function splitBlocks(markdown: string): Block[] {
|
|
92
|
+
const blocks: Block[] = [];
|
|
93
|
+
let current: { line: number; parts: string[] } | undefined;
|
|
94
|
+
const flush = (): void => {
|
|
95
|
+
if (current !== undefined) {
|
|
96
|
+
blocks.push({ line: current.line, text: current.parts.join(" ") });
|
|
97
|
+
current = undefined;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
markdown.split("\n").forEach((raw, index) => {
|
|
101
|
+
const line = raw.trim();
|
|
102
|
+
if (line === "") {
|
|
103
|
+
flush();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (BLOCK_START.test(line) || current === undefined) {
|
|
107
|
+
flush();
|
|
108
|
+
current = { line: index + 1, parts: [line] };
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
current.parts.push(line);
|
|
112
|
+
});
|
|
113
|
+
flush();
|
|
114
|
+
return blocks;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Every backticked token in a block, in order, backticks removed. */
|
|
118
|
+
function backtickedTokens(text: string): string[] {
|
|
119
|
+
return [...text.matchAll(/`([^`\n]+)`/g)].map((m) => m[1] ?? "");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type TokenClass = "template" | "package" | "path" | "identifier" | "other";
|
|
123
|
+
|
|
124
|
+
const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$-]{3,}$/;
|
|
125
|
+
/** A directory (`activities/execute-cursor/`) or a file with an extension, with or without a directory part (`harness-adapters.ts` sits at the `src/` root). */
|
|
126
|
+
const DIRECTORY = /\/$/;
|
|
127
|
+
const FILE_WITH_EXTENSION = /^[^.\s][^\s]*\.[A-Za-z0-9]{1,5}$/;
|
|
128
|
+
|
|
129
|
+
/** Which rule a token falls under; `other` is prose in backticks and is ignored. */
|
|
130
|
+
function classify(token: string): TokenClass {
|
|
131
|
+
if (token.includes("<")) return "template";
|
|
132
|
+
if (token.startsWith("@")) return "package";
|
|
133
|
+
if (DIRECTORY.test(token) || FILE_WITH_EXTENSION.test(token)) return "path";
|
|
134
|
+
if (IDENTIFIER.test(token)) return "identifier";
|
|
135
|
+
return "other";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** The first base under which `token` exists, or `undefined`. */
|
|
139
|
+
function resolvePath(token: string, bases: readonly string[]): string | undefined {
|
|
140
|
+
for (const base of bases) {
|
|
141
|
+
const candidate = join(base, token);
|
|
142
|
+
if (existsSync(candidate)) return candidate;
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface Offence {
|
|
148
|
+
readonly line: number;
|
|
149
|
+
readonly token: string;
|
|
150
|
+
readonly rule: "path" | "symbol" | "no-file-cited";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface Sweep {
|
|
154
|
+
/** What the sweep saw; the liveness guards read these. */
|
|
155
|
+
readonly blocks: number;
|
|
156
|
+
readonly paths: number;
|
|
157
|
+
readonly identifiers: number;
|
|
158
|
+
readonly offences: Offence[];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Run both rules over `markdown`, resolving paths against `bases` in order. */
|
|
162
|
+
function sweep(markdown: string, bases: readonly string[]): Sweep {
|
|
163
|
+
const offences: Offence[] = [];
|
|
164
|
+
let paths = 0;
|
|
165
|
+
let identifiers = 0;
|
|
166
|
+
const blocks = splitBlocks(stripFencedCode(markdown));
|
|
167
|
+
for (const block of blocks) {
|
|
168
|
+
const files: string[] = [];
|
|
169
|
+
const symbols: string[] = [];
|
|
170
|
+
for (const token of backtickedTokens(block.text)) {
|
|
171
|
+
const kind = classify(token);
|
|
172
|
+
switch (kind) {
|
|
173
|
+
case "path": {
|
|
174
|
+
paths += 1;
|
|
175
|
+
const resolved = resolvePath(token, bases);
|
|
176
|
+
if (resolved === undefined) {
|
|
177
|
+
offences.push({ line: block.line, token, rule: "path" });
|
|
178
|
+
} else if (statSync(resolved).isFile()) {
|
|
179
|
+
files.push(resolved);
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case "identifier":
|
|
184
|
+
identifiers += 1;
|
|
185
|
+
symbols.push(token);
|
|
186
|
+
break;
|
|
187
|
+
case "template":
|
|
188
|
+
case "package":
|
|
189
|
+
case "other":
|
|
190
|
+
break;
|
|
191
|
+
default: {
|
|
192
|
+
const exhaustive: never = kind;
|
|
193
|
+
throw new Error(`unhandled token class ${String(exhaustive)}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (symbols.length === 0) continue;
|
|
198
|
+
if (files.length === 0) {
|
|
199
|
+
for (const token of symbols) offences.push({ line: block.line, token, rule: "no-file-cited" });
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const corpus = files.map((f) => readFileSync(f, "utf-8"));
|
|
203
|
+
for (const token of symbols) {
|
|
204
|
+
if (!corpus.some((text) => text.includes(token))) {
|
|
205
|
+
offences.push({ line: block.line, token, rule: "symbol" });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { blocks: blocks.length, paths, identifiers, offences };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function describeOffences(offences: readonly Offence[]): string {
|
|
213
|
+
const words: Record<Offence["rule"], string> = {
|
|
214
|
+
path: "does not exist under src/ or the repository root",
|
|
215
|
+
symbol: "does not occur in any file this passage cites",
|
|
216
|
+
"no-file-cited": "is named in a passage that cites no file",
|
|
217
|
+
};
|
|
218
|
+
return offences.map((o) => ` README.md:${o.line} \`${o.token}\` ${words[o.rule]}`).join("\n");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ── The checker itself ───────────────────────────────────────────────────────
|
|
222
|
+
|
|
223
|
+
describe("the scanner (the checker itself)", () => {
|
|
224
|
+
it("blanks fenced code and keeps the line count", () => {
|
|
225
|
+
const text = ["before", "```bash", "rg -l 'x/y.ts'", "```", "after"].join("\n");
|
|
226
|
+
const stripped = stripFencedCode(text);
|
|
227
|
+
expect(stripped.split("\n")).toHaveLength(5);
|
|
228
|
+
expect(stripped).not.toContain("x/y.ts");
|
|
229
|
+
expect(stripped).toContain("after");
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("splits paragraphs, wrapped list items, table rows and headings into blocks with their first line", () => {
|
|
233
|
+
const text = [
|
|
234
|
+
"# Title",
|
|
235
|
+
"",
|
|
236
|
+
"A paragraph that",
|
|
237
|
+
"wraps onto two lines.",
|
|
238
|
+
"",
|
|
239
|
+
"- `a/b.ts` — a bullet whose",
|
|
240
|
+
" continuation is indented.",
|
|
241
|
+
"- a second bullet",
|
|
242
|
+
"",
|
|
243
|
+
"| `c/d.ts` | row one |",
|
|
244
|
+
"| `e/f.ts` | row two |",
|
|
245
|
+
].join("\n");
|
|
246
|
+
expect(splitBlocks(text)).toEqual([
|
|
247
|
+
{ line: 1, text: "# Title" },
|
|
248
|
+
{ line: 3, text: "A paragraph that wraps onto two lines." },
|
|
249
|
+
{ line: 6, text: "- `a/b.ts` — a bullet whose continuation is indented." },
|
|
250
|
+
{ line: 8, text: "- a second bullet" },
|
|
251
|
+
{ line: 10, text: "| `c/d.ts` | row one |" },
|
|
252
|
+
{ line: 11, text: "| `e/f.ts` | row two |" },
|
|
253
|
+
]);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it.each<[string, TokenClass]>([
|
|
257
|
+
["harness/types.ts", "path"],
|
|
258
|
+
["harness-adapters.ts", "path"],
|
|
259
|
+
["activities/execute-cursor/", "path"],
|
|
260
|
+
["apis/", "path"],
|
|
261
|
+
["apis/ai/stigmer/agentic/session/v1/enum.proto", "path"],
|
|
262
|
+
["activities/<harness>/adapter.ts", "template"],
|
|
263
|
+
["@cursor/sdk", "package"],
|
|
264
|
+
["@temporalio/*", "package"],
|
|
265
|
+
["HarnessAdapter", "identifier"],
|
|
266
|
+
["deep-agent", "identifier"],
|
|
267
|
+
["deny-and-retry", "identifier"],
|
|
268
|
+
["boot", "identifier"],
|
|
269
|
+
["src", "other"],
|
|
270
|
+
["make codegen", "other"],
|
|
271
|
+
["--harness", "other"],
|
|
272
|
+
[".ts", "other"],
|
|
273
|
+
["f25d15131", "identifier"],
|
|
274
|
+
])("classifies %s as %s", (token, expected) => {
|
|
275
|
+
expect(classify(token)).toBe(expected);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("resolves a path against the bases in order and reports a miss", () => {
|
|
279
|
+
expect(resolvePath("harness/types.ts", [SRC_ROOT, REPO_ROOT])).toBe(join(SRC_ROOT, "harness/types.ts"));
|
|
280
|
+
expect(resolvePath("apis/", [SRC_ROOT, REPO_ROOT])).toBe(join(REPO_ROOT, "apis/"));
|
|
281
|
+
expect(resolvePath("harness/no-such-module.ts", [SRC_ROOT, REPO_ROOT])).toBeUndefined();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("flags a missing path, a symbol absent from the cited file, and a symbol with no file cited", () => {
|
|
285
|
+
const text = [
|
|
286
|
+
"- `harness/no-such-module.ts` — a moved module.",
|
|
287
|
+
"- `harness/registry.ts` — `NoSuchExport` was renamed.",
|
|
288
|
+
"- `HarnessName` is named here with no file beside it.",
|
|
289
|
+
"- `harness/registry.ts` — `HarnessName` is fine.",
|
|
290
|
+
].join("\n");
|
|
291
|
+
expect(sweep(text, [SRC_ROOT, REPO_ROOT]).offences).toEqual([
|
|
292
|
+
{ line: 1, token: "harness/no-such-module.ts", rule: "path" },
|
|
293
|
+
{ line: 2, token: "NoSuchExport", rule: "symbol" },
|
|
294
|
+
{ line: 3, token: "HarnessName", rule: "no-file-cited" },
|
|
295
|
+
]);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("ignores templates, package specifiers, prose in backticks and anything inside a code fence", () => {
|
|
299
|
+
const text = [
|
|
300
|
+
"- `activities/<harness>/adapter.ts` loads `@cursor/sdk` inside `boot`; see `harness/types.ts`.",
|
|
301
|
+
"",
|
|
302
|
+
"```bash",
|
|
303
|
+
"rg -l 'x/y.ts' `NoSuchExport`",
|
|
304
|
+
"```",
|
|
305
|
+
].join("\n");
|
|
306
|
+
const result = sweep(text, [SRC_ROOT, REPO_ROOT]);
|
|
307
|
+
expect(result.offences).toEqual([]);
|
|
308
|
+
expect(result.paths).toBe(1);
|
|
309
|
+
expect(result.identifiers).toBe(1);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// ── The README ───────────────────────────────────────────────────────────────
|
|
314
|
+
|
|
315
|
+
describe("src/harness/README.md resolves", () => {
|
|
316
|
+
const readme = readFileSync(README_PATH, "utf-8");
|
|
317
|
+
const result = sweep(readme, [SRC_ROOT, REPO_ROOT]);
|
|
318
|
+
|
|
319
|
+
it("is rooted where it claims (the repository root holds apis/ and backend/)", () => {
|
|
320
|
+
expect(existsSync(join(REPO_ROOT, "apis")), `expected ${REPO_ROOT} to contain apis/`).toBe(true);
|
|
321
|
+
expect(existsSync(join(REPO_ROOT, "backend")), `expected ${REPO_ROOT} to contain backend/`).toBe(true);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("saw the guide (the sweep visited blocks, paths and identifiers)", () => {
|
|
325
|
+
expect(result.blocks).toBeGreaterThan(20);
|
|
326
|
+
expect(result.paths).toBeGreaterThan(40);
|
|
327
|
+
expect(result.identifiers).toBeGreaterThan(20);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it("names no path that does not exist", () => {
|
|
331
|
+
const misses = result.offences.filter((o) => o.rule === "path");
|
|
332
|
+
expect(misses, `paths in the README that resolve nowhere:\n${describeOffences(misses)}`).toEqual([]);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("names no symbol outside a file the same passage cites", () => {
|
|
336
|
+
const misses = result.offences.filter((o) => o.rule !== "path");
|
|
337
|
+
expect(misses, `symbols in the README without a home:\n${describeOffences(misses)}`).toEqual([]);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* this file.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
+
import { join } from "node:path";
|
|
31
32
|
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
32
33
|
import { ApprovalAction, ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
33
34
|
|
|
@@ -38,8 +39,9 @@ vi.mock("../../client/stigmer-client.js", async () =>
|
|
|
38
39
|
import { ScriptedClock, createHermeticEnvironment } from "../../__test-utils__/hermetic-activity.js";
|
|
39
40
|
import { stubRegistryFetch } from "../../__test-utils__/model-registry-fixture.js";
|
|
40
41
|
import { scriptedSubject } from "../../__test-utils__/harness-contract/scripted-adapter.js";
|
|
41
|
-
import { initGitWorkspace } from "../../__test-utils__/git-workspace-fixture.js";
|
|
42
|
+
import { initGitWorkspace, localPathEntry } from "../../__test-utils__/git-workspace-fixture.js";
|
|
42
43
|
import { scenario } from "../../__test-utils__/harness-contract/types.js";
|
|
44
|
+
import { WriteBackCoordinator } from "../../shared/workspace/writeback-coordinator.js";
|
|
43
45
|
import {
|
|
44
46
|
COST_CAP_FAKE_PRICE_USD,
|
|
45
47
|
FAILURE_MESSAGES,
|
|
@@ -58,6 +60,7 @@ import {
|
|
|
58
60
|
type RuntimeContractHarness,
|
|
59
61
|
} from "../../__test-utils__/harness-contract/runtime-contract.js";
|
|
60
62
|
import { TERMINAL_COPY } from "../terminal-table.js";
|
|
63
|
+
import type { HarnessAdapter } from "../types.js";
|
|
61
64
|
|
|
62
65
|
const TASK_QUEUE = "runtime-test-queue";
|
|
63
66
|
|
|
@@ -101,7 +104,7 @@ describe("run-turn: the fake adapter through the real runtime", () => {
|
|
|
101
104
|
expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
|
|
102
105
|
});
|
|
103
106
|
|
|
104
|
-
it("the approval round trip: the WAITING write is the fake's first full persist
|
|
107
|
+
it("the approval round trip: the WAITING write is the fake's first full persist", async () => {
|
|
105
108
|
clock.reset();
|
|
106
109
|
const { driver } = await assertApprovalRoundTrip(harness, "fake-approval");
|
|
107
110
|
expect(driver.record.persistedPhases).toEqual([
|
|
@@ -138,11 +141,11 @@ describe("run-turn: the fake adapter through the real runtime", () => {
|
|
|
138
141
|
expect(aiMessages(final)).toEqual([]);
|
|
139
142
|
});
|
|
140
143
|
|
|
141
|
-
it("REJECT continues the run without the tool and the row settles SKIPPED with its reason (stigmer#197
|
|
142
|
-
// Until
|
|
144
|
+
it("REJECT continues the run without the tool and the row settles SKIPPED with its reason (stigmer#197)", async () => {
|
|
145
|
+
// Until #1096 this arm pinned the opposite: the runtime FAILED a
|
|
143
146
|
// reinvocation carrying any REJECT (`rejectedByUserArm`, Cursor's
|
|
144
147
|
// legacy), against the proto's `APPROVAL_ACTION_REJECT` doc, the
|
|
145
|
-
// conformance suite and the native harness
|
|
148
|
+
// conformance suite and the native harness.
|
|
146
149
|
// The kit's runtime half now carries the contract for every subject;
|
|
147
150
|
// what is the fake's own here is the persist cadence around it.
|
|
148
151
|
clock.reset();
|
|
@@ -156,7 +159,7 @@ describe("run-turn: the fake adapter through the real runtime", () => {
|
|
|
156
159
|
expect(systemMessages(final), "no terminal copy: the run ended normally").toEqual([]);
|
|
157
160
|
});
|
|
158
161
|
|
|
159
|
-
it("structured output on a file-review-pending turn is resolved before the pause and rides the reconcile's completion
|
|
162
|
+
it("structured output on a file-review-pending turn is resolved before the pause and rides the reconcile's completion", async () => {
|
|
160
163
|
clock.reset();
|
|
161
164
|
const driver = new RuntimeExecutionDriver(harness, "fake-review-structured", {
|
|
162
165
|
structuredOutputSchema: { type: "object", properties: { answer: { type: "number" } }, required: ["answer"] },
|
|
@@ -178,4 +181,126 @@ describe("run-turn: the fake adapter through the real runtime", () => {
|
|
|
178
181
|
expect(slim.final_text).toBe('{"answer": 42}');
|
|
179
182
|
});
|
|
180
183
|
});
|
|
184
|
+
|
|
185
|
+
describe("the runtime's own transcript rules", () => {
|
|
186
|
+
it("finalizes the transcript once runTurn returns: an adapter that leaves its last message streaming still persists a settled one", async () => {
|
|
187
|
+
// A harness that streams text and returns without closing the run —
|
|
188
|
+
// the shape of a turn that fails or is cut off before its own settle
|
|
189
|
+
// (native's thrown recursion limit; either harness's internal failure
|
|
190
|
+
// before its settle ran). Before the runtime owned the close, that
|
|
191
|
+
// message persisted `isStreaming: true` in a terminal execution: a
|
|
192
|
+
// spinner the console never stopped, seen by the kit on both real
|
|
193
|
+
// adapters. The rule lives in `run-turn.ts`, so its proof lives here.
|
|
194
|
+
const streamsAndLeaves: HarnessAdapter = {
|
|
195
|
+
...subject.adapter,
|
|
196
|
+
name: "streams-and-leaves",
|
|
197
|
+
boot: (config) => subject.adapter.boot(config),
|
|
198
|
+
shutdown: () => subject.adapter.shutdown(),
|
|
199
|
+
releaseSession: (sessionId) => subject.adapter.releaseSession(sessionId),
|
|
200
|
+
async runTurn(_input, sink) {
|
|
201
|
+
sink.transcript.apply({ kind: "message_start", runId: "r1" });
|
|
202
|
+
sink.transcript.apply({ kind: "text_delta", runId: "r1", text: "half a thou" });
|
|
203
|
+
sink.transcript.apply({ kind: "tool_started", callId: "t1", name: "shell", input: { command: "make" }, mcpServerSlug: "" });
|
|
204
|
+
sink.transcript.apply({ kind: "tool_output_delta", callId: "t1", delta: "building" });
|
|
205
|
+
return { kind: "completed" };
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
const leaving: RuntimeContractHarness = { ...harness, subject: { ...subject, name: streamsAndLeaves.name, adapter: streamsAndLeaves } };
|
|
209
|
+
await streamsAndLeaves.boot(subject.config);
|
|
210
|
+
clock.reset();
|
|
211
|
+
const driver = new RuntimeExecutionDriver(leaving, "fake-streams-and-leaves");
|
|
212
|
+
const invocation = await driver.turn([]);
|
|
213
|
+
|
|
214
|
+
expect(slimOf(leaving.subject, invocation).phase).toBe("EXECUTION_COMPLETED");
|
|
215
|
+
const final = driver.record.lastFullStatus!;
|
|
216
|
+
expect(final.messages.map((m) => [m.content, m.isStreaming]), "the message the adapter left open is closed").toEqual([["half a thou", false]]);
|
|
217
|
+
const row = final.messages[0]!.toolCalls[0]!;
|
|
218
|
+
expect([row.id, row.isStreaming, row.result], "the row the adapter left streaming output is closed, its output kept").toEqual(["t1", false, "building"]);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe("the runtime's write-back rule", () => {
|
|
223
|
+
// `run-turn.ts` calls `frame.writeback.finalize()` in exactly two places:
|
|
224
|
+
// once when a completed turn reaches its epilogue, and once when a resumed
|
|
225
|
+
// file review reconciles cleanly — never when the reconcile failed, since
|
|
226
|
+
// diverged bytes must not reach a remote. These arms pin the CALL and its
|
|
227
|
+
// guards, not the coordinator's own behaviour (`writeback-coordinator.test.ts`
|
|
228
|
+
// does that): the session mounts a local path so a coordinator exists
|
|
229
|
+
// (`provisionWorkspace` builds one whenever the session has an entry; with
|
|
230
|
+
// no git remote it has nothing eligible and `finalize` is a no-op loop), and
|
|
231
|
+
// the spy sits on the prototype because the coordinator is constructed
|
|
232
|
+
// inside `provisionWorkspace` with no injection seam — adding one for a
|
|
233
|
+
// test would be a production change the arm does not need.
|
|
234
|
+
const finalize = vi.spyOn(WriteBackCoordinator.prototype, "finalize");
|
|
235
|
+
|
|
236
|
+
afterAll(() => {
|
|
237
|
+
finalize.mockRestore();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
function driverWithLocalWorkspace(label: string): { driver: RuntimeExecutionDriver; repo: string } {
|
|
241
|
+
const repo = join(env.workspaceRootDir, "repos", label);
|
|
242
|
+
initGitWorkspace(repo, { "README.md": "# write-back\n" });
|
|
243
|
+
const driver = new RuntimeExecutionDriver(harness, label, { workspaceEntries: [localPathEntry("notes", repo)] });
|
|
244
|
+
return { driver, repo };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
it("a completed turn finalizes the write-back exactly once", async () => {
|
|
248
|
+
clock.reset();
|
|
249
|
+
finalize.mockClear();
|
|
250
|
+
const { driver } = driverWithLocalWorkspace("fake-writeback-completed");
|
|
251
|
+
|
|
252
|
+
const invocation = await driver.turn([scenario.say("Nothing to change.")]);
|
|
253
|
+
|
|
254
|
+
expect(slimOf(subject, invocation).phase).toBe("EXECUTION_COMPLETED");
|
|
255
|
+
expect(finalize, "the completion epilogue's one call").toHaveBeenCalledTimes(1);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("a resumed file review that reconciles cleanly finalizes exactly once, on the resume", async () => {
|
|
259
|
+
clock.reset();
|
|
260
|
+
finalize.mockClear();
|
|
261
|
+
const { driver } = driverWithLocalWorkspace("fake-writeback-review");
|
|
262
|
+
|
|
263
|
+
const first = await driver.turn([scenario.flowingWrite("fake-writeback-review-w", "answer.md"), scenario.say("Written.")]);
|
|
264
|
+
expect(slimOf(subject, first).phase).toBe("EXECUTION_WAITING_FOR_APPROVAL");
|
|
265
|
+
expect(finalize, "a turn paused for review has pushed nothing").toHaveBeenCalledTimes(0);
|
|
266
|
+
|
|
267
|
+
clock.tick();
|
|
268
|
+
driver.record.decideCapturedFileChanges({ approve: ["answer.md"] }, new Date().toISOString());
|
|
269
|
+
const second = await driver.turn([]);
|
|
270
|
+
|
|
271
|
+
expect(slimOf(subject, second).phase).toBe("EXECUTION_COMPLETED");
|
|
272
|
+
expect(finalize, "the resolved review's one call; the completion path does not run again").toHaveBeenCalledTimes(1);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("a resumed file review whose reconcile fails never finalizes", async () => {
|
|
276
|
+
clock.reset();
|
|
277
|
+
finalize.mockClear();
|
|
278
|
+
const { driver } = driverWithLocalWorkspace("fake-writeback-diverged");
|
|
279
|
+
|
|
280
|
+
const first = await driver.turn([scenario.flowingWrite("fake-writeback-diverged-w", "answer.md"), scenario.say("Written.")]);
|
|
281
|
+
expect(slimOf(subject, first).phase).toBe("EXECUTION_WAITING_FOR_APPROVAL");
|
|
282
|
+
|
|
283
|
+
// What the reviewer approved must be what applies. On the git substrate
|
|
284
|
+
// the reconcile re-asserts the approved bytes from the pinned capture
|
|
285
|
+
// ref (a working-tree edit after the pause is simply overwritten), so
|
|
286
|
+
// the failure path is the ledger's digest disagreeing with the captured
|
|
287
|
+
// bytes — the same divergence `capture.test.ts` drives at unit level.
|
|
288
|
+
// The reconcile then refuses to apply anything, the review completes
|
|
289
|
+
// with the refusal on the transcript, the tree is left for diagnosis —
|
|
290
|
+
// and nothing may be pushed from it.
|
|
291
|
+
clock.tick();
|
|
292
|
+
driver.record.decideCapturedFileChanges({ approve: ["answer.md"] }, new Date().toISOString());
|
|
293
|
+
const decided = driver.record.status!.fileChangeSets.at(-1)!.changes.find((c) => c.pathAfter === "answer.md")!;
|
|
294
|
+
decided.afterSha256 = "deadbeef".repeat(8);
|
|
295
|
+
const second = await driver.turn([]);
|
|
296
|
+
|
|
297
|
+
expect(slimOf(subject, second).phase).toBe("EXECUTION_COMPLETED");
|
|
298
|
+
const final = driver.record.lastFullStatus!;
|
|
299
|
+
expect(
|
|
300
|
+
final.messages.some((m) => m.content.startsWith(TERMINAL_COPY.fileReview.applyFailedPrefix)),
|
|
301
|
+
"the reconcile reported its refusal",
|
|
302
|
+
).toBe(true);
|
|
303
|
+
expect(finalize, "diverged bytes never reach a remote").toHaveBeenCalledTimes(0);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
181
306
|
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins that the transcript builder knows no engine: every file under
|
|
3
|
+
* `src/harness/transcript/`, tests included, names only the packages on a
|
|
4
|
+
* short allow-list — the proto runtime and the generated protos, Node's
|
|
5
|
+
* builtins, and `vitest` inside `__tests__/`.
|
|
6
|
+
*
|
|
7
|
+
* Why it matters (the canonical transcript's one disposition rule): the builder folds
|
|
8
|
+
* facts into the status proto; every fact about an engine — a LangGraph
|
|
9
|
+
* namespace, a Cursor `SDKMessage`, a LangChain `ToolMessage` envelope —
|
|
10
|
+
* reaches it as a translator's output, never as an import. A Claude or Codex
|
|
11
|
+
* adapter is then a translator and nothing else. `@temporalio/*` is refused
|
|
12
|
+
* for the same reason the adapters refuse it: the builder runs under the
|
|
13
|
+
* contract kit outside any activity, and it moved out from under the native
|
|
14
|
+
* adapter's Temporal-free fence when it moved into `harness/` (the runtime
|
|
15
|
+
* itself is not Temporal-free — `run-turn.ts` heartbeats).
|
|
16
|
+
*
|
|
17
|
+
* An ALLOW-list, not a deny-list: an SDK that does not exist yet is refused
|
|
18
|
+
* on the day this file was written, and admitting a new package is a visible
|
|
19
|
+
* edit here with a reason, not an absence someone forgot to extend. Tests are
|
|
20
|
+
* swept too, on the direction fence's precedent (`import-direction.test.ts`):
|
|
21
|
+
* a test that imported `@langchain/core` to build a fixture would be exactly
|
|
22
|
+
* the coupling that keeps the builder's own tests in the native adapter's
|
|
23
|
+
* folder until #1097 re-keyed them to the canonical union.
|
|
24
|
+
*
|
|
25
|
+
* Landed in #1097, the day the folder was created.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { describe, it, expect } from "vitest";
|
|
29
|
+
import { join, relative, sep } from "node:path";
|
|
30
|
+
import { fileURLToPath } from "node:url";
|
|
31
|
+
|
|
32
|
+
import { packageNames, readSource, typeScriptFilesUnder } from "../../__test-utils__/module-specifiers.js";
|
|
33
|
+
|
|
34
|
+
const SRC_ROOT = fileURLToPath(new URL("../../", import.meta.url));
|
|
35
|
+
const TRANSCRIPT_ROOT = join(SRC_ROOT, "harness", "transcript");
|
|
36
|
+
|
|
37
|
+
/** What a production module under `harness/transcript/` may name. */
|
|
38
|
+
const ALLOWED = new Set(["@bufbuild/protobuf", "@stigmer/protos"]);
|
|
39
|
+
/** What a test under `harness/transcript/__tests__/` may name in addition. */
|
|
40
|
+
const ALLOWED_IN_TESTS = new Set([...ALLOWED, "vitest"]);
|
|
41
|
+
|
|
42
|
+
function isTestFile(file: string): boolean {
|
|
43
|
+
return file.includes(`${sep}__tests__${sep}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("packageNames (the checker itself)", () => {
|
|
47
|
+
const file = join(TRANSCRIPT_ROOT, "builder.ts");
|
|
48
|
+
|
|
49
|
+
it("reduces a specifier to its package and drops relatives and builtins", () => {
|
|
50
|
+
const source = [
|
|
51
|
+
'import { create } from "@bufbuild/protobuf";',
|
|
52
|
+
'import type { AgentMessage } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";',
|
|
53
|
+
'import { join } from "node:path";',
|
|
54
|
+
'import { a } from "./events.js";',
|
|
55
|
+
'import { b } from "../../shared/status.js";',
|
|
56
|
+
'import ts from "typescript";',
|
|
57
|
+
'const m = await import("@langchain/core/messages");',
|
|
58
|
+
].join("\n");
|
|
59
|
+
expect(packageNames(file, source)).toEqual(["@bufbuild/protobuf", "@stigmer/protos", "typescript", "@langchain/core"]);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("src/harness/transcript names no engine, no SDK, no Temporal", () => {
|
|
64
|
+
const files = typeScriptFilesUnder(TRANSCRIPT_ROOT, new Set());
|
|
65
|
+
const offences = files.flatMap((file) => {
|
|
66
|
+
const allowed = isTestFile(file) ? ALLOWED_IN_TESTS : ALLOWED;
|
|
67
|
+
return packageNames(file, readSource(file))
|
|
68
|
+
.filter((pkg) => !allowed.has(pkg))
|
|
69
|
+
.map((pkg) => ` ${relative(SRC_ROOT, file)} names "${pkg}"`);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("inspected the builder's own files, tests included (the walk is rooted where it claims)", () => {
|
|
73
|
+
const walked = files.map((f) => relative(TRANSCRIPT_ROOT, f));
|
|
74
|
+
expect(walked).toEqual(expect.arrayContaining(["builder.ts", "events.ts", "state.ts", join("__tests__", "state.test.ts")]));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("finds no package outside the allow-list", () => {
|
|
78
|
+
expect(
|
|
79
|
+
offences,
|
|
80
|
+
`src/harness/transcript/ may name only ${[...ALLOWED_IN_TESTS].join(", ")} (vitest in tests only):\n${offences.join("\n")}`,
|
|
81
|
+
).toEqual([]);
|
|
82
|
+
});
|
|
83
|
+
});
|