@opengsd/gsd-pi 1.2.0-dev.b1abb545 → 1.2.0-dev.e8563f58
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/mcp-server.js +2 -1
- 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 +122 -58
- 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 +36 -13
- 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 +15 -20
- package/dist/resources/extensions/gsd/blocked-models.js +28 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +29 -8
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -12
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
- 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/closeout-wizard.js +92 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
- package/dist/resources/extensions/gsd/commands-handlers.js +46 -3
- package/dist/resources/extensions/gsd/consent-question.js +353 -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 +6 -21
- 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-command-home.js +22 -12
- package/dist/resources/extensions/gsd/gsd-db.js +172 -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 +85 -24
- 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/tools/workflow-tool-executors.js +67 -2
- 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 +116 -6
- package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
- package/dist/resources/shared/package-manager-detection.js +1 -1
- 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/update-check.d.ts +2 -0
- package/dist/update-check.js +24 -1
- package/dist/update-cmd.js +20 -3
- 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 +2 -2
- 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/node_modules/node-pty/build/Makefile +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/moonshot-tool-schema.d.ts +29 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +4 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +26 -18
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +145 -59
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +5 -4
- 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/index.d.ts +2 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +2 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- 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/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +12 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
- package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +12 -3
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +6 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.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 +40 -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 +137 -61
- 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 +41 -12
- 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 +28 -24
- package/src/resources/extensions/gsd/blocked-models.ts +49 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +37 -10
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +33 -12
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
- 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/closeout-wizard.ts +102 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
- package/src/resources/extensions/gsd/commands-handlers.ts +46 -3
- package/src/resources/extensions/gsd/consent-question.ts +431 -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 +5 -22
- 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-command-home.ts +13 -3
- package/src/resources/extensions/gsd/gsd-db.ts +176 -2375
- 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 +109 -24
- 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 +91 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +198 -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/blocked-models.test.ts +19 -0
- 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 +351 -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/doctor-git-checks-terminal.test.ts +73 -0
- 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-command-home.test.ts +120 -0
- 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/milestone-closeout.test.ts +95 -4
- 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 +138 -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 +275 -40
- 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/tools/workflow-tool-executors.ts +81 -2
- 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 +141 -6
- package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
- package/src/resources/shared/package-manager-detection.ts +1 -1
- 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 → LDHRKiRBIVZmiuMjrL1Vy}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → LDHRKiRBIVZmiuMjrL1Vy}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import { createBashTool } from "@gsd/pi-coding-agent";
|
|
5
|
+
|
|
6
|
+
import { registerDynamicTools } from "../bootstrap/dynamic-tools.ts";
|
|
7
|
+
import { createAsyncBashTool } from "../../async-jobs/async-bash-tool.ts";
|
|
8
|
+
|
|
9
|
+
// These tests assert on the runtime tool objects the agent actually receives —
|
|
10
|
+
// the registered GSD bash tool, the core bash tool, and the async_bash tool —
|
|
11
|
+
// not on source text. The behavioral guarantee (an explicit timeout still
|
|
12
|
+
// fires after the silent 120s cap was removed) is exercised by spawning a real
|
|
13
|
+
// process at the bottom of the file.
|
|
14
|
+
|
|
15
|
+
/** Capture the GSD-registered `bash` tool object from registerDynamicTools. */
|
|
16
|
+
function registerAndCaptureBash(): any {
|
|
17
|
+
let captured: any = undefined;
|
|
18
|
+
const pi = {
|
|
19
|
+
registerTool: (tool: any) => {
|
|
20
|
+
if (!captured && tool && tool.name === "bash") captured = tool;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
registerDynamicTools(pi as any);
|
|
24
|
+
assert.ok(captured, "registerDynamicTools must register a tool named 'bash'");
|
|
25
|
+
return captured;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 1. Cap removal: the GSD bash tool no longer injects a default timeout. The
|
|
29
|
+
// schema's timeout stays optional (no `default`), so an omitted timeout
|
|
30
|
+
// means "no timeout" rather than a silent 120s cap.
|
|
31
|
+
test("GSD bash tool exposes an optional timeout with no injected default", () => {
|
|
32
|
+
const bash = registerAndCaptureBash();
|
|
33
|
+
const timeout = bash.parameters?.properties?.timeout;
|
|
34
|
+
assert.ok(timeout, "bash tool must expose a `timeout` parameter");
|
|
35
|
+
assert.equal(
|
|
36
|
+
"default" in timeout,
|
|
37
|
+
false,
|
|
38
|
+
"the timeout schema must not carry a default — an omitted timeout means uncapped",
|
|
39
|
+
);
|
|
40
|
+
assert.equal(
|
|
41
|
+
bash.parameters?.required?.includes?.("timeout") ?? false,
|
|
42
|
+
false,
|
|
43
|
+
"timeout must remain optional",
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 2. Watchdog verbiage is GSD-scoped: the core bash tool (reused by non-GSD
|
|
48
|
+
// embeddings with no watchdog) must NOT claim a watchdog, while the
|
|
49
|
+
// GSD-registered tool injects it into both description and timeout schema.
|
|
50
|
+
test("core bash tool does not advertise the auto-mode watchdog", () => {
|
|
51
|
+
const core = createBashTool(process.cwd(), { spawnHook: (c: any) => c });
|
|
52
|
+
assert.equal(
|
|
53
|
+
/stalled-tool watchdog/.test(core.description ?? ""),
|
|
54
|
+
false,
|
|
55
|
+
"core bash must not advertise a watchdog — non-GSD embeddings have none",
|
|
56
|
+
);
|
|
57
|
+
assert.equal(
|
|
58
|
+
/stalled-tool watchdog/.test(
|
|
59
|
+
(core.parameters as any)?.properties?.timeout?.description ?? "",
|
|
60
|
+
),
|
|
61
|
+
false,
|
|
62
|
+
"core bash timeout schema must not advertise a watchdog",
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("GSD-registered bash tool advertises the stalled-tool watchdog", () => {
|
|
67
|
+
const bash = registerAndCaptureBash();
|
|
68
|
+
assert.equal(
|
|
69
|
+
/stalled-tool watchdog/.test(bash.description ?? ""),
|
|
70
|
+
true,
|
|
71
|
+
"the GSD bash description must name the stalled-tool watchdog",
|
|
72
|
+
);
|
|
73
|
+
assert.equal(
|
|
74
|
+
/stalled-tool watchdog/.test(
|
|
75
|
+
bash.parameters?.properties?.timeout?.description ?? "",
|
|
76
|
+
),
|
|
77
|
+
true,
|
|
78
|
+
"the GSD bash timeout schema must name the stalled-tool watchdog",
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// 3. async_bash guidance frames itself as a non-blocking/background choice and
|
|
83
|
+
// no longer implies sync bash is time-capped.
|
|
84
|
+
test("async_bash guidance is non-blocking and drops the sync-cap implication", () => {
|
|
85
|
+
const asyncTool: any = createAsyncBashTool(
|
|
86
|
+
() => ({ register: () => "job-0" }) as any,
|
|
87
|
+
() => process.cwd(),
|
|
88
|
+
);
|
|
89
|
+
const guidance = (asyncTool.promptGuidelines ?? []).join("\n");
|
|
90
|
+
assert.equal(
|
|
91
|
+
/more than a few seconds/.test(guidance),
|
|
92
|
+
false,
|
|
93
|
+
"async_bash guidance must not imply sync bash is time-capped",
|
|
94
|
+
);
|
|
95
|
+
assert.equal(
|
|
96
|
+
/non-blocking/.test(guidance),
|
|
97
|
+
true,
|
|
98
|
+
"async_bash guidance must describe itself as non-blocking",
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// 4. Behavioral passthrough: an explicitly-set timeout is still honored after
|
|
103
|
+
// the cap removal. A 1s timeout on a 5s sleep must fire well under 5s.
|
|
104
|
+
test("GSD bash still forwards an explicit timeout (cap removal did not break passthrough)", async () => {
|
|
105
|
+
const bash = registerAndCaptureBash();
|
|
106
|
+
|
|
107
|
+
const start = Date.now();
|
|
108
|
+
let resultText = "";
|
|
109
|
+
try {
|
|
110
|
+
const result: any = await bash.execute(
|
|
111
|
+
"t1",
|
|
112
|
+
{ command: "sleep 5", timeout: 1 },
|
|
113
|
+
undefined,
|
|
114
|
+
undefined,
|
|
115
|
+
{ cwd: process.cwd() },
|
|
116
|
+
);
|
|
117
|
+
resultText = JSON.stringify(result ?? "");
|
|
118
|
+
} catch (err) {
|
|
119
|
+
resultText = String(err instanceof Error ? err.message : err);
|
|
120
|
+
}
|
|
121
|
+
const elapsed = Date.now() - start;
|
|
122
|
+
|
|
123
|
+
assert.equal(
|
|
124
|
+
/timed out|timeout|exited with code|force-killed/i.test(resultText),
|
|
125
|
+
true,
|
|
126
|
+
`explicit 1s timeout should fire before the 5s sleep completes; got: ${resultText}`,
|
|
127
|
+
);
|
|
128
|
+
assert.ok(
|
|
129
|
+
elapsed < 4500,
|
|
130
|
+
`explicit timeout should fire quickly, not run to completion (elapsed ${elapsed}ms)`,
|
|
131
|
+
);
|
|
132
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Engine hook contract: which tool lifecycle hooks fire under which engine,
|
|
2
|
+
// and the consolidated tool-name normalizer seam.
|
|
3
|
+
//
|
|
4
|
+
// 1. Pins the contract arrays (engine-hook-contract.ts) so a change to the
|
|
5
|
+
// fire matrix is a deliberate, reviewed act.
|
|
6
|
+
// 2. Source-scans register-hooks.ts (in the style of
|
|
7
|
+
// single-writer-invariant.test.ts) to assert that the concerns documented
|
|
8
|
+
// as universally mirrored — evidence collection and write-gate (re-)arming —
|
|
9
|
+
// actually live inside a tool_execution_start handler, not only in the
|
|
10
|
+
// native-only tool_call handlers.
|
|
11
|
+
// 3. Pins normalizer parity: canonicalHeadlessToolName delegates to
|
|
12
|
+
// canonicalToolName (strip-only), and canonicalWorkflowToolName adds alias
|
|
13
|
+
// resolution on top of the same strip.
|
|
14
|
+
|
|
15
|
+
import test from "node:test";
|
|
16
|
+
import assert from "node:assert/strict";
|
|
17
|
+
import { readFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
UNIVERSAL_TOOL_HOOKS,
|
|
22
|
+
NATIVE_ONLY_TOOL_HOOKS,
|
|
23
|
+
canonicalToolName,
|
|
24
|
+
canonicalWorkflowToolName,
|
|
25
|
+
} from "../engine-hook-contract.js";
|
|
26
|
+
import { canonicalHeadlessToolName } from "../../../../headless-events.js";
|
|
27
|
+
import { WORKFLOW_TOOL_ALIAS_PAIRS } from "../workflow-tool-surface.js";
|
|
28
|
+
|
|
29
|
+
test("contract arrays pin the verified fire matrix", () => {
|
|
30
|
+
assert.deepEqual([...UNIVERSAL_TOOL_HOOKS], ["tool_execution_start", "tool_execution_end"]);
|
|
31
|
+
assert.deepEqual([...NATIVE_ONLY_TOOL_HOOKS], ["tool_call", "tool_result"]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Source scan: register-hooks.ts must mirror safety concerns universally
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
const registerHooksSource = readFileSync(
|
|
39
|
+
join(process.cwd(), "src/resources/extensions/gsd/bootstrap/register-hooks.ts"),
|
|
40
|
+
"utf8",
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Extract the body of every `pi.on("<eventName>", ...)` registration by
|
|
45
|
+
* scanning balanced parentheses from each registration site.
|
|
46
|
+
*/
|
|
47
|
+
function hookBodies(source: string, eventName: string): string[] {
|
|
48
|
+
const bodies: string[] = [];
|
|
49
|
+
const marker = `pi.on("${eventName}"`;
|
|
50
|
+
let from = 0;
|
|
51
|
+
for (;;) {
|
|
52
|
+
const start = source.indexOf(marker, from);
|
|
53
|
+
if (start < 0) break;
|
|
54
|
+
let depth = 0;
|
|
55
|
+
let end = -1;
|
|
56
|
+
// Scan from pi.on's own opening paren so the whole registration is balanced.
|
|
57
|
+
for (let i = start + "pi.on".length; i < source.length; i++) {
|
|
58
|
+
const ch = source[i];
|
|
59
|
+
if (ch === "(") depth++;
|
|
60
|
+
else if (ch === ")") {
|
|
61
|
+
depth--;
|
|
62
|
+
if (depth === 0) {
|
|
63
|
+
end = i;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
assert.ok(end > start, `unbalanced pi.on("${eventName}") registration`);
|
|
69
|
+
bodies.push(source.slice(start, end + 1));
|
|
70
|
+
from = end + 1;
|
|
71
|
+
}
|
|
72
|
+
return bodies;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
test("tool_execution_start handler mirrors evidence collection and write-gate arming", () => {
|
|
76
|
+
const bodies = hookBodies(registerHooksSource, "tool_execution_start");
|
|
77
|
+
assert.ok(bodies.length >= 1, "register-hooks.ts must register a tool_execution_start handler");
|
|
78
|
+
const merged = bodies.join("\n");
|
|
79
|
+
|
|
80
|
+
// Evidence collection: the safety harness records the call on the universal
|
|
81
|
+
// hook (deduped by toolCallId against the native-only tool_call recording).
|
|
82
|
+
assert.match(merged, /safetyRecordToolCall\(/);
|
|
83
|
+
assert.match(merged, /saveEvidenceToDisk\(/);
|
|
84
|
+
|
|
85
|
+
// Write-gate (re-)arming: external engines never reach the tool_call
|
|
86
|
+
// deferApprovalGate path, so the durable pending gate must be armed here.
|
|
87
|
+
assert.match(merged, /hostWriteGateAdapter\.setPending\(/);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("mirrored concerns also exist on the native-only tool_call side (dedup pairing)", () => {
|
|
91
|
+
const bodies = hookBodies(registerHooksSource, "tool_call");
|
|
92
|
+
assert.ok(bodies.length >= 1, "register-hooks.ts must register tool_call handlers");
|
|
93
|
+
const merged = bodies.join("\n");
|
|
94
|
+
assert.match(merged, /safetyRecordToolCall\(/);
|
|
95
|
+
assert.match(merged, /deferApprovalGate\(/);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("tool_execution_end handler mirrors error classification and evidence persistence", () => {
|
|
99
|
+
const bodies = hookBodies(registerHooksSource, "tool_execution_end");
|
|
100
|
+
assert.ok(bodies.length >= 1, "register-hooks.ts must register a tool_execution_end handler");
|
|
101
|
+
const merged = bodies.join("\n");
|
|
102
|
+
assert.match(merged, /recordToolInvocationError\(/);
|
|
103
|
+
assert.match(merged, /safetyRecordToolResult\(/);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Normalizer parity
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
test("canonicalHeadlessToolName matches canonicalToolName on the edge-case table", () => {
|
|
111
|
+
const cases: Array<{ input: string; expected: string }> = [
|
|
112
|
+
{ input: "mcp__server__tool", expected: "tool" },
|
|
113
|
+
{ input: "mcp__gsd-workflow__gsd_status", expected: "gsd_status" },
|
|
114
|
+
{ input: "plain", expected: "plain" },
|
|
115
|
+
{ input: "ask_user_questions", expected: "ask_user_questions" },
|
|
116
|
+
// Nested underscores: only the first server/tool delimiter splits.
|
|
117
|
+
{ input: "mcp__s__a__b", expected: "a__b" },
|
|
118
|
+
{ input: "", expected: "" },
|
|
119
|
+
{ input: "mcp__", expected: "mcp__" },
|
|
120
|
+
// Malformed names stay unchanged (strict parser: empty server/tool → no strip).
|
|
121
|
+
{ input: "mcp____tool", expected: "mcp____tool" },
|
|
122
|
+
{ input: "mcp__server__", expected: "mcp__server__" },
|
|
123
|
+
];
|
|
124
|
+
for (const { input, expected } of cases) {
|
|
125
|
+
assert.equal(canonicalToolName(input), expected, `canonicalToolName(${JSON.stringify(input)})`);
|
|
126
|
+
assert.equal(
|
|
127
|
+
canonicalHeadlessToolName(input),
|
|
128
|
+
canonicalToolName(input),
|
|
129
|
+
`headless/strip parity for ${JSON.stringify(input)}`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
assert.equal(canonicalHeadlessToolName(undefined), "");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("canonicalWorkflowToolName = prefix strip + workflow alias resolution", () => {
|
|
136
|
+
// Non-alias names behave exactly like canonicalToolName.
|
|
137
|
+
for (const name of ["mcp__server__tool", "plain", "mcp__s__a__b"]) {
|
|
138
|
+
assert.equal(canonicalWorkflowToolName(name), canonicalToolName(name));
|
|
139
|
+
}
|
|
140
|
+
// Alias names additionally resolve to the canonical workflow tool.
|
|
141
|
+
assert.ok(WORKFLOW_TOOL_ALIAS_PAIRS.length > 0, "expected at least one workflow alias");
|
|
142
|
+
for (const { alias, canonical } of WORKFLOW_TOOL_ALIAS_PAIRS) {
|
|
143
|
+
assert.equal(canonicalWorkflowToolName(alias), canonical);
|
|
144
|
+
assert.equal(canonicalWorkflowToolName(`mcp__gsd-workflow__${alias}`), canonical);
|
|
145
|
+
// Plain strip must NOT resolve aliases — that distinction is the seam.
|
|
146
|
+
assert.equal(canonicalToolName(alias), alias);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Regression tests for evidence cross-referencing of gsd_exec /
|
|
3
|
+
// gsd_uat_exec tool calls. Mirrors the live false-positive where an
|
|
4
|
+
// execute-task agent ran its verification commands through gsd_exec (script
|
|
5
|
+
// body in the `script` argument) and the cross-referencer reported
|
|
6
|
+
// "No bash tool call found" despite successful execution.
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
resetEvidence,
|
|
16
|
+
getEvidence,
|
|
17
|
+
recordToolCall,
|
|
18
|
+
recordToolResult,
|
|
19
|
+
isExecutionToolName,
|
|
20
|
+
type BashEvidence,
|
|
21
|
+
} from "../safety/evidence-collector.ts";
|
|
22
|
+
import { crossReferenceEvidence } from "../safety/evidence-cross-ref.ts";
|
|
23
|
+
|
|
24
|
+
function gsdExecResult(exitCode: number, id = "4858202d-2ed7-4a0a-9ef7-4e159e65da83"): unknown {
|
|
25
|
+
return {
|
|
26
|
+
content: [{
|
|
27
|
+
type: "text",
|
|
28
|
+
text: JSON.stringify({
|
|
29
|
+
operation: "gsd_exec",
|
|
30
|
+
id,
|
|
31
|
+
runtime: "bash",
|
|
32
|
+
exit_code: exitCode,
|
|
33
|
+
signal: null,
|
|
34
|
+
timed_out: false,
|
|
35
|
+
duration_ms: 272,
|
|
36
|
+
stdout_bytes: 592,
|
|
37
|
+
stderr_bytes: 0,
|
|
38
|
+
meta_path: `/tmp/does-not-exist/.gsd/exec/${id}.meta.json`,
|
|
39
|
+
}),
|
|
40
|
+
}],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
test("evidence-xref: verification run through gsd_exec script matches the claimed command", () => {
|
|
45
|
+
resetEvidence();
|
|
46
|
+
|
|
47
|
+
// The live false positive: agent runs `node --test tests/verify-s01.test.js`
|
|
48
|
+
// inside a gsd_exec script with a cd prefix and exit-code echo suffix.
|
|
49
|
+
recordToolCall("tc-exec-1", "gsd_exec", {
|
|
50
|
+
script: 'cd /work/.gsd/worktrees/M001 && node --test tests/verify-s01.test.js; echo "EXIT=$?"',
|
|
51
|
+
purpose: "T02: run node --test contract checks against T01 index.html",
|
|
52
|
+
});
|
|
53
|
+
recordToolResult("tc-exec-1", "gsd_exec", gsdExecResult(0), false);
|
|
54
|
+
|
|
55
|
+
const mismatches = crossReferenceEvidence(
|
|
56
|
+
[{ command: "node --test tests/verify-s01.test.js", exitCode: 0, verdict: "passed" }],
|
|
57
|
+
getEvidence(),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
assert.deepEqual(mismatches, [], "gsd_exec-executed verification must not be flagged as missing");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("evidence-xref: multi-line gsd_exec script matches claims for each embedded command", () => {
|
|
64
|
+
resetEvidence();
|
|
65
|
+
|
|
66
|
+
recordToolCall("tc-exec-2", "gsd_exec", {
|
|
67
|
+
script: [
|
|
68
|
+
"cd /work/.gsd/worktrees/M001",
|
|
69
|
+
"sed -i '' \"s/'todos'/'tasks-v1'/\" index.html",
|
|
70
|
+
"node --test tests/verify-s01.test.js > /dev/null 2>&1",
|
|
71
|
+
'echo "BROKEN_EXIT=$?"',
|
|
72
|
+
].join("\n"),
|
|
73
|
+
purpose: "T02: deliberate contract break must fail, then restore",
|
|
74
|
+
});
|
|
75
|
+
recordToolResult("tc-exec-2", "gsd_exec", gsdExecResult(0), false);
|
|
76
|
+
|
|
77
|
+
const mismatches = crossReferenceEvidence(
|
|
78
|
+
[{ command: "node --test tests/verify-s01.test.js > /dev/null 2>&1", exitCode: 0, verdict: "passed" }],
|
|
79
|
+
getEvidence(),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
assert.deepEqual(mismatches, [], "command embedded in a multi-line script must match");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("evidence-xref: claimed pass with failing gsd_exec exit_code is still an error", () => {
|
|
86
|
+
resetEvidence();
|
|
87
|
+
|
|
88
|
+
recordToolCall("tc-exec-3", "gsd_exec", {
|
|
89
|
+
script: "node --test tests/verify-s01.test.js",
|
|
90
|
+
purpose: "verification",
|
|
91
|
+
});
|
|
92
|
+
// gsd_exec reports failures via the JSON envelope's exit_code (and isError).
|
|
93
|
+
recordToolResult("tc-exec-3", "gsd_exec", gsdExecResult(1), true);
|
|
94
|
+
|
|
95
|
+
const mismatches = crossReferenceEvidence(
|
|
96
|
+
[{ command: "node --test tests/verify-s01.test.js", exitCode: 0, verdict: "passed" }],
|
|
97
|
+
getEvidence(),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
assert.equal(mismatches.length, 1);
|
|
101
|
+
assert.equal(mismatches[0].severity, "error");
|
|
102
|
+
assert.match(mismatches[0].reason, /Claimed exitCode=0 but actual exitCode=1/);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("evidence-collector: gsd_uat_exec and MCP-namespaced variants are execution tools", () => {
|
|
106
|
+
assert.equal(isExecutionToolName("gsd_uat_exec"), true);
|
|
107
|
+
assert.equal(isExecutionToolName("mcp__gsd-workflow__gsd_uat_exec"), true);
|
|
108
|
+
assert.equal(isExecutionToolName("mcp__gsd-workflow__gsd_exec"), true);
|
|
109
|
+
|
|
110
|
+
resetEvidence();
|
|
111
|
+
recordToolCall("tc-uat-1", "gsd_uat_exec", { script: "curl -fsS http://localhost:3000/health" });
|
|
112
|
+
const bash = getEvidence().filter((e): e is BashEvidence => e.kind === "bash");
|
|
113
|
+
assert.equal(bash.length, 1, "gsd_uat_exec must record bash evidence");
|
|
114
|
+
assert.equal(bash[0].command, "curl -fsS http://localhost:3000/health");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("evidence-xref: blank-command evidence does not satisfy arbitrary claims", () => {
|
|
118
|
+
// Before script extraction existed, gsd_exec calls were recorded with
|
|
119
|
+
// command: "" — and `"x".includes("")` made them match every claim,
|
|
120
|
+
// masking genuine fabrications. Blank entries must never match.
|
|
121
|
+
const mismatches = crossReferenceEvidence(
|
|
122
|
+
[{ command: "node --test tests/verify-s01.test.js", exitCode: 0, verdict: "passed" }],
|
|
123
|
+
[{
|
|
124
|
+
kind: "bash",
|
|
125
|
+
toolCallId: "tc-blank",
|
|
126
|
+
command: "",
|
|
127
|
+
exitCode: 0,
|
|
128
|
+
outputSnippet: "",
|
|
129
|
+
timestamp: 1,
|
|
130
|
+
}],
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
assert.equal(mismatches.length, 1);
|
|
134
|
+
assert.equal(mismatches[0].severity, "warning");
|
|
135
|
+
assert.match(mismatches[0].reason, /No bash tool call found/);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("evidence-collector: exit code falls back to .gsd/exec meta.json when result text omits it", (t) => {
|
|
139
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-exec-meta-"));
|
|
140
|
+
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
|
141
|
+
|
|
142
|
+
const metaPath = join(dir, "run-1.meta.json");
|
|
143
|
+
writeFileSync(metaPath, JSON.stringify({ id: "run-1", exit_code: 7 }));
|
|
144
|
+
|
|
145
|
+
resetEvidence();
|
|
146
|
+
recordToolCall("tc-meta-1", "gsd_exec", { script: "exit 7" });
|
|
147
|
+
// Truncated result: meta_path survives but exit_code was cut off.
|
|
148
|
+
recordToolResult(
|
|
149
|
+
"tc-meta-1",
|
|
150
|
+
"gsd_exec",
|
|
151
|
+
{ content: [{ type: "text", text: `{"operation":"gsd_exec","meta_path":${JSON.stringify(metaPath)}` }] },
|
|
152
|
+
false,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const bash = getEvidence().filter((e): e is BashEvidence => e.kind === "bash");
|
|
156
|
+
assert.equal(bash[0].exitCode, 7, "exit code must be recovered from meta.json");
|
|
157
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Deterministic timing tests for the exec-sandbox graceful-kill
|
|
3
|
+
// ladder + hard-deadline force-resolve (S04/T02).
|
|
4
|
+
//
|
|
5
|
+
// T01 extended runExecSandbox's timeout path to a graceful
|
|
6
|
+
// SIGTERM -> grace -> SIGKILL ladder (via killProcessTree) plus a caller-side
|
|
7
|
+
// force-resolve hard deadline so a non-closing ("D-state") child can never hang
|
|
8
|
+
// the awaiting promise. A true D-state child is non-portable, so we simulate the
|
|
9
|
+
// exact symptom deterministically:
|
|
10
|
+
// 1. A SIGTERM-cooperative child (trap 'exit 0' TERM) closes promptly on the
|
|
11
|
+
// first SIGTERM — proving the ladder resolves via `close` well before the
|
|
12
|
+
// force-resolve deadline.
|
|
13
|
+
// 2. A SIGTERM-ignoring (trap '' TERM) child combined with a LARGE
|
|
14
|
+
// kill_grace_ms (so SIGKILL never fires in-window) and a SHORT
|
|
15
|
+
// force_resolve_delay_ms — the only way the promise can settle is the
|
|
16
|
+
// hard deadline, proving the no-hang guarantee.
|
|
17
|
+
//
|
|
18
|
+
// Unlike the sync bash path (which throws on force-resolve), runExecSandbox
|
|
19
|
+
// always RESOLVES; force-resolve calls finalize(null, "SIGKILL") and preserves
|
|
20
|
+
// timed_out === true so the agent can still distinguish a graceful timeout exit
|
|
21
|
+
// from a forced kill.
|
|
22
|
+
|
|
23
|
+
import { test } from 'node:test';
|
|
24
|
+
import assert from 'node:assert/strict';
|
|
25
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
26
|
+
import { tmpdir } from 'node:os';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
|
|
29
|
+
import { EXEC_DEFAULTS, runExecSandbox, type ExecSandboxOptions } from '../exec-sandbox.ts';
|
|
30
|
+
|
|
31
|
+
const isWin = process.platform === 'win32';
|
|
32
|
+
|
|
33
|
+
function freshBase(): string {
|
|
34
|
+
return mkdtempSync(join(tmpdir(), 'gsd-exec-gracekill-'));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function cleanup(dir: string): void {
|
|
38
|
+
rmSync(dir, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function baseOpts(base: string, overrides: Partial<ExecSandboxOptions> = {}): ExecSandboxOptions {
|
|
42
|
+
return {
|
|
43
|
+
baseDir: base,
|
|
44
|
+
clamp_timeout_ms: EXEC_DEFAULTS.clampTimeoutMs,
|
|
45
|
+
default_timeout_ms: 10_000,
|
|
46
|
+
stdout_cap_bytes: 1_024,
|
|
47
|
+
stderr_cap_bytes: 1_024,
|
|
48
|
+
digest_chars: 120,
|
|
49
|
+
env_allowlist: EXEC_DEFAULTS.envAllowlist,
|
|
50
|
+
...overrides,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Wall-clock guard: reject if the call has not settled by `ms`. Proves no-hang
|
|
55
|
+
// independently of the assertions on timing/markers.
|
|
56
|
+
function wallClockGuard<T>(promise: Promise<T>, ms: number): Promise<T> {
|
|
57
|
+
return Promise.race([
|
|
58
|
+
promise,
|
|
59
|
+
new Promise<never>((_, reject) => {
|
|
60
|
+
const t = setTimeout(() => reject(new Error(`Call did not settle within ${ms}ms (hang)`)), ms);
|
|
61
|
+
if (typeof t === 'object' && 'unref' in t) t.unref();
|
|
62
|
+
}),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Clean up a detached child (and its process group) that a large kill_grace_ms
|
|
67
|
+
// intentionally leaves alive past the force-resolve deadline.
|
|
68
|
+
function cleanupByPidFile(pidFile: string): void {
|
|
69
|
+
if (!existsSync(pidFile)) return;
|
|
70
|
+
const pid = Number.parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
71
|
+
if (!Number.isFinite(pid) || pid <= 0) return;
|
|
72
|
+
if (isWin) return; // best-effort; test is skipped on win32
|
|
73
|
+
try {
|
|
74
|
+
process.kill(-pid, 'SIGKILL');
|
|
75
|
+
} catch {
|
|
76
|
+
try {
|
|
77
|
+
process.kill(pid, 'SIGKILL');
|
|
78
|
+
} catch {
|
|
79
|
+
// already gone
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
test(
|
|
85
|
+
'runExecSandbox: SIGTERM-cooperative child exits promptly within grace on timeout',
|
|
86
|
+
{ skip: isWin ? 'Unix-primary graceful semantics' : false, timeout: 20_000 },
|
|
87
|
+
async (t) => {
|
|
88
|
+
const base = freshBase();
|
|
89
|
+
t.after(() => cleanup(base));
|
|
90
|
+
|
|
91
|
+
const KILL_GRACE_MS = 5_000;
|
|
92
|
+
const FORCE_RESOLVE_DELAY_MS = 8_000; // grace + hard-deadline; must NOT be reached
|
|
93
|
+
const TIMEOUT_MS = 300;
|
|
94
|
+
|
|
95
|
+
// Child traps SIGTERM and exits 0, then sleeps long. The first SIGTERM from
|
|
96
|
+
// the ladder ends it immediately -> `close` fires -> finalize via close,
|
|
97
|
+
// well before the force-resolve deadline.
|
|
98
|
+
const script = `trap 'exit 0' TERM; sleep 30`;
|
|
99
|
+
|
|
100
|
+
const result = await wallClockGuard(
|
|
101
|
+
runExecSandbox(
|
|
102
|
+
{ runtime: 'bash', script, timeout_ms: TIMEOUT_MS },
|
|
103
|
+
baseOpts(base, {
|
|
104
|
+
kill_grace_ms: KILL_GRACE_MS,
|
|
105
|
+
force_resolve_delay_ms: FORCE_RESOLVE_DELAY_MS,
|
|
106
|
+
}),
|
|
107
|
+
),
|
|
108
|
+
15_000,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// timed_out is preserved even though the child exited cooperatively.
|
|
112
|
+
assert.equal(result.timed_out, true, 'timeout fired so timed_out must be true');
|
|
113
|
+
// Proves SIGTERM (close) resolved it, NOT the force-resolve deadline:
|
|
114
|
+
// a force-resolve would land at ~TIMEOUT_MS + FORCE_RESOLVE_DELAY_MS (~8.3s).
|
|
115
|
+
assert.ok(
|
|
116
|
+
result.duration_ms < KILL_GRACE_MS,
|
|
117
|
+
`expected prompt close well under grace (${KILL_GRACE_MS}ms), got ${result.duration_ms}ms`,
|
|
118
|
+
);
|
|
119
|
+
// A clean SIGTERM-trapped exit resolves via `close` with an exit code,
|
|
120
|
+
// not the force-resolve sentinel (exit_code null / signal SIGKILL).
|
|
121
|
+
assert.notEqual(
|
|
122
|
+
result.signal,
|
|
123
|
+
'SIGKILL',
|
|
124
|
+
'cooperative child must not be force-resolved as SIGKILL',
|
|
125
|
+
);
|
|
126
|
+
assert.equal(result.force_resolved, false, 'a cooperative close must not be flagged as force-resolved');
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
test(
|
|
131
|
+
'runExecSandbox: SIGTERM-ignoring (non-closing) child force-resolves via hard deadline without hanging',
|
|
132
|
+
{ skip: isWin ? 'Unix-primary graceful semantics; force-resolve covered on POSIX' : false, timeout: 20_000 },
|
|
133
|
+
async (t) => {
|
|
134
|
+
const base = freshBase();
|
|
135
|
+
const pidFile = join(base, 'child.pid');
|
|
136
|
+
t.after(() => {
|
|
137
|
+
cleanupByPidFile(pidFile);
|
|
138
|
+
cleanup(base);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Timing seams: SIGKILL never fires in-window (grace huge), so the only way
|
|
142
|
+
// the promise can settle is the hard deadline -> proves the caller-side
|
|
143
|
+
// force-resolve.
|
|
144
|
+
const KILL_GRACE_MS = 30_000;
|
|
145
|
+
const FORCE_RESOLVE_DELAY_MS = 800;
|
|
146
|
+
// Generous timeout so the SIGTERM trap is reliably installed before the kill
|
|
147
|
+
// fires, even under heavy parallel test load. A too-tight timeout can race
|
|
148
|
+
// the shell's startup: the kill lands before `trap '' TERM` runs, SIGTERM
|
|
149
|
+
// takes its default action, the child closes on SIGTERM, and the
|
|
150
|
+
// force-resolve path never runs (flaky 'SIGTERM' instead of 'SIGKILL').
|
|
151
|
+
const TIMEOUT_MS = 1_500;
|
|
152
|
+
|
|
153
|
+
// Install the SIGTERM trap FIRST (before any other command) so the shell is
|
|
154
|
+
// already immune by the time the kill fires; then record the detached
|
|
155
|
+
// shell's PID (process-group leader) for cleanup. The shell loops forever
|
|
156
|
+
// holding its stdout pipe open -> `close` never fires in-window -> the
|
|
157
|
+
// caller's hard deadline must force-resolve.
|
|
158
|
+
const script = `trap '' TERM; echo $$ > '${pidFile}'; while true; do sleep 1; done`;
|
|
159
|
+
|
|
160
|
+
const start = Date.now();
|
|
161
|
+
const result = await wallClockGuard(
|
|
162
|
+
runExecSandbox(
|
|
163
|
+
{ runtime: 'bash', script, timeout_ms: TIMEOUT_MS },
|
|
164
|
+
baseOpts(base, {
|
|
165
|
+
kill_grace_ms: KILL_GRACE_MS,
|
|
166
|
+
force_resolve_delay_ms: FORCE_RESOLVE_DELAY_MS,
|
|
167
|
+
}),
|
|
168
|
+
),
|
|
169
|
+
8_000,
|
|
170
|
+
);
|
|
171
|
+
const elapsed = Date.now() - start;
|
|
172
|
+
|
|
173
|
+
// (a) Did not hang and settled well before the SIGKILL grace would fire.
|
|
174
|
+
assert.ok(
|
|
175
|
+
elapsed < KILL_GRACE_MS,
|
|
176
|
+
`expected force-resolve before SIGKILL grace (${KILL_GRACE_MS}ms), took ${elapsed}ms`,
|
|
177
|
+
);
|
|
178
|
+
// (b) Settled in the force-resolve band: >= timeout (kill initiated) and
|
|
179
|
+
// roughly timeout + force_resolve_delay (generous CI slack, but kept below
|
|
180
|
+
// the 8000ms wallClockGuard so the upper bound is actually reachable).
|
|
181
|
+
assert.ok(
|
|
182
|
+
elapsed >= TIMEOUT_MS && elapsed <= TIMEOUT_MS + FORCE_RESOLVE_DELAY_MS + 4_000,
|
|
183
|
+
`expected settle near ${TIMEOUT_MS + FORCE_RESOLVE_DELAY_MS}ms, took ${elapsed}ms`,
|
|
184
|
+
);
|
|
185
|
+
// (c) Force-resolve preserves timed_out and surfaces the SIGKILL sentinel
|
|
186
|
+
// (exit_code null) plus the explicit force_resolved flag, so the agent can
|
|
187
|
+
// tell a forced kill (D-state hard deadline) from a clean SIGKILL exit.
|
|
188
|
+
assert.equal(result.timed_out, true, 'force-resolve must preserve timed_out');
|
|
189
|
+
assert.equal(result.exit_code, null, 'force-resolve exit_code must be null');
|
|
190
|
+
assert.equal(result.signal, 'SIGKILL', 'force-resolve must mark signal SIGKILL');
|
|
191
|
+
assert.equal(result.force_resolved, true, 'force-resolve must set force_resolved=true');
|
|
192
|
+
},
|
|
193
|
+
);
|
|
@@ -2,7 +2,7 @@ import test from "node:test";
|
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
|
|
4
4
|
import { registerExecTools } from "../bootstrap/exec-tools.ts";
|
|
5
|
-
import { executeUatExec } from "../tools/exec-tool.ts";
|
|
5
|
+
import { executeGsdExec, executeUatExec } from "../tools/exec-tool.ts";
|
|
6
6
|
import type { ExecSandboxRequest, ExecSandboxResult } from "../exec-sandbox.ts";
|
|
7
7
|
|
|
8
8
|
function makeExecResult(request: ExecSandboxRequest): ExecSandboxResult {
|
|
@@ -12,6 +12,7 @@ function makeExecResult(request: ExecSandboxRequest): ExecSandboxResult {
|
|
|
12
12
|
exit_code: 0,
|
|
13
13
|
signal: null,
|
|
14
14
|
timed_out: false,
|
|
15
|
+
force_resolved: false,
|
|
15
16
|
duration_ms: 1,
|
|
16
17
|
stdout_bytes: 12,
|
|
17
18
|
stderr_bytes: 0,
|
|
@@ -51,6 +52,33 @@ test("executeUatExec accepts evidence-mode aliases for intent", async () => {
|
|
|
51
52
|
assert.equal(requests[0]?.metadata?.intent, "uat-artifact-check");
|
|
52
53
|
});
|
|
53
54
|
|
|
55
|
+
test("gsd_exec surfaces a force-resolved (D-state) kill distinctly from a clean exit", async () => {
|
|
56
|
+
// A hard-deadline force-resolve sets force_resolved=true with a synthetic SIGKILL
|
|
57
|
+
// signal and null exit code. The tool result must carry that flag in details and
|
|
58
|
+
// render it as exit=timeout(force-killed) so the agent can tell it apart from a
|
|
59
|
+
// normally-exited or cleanly-timed-out command.
|
|
60
|
+
const result = await executeGsdExec(
|
|
61
|
+
{ runtime: "bash", script: "sleep 60" },
|
|
62
|
+
{
|
|
63
|
+
baseDir: "/tmp/gsd-exec-force-resolved-test",
|
|
64
|
+
preferences: null,
|
|
65
|
+
run: async (request) => ({
|
|
66
|
+
...makeExecResult(request),
|
|
67
|
+
exit_code: null,
|
|
68
|
+
signal: "SIGKILL",
|
|
69
|
+
timed_out: true,
|
|
70
|
+
force_resolved: true,
|
|
71
|
+
digest: "[no stdout \u2014 timed out]",
|
|
72
|
+
}),
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
assert.equal(result.isError, true, "a force-resolved kill is an error result");
|
|
77
|
+
assert.equal(result.details?.force_resolved, true, "details must expose force_resolved");
|
|
78
|
+
const text = result.content.map((c) => c.text ?? "").join("\n");
|
|
79
|
+
assert.match(text, /exit=timeout\(force-killed\)/, "summary must distinguish a force-killed result");
|
|
80
|
+
});
|
|
81
|
+
|
|
54
82
|
test("registerExecTools exposes gsd_uat_exec intent as recoverable string schema", () => {
|
|
55
83
|
const tools: Array<{ name: string; parameters: any }> = [];
|
|
56
84
|
registerExecTools({
|