gsd-pi 2.76.0 → 2.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -25
- package/dist/claude-cli-check.js +32 -3
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.js +35 -1
- package/dist/onboarding.js +45 -0
- package/dist/resource-loader.d.ts +1 -1
- package/dist/resource-loader.js +2 -8
- package/dist/resources/agents/researcher.md +1 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
- package/dist/resources/extensions/gsd/auto/loop.js +9 -0
- package/dist/resources/extensions/gsd/auto/phases.js +104 -11
- package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
- package/dist/resources/extensions/gsd/auto/session.js +22 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
- package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
- package/dist/resources/extensions/gsd/auto-start.js +58 -57
- package/dist/resources/extensions/gsd/auto-verification.js +33 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
- package/dist/resources/extensions/gsd/auto.js +70 -28
- package/dist/resources/extensions/gsd/blocked-models.js +68 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
- package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
- package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
- package/dist/resources/extensions/gsd/db-writer.js +88 -16
- package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
- package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
- package/dist/resources/extensions/gsd/error-classifier.js +31 -3
- package/dist/resources/extensions/gsd/exec-history.js +120 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +168 -23
- package/dist/resources/extensions/gsd/guided-flow.js +190 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -1
- package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
- package/dist/resources/extensions/gsd/init-wizard.js +15 -1
- package/dist/resources/extensions/gsd/key-manager.js +28 -0
- package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
- package/dist/resources/extensions/gsd/memory-store.js +19 -0
- package/dist/resources/extensions/gsd/model-router.js +36 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
- package/dist/resources/extensions/gsd/preferences-types.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
- package/dist/resources/extensions/gsd/preferences.js +17 -17
- package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
- package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
- package/dist/resources/extensions/gsd/state.js +43 -4
- package/dist/resources/extensions/gsd/token-counter.js +22 -5
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
- package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
- package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
- package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
- package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
- package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
- package/dist/resources/extensions/search-the-web/native-search.js +45 -13
- package/dist/resources/skills/api-design/SKILL.md +190 -0
- package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
- package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
- package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
- package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
- package/dist/resources/skills/forensics/SKILL.md +153 -0
- package/dist/resources/skills/grill-me/SKILL.md +93 -0
- package/dist/resources/skills/handoff/SKILL.md +121 -0
- package/dist/resources/skills/observability/SKILL.md +174 -0
- package/dist/resources/skills/security-review/SKILL.md +181 -0
- package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
- package/dist/resources/skills/tdd/SKILL.md +112 -0
- package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
- package/dist/resources/skills/write-docs/SKILL.md +82 -0
- package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/required-server-files.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/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 +10 -10
- package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +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/server.js +1 -1
- package/dist/welcome-screen.js +6 -1
- package/dist/wizard.js +2 -0
- package/package.json +1 -1
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
- package/packages/mcp-server/dist/remote-questions.js +732 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +7 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +70 -8
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.d.ts +14 -0
- package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +49 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +163 -25
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -3
- package/packages/mcp-server/src/mcp-server.test.ts +67 -0
- package/packages/mcp-server/src/remote-questions.test.ts +294 -0
- package/packages/mcp-server/src/remote-questions.ts +916 -0
- package/packages/mcp-server/src/server.ts +89 -14
- package/packages/mcp-server/src/session-manager.ts +43 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
- package/packages/mcp-server/src/workflow-tools.ts +215 -43
- package/packages/mcp-server/tsconfig.test.json +19 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +12 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +30 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +14 -0
- package/packages/pi-agent-core/src/types.ts +34 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/custom.d.ts +38 -0
- package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/custom.js +41 -0
- package/packages/pi-ai/dist/models/custom.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +13 -4
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +16 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.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 +12 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/models/custom.ts +42 -0
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
- package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
- package/packages/pi-ai/src/providers/anthropic.ts +15 -4
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
- package/packages/pi-ai/src/providers/simple-options.ts +17 -1
- package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
- package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
- package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
- package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
- package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
- package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
- package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.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.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
- package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
- package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
- package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
- package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
- package/packages/pi-coding-agent/src/core/index.ts +10 -0
- package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
- package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
- package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
- package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
- package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
- package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
- package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
- package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
- package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
- package/packages/pi-coding-agent/src/index.ts +16 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/scripts/link-workspace-packages.cjs +1 -0
- package/src/resources/agents/researcher.md +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
- package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
- package/src/resources/extensions/gsd/auto/loop.ts +9 -0
- package/src/resources/extensions/gsd/auto/phases.ts +131 -10
- package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
- package/src/resources/extensions/gsd/auto/session.ts +35 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
- package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
- package/src/resources/extensions/gsd/auto-start.ts +60 -68
- package/src/resources/extensions/gsd/auto-verification.ts +33 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
- package/src/resources/extensions/gsd/auto.ts +73 -28
- package/src/resources/extensions/gsd/blocked-models.ts +98 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
- package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
- package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
- package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
- package/src/resources/extensions/gsd/db-writer.ts +88 -17
- package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
- package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
- package/src/resources/extensions/gsd/error-classifier.ts +36 -3
- package/src/resources/extensions/gsd/exec-history.ts +153 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -1
- package/src/resources/extensions/gsd/gsd-db.ts +186 -23
- package/src/resources/extensions/gsd/guided-flow.ts +222 -1
- package/src/resources/extensions/gsd/health-widget.ts +3 -1
- package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
- package/src/resources/extensions/gsd/init-wizard.ts +15 -1
- package/src/resources/extensions/gsd/journal.ts +2 -1
- package/src/resources/extensions/gsd/key-manager.ts +28 -0
- package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
- package/src/resources/extensions/gsd/memory-store.ts +26 -0
- package/src/resources/extensions/gsd/model-router.ts +42 -1
- package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
- package/src/resources/extensions/gsd/preferences-types.ts +46 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
- package/src/resources/extensions/gsd/preferences.ts +17 -17
- package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
- package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
- package/src/resources/extensions/gsd/state.ts +45 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
- package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
- package/src/resources/extensions/gsd/token-counter.ts +22 -5
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
- package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
- package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
- package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
- package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
- package/src/resources/extensions/search-the-web/native-search.ts +48 -12
- package/src/resources/skills/api-design/SKILL.md +190 -0
- package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
- package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
- package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
- package/src/resources/skills/design-an-interface/SKILL.md +102 -0
- package/src/resources/skills/forensics/SKILL.md +153 -0
- package/src/resources/skills/grill-me/SKILL.md +93 -0
- package/src/resources/skills/handoff/SKILL.md +121 -0
- package/src/resources/skills/observability/SKILL.md +174 -0
- package/src/resources/skills/security-review/SKILL.md +181 -0
- package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
- package/src/resources/skills/tdd/SKILL.md +112 -0
- package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
- package/src/resources/skills/write-docs/SKILL.md +82 -0
- package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
- /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// GSD2 — Exec (context-mode) tool registration.
|
|
2
|
+
//
|
|
3
|
+
// Exposes the `gsd_exec` tool over MCP. Opt-in: disabled unless
|
|
4
|
+
// `context_mode.enabled: true` is set in preferences.
|
|
5
|
+
|
|
6
|
+
import { Type } from "@sinclair/typebox";
|
|
7
|
+
import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
8
|
+
|
|
9
|
+
import { executeGsdExec } from "../tools/exec-tool.js";
|
|
10
|
+
import { executeExecSearch } from "../tools/exec-search-tool.js";
|
|
11
|
+
import { executeResume } from "../tools/resume-tool.js";
|
|
12
|
+
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
13
|
+
import { logWarning } from "../workflow-logger.js";
|
|
14
|
+
|
|
15
|
+
export function registerExecTools(pi: ExtensionAPI): void {
|
|
16
|
+
pi.registerTool({
|
|
17
|
+
name: "gsd_exec",
|
|
18
|
+
label: "Exec (Sandboxed)",
|
|
19
|
+
description:
|
|
20
|
+
"Run a short script (bash/node/python) in a subprocess. Full stdout/stderr persist to " +
|
|
21
|
+
".gsd/exec/<id>.{stdout,stderr,meta.json}; only a short digest returns in context. Use " +
|
|
22
|
+
"this instead of reading many files or emitting large tool outputs — e.g. have the script " +
|
|
23
|
+
"count/grep/summarize and log the finding. Enabled by default; opt out via " +
|
|
24
|
+
"preferences.context_mode.enabled=false.",
|
|
25
|
+
promptSnippet:
|
|
26
|
+
"Run a bash/node/python script in a sandbox; full output is saved to disk and only a digest returns",
|
|
27
|
+
promptGuidelines: [
|
|
28
|
+
"Prefer gsd_exec for analyses that would otherwise read >3 files or produce large tool output.",
|
|
29
|
+
"Write scripts that log the finding (counts, matches, summaries) rather than raw dumps.",
|
|
30
|
+
"The digest is the last ~300 chars of stdout — size your log output accordingly.",
|
|
31
|
+
"Need the full output? Read the stdout_path returned in details (file on local disk).",
|
|
32
|
+
],
|
|
33
|
+
parameters: Type.Object({
|
|
34
|
+
runtime: Type.Union(
|
|
35
|
+
[Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")],
|
|
36
|
+
{ description: "Interpreter: bash (-c), node (-e), or python3 (-c)." },
|
|
37
|
+
),
|
|
38
|
+
script: Type.String({ description: "Script body. Keep output small (log the finding, not the data)." }),
|
|
39
|
+
purpose: Type.Optional(Type.String({ description: "Short label recorded in meta.json for later review." })),
|
|
40
|
+
timeout_ms: Type.Optional(
|
|
41
|
+
Type.Number({
|
|
42
|
+
description: "Per-invocation timeout (ms). Capped at 600000. Default from preferences.",
|
|
43
|
+
minimum: 1_000,
|
|
44
|
+
maximum: 600_000,
|
|
45
|
+
}),
|
|
46
|
+
),
|
|
47
|
+
}),
|
|
48
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
49
|
+
let prefs: Awaited<ReturnType<typeof loadEffectiveGSDPreferences>> | null = null;
|
|
50
|
+
try {
|
|
51
|
+
prefs = loadEffectiveGSDPreferences();
|
|
52
|
+
} catch (err) {
|
|
53
|
+
logWarning("tool", `gsd_exec could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
|
|
54
|
+
}
|
|
55
|
+
return executeGsdExec(params as Parameters<typeof executeGsdExec>[0], {
|
|
56
|
+
baseDir: process.cwd(),
|
|
57
|
+
preferences: prefs?.preferences ?? null,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
pi.registerTool({
|
|
63
|
+
name: "gsd_exec_search",
|
|
64
|
+
label: "Search gsd_exec History",
|
|
65
|
+
description:
|
|
66
|
+
"List prior gsd_exec runs (most recent first) from .gsd/exec/*.meta.json. Useful for " +
|
|
67
|
+
"rediscovering the stdout_path of an earlier run without re-executing it. Read-only.",
|
|
68
|
+
promptSnippet: "Search prior gsd_exec runs by substring, runtime, or failing-only filter",
|
|
69
|
+
promptGuidelines: [
|
|
70
|
+
"Use this before re-running an expensive analysis — the prior run's stdout file may still answer.",
|
|
71
|
+
"The preview shows the trailing ~300 chars of stdout; read stdout_path for the full transcript.",
|
|
72
|
+
],
|
|
73
|
+
parameters: Type.Object({
|
|
74
|
+
query: Type.Optional(Type.String({ description: "Substring matched against id and purpose (case-insensitive)." })),
|
|
75
|
+
runtime: Type.Optional(
|
|
76
|
+
Type.Union([Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")], {
|
|
77
|
+
description: "Restrict to one runtime.",
|
|
78
|
+
}),
|
|
79
|
+
),
|
|
80
|
+
failing_only: Type.Optional(Type.Boolean({ description: "Only non-zero exit codes and timeouts." })),
|
|
81
|
+
limit: Type.Optional(Type.Number({ description: "Max results (default 20, cap 200)", minimum: 1, maximum: 200 })),
|
|
82
|
+
}),
|
|
83
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
84
|
+
return executeExecSearch(params as Parameters<typeof executeExecSearch>[0], {
|
|
85
|
+
baseDir: process.cwd(),
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
pi.registerTool({
|
|
91
|
+
name: "gsd_resume",
|
|
92
|
+
label: "Resume (Read Snapshot)",
|
|
93
|
+
description:
|
|
94
|
+
"Return the contents of .gsd/last-snapshot.md — a ≤2 KB digest of top memories, recent " +
|
|
95
|
+
"gsd_exec runs, and active context, written automatically on session_before_compact. Use " +
|
|
96
|
+
"this after compaction or session resume to re-orient quickly.",
|
|
97
|
+
promptSnippet: "Read the pre-compaction snapshot to re-orient after context loss",
|
|
98
|
+
promptGuidelines: [
|
|
99
|
+
"Call this right after a session resumes if you feel you've lost durable context.",
|
|
100
|
+
"The snapshot is a summary — use memory_query or gsd_exec_search for detail.",
|
|
101
|
+
],
|
|
102
|
+
parameters: Type.Object({}),
|
|
103
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
104
|
+
return executeResume(params as Parameters<typeof executeResume>[0], {
|
|
105
|
+
baseDir: process.cwd(),
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -50,6 +50,11 @@ export function registerMemoryTools(pi: ExtensionAPI): void {
|
|
|
50
50
|
),
|
|
51
51
|
tags: Type.Optional(Type.Array(Type.String(), { description: "Free-form tags (reserved for future use)" })),
|
|
52
52
|
scope: Type.Optional(Type.String({ description: "Scope name (reserved for future use; defaults to project)" })),
|
|
53
|
+
structuredFields: Type.Optional(
|
|
54
|
+
Type.Record(Type.String(), Type.Unknown(), {
|
|
55
|
+
description: "Optional structured payload preserved alongside content (ADR-013). Use for decisions to retain scope/decision/choice/rationale/made_by/revisable. Omit for plain captures.",
|
|
56
|
+
}),
|
|
57
|
+
),
|
|
53
58
|
}),
|
|
54
59
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
55
60
|
const ok = await ensureDbOpen();
|
|
@@ -8,6 +8,7 @@ import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-exten
|
|
|
8
8
|
import { loadEcosystemExtensions } from "../ecosystem/loader.js";
|
|
9
9
|
import { registerDbTools } from "./db-tools.js";
|
|
10
10
|
import { registerDynamicTools } from "./dynamic-tools.js";
|
|
11
|
+
import { registerExecTools } from "./exec-tools.js";
|
|
11
12
|
import { registerJournalTools } from "./journal-tools.js";
|
|
12
13
|
import { registerMemoryTools } from "./memory-tools.js";
|
|
13
14
|
import { registerQueryTools } from "./query-tools.js";
|
|
@@ -66,6 +67,19 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
|
66
67
|
registerWorktreeCommand(pi);
|
|
67
68
|
registerExitCommand(pi);
|
|
68
69
|
|
|
70
|
+
// Wire the Layer 2 event emitter bridge so deeply-nested GSD code can emit
|
|
71
|
+
// extension events (git lifecycle, verify, budget, milestone, unit) without
|
|
72
|
+
// threading `pi` through every call site.
|
|
73
|
+
import("../hook-emitter.js")
|
|
74
|
+
.then(({ setHookEmitter }) => setHookEmitter(pi))
|
|
75
|
+
.catch((err) => {
|
|
76
|
+
// Non-fatal — emitters simply become no-ops if this import fails, but
|
|
77
|
+
// surface the failure so silent bootstrap breakage is debuggable.
|
|
78
|
+
process.stderr.write(
|
|
79
|
+
`[gsd] Failed to bootstrap hook-emitter bridge: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`,
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
69
83
|
installEpipeGuard();
|
|
70
84
|
|
|
71
85
|
// Ecosystem handlers captured by the GSDExtensionAPI wrapper for the
|
|
@@ -87,6 +101,7 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
|
87
101
|
["journal-tools", () => registerJournalTools(pi)],
|
|
88
102
|
["query-tools", () => registerQueryTools(pi)],
|
|
89
103
|
["memory-tools", () => registerMemoryTools(pi)],
|
|
104
|
+
["exec-tools", () => registerExecTools(pi)],
|
|
90
105
|
["shortcuts", () => registerShortcuts(pi)],
|
|
91
106
|
["hooks", () => registerHooks(pi, ecosystemHandlers)],
|
|
92
107
|
["ecosystem", () => {
|
|
@@ -18,12 +18,13 @@ import { loadToolApiKeys } from "../commands-config.js";
|
|
|
18
18
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
19
19
|
import { deriveState } from "../state.js";
|
|
20
20
|
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto.js";
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
|
|
23
23
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
24
24
|
import { saveActivityLog } from "../activity-log.js";
|
|
25
25
|
import { resetAskUserQuestionsCache } from "../../ask-user-questions.js";
|
|
26
|
-
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult } from "../safety/evidence-collector.js";
|
|
26
|
+
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
|
|
27
|
+
import { parseUnitId } from "../unit-id.js";
|
|
27
28
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
28
29
|
import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
29
30
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
@@ -48,7 +49,9 @@ export function registerHooks(
|
|
|
48
49
|
initNotificationStore(process.cwd());
|
|
49
50
|
installNotifyInterceptor(ctx);
|
|
50
51
|
initNotificationWidget(ctx);
|
|
51
|
-
|
|
52
|
+
if (!isAutoActive()) {
|
|
53
|
+
initHealthWidget(ctx);
|
|
54
|
+
}
|
|
52
55
|
resetWriteGateState();
|
|
53
56
|
resetToolCallLoopGuard();
|
|
54
57
|
resetAskUserQuestionsCache();
|
|
@@ -90,7 +93,7 @@ export function registerHooks(
|
|
|
90
93
|
}
|
|
91
94
|
loadToolApiKeys();
|
|
92
95
|
if (isAutoActive()) {
|
|
93
|
-
ctx.ui.
|
|
96
|
+
ctx.ui.setWidget("gsd-health", undefined);
|
|
94
97
|
}
|
|
95
98
|
});
|
|
96
99
|
|
|
@@ -113,7 +116,7 @@ export function registerHooks(
|
|
|
113
116
|
}
|
|
114
117
|
loadToolApiKeys();
|
|
115
118
|
if (isAutoActive()) {
|
|
116
|
-
ctx.ui.
|
|
119
|
+
ctx.ui.setWidget("gsd-health", undefined);
|
|
117
120
|
}
|
|
118
121
|
});
|
|
119
122
|
|
|
@@ -225,6 +228,42 @@ export function registerHooks(
|
|
|
225
228
|
}));
|
|
226
229
|
});
|
|
227
230
|
|
|
231
|
+
// Context-mode snapshot: write .gsd/last-snapshot.md before compaction so
|
|
232
|
+
// agents can call gsd_resume (or Read the file) to re-orient. Opt-in via
|
|
233
|
+
// preferences.context_mode.enabled. Runs after the auto-cancel handler
|
|
234
|
+
// above — if that one returned cancel:true, pi still fires us but the
|
|
235
|
+
// compaction won't actually happen; the snapshot is still useful then,
|
|
236
|
+
// since auto may pause and resume later.
|
|
237
|
+
pi.on("session_before_compact", async () => {
|
|
238
|
+
try {
|
|
239
|
+
const { loadEffectiveGSDPreferences } = await import("../preferences.js");
|
|
240
|
+
const { isContextModeEnabled } = await import("../preferences-types.js");
|
|
241
|
+
const prefs = loadEffectiveGSDPreferences();
|
|
242
|
+
if (!isContextModeEnabled(prefs?.preferences)) return;
|
|
243
|
+
const { writeCompactionSnapshot } = await import("../compaction-snapshot.js");
|
|
244
|
+
const { ensureDbOpen } = await import("./dynamic-tools.js");
|
|
245
|
+
await ensureDbOpen();
|
|
246
|
+
const basePath = process.cwd();
|
|
247
|
+
let activeContext: string | null = null;
|
|
248
|
+
try {
|
|
249
|
+
const state = await deriveState(basePath);
|
|
250
|
+
if (state.activeMilestone && state.activeSlice && state.activeTask) {
|
|
251
|
+
activeContext =
|
|
252
|
+
`Active: ${state.activeMilestone.id} / ${state.activeSlice.id} / ${state.activeTask.id}` +
|
|
253
|
+
(state.activeTask.title ? ` — ${state.activeTask.title}` : "");
|
|
254
|
+
}
|
|
255
|
+
} catch {
|
|
256
|
+
/* non-fatal */
|
|
257
|
+
}
|
|
258
|
+
writeCompactionSnapshot(basePath, { activeContext });
|
|
259
|
+
} catch (err) {
|
|
260
|
+
safetyLogWarning(
|
|
261
|
+
"context-mode",
|
|
262
|
+
`failed to write compaction snapshot: ${err instanceof Error ? err.message : String(err)}`,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
228
267
|
pi.on("session_shutdown", async (_event, ctx: ExtensionContext) => {
|
|
229
268
|
if (isParallelActive()) {
|
|
230
269
|
try {
|
|
@@ -445,7 +484,7 @@ export function registerHooks(
|
|
|
445
484
|
|
|
446
485
|
pi.on("tool_execution_start", async (event) => {
|
|
447
486
|
if (!isAutoActive()) return;
|
|
448
|
-
markToolStart(event.toolCallId);
|
|
487
|
+
markToolStart(event.toolCallId, event.toolName);
|
|
449
488
|
});
|
|
450
489
|
|
|
451
490
|
pi.on("tool_execution_end", async (event) => {
|
|
@@ -461,6 +500,15 @@ export function registerHooks(
|
|
|
461
500
|
// Safety harness: record tool execution results for evidence cross-referencing
|
|
462
501
|
if (isAutoActive()) {
|
|
463
502
|
safetyRecordToolResult(event.toolCallId, event.toolName, event.result, event.isError);
|
|
503
|
+
// Persist evidence to disk after each tool result so it survives a session
|
|
504
|
+
// restart mid-unit (Bug #4385 — non-persisted evidence false positives).
|
|
505
|
+
const dash = getAutoDashboardData();
|
|
506
|
+
if (dash.basePath && dash.currentUnit?.type === "execute-task") {
|
|
507
|
+
const { milestone: pMid, slice: pSid, task: pTid } = parseUnitId(dash.currentUnit.id);
|
|
508
|
+
if (pMid && pSid && pTid) {
|
|
509
|
+
saveEvidenceToDisk(dash.basePath, pMid, pSid, pTid);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
464
512
|
}
|
|
465
513
|
});
|
|
466
514
|
|
|
@@ -29,10 +29,30 @@ const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
|
29
29
|
* hardcoding absolute paths in the system prompt template. Only skills
|
|
30
30
|
* that actually exist on disk are included in the table. (#3575)
|
|
31
31
|
*/
|
|
32
|
-
const BUNDLED_SKILL_TRIGGERS: Array<{ trigger: string; skill: string }> = [
|
|
32
|
+
export const BUNDLED_SKILL_TRIGGERS: Array<{ trigger: string; skill: string }> = [
|
|
33
33
|
{ trigger: "Frontend UI - web components, pages, landing pages, dashboards, React/HTML/CSS, styling", skill: "frontend-design" },
|
|
34
34
|
{ trigger: "macOS or iOS apps - SwiftUI, Xcode, App Store", skill: "swiftui" },
|
|
35
35
|
{ trigger: "Debugging - complex bugs, failing tests, root-cause investigation after standard approaches fail", skill: "debug-like-expert" },
|
|
36
|
+
{ trigger: "Code review - security, performance, bugs, quality review of staged/unstaged diffs or PRs", skill: "review" },
|
|
37
|
+
{ trigger: "Test generation or execution - auto-detect framework, generate tests, run suite, analyze failures", skill: "test" },
|
|
38
|
+
{ trigger: "Linting/formatting - run the detected linter/formatter with auto-fix, report remaining issues", skill: "lint" },
|
|
39
|
+
{ trigger: "Polishing UI details - animations, hover states, typography, borders, micro-interactions, optical alignment", skill: "make-interfaces-feel-better" },
|
|
40
|
+
{ trigger: "Accessibility audit - WCAG, screen reader, keyboard navigation, a11y review", skill: "accessibility" },
|
|
41
|
+
{ trigger: "Planning interviews - stress-test a plan, grill the user, resolve decision trees one branch at a time", skill: "grill-me" },
|
|
42
|
+
{ trigger: "Interface design - produce 3+ radically different designs for a module/API, compare in prose, synthesize", skill: "design-an-interface" },
|
|
43
|
+
{ trigger: "TDD - red-green-refactor vertical slices, never refactor while red, tests survive refactors", skill: "tdd" },
|
|
44
|
+
{ trigger: "Draft a milestone brief (M###-CONTEXT.md) or PRD from current conversation context", skill: "write-milestone-brief" },
|
|
45
|
+
{ trigger: "Break a plan into vertical-slice roadmap slices (M###-ROADMAP.md) or GitHub issues with dependency ordering", skill: "decompose-into-slices" },
|
|
46
|
+
{ trigger: "Package spike findings into a reusable project-local skill at .claude/skills/", skill: "spike-wrap-up" },
|
|
47
|
+
{ trigger: "Block completion claims until verification evidence has been produced in this message", skill: "verify-before-complete" },
|
|
48
|
+
{ trigger: "Create a Model Context Protocol (MCP) server — tool design, error handling, Inspector testing, evals", skill: "create-mcp-server" },
|
|
49
|
+
{ trigger: "Write documentation, proposals, specs, RFCs, or READMEs for a fresh reader", skill: "write-docs" },
|
|
50
|
+
{ trigger: "Post-mortem a failed GSD auto-mode run using .gsd/activity, .gsd/journal, and .gsd/metrics.json", skill: "forensics" },
|
|
51
|
+
{ trigger: "Prepare a clean cross-session handoff — continue.md + summary updates (pause/resume work)", skill: "handoff" },
|
|
52
|
+
{ trigger: "Security review with STRIDE threat modeling and exploit-scenario reporting", skill: "security-review" },
|
|
53
|
+
{ trigger: "HTTP/REST/GraphQL API design — verbs, status codes, pagination, errors, idempotency, versioning", skill: "api-design" },
|
|
54
|
+
{ trigger: "Dependency upgrades — risk-batched, verified between batches, one major per commit", skill: "dependency-upgrade" },
|
|
55
|
+
{ trigger: "Agent-first observability — structured logs, persisted failure state, health surfaces, explicit failure modes", skill: "observability" },
|
|
36
56
|
];
|
|
37
57
|
|
|
38
58
|
function buildBundledSkillsTable(): string {
|
|
@@ -111,36 +131,21 @@ export async function buildBeforeAgentStartResult(
|
|
|
111
131
|
);
|
|
112
132
|
}
|
|
113
133
|
|
|
114
|
-
|
|
134
|
+
// ADR-013 step 5: opportunistic decisions->memories backfill. Idempotent
|
|
135
|
+
// and best-effort — first run absorbs the existing decisions table into
|
|
136
|
+
// the memory store; subsequent runs are a single sentinel SELECT.
|
|
115
137
|
try {
|
|
116
|
-
const {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const CRITICAL_CATEGORIES = new Set(["gotcha", "environment", "convention"]);
|
|
121
|
-
const allRanked = getActiveMemoriesRanked(60);
|
|
122
|
-
const critical = allRanked.filter((m) => CRITICAL_CATEGORIES.has(m.category)).slice(0, 5);
|
|
123
|
-
const criticalIds = new Set(critical.map((m) => m.id));
|
|
124
|
-
|
|
125
|
-
// Prompt-relevance set — hybrid FTS5 + (future) semantic retrieval.
|
|
126
|
-
let relevant: typeof allRanked = [];
|
|
127
|
-
const userPrompt = (event.prompt ?? "").trim();
|
|
128
|
-
if (userPrompt) {
|
|
129
|
-
const hits = queryMemoriesRanked({ query: userPrompt, k: 10 });
|
|
130
|
-
relevant = hits.map((h) => h.memory).filter((m) => !criticalIds.has(m.id));
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const merged = [...critical, ...relevant];
|
|
134
|
-
if (merged.length > 0) {
|
|
135
|
-
const formatted = formatMemoriesForPrompt(merged, 2000);
|
|
136
|
-
if (formatted) {
|
|
137
|
-
memoryBlock = `\n\n${formatted}`;
|
|
138
|
-
}
|
|
138
|
+
const { backfillDecisionsToMemories } = await import("../memory-backfill.js");
|
|
139
|
+
const written = backfillDecisionsToMemories();
|
|
140
|
+
if (written > 0) {
|
|
141
|
+
ctx.ui.notify(`GSD: backfilled ${written} decision${written === 1 ? "" : "s"} into the memory store (ADR-013).`, "info");
|
|
139
142
|
}
|
|
140
143
|
} catch (e) {
|
|
141
|
-
logWarning("bootstrap", `
|
|
144
|
+
logWarning("bootstrap", `decisions backfill failed: ${(e as Error).message}`);
|
|
142
145
|
}
|
|
143
146
|
|
|
147
|
+
const memoryBlock = await loadMemoryBlock(event.prompt ?? "");
|
|
148
|
+
|
|
144
149
|
let newSkillsBlock = "";
|
|
145
150
|
if (hasSkillSnapshot()) {
|
|
146
151
|
const newSkills = detectNewSkills();
|
|
@@ -220,6 +225,64 @@ export async function buildBeforeAgentStartResult(
|
|
|
220
225
|
};
|
|
221
226
|
}
|
|
222
227
|
|
|
228
|
+
/**
|
|
229
|
+
* ADR-013 step 4 — auto-injection parity for the memories table.
|
|
230
|
+
*
|
|
231
|
+
* Mirrors loadKnowledgeBlock by producing a labeled, deterministic block
|
|
232
|
+
* combining two memory sets:
|
|
233
|
+
*
|
|
234
|
+
* 1. Always-on "critical" set — top-ranked active memories in categories
|
|
235
|
+
* that future GSD turns generally want without asking. After ADR-013
|
|
236
|
+
* expands this to include "architecture", these memories serve as the
|
|
237
|
+
* auto-injected replacement for inlineDecisionsFromDb when the cutover
|
|
238
|
+
* in step 6 lands.
|
|
239
|
+
* 2. Prompt-relevance set — FTS5/semantic hits against the current user
|
|
240
|
+
* prompt, deduplicated against the critical set.
|
|
241
|
+
*
|
|
242
|
+
* Both sets are ranked, merged, and rendered via formatMemoriesForPrompt
|
|
243
|
+
* with a token-budget cap. Failures degrade gracefully — the function never
|
|
244
|
+
* throws and returns "" so the system prompt construction continues.
|
|
245
|
+
*/
|
|
246
|
+
export async function loadMemoryBlock(userPrompt: string): Promise<string> {
|
|
247
|
+
try {
|
|
248
|
+
const { formatMemoriesForPrompt, getActiveMemoriesRanked, queryMemoriesRanked } = await import("../memory-store.js");
|
|
249
|
+
|
|
250
|
+
// Categories that belong in every turn. Pre-ADR-013 this was just
|
|
251
|
+
// {gotcha, environment, convention}. ADR-013 adds "architecture" so
|
|
252
|
+
// decision-equivalent memories survive the inlineDecisionsFromDb cutover
|
|
253
|
+
// in step 6.
|
|
254
|
+
const CRITICAL_CATEGORIES = new Set(["gotcha", "environment", "convention", "architecture"]);
|
|
255
|
+
const CRITICAL_CAP = 8;
|
|
256
|
+
const QUERY_K = 10;
|
|
257
|
+
// ~1 token ≈ 4 chars. 4000 chars ≈ 1000 tokens — comfortably under the
|
|
258
|
+
// KNOWLEDGE.md 4KB warning threshold and roughly twice the pre-ADR-013
|
|
259
|
+
// budget so the absorbed DECISIONS surface fits.
|
|
260
|
+
const CHAR_BUDGET = 4000;
|
|
261
|
+
|
|
262
|
+
const allRanked = getActiveMemoriesRanked(80);
|
|
263
|
+
const critical = allRanked.filter((m) => CRITICAL_CATEGORIES.has(m.category)).slice(0, CRITICAL_CAP);
|
|
264
|
+
const criticalIds = new Set(critical.map((m) => m.id));
|
|
265
|
+
|
|
266
|
+
let relevant: typeof allRanked = [];
|
|
267
|
+
const trimmed = userPrompt.trim();
|
|
268
|
+
if (trimmed) {
|
|
269
|
+
const hits = queryMemoriesRanked({ query: trimmed, k: QUERY_K });
|
|
270
|
+
relevant = hits.map((h) => h.memory).filter((m) => !criticalIds.has(m.id));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const merged = [...critical, ...relevant];
|
|
274
|
+
if (merged.length === 0) return "";
|
|
275
|
+
|
|
276
|
+
const formatted = formatMemoriesForPrompt(merged, CHAR_BUDGET);
|
|
277
|
+
if (!formatted) return "";
|
|
278
|
+
|
|
279
|
+
return `\n\n[MEMORY — Critical and prompt-relevant memories from the GSD memory store]\n\n${formatted}`;
|
|
280
|
+
} catch (e) {
|
|
281
|
+
logWarning("bootstrap", `memory block fetch failed: ${(e as Error).message}`);
|
|
282
|
+
return "";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
223
286
|
export function loadKnowledgeBlock(gsdHomeDir: string, cwd: string): { block: string; globalSizeKb: number } {
|
|
224
287
|
// 1. Global knowledge (~/.gsd/agent/KNOWLEDGE.md) — cross-project, user-maintained
|
|
225
288
|
let globalKnowledge = "";
|
|
@@ -28,8 +28,29 @@ const QUEUE_SAFE_TOOLS = new Set([
|
|
|
28
28
|
/**
|
|
29
29
|
* Bash commands that are read-only / investigative — safe during queue mode.
|
|
30
30
|
* Matches the leading command in a bash invocation.
|
|
31
|
+
*
|
|
32
|
+
* Extension policy: add commands here when they are read-only / diagnostic.
|
|
33
|
+
* Never add commands that mutate project state (write files, run builds that
|
|
34
|
+
* emit artifacts, install packages, etc.).
|
|
35
|
+
*
|
|
36
|
+
* Current read-only additions (Bug #4385):
|
|
37
|
+
* npm run <diagnostic> — read-only diagnostic scripts: test, lint, typecheck, etc.
|
|
38
|
+
* NOT: build, install, compile, generate, deploy (artifact-producing)
|
|
39
|
+
* npm ls/list/info — inspect installed packages (read-only)
|
|
40
|
+
* npm outdated/audit — security/update checks (read-only)
|
|
41
|
+
* npx <pkg> — run a package binary without installing globally
|
|
42
|
+
* tsx — TypeScript runner used for dry-run / inspection scripts
|
|
43
|
+
* node --print — evaluate and print an expression, no side effects
|
|
44
|
+
* python / python3 — script inspection, version checks
|
|
45
|
+
* pip / pip3 show — show installed package info (read-only)
|
|
46
|
+
* jq — read-only JSON query
|
|
47
|
+
* yq — read-only YAML query
|
|
48
|
+
* curl -s / curl --silent — fetch for inspection (no -o / no output redirect)
|
|
49
|
+
* openssl version — version / certificate inspection
|
|
50
|
+
* env / printenv — print environment variables
|
|
51
|
+
* true / false — shell no-ops / test exit codes
|
|
31
52
|
*/
|
|
32
|
-
const BASH_READ_ONLY_RE = /^\s*(cat|head|tail|less|more|wc|file|stat|du|df|which|type|echo|printf|ls|find|grep|rg|awk|sed\b(?!.*-i)|sort|uniq|diff|comm|tr|cut|tee\s+-a\s+\/dev\/null|git\s+(log|show|diff|status|branch|tag|remote|rev-parse|ls-files|blame|shortlog|describe|stash\s+list|config\s+--get|cat-file)|gh\s+(issue|pr|api|repo|release)\s+(view|list|diff|status|checks)|mkdir\s+-p\s+\.gsd|rtk\s)/;
|
|
53
|
+
const BASH_READ_ONLY_RE = /^\s*(cat|head|tail|less|more|wc|file|stat|du|df|which|type|echo|printf|ls|find|grep|rg|awk|sed\b(?!.*-i)|sort|uniq|diff|comm|tr|cut|tee\s+-a\s+\/dev\/null|git\s+(log|show|diff|status|branch|tag|remote|rev-parse|ls-files|blame|shortlog|describe|stash\s+list|config\s+--get|cat-file)|gh\s+(issue|pr|api|repo|release)\s+(view|list|diff|status|checks)|mkdir\s+-p\s+\.gsd|rtk\s|npm\s+run\s+(test|test:\w+|lint|lint:\w+|typecheck|type-check|type-check:\w+|check|verify|audit|outdated|format:check|ci|validate)\b|npm\s+(ls|list|info|view|show|outdated|audit|explain|doctor|ping|--version|-v)\b|npx\s|tsx\s|node\s+(--print|--version|-v\b)|python[23]?\s+(-c\s+'[^']*'|--version|-V\b|-m\s+(pip\s+show|pip\s+list|site))|pip[23]?\s+(show|list|freeze|check|index\s+versions)\b|jq\s|yq\s|curl\s+(-s\b|--silent\b)(?!\s+[^|>]*\s-[oO]\b)(?!\s+[^|>]*\s--output\b)[^|>]*$|openssl\s+(version|x509|s_client)|env\b|printenv\b|true\b|false\b)/;
|
|
33
54
|
|
|
34
55
|
const verifiedDepthMilestones = new Set<string>();
|
|
35
56
|
let activeQueuePhase = false;
|
|
@@ -117,9 +138,21 @@ function normalizeWriteGateSnapshot(value: unknown): WriteGateSnapshot {
|
|
|
117
138
|
};
|
|
118
139
|
}
|
|
119
140
|
|
|
141
|
+
const EMPTY_SNAPSHOT: WriteGateSnapshot = {
|
|
142
|
+
verifiedDepthMilestones: [],
|
|
143
|
+
activeQueuePhase: false,
|
|
144
|
+
pendingGateId: null,
|
|
145
|
+
};
|
|
146
|
+
|
|
120
147
|
export function loadWriteGateSnapshot(basePath: string = process.cwd()): WriteGateSnapshot {
|
|
121
148
|
const path = writeGateSnapshotPath(basePath);
|
|
122
|
-
if (!existsSync(path))
|
|
149
|
+
if (!existsSync(path)) {
|
|
150
|
+
// When persist mode is active and the file has been deleted, treat it as a
|
|
151
|
+
// full state reset so deleting the file clears the HARD BLOCK gate.
|
|
152
|
+
// In non-persist mode the file is never written, so fall back to in-memory.
|
|
153
|
+
if (shouldPersistWriteGateSnapshot()) return EMPTY_SNAPSHOT;
|
|
154
|
+
return currentWriteGateSnapshot();
|
|
155
|
+
}
|
|
123
156
|
try {
|
|
124
157
|
return normalizeWriteGateSnapshot(JSON.parse(readFileSync(path, "utf-8")));
|
|
125
158
|
} catch {
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* clean-root-preflight.ts — Preflight gate for dirty working trees before milestone merges.
|
|
3
|
+
*
|
|
4
|
+
* #2909: Adds a fast-path git status check before milestone completion merges.
|
|
5
|
+
* When the working tree is dirty the user is warned and changes are auto-stashed
|
|
6
|
+
* so the merge can proceed cleanly. After the merge completes, postflightPopStash
|
|
7
|
+
* restores the stashed changes.
|
|
8
|
+
*
|
|
9
|
+
* Design constraints (from Trek-e approval):
|
|
10
|
+
* - Warn the user before stashing (no silent surprises)
|
|
11
|
+
* - git stash push / git stash pop only — no custom stash management layer
|
|
12
|
+
* - Stash/pop errors are logged but MUST NOT block the merge
|
|
13
|
+
* - Fast-path status check — clean trees pay no extra cost
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
18
|
+
import { logWarning } from "./workflow-logger.js";
|
|
19
|
+
import { nativeHasChanges } from "./native-git-bridge.js";
|
|
20
|
+
|
|
21
|
+
export interface PreflightResult {
|
|
22
|
+
/** true when a stash was pushed and postflightPopStash should be called */
|
|
23
|
+
stashPushed: boolean;
|
|
24
|
+
/** human-readable summary of what happened (empty string for clean trees) */
|
|
25
|
+
summary: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check the working tree for dirty files before a milestone merge.
|
|
30
|
+
*
|
|
31
|
+
* Clean tree path: O(1) — returns immediately with stashPushed=false.
|
|
32
|
+
*
|
|
33
|
+
* Dirty tree path:
|
|
34
|
+
* 1. Emits a warning notification via the provided `notify` callback.
|
|
35
|
+
* 2. Runs `git stash push --include-untracked -m "gsd-preflight-stash"`.
|
|
36
|
+
* 3. Returns stashPushed=true so the caller knows to call postflightPopStash.
|
|
37
|
+
*
|
|
38
|
+
* Any stash error is logged but does NOT throw — the merge proceeds regardless.
|
|
39
|
+
*/
|
|
40
|
+
export function preflightCleanRoot(
|
|
41
|
+
basePath: string,
|
|
42
|
+
milestoneId: string,
|
|
43
|
+
notify: (message: string, level: "info" | "warning" | "error") => void,
|
|
44
|
+
): PreflightResult {
|
|
45
|
+
// Fast-path: clean tree — nothing to do
|
|
46
|
+
let isDirty = false;
|
|
47
|
+
try {
|
|
48
|
+
isDirty = nativeHasChanges(basePath);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
// If the status check itself fails, treat as clean and let the merge decide
|
|
51
|
+
logWarning("preflight", `clean-root status check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
52
|
+
return { stashPushed: false, summary: "" };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!isDirty) {
|
|
56
|
+
return { stashPushed: false, summary: "" };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Warn the user before stashing
|
|
60
|
+
const warnMsg = `Working tree has uncommitted changes before milestone ${milestoneId} merge. Auto-stashing to allow clean merge (stash will be restored after merge).`;
|
|
61
|
+
notify(warnMsg, "warning");
|
|
62
|
+
|
|
63
|
+
// Push the stash
|
|
64
|
+
try {
|
|
65
|
+
execFileSync("git", ["stash", "push", "--include-untracked", "-m", "gsd-preflight-stash"], {
|
|
66
|
+
cwd: basePath,
|
|
67
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
68
|
+
encoding: "utf-8",
|
|
69
|
+
env: GIT_NO_PROMPT_ENV,
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
stashPushed: true,
|
|
73
|
+
summary: `Stashed uncommitted changes before merge (milestone ${milestoneId}).`,
|
|
74
|
+
};
|
|
75
|
+
} catch (err) {
|
|
76
|
+
// Stash failure is non-fatal — log and let the merge attempt proceed
|
|
77
|
+
const msg = `git stash push failed before merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`;
|
|
78
|
+
logWarning("preflight", msg);
|
|
79
|
+
notify(`Auto-stash failed before milestone ${milestoneId} merge — proceeding anyway. ${msg}`, "warning");
|
|
80
|
+
return { stashPushed: false, summary: `stash-push-failed: ${msg}` };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Restore stashed changes after a milestone merge completes.
|
|
86
|
+
*
|
|
87
|
+
* Only called when preflightCleanRoot returned stashPushed=true.
|
|
88
|
+
* Any pop error (e.g. conflict) is logged and notified but does NOT throw —
|
|
89
|
+
* the merge already completed successfully.
|
|
90
|
+
*/
|
|
91
|
+
export function postflightPopStash(
|
|
92
|
+
basePath: string,
|
|
93
|
+
milestoneId: string,
|
|
94
|
+
notify: (message: string, level: "info" | "warning" | "error") => void,
|
|
95
|
+
): void {
|
|
96
|
+
try {
|
|
97
|
+
execFileSync("git", ["stash", "pop"], {
|
|
98
|
+
cwd: basePath,
|
|
99
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
100
|
+
encoding: "utf-8",
|
|
101
|
+
env: GIT_NO_PROMPT_ENV,
|
|
102
|
+
});
|
|
103
|
+
notify(`Restored stashed changes after milestone ${milestoneId} merge.`, "info");
|
|
104
|
+
} catch (err) {
|
|
105
|
+
// Pop conflicts mean the merged code collides with the stashed changes.
|
|
106
|
+
// Log a warning — the user needs to resolve manually, but the merge succeeded.
|
|
107
|
+
const msg = `git stash pop failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. Run "git stash pop" manually to restore your changes.`;
|
|
108
|
+
logWarning("preflight", msg);
|
|
109
|
+
notify(msg, "warning");
|
|
110
|
+
}
|
|
111
|
+
}
|