@opengsd/gsd-pi 1.2.0-dev.b1abb545 → 1.2.0-dev.d6c5343c
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/cli-style.d.ts +17 -0
- package/dist/cli-style.js +28 -0
- package/dist/cli.js +1 -1
- package/dist/headless-events.d.ts +4 -2
- package/dist/headless-events.js +14 -34
- package/dist/models-resolver.d.ts +3 -13
- package/dist/models-resolver.js +3 -22
- package/dist/resource-loader.js +2 -14
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +5 -4
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
- package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
- package/dist/resources/extensions/async-jobs/index.js +65 -0
- package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
- package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
- package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
- package/dist/resources/extensions/bg-shell/overlay.js +9 -6
- package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
- package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
- package/dist/resources/extensions/bg-shell/utilities.js +5 -2
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
- package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
- package/dist/resources/extensions/browser-tools/index.js +69 -12
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +38 -6
- package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +17 -2
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
- package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
- package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +94 -48
- package/dist/resources/extensions/gsd/auto/phases.js +8 -3
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +8 -32
- package/dist/resources/extensions/gsd/auto-dispatch.js +40 -57
- package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
- package/dist/resources/extensions/gsd/auto-post-unit.js +31 -14
- package/dist/resources/extensions/gsd/auto-prompts.js +81 -19
- package/dist/resources/extensions/gsd/auto-start.js +24 -26
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +12 -20
- package/dist/resources/extensions/gsd/auto-verification.js +9 -28
- package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
- package/dist/resources/extensions/gsd/auto.js +8 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -12
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +229 -36
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +319 -71
- package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
- package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
- package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
- package/dist/resources/extensions/gsd/captures.js +5 -15
- package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
- package/dist/resources/extensions/gsd/consent-question.js +337 -0
- package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
- package/dist/resources/extensions/gsd/constants.js +0 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
- package/dist/resources/extensions/gsd/db/engine.js +755 -0
- package/dist/resources/extensions/gsd/db/queries.js +398 -0
- package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
- package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
- package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
- package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
- package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
- package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
- package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
- package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
- package/dist/resources/extensions/gsd/doctor-format.js +9 -6
- package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
- package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
- package/dist/resources/extensions/gsd/error-classifier.js +9 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
- package/dist/resources/extensions/gsd/files.js +33 -19
- package/dist/resources/extensions/gsd/git-service.js +1 -0
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
- package/dist/resources/extensions/gsd/guidance.js +158 -0
- package/dist/resources/extensions/gsd/guided-flow.js +51 -5
- package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
- package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
- package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
- package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
- package/dist/resources/extensions/gsd/milestone-closeout.js +13 -23
- package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
- package/dist/resources/extensions/gsd/model-router.js +3 -0
- package/dist/resources/extensions/gsd/notification-store.js +11 -4
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
- package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
- package/dist/resources/extensions/gsd/paths.js +37 -24
- package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
- package/dist/resources/extensions/gsd/preferences-models.js +14 -48
- package/dist/resources/extensions/gsd/preferences.js +14 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +6 -4
- package/dist/resources/extensions/gsd/prompts/system.md +5 -2
- package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
- package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
- package/dist/resources/extensions/gsd/publication.js +87 -0
- package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
- package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
- package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
- package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
- package/dist/resources/extensions/gsd/state.js +6 -20
- package/dist/resources/extensions/gsd/status-guards.js +56 -8
- package/dist/resources/extensions/gsd/stop-notice.js +57 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
- package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +44 -53
- package/dist/resources/extensions/gsd/tools/exec-tool.js +10 -8
- package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
- package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
- package/dist/resources/extensions/gsd/uat-policy.js +42 -16
- package/dist/resources/extensions/gsd/undo.js +8 -7
- package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
- package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
- package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
- package/dist/resources/extensions/gsd/unit-registry.js +337 -0
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
- package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
- package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
- package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +12 -3
- package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
- package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
- package/dist/resources/extensions/gsd/worktree-root.js +28 -6
- package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
- package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
- package/dist/resources/extensions/search-the-web/native-search.js +5 -3
- package/dist/resources/extensions/shared/browser-contract.js +59 -0
- package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
- package/dist/resources/shared/package.json +3 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
- package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
- package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
- package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
- package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- 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/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +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 +8 -8
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-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/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
- package/dist/web/standalone/package.json +1 -1
- package/dist/worktree-cli.js +3 -6
- package/dist/worktree-status-banner.js +7 -11
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -0
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +4 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +8 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- 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 +4 -4
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/cli.js +6 -3
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +46 -21
- 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/env/nodejs.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
- package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
- package/packages/pi-agent-core/dist/index.d.ts +1 -0
- package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/index.js +3 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/README.md +1 -0
- package/packages/pi-ai/dist/models.generated.d.ts +192 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +166 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +3 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
- package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
- package/packages/pi-coding-agent/dist/core/tools/bash.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/utils/shell.d.ts +28 -2
- package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +9 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +5 -4
- package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
- package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
- package/src/resources/extensions/async-jobs/index.ts +79 -0
- package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
- package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
- package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
- package/src/resources/extensions/bg-shell/overlay.ts +9 -5
- package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
- package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
- package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
- package/src/resources/extensions/bg-shell/utilities.ts +5 -2
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
- package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
- package/src/resources/extensions/browser-tools/index.ts +71 -13
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +40 -4
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
- package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
- package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
- package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
- package/src/resources/extensions/gsd/auto/loop.ts +4 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +109 -51
- package/src/resources/extensions/gsd/auto/phases.ts +12 -3
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -32
- package/src/resources/extensions/gsd/auto-dispatch.ts +38 -52
- package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +37 -13
- package/src/resources/extensions/gsd/auto-prompts.ts +118 -35
- package/src/resources/extensions/gsd/auto-start.ts +24 -29
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +14 -21
- package/src/resources/extensions/gsd/auto-verification.ts +8 -26
- package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
- package/src/resources/extensions/gsd/auto.ts +20 -24
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +33 -12
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +270 -37
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +368 -78
- package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
- package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
- package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
- package/src/resources/extensions/gsd/captures.ts +5 -16
- package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
- package/src/resources/extensions/gsd/consent-question.ts +416 -0
- package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
- package/src/resources/extensions/gsd/constants.ts +0 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
- package/src/resources/extensions/gsd/db/engine.ts +809 -0
- package/src/resources/extensions/gsd/db/queries.ts +490 -0
- package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
- package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
- package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
- package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
- package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
- package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
- package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
- package/src/resources/extensions/gsd/doctor-format.ts +12 -7
- package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
- package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
- package/src/resources/extensions/gsd/error-classifier.ts +11 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/files.ts +33 -12
- package/src/resources/extensions/gsd/git-service.ts +1 -0
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
- package/src/resources/extensions/gsd/guidance.ts +217 -0
- package/src/resources/extensions/gsd/guided-flow.ts +50 -5
- package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
- package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
- package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
- package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
- package/src/resources/extensions/gsd/milestone-closeout.ts +13 -23
- package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
- package/src/resources/extensions/gsd/model-router.ts +3 -0
- package/src/resources/extensions/gsd/notification-store.ts +26 -3
- package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
- package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
- package/src/resources/extensions/gsd/paths.ts +42 -22
- package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
- package/src/resources/extensions/gsd/preferences-models.ts +12 -47
- package/src/resources/extensions/gsd/preferences.ts +18 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +6 -4
- package/src/resources/extensions/gsd/prompts/system.md +5 -2
- package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
- package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
- package/src/resources/extensions/gsd/publication.ts +122 -0
- package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
- package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
- package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
- package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
- package/src/resources/extensions/gsd/state.ts +9 -21
- package/src/resources/extensions/gsd/status-guards.ts +59 -8
- package/src/resources/extensions/gsd/stop-notice.ts +75 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +101 -26
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
- package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/consent-question.test.ts +336 -0
- package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -0
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/guidance.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +58 -15
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +74 -59
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
- package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +112 -29
- package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +109 -1
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
- package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +43 -68
- package/src/resources/extensions/gsd/tools/exec-tool.ts +9 -8
- package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
- package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
- package/src/resources/extensions/gsd/uat-policy.ts +62 -16
- package/src/resources/extensions/gsd/undo.ts +9 -8
- package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
- package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
- package/src/resources/extensions/gsd/unit-registry.ts +412 -0
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
- package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
- package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
- package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +13 -9
- package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
- package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
- package/src/resources/extensions/gsd/worktree-root.ts +29 -6
- package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
- package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
- package/src/resources/extensions/search-the-web/native-search.ts +5 -3
- package/src/resources/extensions/shared/browser-contract.ts +66 -0
- package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
- package/src/resources/shared/package.json +3 -0
- package/src/resources/skills/create-skill/references/executable-code.md +1 -1
- package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
- package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
- package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
- package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
- package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
- package/src/resources/skills/gsd-browser/SKILL.md +1 -1
- package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
- package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
- package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
- /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → jmTLg6xZmAuq_LIqKOxrH}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → jmTLg6xZmAuq_LIqKOxrH}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
|
|
6
|
+
export type GsdIntegrationProject = {
|
|
7
|
+
root: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type CreateGsdIntegrationProjectOptions = {
|
|
11
|
+
prefix?: string;
|
|
12
|
+
initialFiles?: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function projectRoot(project: GsdIntegrationProject | string): string {
|
|
16
|
+
return typeof project === "string" ? project : project.root;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function git(project: GsdIntegrationProject | string, ...args: string[]): string {
|
|
20
|
+
return execFileSync("git", args, {
|
|
21
|
+
cwd: projectRoot(project),
|
|
22
|
+
encoding: "utf-8",
|
|
23
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
24
|
+
}).trim();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createGsdIntegrationProject(
|
|
28
|
+
options: CreateGsdIntegrationProjectOptions | string = {},
|
|
29
|
+
): GsdIntegrationProject {
|
|
30
|
+
const resolvedOptions = typeof options === "string" ? { prefix: options } : options;
|
|
31
|
+
const prefix = resolvedOptions.prefix ?? "gsd-integration-";
|
|
32
|
+
const root = realpathSync(mkdtempSync(join(tmpdir(), prefix)));
|
|
33
|
+
|
|
34
|
+
git(root, "init");
|
|
35
|
+
git(root, "config", "user.email", "test@test.com");
|
|
36
|
+
git(root, "config", "user.name", "Test");
|
|
37
|
+
git(root, "config", "core.autocrlf", "false");
|
|
38
|
+
|
|
39
|
+
writeProjectFile(root, "README.md", "# test\n");
|
|
40
|
+
for (const [relativePath, content] of Object.entries(resolvedOptions.initialFiles ?? {})) {
|
|
41
|
+
writeProjectFile(root, relativePath, content);
|
|
42
|
+
}
|
|
43
|
+
git(root, "add", ".");
|
|
44
|
+
git(root, "commit", "-m", "init");
|
|
45
|
+
git(root, "branch", "-M", "main");
|
|
46
|
+
|
|
47
|
+
return { root };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function writeProjectFile(
|
|
51
|
+
project: GsdIntegrationProject | string,
|
|
52
|
+
relativePath: string,
|
|
53
|
+
content: string,
|
|
54
|
+
): string {
|
|
55
|
+
const filePath = join(projectRoot(project), relativePath);
|
|
56
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
57
|
+
writeFileSync(filePath, content, "utf-8");
|
|
58
|
+
return filePath;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function writeGsdMilestoneContext(
|
|
62
|
+
project: GsdIntegrationProject | string,
|
|
63
|
+
milestoneId: string,
|
|
64
|
+
content = `# ${milestoneId} Context\n`,
|
|
65
|
+
): string {
|
|
66
|
+
return writeProjectFile(
|
|
67
|
+
project,
|
|
68
|
+
join(".gsd", "milestones", milestoneId, "CONTEXT.md"),
|
|
69
|
+
content,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function commitAll(project: GsdIntegrationProject | string, message: string): void {
|
|
74
|
+
git(project, "add", ".");
|
|
75
|
+
git(project, "commit", "-m", message);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function cleanupGsdIntegrationProject(project: GsdIntegrationProject | string): void {
|
|
79
|
+
rmSync(projectRoot(project), { recursive: true, force: true });
|
|
80
|
+
}
|
|
@@ -731,6 +731,75 @@ test('(u) run-uat prompt promotes artifact-driven browser specs to browser-execu
|
|
|
731
731
|
}
|
|
732
732
|
});
|
|
733
733
|
|
|
734
|
+
test('(w) run-uat prompt promotes browser-executable harness specs to runtime-executable (M006/S01)', async () => {
|
|
735
|
+
const base = createFixtureBase();
|
|
736
|
+
try {
|
|
737
|
+
const uatRel = '.gsd/milestones/M006/slices/S01/S01-UAT.md';
|
|
738
|
+
const uatContent = [
|
|
739
|
+
'# S01 UAT',
|
|
740
|
+
'',
|
|
741
|
+
'## UAT Type',
|
|
742
|
+
'- UAT mode: browser-executable',
|
|
743
|
+
'',
|
|
744
|
+
'## Preconditions',
|
|
745
|
+
'- Start the local app server with `npm run start`.',
|
|
746
|
+
'- Open the app at `http://127.0.0.1:4173`.',
|
|
747
|
+
'',
|
|
748
|
+
'## Evidence',
|
|
749
|
+
'- Fresh closeout verification command: `npm run test:uat`',
|
|
750
|
+
].join('\n');
|
|
751
|
+
writeSliceFile(base, 'M006', 'S01', 'UAT', uatContent);
|
|
752
|
+
|
|
753
|
+
const prompt = await buildRunUatPrompt('M006', 'S01', uatRel, uatContent, base);
|
|
754
|
+
|
|
755
|
+
assert.match(prompt, /\*\*Detected UAT mode:\*\*\s*`runtime-executable`/);
|
|
756
|
+
assert.match(prompt, /uatType: "runtime-executable"/);
|
|
757
|
+
assert.match(prompt, /Runtime harness override/i);
|
|
758
|
+
assert.match(prompt, /Do \*\*not\*\* call `uat-service-start`/);
|
|
759
|
+
assert.doesNotMatch(prompt, /uatType: "browser-executable"/);
|
|
760
|
+
} finally {
|
|
761
|
+
cleanup(base);
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
test('(w2) run-uat prompt promotes harness from slice context when UAT only names test:server (M007/S01)', async () => {
|
|
766
|
+
const base = createFixtureBase();
|
|
767
|
+
try {
|
|
768
|
+
const uatRel = '.gsd/milestones/M007/slices/S01/S01-UAT.md';
|
|
769
|
+
const uatContent = [
|
|
770
|
+
'# S01 UAT',
|
|
771
|
+
'',
|
|
772
|
+
'## UAT Type',
|
|
773
|
+
'- UAT mode: browser-executable',
|
|
774
|
+
'',
|
|
775
|
+
'## Preconditions',
|
|
776
|
+
'- Start the dev/local verification server with `npm run test:server`.',
|
|
777
|
+
'- Open the app at the localhost URL printed by the server.',
|
|
778
|
+
].join('\n');
|
|
779
|
+
writeSliceFile(base, 'M007', 'S01', 'UAT', uatContent);
|
|
780
|
+
writeSliceFile(
|
|
781
|
+
base,
|
|
782
|
+
'M007',
|
|
783
|
+
'S01',
|
|
784
|
+
'SUMMARY',
|
|
785
|
+
[
|
|
786
|
+
'# S01 Summary',
|
|
787
|
+
'',
|
|
788
|
+
'Verification: `npm run test:uat` passed with clean browser diagnostics.',
|
|
789
|
+
].join('\n'),
|
|
790
|
+
);
|
|
791
|
+
|
|
792
|
+
const prompt = await buildRunUatPrompt('M007', 'S01', uatRel, uatContent, base);
|
|
793
|
+
|
|
794
|
+
assert.match(prompt, /\*\*Detected UAT mode:\*\*\s*`runtime-executable`/);
|
|
795
|
+
assert.match(prompt, /Runtime harness override/i);
|
|
796
|
+
assert.match(prompt, /npm run test:server/);
|
|
797
|
+
assert.match(prompt, /uatType: "runtime-executable"/);
|
|
798
|
+
} finally {
|
|
799
|
+
cleanup(base);
|
|
800
|
+
}
|
|
801
|
+
});
|
|
802
|
+
|
|
734
803
|
test('(v) run-uat prompt keeps deferred browser work artifact-driven', async () => {
|
|
735
804
|
const base = createFixtureBase();
|
|
736
805
|
try {
|
|
@@ -748,4 +817,134 @@ test('(v) run-uat prompt keeps deferred browser work artifact-driven', async ()
|
|
|
748
817
|
cleanup(base);
|
|
749
818
|
}
|
|
750
819
|
});
|
|
820
|
+
|
|
821
|
+
test('(x) checkNeedsRunUat returns runtime-executable when slice SUMMARY names a self-contained harness (M007/S01)', async () => {
|
|
822
|
+
// Regression: the dispatch gate must surface the same effective UAT mode
|
|
823
|
+
// that buildRunUatPrompt emits. When the UAT file alone declares
|
|
824
|
+
// `browser-executable` but the slice SUMMARY references `npm run test:uat`,
|
|
825
|
+
// the prompt promotes to `runtime-executable` — and so must the gate, or
|
|
826
|
+
// the auto-dispatch path requires browser tools / warms up the browser
|
|
827
|
+
// daemon (and may stop dispatch entirely) for a UAT that never touches
|
|
828
|
+
// the browser. See cursor[bot] review on PR #696.
|
|
829
|
+
const base = createFixtureBase();
|
|
830
|
+
try {
|
|
831
|
+
const roadmapDir = join(base, '.gsd', 'milestones', 'M007');
|
|
832
|
+
mkdirSync(roadmapDir, { recursive: true });
|
|
833
|
+
writeFileSync(
|
|
834
|
+
join(roadmapDir, 'M007-ROADMAP.md'),
|
|
835
|
+
[
|
|
836
|
+
'# M007: Test roadmap',
|
|
837
|
+
'',
|
|
838
|
+
'## Slices',
|
|
839
|
+
'',
|
|
840
|
+
'- [x] **S01: Only slice** `risk:low` `depends:[]`',
|
|
841
|
+
'',
|
|
842
|
+
'## Boundary Map',
|
|
843
|
+
'',
|
|
844
|
+
].join('\n'),
|
|
845
|
+
);
|
|
846
|
+
writeSliceFile(
|
|
847
|
+
base,
|
|
848
|
+
'M007',
|
|
849
|
+
'S01',
|
|
850
|
+
'UAT',
|
|
851
|
+
[
|
|
852
|
+
'# S01 UAT',
|
|
853
|
+
'',
|
|
854
|
+
'## UAT Type',
|
|
855
|
+
'- UAT mode: browser-executable',
|
|
856
|
+
'',
|
|
857
|
+
'## Preconditions',
|
|
858
|
+
'- Start the dev/local verification server with `npm run test:server`.',
|
|
859
|
+
].join('\n'),
|
|
860
|
+
);
|
|
861
|
+
writeSliceFile(
|
|
862
|
+
base,
|
|
863
|
+
'M007',
|
|
864
|
+
'S01',
|
|
865
|
+
'SUMMARY',
|
|
866
|
+
[
|
|
867
|
+
'# S01 Summary',
|
|
868
|
+
'',
|
|
869
|
+
'Verification: `npm run test:uat` passed with clean browser diagnostics.',
|
|
870
|
+
].join('\n'),
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
const state = {
|
|
874
|
+
activeMilestone: { id: 'M007', title: 'Test roadmap' },
|
|
875
|
+
activeSlice: null,
|
|
876
|
+
activeTask: null,
|
|
877
|
+
phase: 'validating-milestone',
|
|
878
|
+
recentDecisions: [],
|
|
879
|
+
blockers: [],
|
|
880
|
+
nextAction: 'Validate M007',
|
|
881
|
+
registry: [],
|
|
882
|
+
} as const;
|
|
883
|
+
|
|
884
|
+
const result = await checkNeedsRunUat(base, 'M007', state as any, { uat_dispatch: true } as any);
|
|
885
|
+
assert.deepStrictEqual(
|
|
886
|
+
result,
|
|
887
|
+
{ sliceId: 'S01', uatType: 'runtime-executable' },
|
|
888
|
+
'dispatch gate must mirror the prompt`s runtime-executable promotion so it does not require browser tools',
|
|
889
|
+
);
|
|
890
|
+
} finally {
|
|
891
|
+
cleanup(base);
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
test('(x2) checkNeedsRunUat leaves true browser-executable UAT unpromoted when no harness is referenced', async () => {
|
|
896
|
+
// Counter-test for (x): when the slice SUMMARY does NOT name a
|
|
897
|
+
// self-contained harness, the dispatch gate must still require browser
|
|
898
|
+
// tools for a genuinely browser-executable UAT.
|
|
899
|
+
const base = createFixtureBase();
|
|
900
|
+
try {
|
|
901
|
+
const roadmapDir = join(base, '.gsd', 'milestones', 'M008');
|
|
902
|
+
mkdirSync(roadmapDir, { recursive: true });
|
|
903
|
+
writeFileSync(
|
|
904
|
+
join(roadmapDir, 'M008-ROADMAP.md'),
|
|
905
|
+
[
|
|
906
|
+
'# M008: Test roadmap',
|
|
907
|
+
'',
|
|
908
|
+
'## Slices',
|
|
909
|
+
'',
|
|
910
|
+
'- [x] **S01: Only slice** `risk:low` `depends:[]`',
|
|
911
|
+
'',
|
|
912
|
+
'## Boundary Map',
|
|
913
|
+
'',
|
|
914
|
+
].join('\n'),
|
|
915
|
+
);
|
|
916
|
+
writeSliceFile(base, 'M008', 'S01', 'UAT', makeBrowserObservableUatContent('browser-executable'));
|
|
917
|
+
writeSliceFile(
|
|
918
|
+
base,
|
|
919
|
+
'M008',
|
|
920
|
+
'S01',
|
|
921
|
+
'SUMMARY',
|
|
922
|
+
[
|
|
923
|
+
'# S01 Summary',
|
|
924
|
+
'',
|
|
925
|
+
'Verification: clicked through the UI and confirmed the search box filters todos.',
|
|
926
|
+
].join('\n'),
|
|
927
|
+
);
|
|
928
|
+
|
|
929
|
+
const state = {
|
|
930
|
+
activeMilestone: { id: 'M008', title: 'Test roadmap' },
|
|
931
|
+
activeSlice: null,
|
|
932
|
+
activeTask: null,
|
|
933
|
+
phase: 'validating-milestone',
|
|
934
|
+
recentDecisions: [],
|
|
935
|
+
blockers: [],
|
|
936
|
+
nextAction: 'Validate M008',
|
|
937
|
+
registry: [],
|
|
938
|
+
} as const;
|
|
939
|
+
|
|
940
|
+
const result = await checkNeedsRunUat(base, 'M008', state as any, { uat_dispatch: true } as any);
|
|
941
|
+
assert.deepStrictEqual(
|
|
942
|
+
result,
|
|
943
|
+
{ sliceId: 'S01', uatType: 'browser-executable' },
|
|
944
|
+
'a true browser-executable UAT without a harness reference must keep its browser-executable mode',
|
|
945
|
+
);
|
|
946
|
+
} finally {
|
|
947
|
+
cleanup(base);
|
|
948
|
+
}
|
|
949
|
+
});
|
|
751
950
|
});
|
|
@@ -60,7 +60,9 @@ test("ensureProjectWorkflowMcpConfig creates .mcp.json with workflow and browser
|
|
|
60
60
|
assert.equal(typeof browserArgs[mcpArgIndex + 6], "string");
|
|
61
61
|
assert.ok((browserArgs[mcpArgIndex + 6] ?? "").length > 0, "identity-key must be non-empty");
|
|
62
62
|
assert.equal(browserArgs[mcpArgIndex + 7], "--identity-project");
|
|
63
|
-
assert.equal(browserArgs[mcpArgIndex + 8],
|
|
63
|
+
assert.equal(typeof browserArgs[mcpArgIndex + 8], "string");
|
|
64
|
+
assert.ok((browserArgs[mcpArgIndex + 8] ?? "").length > 0, "identity-project must be non-empty");
|
|
65
|
+
assert.doesNotMatch(browserArgs[mcpArgIndex + 8] ?? "", /[\\/]/, "identity-project must not be a filesystem path");
|
|
64
66
|
assert.equal((browserServer as { cwd?: string })?.cwd, projectRoot);
|
|
65
67
|
|
|
66
68
|
const settings = JSON.parse(readFileSync(join(projectRoot, ".claude", "settings.local.json"), "utf-8")) as {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import { copyFileSync, mkdtempSync, renameSync, rmSync } from "node:fs";
|
|
3
|
+
import { copyFileSync, mkdirSync, mkdtempSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import test from "node:test";
|
|
@@ -288,6 +288,90 @@ test("migration auto-check refreshes a stale open DB handle before comparing", a
|
|
|
288
288
|
}
|
|
289
289
|
});
|
|
290
290
|
|
|
291
|
+
function writeScratchMilestoneDir(base: string, milestoneId: string, file?: string): void {
|
|
292
|
+
const dir = join(base, ".gsd", "milestones", milestoneId);
|
|
293
|
+
mkdirSync(dir, { recursive: true });
|
|
294
|
+
if (file) writeFileSync(join(dir, file), `# ${milestoneId} discussion context\n`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
test("migration auto-check ignores discussion-scratch milestone dirs (CONTEXT only, no DB row)", async () => {
|
|
298
|
+
const base = makeBase();
|
|
299
|
+
try {
|
|
300
|
+
await writeGSDDirectory(projectFixture(), base); // markdown: M001 / S01 / T01
|
|
301
|
+
assert.equal(await ensureDbOpen(base), true);
|
|
302
|
+
insertMilestone({ id: "M001", title: "Legacy Milestone", status: "active" });
|
|
303
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Legacy Slice", status: "pending", risk: "medium", depends: [], demo: "Legacy slice demo", sequence: 1 });
|
|
304
|
+
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Legacy Task", status: "pending" });
|
|
305
|
+
|
|
306
|
+
// Mid-discussion artifacts: dirs with no ROADMAP and no DB row. The queued
|
|
307
|
+
// DB row is only inserted at discussion handoff, so these are expected to
|
|
308
|
+
// be DB-less — not drift, and recover must not be recommended (it would
|
|
309
|
+
// import them as ghost active milestones).
|
|
310
|
+
writeScratchMilestoneDir(base, "M002", "M002-CONTEXT.md");
|
|
311
|
+
writeScratchMilestoneDir(base, "M003", "M003-CONTEXT-DRAFT.md");
|
|
312
|
+
writeScratchMilestoneDir(base, "M004"); // empty dir
|
|
313
|
+
|
|
314
|
+
const result = await checkMarkdownHierarchyAgainstDb(base);
|
|
315
|
+
assert.equal(result.action, "none");
|
|
316
|
+
assert.equal(result.reason, "in-sync");
|
|
317
|
+
assert.deepEqual(result.markdown, { milestones: 1, slices: 1, tasks: 1 });
|
|
318
|
+
} finally {
|
|
319
|
+
cleanup(base);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("migration auto-check stays quiet mid-first-discussion (scratch dir over empty DB)", async () => {
|
|
324
|
+
const base = makeBase();
|
|
325
|
+
try {
|
|
326
|
+
await writeGSDDirectory({ projectContent: "# P\n", decisionsContent: "", requirements: [], milestones: [] }, base);
|
|
327
|
+
assert.equal(await ensureDbOpen(base), true);
|
|
328
|
+
writeScratchMilestoneDir(base, "M001", "M001-CONTEXT.md");
|
|
329
|
+
|
|
330
|
+
const result = await checkMarkdownHierarchyAgainstDb(base);
|
|
331
|
+
assert.equal(result.action, "none");
|
|
332
|
+
assert.equal(result.reason, "no-markdown");
|
|
333
|
+
} finally {
|
|
334
|
+
cleanup(base);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("migration auto-check still reports real drift with scratch dirs excluded from counts", async () => {
|
|
339
|
+
const base = makeBase();
|
|
340
|
+
try {
|
|
341
|
+
await writeGSDDirectory(projectFixture(), base); // markdown: M001 / S01 / T01, DB empty
|
|
342
|
+
assert.equal(await ensureDbOpen(base), true);
|
|
343
|
+
writeScratchMilestoneDir(base, "M002", "M002-CONTEXT.md");
|
|
344
|
+
|
|
345
|
+
const result = await checkMarkdownHierarchyAgainstDb(base);
|
|
346
|
+
assert.equal(result.action, "recovery-required");
|
|
347
|
+
assert.equal(result.reason, "db-empty");
|
|
348
|
+
assert.equal(result.recoveryCommand, "/gsd recover --confirm");
|
|
349
|
+
// The scratch dir must not inflate the reported markdown count.
|
|
350
|
+
assert.deepEqual(result.markdown, { milestones: 1, slices: 1, tasks: 1 });
|
|
351
|
+
} finally {
|
|
352
|
+
cleanup(base);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("migration auto-check still compares a roadmapless milestone that HAS a DB row", async () => {
|
|
357
|
+
const base = makeBase();
|
|
358
|
+
try {
|
|
359
|
+
await writeGSDDirectory({ projectContent: "# P\n", decisionsContent: "", requirements: [], milestones: [] }, base);
|
|
360
|
+
assert.equal(await ensureDbOpen(base), true);
|
|
361
|
+
// Post-handoff queued milestone: CONTEXT-only dir WITH a DB row. It must
|
|
362
|
+
// stay in the comparison (both sides have it → in-sync).
|
|
363
|
+
insertMilestone({ id: "M001", title: "M001", status: "queued" });
|
|
364
|
+
writeScratchMilestoneDir(base, "M001", "M001-CONTEXT.md");
|
|
365
|
+
|
|
366
|
+
const result = await checkMarkdownHierarchyAgainstDb(base);
|
|
367
|
+
assert.equal(result.action, "none");
|
|
368
|
+
assert.equal(result.reason, "in-sync");
|
|
369
|
+
assert.deepEqual(result.markdown, { milestones: 1, slices: 0, tasks: 0 });
|
|
370
|
+
} finally {
|
|
371
|
+
cleanup(base);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
291
375
|
test("rebuildMarkdownProjectionsFromDb realigns markdown when DB holds extra rows", async () => {
|
|
292
376
|
const base = makeBase();
|
|
293
377
|
try {
|
|
@@ -14,7 +14,7 @@ import { tmpdir } from "node:os";
|
|
|
14
14
|
import { resolveExpectedArtifactPath } from "../auto-artifact-paths.ts";
|
|
15
15
|
import { unitPhaseLabel, unitVerb } from "../auto-dashboard.ts";
|
|
16
16
|
import { classifyUnitPhase } from "../metrics.ts";
|
|
17
|
-
import { resolveModelWithFallbacksForUnit } from "../preferences-models.ts";
|
|
17
|
+
import { resolveDefaultSessionModel, resolveModelWithFallbacksForUnit } from "../preferences-models.ts";
|
|
18
18
|
import { KNOWN_UNIT_LABELS } from "../preferences-types.ts";
|
|
19
19
|
|
|
20
20
|
function withModelPreferences<T>(fn: () => T): T {
|
|
@@ -92,6 +92,37 @@ test("run-uat falls back to completion when uat bucket is not configured", () =>
|
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
+
test("default session model resolves from the explicit project base path", () => {
|
|
96
|
+
const oldHome = process.env.GSD_HOME;
|
|
97
|
+
const originalCwd = process.cwd();
|
|
98
|
+
const home = mkdtempSync(join(tmpdir(), "gsd-model-map-home-"));
|
|
99
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-model-map-project-"));
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
process.env.GSD_HOME = home;
|
|
103
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
104
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), [
|
|
105
|
+
"---",
|
|
106
|
+
"models:",
|
|
107
|
+
" execution: gpt-5.5",
|
|
108
|
+
"---",
|
|
109
|
+
"",
|
|
110
|
+
].join("\n"));
|
|
111
|
+
process.chdir(home);
|
|
112
|
+
|
|
113
|
+
assert.deepEqual(resolveDefaultSessionModel("openai-codex", base), {
|
|
114
|
+
provider: "openai-codex",
|
|
115
|
+
id: "gpt-5.5",
|
|
116
|
+
});
|
|
117
|
+
} finally {
|
|
118
|
+
process.chdir(originalCwd);
|
|
119
|
+
if (oldHome === undefined) delete process.env.GSD_HOME;
|
|
120
|
+
else process.env.GSD_HOME = oldHome;
|
|
121
|
+
rmSync(home, { recursive: true, force: true });
|
|
122
|
+
rmSync(base, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
95
126
|
test("every known unit label with a dispatch phase resolves when all model buckets are configured", () => {
|
|
96
127
|
withModelPreferences(() => {
|
|
97
128
|
const missing = KNOWN_UNIT_LABELS.filter((unitType) => !resolveModelWithFallbacksForUnit(unitType));
|
|
@@ -306,6 +306,38 @@ describe("notification-store", () => {
|
|
|
306
306
|
rmSync(lockPath, { force: true });
|
|
307
307
|
});
|
|
308
308
|
|
|
309
|
+
test("structured meta persists kind and scope on the entry", () => {
|
|
310
|
+
initNotificationStore(tmp);
|
|
311
|
+
appendNotification("Auto-mode blocked — validation gate", "warning", "notify", { kind: "auto-stop", scope: "M005" });
|
|
312
|
+
|
|
313
|
+
const entries = readNotifications();
|
|
314
|
+
assert.equal(entries.length, 1);
|
|
315
|
+
assert.equal(entries[0].kind, "auto-stop");
|
|
316
|
+
assert.equal(entries[0].scope, "M005");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test("dedup keys on kind+scope when present, not on prose", () => {
|
|
320
|
+
initNotificationStore(tmp);
|
|
321
|
+
appendNotification("Auto-mode blocked — validation gate", "warning", "notify", { kind: "auto-stop", scope: "M005" });
|
|
322
|
+
// Rephrased message, same structured identity → deduped within the window
|
|
323
|
+
appendNotification("Auto-mode blocked — gate rejected", "warning", "notify", { kind: "auto-stop", scope: "M005" });
|
|
324
|
+
// Same kind, different scope → distinct
|
|
325
|
+
appendNotification("Auto-mode blocked — validation gate", "warning", "notify", { kind: "auto-stop", scope: "M006" });
|
|
326
|
+
|
|
327
|
+
assert.equal(readNotifications().length, 2);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("readNotifications filters by kind and scope", () => {
|
|
331
|
+
initNotificationStore(tmp);
|
|
332
|
+
appendNotification("a", "info", "notify", { kind: "auto-stop", scope: "M005" });
|
|
333
|
+
appendNotification("b", "info", "notify", { kind: "provider-error-pause", scope: "M005" });
|
|
334
|
+
appendNotification("c", "info");
|
|
335
|
+
|
|
336
|
+
assert.equal(readNotifications(tmp, { kind: "auto-stop" }).length, 1);
|
|
337
|
+
assert.equal(readNotifications(tmp, { scope: "M005" }).length, 2);
|
|
338
|
+
assert.equal(readNotifications(tmp, { kind: "provider-error-pause", scope: "M005" })[0].message, "b");
|
|
339
|
+
});
|
|
340
|
+
|
|
309
341
|
test("listeners are notified on append, markAllRead, and clear", () => {
|
|
310
342
|
initNotificationStore(tmp);
|
|
311
343
|
let calls = 0;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth/subscription vs pay-per-token API routing for bare model IDs.
|
|
3
|
+
*
|
|
4
|
+
* When the same model ID (e.g. gpt-5.5) exists on multiple providers, resolveModelId
|
|
5
|
+
* must prefer subscription/OAuth routes over platform API keys.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { MODELS } from "../../../../../packages/pi-ai/dist/models.generated.js";
|
|
11
|
+
import {
|
|
12
|
+
BARE_ID_SUBSCRIPTION_PROVIDER_PRECEDENCE,
|
|
13
|
+
resolveModelId,
|
|
14
|
+
} from "../auto-model-selection.js";
|
|
15
|
+
|
|
16
|
+
type ModelRef = { id: string; provider: string };
|
|
17
|
+
|
|
18
|
+
function modelsForProviders(modelId: string, providers: string[]): ModelRef[] {
|
|
19
|
+
return providers.map((provider) => ({ id: modelId, provider }));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Table-driven precedence cases — one row per conflict shape, not per model ID. */
|
|
23
|
+
const PRECEDENCE_CASES: Array<{
|
|
24
|
+
label: string;
|
|
25
|
+
modelId: string;
|
|
26
|
+
providers: string[];
|
|
27
|
+
expected: string;
|
|
28
|
+
currentProvider?: string;
|
|
29
|
+
}> = [
|
|
30
|
+
{
|
|
31
|
+
label: "ChatGPT OAuth beats OpenAI API (gpt-5.5)",
|
|
32
|
+
modelId: "gpt-5.5",
|
|
33
|
+
providers: ["openai", "openai-codex"],
|
|
34
|
+
expected: "openai-codex",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: "Codex beats Copilot beats OpenAI API (gpt-5.5 triple)",
|
|
38
|
+
modelId: "gpt-5.5",
|
|
39
|
+
providers: ["openai", "github-copilot", "openai-codex"],
|
|
40
|
+
expected: "openai-codex",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: "Copilot OAuth beats OpenAI API when no Codex (gpt-5.5)",
|
|
44
|
+
modelId: "gpt-5.5",
|
|
45
|
+
providers: ["openai", "github-copilot"],
|
|
46
|
+
expected: "github-copilot",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: "Copilot OAuth beats OpenAI API (gpt-5-mini)",
|
|
50
|
+
modelId: "gpt-5-mini",
|
|
51
|
+
providers: ["openai", "github-copilot"],
|
|
52
|
+
expected: "github-copilot",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: "Anthropic beats Copilot for Claude (claude-sonnet-4-6)",
|
|
56
|
+
modelId: "claude-sonnet-4-6",
|
|
57
|
+
providers: ["anthropic", "github-copilot"],
|
|
58
|
+
expected: "anthropic",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
label: "Copilot beats Google API for Gemini (gemini-2.5-pro)",
|
|
62
|
+
modelId: "gemini-2.5-pro",
|
|
63
|
+
providers: ["google", "github-copilot"],
|
|
64
|
+
expected: "github-copilot",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
label: "Gemini CLI beats Google API (gemini-2.5-pro)",
|
|
68
|
+
modelId: "gemini-2.5-pro",
|
|
69
|
+
providers: ["google", "google-gemini-cli"],
|
|
70
|
+
expected: "google-gemini-cli",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
label: "Gemini CLI beats Copilot beats Google API",
|
|
74
|
+
modelId: "gemini-2.5-pro",
|
|
75
|
+
providers: ["google", "github-copilot", "google-gemini-cli"],
|
|
76
|
+
expected: "google-gemini-cli",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: "Session provider still wins (openai-codex explicit)",
|
|
80
|
+
modelId: "gpt-5.5",
|
|
81
|
+
providers: ["openai", "openai-codex", "github-copilot"],
|
|
82
|
+
expected: "github-copilot",
|
|
83
|
+
currentProvider: "github-copilot",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: "claude-code session beats anthropic (#3772)",
|
|
87
|
+
modelId: "claude-sonnet-4-6",
|
|
88
|
+
providers: ["anthropic", "claude-code"],
|
|
89
|
+
expected: "claude-code",
|
|
90
|
+
currentProvider: "claude-code",
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
for (const row of PRECEDENCE_CASES) {
|
|
95
|
+
test(`resolveModelId precedence: ${row.label}`, () => {
|
|
96
|
+
const available = modelsForProviders(row.modelId, row.providers);
|
|
97
|
+
const result = resolveModelId(row.modelId, available, row.currentProvider);
|
|
98
|
+
assert.ok(result, `expected a match for ${row.modelId}`);
|
|
99
|
+
assert.equal(result.provider, row.expected);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
test("BARE_ID_SUBSCRIPTION_PROVIDER_PRECEDENCE covers known OAuth/subscription providers", () => {
|
|
104
|
+
const expected = [
|
|
105
|
+
"openai-codex",
|
|
106
|
+
"google-gemini-cli",
|
|
107
|
+
"anthropic",
|
|
108
|
+
"github-copilot",
|
|
109
|
+
"google-antigravity",
|
|
110
|
+
];
|
|
111
|
+
assert.deepEqual([...BARE_ID_SUBSCRIPTION_PROVIDER_PRECEDENCE], expected);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("every catalog overlap with OAuth/subscription + API resolves to subscription route", () => {
|
|
115
|
+
const oauthProviders = new Set(["anthropic", "github-copilot", "openai-codex"]);
|
|
116
|
+
const subscriptionCli = new Set(["google-gemini-cli", "google-antigravity", "claude-code"]);
|
|
117
|
+
const apiPayPerToken = new Set(["openai", "google", "azure-openai-responses"]);
|
|
118
|
+
|
|
119
|
+
const byId = new Map<string, Set<string>>();
|
|
120
|
+
for (const [provider, models] of Object.entries(MODELS)) {
|
|
121
|
+
for (const id of Object.keys(models)) {
|
|
122
|
+
if (!byId.has(id)) byId.set(id, new Set());
|
|
123
|
+
byId.get(id)!.add(provider);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const failures: string[] = [];
|
|
128
|
+
|
|
129
|
+
for (const [modelId, providers] of byId) {
|
|
130
|
+
if (providers.size < 2) continue;
|
|
131
|
+
|
|
132
|
+
const hasApi = [...providers].some((p) => apiPayPerToken.has(p));
|
|
133
|
+
const subscriptionCandidates = [...providers].filter(
|
|
134
|
+
(p) => oauthProviders.has(p) || subscriptionCli.has(p),
|
|
135
|
+
);
|
|
136
|
+
if (!hasApi || subscriptionCandidates.length === 0) continue;
|
|
137
|
+
|
|
138
|
+
const testProviders = new Set<string>(subscriptionCandidates);
|
|
139
|
+
for (const p of providers) {
|
|
140
|
+
if (apiPayPerToken.has(p)) testProviders.add(p);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const available = modelsForProviders(modelId, [...testProviders]);
|
|
144
|
+
const result = resolveModelId(modelId, available, undefined);
|
|
145
|
+
if (!result) {
|
|
146
|
+
failures.push(`${modelId}: no resolution among ${[...testProviders].join(", ")}`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const winnerIsSubscription =
|
|
151
|
+
oauthProviders.has(result.provider) ||
|
|
152
|
+
subscriptionCli.has(result.provider) ||
|
|
153
|
+
result.provider === "anthropic";
|
|
154
|
+
|
|
155
|
+
if (!winnerIsSubscription) {
|
|
156
|
+
failures.push(
|
|
157
|
+
`${modelId}: got ${result.provider}, expected subscription route among ${[...testProviders].join(", ")}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
assert.equal(
|
|
163
|
+
failures.length,
|
|
164
|
+
0,
|
|
165
|
+
`catalog overlap routing failures:\n${failures.join("\n")}`,
|
|
166
|
+
);
|
|
167
|
+
});
|