@opengsd/gsd-pi 1.0.2-dev.867e002 → 1.0.2-dev.88c4dc5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/onboarding.js +22 -3
- package/dist/resource-loader.js +3 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/context7/index.js +12 -2
- package/dist/resources/extensions/get-secrets-from-user.js +16 -16
- package/dist/resources/extensions/google-cli/index.js +30 -0
- package/dist/resources/extensions/google-cli/models.js +55 -0
- package/dist/resources/extensions/google-cli/package.json +11 -0
- package/dist/resources/extensions/google-cli/readiness.js +12 -0
- package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
- package/dist/resources/extensions/gsd/auto/loop.js +62 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +37 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
- package/dist/resources/extensions/gsd/auto-post-unit.js +21 -11
- package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-start.js +232 -49
- package/dist/resources/extensions/gsd/auto.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
- package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
- package/dist/resources/extensions/gsd/commands-usage.js +105 -1
- package/dist/resources/extensions/gsd/config-overlay.js +20 -14
- package/dist/resources/extensions/gsd/context-overlay.js +22 -16
- package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
- package/dist/resources/extensions/gsd/doctor.js +6 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
- package/dist/resources/extensions/gsd/guided-flow.js +5 -6
- package/dist/resources/extensions/gsd/key-manager.js +45 -13
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
- package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
- package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
- package/dist/resources/extensions/gsd/preferences.js +14 -2
- package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -3
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
- package/dist/resources/extensions/gsd/repository-registry.js +3 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +11 -4
- package/dist/resources/extensions/gsd/skill-activation.js +233 -0
- package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
- package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
- package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
- package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
- package/dist/resources/extensions/gsd/skill-scope.js +52 -0
- package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
- package/dist/resources/extensions/gsd/skills.js +60 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
- package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
- package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
- package/dist/resources/extensions/gsd/vision-ask.js +22 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
- package/dist/resources/extensions/search-the-web/native-search.js +57 -8
- package/dist/resources/extensions/shared/confirm-ui.js +9 -6
- package/dist/resources/extensions/shared/dialog-frame.js +42 -0
- package/dist/resources/extensions/shared/interview-ui.js +42 -30
- package/dist/resources/extensions/shared/next-action-ui.js +6 -6
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +4 -4
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +4 -4
- package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.test.js +5 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +7 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +8 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/dist/workflow.test.js +1 -0
- package/packages/contracts/dist/workflow.test.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +28 -5
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/skills.js +6 -0
- package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +8 -59
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +21 -72
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +50 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
- package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +3 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/context7/index.ts +15 -2
- package/src/resources/extensions/get-secrets-from-user.ts +17 -16
- package/src/resources/extensions/google-cli/index.ts +34 -0
- package/src/resources/extensions/google-cli/models.ts +57 -0
- package/src/resources/extensions/google-cli/package.json +11 -0
- package/src/resources/extensions/google-cli/readiness.ts +15 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
- package/src/resources/extensions/gsd/auto/loop.ts +74 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +46 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +43 -14
- package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
- package/src/resources/extensions/gsd/auto-start.ts +307 -56
- package/src/resources/extensions/gsd/auto.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
- package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
- package/src/resources/extensions/gsd/commands-usage.ts +110 -5
- package/src/resources/extensions/gsd/config-overlay.ts +19 -16
- package/src/resources/extensions/gsd/context-overlay.ts +24 -19
- package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +6 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
- package/src/resources/extensions/gsd/guided-flow.ts +5 -6
- package/src/resources/extensions/gsd/key-manager.ts +57 -14
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
- package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
- package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
- package/src/resources/extensions/gsd/preferences.ts +17 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -3
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
- package/src/resources/extensions/gsd/repository-registry.ts +3 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -4
- package/src/resources/extensions/gsd/skill-activation.ts +292 -0
- package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
- package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
- package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
- package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
- package/src/resources/extensions/gsd/skill-scope.ts +63 -0
- package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
- package/src/resources/extensions/gsd/skills.ts +75 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
- package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
- package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +74 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
- package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
- package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
- package/src/resources/extensions/gsd/vision-ask.ts +28 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
- package/src/resources/extensions/search-the-web/native-search.ts +60 -8
- package/src/resources/extensions/shared/confirm-ui.ts +8 -12
- package/src/resources/extensions/shared/dialog-frame.ts +71 -0
- package/src/resources/extensions/shared/interview-ui.ts +43 -42
- package/src/resources/extensions/shared/next-action-ui.ts +6 -6
- package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
- package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → PkhJfy4kKo4yUHj1wY7_q}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → PkhJfy4kKo4yUHj1wY7_q}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
applyUnitSkillVisibility,
|
|
6
|
+
effectiveSkillNamesForUnit,
|
|
7
|
+
resolveVisibleSkillNames,
|
|
8
|
+
unitHasSkillManifest,
|
|
9
|
+
} from "../skill-scope.ts";
|
|
10
|
+
|
|
11
|
+
test("resolveVisibleSkillNames: none policy suppresses catalog", () => {
|
|
12
|
+
assert.deepEqual(resolveVisibleSkillNames("workflow-preferences"), []);
|
|
13
|
+
assert.equal(unitHasSkillManifest("workflow-preferences"), true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("resolveVisibleSkillNames: wildcard units use full catalog", () => {
|
|
17
|
+
assert.equal(resolveVisibleSkillNames("execute-task"), undefined);
|
|
18
|
+
assert.equal(unitHasSkillManifest("execute-task"), false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("unitHasSkillManifest: manifest unit types return true", () => {
|
|
22
|
+
assert.equal(unitHasSkillManifest("research-milestone"), true);
|
|
23
|
+
assert.equal(unitHasSkillManifest("plan-slice"), true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("unitHasSkillManifest: wildcard unit types return false", () => {
|
|
27
|
+
assert.equal(unitHasSkillManifest("execute-task"), false);
|
|
28
|
+
assert.equal(unitHasSkillManifest(undefined), false);
|
|
29
|
+
assert.equal(unitHasSkillManifest("unknown-unit"), false);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("applyUnitSkillVisibility: sets manifest names for scoped units", () => {
|
|
33
|
+
let visible: string[] | undefined;
|
|
34
|
+
applyUnitSkillVisibility({
|
|
35
|
+
setVisibleSkills: (names) => {
|
|
36
|
+
visible = names;
|
|
37
|
+
},
|
|
38
|
+
}, "research-milestone");
|
|
39
|
+
|
|
40
|
+
assert.ok(Array.isArray(visible));
|
|
41
|
+
assert.ok(visible!.includes("write-docs"));
|
|
42
|
+
assert.ok(visible!.length < 15);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("applyUnitSkillVisibility: restores full catalog for wildcard units", () => {
|
|
46
|
+
let visible: string[] | undefined = ["stale"];
|
|
47
|
+
applyUnitSkillVisibility({
|
|
48
|
+
setVisibleSkills: (names) => {
|
|
49
|
+
visible = names;
|
|
50
|
+
},
|
|
51
|
+
}, "execute-task");
|
|
52
|
+
|
|
53
|
+
assert.equal(visible, undefined);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("effectiveSkillNamesForUnit: filters installed names by manifest", () => {
|
|
57
|
+
const installed = ["write-docs", "review", "frontend-design", "tdd"];
|
|
58
|
+
const scoped = effectiveSkillNamesForUnit("research-milestone", installed);
|
|
59
|
+
assert.ok(scoped.includes("write-docs"));
|
|
60
|
+
assert.ok(!scoped.includes("review"));
|
|
61
|
+
assert.ok(scoped.length < installed.length);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("effectiveSkillNamesForUnit: pass-through for wildcard units", () => {
|
|
65
|
+
const installed = ["write-docs", "review"];
|
|
66
|
+
assert.deepEqual(effectiveSkillNamesForUnit("execute-task", installed), installed);
|
|
67
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import type { Skill } from "@gsd/pi-coding-agent";
|
|
4
|
+
import {
|
|
5
|
+
detectNewlyInstalledSkills,
|
|
6
|
+
getInstalledSkillNames,
|
|
7
|
+
getInstalledSkills,
|
|
8
|
+
normalizeSkillName,
|
|
9
|
+
resolveInstalledSkill,
|
|
10
|
+
snapshotInstalledSkillNames,
|
|
11
|
+
} from "../skills.js";
|
|
12
|
+
|
|
13
|
+
function makeSkill(name: string, filePath = `/tmp/${name}/SKILL.md`): Skill {
|
|
14
|
+
return {
|
|
15
|
+
name,
|
|
16
|
+
description: `Use for ${name}.`,
|
|
17
|
+
filePath,
|
|
18
|
+
baseDir: `/tmp/${name}`,
|
|
19
|
+
source: "user",
|
|
20
|
+
sourceInfo: {
|
|
21
|
+
path: filePath,
|
|
22
|
+
source: "local",
|
|
23
|
+
scope: "user",
|
|
24
|
+
origin: "top-level",
|
|
25
|
+
baseDir: `/tmp/${name}`,
|
|
26
|
+
},
|
|
27
|
+
disableModelInvocation: false,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
test("normalizeSkillName lowercases and trims", () => {
|
|
32
|
+
assert.equal(normalizeSkillName(" React-Best "), "react-best");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("getInstalledSkills returns explicit override", () => {
|
|
36
|
+
const skills = [makeSkill("alpha"), makeSkill("beta")];
|
|
37
|
+
assert.deepEqual(getInstalledSkills(skills).map((s) => s.name), ["alpha", "beta"]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("snapshotInstalledSkillNames and detectNewlyInstalledSkills diff normalized names", () => {
|
|
41
|
+
const baseline = snapshotInstalledSkillNames([makeSkill("alpha")]);
|
|
42
|
+
const added = detectNewlyInstalledSkills(baseline, [makeSkill("alpha"), makeSkill("Beta")]);
|
|
43
|
+
assert.deepEqual(added, ["beta"]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("getInstalledSkillNames maps skill names", () => {
|
|
47
|
+
assert.deepEqual(getInstalledSkillNames([makeSkill("tdd")]), ["tdd"]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("resolveInstalledSkill matches installed catalog by name", () => {
|
|
51
|
+
const skills = [makeSkill("react", "/home/user/.gsd/agent/skills/react/SKILL.md")];
|
|
52
|
+
const result = resolveInstalledSkill("react", "/project", skills);
|
|
53
|
+
assert.equal(result.skill?.name, "react");
|
|
54
|
+
assert.equal(result.resolvedPath, "/home/user/.gsd/agent/skills/react/SKILL.md");
|
|
55
|
+
});
|
|
@@ -15,6 +15,13 @@ function readGsdFile(relativePath: string): string {
|
|
|
15
15
|
return readFileSync(resolve(gsdDir, relativePath), "utf-8");
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function firstIndexOfAny(source: string, needles: string[]): number {
|
|
19
|
+
const indexes = needles
|
|
20
|
+
.map((needle) => source.indexOf(needle))
|
|
21
|
+
.filter((index) => index > -1);
|
|
22
|
+
return indexes.length > 0 ? Math.min(...indexes) : -1;
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
test("command entrypoints use startAutoDetached instead of awaiting startAuto (#3733)", () => {
|
|
19
26
|
const autoHandlerSrc = readGsdFile("commands/handlers/auto.ts");
|
|
20
27
|
const workflowHandlerSrc = readGsdFile("commands/handlers/workflow.ts");
|
|
@@ -145,7 +152,11 @@ test("fresh start registers the auto worker before bootstrap enters worktree flo
|
|
|
145
152
|
const resumeEnterMilestoneIdx = resumeBody.indexOf("buildLifecycle().enterMilestone");
|
|
146
153
|
const dbOpenIdx = bootstrapBody.indexOf("await openProjectDbIfPresent(base);");
|
|
147
154
|
const bootstrapRegisterIdx = bootstrapBody.indexOf("registerAutoWorkerForSession(base);");
|
|
148
|
-
const enterMilestoneIdx = bootstrapBody
|
|
155
|
+
const enterMilestoneIdx = firstIndexOfAny(bootstrapBody, [
|
|
156
|
+
"buildLifecycle().enterMilestone",
|
|
157
|
+
"lifecycle.enterMilestone",
|
|
158
|
+
"lifecycle.adoptStrandedMilestone",
|
|
159
|
+
]);
|
|
149
160
|
|
|
150
161
|
assert.ok(startAutoIdx > -1, "startAuto should exist");
|
|
151
162
|
assert.ok(preBootstrapRegisterIdx > -1, "startAuto should register worker before bootstrap");
|
|
@@ -158,7 +169,7 @@ test("fresh start registers the auto worker before bootstrap enters worktree flo
|
|
|
158
169
|
assert.ok(bootstrapIdx > -1, "bootstrapAutoSession should exist");
|
|
159
170
|
assert.ok(dbOpenIdx > -1, "bootstrap should open the project DB");
|
|
160
171
|
assert.ok(bootstrapRegisterIdx > -1, "bootstrap should register worker after DB open");
|
|
161
|
-
assert.ok(enterMilestoneIdx > -1, "bootstrap should enter milestones through lifecycle");
|
|
172
|
+
assert.ok(enterMilestoneIdx > -1, "bootstrap should enter or adopt milestones through lifecycle");
|
|
162
173
|
assert.ok(
|
|
163
174
|
preBootstrapRegisterIdx < bootstrapCallIdx,
|
|
164
175
|
"worker registration must happen before bootstrap so enterMilestone can claim milestone leases on first entry",
|
|
@@ -17,6 +17,8 @@ import { randomUUID } from "node:crypto";
|
|
|
17
17
|
import {
|
|
18
18
|
openDatabase,
|
|
19
19
|
closeDatabase,
|
|
20
|
+
_getAdapter,
|
|
21
|
+
insertArtifact,
|
|
20
22
|
insertMilestone,
|
|
21
23
|
insertSlice,
|
|
22
24
|
insertTask,
|
|
@@ -229,6 +231,175 @@ test("ADR-017 (#5700): classifyFailure recognizes ReconciliationFailedError", ()
|
|
|
229
231
|
assert.match(result.remediation, /persistent or repair-failed drift kinds/);
|
|
230
232
|
});
|
|
231
233
|
|
|
234
|
+
test("ADR-017: terminal drift blockers return blockers instead of repair exceptions", async () => {
|
|
235
|
+
const record: DriftRecord = { kind: "stale-sketch-flag", mid: "M001", sid: "S02" };
|
|
236
|
+
const handler: DriftHandler = {
|
|
237
|
+
kind: "stale-sketch-flag",
|
|
238
|
+
detect: () => [record],
|
|
239
|
+
blocker: () => "manual drift review required",
|
|
240
|
+
repair: () => {
|
|
241
|
+
throw new Error("repair should not run for terminal blockers");
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const result = await reconcileBeforeDispatch("/project", {
|
|
246
|
+
invalidateStateCache: () => {},
|
|
247
|
+
deriveState: async () => makeState(),
|
|
248
|
+
registry: [handler],
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
assert.equal(result.ok, true);
|
|
252
|
+
assert.deepEqual(result.blockers, ["manual drift review required"]);
|
|
253
|
+
assert.equal(result.repaired.length, 0);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("ADR-017: terminal blockers return a state snapshot refreshed after co-occurring repairs", async () => {
|
|
257
|
+
const repairDrift: DriftRecord = { kind: "stale-sketch-flag", mid: "M001", sid: "S02" };
|
|
258
|
+
const terminalDrift: DriftRecord = {
|
|
259
|
+
kind: "completed-milestone-reopened",
|
|
260
|
+
milestoneId: "M001",
|
|
261
|
+
dbStatus: "active",
|
|
262
|
+
};
|
|
263
|
+
let repaired = false;
|
|
264
|
+
const repairHandler: DriftHandler = {
|
|
265
|
+
kind: "stale-sketch-flag",
|
|
266
|
+
detect: (state) => (state.nextAction === "before repair" ? [repairDrift] : []),
|
|
267
|
+
repair: () => {
|
|
268
|
+
repaired = true;
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
const terminalHandler: DriftHandler = {
|
|
272
|
+
kind: "completed-milestone-reopened",
|
|
273
|
+
detect: (state) => (state.nextAction === "before repair" ? [terminalDrift] : []),
|
|
274
|
+
blocker: () => "manual completed-milestone review required",
|
|
275
|
+
repair: () => {
|
|
276
|
+
throw new Error("repair should not run for terminal blockers");
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const result = await reconcileBeforeDispatch("/project", {
|
|
281
|
+
invalidateStateCache: () => {},
|
|
282
|
+
deriveState: async () =>
|
|
283
|
+
makeState({ nextAction: repaired ? "after repair" : "before repair" }),
|
|
284
|
+
registry: [repairHandler, terminalHandler],
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
assert.equal(result.ok, true);
|
|
288
|
+
assert.equal(result.stateSnapshot.nextAction, "after repair");
|
|
289
|
+
assert.equal(result.repaired.length, 1);
|
|
290
|
+
assert.deepEqual(result.blockers, ["manual completed-milestone review required"]);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("ADR-017: terminal drift blockers take precedence over co-occurring repair failures", async () => {
|
|
294
|
+
const terminalDrift: DriftRecord = {
|
|
295
|
+
kind: "completed-milestone-reopened",
|
|
296
|
+
milestoneId: "M001",
|
|
297
|
+
dbStatus: "active",
|
|
298
|
+
};
|
|
299
|
+
const repairDrift: DriftRecord = { kind: "stale-sketch-flag", mid: "M001", sid: "S02" };
|
|
300
|
+
const terminalHandler: DriftHandler = {
|
|
301
|
+
kind: "completed-milestone-reopened",
|
|
302
|
+
detect: () => [terminalDrift],
|
|
303
|
+
blocker: () => "manual completed-milestone review required",
|
|
304
|
+
repair: () => {
|
|
305
|
+
throw new Error("repair should not run for terminal blockers");
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
const repairHandler: DriftHandler = {
|
|
309
|
+
kind: "stale-sketch-flag",
|
|
310
|
+
detect: () => [repairDrift],
|
|
311
|
+
repair: () => {
|
|
312
|
+
throw new Error("simulated repair failure");
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const result = await reconcileBeforeDispatch("/project", {
|
|
317
|
+
invalidateStateCache: () => {},
|
|
318
|
+
deriveState: async () => makeState(),
|
|
319
|
+
registry: [repairHandler, terminalHandler],
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
assert.equal(result.ok, true);
|
|
323
|
+
assert.deepEqual(result.blockers, ["manual completed-milestone review required"]);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("ADR-017: terminal drift found after repair cap returns blockers", async () => {
|
|
327
|
+
const repairDrift: DriftRecord = { kind: "stale-sketch-flag", mid: "M001", sid: "S02" };
|
|
328
|
+
const terminalDrift: DriftRecord = {
|
|
329
|
+
kind: "completed-milestone-reopened",
|
|
330
|
+
milestoneId: "M001",
|
|
331
|
+
dbStatus: "active",
|
|
332
|
+
};
|
|
333
|
+
let repairCount = 0;
|
|
334
|
+
const repairHandler: DriftHandler = {
|
|
335
|
+
kind: "stale-sketch-flag",
|
|
336
|
+
detect: () => (repairCount < 2 ? [repairDrift] : []),
|
|
337
|
+
repair: () => {
|
|
338
|
+
repairCount++;
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
const terminalHandler: DriftHandler = {
|
|
342
|
+
kind: "completed-milestone-reopened",
|
|
343
|
+
detect: () => (repairCount >= 2 ? [terminalDrift] : []),
|
|
344
|
+
blocker: () => "manual completed-milestone review required",
|
|
345
|
+
repair: () => {
|
|
346
|
+
throw new Error("repair should not run for terminal blockers");
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const result = await reconcileBeforeDispatch("/project", {
|
|
351
|
+
invalidateStateCache: () => {},
|
|
352
|
+
deriveState: async () => makeState(),
|
|
353
|
+
registry: [repairHandler, terminalHandler],
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
assert.equal(result.ok, true);
|
|
357
|
+
assert.equal(result.repaired.length, 2);
|
|
358
|
+
assert.deepEqual(result.blockers, ["manual completed-milestone review required"]);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
test("ADR-017: final persistent drift mixed with blockers still fails closed", async () => {
|
|
362
|
+
const repairDrift: DriftRecord = { kind: "stale-sketch-flag", mid: "M001", sid: "S02" };
|
|
363
|
+
const terminalDrift: DriftRecord = {
|
|
364
|
+
kind: "completed-milestone-reopened",
|
|
365
|
+
milestoneId: "M001",
|
|
366
|
+
dbStatus: "active",
|
|
367
|
+
};
|
|
368
|
+
let repairCount = 0;
|
|
369
|
+
const repairHandler: DriftHandler = {
|
|
370
|
+
kind: "stale-sketch-flag",
|
|
371
|
+
detect: () => [repairDrift],
|
|
372
|
+
repair: () => {
|
|
373
|
+
repairCount++;
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
const terminalHandler: DriftHandler = {
|
|
377
|
+
kind: "completed-milestone-reopened",
|
|
378
|
+
detect: () => (repairCount >= 2 ? [terminalDrift] : []),
|
|
379
|
+
blocker: () => "manual completed-milestone review required",
|
|
380
|
+
repair: () => {
|
|
381
|
+
throw new Error("repair should not run for terminal blockers");
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
await assert.rejects(
|
|
386
|
+
() =>
|
|
387
|
+
reconcileBeforeDispatch("/project", {
|
|
388
|
+
invalidateStateCache: () => {},
|
|
389
|
+
deriveState: async () => makeState(),
|
|
390
|
+
registry: [repairHandler, terminalHandler],
|
|
391
|
+
}),
|
|
392
|
+
(err: unknown) => {
|
|
393
|
+
assert.ok(err instanceof ReconciliationFailedError);
|
|
394
|
+
assert.deepEqual(err.persistentDrift.map((d) => d.kind).sort(), [
|
|
395
|
+
"completed-milestone-reopened",
|
|
396
|
+
"stale-sketch-flag",
|
|
397
|
+
]);
|
|
398
|
+
return true;
|
|
399
|
+
},
|
|
400
|
+
);
|
|
401
|
+
});
|
|
402
|
+
|
|
232
403
|
// ─── #5701: merge-state drift ────────────────────────────────────────────────
|
|
233
404
|
|
|
234
405
|
function makeGitBase(): string {
|
|
@@ -1052,6 +1223,138 @@ test("ADR-017 (#5706): repair is idempotent — re-running preserves the timesta
|
|
|
1052
1223
|
assert.equal(getSlice("M001", "S01")?.completed_at, tsAfterFirst, "timestamp unchanged");
|
|
1053
1224
|
});
|
|
1054
1225
|
|
|
1226
|
+
test("ADR-017: artifact/DB status divergence fails closed instead of importing completion artifacts", async (t) => {
|
|
1227
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-artifact-db-drift-"));
|
|
1228
|
+
t.after(() => cleanup(base));
|
|
1229
|
+
|
|
1230
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01"), { recursive: true });
|
|
1231
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
1232
|
+
insertMilestone({ id: "M001", title: "Milestone", status: "active" });
|
|
1233
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "pending" });
|
|
1234
|
+
writeFileSync(
|
|
1235
|
+
join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md"),
|
|
1236
|
+
"# S01 Summary\n\nAlready done on disk.\n",
|
|
1237
|
+
);
|
|
1238
|
+
|
|
1239
|
+
const result = await reconcileBeforeDispatch(base, {
|
|
1240
|
+
invalidateStateCache: () => {},
|
|
1241
|
+
deriveState: async () => makeState({ activeMilestone: { id: "M001", title: "Milestone" } }),
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
assert.equal(result.ok, true);
|
|
1245
|
+
assert.match(result.blockers.join("\n"), /Artifact\/DB status drift/);
|
|
1246
|
+
assert.equal(getSlice("M001", "S01")?.status, "pending", "DB status remains authoritative");
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
test("ADR-017: meaningful disk-only slice drift blocker includes repair guidance", async (t) => {
|
|
1250
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-disk-slice-guidance-"));
|
|
1251
|
+
const diskOnlySliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S99");
|
|
1252
|
+
t.after(() => cleanup(base));
|
|
1253
|
+
|
|
1254
|
+
mkdirSync(diskOnlySliceDir, { recursive: true });
|
|
1255
|
+
writeFileSync(join(diskOnlySliceDir, "S99-PLAN.md"), "# Disk-only plan\n\nWork to review.\n");
|
|
1256
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
1257
|
+
insertMilestone({ id: "M001", title: "Milestone", status: "active" });
|
|
1258
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Known Slice", status: "pending" });
|
|
1259
|
+
|
|
1260
|
+
const result = await reconcileBeforeDispatch(base, {
|
|
1261
|
+
invalidateStateCache: () => {},
|
|
1262
|
+
deriveState: async () => makeState({ activeMilestone: { id: "M001", title: "Milestone" } }),
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
assert.equal(result.ok, true);
|
|
1266
|
+
const message = result.blockers.join("\n");
|
|
1267
|
+
assert.match(message, /Slice ID drift in M001/);
|
|
1268
|
+
assert.match(message, /Review .*S99/);
|
|
1269
|
+
assert.match(message, /move or delete/);
|
|
1270
|
+
assert.match(message, /\.gsd\/quarantine\/milestones\/M001\/slices\/S99-manual-review/);
|
|
1271
|
+
assert.match(message, /copy or merge/);
|
|
1272
|
+
assert.match(message, /\/gsd doctor M001/);
|
|
1273
|
+
assert.match(message, /\/gsd next or \/gsd auto/);
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
test("ADR-017: orphan task completion artifact fails closed", async (t) => {
|
|
1277
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-orphan-task-artifact-drift-"));
|
|
1278
|
+
t.after(() => cleanup(base));
|
|
1279
|
+
|
|
1280
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T99"), { recursive: true });
|
|
1281
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
1282
|
+
insertMilestone({ id: "M001", title: "Milestone", status: "active" });
|
|
1283
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "pending" });
|
|
1284
|
+
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Task", status: "pending" });
|
|
1285
|
+
insertArtifact({
|
|
1286
|
+
path: join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T99", "T99-SUMMARY.md"),
|
|
1287
|
+
artifact_type: "SUMMARY",
|
|
1288
|
+
milestone_id: "M001",
|
|
1289
|
+
slice_id: "S01",
|
|
1290
|
+
task_id: "T99",
|
|
1291
|
+
full_content: "# T99 Summary\n\nStale artifact after replan.\n",
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
const result = await reconcileBeforeDispatch(base, {
|
|
1295
|
+
invalidateStateCache: () => {},
|
|
1296
|
+
deriveState: async () => makeState({ activeMilestone: { id: "M001", title: "Milestone" } }),
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
assert.equal(result.ok, true);
|
|
1300
|
+
assert.match(result.blockers.join("\n"), /Artifact\/DB status drift/);
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
test("ADR-017: completed milestone dispatch history blocks accidental re-planning", async (t) => {
|
|
1304
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-completed-reopened-drift-"));
|
|
1305
|
+
t.after(() => cleanup(base));
|
|
1306
|
+
|
|
1307
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
1308
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
1309
|
+
insertMilestone({ id: "M001", title: "Milestone", status: "active" });
|
|
1310
|
+
|
|
1311
|
+
const adapter = _getAdapter();
|
|
1312
|
+
assert.ok(adapter);
|
|
1313
|
+
adapter.prepare(
|
|
1314
|
+
`INSERT OR REPLACE INTO workers
|
|
1315
|
+
(worker_id, host, pid, started_at, version, last_heartbeat_at, status, project_root_realpath)
|
|
1316
|
+
VALUES ('w1', 'local', 1, '2026-05-30T00:00:00.000Z', 'test', '2026-05-30T00:00:00.000Z', 'stopped', :root)`,
|
|
1317
|
+
).run({ ":root": base });
|
|
1318
|
+
adapter.prepare(
|
|
1319
|
+
`INSERT INTO unit_dispatches
|
|
1320
|
+
(trace_id, worker_id, milestone_lease_token, milestone_id, unit_type, unit_id, status, attempt_n, started_at, ended_at)
|
|
1321
|
+
VALUES
|
|
1322
|
+
('trace', 'w1', 1, 'M001', 'complete-milestone', 'M001', 'completed', 1, '2026-05-30T00:00:00.000Z', '2026-05-30T00:01:00.000Z')`,
|
|
1323
|
+
).run();
|
|
1324
|
+
|
|
1325
|
+
const result = await reconcileBeforeDispatch(base, {
|
|
1326
|
+
invalidateStateCache: () => {},
|
|
1327
|
+
deriveState: async () => makeState({ activeMilestone: { id: "M001", title: "Milestone" } }),
|
|
1328
|
+
});
|
|
1329
|
+
|
|
1330
|
+
assert.equal(result.ok, true);
|
|
1331
|
+
assert.match(result.blockers.join("\n"), /completed complete-milestone dispatch history/);
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1334
|
+
test("ADR-017: synthetic parallel-research slice directory is ignored", async (t) => {
|
|
1335
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-parallel-sentinel-drift-"));
|
|
1336
|
+
t.after(() => cleanup(base));
|
|
1337
|
+
|
|
1338
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01"), { recursive: true });
|
|
1339
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "parallel-research", "tasks"), { recursive: true });
|
|
1340
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
1341
|
+
insertMilestone({ id: "M001", title: "Milestone", status: "active" });
|
|
1342
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "pending" });
|
|
1343
|
+
|
|
1344
|
+
const result = await reconcileBeforeDispatch(base, {
|
|
1345
|
+
invalidateStateCache: () => {},
|
|
1346
|
+
deriveState: async () => makeState({ activeMilestone: { id: "M001", title: "Milestone" } }),
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
assert.equal(result.ok, true);
|
|
1350
|
+
assert.equal(
|
|
1351
|
+
existsSync(join(base, ".gsd", "milestones", "M001", "slices", "parallel-research")),
|
|
1352
|
+
true,
|
|
1353
|
+
"sentinel directory is left alone, not treated as a real disk-only slice",
|
|
1354
|
+
);
|
|
1355
|
+
assert.equal(result.repaired.some((record) => record.kind === "disk-slice-id-divergence"), false);
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1055
1358
|
// ─── #5707: caller closure (reconcileBeforeSpawn) ────────────────────────────
|
|
1056
1359
|
|
|
1057
1360
|
test("ADR-017 (#5707): reconcileBeforeSpawn returns ok=true on clean reconciliation", async () => {
|
|
@@ -6,6 +6,7 @@ import test from "node:test";
|
|
|
6
6
|
|
|
7
7
|
import { DISCUSS_TOOLS_ALLOWLIST } from "../constants.ts";
|
|
8
8
|
import { buildMinimalAutoGsdToolSet, buildMinimalGsdToolSet, buildMinimalGsdWorkflowToolSet, buildRequestScopedGsdToolSet, MINIMAL_AUTO_BASE_TOOL_NAMES, MINIMAL_GSD_TOOL_NAMES, restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch } from "../bootstrap/register-hooks.ts";
|
|
9
|
+
import { applyUnitSkillVisibility } from "../skill-scope.ts";
|
|
9
10
|
|
|
10
11
|
test("buildMinimalGsdToolSet preserves non-GSD tools and replaces broad GSD surface", () => {
|
|
11
12
|
const result = buildMinimalGsdToolSet([
|
|
@@ -435,3 +436,21 @@ test("scopeGsdWorkflowToolsForDispatch applies and restores per-unit skill visib
|
|
|
435
436
|
assert.deepEqual(visibleSkills, ["previous-skill"]);
|
|
436
437
|
assert.equal(calls.filter((call) => call.kind === "skills").length, 2);
|
|
437
438
|
});
|
|
439
|
+
|
|
440
|
+
test("applyUnitSkillVisibility sets manifest or clears for wildcard", () => {
|
|
441
|
+
const calls: Array<string[] | undefined> = [];
|
|
442
|
+
applyUnitSkillVisibility({
|
|
443
|
+
setVisibleSkills: (names) => {
|
|
444
|
+
calls.push(names);
|
|
445
|
+
},
|
|
446
|
+
}, "plan-milestone");
|
|
447
|
+
assert.ok(Array.isArray(calls[0]));
|
|
448
|
+
assert.ok(calls[0]!.includes("tdd"));
|
|
449
|
+
|
|
450
|
+
applyUnitSkillVisibility({
|
|
451
|
+
setVisibleSkills: (names) => {
|
|
452
|
+
calls.push(names);
|
|
453
|
+
},
|
|
454
|
+
}, "execute-task");
|
|
455
|
+
assert.equal(calls[1], undefined);
|
|
456
|
+
});
|
|
@@ -235,12 +235,16 @@ test("gsd_task_complete — enrichment arrays are optional", () => {
|
|
|
235
235
|
"milestoneId",
|
|
236
236
|
"oneLiner",
|
|
237
237
|
"narrative",
|
|
238
|
-
"verification",
|
|
239
238
|
];
|
|
240
239
|
for (const field of coreRequired) {
|
|
241
240
|
assert.ok(required.has(field), `core field "${field}" must be required`);
|
|
242
241
|
}
|
|
243
242
|
|
|
243
|
+
assert.ok(
|
|
244
|
+
!required.has("verification"),
|
|
245
|
+
"verification must be optional at the schema layer so step-mode can recover when verificationEvidence is present",
|
|
246
|
+
);
|
|
247
|
+
|
|
244
248
|
// Enrichment fields must be optional
|
|
245
249
|
const enrichmentFields = [
|
|
246
250
|
"keyFiles",
|
|
@@ -272,6 +276,25 @@ test("gsd_task_complete — validates with only core params", () => {
|
|
|
272
276
|
assert.strictEqual(errors.length, 0, `Minimal params should validate but got errors: ${errors.join(", ")}`);
|
|
273
277
|
});
|
|
274
278
|
|
|
279
|
+
test("gsd_task_complete — accepts evidence-only verification at schema layer", () => {
|
|
280
|
+
const tool = getTool("gsd_task_complete");
|
|
281
|
+
assert.ok(tool, "gsd_task_complete must be registered");
|
|
282
|
+
|
|
283
|
+
const params = {
|
|
284
|
+
taskId: "T01",
|
|
285
|
+
sliceId: "S01",
|
|
286
|
+
milestoneId: "M001",
|
|
287
|
+
oneLiner: "Implemented the feature",
|
|
288
|
+
narrative: "Created the module and wired it up.",
|
|
289
|
+
verificationEvidence: [
|
|
290
|
+
{ command: "npm test", exitCode: 0, verdict: "pass", durationMs: 1234 },
|
|
291
|
+
],
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const errors = validateSchema(tool, params);
|
|
295
|
+
assert.strictEqual(errors.length, 0, `Evidence-only params should validate but got errors: ${errors.join(", ")}`);
|
|
296
|
+
});
|
|
297
|
+
|
|
275
298
|
// ─── gsd_complete_milestone: enrichment arrays must be optional ──────────────
|
|
276
299
|
|
|
277
300
|
test("gsd_complete_milestone — enrichment arrays are optional", () => {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
|
|
3
|
+
import { visibleWidth } from "@gsd/pi-tui";
|
|
4
|
+
|
|
5
|
+
const ANSI_PATTERN = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
6
|
+
|
|
7
|
+
function stripAnsi(text: string): string {
|
|
8
|
+
return text.replace(ANSI_PATTERN, "");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function assertFullOuterBorder(lines: string[], width: number): void {
|
|
12
|
+
assert.ok(lines.length >= 2, "dialog must include top and bottom borders");
|
|
13
|
+
|
|
14
|
+
for (const [index, line] of lines.entries()) {
|
|
15
|
+
assert.equal(visibleWidth(line), width, `line ${index} must fill dialog width`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const top = stripAnsi(lines[0] ?? "");
|
|
19
|
+
const bottom = stripAnsi(lines.at(-1) ?? "");
|
|
20
|
+
assert.match(top, /^[╭┌].*[╮┐]$/, `top border missing full corners: ${top}`);
|
|
21
|
+
assert.match(bottom, /^[╰└].*[╯┘]$/, `bottom border missing full corners: ${bottom}`);
|
|
22
|
+
|
|
23
|
+
for (let index = 1; index < lines.length - 1; index++) {
|
|
24
|
+
const line = stripAnsi(lines[index] ?? "");
|
|
25
|
+
assert.match(line, /^[│┃├]/, `line ${index} missing left border: ${line}`);
|
|
26
|
+
assert.match(line, /[│┃┤]$/, `line ${index} missing right border: ${line}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -5,8 +5,10 @@ import { describe, test } from "node:test";
|
|
|
5
5
|
import assert from "node:assert/strict";
|
|
6
6
|
|
|
7
7
|
import { visibleWidth } from "@gsd/pi-tui";
|
|
8
|
+
import { assertFullOuterBorder } from "./tui-border-assertions.ts";
|
|
8
9
|
import {
|
|
9
10
|
padRightVisible,
|
|
11
|
+
renderDialogFrame,
|
|
10
12
|
renderFrame,
|
|
11
13
|
renderKeyHints,
|
|
12
14
|
renderPanel,
|
|
@@ -60,6 +62,18 @@ describe("tui render kit", () => {
|
|
|
60
62
|
}
|
|
61
63
|
});
|
|
62
64
|
|
|
65
|
+
test("renderDialogFrame draws a full titled modal border with footer", () => {
|
|
66
|
+
const lines = renderDialogFrame(theme, "Dialog", ["row", "long ".repeat(40)], 40, {
|
|
67
|
+
footer: renderKeyHints(theme, ["esc close"], 36),
|
|
68
|
+
});
|
|
69
|
+
assertWidth(lines, 40);
|
|
70
|
+
assertFullOuterBorder(lines, 40);
|
|
71
|
+
assert.match(lines[0] ?? "", /^╭─ Dialog ─+╮$/);
|
|
72
|
+
assert.ok(lines.some((line) => line.startsWith("│") && line.endsWith("│")));
|
|
73
|
+
assert.ok(lines.some((line) => line.startsWith("├") && line.endsWith("┤")));
|
|
74
|
+
assert.match(lines.at(-1) ?? "", /^╰─+╯$/);
|
|
75
|
+
});
|
|
76
|
+
|
|
63
77
|
test("renderPanel stays within width and draws no vertical borders", () => {
|
|
64
78
|
for (const width of [3, 40, 80]) {
|
|
65
79
|
const lines = renderPanel(theme, "Title", ["row", "long ".repeat(40)], width);
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type SkillsPolicy,
|
|
15
15
|
type UnitContextManifest,
|
|
16
16
|
} from "../unit-context-manifest.ts";
|
|
17
|
+
import { resolveSkillManifest } from "../skill-manifest.ts";
|
|
17
18
|
import {
|
|
18
19
|
ALLOWED_PLANNING_DISPATCH_AGENTS,
|
|
19
20
|
shouldBlockPlanningUnit,
|
|
@@ -148,6 +149,23 @@ test("#4782 phase 1: skills policy shapes are valid discriminated-union members"
|
|
|
148
149
|
}
|
|
149
150
|
});
|
|
150
151
|
|
|
152
|
+
test("#4782 phase 1b: allowlist skills policy matches skill-manifest resolver", () => {
|
|
153
|
+
for (const unitType of KNOWN_UNIT_TYPES) {
|
|
154
|
+
const manifest = UNIT_MANIFESTS[unitType];
|
|
155
|
+
const allowlist = resolveSkillManifest(unitType);
|
|
156
|
+
if (allowlist) {
|
|
157
|
+
assert.strictEqual(manifest.skills.mode, "allowlist", unitType);
|
|
158
|
+
assert.deepEqual(
|
|
159
|
+
[...(manifest.skills as Extract<SkillsPolicy, { mode: "allowlist" }>).skills].sort(),
|
|
160
|
+
[...allowlist].sort(),
|
|
161
|
+
unitType,
|
|
162
|
+
);
|
|
163
|
+
} else {
|
|
164
|
+
assert.notStrictEqual(manifest.skills.mode, "allowlist", unitType);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
151
169
|
// ─── Lookup helper ────────────────────────────────────────────────────────
|
|
152
170
|
|
|
153
171
|
test("#4782 phase 1: resolveManifest returns null for an unknown unit type", () => {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import * as userInputBoundary from "../user-input-boundary.ts";
|
|
5
|
+
|
|
6
|
+
test("lastAssistantText extracts the latest assistant text block content", () => {
|
|
7
|
+
const lastAssistantText = (userInputBoundary as {
|
|
8
|
+
lastAssistantText?: (messages: unknown[] | null | undefined) => string;
|
|
9
|
+
}).lastAssistantText;
|
|
10
|
+
|
|
11
|
+
assert.equal(typeof lastAssistantText, "function");
|
|
12
|
+
assert.equal(
|
|
13
|
+
lastAssistantText?.([
|
|
14
|
+
{ role: "assistant", content: "Older message" },
|
|
15
|
+
{
|
|
16
|
+
role: "assistant",
|
|
17
|
+
content: [
|
|
18
|
+
{ type: "text", text: "First line" },
|
|
19
|
+
{ type: "text", text: "Second line" },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
]),
|
|
23
|
+
"First line\nSecond line",
|
|
24
|
+
);
|
|
25
|
+
assert.equal(lastAssistantText?.(null), "");
|
|
26
|
+
});
|