@opengsd/gsd-pi 1.2.0-dev.5457a158 → 1.2.0-dev.822c9439
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/headless-events.js +7 -5
- package/dist/mcp-server.js +2 -1
- package/dist/resource-loader.d.ts +9 -5
- package/dist/resource-loader.js +114 -6
- 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/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/stream-adapter.js +3 -2
- 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 +89 -54
- package/dist/resources/extensions/gsd/auto/phases.js +49 -6
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -34
- package/dist/resources/extensions/gsd/auto-dispatch.js +50 -58
- package/dist/resources/extensions/gsd/auto-model-selection.js +36 -13
- package/dist/resources/extensions/gsd/auto-post-unit.js +30 -12
- package/dist/resources/extensions/gsd/auto-prompts.js +78 -19
- package/dist/resources/extensions/gsd/auto-start.js +12 -12
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +5 -4
- package/dist/resources/extensions/gsd/auto-verification.js +23 -30
- package/dist/resources/extensions/gsd/auto-worktree.js +14 -1
- package/dist/resources/extensions/gsd/auto.js +37 -1
- package/dist/resources/extensions/gsd/blocked-models.js +28 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +26 -6
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
- 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 +172 -59
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +302 -80
- 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/closeout-wizard.js +92 -0
- package/dist/resources/extensions/gsd/commands/context.js +16 -2
- 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 +8 -3
- package/dist/resources/extensions/gsd/db/queries.js +26 -0
- package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
- package/dist/resources/extensions/gsd/doctor-git-checks.js +2 -18
- package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -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/gsd-command-home.js +22 -12
- package/dist/resources/extensions/gsd/gsd-db.js +2 -1
- package/dist/resources/extensions/gsd/guidance.js +60 -0
- package/dist/resources/extensions/gsd/guided-flow.js +6 -3
- 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/milestone-closeout.js +85 -24
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
- package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
- package/dist/resources/extensions/gsd/preferences-models.js +2 -2
- package/dist/resources/extensions/gsd/projection-flush.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.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/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +7 -5
- package/dist/resources/extensions/gsd/prompts/system.md +5 -2
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
- package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
- package/dist/resources/extensions/gsd/session-lock.js +1 -1
- package/dist/resources/extensions/gsd/state.js +5 -0
- package/dist/resources/extensions/gsd/tool-contract.js +14 -3
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +22 -12
- package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
- package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
- 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/unit-context-composer.js +65 -0
- package/dist/resources/extensions/gsd/unit-registry.js +7 -20
- package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
- package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
- package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
- package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
- package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
- package/dist/resources/extensions/gsd/workflow-events.js +6 -18
- package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +3 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
- package/dist/resources/extensions/gsd/worktree.js +8 -1
- 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/SKILL.md +3 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
- package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
- 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/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 +11 -11
- 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/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/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 +11 -11
- 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/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/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 +5 -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 +10 -5
- 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 +18 -18
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +99 -38
- 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/image-models.generated.d.ts +2 -2
- package/packages/pi-ai/dist/image-models.generated.js +6 -6
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- 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 +239 -153
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +256 -145
- 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/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/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/stream-adapter.ts +3 -2
- 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.ts +4 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +98 -56
- package/src/resources/extensions/gsd/auto/phases.ts +65 -26
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +18 -48
- package/src/resources/extensions/gsd/auto-dispatch.ts +48 -61
- package/src/resources/extensions/gsd/auto-model-selection.ts +41 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +33 -12
- package/src/resources/extensions/gsd/auto-prompts.ts +115 -35
- package/src/resources/extensions/gsd/auto-start.ts +12 -14
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +4 -4
- package/src/resources/extensions/gsd/auto-verification.ts +26 -28
- package/src/resources/extensions/gsd/auto-worktree.ts +14 -1
- package/src/resources/extensions/gsd/auto.ts +44 -1
- package/src/resources/extensions/gsd/blocked-models.ts +49 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -5
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
- 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 +211 -59
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +350 -86
- 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/closeout-wizard.ts +102 -0
- package/src/resources/extensions/gsd/commands/context.ts +16 -2
- 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 +10 -2
- package/src/resources/extensions/gsd/db/queries.ts +37 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
- package/src/resources/extensions/gsd/doctor-git-checks.ts +2 -19
- package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -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/gsd-command-home.ts +13 -3
- package/src/resources/extensions/gsd/gsd-db.ts +4 -3
- package/src/resources/extensions/gsd/guidance.ts +78 -0
- package/src/resources/extensions/gsd/guided-flow.ts +21 -26
- 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/milestone-closeout.ts +109 -24
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
- package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
- package/src/resources/extensions/gsd/preferences-models.ts +2 -1
- package/src/resources/extensions/gsd/projection-flush.ts +20 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.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/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +7 -5
- package/src/resources/extensions/gsd/prompts/system.md +5 -2
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
- package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
- package/src/resources/extensions/gsd/session-lock.ts +1 -1
- package/src/resources/extensions/gsd/state.ts +5 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +97 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +198 -26
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
- 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/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/discuss-routing-fixes.test.ts +12 -2
- 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/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/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 +23 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +2 -6
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +7 -11
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +20 -58
- 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/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/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/phases-terminal-complete-idempotent.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +112 -29
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -1
- package/src/resources/extensions/gsd/tool-contract.ts +38 -3
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +22 -12
- package/src/resources/extensions/gsd/tools/complete-task.ts +3 -2
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
- 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/unit-context-composer.ts +99 -0
- package/src/resources/extensions/gsd/unit-registry.ts +7 -20
- package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
- package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
- package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
- package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
- package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
- package/src/resources/extensions/gsd/workflow-events.ts +12 -20
- package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +3 -8
- package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
- package/src/resources/extensions/gsd/worktree.ts +7 -1
- 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/SKILL.md +3 -0
- package/src/resources/skills/create-skill/references/executable-code.md +1 -1
- package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
- 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/spike-wrap-up/SKILL.md +9 -9
- package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
- package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
- 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/src/resources/skills/gsd-browser/SKILL.md +0 -41
- /package/dist/web/standalone/.next/static/{2p9Rv9pQflAxCBbGVI2vb → yWwBo-w09Y_W-nmeeWFRp}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{2p9Rv9pQflAxCBbGVI2vb → yWwBo-w09Y_W-nmeeWFRp}/_ssgManifest.js +0 -0
package/dist/headless-events.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* so wording stays in lockstep with detection.
|
|
12
12
|
*/
|
|
13
13
|
import { isBlockedNoticeMessage, isManualResolutionNotice, isPauseNotice, isTerminalNotice, } from './resources/extensions/gsd/stop-notice.js';
|
|
14
|
+
import { canonicalToolName } from './resources/extensions/gsd/engine-hook-contract.js';
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
15
16
|
// Exit Code Constants
|
|
16
17
|
// ---------------------------------------------------------------------------
|
|
@@ -76,12 +77,13 @@ export const IDLE_TIMEOUT_MS = 15_000;
|
|
|
76
77
|
// longer idle timeout to avoid killing the session prematurely (#808).
|
|
77
78
|
export const NEW_MILESTONE_IDLE_TIMEOUT_MS = 120_000;
|
|
78
79
|
const INTERACTIVE_HEADLESS_TOOLS = new Set(['ask_user_questions', 'secure_env_collect']);
|
|
80
|
+
// Delegates to the shared normalizer seam (engine-hook-contract.ts) instead of
|
|
81
|
+
// a hand-rolled parser. Behavior differs from the old parser only on malformed
|
|
82
|
+
// MCP names: `mcp____tool` (empty server) and `mcp__server__` (empty tool) are
|
|
83
|
+
// now returned unchanged rather than partially stripped — neither can match a
|
|
84
|
+
// real tool name, so detection behavior is unaffected.
|
|
79
85
|
export function canonicalHeadlessToolName(toolName) {
|
|
80
|
-
|
|
81
|
-
if (!name.startsWith('mcp__'))
|
|
82
|
-
return name;
|
|
83
|
-
const toolSeparator = name.indexOf('__', 'mcp__'.length);
|
|
84
|
-
return toolSeparator >= 0 ? name.slice(toolSeparator + 2) : name;
|
|
86
|
+
return canonicalToolName(String(toolName ?? ''));
|
|
85
87
|
}
|
|
86
88
|
function getCommandBlockContent(event) {
|
|
87
89
|
if (event.type !== 'message_start' && event.type !== 'message_end')
|
package/dist/mcp-server.js
CHANGED
|
@@ -29,6 +29,7 @@ function isPlainObject(value) {
|
|
|
29
29
|
// built via a template string so TypeScript's NodeNext resolver treats them as
|
|
30
30
|
// `any` and skips static checking.
|
|
31
31
|
const MCP_PKG = '@modelcontextprotocol/sdk';
|
|
32
|
+
import { sanitizeSchemaForMoonshot } from '@gsd/pi-ai';
|
|
32
33
|
export function mcpSdkSpecifier(subpath) {
|
|
33
34
|
return `${MCP_PKG}/${subpath}.js`;
|
|
34
35
|
}
|
|
@@ -65,7 +66,7 @@ export async function startMcpServer(options) {
|
|
|
65
66
|
tools: tools.map((t) => ({
|
|
66
67
|
name: t.name,
|
|
67
68
|
description: t.description,
|
|
68
|
-
inputSchema: t.parameters,
|
|
69
|
+
inputSchema: sanitizeSchemaForMoonshot(t.parameters),
|
|
69
70
|
})),
|
|
70
71
|
}));
|
|
71
72
|
// tools/call — execute the requested tool and return content blocks.
|
|
@@ -22,6 +22,8 @@ export declare function readManagedResourceVersion(agentDir: string): string | n
|
|
|
22
22
|
* directory (e.g. pre-install verification).
|
|
23
23
|
*/
|
|
24
24
|
export declare function computeResourceFingerprint(rootDir?: string): string;
|
|
25
|
+
export declare function collectGsdBrowserPackageSkillReferences(content: string): string[];
|
|
26
|
+
export declare function hasStaleGsdBrowserPackageSkill(skillsDir: string): boolean;
|
|
25
27
|
export declare function getNewerManagedResourceVersion(agentDir: string, currentVersion: string): string | null;
|
|
26
28
|
/**
|
|
27
29
|
* Syncs a single bundled resource directory into the agent directory.
|
|
@@ -49,18 +51,20 @@ export declare function reconcileMergedNodeModules(agentNodeModules: string, hoi
|
|
|
49
51
|
/** Build a cache fingerprint from packageRoot + sorted entry names of both directories */
|
|
50
52
|
export declare function mergedFingerprint(hoisted: string, internal: string): string;
|
|
51
53
|
/**
|
|
52
|
-
*
|
|
54
|
+
* Initializes managed resources under agentDir (~/.gsd/agent/).
|
|
53
55
|
*
|
|
54
56
|
* - extensions/ → ~/.gsd/agent/extensions/ (overwrite when version changes)
|
|
55
57
|
* - shared/ → ~/.gsd/agent/shared/ (overwrite when version changes)
|
|
56
58
|
* - agents/ → ~/.gsd/agent/agents/ (overwrite when version changes)
|
|
57
59
|
* - skills/ → ~/.gsd/agent/skills/ (overwrite when version changes)
|
|
60
|
+
* - gsd-browser skill → ~/.gsd/agent/skills/gsd-browser/ from @opengsd/gsd-browser
|
|
58
61
|
* - GSD-WORKFLOW.md → ~/.gsd/agent/GSD-WORKFLOW.md (fallback for env var miss)
|
|
59
62
|
*
|
|
60
|
-
* Skips the copy when the managed-resources.json version
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
63
|
+
* Skips the full copy only when the managed-resources.json version, content
|
|
64
|
+
* fingerprint, and package-owned gsd-browser skill all match the current
|
|
65
|
+
* install, avoiding ~128ms of synchronous cpSync on steady-state startup.
|
|
66
|
+
* After `npm update -g @opengsd/gsd-pi`, versions will differ and the copy
|
|
67
|
+
* runs once to land the new resources.
|
|
64
68
|
*
|
|
65
69
|
* Inspectable: `ls ~/.gsd/agent/extensions/`
|
|
66
70
|
*/
|
package/dist/resource-loader.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { chmodSync, copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, readdirSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
4
5
|
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { compareSemver } from './update-check.js';
|
|
@@ -24,6 +25,9 @@ const resourcesDir = resolveBundledResourcesDirFromPackageRoot(packageRoot);
|
|
|
24
25
|
const bundledExtensionsDir = join(resourcesDir, 'extensions');
|
|
25
26
|
const resourceVersionManifestName = 'managed-resources.json';
|
|
26
27
|
const resourceFingerprintFileName = '.managed-resources-content-hash';
|
|
28
|
+
const gsdBrowserSkillName = 'gsd-browser';
|
|
29
|
+
const requireFromResourceLoader = createRequire(import.meta.url);
|
|
30
|
+
const gsdBrowserSkillReferenceDirs = ['docs', 'scripts', 'gsd-browser-skill'];
|
|
27
31
|
export { discoverExtensionEntryPaths } from './extension-discovery.js';
|
|
28
32
|
export function getExtensionKey(entryPath, extensionsDir) {
|
|
29
33
|
const relPath = relative(extensionsDir, entryPath);
|
|
@@ -153,6 +157,105 @@ function getCurrentResourceFingerprint() {
|
|
|
153
157
|
}
|
|
154
158
|
return computeResourceFingerprint();
|
|
155
159
|
}
|
|
160
|
+
function resolveGsdBrowserPackageSkillPath() {
|
|
161
|
+
try {
|
|
162
|
+
return requireFromResourceLoader.resolve('@opengsd/gsd-browser/SKILL.md');
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export function collectGsdBrowserPackageSkillReferences(content) {
|
|
169
|
+
const refs = new Set();
|
|
170
|
+
const referencePattern = /`((?:\.\/)?(?:docs|scripts|gsd-browser-skill)\/[^`\s]+)`/g;
|
|
171
|
+
for (const match of content.matchAll(referencePattern)) {
|
|
172
|
+
const ref = normalizeGsdBrowserPackageSkillReference(match[1]);
|
|
173
|
+
if (ref)
|
|
174
|
+
refs.add(ref);
|
|
175
|
+
}
|
|
176
|
+
return [...refs].sort();
|
|
177
|
+
}
|
|
178
|
+
function normalizeGsdBrowserPackageSkillReference(ref) {
|
|
179
|
+
if (!ref)
|
|
180
|
+
return null;
|
|
181
|
+
const normalized = ref
|
|
182
|
+
.replace(/^\.\//, '')
|
|
183
|
+
.replace(/[),.;:]+$/, '');
|
|
184
|
+
if (normalized.includes('..') || normalized.startsWith('/'))
|
|
185
|
+
return null;
|
|
186
|
+
if (!gsdBrowserSkillReferenceDirs.some(dir => normalized === dir || normalized.startsWith(`${dir}/`))) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
return normalized;
|
|
190
|
+
}
|
|
191
|
+
function readGsdBrowserPackageSkillBundle(sourceSkillPath) {
|
|
192
|
+
const skillContent = readFileSync(sourceSkillPath);
|
|
193
|
+
const files = new Map([['SKILL.md', skillContent]]);
|
|
194
|
+
const supportRefs = collectGsdBrowserPackageSkillReferences(skillContent.toString('utf-8'));
|
|
195
|
+
const sourceDir = dirname(sourceSkillPath);
|
|
196
|
+
for (const relPath of supportRefs) {
|
|
197
|
+
const sourcePath = join(sourceDir, relPath);
|
|
198
|
+
if (existsSync(sourcePath)) {
|
|
199
|
+
files.set(relPath, readFileSync(sourcePath));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return files;
|
|
203
|
+
}
|
|
204
|
+
export function hasStaleGsdBrowserPackageSkill(skillsDir) {
|
|
205
|
+
const targetDir = join(skillsDir, gsdBrowserSkillName);
|
|
206
|
+
const sourceSkillPath = resolveGsdBrowserPackageSkillPath();
|
|
207
|
+
// Package unresolvable. syncGsdBrowserPackageSkill is a no-op in this case
|
|
208
|
+
// (it preserves any existing managed skill), so reporting "stale" here
|
|
209
|
+
// would drive a full resource resync on every launch that the sync cannot
|
|
210
|
+
// actually satisfy. Keep the existing managed skill in place until the
|
|
211
|
+
// package becomes resolvable again or the manifest fingerprint changes.
|
|
212
|
+
if (!sourceSkillPath)
|
|
213
|
+
return false;
|
|
214
|
+
try {
|
|
215
|
+
const sourceDir = dirname(sourceSkillPath);
|
|
216
|
+
const skillContent = readFileSync(sourceSkillPath, 'utf-8');
|
|
217
|
+
for (const [relPath, content] of readGsdBrowserPackageSkillBundle(sourceSkillPath)) {
|
|
218
|
+
const targetPath = join(targetDir, relPath);
|
|
219
|
+
if (!existsSync(targetPath) || !readFileSync(targetPath).equals(content)) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Only flag SKILL.md references when sync can actually correct them.
|
|
224
|
+
// The bundle loop above already covers "source has it, target missing".
|
|
225
|
+
// A reference the package itself does not ship (source missing) is only
|
|
226
|
+
// worth a resync if the target still has a stale copy that sync should
|
|
227
|
+
// clean up; missing on both sides is the steady state when upstream
|
|
228
|
+
// omits files referenced from SKILL.md and is not actionable here.
|
|
229
|
+
for (const relPath of collectGsdBrowserPackageSkillReferences(skillContent)) {
|
|
230
|
+
const sourcePath = join(sourceDir, relPath);
|
|
231
|
+
const targetPath = join(targetDir, relPath);
|
|
232
|
+
if (!existsSync(sourcePath) && existsSync(targetPath)) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function syncGsdBrowserPackageSkill(skillsDir) {
|
|
243
|
+
const targetDir = join(skillsDir, gsdBrowserSkillName);
|
|
244
|
+
const sourceSkillPath = resolveGsdBrowserPackageSkillPath();
|
|
245
|
+
if (!sourceSkillPath)
|
|
246
|
+
return;
|
|
247
|
+
makeTreeWritable(targetDir);
|
|
248
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
249
|
+
for (const [relPath, content] of readGsdBrowserPackageSkillBundle(sourceSkillPath)) {
|
|
250
|
+
const targetPath = join(targetDir, relPath);
|
|
251
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
252
|
+
writeFileSync(targetPath, content);
|
|
253
|
+
if (relPath.startsWith('scripts/') && relPath.endsWith('.sh')) {
|
|
254
|
+
chmodSync(targetPath, 0o755);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
makeTreeWritable(targetDir);
|
|
258
|
+
}
|
|
156
259
|
function collectFileEntries(dir, root, out) {
|
|
157
260
|
if (!existsSync(dir))
|
|
158
261
|
return;
|
|
@@ -557,18 +660,20 @@ function pruneRemovedBundledExtensions(manifest, agentDir) {
|
|
|
557
660
|
removeFileIfStale('env-utils.js');
|
|
558
661
|
}
|
|
559
662
|
/**
|
|
560
|
-
*
|
|
663
|
+
* Initializes managed resources under agentDir (~/.gsd/agent/).
|
|
561
664
|
*
|
|
562
665
|
* - extensions/ → ~/.gsd/agent/extensions/ (overwrite when version changes)
|
|
563
666
|
* - shared/ → ~/.gsd/agent/shared/ (overwrite when version changes)
|
|
564
667
|
* - agents/ → ~/.gsd/agent/agents/ (overwrite when version changes)
|
|
565
668
|
* - skills/ → ~/.gsd/agent/skills/ (overwrite when version changes)
|
|
669
|
+
* - gsd-browser skill → ~/.gsd/agent/skills/gsd-browser/ from @opengsd/gsd-browser
|
|
566
670
|
* - GSD-WORKFLOW.md → ~/.gsd/agent/GSD-WORKFLOW.md (fallback for env var miss)
|
|
567
671
|
*
|
|
568
|
-
* Skips the copy when the managed-resources.json version
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
672
|
+
* Skips the full copy only when the managed-resources.json version, content
|
|
673
|
+
* fingerprint, and package-owned gsd-browser skill all match the current
|
|
674
|
+
* install, avoiding ~128ms of synchronous cpSync on steady-state startup.
|
|
675
|
+
* After `npm update -g @opengsd/gsd-pi`, versions will differ and the copy
|
|
676
|
+
* runs once to land the new resources.
|
|
572
677
|
*
|
|
573
678
|
* Inspectable: `ls ~/.gsd/agent/extensions/`
|
|
574
679
|
*/
|
|
@@ -603,11 +708,13 @@ export function initResources(agentDir, skillsDir = join(agentDir, 'skills')) {
|
|
|
603
708
|
const hasStaleExtensionFiles = hasStaleCompiledExtensionSiblings(extensionsDir, bundledExtensionsDir);
|
|
604
709
|
const hasMissingSharedFiles = hasMissingBundledResourceFiles(join(agentDir, 'shared'), join(resourcesDir, 'shared'));
|
|
605
710
|
const hasMissingSkillFiles = hasMissingBundledResourceFiles(skillsDir, join(resourcesDir, 'skills'));
|
|
711
|
+
const hasStaleGsdBrowserSkill = hasStaleGsdBrowserPackageSkill(skillsDir);
|
|
606
712
|
if (manifest.contentHash &&
|
|
607
713
|
manifest.contentHash === currentHash &&
|
|
608
714
|
!hasStaleExtensionFiles &&
|
|
609
715
|
!hasMissingSharedFiles &&
|
|
610
|
-
!hasMissingSkillFiles
|
|
716
|
+
!hasMissingSkillFiles &&
|
|
717
|
+
!hasStaleGsdBrowserSkill) {
|
|
611
718
|
return;
|
|
612
719
|
}
|
|
613
720
|
}
|
|
@@ -616,6 +723,7 @@ export function initResources(agentDir, skillsDir = join(agentDir, 'skills')) {
|
|
|
616
723
|
syncResourceDir(join(resourcesDir, 'shared'), join(agentDir, 'shared'));
|
|
617
724
|
syncResourceDir(join(resourcesDir, 'agents'), join(agentDir, 'agents'));
|
|
618
725
|
syncResourceDir(join(resourcesDir, 'skills'), skillsDir);
|
|
726
|
+
syncGsdBrowserPackageSkill(skillsDir);
|
|
619
727
|
// Sync GSD-WORKFLOW.md to agentDir as a fallback for when GSD_WORKFLOW_PATH
|
|
620
728
|
// env var is not set (e.g. fork/dev builds, alternative entry points).
|
|
621
729
|
const workflowSrc = join(resourcesDir, 'GSD-WORKFLOW.md');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
dab8e4d2f1341f51
|
|
@@ -470,13 +470,13 @@ key_decisions: []
|
|
|
470
470
|
|
|
471
471
|
**After a slice completes:**
|
|
472
472
|
1. Write slice `S##-SUMMARY.md` (compresses all task summaries).
|
|
473
|
-
2. Write slice `S##-UAT.md` — a
|
|
473
|
+
2. Write slice `S##-UAT.md` — a human test script derived from the slice's must-haves and demo sentence.
|
|
474
474
|
3. Mark the slice checkbox in `M###-ROADMAP.md` as `[x]`.
|
|
475
475
|
4. Update `STATE.md` with new position.
|
|
476
476
|
5. Update milestone `M###-SUMMARY.md` with the completed slice's contributions.
|
|
477
|
-
6. Continue to next slice immediately.
|
|
478
|
-
7. If
|
|
479
|
-
8. If all slices done → milestone complete.
|
|
477
|
+
6. Continue to next slice immediately. UAT can run after slice completion; automatic milestone closure requires each slice assessment to record `PASS`.
|
|
478
|
+
7. If UAT is missing or non-PASS at milestone closeout, run `/gsd dispatch uat`, request a slice-specific UAT rerun when needed, or create remediation work with `/gsd dispatch reassess`.
|
|
479
|
+
8. If all slices are done and UAT plus milestone validation pass → milestone complete.
|
|
480
480
|
|
|
481
481
|
---
|
|
482
482
|
|
|
@@ -605,6 +605,7 @@ Commit types: `feat`, `fix`, `test`, `refactor`, `docs`, `perf`, `chore`
|
|
|
605
605
|
|---------|-----|
|
|
606
606
|
| Bad task | Revert the task commit on the active branch |
|
|
607
607
|
| Bad milestone squash | Revert the squash commit on the integration branch |
|
|
608
|
+
| UAT missing or non-PASS at closeout | Run `/gsd dispatch uat`, request a slice-specific UAT rerun when needed, or create remediation work with `/gsd dispatch reassess` |
|
|
608
609
|
| UAT failure after merge | Create follow-up fix tasks in the current or next milestone |
|
|
609
610
|
|
|
610
611
|
---
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* immediately. The LLM can continue working and check results later
|
|
6
6
|
* with await_job.
|
|
7
7
|
*/
|
|
8
|
-
import { getShellConfig, sanitizeCommand, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, } from "@gsd/pi-coding-agent";
|
|
8
|
+
import { getShellConfig, sanitizeCommand, killProcessTree, SIGKILL_GRACE_MS, HARD_DEADLINE_MS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, } from "@gsd/pi-coding-agent";
|
|
9
9
|
import { Type } from "@sinclair/typebox";
|
|
10
|
-
import { spawn
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
11
|
import { createWriteStream } from "node:fs";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { join } from "node:path";
|
|
@@ -22,37 +22,6 @@ function getTempFilePath() {
|
|
|
22
22
|
const id = randomBytes(8).toString("hex");
|
|
23
23
|
return join(tmpdir(), `pi-async-bash-${id}.log`);
|
|
24
24
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Kill a process and its children (cross-platform).
|
|
27
|
-
* Uses process group kill on Unix; taskkill /F /T on Windows.
|
|
28
|
-
*/
|
|
29
|
-
function killTree(pid) {
|
|
30
|
-
if (process.platform === "win32") {
|
|
31
|
-
try {
|
|
32
|
-
spawnSync("taskkill", ["/F", "/T", "/PID", String(pid)], {
|
|
33
|
-
timeout: 5_000,
|
|
34
|
-
stdio: "ignore",
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
try {
|
|
39
|
-
process.kill(pid, "SIGTERM");
|
|
40
|
-
}
|
|
41
|
-
catch { /* already exited */ }
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
try {
|
|
46
|
-
process.kill(-pid, "SIGTERM");
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
try {
|
|
50
|
-
process.kill(pid, "SIGTERM");
|
|
51
|
-
}
|
|
52
|
-
catch { /* already exited */ }
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
25
|
export function createAsyncBashTool(getManager, getCwd) {
|
|
57
26
|
return {
|
|
58
27
|
name: "async_bash",
|
|
@@ -62,7 +31,7 @@ export function createAsyncBashTool(getManager, getCwd) {
|
|
|
62
31
|
`Output is truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB.`,
|
|
63
32
|
promptSnippet: "Run a bash command in the background, returning a job ID immediately.",
|
|
64
33
|
promptGuidelines: [
|
|
65
|
-
"Use async_bash for
|
|
34
|
+
"Use async_bash for long-running builds, tests, installs, or operations that should run in the background so you can continue other work (the job ID lets you await_job later). Sync bash is uncapped — use async_bash when you want non-blocking behavior, not because of a timeout concern.",
|
|
66
35
|
"After starting async jobs, continue with other work and use await_job when you need the results.",
|
|
67
36
|
"await_job has a configurable timeout (default 120s) to prevent indefinite blocking — if it times out, jobs keep running and you can check again later.",
|
|
68
37
|
"For long-running processes (SSH, deploys, training) that may take minutes+, prefer async_bash with periodic await_job polling over a single long await.",
|
|
@@ -122,36 +91,25 @@ function executeBashInBackground(command, cwd, signal, timeout) {
|
|
|
122
91
|
});
|
|
123
92
|
let timedOut = false;
|
|
124
93
|
let timeoutHandle;
|
|
125
|
-
let sigkillHandle;
|
|
126
94
|
let hardDeadlineHandle;
|
|
127
|
-
/** Grace period (ms) between SIGTERM and SIGKILL. */
|
|
128
|
-
const SIGKILL_GRACE_MS = 5_000;
|
|
129
|
-
/** Hard deadline (ms) after SIGKILL to force-resolve the promise. */
|
|
130
|
-
const HARD_DEADLINE_MS = 3_000;
|
|
131
95
|
if (timeout !== undefined && timeout > 0) {
|
|
132
96
|
timeoutHandle = setTimeout(() => {
|
|
133
97
|
timedOut = true;
|
|
98
|
+
// killProcessTree owns the SIGTERM -> grace -> SIGKILL escalation, so a
|
|
99
|
+
// SIGTERM-immune child is actually force-killed rather than left running.
|
|
134
100
|
if (child.pid)
|
|
135
|
-
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
? `${output}\n\nCommand timed out after ${timeout} seconds (force-killed)`
|
|
148
|
-
: `Command timed out after ${timeout} seconds (force-killed)`);
|
|
149
|
-
}, HARD_DEADLINE_MS);
|
|
150
|
-
if (typeof hardDeadlineHandle === "object" && "unref" in hardDeadlineHandle)
|
|
151
|
-
hardDeadlineHandle.unref();
|
|
152
|
-
}, SIGKILL_GRACE_MS);
|
|
153
|
-
if (typeof sigkillHandle === "object" && "unref" in sigkillHandle)
|
|
154
|
-
sigkillHandle.unref();
|
|
101
|
+
killProcessTree(child.pid);
|
|
102
|
+
// Hard deadline: a D-state (uninterruptible-I/O) child never emits 'close'
|
|
103
|
+
// even after SIGKILL, so force-resolve the promise rather than hang (#2186).
|
|
104
|
+
// Fires after the full grace window so SIGKILL has had its chance first.
|
|
105
|
+
hardDeadlineHandle = setTimeout(() => {
|
|
106
|
+
const output = Buffer.concat(chunks).toString("utf-8");
|
|
107
|
+
safeResolve(output
|
|
108
|
+
? `${output}\n\nCommand timed out after ${timeout} seconds (force-killed)`
|
|
109
|
+
: `Command timed out after ${timeout} seconds (force-killed)`);
|
|
110
|
+
}, SIGKILL_GRACE_MS + HARD_DEADLINE_MS);
|
|
111
|
+
if (typeof hardDeadlineHandle === "object" && "unref" in hardDeadlineHandle)
|
|
112
|
+
hardDeadlineHandle.unref();
|
|
155
113
|
}, timeout * 1000);
|
|
156
114
|
}
|
|
157
115
|
const chunks = [];
|
|
@@ -182,7 +140,19 @@ function executeBashInBackground(command, cwd, signal, timeout) {
|
|
|
182
140
|
child.stderr.on("data", onData);
|
|
183
141
|
const onAbort = () => {
|
|
184
142
|
if (child.pid)
|
|
185
|
-
|
|
143
|
+
killProcessTree(child.pid);
|
|
144
|
+
// Arm the same hard-deadline force-resolve the timeout path uses, so a
|
|
145
|
+
// cancelled D-state child (never emits 'close' even after SIGKILL) can't
|
|
146
|
+
// hang the job promise forever. safeResolve is idempotent, so the real
|
|
147
|
+
// 'close' still wins if the child does exit.
|
|
148
|
+
if (!hardDeadlineHandle) {
|
|
149
|
+
hardDeadlineHandle = setTimeout(() => {
|
|
150
|
+
const output = Buffer.concat(chunks).toString("utf-8");
|
|
151
|
+
safeResolve(output ? `${output}\n\nCommand aborted (force-killed)` : "Command aborted (force-killed)");
|
|
152
|
+
}, SIGKILL_GRACE_MS + HARD_DEADLINE_MS);
|
|
153
|
+
if (typeof hardDeadlineHandle === "object" && "unref" in hardDeadlineHandle)
|
|
154
|
+
hardDeadlineHandle.unref();
|
|
155
|
+
}
|
|
186
156
|
};
|
|
187
157
|
if (signal.aborted) {
|
|
188
158
|
onAbort();
|
|
@@ -193,8 +163,6 @@ function executeBashInBackground(command, cwd, signal, timeout) {
|
|
|
193
163
|
child.on("error", (err) => {
|
|
194
164
|
if (timeoutHandle)
|
|
195
165
|
clearTimeout(timeoutHandle);
|
|
196
|
-
if (sigkillHandle)
|
|
197
|
-
clearTimeout(sigkillHandle);
|
|
198
166
|
if (hardDeadlineHandle)
|
|
199
167
|
clearTimeout(hardDeadlineHandle);
|
|
200
168
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -203,8 +171,6 @@ function executeBashInBackground(command, cwd, signal, timeout) {
|
|
|
203
171
|
child.on("close", (code) => {
|
|
204
172
|
if (timeoutHandle)
|
|
205
173
|
clearTimeout(timeoutHandle);
|
|
206
|
-
if (sigkillHandle)
|
|
207
|
-
clearTimeout(sigkillHandle);
|
|
208
174
|
if (hardDeadlineHandle)
|
|
209
175
|
clearTimeout(hardDeadlineHandle);
|
|
210
176
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -21,7 +21,7 @@ export function createAwaitTool(getManager) {
|
|
|
21
21
|
label: "Await Background Job",
|
|
22
22
|
description: "Wait for background jobs to complete. Provide specific job IDs or omit to wait for the next job that finishes. Returns results of completed jobs.",
|
|
23
23
|
parameters: schema,
|
|
24
|
-
async execute(_toolCallId, params,
|
|
24
|
+
async execute(_toolCallId, params, signal, _onUpdate, _ctx) {
|
|
25
25
|
const manager = getManager();
|
|
26
26
|
const { jobs: jobIds, timeout } = params;
|
|
27
27
|
const timeoutMs = ((timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1000);
|
|
@@ -54,37 +54,75 @@ export function createAwaitTool(getManager) {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
//
|
|
57
|
+
// If all watched jobs are already done, suppress follow-up and return immediately.
|
|
58
58
|
// suppressFollowUp() cancels the pending delivery timer (if any), which
|
|
59
59
|
// handles both the within-turn case (job completes while we await) and
|
|
60
60
|
// the cross-turn case (job already completed before await_job was called).
|
|
61
61
|
// Previously this only set j.awaited = true, which missed the cross-turn
|
|
62
62
|
// case because the queueMicrotask had already fired (#3787).
|
|
63
|
-
for (const j of watched)
|
|
64
|
-
manager.suppressFollowUp(j.id);
|
|
65
|
-
// If all watched jobs are already done, return immediately
|
|
66
63
|
const running = watched.filter((j) => j.status === "running");
|
|
67
64
|
if (running.length === 0) {
|
|
68
|
-
const
|
|
69
|
-
|
|
65
|
+
for (const j of watched)
|
|
66
|
+
manager.suppressFollowUp(j.id);
|
|
67
|
+
return { content: [{ type: "text", text: renderCompleted(watched) }], details: undefined };
|
|
70
68
|
}
|
|
71
|
-
// Wait for at least one to complete, or
|
|
69
|
+
// Wait for at least one to complete, timeout, or abort signal
|
|
72
70
|
const TIMEOUT_SENTINEL = Symbol("timeout");
|
|
71
|
+
const ABORT_SENTINEL = Symbol("abort");
|
|
72
|
+
// The race timer and abort listener are explicitly torn down once the race
|
|
73
|
+
// settles (below) so a completion- or timeout-won race never leaks a pending
|
|
74
|
+
// timer or a lingering abort listener — the listener holds a closure over the
|
|
75
|
+
// race resolver, so { once: true } alone (which only detaches on fire) is not
|
|
76
|
+
// enough when ESC never happens.
|
|
77
|
+
let raceTimer;
|
|
78
|
+
let abortListener;
|
|
73
79
|
const timeoutPromise = new Promise((resolve) => {
|
|
74
|
-
|
|
80
|
+
raceTimer = setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs);
|
|
75
81
|
// Allow the process to exit even if the timer is pending
|
|
76
|
-
if (typeof
|
|
77
|
-
|
|
82
|
+
if (typeof raceTimer === "object" && "unref" in raceTimer)
|
|
83
|
+
raceTimer.unref();
|
|
84
|
+
});
|
|
85
|
+
const abortPromise = new Promise((resolve) => {
|
|
86
|
+
if (!signal || signal.aborted) {
|
|
87
|
+
resolve(ABORT_SENTINEL);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
abortListener = () => resolve(ABORT_SENTINEL);
|
|
91
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
92
|
+
}
|
|
78
93
|
});
|
|
79
94
|
const raceResult = await Promise.race([
|
|
80
95
|
Promise.race(running.map((j) => j.promise)).then(() => "completed"),
|
|
81
96
|
timeoutPromise,
|
|
97
|
+
abortPromise,
|
|
82
98
|
]);
|
|
99
|
+
// Tear down race resources now that a winner is decided.
|
|
100
|
+
if (raceTimer)
|
|
101
|
+
clearTimeout(raceTimer);
|
|
102
|
+
if (abortListener && signal)
|
|
103
|
+
signal.removeEventListener("abort", abortListener);
|
|
104
|
+
const aborted = raceResult === ABORT_SENTINEL;
|
|
83
105
|
const timedOut = raceResult === TIMEOUT_SENTINEL;
|
|
84
106
|
// Collect all completed results (more may have finished while waiting)
|
|
85
107
|
const completed = watched.filter((j) => j.status !== "running");
|
|
86
108
|
const stillRunning = watched.filter((j) => j.status === "running");
|
|
87
|
-
|
|
109
|
+
// Suppress follow-up ONLY for completed jobs — leave stillRunning unsuppressed
|
|
110
|
+
// so deliverResult/onJobComplete can resurface their results later.
|
|
111
|
+
for (const j of completed)
|
|
112
|
+
manager.suppressFollowUp(j.id);
|
|
113
|
+
if (aborted) {
|
|
114
|
+
// ESC ended the wait, not the jobs: still-running jobs keep going and
|
|
115
|
+
// resurface via onJobComplete (they were deliberately not suppressed above).
|
|
116
|
+
const runningDesc = stillRunning.map((j) => `${j.id} (${j.label})`).join(", ");
|
|
117
|
+
const interrupt = stillRunning.length > 0
|
|
118
|
+
? `Wait interrupted. Still running: ${runningDesc} — results will surface when complete.`
|
|
119
|
+
: "Wait interrupted.";
|
|
120
|
+
const text = completed.length > 0
|
|
121
|
+
? `${renderCompleted(completed)}\n\n${interrupt}`
|
|
122
|
+
: interrupt;
|
|
123
|
+
return { content: [{ type: "text", text }], details: undefined };
|
|
124
|
+
}
|
|
125
|
+
let result = renderCompleted(completed);
|
|
88
126
|
if (stillRunning.length > 0) {
|
|
89
127
|
result += `\n\n**Still running:** ${stillRunning.map((j) => `${j.id} (${j.label})`).join(", ")}`;
|
|
90
128
|
}
|
|
@@ -97,6 +135,36 @@ export function createAwaitTool(getManager) {
|
|
|
97
135
|
},
|
|
98
136
|
};
|
|
99
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Render completed jobs for the await_job result, de-duplicating against
|
|
140
|
+
* follow-ups that have already been delivered to context.
|
|
141
|
+
*
|
|
142
|
+
* A job's follow-up fires ~immediately (setTimeout(0)) once it settles, so when
|
|
143
|
+
* await_job runs in a LATER turn the result is already in context. Reprinting it
|
|
144
|
+
* inline produces the same output twice. Jobs already `delivered` are therefore
|
|
145
|
+
* acknowledged on a single line instead of having their full output reprinted;
|
|
146
|
+
* not-yet-delivered jobs (the within-turn case, where suppressFollowUp won the
|
|
147
|
+
* race) are rendered in full as before.
|
|
148
|
+
*/
|
|
149
|
+
function renderCompleted(jobs) {
|
|
150
|
+
if (jobs.length === 0)
|
|
151
|
+
return "No completed jobs.";
|
|
152
|
+
const fresh = jobs.filter((j) => !j.delivered);
|
|
153
|
+
const alreadyDelivered = jobs.filter((j) => j.delivered);
|
|
154
|
+
const sections = [];
|
|
155
|
+
if (fresh.length > 0)
|
|
156
|
+
sections.push(formatResults(fresh));
|
|
157
|
+
if (alreadyDelivered.length > 0) {
|
|
158
|
+
const names = alreadyDelivered
|
|
159
|
+
.map((j) => `${j.id} (${j.label})`)
|
|
160
|
+
.join(", ");
|
|
161
|
+
const sentence = alreadyDelivered.length === 1
|
|
162
|
+
? `This job already finished and its result was shown above when it completed, so there is nothing new to report: ${names}.`
|
|
163
|
+
: `These jobs already finished and their results were shown above when they completed, so there is nothing new to report: ${names}.`;
|
|
164
|
+
sections.push(sentence);
|
|
165
|
+
}
|
|
166
|
+
return sections.join("\n\n");
|
|
167
|
+
}
|
|
100
168
|
function formatResults(jobs) {
|
|
101
169
|
if (jobs.length === 0)
|
|
102
170
|
return "No completed jobs.";
|
|
@@ -98,9 +98,74 @@ export default function AsyncJobs(pi) {
|
|
|
98
98
|
});
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
+
const ctx = _ctx;
|
|
101
102
|
const running = manager.getRunningJobs();
|
|
102
103
|
const recent = manager.getRecentJobs(10);
|
|
103
104
|
const completed = recent.filter((j) => j.status !== "running");
|
|
105
|
+
// Interactive kill-picker when there are running jobs and a UI is available
|
|
106
|
+
if (running.length > 0 && ctx.hasUI) {
|
|
107
|
+
// Kill-picker loop: each iteration shows live running jobs.
|
|
108
|
+
// Step 1 picks a job (neutral label — selecting does NOT cancel yet);
|
|
109
|
+
// step 2 confirms before the destructive cancel. Labels deliberately
|
|
110
|
+
// omit a live elapsed time: ctx.ui.select renders the option strings
|
|
111
|
+
// once and never refreshes them, so a "(24s)" baked into the label
|
|
112
|
+
// would freeze and mislead. Accurate elapsed times are shown in the
|
|
113
|
+
// post-picker summary (rebuilt fresh) instead.
|
|
114
|
+
const DONE = "Close";
|
|
115
|
+
while (true) {
|
|
116
|
+
const liveJobs = manager.getRunningJobs();
|
|
117
|
+
if (liveJobs.length === 0)
|
|
118
|
+
break;
|
|
119
|
+
// Map display label -> job id so we never parse ids back out of
|
|
120
|
+
// free-form label text.
|
|
121
|
+
const labelToId = new Map();
|
|
122
|
+
for (const j of liveJobs) {
|
|
123
|
+
labelToId.set(`${j.id} — ${j.label} (running)`, j.id);
|
|
124
|
+
}
|
|
125
|
+
const options = [...labelToId.keys(), DONE];
|
|
126
|
+
const choice = await ctx.ui.select("Background jobs — pick one to cancel, Escape to close", options);
|
|
127
|
+
// ESC returns undefined; headless may return string[]; DONE closes
|
|
128
|
+
if (!choice || typeof choice !== "string" || choice === DONE)
|
|
129
|
+
break;
|
|
130
|
+
const id = labelToId.get(choice);
|
|
131
|
+
if (!id)
|
|
132
|
+
break;
|
|
133
|
+
const job = liveJobs.find((j) => j.id === id);
|
|
134
|
+
const confirmed = await ctx.ui.confirm("Cancel background job?", `This will stop ${id}${job ? ` — ${job.label}` : ""}. Other jobs keep running.`);
|
|
135
|
+
if (!confirmed)
|
|
136
|
+
continue;
|
|
137
|
+
const r = manager.cancel(id);
|
|
138
|
+
ctx.ui.notify(r === "cancelled" ? `Job ${id} cancelled.` : `Job ${id}: ${r}`, r === "cancelled" ? "success" : "warning");
|
|
139
|
+
}
|
|
140
|
+
// After picker, send a summary of any still-running jobs
|
|
141
|
+
const stillRunning = manager.getRunningJobs();
|
|
142
|
+
const summaryLines = ["## Background Jobs"];
|
|
143
|
+
if (stillRunning.length > 0) {
|
|
144
|
+
summaryLines.push("", "### Running");
|
|
145
|
+
for (const job of stillRunning) {
|
|
146
|
+
const elapsed = ((Date.now() - job.startTime) / 1000).toFixed(0);
|
|
147
|
+
summaryLines.push(`- **${job.id}** — ${job.label} (${elapsed}s)`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const recentCompleted = manager.getRecentJobs(10).filter((j) => j.status !== "running");
|
|
151
|
+
if (recentCompleted.length > 0) {
|
|
152
|
+
summaryLines.push("", "### Recent");
|
|
153
|
+
for (const job of recentCompleted) {
|
|
154
|
+
const elapsed = ((Date.now() - job.startTime) / 1000).toFixed(1);
|
|
155
|
+
summaryLines.push(`- **${job.id}** — ${job.label} (${job.status}, ${elapsed}s)`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (stillRunning.length === 0 && recentCompleted.length === 0) {
|
|
159
|
+
summaryLines.push("", "No background jobs.");
|
|
160
|
+
}
|
|
161
|
+
pi.sendMessage({
|
|
162
|
+
customType: "async_jobs_list",
|
|
163
|
+
content: summaryLines.join("\n"),
|
|
164
|
+
display: true,
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Text-only display: headless/RPC mode, or no running jobs
|
|
104
169
|
const lines = ["## Background Jobs"];
|
|
105
170
|
if (running.length === 0 && completed.length === 0) {
|
|
106
171
|
lines.push("", "No background jobs.");
|