lsd-pi 1.0.0 → 1.1.1
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 +283 -648
- package/dist/cli-theme.d.ts +1 -1
- package/dist/cli-theme.js +4 -4
- package/dist/cli.js +2 -2
- package/dist/headless.js +4 -6
- package/dist/help-text.js +1 -3
- package/dist/loader.js +8 -7
- package/dist/logo.d.ts +9 -0
- package/dist/logo.js +18 -8
- package/dist/lsd-brand.d.ts +14 -0
- package/dist/lsd-brand.js +42 -0
- package/dist/onboarding.js +51 -0
- package/dist/resource-loader.d.ts +2 -3
- package/dist/resource-loader.js +18 -20
- package/dist/resources/agents/generic.md +29 -0
- package/dist/resources/agents/scout.md +1 -0
- package/dist/resources/extensions/ask-user-questions.js +0 -4
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +6 -0
- package/dist/resources/extensions/get-secrets-from-user.js +2 -3
- package/dist/resources/extensions/memory/auto-extract.js +154 -0
- package/dist/resources/extensions/memory/extension-manifest.json +11 -0
- package/dist/resources/extensions/memory/index.js +223 -0
- package/dist/resources/extensions/memory/memory-age.js +43 -0
- package/dist/resources/extensions/memory/memory-paths.js +49 -0
- package/dist/resources/extensions/memory/memory-recall.js +150 -0
- package/dist/resources/extensions/memory/memory-scan.js +90 -0
- package/dist/resources/extensions/memory/memory-types.js +96 -0
- package/dist/resources/extensions/remote-questions/config.js +3 -3
- package/dist/resources/extensions/remote-questions/extension-manifest.json +1 -1
- package/dist/resources/extensions/remote-questions/index.js +53 -0
- package/dist/resources/extensions/remote-questions/remote-command.js +4 -27
- package/dist/resources/extensions/remote-questions/telegram-adapter.js +6 -13
- package/dist/resources/extensions/remote-questions/telegram-live-relay.js +447 -0
- package/dist/resources/extensions/remote-questions/telegram-update-stream.js +67 -0
- package/dist/resources/extensions/search-the-web/native-search.js +1 -1
- package/dist/resources/extensions/search-the-web/provider.js +4 -12
- package/dist/resources/extensions/shared/debug-logger.js +103 -0
- package/dist/resources/extensions/shared/env-utils.js +17 -0
- package/dist/resources/extensions/shared/paths.js +17 -0
- package/dist/resources/extensions/shared/preferences.js +90 -0
- package/dist/resources/extensions/shared/remote-questions-config.js +27 -0
- package/dist/resources/extensions/shared/rtk-session-stats.js +2 -2
- package/dist/resources/extensions/shared/secrets-manifest.js +115 -0
- package/dist/resources/extensions/slash-commands/extension-manifest.json +2 -1
- package/dist/resources/extensions/slash-commands/index.js +2 -0
- package/dist/resources/extensions/slash-commands/plan.js +284 -0
- package/dist/resources/extensions/subagent/agents.js +1 -1
- package/dist/resources/extensions/subagent/approval-proxy.js +34 -0
- package/dist/resources/extensions/subagent/configured-model.js +9 -0
- package/dist/resources/extensions/subagent/index.js +95 -144
- package/dist/resources/extensions/subagent/model-resolution.js +12 -0
- package/dist/resources/extensions/ttsr/ttsr-manager.js +1 -1
- package/dist/resources/skills/create-skill/SKILL.md +2 -2
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +8 -7
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +6 -5
- package/dist/shared-paths.d.ts +1 -0
- package/dist/shared-paths.js +17 -0
- package/dist/shared-preferences.d.ts +37 -0
- package/dist/shared-preferences.js +102 -0
- package/dist/welcome-screen.js +24 -18
- package/dist/worktree-cli.d.ts +4 -49
- package/dist/worktree-cli.js +197 -113
- package/package.json +6 -6
- package/packages/pi-coding-agent/dist/cli/args.d.ts +1 -1
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +13 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +35 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +8 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +77 -15
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +76 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -2
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +8 -8
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-lsd-md.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/resource-loader-lsd-md.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/resource-loader-lsd-md.test.js +59 -0
- package/packages/pi-coding-agent/dist/core/resource-loader-lsd-md.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +32 -14
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +13 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -6
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +18 -13
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.js +2 -0
- package/packages/pi-coding-agent/dist/core/tool-approval.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +1 -1
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +5 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +11 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +11 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +7 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +33 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +129 -57
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +12 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +46 -6
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +28 -20
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +14 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +30 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +36 -0
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +9 -0
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +87 -0
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +84 -16
- package/packages/pi-coding-agent/src/core/keybindings.ts +2 -2
- package/packages/pi-coding-agent/src/core/package-manager.ts +8 -8
- package/packages/pi-coding-agent/src/core/resource-loader-lsd-md.test.ts +67 -0
- package/packages/pi-coding-agent/src/core/resource-loader.ts +32 -13
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -5
- package/packages/pi-coding-agent/src/core/skills.ts +20 -14
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -1
- package/packages/pi-coding-agent/src/core/tool-approval.js +111 -0
- package/packages/pi-coding-agent/src/core/tool-approval.ts +2 -1
- package/packages/pi-coding-agent/src/index.ts +2 -0
- package/packages/pi-coding-agent/src/main.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +14 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +11 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +40 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +135 -66
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +12 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +70 -6
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +28 -20
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +28 -20
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/agents/generic.md +29 -0
- package/src/resources/agents/scout.md +1 -0
- package/src/resources/extensions/ask-user-questions.ts +0 -3
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +6 -0
- package/src/resources/extensions/cmux/index.ts +29 -10
- package/src/resources/extensions/get-secrets-from-user.ts +2 -4
- package/src/resources/extensions/gsd/tests/test-helpers.ts +44 -44
- package/src/resources/extensions/memory/auto-extract.ts +172 -0
- package/src/resources/extensions/memory/extension-manifest.json +11 -0
- package/src/resources/extensions/memory/index.ts +263 -0
- package/src/resources/extensions/memory/memory-age.ts +43 -0
- package/src/resources/extensions/memory/memory-paths.ts +55 -0
- package/src/resources/extensions/memory/memory-recall.ts +186 -0
- package/src/resources/extensions/memory/memory-scan.ts +118 -0
- package/src/resources/extensions/memory/memory-types.ts +106 -0
- package/src/resources/extensions/memory/tests/auto-extract.test.ts +141 -0
- package/src/resources/extensions/memory/tests/memory-age.test.ts +60 -0
- package/src/resources/extensions/memory/tests/memory-paths.test.ts +89 -0
- package/src/resources/extensions/memory/tests/memory-scan.test.ts +244 -0
- package/src/resources/extensions/remote-questions/config.ts +3 -3
- package/src/resources/extensions/remote-questions/extension-manifest.json +1 -1
- package/src/resources/extensions/remote-questions/index.ts +65 -0
- package/src/resources/extensions/remote-questions/remote-command.ts +4 -30
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +6 -14
- package/src/resources/extensions/remote-questions/telegram-live-relay.ts +471 -0
- package/src/resources/extensions/remote-questions/telegram-update-stream.ts +116 -0
- package/src/resources/extensions/search-the-web/native-search.ts +2 -1
- package/src/resources/extensions/search-the-web/provider.ts +3 -10
- package/src/resources/extensions/shared/debug-logger.ts +102 -0
- package/src/resources/extensions/shared/env-utils.ts +18 -0
- package/src/resources/extensions/shared/paths.ts +15 -0
- package/src/resources/extensions/shared/preferences.ts +122 -0
- package/src/resources/extensions/shared/remote-questions-config.ts +30 -0
- package/src/resources/extensions/shared/rtk-session-stats.ts +2 -2
- package/src/resources/extensions/shared/secrets-manifest.ts +130 -0
- package/src/resources/extensions/slash-commands/extension-manifest.json +2 -1
- package/src/resources/extensions/slash-commands/index.ts +2 -0
- package/src/resources/extensions/slash-commands/plan.ts +328 -0
- package/src/resources/extensions/subagent/agents.ts +1 -1
- package/src/resources/extensions/subagent/approval-proxy.ts +70 -0
- package/src/resources/extensions/subagent/configured-model.ts +15 -0
- package/src/resources/extensions/subagent/index.ts +126 -185
- package/src/resources/extensions/subagent/model-resolution.ts +26 -0
- package/src/resources/extensions/ttsr/ttsr-manager.ts +1 -1
- package/src/resources/skills/create-skill/SKILL.md +2 -2
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +8 -7
- package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +6 -5
- package/dist/resources/extensions/github-sync/cli.js +0 -284
- package/dist/resources/extensions/github-sync/index.js +0 -73
- package/dist/resources/extensions/github-sync/mapping.js +0 -67
- package/dist/resources/extensions/github-sync/sync.js +0 -425
- package/dist/resources/extensions/github-sync/templates.js +0 -118
- package/dist/resources/extensions/github-sync/types.js +0 -7
- package/dist/resources/extensions/gsd/activity-log.js +0 -153
- package/dist/resources/extensions/gsd/atomic-write.js +0 -134
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +0 -49
- package/dist/resources/extensions/gsd/auto/infra-errors.js +0 -49
- package/dist/resources/extensions/gsd/auto/loop-deps.js +0 -6
- package/dist/resources/extensions/gsd/auto/loop.js +0 -256
- package/dist/resources/extensions/gsd/auto/phases.js +0 -942
- package/dist/resources/extensions/gsd/auto/resolve.js +0 -90
- package/dist/resources/extensions/gsd/auto/run-unit.js +0 -106
- package/dist/resources/extensions/gsd/auto/session.js +0 -171
- package/dist/resources/extensions/gsd/auto/types.js +0 -23
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +0 -116
- package/dist/resources/extensions/gsd/auto-budget.js +0 -30
- package/dist/resources/extensions/gsd/auto-dashboard.js +0 -751
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +0 -212
- package/dist/resources/extensions/gsd/auto-dispatch.js +0 -627
- package/dist/resources/extensions/gsd/auto-loop.js +0 -13
- package/dist/resources/extensions/gsd/auto-model-selection.js +0 -192
- package/dist/resources/extensions/gsd/auto-observability.js +0 -54
- package/dist/resources/extensions/gsd/auto-post-unit.js +0 -548
- package/dist/resources/extensions/gsd/auto-prompts.js +0 -1686
- package/dist/resources/extensions/gsd/auto-recovery.js +0 -533
- package/dist/resources/extensions/gsd/auto-start.js +0 -544
- package/dist/resources/extensions/gsd/auto-supervisor.js +0 -73
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +0 -180
- package/dist/resources/extensions/gsd/auto-timers.js +0 -261
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +0 -77
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +0 -30
- package/dist/resources/extensions/gsd/auto-utils.js +0 -20
- package/dist/resources/extensions/gsd/auto-verification.js +0 -163
- package/dist/resources/extensions/gsd/auto-worktree.js +0 -1645
- package/dist/resources/extensions/gsd/auto.js +0 -1087
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +0 -191
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +0 -1207
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +0 -149
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +0 -62
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +0 -18
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +0 -53
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +0 -267
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +0 -45
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +0 -367
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +0 -75
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +0 -105
- package/dist/resources/extensions/gsd/branch-patterns.js +0 -13
- package/dist/resources/extensions/gsd/cache.js +0 -27
- package/dist/resources/extensions/gsd/captures.js +0 -414
- package/dist/resources/extensions/gsd/changelog.js +0 -162
- package/dist/resources/extensions/gsd/claude-import.js +0 -591
- package/dist/resources/extensions/gsd/collision-diagnostics.js +0 -226
- package/dist/resources/extensions/gsd/commands/catalog.js +0 -336
- package/dist/resources/extensions/gsd/commands/context.js +0 -87
- package/dist/resources/extensions/gsd/commands/dispatcher.js +0 -21
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +0 -175
- package/dist/resources/extensions/gsd/commands/handlers/core.js +0 -249
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +0 -207
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +0 -106
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +0 -253
- package/dist/resources/extensions/gsd/commands/index.js +0 -11
- package/dist/resources/extensions/gsd/commands-bootstrap.js +0 -224
- package/dist/resources/extensions/gsd/commands-cmux.js +0 -120
- package/dist/resources/extensions/gsd/commands-config.js +0 -94
- package/dist/resources/extensions/gsd/commands-extensions.js +0 -260
- package/dist/resources/extensions/gsd/commands-handlers.js +0 -318
- package/dist/resources/extensions/gsd/commands-inspect.js +0 -77
- package/dist/resources/extensions/gsd/commands-logs.js +0 -468
- package/dist/resources/extensions/gsd/commands-maintenance.js +0 -485
- package/dist/resources/extensions/gsd/commands-mcp-status.js +0 -187
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +0 -664
- package/dist/resources/extensions/gsd/commands-rate.js +0 -31
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +0 -408
- package/dist/resources/extensions/gsd/commands.js +0 -9
- package/dist/resources/extensions/gsd/complexity-classifier.js +0 -259
- package/dist/resources/extensions/gsd/constants.js +0 -15
- package/dist/resources/extensions/gsd/context-budget.js +0 -179
- package/dist/resources/extensions/gsd/context-injector.js +0 -74
- package/dist/resources/extensions/gsd/context-store.js +0 -166
- package/dist/resources/extensions/gsd/crash-recovery.js +0 -112
- package/dist/resources/extensions/gsd/custom-execution-policy.js +0 -48
- package/dist/resources/extensions/gsd/custom-verification.js +0 -147
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +0 -165
- package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -539
- package/dist/resources/extensions/gsd/db-writer.js +0 -518
- package/dist/resources/extensions/gsd/debug-logger.js +0 -161
- package/dist/resources/extensions/gsd/definition-loader.js +0 -352
- package/dist/resources/extensions/gsd/detection.js +0 -977
- package/dist/resources/extensions/gsd/dev-execution-policy.js +0 -24
- package/dist/resources/extensions/gsd/dev-workflow-engine.js +0 -82
- package/dist/resources/extensions/gsd/diff-context.js +0 -168
- package/dist/resources/extensions/gsd/dispatch-guard.js +0 -114
- package/dist/resources/extensions/gsd/docs/claude-marketplace-import.md +0 -214
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -671
- package/dist/resources/extensions/gsd/doctor-checks.js +0 -5
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +0 -168
- package/dist/resources/extensions/gsd/doctor-environment.js +0 -565
- package/dist/resources/extensions/gsd/doctor-format.js +0 -86
- package/dist/resources/extensions/gsd/doctor-git-checks.js +0 -433
- package/dist/resources/extensions/gsd/doctor-global-checks.js +0 -74
- package/dist/resources/extensions/gsd/doctor-proactive.js +0 -349
- package/dist/resources/extensions/gsd/doctor-providers.js +0 -356
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +0 -601
- package/dist/resources/extensions/gsd/doctor-types.js +0 -15
- package/dist/resources/extensions/gsd/doctor.js +0 -765
- package/dist/resources/extensions/gsd/engine-resolver.js +0 -40
- package/dist/resources/extensions/gsd/engine-types.js +0 -8
- package/dist/resources/extensions/gsd/env-utils.js +0 -29
- package/dist/resources/extensions/gsd/error-classifier.js +0 -108
- package/dist/resources/extensions/gsd/error-utils.js +0 -6
- package/dist/resources/extensions/gsd/errors.js +0 -24
- package/dist/resources/extensions/gsd/execution-policy.js +0 -8
- package/dist/resources/extensions/gsd/exit-command.js +0 -22
- package/dist/resources/extensions/gsd/export-html.js +0 -1271
- package/dist/resources/extensions/gsd/export.js +0 -264
- package/dist/resources/extensions/gsd/extension-manifest.json +0 -33
- package/dist/resources/extensions/gsd/file-watcher.js +0 -80
- package/dist/resources/extensions/gsd/files.js +0 -863
- package/dist/resources/extensions/gsd/forensics.js +0 -996
- package/dist/resources/extensions/gsd/git-constants.js +0 -11
- package/dist/resources/extensions/gsd/git-self-heal.js +0 -113
- package/dist/resources/extensions/gsd/git-service.js +0 -586
- package/dist/resources/extensions/gsd/gitignore.js +0 -285
- package/dist/resources/extensions/gsd/graph.js +0 -225
- package/dist/resources/extensions/gsd/gsd-db.js +0 -1808
- package/dist/resources/extensions/gsd/guided-flow-queue.js +0 -365
- package/dist/resources/extensions/gsd/guided-flow.js +0 -1456
- package/dist/resources/extensions/gsd/health-widget-core.js +0 -89
- package/dist/resources/extensions/gsd/health-widget.js +0 -126
- package/dist/resources/extensions/gsd/history.js +0 -119
- package/dist/resources/extensions/gsd/index.js +0 -5
- package/dist/resources/extensions/gsd/init-wizard.js +0 -487
- package/dist/resources/extensions/gsd/journal.js +0 -85
- package/dist/resources/extensions/gsd/json-persistence.js +0 -70
- package/dist/resources/extensions/gsd/jsonl-utils.js +0 -24
- package/dist/resources/extensions/gsd/key-manager.js +0 -820
- package/dist/resources/extensions/gsd/markdown-renderer.js +0 -891
- package/dist/resources/extensions/gsd/marketplace-discovery.js +0 -356
- package/dist/resources/extensions/gsd/md-importer.js +0 -623
- package/dist/resources/extensions/gsd/memory-extractor.js +0 -302
- package/dist/resources/extensions/gsd/memory-store.js +0 -366
- package/dist/resources/extensions/gsd/metrics.js +0 -419
- package/dist/resources/extensions/gsd/migrate/command.js +0 -157
- package/dist/resources/extensions/gsd/migrate/index.js +0 -7
- package/dist/resources/extensions/gsd/migrate/parser.js +0 -268
- package/dist/resources/extensions/gsd/migrate/parsers.js +0 -477
- package/dist/resources/extensions/gsd/migrate/preview.js +0 -47
- package/dist/resources/extensions/gsd/migrate/transformer.js +0 -278
- package/dist/resources/extensions/gsd/migrate/types.js +0 -4
- package/dist/resources/extensions/gsd/migrate/validator.js +0 -41
- package/dist/resources/extensions/gsd/migrate/writer.js +0 -477
- package/dist/resources/extensions/gsd/migrate-external.js +0 -207
- package/dist/resources/extensions/gsd/milestone-actions.js +0 -130
- package/dist/resources/extensions/gsd/milestone-id-utils.js +0 -28
- package/dist/resources/extensions/gsd/milestone-ids.js +0 -116
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +0 -45
- package/dist/resources/extensions/gsd/model-cost-table.js +0 -66
- package/dist/resources/extensions/gsd/model-router.js +0 -246
- package/dist/resources/extensions/gsd/namespaced-registry.js +0 -322
- package/dist/resources/extensions/gsd/namespaced-resolver.js +0 -176
- package/dist/resources/extensions/gsd/native-git-bridge.js +0 -992
- package/dist/resources/extensions/gsd/native-parser-bridge.js +0 -156
- package/dist/resources/extensions/gsd/notifications.js +0 -105
- package/dist/resources/extensions/gsd/observability-validator.js +0 -422
- package/dist/resources/extensions/gsd/package.json +0 -11
- package/dist/resources/extensions/gsd/parallel-eligibility.js +0 -188
- package/dist/resources/extensions/gsd/parallel-merge.js +0 -194
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +0 -413
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +0 -850
- package/dist/resources/extensions/gsd/parsers-legacy.js +0 -256
- package/dist/resources/extensions/gsd/paths.js +0 -527
- package/dist/resources/extensions/gsd/plugin-importer.js +0 -254
- package/dist/resources/extensions/gsd/post-unit-hooks.js +0 -48
- package/dist/resources/extensions/gsd/preferences-models.js +0 -295
- package/dist/resources/extensions/gsd/preferences-skills.js +0 -160
- package/dist/resources/extensions/gsd/preferences-types.js +0 -82
- package/dist/resources/extensions/gsd/preferences-validation.js +0 -852
- package/dist/resources/extensions/gsd/preferences.js +0 -432
- package/dist/resources/extensions/gsd/progress-score.js +0 -121
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +0 -150
- package/dist/resources/extensions/gsd/prompt-loader.js +0 -156
- package/dist/resources/extensions/gsd/prompt-ordering.js +0 -170
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +0 -66
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +0 -40
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +0 -253
- package/dist/resources/extensions/gsd/prompts/discuss.md +0 -290
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +0 -29
- package/dist/resources/extensions/gsd/prompts/execute-task.md +0 -80
- package/dist/resources/extensions/gsd/prompts/forensics.md +0 -196
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +0 -32
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +0 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +0 -110
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +0 -62
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +0 -3
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +0 -30
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +0 -3
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +0 -15
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +0 -1
- package/dist/resources/extensions/gsd/prompts/heal-skill.md +0 -45
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +0 -108
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +0 -89
- package/dist/resources/extensions/gsd/prompts/queue.md +0 -132
- package/dist/resources/extensions/gsd/prompts/quick-task.md +0 -44
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +0 -44
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +0 -66
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +0 -39
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +0 -47
- package/dist/resources/extensions/gsd/prompts/research-slice.md +0 -57
- package/dist/resources/extensions/gsd/prompts/rethink.md +0 -83
- package/dist/resources/extensions/gsd/prompts/review-migration.md +0 -66
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +0 -31
- package/dist/resources/extensions/gsd/prompts/run-uat.md +0 -89
- package/dist/resources/extensions/gsd/prompts/system.md +0 -220
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +0 -63
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +0 -47
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +0 -28
- package/dist/resources/extensions/gsd/prompts/worktree-merge.md +0 -123
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -31
- package/dist/resources/extensions/gsd/queue-order.js +0 -178
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +0 -235
- package/dist/resources/extensions/gsd/quick.js +0 -206
- package/dist/resources/extensions/gsd/reactive-graph.js +0 -257
- package/dist/resources/extensions/gsd/repo-identity.js +0 -641
- package/dist/resources/extensions/gsd/reports.js +0 -409
- package/dist/resources/extensions/gsd/rethink.js +0 -120
- package/dist/resources/extensions/gsd/roadmap-mutations.js +0 -110
- package/dist/resources/extensions/gsd/roadmap-slices.js +0 -255
- package/dist/resources/extensions/gsd/routing-history.js +0 -210
- package/dist/resources/extensions/gsd/rtk-status.js +0 -43
- package/dist/resources/extensions/gsd/rule-registry.js +0 -488
- package/dist/resources/extensions/gsd/rule-types.js +0 -6
- package/dist/resources/extensions/gsd/run-manager.js +0 -134
- package/dist/resources/extensions/gsd/safe-fs.js +0 -52
- package/dist/resources/extensions/gsd/service-tier.js +0 -158
- package/dist/resources/extensions/gsd/session-forensics.js +0 -435
- package/dist/resources/extensions/gsd/session-lock.js +0 -554
- package/dist/resources/extensions/gsd/session-status-io.js +0 -134
- package/dist/resources/extensions/gsd/skill-catalog.js +0 -1026
- package/dist/resources/extensions/gsd/skill-discovery.js +0 -122
- package/dist/resources/extensions/gsd/skill-health.js +0 -326
- package/dist/resources/extensions/gsd/skill-telemetry.js +0 -121
- package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +0 -242
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +0 -83
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +0 -64
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +0 -176
- package/dist/resources/extensions/gsd/state.js +0 -1407
- package/dist/resources/extensions/gsd/status-guards.js +0 -12
- package/dist/resources/extensions/gsd/structured-data-formatter.js +0 -98
- package/dist/resources/extensions/gsd/sync-lock.js +0 -89
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +0 -80
- package/dist/resources/extensions/gsd/templates/context.md +0 -76
- package/dist/resources/extensions/gsd/templates/decisions.md +0 -8
- package/dist/resources/extensions/gsd/templates/knowledge.md +0 -19
- package/dist/resources/extensions/gsd/templates/milestone-summary.md +0 -81
- package/dist/resources/extensions/gsd/templates/milestone-validation.md +0 -74
- package/dist/resources/extensions/gsd/templates/plan.md +0 -148
- package/dist/resources/extensions/gsd/templates/project.md +0 -31
- package/dist/resources/extensions/gsd/templates/reassessment.md +0 -29
- package/dist/resources/extensions/gsd/templates/requirements.md +0 -81
- package/dist/resources/extensions/gsd/templates/research.md +0 -79
- package/dist/resources/extensions/gsd/templates/roadmap.md +0 -131
- package/dist/resources/extensions/gsd/templates/runtime.md +0 -21
- package/dist/resources/extensions/gsd/templates/secrets-manifest.md +0 -22
- package/dist/resources/extensions/gsd/templates/slice-context.md +0 -58
- package/dist/resources/extensions/gsd/templates/slice-summary.md +0 -108
- package/dist/resources/extensions/gsd/templates/state.md +0 -17
- package/dist/resources/extensions/gsd/templates/task-plan.md +0 -87
- package/dist/resources/extensions/gsd/templates/task-summary.md +0 -66
- package/dist/resources/extensions/gsd/templates/uat.md +0 -54
- package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
- package/dist/resources/extensions/gsd/token-counter.js +0 -54
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +0 -172
- package/dist/resources/extensions/gsd/tools/complete-slice.js +0 -276
- package/dist/resources/extensions/gsd/tools/complete-task.js +0 -205
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +0 -250
- package/dist/resources/extensions/gsd/tools/plan-slice.js +0 -199
- package/dist/resources/extensions/gsd/tools/plan-task.js +0 -121
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +0 -219
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +0 -87
- package/dist/resources/extensions/gsd/tools/reopen-task.js +0 -91
- package/dist/resources/extensions/gsd/tools/replan-slice.js +0 -188
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +0 -110
- package/dist/resources/extensions/gsd/triage-resolution.js +0 -322
- package/dist/resources/extensions/gsd/triage-ui.js +0 -135
- package/dist/resources/extensions/gsd/types.js +0 -4
- package/dist/resources/extensions/gsd/undo.js +0 -400
- package/dist/resources/extensions/gsd/unit-id.js +0 -7
- package/dist/resources/extensions/gsd/unit-ownership.js +0 -216
- package/dist/resources/extensions/gsd/unit-runtime.js +0 -132
- package/dist/resources/extensions/gsd/validate-directory.js +0 -143
- package/dist/resources/extensions/gsd/validation.js +0 -21
- package/dist/resources/extensions/gsd/verdict-parser.js +0 -96
- package/dist/resources/extensions/gsd/verification-evidence.js +0 -122
- package/dist/resources/extensions/gsd/verification-gate.js +0 -519
- package/dist/resources/extensions/gsd/visualizer-data.js +0 -674
- package/dist/resources/extensions/gsd/visualizer-overlay.js +0 -501
- package/dist/resources/extensions/gsd/visualizer-views.js +0 -945
- package/dist/resources/extensions/gsd/workflow-engine.js +0 -7
- package/dist/resources/extensions/gsd/workflow-events.js +0 -102
- package/dist/resources/extensions/gsd/workflow-logger.js +0 -192
- package/dist/resources/extensions/gsd/workflow-manifest.js +0 -263
- package/dist/resources/extensions/gsd/workflow-migration.js +0 -280
- package/dist/resources/extensions/gsd/workflow-projections.js +0 -405
- package/dist/resources/extensions/gsd/workflow-reconcile.js +0 -441
- package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +0 -87
- package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +0 -74
- package/dist/resources/extensions/gsd/workflow-templates/full-project.md +0 -40
- package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +0 -45
- package/dist/resources/extensions/gsd/workflow-templates/refactor.md +0 -83
- package/dist/resources/extensions/gsd/workflow-templates/registry.json +0 -85
- package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +0 -73
- package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +0 -81
- package/dist/resources/extensions/gsd/workflow-templates/spike.md +0 -69
- package/dist/resources/extensions/gsd/workflow-templates.js +0 -200
- package/dist/resources/extensions/gsd/workspace-index.js +0 -190
- package/dist/resources/extensions/gsd/worktree-command-bootstrap.js +0 -40
- package/dist/resources/extensions/gsd/worktree-command.js +0 -702
- package/dist/resources/extensions/gsd/worktree-health.js +0 -126
- package/dist/resources/extensions/gsd/worktree-manager.js +0 -518
- package/dist/resources/extensions/gsd/worktree-resolver.js +0 -480
- package/dist/resources/extensions/gsd/worktree.js +0 -310
- package/dist/resources/extensions/gsd/write-intercept.js +0 -84
- package/src/resources/extensions/github-sync/cli.ts +0 -364
- package/src/resources/extensions/github-sync/index.ts +0 -93
- package/src/resources/extensions/github-sync/mapping.ts +0 -81
- package/src/resources/extensions/github-sync/sync.ts +0 -557
- package/src/resources/extensions/github-sync/templates.ts +0 -183
- package/src/resources/extensions/github-sync/tests/cli.test.ts +0 -20
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +0 -43
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +0 -104
- package/src/resources/extensions/github-sync/tests/templates.test.ts +0 -110
- package/src/resources/extensions/github-sync/types.ts +0 -47
- package/src/resources/extensions/gsd/activity-log.ts +0 -163
- package/src/resources/extensions/gsd/atomic-write.ts +0 -185
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +0 -60
- package/src/resources/extensions/gsd/auto/infra-errors.ts +0 -48
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -268
- package/src/resources/extensions/gsd/auto/loop.ts +0 -318
- package/src/resources/extensions/gsd/auto/phases.ts +0 -1327
- package/src/resources/extensions/gsd/auto/resolve.ts +0 -106
- package/src/resources/extensions/gsd/auto/run-unit.ts +0 -136
- package/src/resources/extensions/gsd/auto/session.ts +0 -237
- package/src/resources/extensions/gsd/auto/types.ts +0 -117
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +0 -135
- package/src/resources/extensions/gsd/auto-budget.ts +0 -32
- package/src/resources/extensions/gsd/auto-dashboard.ts +0 -880
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +0 -256
- package/src/resources/extensions/gsd/auto-dispatch.ts +0 -781
- package/src/resources/extensions/gsd/auto-loop.ts +0 -16
- package/src/resources/extensions/gsd/auto-model-selection.ts +0 -251
- package/src/resources/extensions/gsd/auto-observability.ts +0 -72
- package/src/resources/extensions/gsd/auto-post-unit.ts +0 -687
- package/src/resources/extensions/gsd/auto-prompts.ts +0 -1896
- package/src/resources/extensions/gsd/auto-recovery.ts +0 -594
- package/src/resources/extensions/gsd/auto-start.ts +0 -737
- package/src/resources/extensions/gsd/auto-supervisor.ts +0 -79
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +0 -262
- package/src/resources/extensions/gsd/auto-timers.ts +0 -313
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +0 -85
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +0 -48
- package/src/resources/extensions/gsd/auto-utils.ts +0 -25
- package/src/resources/extensions/gsd/auto-verification.ts +0 -225
- package/src/resources/extensions/gsd/auto-worktree.ts +0 -1897
- package/src/resources/extensions/gsd/auto.ts +0 -1477
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +0 -219
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +0 -1286
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +0 -194
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +0 -62
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +0 -53
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +0 -61
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +0 -282
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +0 -56
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +0 -416
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +0 -91
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +0 -126
- package/src/resources/extensions/gsd/branch-patterns.ts +0 -16
- package/src/resources/extensions/gsd/cache.ts +0 -29
- package/src/resources/extensions/gsd/captures.ts +0 -502
- package/src/resources/extensions/gsd/changelog.ts +0 -213
- package/src/resources/extensions/gsd/claude-import.ts +0 -705
- package/src/resources/extensions/gsd/collision-diagnostics.ts +0 -332
- package/src/resources/extensions/gsd/commands/catalog.ts +0 -359
- package/src/resources/extensions/gsd/commands/context.ts +0 -108
- package/src/resources/extensions/gsd/commands/dispatcher.ts +0 -32
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +0 -184
- package/src/resources/extensions/gsd/commands/handlers/core.ts +0 -277
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +0 -210
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +0 -135
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +0 -281
- package/src/resources/extensions/gsd/commands/index.ts +0 -14
- package/src/resources/extensions/gsd/commands-bootstrap.ts +0 -253
- package/src/resources/extensions/gsd/commands-cmux.ts +0 -143
- package/src/resources/extensions/gsd/commands-config.ts +0 -108
- package/src/resources/extensions/gsd/commands-extensions.ts +0 -330
- package/src/resources/extensions/gsd/commands-handlers.ts +0 -404
- package/src/resources/extensions/gsd/commands-inspect.ts +0 -98
- package/src/resources/extensions/gsd/commands-logs.ts +0 -536
- package/src/resources/extensions/gsd/commands-maintenance.ts +0 -535
- package/src/resources/extensions/gsd/commands-mcp-status.ts +0 -247
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +0 -784
- package/src/resources/extensions/gsd/commands-rate.ts +0 -55
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +0 -543
- package/src/resources/extensions/gsd/commands.ts +0 -17
- package/src/resources/extensions/gsd/complexity-classifier.ts +0 -322
- package/src/resources/extensions/gsd/constants.ts +0 -21
- package/src/resources/extensions/gsd/context-budget.ts +0 -256
- package/src/resources/extensions/gsd/context-injector.ts +0 -100
- package/src/resources/extensions/gsd/context-store.ts +0 -196
- package/src/resources/extensions/gsd/crash-recovery.ts +0 -120
- package/src/resources/extensions/gsd/custom-execution-policy.ts +0 -74
- package/src/resources/extensions/gsd/custom-verification.ts +0 -182
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +0 -217
- package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -659
- package/src/resources/extensions/gsd/db-writer.ts +0 -612
- package/src/resources/extensions/gsd/debug-logger.ts +0 -178
- package/src/resources/extensions/gsd/definition-loader.ts +0 -462
- package/src/resources/extensions/gsd/detection.ts +0 -1148
- package/src/resources/extensions/gsd/dev-execution-policy.ts +0 -51
- package/src/resources/extensions/gsd/dev-workflow-engine.ts +0 -110
- package/src/resources/extensions/gsd/diff-context.ts +0 -214
- package/src/resources/extensions/gsd/dispatch-guard.ts +0 -120
- package/src/resources/extensions/gsd/docs/claude-marketplace-import.md +0 -214
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -671
- package/src/resources/extensions/gsd/doctor-checks.ts +0 -5
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +0 -182
- package/src/resources/extensions/gsd/doctor-environment.ts +0 -642
- package/src/resources/extensions/gsd/doctor-format.ts +0 -98
- package/src/resources/extensions/gsd/doctor-git-checks.ts +0 -441
- package/src/resources/extensions/gsd/doctor-global-checks.ts +0 -84
- package/src/resources/extensions/gsd/doctor-proactive.ts +0 -431
- package/src/resources/extensions/gsd/doctor-providers.ts +0 -415
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +0 -627
- package/src/resources/extensions/gsd/doctor-types.ts +0 -123
- package/src/resources/extensions/gsd/doctor.ts +0 -808
- package/src/resources/extensions/gsd/engine-resolver.ts +0 -57
- package/src/resources/extensions/gsd/engine-types.ts +0 -71
- package/src/resources/extensions/gsd/env-utils.ts +0 -31
- package/src/resources/extensions/gsd/error-classifier.ts +0 -142
- package/src/resources/extensions/gsd/error-utils.ts +0 -6
- package/src/resources/extensions/gsd/errors.ts +0 -29
- package/src/resources/extensions/gsd/execution-policy.ts +0 -43
- package/src/resources/extensions/gsd/exit-command.ts +0 -30
- package/src/resources/extensions/gsd/export-html.ts +0 -1408
- package/src/resources/extensions/gsd/export.ts +0 -310
- package/src/resources/extensions/gsd/extension-manifest.json +0 -33
- package/src/resources/extensions/gsd/file-watcher.ts +0 -100
- package/src/resources/extensions/gsd/files.ts +0 -971
- package/src/resources/extensions/gsd/forensics.ts +0 -1178
- package/src/resources/extensions/gsd/git-constants.ts +0 -12
- package/src/resources/extensions/gsd/git-self-heal.ts +0 -127
- package/src/resources/extensions/gsd/git-service.ts +0 -755
- package/src/resources/extensions/gsd/gitignore.ts +0 -315
- package/src/resources/extensions/gsd/graph.ts +0 -312
- package/src/resources/extensions/gsd/gsd-db.ts +0 -2205
- package/src/resources/extensions/gsd/guided-flow-queue.ts +0 -439
- package/src/resources/extensions/gsd/guided-flow.ts +0 -1666
- package/src/resources/extensions/gsd/health-widget-core.ts +0 -111
- package/src/resources/extensions/gsd/health-widget.ts +0 -143
- package/src/resources/extensions/gsd/history.ts +0 -144
- package/src/resources/extensions/gsd/index.ts +0 -14
- package/src/resources/extensions/gsd/init-wizard.ts +0 -595
- package/src/resources/extensions/gsd/journal.ts +0 -139
- package/src/resources/extensions/gsd/json-persistence.ts +0 -75
- package/src/resources/extensions/gsd/jsonl-utils.ts +0 -21
- package/src/resources/extensions/gsd/key-manager.ts +0 -987
- package/src/resources/extensions/gsd/markdown-renderer.ts +0 -1132
- package/src/resources/extensions/gsd/marketplace-discovery.ts +0 -508
- package/src/resources/extensions/gsd/md-importer.ts +0 -742
- package/src/resources/extensions/gsd/memory-extractor.ts +0 -360
- package/src/resources/extensions/gsd/memory-store.ts +0 -452
- package/src/resources/extensions/gsd/metrics.ts +0 -575
- package/src/resources/extensions/gsd/migrate/command.ts +0 -219
- package/src/resources/extensions/gsd/migrate/index.ts +0 -42
- package/src/resources/extensions/gsd/migrate/parser.ts +0 -323
- package/src/resources/extensions/gsd/migrate/parsers.ts +0 -539
- package/src/resources/extensions/gsd/migrate/preview.ts +0 -48
- package/src/resources/extensions/gsd/migrate/transformer.ts +0 -346
- package/src/resources/extensions/gsd/migrate/types.ts +0 -370
- package/src/resources/extensions/gsd/migrate/validator.ts +0 -55
- package/src/resources/extensions/gsd/migrate/writer.ts +0 -579
- package/src/resources/extensions/gsd/migrate-external.ts +0 -210
- package/src/resources/extensions/gsd/milestone-actions.ts +0 -143
- package/src/resources/extensions/gsd/milestone-id-utils.ts +0 -32
- package/src/resources/extensions/gsd/milestone-ids.ts +0 -135
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +0 -56
- package/src/resources/extensions/gsd/model-cost-table.ts +0 -84
- package/src/resources/extensions/gsd/model-router.ts +0 -315
- package/src/resources/extensions/gsd/namespaced-registry.ts +0 -467
- package/src/resources/extensions/gsd/namespaced-resolver.ts +0 -307
- package/src/resources/extensions/gsd/native-git-bridge.ts +0 -1197
- package/src/resources/extensions/gsd/native-parser-bridge.ts +0 -267
- package/src/resources/extensions/gsd/notifications.ts +0 -135
- package/src/resources/extensions/gsd/observability-validator.ts +0 -456
- package/src/resources/extensions/gsd/package.json +0 -11
- package/src/resources/extensions/gsd/parallel-eligibility.ts +0 -242
- package/src/resources/extensions/gsd/parallel-merge.ts +0 -240
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +0 -497
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +0 -1013
- package/src/resources/extensions/gsd/parsers-legacy.ts +0 -290
- package/src/resources/extensions/gsd/paths.ts +0 -561
- package/src/resources/extensions/gsd/plugin-importer.ts +0 -411
- package/src/resources/extensions/gsd/post-unit-hooks.ts +0 -86
- package/src/resources/extensions/gsd/preferences-models.ts +0 -330
- package/src/resources/extensions/gsd/preferences-skills.ts +0 -175
- package/src/resources/extensions/gsd/preferences-types.ts +0 -285
- package/src/resources/extensions/gsd/preferences-validation.ts +0 -823
- package/src/resources/extensions/gsd/preferences.ts +0 -539
- package/src/resources/extensions/gsd/progress-score.ts +0 -161
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +0 -213
- package/src/resources/extensions/gsd/prompt-loader.ts +0 -169
- package/src/resources/extensions/gsd/prompt-ordering.ts +0 -200
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +0 -66
- package/src/resources/extensions/gsd/prompts/complete-slice.md +0 -40
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +0 -253
- package/src/resources/extensions/gsd/prompts/discuss.md +0 -290
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +0 -29
- package/src/resources/extensions/gsd/prompts/execute-task.md +0 -80
- package/src/resources/extensions/gsd/prompts/forensics.md +0 -196
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +0 -32
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +0 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +0 -110
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +0 -62
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +0 -3
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +0 -30
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +0 -3
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +0 -15
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +0 -1
- package/src/resources/extensions/gsd/prompts/heal-skill.md +0 -45
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +0 -108
- package/src/resources/extensions/gsd/prompts/plan-slice.md +0 -89
- package/src/resources/extensions/gsd/prompts/queue.md +0 -132
- package/src/resources/extensions/gsd/prompts/quick-task.md +0 -44
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +0 -44
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +0 -66
- package/src/resources/extensions/gsd/prompts/replan-slice.md +0 -39
- package/src/resources/extensions/gsd/prompts/research-milestone.md +0 -47
- package/src/resources/extensions/gsd/prompts/research-slice.md +0 -57
- package/src/resources/extensions/gsd/prompts/rethink.md +0 -83
- package/src/resources/extensions/gsd/prompts/review-migration.md +0 -66
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +0 -31
- package/src/resources/extensions/gsd/prompts/run-uat.md +0 -89
- package/src/resources/extensions/gsd/prompts/system.md +0 -220
- package/src/resources/extensions/gsd/prompts/triage-captures.md +0 -63
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +0 -47
- package/src/resources/extensions/gsd/prompts/workflow-start.md +0 -28
- package/src/resources/extensions/gsd/prompts/worktree-merge.md +0 -123
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -49
- package/src/resources/extensions/gsd/queue-order.ts +0 -230
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +0 -277
- package/src/resources/extensions/gsd/quick.ts +0 -257
- package/src/resources/extensions/gsd/reactive-graph.ts +0 -319
- package/src/resources/extensions/gsd/repo-identity.ts +0 -657
- package/src/resources/extensions/gsd/reports.ts +0 -504
- package/src/resources/extensions/gsd/rethink.ts +0 -160
- package/src/resources/extensions/gsd/roadmap-mutations.ts +0 -134
- package/src/resources/extensions/gsd/roadmap-slices.ts +0 -273
- package/src/resources/extensions/gsd/routing-history.ts +0 -286
- package/src/resources/extensions/gsd/rtk-status.ts +0 -53
- package/src/resources/extensions/gsd/rule-registry.ts +0 -598
- package/src/resources/extensions/gsd/rule-types.ts +0 -68
- package/src/resources/extensions/gsd/run-manager.ts +0 -180
- package/src/resources/extensions/gsd/safe-fs.ts +0 -47
- package/src/resources/extensions/gsd/service-tier.ts +0 -196
- package/src/resources/extensions/gsd/session-forensics.ts +0 -546
- package/src/resources/extensions/gsd/session-lock.ts +0 -640
- package/src/resources/extensions/gsd/session-status-io.ts +0 -179
- package/src/resources/extensions/gsd/skill-catalog.ts +0 -1085
- package/src/resources/extensions/gsd/skill-discovery.ts +0 -140
- package/src/resources/extensions/gsd/skill-health.ts +0 -418
- package/src/resources/extensions/gsd/skill-telemetry.ts +0 -137
- package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +0 -242
- package/src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +0 -83
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +0 -64
- package/src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +0 -176
- package/src/resources/extensions/gsd/state.ts +0 -1554
- package/src/resources/extensions/gsd/status-guards.ts +0 -13
- package/src/resources/extensions/gsd/structured-data-formatter.ts +0 -146
- package/src/resources/extensions/gsd/sync-lock.ts +0 -94
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +0 -80
- package/src/resources/extensions/gsd/templates/context.md +0 -76
- package/src/resources/extensions/gsd/templates/decisions.md +0 -8
- package/src/resources/extensions/gsd/templates/knowledge.md +0 -19
- package/src/resources/extensions/gsd/templates/milestone-summary.md +0 -81
- package/src/resources/extensions/gsd/templates/milestone-validation.md +0 -74
- package/src/resources/extensions/gsd/templates/plan.md +0 -148
- package/src/resources/extensions/gsd/templates/project.md +0 -31
- package/src/resources/extensions/gsd/templates/reassessment.md +0 -29
- package/src/resources/extensions/gsd/templates/requirements.md +0 -81
- package/src/resources/extensions/gsd/templates/research.md +0 -79
- package/src/resources/extensions/gsd/templates/roadmap.md +0 -131
- package/src/resources/extensions/gsd/templates/runtime.md +0 -21
- package/src/resources/extensions/gsd/templates/secrets-manifest.md +0 -22
- package/src/resources/extensions/gsd/templates/slice-context.md +0 -58
- package/src/resources/extensions/gsd/templates/slice-summary.md +0 -108
- package/src/resources/extensions/gsd/templates/state.md +0 -17
- package/src/resources/extensions/gsd/templates/task-plan.md +0 -87
- package/src/resources/extensions/gsd/templates/task-summary.md +0 -66
- package/src/resources/extensions/gsd/templates/uat.md +0 -54
- package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +0 -91
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +0 -175
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +0 -143
- package/src/resources/extensions/gsd/tests/atomic-write.test.ts +0 -144
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +0 -50
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +0 -211
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +0 -213
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +0 -2307
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +0 -61
- package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +0 -71
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +0 -209
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +0 -129
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +0 -88
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +0 -255
- package/src/resources/extensions/gsd/tests/auto-stale-lock-self-kill.test.ts +0 -87
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +0 -37
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -28
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +0 -218
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +0 -80
- package/src/resources/extensions/gsd/tests/autocomplete-regressions-1675.test.ts +0 -83
- package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -133
- package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +0 -220
- package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +0 -180
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +0 -294
- package/src/resources/extensions/gsd/tests/captures.test.ts +0 -524
- package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +0 -191
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +0 -350
- package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/cmux.test.ts +0 -215
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +0 -506
- package/src/resources/extensions/gsd/tests/collision-diagnostics.test.ts +0 -705
- package/src/resources/extensions/gsd/tests/commands-config.test.ts +0 -24
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +0 -46
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +0 -241
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +0 -283
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +0 -311
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +0 -432
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +0 -106
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +0 -454
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +0 -111
- package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +0 -192
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +0 -181
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +0 -352
- package/src/resources/extensions/gsd/tests/context-injector.test.ts +0 -313
- package/src/resources/extensions/gsd/tests/context-store.test.ts +0 -454
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +0 -120
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +0 -122
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -535
- package/src/resources/extensions/gsd/tests/custom-verification.test.ts +0 -415
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +0 -339
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +0 -329
- package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +0 -87
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +0 -131
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +0 -656
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +0 -185
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +0 -762
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +0 -512
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +0 -121
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +0 -1127
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +0 -641
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +0 -310
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +0 -982
- package/src/resources/extensions/gsd/tests/detection.test.ts +0 -1190
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +0 -314
- package/src/resources/extensions/gsd/tests/diff-context.test.ts +0 -136
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +0 -15
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +0 -281
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -265
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +0 -126
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +0 -172
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +0 -603
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +0 -97
- package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +0 -169
- package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +0 -20
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -74
- package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +0 -271
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +0 -164
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +0 -120
- package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +0 -140
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +0 -101
- package/src/resources/extensions/gsd/tests/export-html-all.test.ts +0 -105
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +0 -379
- package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +0 -144
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +0 -18
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +0 -278
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -129
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +0 -121
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +0 -43
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +0 -232
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +0 -189
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +0 -156
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +0 -593
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +0 -351
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +0 -114
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +0 -440
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +0 -406
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +0 -164
- package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +0 -135
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +0 -97
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +0 -340
- package/src/resources/extensions/gsd/tests/headless-query.test.ts +0 -184
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +0 -179
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +0 -98
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
- package/src/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +0 -32
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +0 -129
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +0 -195
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +0 -248
- package/src/resources/extensions/gsd/tests/integration/atomic-task-closeout.test.ts +0 -72
- package/src/resources/extensions/gsd/tests/integration/auto-preflight.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +0 -825
- package/src/resources/extensions/gsd/tests/integration/auto-secrets-gate.test.ts +0 -194
- package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +0 -121
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +0 -759
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +0 -348
- package/src/resources/extensions/gsd/tests/integration/continue-here.test.ts +0 -281
- package/src/resources/extensions/gsd/tests/integration/doctor-completion-deferral.test.ts +0 -88
- package/src/resources/extensions/gsd/tests/integration/doctor-delimiter-fix.test.ts +0 -83
- package/src/resources/extensions/gsd/tests/integration/doctor-enhancements.test.ts +0 -243
- package/src/resources/extensions/gsd/tests/integration/doctor-environment-worktree.test.ts +0 -164
- package/src/resources/extensions/gsd/tests/integration/doctor-environment.test.ts +0 -403
- package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +0 -243
- package/src/resources/extensions/gsd/tests/integration/doctor-fixlevel.test.ts +0 -212
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +0 -653
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +0 -325
- package/src/resources/extensions/gsd/tests/integration/doctor-roadmap-summary-atomicity.test.ts +0 -123
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +0 -377
- package/src/resources/extensions/gsd/tests/integration/doctor.test.ts +0 -612
- package/src/resources/extensions/gsd/tests/integration/e2e-workflow-pipeline-integration.test.ts +0 -476
- package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +0 -415
- package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +0 -119
- package/src/resources/extensions/gsd/tests/integration/git-self-heal.test.ts +0 -131
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +0 -1458
- package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +0 -150
- package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +0 -256
- package/src/resources/extensions/gsd/tests/integration/headless-command.ts +0 -534
- package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +0 -359
- package/src/resources/extensions/gsd/tests/integration/inherited-repo-home-dir.test.ts +0 -191
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +0 -266
- package/src/resources/extensions/gsd/tests/integration/integration-mixed-milestones.test.ts +0 -539
- package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +0 -634
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +0 -360
- package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -166
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +0 -577
- package/src/resources/extensions/gsd/tests/integration/parallel-workers-multi-milestone-e2e.test.ts +0 -337
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +0 -98
- package/src/resources/extensions/gsd/tests/integration/plugin-importer-live.test.ts +0 -481
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +0 -155
- package/src/resources/extensions/gsd/tests/integration/queue-reorder-e2e.test.ts +0 -335
- package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +0 -253
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +0 -609
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +0 -959
- package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +0 -364
- package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +0 -237
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +0 -223
- package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +0 -119
- package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +0 -429
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -601
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +0 -147
- package/src/resources/extensions/gsd/tests/journal.test.ts +0 -341
- package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +0 -183
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +0 -429
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +0 -250
- package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +0 -15
- package/src/resources/extensions/gsd/tests/manifest-status.test.ts +0 -274
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +0 -1161
- package/src/resources/extensions/gsd/tests/marketplace-test-fixtures.ts +0 -91
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +0 -416
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +0 -254
- package/src/resources/extensions/gsd/tests/memory-leak-guards.test.ts +0 -91
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +0 -332
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +0 -66
- package/src/resources/extensions/gsd/tests/metrics.test.ts +0 -384
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +0 -105
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +0 -429
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +0 -748
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +0 -619
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +0 -390
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +0 -295
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +0 -361
- package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +0 -51
- package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +0 -140
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +0 -130
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/model-router.test.ts +0 -272
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +0 -220
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +0 -278
- package/src/resources/extensions/gsd/tests/namespaced-registry.test.ts +0 -1027
- package/src/resources/extensions/gsd/tests/namespaced-resolver.test.ts +0 -671
- package/src/resources/extensions/gsd/tests/native-has-changes-cache.test.ts +0 -61
- package/src/resources/extensions/gsd/tests/next-milestone-id.test.ts +0 -23
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +0 -152
- package/src/resources/extensions/gsd/tests/notifications.test.ts +0 -134
- package/src/resources/extensions/gsd/tests/overrides.test.ts +0 -124
- package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -330
- package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -284
- package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +0 -150
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +0 -60
- package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +0 -736
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +0 -277
- package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +0 -226
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -199
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +0 -85
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +0 -253
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +0 -354
- package/src/resources/extensions/gsd/tests/parsers.test.ts +0 -1867
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/plan-milestone-queue-context.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +0 -70
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +0 -231
- package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +0 -474
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +0 -298
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +0 -179
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +0 -145
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +0 -305
- package/src/resources/extensions/gsd/tests/plugin-importer.test.ts +0 -1383
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +0 -171
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +0 -300
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +0 -133
- package/src/resources/extensions/gsd/tests/preferences.test.ts +0 -463
- package/src/resources/extensions/gsd/tests/preflight-context-draft-filter.test.ts +0 -115
- package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +0 -297
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +0 -174
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +0 -464
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +0 -314
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +0 -239
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +0 -387
- package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +0 -178
- package/src/resources/extensions/gsd/tests/prompt-ordering.test.ts +0 -296
- package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +0 -69
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +0 -479
- package/src/resources/extensions/gsd/tests/quality-gates.test.ts +0 -347
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +0 -100
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +0 -192
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +0 -100
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +0 -90
- package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +0 -90
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +0 -511
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +0 -299
- package/src/resources/extensions/gsd/tests/reassess-detection.test.ts +0 -154
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +0 -442
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +0 -135
- package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +0 -176
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +0 -281
- package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +0 -59
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +0 -110
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +0 -755
- package/src/resources/extensions/gsd/tests/remote-status.test.ts +0 -99
- package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +0 -155
- package/src/resources/extensions/gsd/tests/reopen-task.test.ts +0 -165
- package/src/resources/extensions/gsd/tests/replan-handler.test.ts +0 -410
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +0 -606
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +0 -231
- package/src/resources/extensions/gsd/tests/requirements.test.ts +0 -101
- package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
- package/src/resources/extensions/gsd/tests/retry-diagnostic-reasoning.test.ts +0 -161
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +0 -305
- package/src/resources/extensions/gsd/tests/rewrite-count-persist.test.ts +0 -82
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +0 -399
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +0 -395
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +0 -296
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +0 -229
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +0 -411
- package/src/resources/extensions/gsd/tests/run-manager.test.ts +0 -229
- package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +0 -176
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +0 -319
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +0 -166
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +0 -315
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +0 -224
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +0 -209
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +0 -181
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +0 -233
- package/src/resources/extensions/gsd/tests/skill-catalog.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +0 -126
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +0 -233
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +0 -53
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +0 -123
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +0 -65
- package/src/resources/extensions/gsd/tests/stale-milestone-id-reservation.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +0 -139
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +0 -100
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +0 -125
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +0 -305
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +0 -405
- package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +0 -257
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +0 -1628
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +0 -30
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +0 -67
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +0 -106
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +0 -158
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +0 -366
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +0 -174
- package/src/resources/extensions/gsd/tests/subagent-agent-discovery.test.ts +0 -44
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +0 -221
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +0 -108
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +0 -145
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +0 -122
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +0 -84
- package/src/resources/extensions/gsd/tests/test-utils.ts +0 -165
- package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +0 -118
- package/src/resources/extensions/gsd/tests/token-counter.test.ts +0 -129
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +0 -268
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +0 -166
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +0 -125
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +0 -345
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +0 -563
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +0 -289
- package/src/resources/extensions/gsd/tests/unborn-branch.test.ts +0 -85
- package/src/resources/extensions/gsd/tests/undo.test.ts +0 -462
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +0 -203
- package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +0 -258
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +0 -257
- package/src/resources/extensions/gsd/tests/update-command.test.ts +0 -67
- package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +0 -115
- package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +0 -154
- package/src/resources/extensions/gsd/tests/validate-directory.test.ts +0 -237
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +0 -115
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +0 -393
- package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +0 -166
- package/src/resources/extensions/gsd/tests/validation.test.ts +0 -72
- package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +0 -156
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +0 -601
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +0 -999
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +0 -82
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +0 -143
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +0 -444
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +0 -235
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +0 -716
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +0 -97
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +0 -146
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +0 -205
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +0 -403
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +0 -278
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +0 -173
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +0 -171
- package/src/resources/extensions/gsd/tests/workspace-index.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +0 -117
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -202
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +0 -140
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +0 -175
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +0 -445
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +0 -142
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +0 -181
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +0 -200
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +0 -220
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +0 -238
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +0 -101
- package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +0 -165
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +0 -155
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -962
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +0 -65
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +0 -133
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +0 -617
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +0 -204
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +0 -206
- package/src/resources/extensions/gsd/tests/worktree.test.ts +0 -279
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/write-intercept.test.ts +0 -76
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +0 -95
- package/src/resources/extensions/gsd/token-counter.ts +0 -65
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +0 -229
- package/src/resources/extensions/gsd/tools/complete-slice.ts +0 -340
- package/src/resources/extensions/gsd/tools/complete-task.ts +0 -257
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +0 -304
- package/src/resources/extensions/gsd/tools/plan-slice.ts +0 -250
- package/src/resources/extensions/gsd/tools/plan-task.ts +0 -152
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +0 -288
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +0 -126
- package/src/resources/extensions/gsd/tools/reopen-task.ts +0 -130
- package/src/resources/extensions/gsd/tools/replan-slice.ts +0 -243
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +0 -156
- package/src/resources/extensions/gsd/triage-resolution.ts +0 -413
- package/src/resources/extensions/gsd/triage-ui.ts +0 -187
- package/src/resources/extensions/gsd/types.ts +0 -593
- package/src/resources/extensions/gsd/undo.ts +0 -464
- package/src/resources/extensions/gsd/unit-id.ts +0 -14
- package/src/resources/extensions/gsd/unit-ownership.ts +0 -275
- package/src/resources/extensions/gsd/unit-runtime.ts +0 -189
- package/src/resources/extensions/gsd/validate-directory.ts +0 -164
- package/src/resources/extensions/gsd/validation.ts +0 -23
- package/src/resources/extensions/gsd/verdict-parser.ts +0 -110
- package/src/resources/extensions/gsd/verification-evidence.ts +0 -202
- package/src/resources/extensions/gsd/verification-gate.ts +0 -634
- package/src/resources/extensions/gsd/visualizer-data.ts +0 -953
- package/src/resources/extensions/gsd/visualizer-overlay.ts +0 -566
- package/src/resources/extensions/gsd/visualizer-views.ts +0 -1229
- package/src/resources/extensions/gsd/workflow-engine.ts +0 -38
- package/src/resources/extensions/gsd/workflow-events.ts +0 -154
- package/src/resources/extensions/gsd/workflow-logger.ts +0 -244
- package/src/resources/extensions/gsd/workflow-manifest.ts +0 -351
- package/src/resources/extensions/gsd/workflow-migration.ts +0 -345
- package/src/resources/extensions/gsd/workflow-projections.ts +0 -458
- package/src/resources/extensions/gsd/workflow-reconcile.ts +0 -532
- package/src/resources/extensions/gsd/workflow-templates/bugfix.md +0 -87
- package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +0 -74
- package/src/resources/extensions/gsd/workflow-templates/full-project.md +0 -40
- package/src/resources/extensions/gsd/workflow-templates/hotfix.md +0 -45
- package/src/resources/extensions/gsd/workflow-templates/refactor.md +0 -83
- package/src/resources/extensions/gsd/workflow-templates/registry.json +0 -85
- package/src/resources/extensions/gsd/workflow-templates/security-audit.md +0 -73
- package/src/resources/extensions/gsd/workflow-templates/small-feature.md +0 -81
- package/src/resources/extensions/gsd/workflow-templates/spike.md +0 -69
- package/src/resources/extensions/gsd/workflow-templates.ts +0 -252
- package/src/resources/extensions/gsd/workspace-index.ts +0 -272
- package/src/resources/extensions/gsd/worktree-command-bootstrap.ts +0 -46
- package/src/resources/extensions/gsd/worktree-command.ts +0 -846
- package/src/resources/extensions/gsd/worktree-health.ts +0 -178
- package/src/resources/extensions/gsd/worktree-manager.ts +0 -630
- package/src/resources/extensions/gsd/worktree-resolver.ts +0 -640
- package/src/resources/extensions/gsd/worktree.ts +0 -336
- package/src/resources/extensions/gsd/write-intercept.ts +0 -90
|
@@ -1,2307 +0,0 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
import { resolve } from "node:path";
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
resolveAgentEnd,
|
|
8
|
-
resolveAgentEndCancelled,
|
|
9
|
-
runUnit,
|
|
10
|
-
autoLoop,
|
|
11
|
-
detectStuck,
|
|
12
|
-
_resetPendingResolve,
|
|
13
|
-
_setActiveSession,
|
|
14
|
-
isSessionSwitchInFlight,
|
|
15
|
-
type UnitResult,
|
|
16
|
-
type AgentEndEvent,
|
|
17
|
-
type LoopDeps,
|
|
18
|
-
} from "../auto-loop.js";
|
|
19
|
-
import type { SessionLockStatus } from "../session-lock.js";
|
|
20
|
-
|
|
21
|
-
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
function makeEvent(
|
|
24
|
-
messages: unknown[] = [{ role: "assistant" }],
|
|
25
|
-
): AgentEndEvent {
|
|
26
|
-
return { messages };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Build a minimal mock AutoSession with controllable newSession behavior.
|
|
31
|
-
*/
|
|
32
|
-
function makeMockSession(opts?: {
|
|
33
|
-
newSessionResult?: { cancelled: boolean };
|
|
34
|
-
newSessionThrows?: string;
|
|
35
|
-
newSessionDelayMs?: number;
|
|
36
|
-
onNewSessionStart?: (session: any) => void;
|
|
37
|
-
onNewSessionSettle?: (session: any) => void;
|
|
38
|
-
}) {
|
|
39
|
-
const session = {
|
|
40
|
-
active: true,
|
|
41
|
-
verbose: false,
|
|
42
|
-
cmdCtx: {
|
|
43
|
-
newSession: () => {
|
|
44
|
-
opts?.onNewSessionStart?.(session);
|
|
45
|
-
if (opts?.newSessionThrows) {
|
|
46
|
-
return Promise.reject(new Error(opts.newSessionThrows));
|
|
47
|
-
}
|
|
48
|
-
const result = opts?.newSessionResult ?? { cancelled: false };
|
|
49
|
-
const delay = opts?.newSessionDelayMs ?? 0;
|
|
50
|
-
if (delay > 0) {
|
|
51
|
-
return new Promise<{ cancelled: boolean }>((res) =>
|
|
52
|
-
setTimeout(() => {
|
|
53
|
-
opts?.onNewSessionSettle?.(session);
|
|
54
|
-
res(result);
|
|
55
|
-
}, delay),
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
opts?.onNewSessionSettle?.(session);
|
|
59
|
-
return Promise.resolve(result);
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
clearTimers: () => {},
|
|
63
|
-
} as any;
|
|
64
|
-
return session;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Build a minimal mock ExtensionContext.
|
|
69
|
-
*/
|
|
70
|
-
function makeMockCtx() {
|
|
71
|
-
return {
|
|
72
|
-
ui: { notify: () => {} },
|
|
73
|
-
model: { id: "test-model" },
|
|
74
|
-
} as any;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Build a minimal mock ExtensionAPI that records sendMessage calls.
|
|
79
|
-
*/
|
|
80
|
-
function makeMockPi() {
|
|
81
|
-
const calls: unknown[] = [];
|
|
82
|
-
const setModelCalls: unknown[] = [];
|
|
83
|
-
return {
|
|
84
|
-
sendMessage: (...args: unknown[]) => {
|
|
85
|
-
calls.push(args);
|
|
86
|
-
},
|
|
87
|
-
setModel: async (...args: unknown[]) => {
|
|
88
|
-
setModelCalls.push(args);
|
|
89
|
-
return true;
|
|
90
|
-
},
|
|
91
|
-
calls,
|
|
92
|
-
setModelCalls,
|
|
93
|
-
} as any;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
97
|
-
|
|
98
|
-
test("resolveAgentEnd resolves a pending runUnit promise", async () => {
|
|
99
|
-
_resetPendingResolve();
|
|
100
|
-
|
|
101
|
-
const ctx = makeMockCtx();
|
|
102
|
-
const pi = makeMockPi();
|
|
103
|
-
const s = makeMockSession();
|
|
104
|
-
const event = makeEvent();
|
|
105
|
-
|
|
106
|
-
// Start runUnit — it will create the promise and send a message,
|
|
107
|
-
// then block awaiting agent_end
|
|
108
|
-
const resultPromise = runUnit(
|
|
109
|
-
ctx,
|
|
110
|
-
pi,
|
|
111
|
-
s,
|
|
112
|
-
"task",
|
|
113
|
-
"T01",
|
|
114
|
-
"do stuff",
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
// Give the microtask queue a tick so runUnit reaches the await
|
|
118
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
119
|
-
|
|
120
|
-
// Now resolve the agent_end
|
|
121
|
-
resolveAgentEnd(event);
|
|
122
|
-
|
|
123
|
-
const result = await resultPromise;
|
|
124
|
-
assert.equal(result.status, "completed");
|
|
125
|
-
assert.deepEqual(result.event, event);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test("resolveAgentEnd drops event when no promise is pending", () => {
|
|
129
|
-
_resetPendingResolve();
|
|
130
|
-
|
|
131
|
-
// Should not throw — event is dropped (logged as warning)
|
|
132
|
-
assert.doesNotThrow(() => {
|
|
133
|
-
resolveAgentEnd(makeEvent());
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("double resolveAgentEnd only resolves once (second is dropped)", async () => {
|
|
138
|
-
_resetPendingResolve();
|
|
139
|
-
|
|
140
|
-
const ctx = makeMockCtx();
|
|
141
|
-
const pi = makeMockPi();
|
|
142
|
-
const s = makeMockSession();
|
|
143
|
-
const event1 = makeEvent([{ id: 1 }]);
|
|
144
|
-
const event2 = makeEvent([{ id: 2 }]);
|
|
145
|
-
|
|
146
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
147
|
-
|
|
148
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
149
|
-
|
|
150
|
-
// First resolve — should work
|
|
151
|
-
resolveAgentEnd(event1);
|
|
152
|
-
|
|
153
|
-
// Second resolve — should be dropped (no pending resolver)
|
|
154
|
-
assert.doesNotThrow(() => {
|
|
155
|
-
resolveAgentEnd(event2);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const result = await resultPromise;
|
|
159
|
-
assert.equal(result.status, "completed");
|
|
160
|
-
// Should have the first event, not the second
|
|
161
|
-
assert.deepEqual(result.event, event1);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("runUnit returns cancelled when session creation fails", async () => {
|
|
165
|
-
_resetPendingResolve();
|
|
166
|
-
|
|
167
|
-
const ctx = makeMockCtx();
|
|
168
|
-
const pi = makeMockPi();
|
|
169
|
-
const s = makeMockSession({ newSessionThrows: "connection refused" });
|
|
170
|
-
|
|
171
|
-
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
172
|
-
|
|
173
|
-
assert.equal(result.status, "cancelled");
|
|
174
|
-
assert.equal(result.event, undefined);
|
|
175
|
-
// sendMessage should NOT have been called
|
|
176
|
-
assert.equal(pi.calls.length, 0);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test("runUnit returns cancelled when session creation times out", async () => {
|
|
180
|
-
_resetPendingResolve();
|
|
181
|
-
|
|
182
|
-
const ctx = makeMockCtx();
|
|
183
|
-
const pi = makeMockPi();
|
|
184
|
-
// Session returns cancelled: true (simulates the timeout race outcome)
|
|
185
|
-
const s = makeMockSession({ newSessionResult: { cancelled: true } });
|
|
186
|
-
|
|
187
|
-
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
188
|
-
|
|
189
|
-
assert.equal(result.status, "cancelled");
|
|
190
|
-
assert.equal(result.event, undefined);
|
|
191
|
-
assert.equal(pi.calls.length, 0);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
test("runUnit returns cancelled when s.active is false before sendMessage", async () => {
|
|
195
|
-
_resetPendingResolve();
|
|
196
|
-
|
|
197
|
-
const ctx = makeMockCtx();
|
|
198
|
-
const pi = makeMockPi();
|
|
199
|
-
const s = makeMockSession();
|
|
200
|
-
s.active = false;
|
|
201
|
-
|
|
202
|
-
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
203
|
-
|
|
204
|
-
assert.equal(result.status, "cancelled");
|
|
205
|
-
assert.equal(pi.calls.length, 0);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
test("runUnit only arms resolve after newSession completes", async () => {
|
|
209
|
-
_resetPendingResolve();
|
|
210
|
-
|
|
211
|
-
let sawSwitchFlag = false;
|
|
212
|
-
|
|
213
|
-
const ctx = makeMockCtx();
|
|
214
|
-
const pi = makeMockPi();
|
|
215
|
-
const s = makeMockSession({
|
|
216
|
-
newSessionDelayMs: 20,
|
|
217
|
-
onNewSessionStart: () => {
|
|
218
|
-
sawSwitchFlag = isSessionSwitchInFlight();
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
223
|
-
|
|
224
|
-
await new Promise((r) => setTimeout(r, 30));
|
|
225
|
-
|
|
226
|
-
assert.equal(sawSwitchFlag, true, "session switch guard should be active during newSession");
|
|
227
|
-
assert.equal(isSessionSwitchInFlight(), false, "session switch guard should clear after newSession settles");
|
|
228
|
-
|
|
229
|
-
resolveAgentEnd(makeEvent());
|
|
230
|
-
|
|
231
|
-
const result = await resultPromise;
|
|
232
|
-
assert.equal(result.status, "completed");
|
|
233
|
-
assert.equal(pi.calls.length, 1);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test("runUnit re-applies the selected unit model after newSession before dispatch", async () => {
|
|
237
|
-
_resetPendingResolve();
|
|
238
|
-
|
|
239
|
-
const callOrder: string[] = [];
|
|
240
|
-
const ctx = makeMockCtx();
|
|
241
|
-
const pi = makeMockPi();
|
|
242
|
-
pi.setModel = async (...args: unknown[]) => {
|
|
243
|
-
callOrder.push("setModel");
|
|
244
|
-
pi.setModelCalls.push(args);
|
|
245
|
-
return true;
|
|
246
|
-
};
|
|
247
|
-
pi.sendMessage = (...args: unknown[]) => {
|
|
248
|
-
callOrder.push("sendMessage");
|
|
249
|
-
pi.calls.push(args);
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const s = makeMockSession();
|
|
253
|
-
s.currentUnitModel = { provider: "anthropic", id: "claude-opus-4-6" };
|
|
254
|
-
|
|
255
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
256
|
-
|
|
257
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
258
|
-
resolveAgentEnd(makeEvent());
|
|
259
|
-
|
|
260
|
-
const result = await resultPromise;
|
|
261
|
-
assert.equal(result.status, "completed");
|
|
262
|
-
assert.deepEqual(callOrder, ["setModel", "sendMessage"]);
|
|
263
|
-
assert.equal(pi.setModelCalls.length, 1);
|
|
264
|
-
assert.deepEqual(pi.setModelCalls[0][0], s.currentUnitModel);
|
|
265
|
-
assert.equal(pi.calls.length, 1);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// ─── Structural assertions ───────────────────────────────────────────────────
|
|
269
|
-
|
|
270
|
-
test("auto-loop.ts exports autoLoop, runUnit, resolveAgentEnd", async () => {
|
|
271
|
-
const mod = await import("../auto-loop.js");
|
|
272
|
-
assert.equal(
|
|
273
|
-
typeof mod.autoLoop,
|
|
274
|
-
"function",
|
|
275
|
-
"autoLoop should be exported as a function",
|
|
276
|
-
);
|
|
277
|
-
assert.equal(
|
|
278
|
-
typeof mod.runUnit,
|
|
279
|
-
"function",
|
|
280
|
-
"runUnit should be exported as a function",
|
|
281
|
-
);
|
|
282
|
-
assert.equal(
|
|
283
|
-
typeof mod.resolveAgentEnd,
|
|
284
|
-
"function",
|
|
285
|
-
"resolveAgentEnd should be exported as a function",
|
|
286
|
-
);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
test("auto/loop.ts contains a while keyword", () => {
|
|
290
|
-
const src = readFileSync(
|
|
291
|
-
resolve(import.meta.dirname, "..", "auto", "loop.ts"),
|
|
292
|
-
"utf-8",
|
|
293
|
-
);
|
|
294
|
-
assert.ok(
|
|
295
|
-
src.includes("while"),
|
|
296
|
-
"auto/loop.ts should contain a while keyword (loop or placeholder)",
|
|
297
|
-
);
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
test("auto/resolve.ts one-shot pattern: _currentResolve is nulled before calling resolver", () => {
|
|
301
|
-
const src = readFileSync(
|
|
302
|
-
resolve(import.meta.dirname, "..", "auto", "resolve.ts"),
|
|
303
|
-
"utf-8",
|
|
304
|
-
);
|
|
305
|
-
// The one-shot pattern requires: save ref, null the variable, then call
|
|
306
|
-
const resolveBlock = src.slice(
|
|
307
|
-
src.indexOf("export function resolveAgentEnd"),
|
|
308
|
-
src.indexOf("export function resolveAgentEnd") + 600,
|
|
309
|
-
);
|
|
310
|
-
const nullIdx = resolveBlock.indexOf("_currentResolve = null");
|
|
311
|
-
const callIdx = resolveBlock.indexOf("r({");
|
|
312
|
-
assert.ok(nullIdx > 0, "should null _currentResolve in resolveAgentEnd");
|
|
313
|
-
assert.ok(callIdx > 0, "should call resolver in resolveAgentEnd");
|
|
314
|
-
assert.ok(
|
|
315
|
-
nullIdx < callIdx,
|
|
316
|
-
"_currentResolve should be nulled before calling the resolver (one-shot)",
|
|
317
|
-
);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
test("auto/phases.ts: selectAndApplyModel called exactly once and before updateProgressWidget (#2907)", () => {
|
|
321
|
-
const src = readFileSync(
|
|
322
|
-
resolve(import.meta.dirname, "..", "auto", "phases.ts"),
|
|
323
|
-
"utf-8",
|
|
324
|
-
);
|
|
325
|
-
// Extract the runUnitPhase function body
|
|
326
|
-
const fnStart = src.indexOf("export async function runUnitPhase");
|
|
327
|
-
assert.ok(fnStart > 0, "runUnitPhase should exist in phases.ts");
|
|
328
|
-
const fnBody = src.slice(fnStart, fnStart + 8000);
|
|
329
|
-
|
|
330
|
-
// selectAndApplyModel must appear exactly once
|
|
331
|
-
const allOccurrences = [...fnBody.matchAll(/selectAndApplyModel\(/g)];
|
|
332
|
-
assert.equal(
|
|
333
|
-
allOccurrences.length,
|
|
334
|
-
1,
|
|
335
|
-
`selectAndApplyModel should be called exactly once in runUnitPhase, found ${allOccurrences.length} calls`,
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
// selectAndApplyModel must appear BEFORE updateProgressWidget
|
|
339
|
-
const modelIdx = fnBody.indexOf("selectAndApplyModel(");
|
|
340
|
-
const widgetIdx = fnBody.indexOf("updateProgressWidget(");
|
|
341
|
-
assert.ok(modelIdx > 0, "selectAndApplyModel should exist in runUnitPhase");
|
|
342
|
-
assert.ok(widgetIdx > 0, "updateProgressWidget should exist in runUnitPhase");
|
|
343
|
-
assert.ok(
|
|
344
|
-
modelIdx < widgetIdx,
|
|
345
|
-
"selectAndApplyModel must be called BEFORE updateProgressWidget (#2899/#2907)",
|
|
346
|
-
);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
// ─── autoLoop tests (T02) ─────────────────────────────────────────────────
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Build a mock LoopDeps that tracks call order and allows controlling
|
|
353
|
-
* behavior via overrides.
|
|
354
|
-
*/
|
|
355
|
-
function makeMockDeps(
|
|
356
|
-
overrides?: Partial<LoopDeps>,
|
|
357
|
-
): LoopDeps & { callLog: string[] } {
|
|
358
|
-
const callLog: string[] = [];
|
|
359
|
-
|
|
360
|
-
const baseDeps: LoopDeps = {
|
|
361
|
-
lockBase: () => "/tmp/test-lock",
|
|
362
|
-
buildSnapshotOpts: () => ({}),
|
|
363
|
-
stopAuto: async () => {
|
|
364
|
-
callLog.push("stopAuto");
|
|
365
|
-
},
|
|
366
|
-
pauseAuto: async () => {
|
|
367
|
-
callLog.push("pauseAuto");
|
|
368
|
-
},
|
|
369
|
-
clearUnitTimeout: () => {},
|
|
370
|
-
updateProgressWidget: () => {},
|
|
371
|
-
syncCmuxSidebar: () => {},
|
|
372
|
-
logCmuxEvent: () => {},
|
|
373
|
-
invalidateAllCaches: () => {
|
|
374
|
-
callLog.push("invalidateAllCaches");
|
|
375
|
-
},
|
|
376
|
-
deriveState: async () => {
|
|
377
|
-
callLog.push("deriveState");
|
|
378
|
-
return {
|
|
379
|
-
phase: "executing",
|
|
380
|
-
activeMilestone: {
|
|
381
|
-
id: "M001",
|
|
382
|
-
title: "Test Milestone",
|
|
383
|
-
status: "active",
|
|
384
|
-
},
|
|
385
|
-
activeSlice: { id: "S01", title: "Test Slice" },
|
|
386
|
-
activeTask: { id: "T01" },
|
|
387
|
-
registry: [{ id: "M001", status: "active" }],
|
|
388
|
-
blockers: [],
|
|
389
|
-
} as any;
|
|
390
|
-
},
|
|
391
|
-
loadEffectiveGSDPreferences: () => ({ preferences: {} }),
|
|
392
|
-
preDispatchHealthGate: async () => ({ proceed: true, fixesApplied: [] }),
|
|
393
|
-
syncProjectRootToWorktree: () => {},
|
|
394
|
-
checkResourcesStale: () => null,
|
|
395
|
-
validateSessionLock: () => ({ valid: true } as SessionLockStatus),
|
|
396
|
-
updateSessionLock: () => {
|
|
397
|
-
callLog.push("updateSessionLock");
|
|
398
|
-
},
|
|
399
|
-
handleLostSessionLock: () => {
|
|
400
|
-
callLog.push("handleLostSessionLock");
|
|
401
|
-
},
|
|
402
|
-
sendDesktopNotification: () => {},
|
|
403
|
-
setActiveMilestoneId: () => {},
|
|
404
|
-
pruneQueueOrder: () => {},
|
|
405
|
-
isInAutoWorktree: () => false,
|
|
406
|
-
shouldUseWorktreeIsolation: () => false,
|
|
407
|
-
mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: true }),
|
|
408
|
-
teardownAutoWorktree: () => {},
|
|
409
|
-
createAutoWorktree: () => "/tmp/wt",
|
|
410
|
-
captureIntegrationBranch: () => {},
|
|
411
|
-
getIsolationMode: () => "none",
|
|
412
|
-
getCurrentBranch: () => "main",
|
|
413
|
-
autoWorktreeBranch: () => "auto/M001",
|
|
414
|
-
resolveMilestoneFile: () => null,
|
|
415
|
-
reconcileMergeState: () => false,
|
|
416
|
-
getLedger: () => null,
|
|
417
|
-
getProjectTotals: () => ({ cost: 0 }),
|
|
418
|
-
formatCost: (c: number) => `$${c.toFixed(2)}`,
|
|
419
|
-
getBudgetAlertLevel: () => 0,
|
|
420
|
-
getNewBudgetAlertLevel: () => 0,
|
|
421
|
-
getBudgetEnforcementAction: () => "none",
|
|
422
|
-
getManifestStatus: async () => null,
|
|
423
|
-
collectSecretsFromManifest: async () => null,
|
|
424
|
-
resolveDispatch: async () => {
|
|
425
|
-
callLog.push("resolveDispatch");
|
|
426
|
-
return {
|
|
427
|
-
action: "dispatch" as const,
|
|
428
|
-
unitType: "execute-task",
|
|
429
|
-
unitId: "M001/S01/T01",
|
|
430
|
-
prompt: "do the thing",
|
|
431
|
-
};
|
|
432
|
-
},
|
|
433
|
-
runPreDispatchHooks: () => ({ firedHooks: [], action: "proceed" }),
|
|
434
|
-
getPriorSliceCompletionBlocker: () => null,
|
|
435
|
-
getMainBranch: () => "main",
|
|
436
|
-
closeoutUnit: async () => {},
|
|
437
|
-
recordOutcome: () => {},
|
|
438
|
-
writeLock: () => {},
|
|
439
|
-
captureAvailableSkills: () => {},
|
|
440
|
-
ensurePreconditions: () => {},
|
|
441
|
-
updateSliceProgressCache: () => {},
|
|
442
|
-
selectAndApplyModel: async () => ({ routing: null, appliedModel: null }),
|
|
443
|
-
startUnitSupervision: () => {},
|
|
444
|
-
getDeepDiagnostic: () => null,
|
|
445
|
-
isDbAvailable: () => false,
|
|
446
|
-
reorderForCaching: (p: string) => p,
|
|
447
|
-
existsSync: (p: string) => p.endsWith(".git") || p.endsWith("package.json"),
|
|
448
|
-
readFileSync: () => "",
|
|
449
|
-
atomicWriteSync: () => {},
|
|
450
|
-
GitServiceImpl: class {} as any,
|
|
451
|
-
resolver: {
|
|
452
|
-
get workPath() {
|
|
453
|
-
return "/tmp/project";
|
|
454
|
-
},
|
|
455
|
-
get projectRoot() {
|
|
456
|
-
return "/tmp/project";
|
|
457
|
-
},
|
|
458
|
-
get lockPath() {
|
|
459
|
-
return "/tmp/project";
|
|
460
|
-
},
|
|
461
|
-
enterMilestone: () => {},
|
|
462
|
-
exitMilestone: () => {},
|
|
463
|
-
mergeAndExit: () => {},
|
|
464
|
-
mergeAndEnterNext: () => {},
|
|
465
|
-
} as any,
|
|
466
|
-
postUnitPreVerification: async () => {
|
|
467
|
-
callLog.push("postUnitPreVerification");
|
|
468
|
-
return "continue" as const;
|
|
469
|
-
},
|
|
470
|
-
runPostUnitVerification: async () => {
|
|
471
|
-
callLog.push("runPostUnitVerification");
|
|
472
|
-
return "continue" as const;
|
|
473
|
-
},
|
|
474
|
-
postUnitPostVerification: async () => {
|
|
475
|
-
callLog.push("postUnitPostVerification");
|
|
476
|
-
return "continue" as const;
|
|
477
|
-
},
|
|
478
|
-
getSessionFile: () => "/tmp/session.json",
|
|
479
|
-
rebuildState: async () => {},
|
|
480
|
-
resolveModelId: (id: string, models: any[]) => models.find((m: any) => m.id === id),
|
|
481
|
-
emitJournalEvent: () => {},
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
const merged = { ...baseDeps, ...overrides, callLog };
|
|
485
|
-
return merged;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Build a mock session for autoLoop testing — needs more fields than the
|
|
490
|
-
* runUnit mock (dispatch counters, milestone state, etc.).
|
|
491
|
-
*/
|
|
492
|
-
function makeLoopSession(overrides?: Partial<Record<string, unknown>>) {
|
|
493
|
-
return {
|
|
494
|
-
active: true,
|
|
495
|
-
verbose: false,
|
|
496
|
-
stepMode: false,
|
|
497
|
-
paused: false,
|
|
498
|
-
basePath: "/tmp/project",
|
|
499
|
-
originalBasePath: "",
|
|
500
|
-
currentMilestoneId: "M001",
|
|
501
|
-
currentUnit: null,
|
|
502
|
-
currentUnitRouting: null,
|
|
503
|
-
completedUnits: [],
|
|
504
|
-
resourceVersionOnStart: null,
|
|
505
|
-
lastPromptCharCount: undefined,
|
|
506
|
-
lastBaselineCharCount: undefined,
|
|
507
|
-
lastBudgetAlertLevel: 0,
|
|
508
|
-
pendingVerificationRetry: null,
|
|
509
|
-
pendingCrashRecovery: null,
|
|
510
|
-
pendingQuickTasks: [],
|
|
511
|
-
sidecarQueue: [],
|
|
512
|
-
autoModeStartModel: null,
|
|
513
|
-
unitDispatchCount: new Map<string, number>(),
|
|
514
|
-
unitLifetimeDispatches: new Map<string, number>(),
|
|
515
|
-
unitRecoveryCount: new Map<string, number>(),
|
|
516
|
-
verificationRetryCount: new Map<string, number>(),
|
|
517
|
-
gitService: null,
|
|
518
|
-
autoStartTime: Date.now(),
|
|
519
|
-
cmdCtx: {
|
|
520
|
-
newSession: () => Promise.resolve({ cancelled: false }),
|
|
521
|
-
getContextUsage: () => ({ percent: 10, tokens: 1000, limit: 10000 }),
|
|
522
|
-
},
|
|
523
|
-
clearTimers: () => {},
|
|
524
|
-
...overrides,
|
|
525
|
-
} as any;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
test("autoLoop exits when s.active is set to false", async (t) => {
|
|
529
|
-
_resetPendingResolve();
|
|
530
|
-
|
|
531
|
-
const ctx = makeMockCtx();
|
|
532
|
-
ctx.ui.setStatus = () => {};
|
|
533
|
-
const pi = makeMockPi();
|
|
534
|
-
const s = makeLoopSession({ active: false });
|
|
535
|
-
|
|
536
|
-
const deps = makeMockDeps();
|
|
537
|
-
await autoLoop(ctx, pi, s, deps);
|
|
538
|
-
|
|
539
|
-
// Loop body should not have executed (deriveState never called)
|
|
540
|
-
assert.ok(
|
|
541
|
-
!deps.callLog.includes("deriveState"),
|
|
542
|
-
"loop should not have iterated",
|
|
543
|
-
);
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
test("autoLoop exits on terminal complete state", async (t) => {
|
|
547
|
-
_resetPendingResolve();
|
|
548
|
-
|
|
549
|
-
const ctx = makeMockCtx();
|
|
550
|
-
ctx.ui.setStatus = () => {};
|
|
551
|
-
const pi = makeMockPi();
|
|
552
|
-
const s = makeLoopSession();
|
|
553
|
-
|
|
554
|
-
const deps = makeMockDeps({
|
|
555
|
-
deriveState: async () => {
|
|
556
|
-
deps.callLog.push("deriveState");
|
|
557
|
-
return {
|
|
558
|
-
phase: "complete",
|
|
559
|
-
activeMilestone: { id: "M001", title: "Test", status: "complete" },
|
|
560
|
-
activeSlice: null,
|
|
561
|
-
activeTask: null,
|
|
562
|
-
registry: [{ id: "M001", status: "complete" }],
|
|
563
|
-
blockers: [],
|
|
564
|
-
} as any;
|
|
565
|
-
},
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
await autoLoop(ctx, pi, s, deps);
|
|
569
|
-
|
|
570
|
-
assert.ok(deps.callLog.includes("deriveState"), "should have derived state");
|
|
571
|
-
assert.ok(
|
|
572
|
-
deps.callLog.includes("stopAuto"),
|
|
573
|
-
"should have called stopAuto for complete state",
|
|
574
|
-
);
|
|
575
|
-
// Should NOT have dispatched a unit
|
|
576
|
-
assert.ok(
|
|
577
|
-
!deps.callLog.includes("resolveDispatch"),
|
|
578
|
-
"should not dispatch when complete",
|
|
579
|
-
);
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
test("autoLoop passes structured session-lock failure details to the handler", async () => {
|
|
583
|
-
_resetPendingResolve();
|
|
584
|
-
|
|
585
|
-
const ctx = makeMockCtx();
|
|
586
|
-
ctx.ui.setStatus = () => {};
|
|
587
|
-
const pi = makeMockPi();
|
|
588
|
-
const s = makeLoopSession();
|
|
589
|
-
let observedLockStatus: SessionLockStatus | undefined;
|
|
590
|
-
|
|
591
|
-
const deps = makeMockDeps({
|
|
592
|
-
validateSessionLock: () =>
|
|
593
|
-
({
|
|
594
|
-
valid: false,
|
|
595
|
-
failureReason: "compromised",
|
|
596
|
-
expectedPid: process.pid,
|
|
597
|
-
}) as SessionLockStatus,
|
|
598
|
-
handleLostSessionLock: (_ctx, lockStatus) => {
|
|
599
|
-
observedLockStatus = lockStatus;
|
|
600
|
-
deps.callLog.push("handleLostSessionLock");
|
|
601
|
-
},
|
|
602
|
-
});
|
|
603
|
-
|
|
604
|
-
await autoLoop(ctx, pi, s, deps);
|
|
605
|
-
|
|
606
|
-
assert.deepEqual(observedLockStatus, {
|
|
607
|
-
valid: false,
|
|
608
|
-
failureReason: "compromised",
|
|
609
|
-
expectedPid: process.pid,
|
|
610
|
-
});
|
|
611
|
-
assert.ok(
|
|
612
|
-
!deps.callLog.includes("resolveDispatch"),
|
|
613
|
-
"should stop before dispatch after lock validation fails",
|
|
614
|
-
);
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
test("autoLoop exits on terminal blocked state", async (t) => {
|
|
618
|
-
_resetPendingResolve();
|
|
619
|
-
|
|
620
|
-
const ctx = makeMockCtx();
|
|
621
|
-
ctx.ui.setStatus = () => {};
|
|
622
|
-
const pi = makeMockPi();
|
|
623
|
-
const s = makeLoopSession();
|
|
624
|
-
|
|
625
|
-
const deps = makeMockDeps({
|
|
626
|
-
deriveState: async () => {
|
|
627
|
-
deps.callLog.push("deriveState");
|
|
628
|
-
return {
|
|
629
|
-
phase: "blocked",
|
|
630
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
631
|
-
activeSlice: null,
|
|
632
|
-
activeTask: null,
|
|
633
|
-
registry: [{ id: "M001", status: "active" }],
|
|
634
|
-
blockers: ["Missing API key"],
|
|
635
|
-
} as any;
|
|
636
|
-
},
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
await autoLoop(ctx, pi, s, deps);
|
|
640
|
-
|
|
641
|
-
assert.ok(deps.callLog.includes("deriveState"), "should have derived state");
|
|
642
|
-
assert.ok(
|
|
643
|
-
deps.callLog.includes("stopAuto"),
|
|
644
|
-
"should have called stopAuto for blocked state",
|
|
645
|
-
);
|
|
646
|
-
assert.ok(
|
|
647
|
-
!deps.callLog.includes("resolveDispatch"),
|
|
648
|
-
"should not dispatch when blocked",
|
|
649
|
-
);
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
test("autoLoop calls deriveState → resolveDispatch → runUnit in sequence", async (t) => {
|
|
653
|
-
_resetPendingResolve();
|
|
654
|
-
|
|
655
|
-
const ctx = makeMockCtx();
|
|
656
|
-
ctx.ui.setStatus = () => {};
|
|
657
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
658
|
-
const pi = makeMockPi();
|
|
659
|
-
|
|
660
|
-
const s = makeLoopSession();
|
|
661
|
-
|
|
662
|
-
const deps = makeMockDeps({
|
|
663
|
-
deriveState: async () => {
|
|
664
|
-
deps.callLog.push("deriveState");
|
|
665
|
-
return {
|
|
666
|
-
phase: "executing",
|
|
667
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
668
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
669
|
-
activeTask: { id: "T01" },
|
|
670
|
-
registry: [{ id: "M001", status: "active" }],
|
|
671
|
-
blockers: [],
|
|
672
|
-
} as any;
|
|
673
|
-
},
|
|
674
|
-
resolveDispatch: async () => {
|
|
675
|
-
deps.callLog.push("resolveDispatch");
|
|
676
|
-
return {
|
|
677
|
-
action: "dispatch" as const,
|
|
678
|
-
unitType: "execute-task",
|
|
679
|
-
unitId: "M001/S01/T01",
|
|
680
|
-
prompt: "do the thing",
|
|
681
|
-
};
|
|
682
|
-
},
|
|
683
|
-
postUnitPostVerification: async () => {
|
|
684
|
-
deps.callLog.push("postUnitPostVerification");
|
|
685
|
-
// Deactivate after first iteration to exit the loop
|
|
686
|
-
s.active = false;
|
|
687
|
-
return "continue" as const;
|
|
688
|
-
},
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
// Run autoLoop — it will call runUnit internally which creates a promise.
|
|
692
|
-
// We need to resolve the promise from outside via resolveAgentEnd.
|
|
693
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
694
|
-
|
|
695
|
-
// Give the loop time to reach runUnit's await
|
|
696
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
697
|
-
|
|
698
|
-
// Resolve the first unit's agent_end
|
|
699
|
-
resolveAgentEnd(makeEvent());
|
|
700
|
-
|
|
701
|
-
await loopPromise;
|
|
702
|
-
|
|
703
|
-
// Verify the sequence: deriveState → resolveDispatch → then finalize callbacks
|
|
704
|
-
const deriveIdx = deps.callLog.indexOf("deriveState");
|
|
705
|
-
const dispatchIdx = deps.callLog.indexOf("resolveDispatch");
|
|
706
|
-
const preVerIdx = deps.callLog.indexOf("postUnitPreVerification");
|
|
707
|
-
const verIdx = deps.callLog.indexOf("runPostUnitVerification");
|
|
708
|
-
const postVerIdx = deps.callLog.indexOf("postUnitPostVerification");
|
|
709
|
-
|
|
710
|
-
assert.ok(deriveIdx >= 0, "deriveState should have been called");
|
|
711
|
-
assert.ok(
|
|
712
|
-
dispatchIdx > deriveIdx,
|
|
713
|
-
"resolveDispatch should come after deriveState",
|
|
714
|
-
);
|
|
715
|
-
assert.ok(
|
|
716
|
-
preVerIdx > dispatchIdx,
|
|
717
|
-
"postUnitPreVerification should come after resolveDispatch",
|
|
718
|
-
);
|
|
719
|
-
assert.ok(
|
|
720
|
-
verIdx > preVerIdx,
|
|
721
|
-
"runPostUnitVerification should come after pre-verification",
|
|
722
|
-
);
|
|
723
|
-
assert.ok(
|
|
724
|
-
postVerIdx > verIdx,
|
|
725
|
-
"postUnitPostVerification should come after verification",
|
|
726
|
-
);
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
test("crash lock records session file from AFTER newSession, not before (#1710)", async (t) => {
|
|
730
|
-
_resetPendingResolve();
|
|
731
|
-
|
|
732
|
-
const ctx = makeMockCtx();
|
|
733
|
-
ctx.ui.setStatus = () => {};
|
|
734
|
-
|
|
735
|
-
// Simulate newSession changing the session file path.
|
|
736
|
-
// newSession() in runUnit changes the underlying session, so getSessionFile
|
|
737
|
-
// returns a different path after newSession completes.
|
|
738
|
-
let currentSessionFile = "/tmp/old-session.json";
|
|
739
|
-
ctx.sessionManager = {
|
|
740
|
-
getSessionFile: () => currentSessionFile,
|
|
741
|
-
};
|
|
742
|
-
const pi = makeMockPi();
|
|
743
|
-
|
|
744
|
-
const s = makeLoopSession({
|
|
745
|
-
cmdCtx: {
|
|
746
|
-
newSession: () => {
|
|
747
|
-
// When newSession completes, the session file changes
|
|
748
|
-
currentSessionFile = "/tmp/new-session-after-newSession.json";
|
|
749
|
-
return Promise.resolve({ cancelled: false });
|
|
750
|
-
},
|
|
751
|
-
getContextUsage: () => ({ percent: 10, tokens: 1000, limit: 10000 }),
|
|
752
|
-
},
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
// Track all writeLock calls with their sessionFile argument
|
|
756
|
-
const writeLockCalls: { sessionFile: string | undefined }[] = [];
|
|
757
|
-
const updateSessionLockCalls: { sessionFile: string | undefined }[] = [];
|
|
758
|
-
|
|
759
|
-
const deps = makeMockDeps({
|
|
760
|
-
deriveState: async () => {
|
|
761
|
-
deps.callLog.push("deriveState");
|
|
762
|
-
return {
|
|
763
|
-
phase: "executing",
|
|
764
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
765
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
766
|
-
activeTask: { id: "T01" },
|
|
767
|
-
registry: [{ id: "M001", status: "active" }],
|
|
768
|
-
blockers: [],
|
|
769
|
-
} as any;
|
|
770
|
-
},
|
|
771
|
-
resolveDispatch: async () => {
|
|
772
|
-
deps.callLog.push("resolveDispatch");
|
|
773
|
-
return {
|
|
774
|
-
action: "dispatch" as const,
|
|
775
|
-
unitType: "execute-task",
|
|
776
|
-
unitId: "M001/S01/T01",
|
|
777
|
-
prompt: "do the thing",
|
|
778
|
-
};
|
|
779
|
-
},
|
|
780
|
-
writeLock: (_base: string, _ut: string, _uid: string, sessionFile?: string) => {
|
|
781
|
-
writeLockCalls.push({ sessionFile });
|
|
782
|
-
},
|
|
783
|
-
updateSessionLock: (_base: string, _ut: string, _uid: string, sessionFile?: string) => {
|
|
784
|
-
updateSessionLockCalls.push({ sessionFile });
|
|
785
|
-
},
|
|
786
|
-
getSessionFile: (ctxArg: any) => {
|
|
787
|
-
return ctxArg.sessionManager?.getSessionFile() ?? "";
|
|
788
|
-
},
|
|
789
|
-
postUnitPostVerification: async () => {
|
|
790
|
-
deps.callLog.push("postUnitPostVerification");
|
|
791
|
-
// Deactivate after first iteration to exit the loop
|
|
792
|
-
s.active = false;
|
|
793
|
-
return "continue" as const;
|
|
794
|
-
},
|
|
795
|
-
});
|
|
796
|
-
|
|
797
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
798
|
-
|
|
799
|
-
// Give the loop time to reach runUnit's await
|
|
800
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
801
|
-
|
|
802
|
-
// Resolve the unit's agent_end
|
|
803
|
-
resolveAgentEnd(makeEvent());
|
|
804
|
-
|
|
805
|
-
await loopPromise;
|
|
806
|
-
|
|
807
|
-
// The preliminary lock (before runUnit) should have NO session file
|
|
808
|
-
assert.ok(
|
|
809
|
-
writeLockCalls.length >= 2,
|
|
810
|
-
`expected at least 2 writeLock calls, got ${writeLockCalls.length}`,
|
|
811
|
-
);
|
|
812
|
-
assert.strictEqual(
|
|
813
|
-
writeLockCalls[0].sessionFile,
|
|
814
|
-
undefined,
|
|
815
|
-
"preliminary lock before runUnit should have no session file",
|
|
816
|
-
);
|
|
817
|
-
|
|
818
|
-
// The post-runUnit lock should have the NEW session file path
|
|
819
|
-
assert.strictEqual(
|
|
820
|
-
writeLockCalls[1].sessionFile,
|
|
821
|
-
"/tmp/new-session-after-newSession.json",
|
|
822
|
-
"post-runUnit lock should record the session file created by newSession",
|
|
823
|
-
);
|
|
824
|
-
|
|
825
|
-
// updateSessionLock should also have the new session file
|
|
826
|
-
assert.ok(
|
|
827
|
-
updateSessionLockCalls.length >= 1,
|
|
828
|
-
"updateSessionLock should have been called at least once",
|
|
829
|
-
);
|
|
830
|
-
assert.strictEqual(
|
|
831
|
-
updateSessionLockCalls[0].sessionFile,
|
|
832
|
-
"/tmp/new-session-after-newSession.json",
|
|
833
|
-
"updateSessionLock should record the session file created by newSession",
|
|
834
|
-
);
|
|
835
|
-
});
|
|
836
|
-
|
|
837
|
-
test("autoLoop handles verification retry by continuing loop", async (t) => {
|
|
838
|
-
_resetPendingResolve();
|
|
839
|
-
|
|
840
|
-
const ctx = makeMockCtx();
|
|
841
|
-
ctx.ui.setStatus = () => {};
|
|
842
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
843
|
-
const pi = makeMockPi();
|
|
844
|
-
|
|
845
|
-
let verifyCallCount = 0;
|
|
846
|
-
let deriveCallCount = 0;
|
|
847
|
-
const s = makeLoopSession();
|
|
848
|
-
|
|
849
|
-
// Pre-queued verification actions: each entry provides a side-effect + return value
|
|
850
|
-
type VerifyAction = { sideEffect?: () => void; response: "retry" | "continue" };
|
|
851
|
-
const verificationActions: VerifyAction[] = [
|
|
852
|
-
{
|
|
853
|
-
sideEffect: () => {
|
|
854
|
-
// Simulate retry — set pendingVerificationRetry on session
|
|
855
|
-
s.pendingVerificationRetry = {
|
|
856
|
-
unitId: "M001/S01/T01",
|
|
857
|
-
failureContext: "test failed: expected X got Y",
|
|
858
|
-
attempt: 1,
|
|
859
|
-
};
|
|
860
|
-
},
|
|
861
|
-
response: "retry",
|
|
862
|
-
},
|
|
863
|
-
{ response: "continue" },
|
|
864
|
-
];
|
|
865
|
-
|
|
866
|
-
const deps = makeMockDeps({
|
|
867
|
-
deriveState: async () => {
|
|
868
|
-
deriveCallCount++;
|
|
869
|
-
deps.callLog.push("deriveState");
|
|
870
|
-
return {
|
|
871
|
-
phase: "executing",
|
|
872
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
873
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
874
|
-
activeTask: { id: "T01" },
|
|
875
|
-
registry: [{ id: "M001", status: "active" }],
|
|
876
|
-
blockers: [],
|
|
877
|
-
} as any;
|
|
878
|
-
},
|
|
879
|
-
runPostUnitVerification: async () => {
|
|
880
|
-
const action = verificationActions[verifyCallCount] ?? { response: "continue" as const };
|
|
881
|
-
verifyCallCount++;
|
|
882
|
-
deps.callLog.push("runPostUnitVerification");
|
|
883
|
-
action.sideEffect?.();
|
|
884
|
-
return action.response;
|
|
885
|
-
},
|
|
886
|
-
postUnitPostVerification: async () => {
|
|
887
|
-
deps.callLog.push("postUnitPostVerification");
|
|
888
|
-
// After the retry cycle completes, deactivate
|
|
889
|
-
s.active = false;
|
|
890
|
-
return "continue" as const;
|
|
891
|
-
},
|
|
892
|
-
});
|
|
893
|
-
|
|
894
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
895
|
-
|
|
896
|
-
// First iteration: runUnit → verification returns "retry" → loop continues
|
|
897
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
898
|
-
resolveAgentEnd(makeEvent()); // resolve first unit
|
|
899
|
-
|
|
900
|
-
// Second iteration: runUnit → verification returns "continue"
|
|
901
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
902
|
-
resolveAgentEnd(makeEvent()); // resolve retry unit
|
|
903
|
-
|
|
904
|
-
await loopPromise;
|
|
905
|
-
|
|
906
|
-
// Verify deriveState was called twice (two iterations)
|
|
907
|
-
const deriveCount = deps.callLog.filter((c) => c === "deriveState").length;
|
|
908
|
-
assert.ok(
|
|
909
|
-
deriveCount >= 2,
|
|
910
|
-
`deriveState should be called at least 2 times (got ${deriveCount})`,
|
|
911
|
-
);
|
|
912
|
-
|
|
913
|
-
// Verify verification was called twice
|
|
914
|
-
assert.equal(
|
|
915
|
-
verifyCallCount,
|
|
916
|
-
2,
|
|
917
|
-
"verification should have been called twice (once retry, once pass)",
|
|
918
|
-
);
|
|
919
|
-
});
|
|
920
|
-
|
|
921
|
-
test("autoLoop handles dispatch stop action", async (t) => {
|
|
922
|
-
_resetPendingResolve();
|
|
923
|
-
|
|
924
|
-
const ctx = makeMockCtx();
|
|
925
|
-
ctx.ui.setStatus = () => {};
|
|
926
|
-
const pi = makeMockPi();
|
|
927
|
-
const s = makeLoopSession();
|
|
928
|
-
|
|
929
|
-
const deps = makeMockDeps({
|
|
930
|
-
resolveDispatch: async () => {
|
|
931
|
-
deps.callLog.push("resolveDispatch");
|
|
932
|
-
return {
|
|
933
|
-
action: "stop" as const,
|
|
934
|
-
reason: "test-stop-reason",
|
|
935
|
-
level: "info" as const,
|
|
936
|
-
};
|
|
937
|
-
},
|
|
938
|
-
});
|
|
939
|
-
|
|
940
|
-
await autoLoop(ctx, pi, s, deps);
|
|
941
|
-
|
|
942
|
-
assert.ok(
|
|
943
|
-
deps.callLog.includes("resolveDispatch"),
|
|
944
|
-
"should have called resolveDispatch",
|
|
945
|
-
);
|
|
946
|
-
assert.ok(
|
|
947
|
-
deps.callLog.includes("stopAuto"),
|
|
948
|
-
"should have stopped on dispatch stop action",
|
|
949
|
-
);
|
|
950
|
-
});
|
|
951
|
-
|
|
952
|
-
// #2474: warning-level dispatch stop should pause (resumable), not hard-stop
|
|
953
|
-
test("autoLoop pauses instead of stopping for warning-level dispatch stop", async (t) => {
|
|
954
|
-
_resetPendingResolve();
|
|
955
|
-
|
|
956
|
-
const ctx = makeMockCtx();
|
|
957
|
-
ctx.ui.setStatus = () => {};
|
|
958
|
-
const pi = makeMockPi();
|
|
959
|
-
const s = makeLoopSession();
|
|
960
|
-
|
|
961
|
-
const deps = makeMockDeps({
|
|
962
|
-
resolveDispatch: async () => {
|
|
963
|
-
deps.callLog.push("resolveDispatch");
|
|
964
|
-
return {
|
|
965
|
-
action: "stop" as const,
|
|
966
|
-
reason: 'UAT verdict for S01 is "partial" — blocking progression.',
|
|
967
|
-
level: "warning" as const,
|
|
968
|
-
};
|
|
969
|
-
},
|
|
970
|
-
});
|
|
971
|
-
|
|
972
|
-
await autoLoop(ctx, pi, s, deps);
|
|
973
|
-
|
|
974
|
-
assert.ok(
|
|
975
|
-
deps.callLog.includes("resolveDispatch"),
|
|
976
|
-
"should have called resolveDispatch",
|
|
977
|
-
);
|
|
978
|
-
assert.ok(
|
|
979
|
-
deps.callLog.includes("pauseAuto"),
|
|
980
|
-
"warning-level stop should call pauseAuto (resumable)",
|
|
981
|
-
);
|
|
982
|
-
assert.ok(
|
|
983
|
-
!deps.callLog.includes("stopAuto"),
|
|
984
|
-
"warning-level stop should NOT call stopAuto (hard stop)",
|
|
985
|
-
);
|
|
986
|
-
});
|
|
987
|
-
|
|
988
|
-
// #2474: error-level dispatch stop should still hard-stop
|
|
989
|
-
test("autoLoop hard-stops for error-level dispatch stop", async (t) => {
|
|
990
|
-
_resetPendingResolve();
|
|
991
|
-
|
|
992
|
-
const ctx = makeMockCtx();
|
|
993
|
-
ctx.ui.setStatus = () => {};
|
|
994
|
-
const pi = makeMockPi();
|
|
995
|
-
const s = makeLoopSession();
|
|
996
|
-
|
|
997
|
-
const deps = makeMockDeps({
|
|
998
|
-
resolveDispatch: async () => {
|
|
999
|
-
deps.callLog.push("resolveDispatch");
|
|
1000
|
-
return {
|
|
1001
|
-
action: "stop" as const,
|
|
1002
|
-
reason: "Cannot complete milestone: missing SUMMARY files.",
|
|
1003
|
-
level: "error" as const,
|
|
1004
|
-
};
|
|
1005
|
-
},
|
|
1006
|
-
});
|
|
1007
|
-
|
|
1008
|
-
await autoLoop(ctx, pi, s, deps);
|
|
1009
|
-
|
|
1010
|
-
assert.ok(
|
|
1011
|
-
deps.callLog.includes("stopAuto"),
|
|
1012
|
-
"error-level stop should call stopAuto (hard stop)",
|
|
1013
|
-
);
|
|
1014
|
-
assert.ok(
|
|
1015
|
-
!deps.callLog.includes("pauseAuto"),
|
|
1016
|
-
"error-level stop should NOT call pauseAuto",
|
|
1017
|
-
);
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
test("autoLoop handles dispatch skip action by continuing", async (t) => {
|
|
1021
|
-
_resetPendingResolve();
|
|
1022
|
-
|
|
1023
|
-
const ctx = makeMockCtx();
|
|
1024
|
-
ctx.ui.setStatus = () => {};
|
|
1025
|
-
const pi = makeMockPi();
|
|
1026
|
-
const s = makeLoopSession();
|
|
1027
|
-
|
|
1028
|
-
let dispatchCallCount = 0;
|
|
1029
|
-
// Pre-queued dispatch responses: first call returns "skip", second returns "stop"
|
|
1030
|
-
const dispatchResponses = [
|
|
1031
|
-
{ action: "skip" as const },
|
|
1032
|
-
{ action: "stop" as const, reason: "done", level: "info" as const },
|
|
1033
|
-
];
|
|
1034
|
-
const deps = makeMockDeps({
|
|
1035
|
-
resolveDispatch: async () => {
|
|
1036
|
-
const response = dispatchResponses[dispatchCallCount] ?? dispatchResponses[dispatchResponses.length - 1];
|
|
1037
|
-
dispatchCallCount++;
|
|
1038
|
-
deps.callLog.push("resolveDispatch");
|
|
1039
|
-
return response;
|
|
1040
|
-
},
|
|
1041
|
-
});
|
|
1042
|
-
|
|
1043
|
-
await autoLoop(ctx, pi, s, deps);
|
|
1044
|
-
|
|
1045
|
-
// Should have called resolveDispatch twice (skip → re-derive → stop)
|
|
1046
|
-
const dispatchCalls = deps.callLog.filter((c) => c === "resolveDispatch");
|
|
1047
|
-
assert.equal(
|
|
1048
|
-
dispatchCalls.length,
|
|
1049
|
-
2,
|
|
1050
|
-
"resolveDispatch should be called twice (skip then stop)",
|
|
1051
|
-
);
|
|
1052
|
-
const deriveCalls = deps.callLog.filter((c) => c === "deriveState");
|
|
1053
|
-
assert.ok(
|
|
1054
|
-
deriveCalls.length >= 2,
|
|
1055
|
-
"deriveState should be called at least twice (one per iteration)",
|
|
1056
|
-
);
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
test("autoLoop drains sidecar queue after postUnitPostVerification enqueues items", async (t) => {
|
|
1060
|
-
_resetPendingResolve();
|
|
1061
|
-
|
|
1062
|
-
const ctx = makeMockCtx();
|
|
1063
|
-
ctx.ui.setStatus = () => {};
|
|
1064
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
1065
|
-
const pi = makeMockPi();
|
|
1066
|
-
const s = makeLoopSession();
|
|
1067
|
-
|
|
1068
|
-
let postVerCallCount = 0;
|
|
1069
|
-
const postVerActions: Array<() => void> = [
|
|
1070
|
-
() => {
|
|
1071
|
-
// First call (main unit): enqueue a sidecar item
|
|
1072
|
-
s.sidecarQueue.push({
|
|
1073
|
-
kind: "hook" as const,
|
|
1074
|
-
unitType: "hook/review",
|
|
1075
|
-
unitId: "M001/S01/T01/review",
|
|
1076
|
-
prompt: "review the code",
|
|
1077
|
-
});
|
|
1078
|
-
},
|
|
1079
|
-
() => {
|
|
1080
|
-
// Second call (sidecar unit completed): deactivate
|
|
1081
|
-
s.active = false;
|
|
1082
|
-
},
|
|
1083
|
-
];
|
|
1084
|
-
const deps = makeMockDeps({
|
|
1085
|
-
postUnitPostVerification: async () => {
|
|
1086
|
-
postVerActions[postVerCallCount]?.();
|
|
1087
|
-
postVerCallCount++;
|
|
1088
|
-
deps.callLog.push("postUnitPostVerification");
|
|
1089
|
-
return "continue" as const;
|
|
1090
|
-
},
|
|
1091
|
-
});
|
|
1092
|
-
|
|
1093
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
1094
|
-
|
|
1095
|
-
// Wait for main unit's runUnit to be awaiting
|
|
1096
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
1097
|
-
resolveAgentEnd(makeEvent()); // resolve main unit
|
|
1098
|
-
|
|
1099
|
-
// Wait for the sidecar unit's runUnit to be awaiting
|
|
1100
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
1101
|
-
resolveAgentEnd(makeEvent()); // resolve sidecar unit
|
|
1102
|
-
|
|
1103
|
-
await loopPromise;
|
|
1104
|
-
|
|
1105
|
-
// postUnitPostVerification should have been called twice (main + sidecar)
|
|
1106
|
-
assert.equal(
|
|
1107
|
-
postVerCallCount,
|
|
1108
|
-
2,
|
|
1109
|
-
"postUnitPostVerification should be called twice (main + sidecar)",
|
|
1110
|
-
);
|
|
1111
|
-
});
|
|
1112
|
-
|
|
1113
|
-
test("autoLoop exits when no active milestone found", async (t) => {
|
|
1114
|
-
_resetPendingResolve();
|
|
1115
|
-
|
|
1116
|
-
const ctx = makeMockCtx();
|
|
1117
|
-
ctx.ui.setStatus = () => {};
|
|
1118
|
-
const pi = makeMockPi();
|
|
1119
|
-
const s = makeLoopSession({ currentMilestoneId: null });
|
|
1120
|
-
|
|
1121
|
-
const deps = makeMockDeps({
|
|
1122
|
-
deriveState: async () => {
|
|
1123
|
-
deps.callLog.push("deriveState");
|
|
1124
|
-
return {
|
|
1125
|
-
phase: "executing",
|
|
1126
|
-
activeMilestone: null,
|
|
1127
|
-
activeSlice: null,
|
|
1128
|
-
activeTask: null,
|
|
1129
|
-
registry: [],
|
|
1130
|
-
blockers: [],
|
|
1131
|
-
} as any;
|
|
1132
|
-
},
|
|
1133
|
-
});
|
|
1134
|
-
|
|
1135
|
-
await autoLoop(ctx, pi, s, deps);
|
|
1136
|
-
|
|
1137
|
-
assert.ok(
|
|
1138
|
-
deps.callLog.includes("stopAuto"),
|
|
1139
|
-
"should stop when no milestone and all complete",
|
|
1140
|
-
);
|
|
1141
|
-
});
|
|
1142
|
-
|
|
1143
|
-
test("autoLoop exports LoopDeps type", async () => {
|
|
1144
|
-
const src = readFileSync(
|
|
1145
|
-
resolve(import.meta.dirname, "..", "auto", "loop-deps.ts"),
|
|
1146
|
-
"utf-8",
|
|
1147
|
-
);
|
|
1148
|
-
assert.ok(
|
|
1149
|
-
src.includes("export interface LoopDeps"),
|
|
1150
|
-
"auto/loop-deps.ts should export LoopDeps interface",
|
|
1151
|
-
);
|
|
1152
|
-
});
|
|
1153
|
-
|
|
1154
|
-
test("autoLoop signature accepts deps parameter", async () => {
|
|
1155
|
-
const src = readFileSync(
|
|
1156
|
-
resolve(import.meta.dirname, "..", "auto", "loop.ts"),
|
|
1157
|
-
"utf-8",
|
|
1158
|
-
);
|
|
1159
|
-
assert.ok(
|
|
1160
|
-
src.includes("deps: LoopDeps"),
|
|
1161
|
-
"autoLoop should accept a deps: LoopDeps parameter",
|
|
1162
|
-
);
|
|
1163
|
-
});
|
|
1164
|
-
|
|
1165
|
-
test("autoLoop contains while (s.active) loop", () => {
|
|
1166
|
-
const src = readFileSync(
|
|
1167
|
-
resolve(import.meta.dirname, "..", "auto", "loop.ts"),
|
|
1168
|
-
"utf-8",
|
|
1169
|
-
);
|
|
1170
|
-
assert.ok(
|
|
1171
|
-
src.includes("while (s.active)"),
|
|
1172
|
-
"autoLoop should contain a while (s.active) loop",
|
|
1173
|
-
);
|
|
1174
|
-
});
|
|
1175
|
-
|
|
1176
|
-
// ── T03: End-to-end wiring structural assertions ─────────────────────────────
|
|
1177
|
-
|
|
1178
|
-
test("auto-loop.ts barrel re-exports autoLoop, runUnit, and resolveAgentEnd", () => {
|
|
1179
|
-
const barrel = readFileSync(
|
|
1180
|
-
resolve(import.meta.dirname, "..", "auto-loop.ts"),
|
|
1181
|
-
"utf-8",
|
|
1182
|
-
);
|
|
1183
|
-
assert.ok(
|
|
1184
|
-
barrel.includes("autoLoop"),
|
|
1185
|
-
"barrel must re-export autoLoop",
|
|
1186
|
-
);
|
|
1187
|
-
assert.ok(
|
|
1188
|
-
barrel.includes("runUnit"),
|
|
1189
|
-
"barrel must re-export runUnit",
|
|
1190
|
-
);
|
|
1191
|
-
assert.ok(
|
|
1192
|
-
barrel.includes("resolveAgentEnd"),
|
|
1193
|
-
"barrel must re-export resolveAgentEnd",
|
|
1194
|
-
);
|
|
1195
|
-
// Verify the actual function declarations exist in the submodules
|
|
1196
|
-
const loopSrc = readFileSync(
|
|
1197
|
-
resolve(import.meta.dirname, "..", "auto", "loop.ts"),
|
|
1198
|
-
"utf-8",
|
|
1199
|
-
);
|
|
1200
|
-
assert.ok(
|
|
1201
|
-
loopSrc.includes("export async function autoLoop"),
|
|
1202
|
-
"auto/loop.ts must define autoLoop",
|
|
1203
|
-
);
|
|
1204
|
-
const runUnitSrc = readFileSync(
|
|
1205
|
-
resolve(import.meta.dirname, "..", "auto", "run-unit.ts"),
|
|
1206
|
-
"utf-8",
|
|
1207
|
-
);
|
|
1208
|
-
assert.ok(
|
|
1209
|
-
runUnitSrc.includes("export async function runUnit"),
|
|
1210
|
-
"auto/run-unit.ts must define runUnit",
|
|
1211
|
-
);
|
|
1212
|
-
const resolveSrc = readFileSync(
|
|
1213
|
-
resolve(import.meta.dirname, "..", "auto", "resolve.ts"),
|
|
1214
|
-
"utf-8",
|
|
1215
|
-
);
|
|
1216
|
-
assert.ok(
|
|
1217
|
-
resolveSrc.includes("export function resolveAgentEnd"),
|
|
1218
|
-
"auto/resolve.ts must define resolveAgentEnd",
|
|
1219
|
-
);
|
|
1220
|
-
});
|
|
1221
|
-
|
|
1222
|
-
test("auto.ts startAuto calls autoLoop (not dispatchNextUnit as first dispatch)", () => {
|
|
1223
|
-
const src = readFileSync(
|
|
1224
|
-
resolve(import.meta.dirname, "..", "auto.ts"),
|
|
1225
|
-
"utf-8",
|
|
1226
|
-
);
|
|
1227
|
-
// Find the startAuto function body
|
|
1228
|
-
const fnIdx = src.indexOf("export async function startAuto");
|
|
1229
|
-
assert.ok(fnIdx > -1, "startAuto must exist in auto.ts");
|
|
1230
|
-
const fnEnd = src.indexOf("\n// ─── ", fnIdx + 100);
|
|
1231
|
-
const fnBlock =
|
|
1232
|
-
fnEnd > -1 ? src.slice(fnIdx, fnEnd) : src.slice(fnIdx, fnIdx + 5000);
|
|
1233
|
-
assert.ok(
|
|
1234
|
-
fnBlock.includes("autoLoop("),
|
|
1235
|
-
"startAuto must call autoLoop() instead of dispatchNextUnit()",
|
|
1236
|
-
);
|
|
1237
|
-
});
|
|
1238
|
-
|
|
1239
|
-
test("startAuto calls selfHealRuntimeRecords before autoLoop (#1727)", { skip: "selfHealRuntimeRecords moved to crash-recovery pipeline in v3" }, () => {
|
|
1240
|
-
const src = readFileSync(
|
|
1241
|
-
resolve(import.meta.dirname, "..", "auto.ts"),
|
|
1242
|
-
"utf-8",
|
|
1243
|
-
);
|
|
1244
|
-
const fnIdx = src.indexOf("export async function startAuto");
|
|
1245
|
-
assert.ok(fnIdx > -1, "startAuto must exist in auto.ts");
|
|
1246
|
-
const fnEnd = src.indexOf("\n// ─── ", fnIdx + 100);
|
|
1247
|
-
const fnBlock =
|
|
1248
|
-
fnEnd > -1 ? src.slice(fnIdx, fnEnd) : src.slice(fnIdx, fnIdx + 5000);
|
|
1249
|
-
|
|
1250
|
-
// Both autoLoop call sites must be preceded by selfHealRuntimeRecords
|
|
1251
|
-
const healIdx = fnBlock.indexOf("selfHealRuntimeRecords");
|
|
1252
|
-
const loopIdx = fnBlock.indexOf("autoLoop(");
|
|
1253
|
-
assert.ok(healIdx > -1, "startAuto must call selfHealRuntimeRecords");
|
|
1254
|
-
assert.ok(healIdx < loopIdx, "selfHealRuntimeRecords must be called before autoLoop");
|
|
1255
|
-
|
|
1256
|
-
// Verify the second autoLoop call site also has selfHeal before it (if present)
|
|
1257
|
-
const secondLoopIdx = fnBlock.indexOf("autoLoop(", loopIdx + 1);
|
|
1258
|
-
const secondHealIdx = fnBlock.indexOf("selfHealRuntimeRecords", healIdx + 1);
|
|
1259
|
-
assert.ok(
|
|
1260
|
-
secondLoopIdx === -1 || (secondHealIdx > -1 && secondHealIdx < secondLoopIdx),
|
|
1261
|
-
"if a second autoLoop call exists, it must also be preceded by selfHealRuntimeRecords",
|
|
1262
|
-
);
|
|
1263
|
-
});
|
|
1264
|
-
|
|
1265
|
-
test("startAuto guards against concurrent invocation (#2923)", () => {
|
|
1266
|
-
const src = readFileSync(
|
|
1267
|
-
resolve(import.meta.dirname, "..", "auto.ts"),
|
|
1268
|
-
"utf-8",
|
|
1269
|
-
);
|
|
1270
|
-
const fnIdx = src.indexOf("export async function startAuto");
|
|
1271
|
-
assert.ok(fnIdx > -1, "startAuto must exist in auto.ts");
|
|
1272
|
-
// The guard must appear before any other logic in the function body
|
|
1273
|
-
const fnBody = src.slice(fnIdx, fnIdx + 500);
|
|
1274
|
-
const activeGuard = fnBody.indexOf("if (s.active)");
|
|
1275
|
-
assert.ok(activeGuard > -1, "startAuto must check s.active to prevent concurrent auto-loops");
|
|
1276
|
-
const returnIdx = fnBody.indexOf("return;", activeGuard);
|
|
1277
|
-
assert.ok(
|
|
1278
|
-
returnIdx > -1 && returnIdx < activeGuard + 120,
|
|
1279
|
-
"s.active guard must early-return to prevent a second concurrent loop",
|
|
1280
|
-
);
|
|
1281
|
-
});
|
|
1282
|
-
|
|
1283
|
-
test("agent_end handler calls resolveAgentEnd (not handleAgentEnd)", () => {
|
|
1284
|
-
const hooksSrc = readFileSync(
|
|
1285
|
-
resolve(import.meta.dirname, "..", "bootstrap", "register-hooks.ts"),
|
|
1286
|
-
"utf-8",
|
|
1287
|
-
);
|
|
1288
|
-
// Verify the agent_end hook is registered
|
|
1289
|
-
const handlerIdx = hooksSrc.indexOf('pi.on("agent_end"');
|
|
1290
|
-
assert.ok(handlerIdx > -1, "register-hooks.ts must have an agent_end handler");
|
|
1291
|
-
|
|
1292
|
-
const recoverySrc = readFileSync(
|
|
1293
|
-
resolve(import.meta.dirname, "..", "bootstrap", "agent-end-recovery.ts"),
|
|
1294
|
-
"utf-8",
|
|
1295
|
-
);
|
|
1296
|
-
assert.ok(
|
|
1297
|
-
recoverySrc.includes("resolveAgentEnd(event)"),
|
|
1298
|
-
"agent_end success path must call resolveAgentEnd(event) instead of handleAgentEnd(ctx, pi)",
|
|
1299
|
-
);
|
|
1300
|
-
assert.ok(
|
|
1301
|
-
recoverySrc.includes("isSessionSwitchInFlight()"),
|
|
1302
|
-
"agent_end handler must ignore session-switch agent_end events from cmdCtx.newSession()",
|
|
1303
|
-
);
|
|
1304
|
-
});
|
|
1305
|
-
|
|
1306
|
-
test("auto-verification.ts runPostUnitVerification does not take dispatchNextUnit callback", () => {
|
|
1307
|
-
const src = readFileSync(
|
|
1308
|
-
resolve(import.meta.dirname, "..", "auto-verification.ts"),
|
|
1309
|
-
"utf-8",
|
|
1310
|
-
);
|
|
1311
|
-
const fnIdx = src.indexOf("export async function runPostUnitVerification");
|
|
1312
|
-
assert.ok(fnIdx > -1, "runPostUnitVerification must exist");
|
|
1313
|
-
const sigEnd = src.indexOf("): Promise<VerificationResult>", fnIdx);
|
|
1314
|
-
const signature = src.slice(fnIdx, sigEnd);
|
|
1315
|
-
assert.ok(
|
|
1316
|
-
!signature.includes("dispatchNextUnit"),
|
|
1317
|
-
"runPostUnitVerification must not take a dispatchNextUnit callback parameter",
|
|
1318
|
-
);
|
|
1319
|
-
assert.ok(
|
|
1320
|
-
!signature.includes("startDispatchGapWatchdog"),
|
|
1321
|
-
"runPostUnitVerification must not take a startDispatchGapWatchdog callback parameter",
|
|
1322
|
-
);
|
|
1323
|
-
});
|
|
1324
|
-
|
|
1325
|
-
test("auto-timeout-recovery.ts calls resolveAgentEnd instead of dispatchNextUnit", () => {
|
|
1326
|
-
const src = readFileSync(
|
|
1327
|
-
resolve(import.meta.dirname, "..", "auto-timeout-recovery.ts"),
|
|
1328
|
-
"utf-8",
|
|
1329
|
-
);
|
|
1330
|
-
assert.ok(
|
|
1331
|
-
!src.includes("await dispatchNextUnit"),
|
|
1332
|
-
"auto-timeout-recovery.ts must not call dispatchNextUnit",
|
|
1333
|
-
);
|
|
1334
|
-
assert.ok(
|
|
1335
|
-
src.includes("resolveAgentEnd("),
|
|
1336
|
-
"auto-timeout-recovery.ts must call resolveAgentEnd to re-iterate the loop on timeout recovery",
|
|
1337
|
-
);
|
|
1338
|
-
});
|
|
1339
|
-
|
|
1340
|
-
test("handleAgentEnd in auto.ts is a thin wrapper calling resolveAgentEnd", () => {
|
|
1341
|
-
const src = readFileSync(
|
|
1342
|
-
resolve(import.meta.dirname, "..", "auto.ts"),
|
|
1343
|
-
"utf-8",
|
|
1344
|
-
);
|
|
1345
|
-
const fnIdx = src.indexOf("export async function handleAgentEnd");
|
|
1346
|
-
assert.ok(fnIdx > -1, "handleAgentEnd must exist");
|
|
1347
|
-
const fnEnd = src.indexOf("\n// ─── ", fnIdx + 100);
|
|
1348
|
-
const fnBlock =
|
|
1349
|
-
fnEnd > -1 ? src.slice(fnIdx, fnEnd) : src.slice(fnIdx, fnIdx + 1000);
|
|
1350
|
-
assert.ok(
|
|
1351
|
-
fnBlock.includes("resolveAgentEnd("),
|
|
1352
|
-
"handleAgentEnd must call resolveAgentEnd",
|
|
1353
|
-
);
|
|
1354
|
-
// The function should be short — no reentrancy guard, no verification, no dispatch
|
|
1355
|
-
assert.ok(
|
|
1356
|
-
!fnBlock.includes("dispatchNextUnit"),
|
|
1357
|
-
"handleAgentEnd must not call dispatchNextUnit (it's now a thin wrapper)",
|
|
1358
|
-
);
|
|
1359
|
-
assert.ok(
|
|
1360
|
-
!fnBlock.includes("postUnitPreVerification") &&
|
|
1361
|
-
!fnBlock.includes("postUnitPostVerification"),
|
|
1362
|
-
"handleAgentEnd must not contain verification logic (moved to autoLoop)",
|
|
1363
|
-
);
|
|
1364
|
-
});
|
|
1365
|
-
|
|
1366
|
-
// ── Stuck counter tests ──────────────────────────────────────────────────────
|
|
1367
|
-
|
|
1368
|
-
test("stuck detection: stops when sliding window detects same unit 3 consecutive times", async () => {
|
|
1369
|
-
_resetPendingResolve();
|
|
1370
|
-
|
|
1371
|
-
const ctx = makeMockCtx();
|
|
1372
|
-
ctx.ui.setStatus = () => {};
|
|
1373
|
-
ctx.ui.notify = () => {};
|
|
1374
|
-
const pi = makeMockPi();
|
|
1375
|
-
const s = makeLoopSession();
|
|
1376
|
-
|
|
1377
|
-
let stopReason = "";
|
|
1378
|
-
const deps = makeMockDeps({
|
|
1379
|
-
deriveState: async () =>
|
|
1380
|
-
({
|
|
1381
|
-
phase: "executing",
|
|
1382
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
1383
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
1384
|
-
activeTask: { id: "T01" },
|
|
1385
|
-
registry: [{ id: "M001", status: "active" }],
|
|
1386
|
-
blockers: [],
|
|
1387
|
-
}) as any,
|
|
1388
|
-
resolveDispatch: async () => ({
|
|
1389
|
-
action: "dispatch" as const,
|
|
1390
|
-
unitType: "execute-task",
|
|
1391
|
-
unitId: "M001/S01/T01",
|
|
1392
|
-
prompt: "do the thing",
|
|
1393
|
-
}),
|
|
1394
|
-
stopAuto: async (_ctx?: any, _pi?: any, reason?: string) => {
|
|
1395
|
-
deps.callLog.push("stopAuto");
|
|
1396
|
-
stopReason = reason ?? "";
|
|
1397
|
-
s.active = false;
|
|
1398
|
-
},
|
|
1399
|
-
});
|
|
1400
|
-
|
|
1401
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
1402
|
-
|
|
1403
|
-
// Sliding window: iteration 1 pushes [A], iteration 2 pushes [A,A],
|
|
1404
|
-
// iteration 3 pushes [A,A,A] → Rule 2 fires (3 consecutive) → Level 1 recovery.
|
|
1405
|
-
// Level 1 invalidates caches and continues. Iteration 4 pushes [A,A,A,A] →
|
|
1406
|
-
// Rule 2 fires again → Level 2 hard stop.
|
|
1407
|
-
// Iterations 1-3 each run a unit (3 resolves needed). Iteration 3 triggers
|
|
1408
|
-
// Level 1 (cache invalidation + continue). Iteration 4 triggers Level 2 (stop
|
|
1409
|
-
// before runUnit), so no 4th resolve needed.
|
|
1410
|
-
|
|
1411
|
-
for (let i = 0; i < 3; i++) {
|
|
1412
|
-
await new Promise((r) => setTimeout(r, 30));
|
|
1413
|
-
resolveAgentEnd(makeEvent());
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
await loopPromise;
|
|
1417
|
-
|
|
1418
|
-
assert.ok(
|
|
1419
|
-
deps.callLog.includes("stopAuto"),
|
|
1420
|
-
"stopAuto should have been called",
|
|
1421
|
-
);
|
|
1422
|
-
assert.ok(
|
|
1423
|
-
stopReason.includes("Stuck"),
|
|
1424
|
-
`stop reason should mention 'Stuck', got: ${stopReason}`,
|
|
1425
|
-
);
|
|
1426
|
-
assert.ok(
|
|
1427
|
-
stopReason.includes("M001/S01/T01"),
|
|
1428
|
-
"stop reason should include unitId",
|
|
1429
|
-
);
|
|
1430
|
-
});
|
|
1431
|
-
|
|
1432
|
-
test("stuck detection: window resets recovery when deriveState returns a different unit", async () => {
|
|
1433
|
-
_resetPendingResolve();
|
|
1434
|
-
|
|
1435
|
-
const ctx = makeMockCtx();
|
|
1436
|
-
ctx.ui.setStatus = () => {};
|
|
1437
|
-
ctx.ui.notify = () => {};
|
|
1438
|
-
const pi = makeMockPi();
|
|
1439
|
-
const s = makeLoopSession();
|
|
1440
|
-
|
|
1441
|
-
let deriveCallCount = 0;
|
|
1442
|
-
let postVerCallCount = 0;
|
|
1443
|
-
let stopCalled = false;
|
|
1444
|
-
|
|
1445
|
-
// First 3 derives return T01, 4th returns T02; dispatch follows the derived task
|
|
1446
|
-
const derivedTaskIds = ["T01", "T01", "T01", "T02"];
|
|
1447
|
-
|
|
1448
|
-
const deps = makeMockDeps({
|
|
1449
|
-
deriveState: async () => {
|
|
1450
|
-
const taskId = derivedTaskIds[Math.min(deriveCallCount, derivedTaskIds.length - 1)];
|
|
1451
|
-
deriveCallCount++;
|
|
1452
|
-
deps.callLog.push("deriveState");
|
|
1453
|
-
return {
|
|
1454
|
-
phase: "executing",
|
|
1455
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
1456
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
1457
|
-
activeTask: { id: taskId },
|
|
1458
|
-
registry: [{ id: "M001", status: "active" }],
|
|
1459
|
-
blockers: [],
|
|
1460
|
-
} as any;
|
|
1461
|
-
},
|
|
1462
|
-
resolveDispatch: async () => {
|
|
1463
|
-
const taskId = derivedTaskIds[Math.min(deriveCallCount - 1, derivedTaskIds.length - 1)];
|
|
1464
|
-
deps.callLog.push("resolveDispatch");
|
|
1465
|
-
return {
|
|
1466
|
-
action: "dispatch" as const,
|
|
1467
|
-
unitType: "execute-task",
|
|
1468
|
-
unitId: `M001/S01/${taskId}`,
|
|
1469
|
-
prompt: "do the thing",
|
|
1470
|
-
};
|
|
1471
|
-
},
|
|
1472
|
-
stopAuto: async (_ctx?: any, _pi?: any, reason?: string) => {
|
|
1473
|
-
deps.callLog.push("stopAuto");
|
|
1474
|
-
stopCalled = true;
|
|
1475
|
-
s.active = false;
|
|
1476
|
-
},
|
|
1477
|
-
postUnitPostVerification: async () => {
|
|
1478
|
-
postVerCallCount++;
|
|
1479
|
-
deps.callLog.push("postUnitPostVerification");
|
|
1480
|
-
// Exit on the 4th call (after T02 unit completes)
|
|
1481
|
-
const shouldExit = postVerCallCount >= 4;
|
|
1482
|
-
s.active = !shouldExit;
|
|
1483
|
-
return "continue" as const;
|
|
1484
|
-
},
|
|
1485
|
-
});
|
|
1486
|
-
|
|
1487
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
1488
|
-
|
|
1489
|
-
// Resolve agent_end for iterations 1-4
|
|
1490
|
-
for (let i = 0; i < 4; i++) {
|
|
1491
|
-
await new Promise((r) => setTimeout(r, 30));
|
|
1492
|
-
resolveAgentEnd(makeEvent());
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
await loopPromise;
|
|
1496
|
-
|
|
1497
|
-
// Level 1 recovery fires on iteration 3 (cache invalidation + continue),
|
|
1498
|
-
// then iteration 4 derives T02 — no Level 2 hard stop.
|
|
1499
|
-
assert.ok(
|
|
1500
|
-
!stopCalled,
|
|
1501
|
-
"stopAuto should NOT have been called — different unit broke stuck pattern",
|
|
1502
|
-
);
|
|
1503
|
-
assert.ok(
|
|
1504
|
-
deriveCallCount >= 4,
|
|
1505
|
-
`deriveState should have been called at least 4 times (got ${deriveCallCount})`,
|
|
1506
|
-
);
|
|
1507
|
-
});
|
|
1508
|
-
|
|
1509
|
-
test("stuck detection: does not push to window during verification retry", async () => {
|
|
1510
|
-
_resetPendingResolve();
|
|
1511
|
-
|
|
1512
|
-
const ctx = makeMockCtx();
|
|
1513
|
-
ctx.ui.setStatus = () => {};
|
|
1514
|
-
ctx.ui.notify = () => {};
|
|
1515
|
-
const pi = makeMockPi();
|
|
1516
|
-
const s = makeLoopSession();
|
|
1517
|
-
|
|
1518
|
-
let verifyCallCount = 0;
|
|
1519
|
-
let stopReason = "";
|
|
1520
|
-
|
|
1521
|
-
// Pre-queued responses: 3 retries then a continue (exit)
|
|
1522
|
-
const verifyActions: Array<() => "retry" | "continue"> = [
|
|
1523
|
-
() => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed", attempt: 1 }; return "retry"; },
|
|
1524
|
-
() => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed", attempt: 2 }; return "retry"; },
|
|
1525
|
-
() => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed", attempt: 3 }; return "retry"; },
|
|
1526
|
-
() => { s.active = false; return "continue"; },
|
|
1527
|
-
];
|
|
1528
|
-
|
|
1529
|
-
const deps = makeMockDeps({
|
|
1530
|
-
deriveState: async () =>
|
|
1531
|
-
({
|
|
1532
|
-
phase: "executing",
|
|
1533
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
1534
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
1535
|
-
activeTask: { id: "T01" },
|
|
1536
|
-
registry: [{ id: "M001", status: "active" }],
|
|
1537
|
-
blockers: [],
|
|
1538
|
-
}) as any,
|
|
1539
|
-
resolveDispatch: async () => ({
|
|
1540
|
-
action: "dispatch" as const,
|
|
1541
|
-
unitType: "execute-task",
|
|
1542
|
-
unitId: "M001/S01/T01",
|
|
1543
|
-
prompt: "do the thing",
|
|
1544
|
-
}),
|
|
1545
|
-
runPostUnitVerification: async () => {
|
|
1546
|
-
const action = verifyActions[verifyCallCount] ?? (() => { s.active = false; return "continue" as const; });
|
|
1547
|
-
verifyCallCount++;
|
|
1548
|
-
deps.callLog.push("runPostUnitVerification");
|
|
1549
|
-
return action();
|
|
1550
|
-
},
|
|
1551
|
-
stopAuto: async (_ctx?: any, _pi?: any, reason?: string) => {
|
|
1552
|
-
deps.callLog.push("stopAuto");
|
|
1553
|
-
stopReason = reason ?? "";
|
|
1554
|
-
s.active = false;
|
|
1555
|
-
},
|
|
1556
|
-
});
|
|
1557
|
-
|
|
1558
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
1559
|
-
|
|
1560
|
-
// Resolve agent_end for 4 iterations (1 initial + 3 retries)
|
|
1561
|
-
for (let i = 0; i < 4; i++) {
|
|
1562
|
-
await new Promise((r) => setTimeout(r, 30));
|
|
1563
|
-
resolveAgentEnd(makeEvent());
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
await loopPromise;
|
|
1567
|
-
|
|
1568
|
-
// Even though same unit was derived 4 times, verification retries should
|
|
1569
|
-
// not push to the sliding window, so stuck detection should not have fired
|
|
1570
|
-
assert.ok(
|
|
1571
|
-
!stopReason.includes("Stuck"),
|
|
1572
|
-
`stuck detection should not fire during verification retries, got: ${stopReason}`,
|
|
1573
|
-
);
|
|
1574
|
-
assert.equal(
|
|
1575
|
-
verifyCallCount,
|
|
1576
|
-
4,
|
|
1577
|
-
"verification should have been called 4 times (1 initial + 3 retries)",
|
|
1578
|
-
);
|
|
1579
|
-
});
|
|
1580
|
-
|
|
1581
|
-
// ── detectStuck unit tests ────────────────────────────────────────────────────
|
|
1582
|
-
|
|
1583
|
-
test("detectStuck: returns null for fewer than 2 entries", () => {
|
|
1584
|
-
assert.equal(detectStuck([]), null);
|
|
1585
|
-
assert.equal(detectStuck([{ key: "A" }]), null);
|
|
1586
|
-
});
|
|
1587
|
-
|
|
1588
|
-
test("detectStuck: Rule 1 — same error twice in a row", () => {
|
|
1589
|
-
const result = detectStuck([
|
|
1590
|
-
{ key: "A", error: "ENOENT: file not found" },
|
|
1591
|
-
{ key: "A", error: "ENOENT: file not found" },
|
|
1592
|
-
]);
|
|
1593
|
-
assert.ok(result?.stuck, "should detect same error repeated");
|
|
1594
|
-
assert.ok(result?.reason.includes("Same error repeated"));
|
|
1595
|
-
});
|
|
1596
|
-
|
|
1597
|
-
test("detectStuck: Rule 1 — different errors do not trigger", () => {
|
|
1598
|
-
const result = detectStuck([
|
|
1599
|
-
{ key: "A", error: "ENOENT: file not found" },
|
|
1600
|
-
{ key: "A", error: "EACCES: permission denied" },
|
|
1601
|
-
]);
|
|
1602
|
-
assert.equal(result, null);
|
|
1603
|
-
});
|
|
1604
|
-
|
|
1605
|
-
test("detectStuck: Rule 2 — same unit 3 consecutive times", () => {
|
|
1606
|
-
const result = detectStuck([
|
|
1607
|
-
{ key: "execute-task/M001/S01/T01" },
|
|
1608
|
-
{ key: "execute-task/M001/S01/T01" },
|
|
1609
|
-
{ key: "execute-task/M001/S01/T01" },
|
|
1610
|
-
]);
|
|
1611
|
-
assert.ok(result?.stuck);
|
|
1612
|
-
assert.ok(result?.reason.includes("3 consecutive times"));
|
|
1613
|
-
});
|
|
1614
|
-
|
|
1615
|
-
test("detectStuck: Rule 2 — 2 consecutive does not trigger", () => {
|
|
1616
|
-
assert.equal(detectStuck([
|
|
1617
|
-
{ key: "A" },
|
|
1618
|
-
{ key: "A" },
|
|
1619
|
-
]), null);
|
|
1620
|
-
});
|
|
1621
|
-
|
|
1622
|
-
test("detectStuck: Rule 3 — oscillation A→B→A→B", () => {
|
|
1623
|
-
const result = detectStuck([
|
|
1624
|
-
{ key: "A" },
|
|
1625
|
-
{ key: "B" },
|
|
1626
|
-
{ key: "A" },
|
|
1627
|
-
{ key: "B" },
|
|
1628
|
-
]);
|
|
1629
|
-
assert.ok(result?.stuck);
|
|
1630
|
-
assert.ok(result?.reason.includes("Oscillation"));
|
|
1631
|
-
});
|
|
1632
|
-
|
|
1633
|
-
test("detectStuck: Rule 3 — non-oscillation pattern A→B→C→B", () => {
|
|
1634
|
-
assert.equal(detectStuck([
|
|
1635
|
-
{ key: "A" },
|
|
1636
|
-
{ key: "B" },
|
|
1637
|
-
{ key: "C" },
|
|
1638
|
-
{ key: "B" },
|
|
1639
|
-
]), null);
|
|
1640
|
-
});
|
|
1641
|
-
|
|
1642
|
-
test("detectStuck: Rule 1 takes priority over Rule 2 when both match", () => {
|
|
1643
|
-
const result = detectStuck([
|
|
1644
|
-
{ key: "A", error: "test error" },
|
|
1645
|
-
{ key: "A", error: "test error" },
|
|
1646
|
-
{ key: "A", error: "test error" },
|
|
1647
|
-
]);
|
|
1648
|
-
assert.ok(result?.stuck);
|
|
1649
|
-
// Rule 1 fires first
|
|
1650
|
-
assert.ok(result?.reason.includes("Same error repeated"));
|
|
1651
|
-
});
|
|
1652
|
-
|
|
1653
|
-
test("detectStuck: truncates long error strings", () => {
|
|
1654
|
-
const longError = "x".repeat(500);
|
|
1655
|
-
const result = detectStuck([
|
|
1656
|
-
{ key: "A", error: longError },
|
|
1657
|
-
{ key: "A", error: longError },
|
|
1658
|
-
]);
|
|
1659
|
-
assert.ok(result?.stuck);
|
|
1660
|
-
assert.ok(result!.reason.length < 300, "reason should be truncated");
|
|
1661
|
-
});
|
|
1662
|
-
|
|
1663
|
-
test("stuck detection: logs debug output with stuck-detected phase", () => {
|
|
1664
|
-
// Structural test: verify auto/phases.ts contains
|
|
1665
|
-
// stuck-detected and stuck-counter-reset debug log phases, plus detectStuck
|
|
1666
|
-
const src = readFileSync(
|
|
1667
|
-
resolve(import.meta.dirname, "..", "auto", "phases.ts"),
|
|
1668
|
-
"utf-8",
|
|
1669
|
-
);
|
|
1670
|
-
assert.ok(
|
|
1671
|
-
src.includes('"stuck-detected"'),
|
|
1672
|
-
"auto/phases.ts must log phase: 'stuck-detected' when stuck detection fires",
|
|
1673
|
-
);
|
|
1674
|
-
assert.ok(
|
|
1675
|
-
src.includes('"stuck-counter-reset"'),
|
|
1676
|
-
"auto/phases.ts must log phase: 'stuck-counter-reset' when recovery resets on new unit",
|
|
1677
|
-
);
|
|
1678
|
-
assert.ok(
|
|
1679
|
-
src.includes("detectStuck"),
|
|
1680
|
-
"auto/phases.ts must use detectStuck for sliding window analysis",
|
|
1681
|
-
);
|
|
1682
|
-
});
|
|
1683
|
-
|
|
1684
|
-
// ── Lifecycle test (S05/T02) ─────────────────────────────────────────────────
|
|
1685
|
-
|
|
1686
|
-
test("autoLoop lifecycle: advances through research → plan → execute → verify → complete across iterations", async () => {
|
|
1687
|
-
_resetPendingResolve();
|
|
1688
|
-
|
|
1689
|
-
const ctx = makeMockCtx();
|
|
1690
|
-
ctx.ui.setStatus = () => {};
|
|
1691
|
-
ctx.ui.notify = () => {};
|
|
1692
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
1693
|
-
const pi = makeMockPi();
|
|
1694
|
-
const s = makeLoopSession();
|
|
1695
|
-
|
|
1696
|
-
let deriveCallCount = 0;
|
|
1697
|
-
let dispatchCallCount = 0;
|
|
1698
|
-
const dispatchedUnitTypes: string[] = [];
|
|
1699
|
-
|
|
1700
|
-
// Phase sequence: each deriveState call returns a different phase.
|
|
1701
|
-
// The 6th entry (index 5) is the terminal "complete" phase that stops the loop.
|
|
1702
|
-
const phases = [
|
|
1703
|
-
// Call 1: researching → dispatches research-slice
|
|
1704
|
-
{
|
|
1705
|
-
phase: "researching",
|
|
1706
|
-
activeSlice: { id: "S01", title: "Research Slice" },
|
|
1707
|
-
activeTask: null,
|
|
1708
|
-
},
|
|
1709
|
-
// Call 2: planning → dispatches plan-slice
|
|
1710
|
-
{
|
|
1711
|
-
phase: "planning",
|
|
1712
|
-
activeSlice: { id: "S01", title: "Plan Slice" },
|
|
1713
|
-
activeTask: null,
|
|
1714
|
-
},
|
|
1715
|
-
// Call 3: executing → dispatches execute-task
|
|
1716
|
-
{
|
|
1717
|
-
phase: "executing",
|
|
1718
|
-
activeSlice: { id: "S01", title: "Execute Slice" },
|
|
1719
|
-
activeTask: { id: "T01" },
|
|
1720
|
-
},
|
|
1721
|
-
// Call 4: verifying → dispatches verify-slice
|
|
1722
|
-
{
|
|
1723
|
-
phase: "verifying",
|
|
1724
|
-
activeSlice: { id: "S01", title: "Verify Slice" },
|
|
1725
|
-
activeTask: null,
|
|
1726
|
-
},
|
|
1727
|
-
// Call 5: completing → dispatches complete-slice
|
|
1728
|
-
{
|
|
1729
|
-
phase: "completing",
|
|
1730
|
-
activeSlice: { id: "S01", title: "Complete Slice" },
|
|
1731
|
-
activeTask: null,
|
|
1732
|
-
},
|
|
1733
|
-
// Call 6: terminal — deactivate to exit the loop
|
|
1734
|
-
{
|
|
1735
|
-
phase: "complete",
|
|
1736
|
-
activeSlice: null,
|
|
1737
|
-
activeTask: null,
|
|
1738
|
-
},
|
|
1739
|
-
];
|
|
1740
|
-
|
|
1741
|
-
const dispatches = [
|
|
1742
|
-
{ unitType: "research-slice", unitId: "M001/S01", prompt: "research" },
|
|
1743
|
-
{ unitType: "plan-slice", unitId: "M001/S01", prompt: "plan" },
|
|
1744
|
-
{ unitType: "execute-task", unitId: "M001/S01/T01", prompt: "execute" },
|
|
1745
|
-
{ unitType: "verify-slice", unitId: "M001/S01", prompt: "verify" },
|
|
1746
|
-
{ unitType: "complete-slice", unitId: "M001/S01", prompt: "complete" },
|
|
1747
|
-
];
|
|
1748
|
-
|
|
1749
|
-
const deps = makeMockDeps({
|
|
1750
|
-
deriveState: async () => {
|
|
1751
|
-
const p = phases[Math.min(deriveCallCount, phases.length - 1)];
|
|
1752
|
-
deriveCallCount++;
|
|
1753
|
-
deps.callLog.push("deriveState");
|
|
1754
|
-
|
|
1755
|
-
const terminalPhases: Record<string, string> = { complete: "complete" };
|
|
1756
|
-
s.active = p.phase !== "complete";
|
|
1757
|
-
const milestoneStatus = terminalPhases[p.phase] ?? "active";
|
|
1758
|
-
return {
|
|
1759
|
-
phase: p.phase,
|
|
1760
|
-
activeMilestone: { id: "M001", title: "Test", status: milestoneStatus },
|
|
1761
|
-
activeSlice: p.activeSlice ?? null,
|
|
1762
|
-
activeTask: p.activeTask ?? null,
|
|
1763
|
-
registry: [{ id: "M001", status: milestoneStatus }],
|
|
1764
|
-
blockers: [],
|
|
1765
|
-
} as any;
|
|
1766
|
-
},
|
|
1767
|
-
resolveDispatch: async () => {
|
|
1768
|
-
const d = dispatches[Math.min(dispatchCallCount, dispatches.length - 1)];
|
|
1769
|
-
dispatchCallCount++;
|
|
1770
|
-
deps.callLog.push("resolveDispatch");
|
|
1771
|
-
dispatchedUnitTypes.push(d.unitType);
|
|
1772
|
-
return {
|
|
1773
|
-
action: "dispatch" as const,
|
|
1774
|
-
unitType: d.unitType,
|
|
1775
|
-
unitId: d.unitId,
|
|
1776
|
-
prompt: d.prompt,
|
|
1777
|
-
};
|
|
1778
|
-
},
|
|
1779
|
-
postUnitPostVerification: async () => {
|
|
1780
|
-
deps.callLog.push("postUnitPostVerification");
|
|
1781
|
-
return "continue" as const;
|
|
1782
|
-
},
|
|
1783
|
-
});
|
|
1784
|
-
|
|
1785
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
1786
|
-
|
|
1787
|
-
// Resolve each iteration's agent_end — 5 iterations, each dispatches a unit
|
|
1788
|
-
for (let i = 0; i < 5; i++) {
|
|
1789
|
-
await new Promise((r) => setTimeout(r, 30));
|
|
1790
|
-
resolveAgentEnd(makeEvent());
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
await loopPromise;
|
|
1794
|
-
|
|
1795
|
-
// Assert deriveState was called at least 5 times (once per iteration)
|
|
1796
|
-
assert.ok(
|
|
1797
|
-
deriveCallCount >= 5,
|
|
1798
|
-
`deriveState should be called at least 5 times (got ${deriveCallCount})`,
|
|
1799
|
-
);
|
|
1800
|
-
|
|
1801
|
-
// Assert the dispatched unit types cover the full lifecycle sequence
|
|
1802
|
-
assert.ok(
|
|
1803
|
-
dispatchedUnitTypes.includes("research-slice"),
|
|
1804
|
-
`should have dispatched research-slice, got: ${dispatchedUnitTypes.join(", ")}`,
|
|
1805
|
-
);
|
|
1806
|
-
assert.ok(
|
|
1807
|
-
dispatchedUnitTypes.includes("plan-slice"),
|
|
1808
|
-
`should have dispatched plan-slice, got: ${dispatchedUnitTypes.join(", ")}`,
|
|
1809
|
-
);
|
|
1810
|
-
assert.ok(
|
|
1811
|
-
dispatchedUnitTypes.includes("execute-task"),
|
|
1812
|
-
`should have dispatched execute-task, got: ${dispatchedUnitTypes.join(", ")}`,
|
|
1813
|
-
);
|
|
1814
|
-
assert.ok(
|
|
1815
|
-
dispatchedUnitTypes.includes("verify-slice"),
|
|
1816
|
-
`should have dispatched verify-slice, got: ${dispatchedUnitTypes.join(", ")}`,
|
|
1817
|
-
);
|
|
1818
|
-
assert.ok(
|
|
1819
|
-
dispatchedUnitTypes.includes("complete-slice"),
|
|
1820
|
-
`should have dispatched complete-slice, got: ${dispatchedUnitTypes.join(", ")}`,
|
|
1821
|
-
);
|
|
1822
|
-
|
|
1823
|
-
// Assert call sequence: deriveState and resolveDispatch entries are interleaved
|
|
1824
|
-
const deriveEntries = deps.callLog.filter((c) => c === "deriveState");
|
|
1825
|
-
const dispatchEntries = deps.callLog.filter((c) => c === "resolveDispatch");
|
|
1826
|
-
assert.ok(
|
|
1827
|
-
deriveEntries.length >= 5,
|
|
1828
|
-
`callLog should have at least 5 deriveState entries (got ${deriveEntries.length})`,
|
|
1829
|
-
);
|
|
1830
|
-
assert.ok(
|
|
1831
|
-
dispatchEntries.length >= 5,
|
|
1832
|
-
`callLog should have at least 5 resolveDispatch entries (got ${dispatchEntries.length})`,
|
|
1833
|
-
);
|
|
1834
|
-
|
|
1835
|
-
// Verify interleaving: a deriveState must follow a resolveDispatch (confirms loop advanced)
|
|
1836
|
-
const firstDispatchIdx = deps.callLog.indexOf("resolveDispatch");
|
|
1837
|
-
const firstDeriveAfterDispatch = deps.callLog.indexOf("deriveState", firstDispatchIdx + 1);
|
|
1838
|
-
assert.ok(firstDispatchIdx >= 0, "resolveDispatch should appear in callLog");
|
|
1839
|
-
assert.ok(firstDeriveAfterDispatch > firstDispatchIdx, "deriveState should follow resolveDispatch to confirm loop advanced");
|
|
1840
|
-
|
|
1841
|
-
// Assert the exact sequence of dispatched unit types
|
|
1842
|
-
assert.deepEqual(
|
|
1843
|
-
dispatchedUnitTypes,
|
|
1844
|
-
[
|
|
1845
|
-
"research-slice",
|
|
1846
|
-
"plan-slice",
|
|
1847
|
-
"execute-task",
|
|
1848
|
-
"verify-slice",
|
|
1849
|
-
"complete-slice",
|
|
1850
|
-
],
|
|
1851
|
-
"dispatched unit types should follow the full lifecycle sequence",
|
|
1852
|
-
);
|
|
1853
|
-
});
|
|
1854
|
-
|
|
1855
|
-
// ─── resolveAgentEndCancelled tests ──────────────────────────────────────────
|
|
1856
|
-
|
|
1857
|
-
test("resolveAgentEndCancelled resolves a pending promise with cancelled status", async () => {
|
|
1858
|
-
_resetPendingResolve();
|
|
1859
|
-
|
|
1860
|
-
const ctx = makeMockCtx();
|
|
1861
|
-
const pi = makeMockPi();
|
|
1862
|
-
const s = makeMockSession();
|
|
1863
|
-
|
|
1864
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
1865
|
-
|
|
1866
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
1867
|
-
|
|
1868
|
-
resolveAgentEndCancelled();
|
|
1869
|
-
|
|
1870
|
-
const result = await resultPromise;
|
|
1871
|
-
assert.equal(result.status, "cancelled");
|
|
1872
|
-
assert.equal(result.event, undefined);
|
|
1873
|
-
});
|
|
1874
|
-
|
|
1875
|
-
test("resolveAgentEndCancelled is a no-op when no promise is pending", () => {
|
|
1876
|
-
_resetPendingResolve();
|
|
1877
|
-
|
|
1878
|
-
assert.doesNotThrow(() => {
|
|
1879
|
-
resolveAgentEndCancelled();
|
|
1880
|
-
});
|
|
1881
|
-
});
|
|
1882
|
-
|
|
1883
|
-
test("resolveAgentEndCancelled prevents orphaned promise after abort path", async () => {
|
|
1884
|
-
_resetPendingResolve();
|
|
1885
|
-
|
|
1886
|
-
const ctx = makeMockCtx();
|
|
1887
|
-
const pi = makeMockPi();
|
|
1888
|
-
const s = makeMockSession();
|
|
1889
|
-
|
|
1890
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
1891
|
-
|
|
1892
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
1893
|
-
|
|
1894
|
-
s.active = false;
|
|
1895
|
-
resolveAgentEndCancelled();
|
|
1896
|
-
|
|
1897
|
-
const result = await resultPromise;
|
|
1898
|
-
assert.equal(result.status, "cancelled");
|
|
1899
|
-
});
|
|
1900
|
-
|
|
1901
|
-
test("resolveAgentEndCancelled with errorContext passes it through to resolved promise", async () => {
|
|
1902
|
-
_resetPendingResolve();
|
|
1903
|
-
|
|
1904
|
-
const { _setCurrentResolve } = await import("../auto/resolve.js");
|
|
1905
|
-
|
|
1906
|
-
const p = new Promise<UnitResult>((r) => {
|
|
1907
|
-
_setCurrentResolve(r);
|
|
1908
|
-
});
|
|
1909
|
-
|
|
1910
|
-
resolveAgentEndCancelled({ message: "test timeout", category: "timeout", isTransient: true });
|
|
1911
|
-
|
|
1912
|
-
const resolved = await p;
|
|
1913
|
-
assert.equal(resolved.status, "cancelled");
|
|
1914
|
-
assert.ok(resolved.errorContext, "errorContext must be present");
|
|
1915
|
-
assert.equal(resolved.errorContext!.category, "timeout");
|
|
1916
|
-
assert.equal(resolved.errorContext!.message, "test timeout");
|
|
1917
|
-
assert.equal(resolved.errorContext!.isTransient, true);
|
|
1918
|
-
});
|
|
1919
|
-
|
|
1920
|
-
test("resolveAgentEndCancelled without args produces no errorContext field", async () => {
|
|
1921
|
-
_resetPendingResolve();
|
|
1922
|
-
|
|
1923
|
-
const { _setCurrentResolve } = await import("../auto/resolve.js");
|
|
1924
|
-
|
|
1925
|
-
const p = new Promise<UnitResult>((r) => {
|
|
1926
|
-
_setCurrentResolve(r);
|
|
1927
|
-
});
|
|
1928
|
-
|
|
1929
|
-
resolveAgentEndCancelled();
|
|
1930
|
-
|
|
1931
|
-
const resolved = await p;
|
|
1932
|
-
assert.equal(resolved.status, "cancelled");
|
|
1933
|
-
assert.equal(resolved.errorContext, undefined, "errorContext must not be present when no args passed");
|
|
1934
|
-
});
|
|
1935
|
-
|
|
1936
|
-
// ─── #1571: artifact verification retry ──────────────────────────────────────
|
|
1937
|
-
|
|
1938
|
-
test("autoLoop re-iterates when postUnitPreVerification returns retry (#1571)", async () => {
|
|
1939
|
-
_resetPendingResolve();
|
|
1940
|
-
|
|
1941
|
-
const ctx = makeMockCtx();
|
|
1942
|
-
ctx.ui.setStatus = () => {};
|
|
1943
|
-
const pi = makeMockPi();
|
|
1944
|
-
const s = makeLoopSession();
|
|
1945
|
-
|
|
1946
|
-
let preVerifyCallCount = 0;
|
|
1947
|
-
// Pre-queued responses: first call returns "retry", second returns "continue"
|
|
1948
|
-
const preVerifyResponses = ["retry", "continue"] as const;
|
|
1949
|
-
|
|
1950
|
-
const deps = makeMockDeps({
|
|
1951
|
-
deriveState: async () => {
|
|
1952
|
-
deps.callLog.push("deriveState");
|
|
1953
|
-
return {
|
|
1954
|
-
phase: "executing",
|
|
1955
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
1956
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
1957
|
-
activeTask: { id: "T01" },
|
|
1958
|
-
registry: [{ id: "M001", status: "active" }],
|
|
1959
|
-
blockers: [],
|
|
1960
|
-
} as any;
|
|
1961
|
-
},
|
|
1962
|
-
postUnitPreVerification: async () => {
|
|
1963
|
-
deps.callLog.push("postUnitPreVerification");
|
|
1964
|
-
return preVerifyResponses[preVerifyCallCount++] ?? "continue";
|
|
1965
|
-
},
|
|
1966
|
-
postUnitPostVerification: async () => {
|
|
1967
|
-
deps.callLog.push("postUnitPostVerification");
|
|
1968
|
-
s.active = false;
|
|
1969
|
-
return "continue" as const;
|
|
1970
|
-
},
|
|
1971
|
-
});
|
|
1972
|
-
|
|
1973
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
1974
|
-
|
|
1975
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
1976
|
-
resolveAgentEnd(makeEvent());
|
|
1977
|
-
|
|
1978
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
1979
|
-
resolveAgentEnd(makeEvent());
|
|
1980
|
-
|
|
1981
|
-
await loopPromise;
|
|
1982
|
-
|
|
1983
|
-
assert.equal(preVerifyCallCount, 2, "preVerification should be called twice");
|
|
1984
|
-
|
|
1985
|
-
const postVerifyCalls = deps.callLog.filter(
|
|
1986
|
-
(c: string) => c === "runPostUnitVerification",
|
|
1987
|
-
);
|
|
1988
|
-
const postPostVerifyCalls = deps.callLog.filter(
|
|
1989
|
-
(c: string) => c === "postUnitPostVerification",
|
|
1990
|
-
);
|
|
1991
|
-
|
|
1992
|
-
assert.equal(postVerifyCalls.length, 1, "runPostUnitVerification should only be called once");
|
|
1993
|
-
assert.equal(postPostVerifyCalls.length, 1, "postUnitPostVerification should only be called once");
|
|
1994
|
-
});
|
|
1995
|
-
|
|
1996
|
-
// ─── stopAuto unitPromise leak regression (#1799) ────────────────────────────
|
|
1997
|
-
|
|
1998
|
-
test("resolveAgentEnd unblocks pending runUnit when called before session reset (#1799)", async () => {
|
|
1999
|
-
_resetPendingResolve();
|
|
2000
|
-
|
|
2001
|
-
const ctx = makeMockCtx();
|
|
2002
|
-
const pi = makeMockPi();
|
|
2003
|
-
const s = makeMockSession();
|
|
2004
|
-
|
|
2005
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "do work");
|
|
2006
|
-
|
|
2007
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
2008
|
-
|
|
2009
|
-
resolveAgentEnd({ messages: [] });
|
|
2010
|
-
_resetPendingResolve();
|
|
2011
|
-
s.active = false;
|
|
2012
|
-
|
|
2013
|
-
const result = await resultPromise;
|
|
2014
|
-
assert.equal(result.status, "completed", "runUnit should resolve, not hang");
|
|
2015
|
-
});
|
|
2016
|
-
|
|
2017
|
-
// ─── Zero tool-call hallucination guard (#1833) ───────────────────────────
|
|
2018
|
-
|
|
2019
|
-
test("autoLoop rejects execute-task with 0 tool calls as hallucinated (#1833)", async () => {
|
|
2020
|
-
_resetPendingResolve();
|
|
2021
|
-
|
|
2022
|
-
const ctx = makeMockCtx();
|
|
2023
|
-
ctx.ui.setStatus = () => {};
|
|
2024
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
2025
|
-
const pi = makeMockPi();
|
|
2026
|
-
|
|
2027
|
-
let iterationCount = 0;
|
|
2028
|
-
const notifications: string[] = [];
|
|
2029
|
-
ctx.ui.notify = (msg: string) => { notifications.push(msg); };
|
|
2030
|
-
|
|
2031
|
-
const s = makeLoopSession();
|
|
2032
|
-
|
|
2033
|
-
// Mock ledger: execute-task completed with 0 tool calls
|
|
2034
|
-
const mockLedger = {
|
|
2035
|
-
version: 1,
|
|
2036
|
-
projectStartedAt: Date.now(),
|
|
2037
|
-
units: [] as any[],
|
|
2038
|
-
};
|
|
2039
|
-
|
|
2040
|
-
const deps = makeMockDeps({
|
|
2041
|
-
deriveState: async () => {
|
|
2042
|
-
deps.callLog.push("deriveState");
|
|
2043
|
-
return {
|
|
2044
|
-
phase: "executing",
|
|
2045
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
2046
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
2047
|
-
activeTask: { id: "T01" },
|
|
2048
|
-
registry: [{ id: "M001", status: "active" }],
|
|
2049
|
-
blockers: [],
|
|
2050
|
-
} as any;
|
|
2051
|
-
},
|
|
2052
|
-
resolveDispatch: async () => {
|
|
2053
|
-
deps.callLog.push("resolveDispatch");
|
|
2054
|
-
return {
|
|
2055
|
-
action: "dispatch" as const,
|
|
2056
|
-
unitType: "execute-task",
|
|
2057
|
-
unitId: "M001/S01/T01",
|
|
2058
|
-
prompt: "implement the feature",
|
|
2059
|
-
};
|
|
2060
|
-
},
|
|
2061
|
-
closeoutUnit: async () => {
|
|
2062
|
-
// Simulate snapshotUnitMetrics adding a 0-toolCalls entry to ledger
|
|
2063
|
-
mockLedger.units.push({
|
|
2064
|
-
type: "execute-task",
|
|
2065
|
-
id: "M001/S01/T01",
|
|
2066
|
-
startedAt: s.currentUnit?.startedAt ?? Date.now(),
|
|
2067
|
-
toolCalls: 0,
|
|
2068
|
-
assistantMessages: 1,
|
|
2069
|
-
tokens: { input: 100, output: 200, total: 300, cacheRead: 0, cacheWrite: 0 },
|
|
2070
|
-
cost: 0.50,
|
|
2071
|
-
});
|
|
2072
|
-
},
|
|
2073
|
-
getLedger: () => mockLedger,
|
|
2074
|
-
postUnitPostVerification: async () => {
|
|
2075
|
-
deps.callLog.push("postUnitPostVerification");
|
|
2076
|
-
iterationCount++;
|
|
2077
|
-
// Deactivate after 2nd iteration
|
|
2078
|
-
s.active = iterationCount < 2;
|
|
2079
|
-
return "continue" as const;
|
|
2080
|
-
},
|
|
2081
|
-
});
|
|
2082
|
-
|
|
2083
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
2084
|
-
|
|
2085
|
-
// First iteration: execute-task with 0 tool calls → rejected
|
|
2086
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
2087
|
-
resolveAgentEnd(makeEvent());
|
|
2088
|
-
|
|
2089
|
-
// Second iteration: same task re-dispatched, this time with tool calls
|
|
2090
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
2091
|
-
mockLedger.units.length = 0; // clear previous entry
|
|
2092
|
-
(deps as any).closeoutUnit = async () => {
|
|
2093
|
-
mockLedger.units.push({
|
|
2094
|
-
type: "execute-task",
|
|
2095
|
-
id: "M001/S01/T01",
|
|
2096
|
-
startedAt: s.currentUnit?.startedAt ?? Date.now(),
|
|
2097
|
-
toolCalls: 5,
|
|
2098
|
-
assistantMessages: 3,
|
|
2099
|
-
tokens: { input: 500, output: 800, total: 1300, cacheRead: 0, cacheWrite: 0 },
|
|
2100
|
-
cost: 1.00,
|
|
2101
|
-
});
|
|
2102
|
-
};
|
|
2103
|
-
resolveAgentEnd(makeEvent());
|
|
2104
|
-
|
|
2105
|
-
await loopPromise;
|
|
2106
|
-
|
|
2107
|
-
// The task should NOT have been added to completedUnits on the first iteration
|
|
2108
|
-
// (0 tool calls), but SHOULD be added on the second iteration (5 tool calls)
|
|
2109
|
-
const warningNotification = notifications.find(
|
|
2110
|
-
(n) => n.includes("0 tool calls") && n.includes("hallucinated"),
|
|
2111
|
-
);
|
|
2112
|
-
assert.ok(
|
|
2113
|
-
warningNotification,
|
|
2114
|
-
"should notify about 0 tool calls hallucination",
|
|
2115
|
-
);
|
|
2116
|
-
|
|
2117
|
-
// Verify deriveState was called at least twice (two iterations)
|
|
2118
|
-
const deriveCount = deps.callLog.filter((c) => c === "deriveState").length;
|
|
2119
|
-
assert.ok(
|
|
2120
|
-
deriveCount >= 2,
|
|
2121
|
-
`deriveState should be called at least 2 times for retry (got ${deriveCount})`,
|
|
2122
|
-
);
|
|
2123
|
-
});
|
|
2124
|
-
|
|
2125
|
-
test("autoLoop does NOT reject non-execute-task units with 0 tool calls (#1833)", async () => {
|
|
2126
|
-
_resetPendingResolve();
|
|
2127
|
-
|
|
2128
|
-
const ctx = makeMockCtx();
|
|
2129
|
-
ctx.ui.setStatus = () => {};
|
|
2130
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
2131
|
-
const pi = makeMockPi();
|
|
2132
|
-
|
|
2133
|
-
const notifications: string[] = [];
|
|
2134
|
-
ctx.ui.notify = (msg: string) => { notifications.push(msg); };
|
|
2135
|
-
|
|
2136
|
-
const s = makeLoopSession();
|
|
2137
|
-
|
|
2138
|
-
const mockLedger = {
|
|
2139
|
-
version: 1,
|
|
2140
|
-
projectStartedAt: Date.now(),
|
|
2141
|
-
units: [] as any[],
|
|
2142
|
-
};
|
|
2143
|
-
|
|
2144
|
-
const deps = makeMockDeps({
|
|
2145
|
-
deriveState: async () => {
|
|
2146
|
-
deps.callLog.push("deriveState");
|
|
2147
|
-
return {
|
|
2148
|
-
phase: "executing",
|
|
2149
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
2150
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
2151
|
-
activeTask: { id: "T01" },
|
|
2152
|
-
registry: [{ id: "M001", status: "active" }],
|
|
2153
|
-
blockers: [],
|
|
2154
|
-
} as any;
|
|
2155
|
-
},
|
|
2156
|
-
resolveDispatch: async () => {
|
|
2157
|
-
deps.callLog.push("resolveDispatch");
|
|
2158
|
-
return {
|
|
2159
|
-
action: "dispatch" as const,
|
|
2160
|
-
unitType: "complete-slice",
|
|
2161
|
-
unitId: "M001/S01",
|
|
2162
|
-
prompt: "complete the slice",
|
|
2163
|
-
};
|
|
2164
|
-
},
|
|
2165
|
-
closeoutUnit: async () => {
|
|
2166
|
-
// complete-slice with 0 tool calls is fine (e.g. it may just update status)
|
|
2167
|
-
mockLedger.units.push({
|
|
2168
|
-
type: "complete-slice",
|
|
2169
|
-
id: "M001/S01",
|
|
2170
|
-
startedAt: s.currentUnit?.startedAt ?? Date.now(),
|
|
2171
|
-
toolCalls: 0,
|
|
2172
|
-
assistantMessages: 1,
|
|
2173
|
-
tokens: { input: 50, output: 100, total: 150, cacheRead: 0, cacheWrite: 0 },
|
|
2174
|
-
cost: 0.10,
|
|
2175
|
-
});
|
|
2176
|
-
},
|
|
2177
|
-
getLedger: () => mockLedger,
|
|
2178
|
-
postUnitPostVerification: async () => {
|
|
2179
|
-
deps.callLog.push("postUnitPostVerification");
|
|
2180
|
-
s.active = false;
|
|
2181
|
-
return "continue" as const;
|
|
2182
|
-
},
|
|
2183
|
-
});
|
|
2184
|
-
|
|
2185
|
-
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
2186
|
-
|
|
2187
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
2188
|
-
resolveAgentEnd(makeEvent());
|
|
2189
|
-
|
|
2190
|
-
await loopPromise;
|
|
2191
|
-
|
|
2192
|
-
// Should NOT have a hallucination warning for non-execute-task units
|
|
2193
|
-
const warningNotification = notifications.find(
|
|
2194
|
-
(n) => n.includes("0 tool calls") && n.includes("hallucinated"),
|
|
2195
|
-
);
|
|
2196
|
-
assert.ok(
|
|
2197
|
-
!warningNotification,
|
|
2198
|
-
"should NOT flag non-execute-task units with 0 tool calls",
|
|
2199
|
-
);
|
|
2200
|
-
|
|
2201
|
-
// Verify the loop ran to completion (postUnitPostVerification was called)
|
|
2202
|
-
assert.ok(
|
|
2203
|
-
deps.callLog.includes("postUnitPostVerification"),
|
|
2204
|
-
"complete-slice with 0 tool calls should still complete the post-unit pipeline",
|
|
2205
|
-
);
|
|
2206
|
-
});
|
|
2207
|
-
|
|
2208
|
-
// ─── Worktree health check (#1833) ────────────────────────────────────────
|
|
2209
|
-
|
|
2210
|
-
test("autoLoop stops when worktree has no .git for execute-task (#1833)", async () => {
|
|
2211
|
-
_resetPendingResolve();
|
|
2212
|
-
|
|
2213
|
-
const ctx = makeMockCtx();
|
|
2214
|
-
ctx.ui.setStatus = () => {};
|
|
2215
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
2216
|
-
const pi = makeMockPi();
|
|
2217
|
-
|
|
2218
|
-
const notifications: string[] = [];
|
|
2219
|
-
ctx.ui.notify = (msg: string) => { notifications.push(msg); };
|
|
2220
|
-
|
|
2221
|
-
const s = makeLoopSession({ basePath: "/tmp/broken-worktree" });
|
|
2222
|
-
|
|
2223
|
-
const deps = makeMockDeps({
|
|
2224
|
-
deriveState: async () => {
|
|
2225
|
-
deps.callLog.push("deriveState");
|
|
2226
|
-
return {
|
|
2227
|
-
phase: "executing",
|
|
2228
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
2229
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
2230
|
-
activeTask: { id: "T01" },
|
|
2231
|
-
registry: [{ id: "M001", status: "active" }],
|
|
2232
|
-
blockers: [],
|
|
2233
|
-
} as any;
|
|
2234
|
-
},
|
|
2235
|
-
// .git does not exist in the broken worktree
|
|
2236
|
-
existsSync: (p: string) => !p.endsWith(".git"),
|
|
2237
|
-
});
|
|
2238
|
-
|
|
2239
|
-
await autoLoop(ctx, pi, s, deps);
|
|
2240
|
-
|
|
2241
|
-
assert.ok(
|
|
2242
|
-
deps.callLog.includes("stopAuto"),
|
|
2243
|
-
"should stop auto-mode when worktree is invalid",
|
|
2244
|
-
);
|
|
2245
|
-
const healthNotification = notifications.find(
|
|
2246
|
-
(n) => n.includes("Worktree health check failed") && n.includes("no .git"),
|
|
2247
|
-
);
|
|
2248
|
-
assert.ok(
|
|
2249
|
-
healthNotification,
|
|
2250
|
-
"should notify about missing .git in worktree",
|
|
2251
|
-
);
|
|
2252
|
-
});
|
|
2253
|
-
|
|
2254
|
-
test("autoLoop warns but proceeds for greenfield project (no project files) (#1833)", async () => {
|
|
2255
|
-
_resetPendingResolve();
|
|
2256
|
-
|
|
2257
|
-
const ctx = makeMockCtx();
|
|
2258
|
-
ctx.ui.setStatus = () => {};
|
|
2259
|
-
ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
|
|
2260
|
-
const pi = makeMockPi();
|
|
2261
|
-
|
|
2262
|
-
const notifications: string[] = [];
|
|
2263
|
-
const s = makeLoopSession({ basePath: "/tmp/empty-worktree" });
|
|
2264
|
-
|
|
2265
|
-
ctx.ui.notify = (msg: string) => {
|
|
2266
|
-
notifications.push(msg);
|
|
2267
|
-
// Terminate the loop after the greenfield warning fires,
|
|
2268
|
-
// so we don't hang waiting for dispatch resolution.
|
|
2269
|
-
if (msg.includes("greenfield")) {
|
|
2270
|
-
s.active = false;
|
|
2271
|
-
}
|
|
2272
|
-
};
|
|
2273
|
-
|
|
2274
|
-
const deps = makeMockDeps({
|
|
2275
|
-
deriveState: async () => {
|
|
2276
|
-
deps.callLog.push("deriveState");
|
|
2277
|
-
return {
|
|
2278
|
-
phase: "executing",
|
|
2279
|
-
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
2280
|
-
activeSlice: { id: "S01", title: "Slice 1" },
|
|
2281
|
-
activeTask: { id: "T01" },
|
|
2282
|
-
registry: [{ id: "M001", status: "active" }],
|
|
2283
|
-
blockers: [],
|
|
2284
|
-
} as any;
|
|
2285
|
-
},
|
|
2286
|
-
// Has .git but no package.json or src/
|
|
2287
|
-
existsSync: (p: string) => p.endsWith(".git"),
|
|
2288
|
-
});
|
|
2289
|
-
|
|
2290
|
-
await autoLoop(ctx, pi, s, deps);
|
|
2291
|
-
|
|
2292
|
-
// Should NOT have stopped auto-mode due to health check — greenfield is allowed
|
|
2293
|
-
const stoppedForHealth = notifications.find(
|
|
2294
|
-
(n) => n.includes("Worktree health check failed"),
|
|
2295
|
-
);
|
|
2296
|
-
assert.ok(
|
|
2297
|
-
!stoppedForHealth,
|
|
2298
|
-
"should not stop with health check failure for greenfield project",
|
|
2299
|
-
);
|
|
2300
|
-
const greenfieldWarning = notifications.find(
|
|
2301
|
-
(n) => n.includes("no recognized project files") && n.includes("greenfield"),
|
|
2302
|
-
);
|
|
2303
|
-
assert.ok(
|
|
2304
|
-
greenfieldWarning,
|
|
2305
|
-
"should warn about greenfield project (no project files)",
|
|
2306
|
-
);
|
|
2307
|
-
});
|