@opengsd/gsd-pi 1.0.2-dev.867e002 → 1.0.2-dev.a271e2d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/onboarding.js +22 -3
- package/dist/resource-loader.js +3 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/context7/index.js +12 -2
- package/dist/resources/extensions/get-secrets-from-user.js +16 -16
- package/dist/resources/extensions/google-cli/index.js +30 -0
- package/dist/resources/extensions/google-cli/models.js +55 -0
- package/dist/resources/extensions/google-cli/package.json +11 -0
- package/dist/resources/extensions/google-cli/readiness.js +12 -0
- package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
- package/dist/resources/extensions/gsd/auto/loop.js +62 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +37 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
- package/dist/resources/extensions/gsd/auto-post-unit.js +21 -11
- package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-start.js +232 -49
- package/dist/resources/extensions/gsd/auto.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
- package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
- package/dist/resources/extensions/gsd/commands-usage.js +105 -1
- package/dist/resources/extensions/gsd/config-overlay.js +20 -14
- package/dist/resources/extensions/gsd/context-overlay.js +22 -16
- package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
- package/dist/resources/extensions/gsd/doctor.js +6 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
- package/dist/resources/extensions/gsd/guided-flow.js +5 -6
- package/dist/resources/extensions/gsd/key-manager.js +45 -13
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
- package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
- package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
- package/dist/resources/extensions/gsd/preferences.js +14 -2
- package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -3
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
- package/dist/resources/extensions/gsd/repository-registry.js +3 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +11 -4
- package/dist/resources/extensions/gsd/skill-activation.js +233 -0
- package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
- package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
- package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
- package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
- package/dist/resources/extensions/gsd/skill-scope.js +52 -0
- package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
- package/dist/resources/extensions/gsd/skills.js +60 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
- package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
- package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
- package/dist/resources/extensions/gsd/vision-ask.js +22 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
- package/dist/resources/extensions/search-the-web/native-search.js +57 -8
- package/dist/resources/extensions/shared/confirm-ui.js +9 -6
- package/dist/resources/extensions/shared/dialog-frame.js +42 -0
- package/dist/resources/extensions/shared/interview-ui.js +42 -30
- package/dist/resources/extensions/shared/next-action-ui.js +6 -6
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
- package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.test.js +5 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +7 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +8 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/dist/workflow.test.js +1 -0
- package/packages/contracts/dist/workflow.test.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +28 -5
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/skills.js +6 -0
- package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +8 -59
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +21 -72
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +50 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
- package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +3 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/context7/index.ts +15 -2
- package/src/resources/extensions/get-secrets-from-user.ts +17 -16
- package/src/resources/extensions/google-cli/index.ts +34 -0
- package/src/resources/extensions/google-cli/models.ts +57 -0
- package/src/resources/extensions/google-cli/package.json +11 -0
- package/src/resources/extensions/google-cli/readiness.ts +15 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
- package/src/resources/extensions/gsd/auto/loop.ts +74 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +46 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +43 -14
- package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
- package/src/resources/extensions/gsd/auto-start.ts +307 -56
- package/src/resources/extensions/gsd/auto.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
- package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
- package/src/resources/extensions/gsd/commands-usage.ts +110 -5
- package/src/resources/extensions/gsd/config-overlay.ts +19 -16
- package/src/resources/extensions/gsd/context-overlay.ts +24 -19
- package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +6 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
- package/src/resources/extensions/gsd/guided-flow.ts +5 -6
- package/src/resources/extensions/gsd/key-manager.ts +57 -14
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
- package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
- package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
- package/src/resources/extensions/gsd/preferences.ts +17 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -3
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
- package/src/resources/extensions/gsd/repository-registry.ts +3 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -4
- package/src/resources/extensions/gsd/skill-activation.ts +292 -0
- package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
- package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
- package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
- package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
- package/src/resources/extensions/gsd/skill-scope.ts +63 -0
- package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
- package/src/resources/extensions/gsd/skills.ts +75 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
- package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
- package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +74 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
- package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
- package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
- package/src/resources/extensions/gsd/vision-ask.ts +28 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
- package/src/resources/extensions/search-the-web/native-search.ts +60 -8
- package/src/resources/extensions/shared/confirm-ui.ts +8 -12
- package/src/resources/extensions/shared/dialog-frame.ts +71 -0
- package/src/resources/extensions/shared/interview-ui.ts +43 -42
- package/src/resources/extensions/shared/next-action-ui.ts +6 -6
- package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
- package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_ssgManifest.js +0 -0
|
@@ -11,10 +11,17 @@ import { gsdHome } from "./gsd-home.js";
|
|
|
11
11
|
import { statSync } from "node:fs";
|
|
12
12
|
import { validatePreferences } from "./preferences-validation.js";
|
|
13
13
|
/**
|
|
14
|
-
* Known skill directories
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* Known skill directories for **preference reference resolution** (bare skill names).
|
|
15
|
+
*
|
|
16
|
+
* Search order (first match wins):
|
|
17
|
+
* 1. ~/.gsd/agent/skills/ (GSD bundled)
|
|
18
|
+
* 2. ~/.agents/skills/ (ecosystem global)
|
|
19
|
+
* 3. .agents/skills/ (project ecosystem)
|
|
20
|
+
* 4. ~/.claude/skills/ and .claude/skills/ (Claude Code compatibility)
|
|
21
|
+
*
|
|
22
|
+
* Note: the ResourceLoader catalog uses PackageManager precedence instead —
|
|
23
|
+
* project `.gsd/skills` and `.agents/skills` can override bundled GSD skills
|
|
24
|
+
* on name collision. See docs/dev/what-is-pi/09-the-customization-stack.md.
|
|
18
25
|
*/
|
|
19
26
|
export function getSkillSearchDirs(cwd) {
|
|
20
27
|
const dirs = [
|
|
@@ -455,9 +455,10 @@ function mergePreDispatchHooks(base, override) {
|
|
|
455
455
|
return merged.length > 0 ? merged : undefined;
|
|
456
456
|
}
|
|
457
457
|
// ─── System Prompt Rendering ──────────────────────────────────────────────────
|
|
458
|
-
export function renderPreferencesForSystemPrompt(preferences, resolutions) {
|
|
458
|
+
export function renderPreferencesForSystemPrompt(preferences, resolutions, options) {
|
|
459
459
|
const validated = validatePreferences(preferences);
|
|
460
460
|
const lines = ["## GSD Skill Preferences"];
|
|
461
|
+
const includeResolvedPaths = options?.includeResolvedPaths ?? true;
|
|
461
462
|
if (validated.errors.length > 0) {
|
|
462
463
|
lines.push("- Validation: some preference values were ignored because they were invalid.");
|
|
463
464
|
}
|
|
@@ -466,7 +467,18 @@ export function renderPreferencesForSystemPrompt(preferences, resolutions) {
|
|
|
466
467
|
}
|
|
467
468
|
preferences = validated.preferences;
|
|
468
469
|
lines.push("- Treat these as explicit skill-selection policy for GSD work.", "- If a listed skill exists and is relevant, load and follow it instead of treating it as a vague suggestion.", "- Current user instructions still override these defaults.");
|
|
469
|
-
const fmt = (ref) =>
|
|
470
|
+
const fmt = (ref) => {
|
|
471
|
+
if (!resolutions)
|
|
472
|
+
return ref;
|
|
473
|
+
if (!includeResolvedPaths) {
|
|
474
|
+
const resolution = resolutions.get(ref);
|
|
475
|
+
if (!resolution || resolution.method === "unresolved") {
|
|
476
|
+
return `${ref} (⚠ not found — check skill name or path)`;
|
|
477
|
+
}
|
|
478
|
+
return ref;
|
|
479
|
+
}
|
|
480
|
+
return formatSkillRef(ref, resolutions);
|
|
481
|
+
};
|
|
470
482
|
if (preferences.always_use_skills && preferences.always_use_skills.length > 0) {
|
|
471
483
|
lines.push("- Always use these skills when relevant:");
|
|
472
484
|
for (const skill of preferences.always_use_skills) {
|
|
@@ -21,6 +21,7 @@ import { join, dirname } from "node:path";
|
|
|
21
21
|
import { fileURLToPath } from "node:url";
|
|
22
22
|
import { logWarning } from "./workflow-logger.js";
|
|
23
23
|
import { gsdHome } from "./gsd-home.js";
|
|
24
|
+
import { chooseVisionAskVariant } from "./vision-ask.js";
|
|
24
25
|
function hasRequiredExtensionAssets(rootDir, exists = existsSync) {
|
|
25
26
|
return (exists(join(rootDir, "prompts")) &&
|
|
26
27
|
exists(join(rootDir, "templates", "task-summary.md")));
|
|
@@ -168,6 +169,7 @@ export function loadPrompt(name, vars = {}) {
|
|
|
168
169
|
planTemplatePath: join(getTemplatesDir(), "plan.md"),
|
|
169
170
|
taskPlanTemplatePath: join(getTemplatesDir(), "task-plan.md"),
|
|
170
171
|
taskSummaryTemplatePath: join(getTemplatesDir(), "task-summary.md"),
|
|
172
|
+
visionAsk: chooseVisionAskVariant(),
|
|
171
173
|
skillActivation: "If a `GSD Skill Preferences` block is present in system context, use it and the `<available_skills>` catalog in your system prompt to decide which skills to load and follow for this unit, without relaxing required verification or artifact rules.",
|
|
172
174
|
...vars,
|
|
173
175
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{{preamble}}
|
|
2
2
|
|
|
3
|
-
Ask
|
|
3
|
+
Ask exactly this once: "{{visionAsk}}" Then use the user's reply as vision input.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The opener is intentionally variable so GSD feels alive across project starts. Keep it natural, easy to answer, and assistant/developer shaped: plain language, light guidance, no corporate wording, no roleplay.
|
|
6
|
+
|
|
7
|
+
**Special handling:** If the **user's** message is status, branch state, clarification, or any other non-project-description, treat it as vision input and proceed instead of repeating the opener. Do **not** treat the system preamble above (e.g. "New milestone M00X.") as vision input — wait for the user.
|
|
6
8
|
|
|
7
9
|
## Reflection Step
|
|
8
10
|
|
|
@@ -4,6 +4,8 @@ Discuss milestone {{milestoneId}} ("{{milestoneTitle}}"). Identify real gray are
|
|
|
4
4
|
|
|
5
5
|
**Structured questions available: {{structuredQuestionsAvailable}}**
|
|
6
6
|
|
|
7
|
+
**Conversation opener:** For the first user-facing question round, if you need a broad starting question, use: "{{visionAsk}}" Pair it with investigation-shaped follow-ups. Keep the tone natural and easy to answer, like an assistant/developer helping the user shape the next piece of work.
|
|
8
|
+
|
|
7
9
|
{{inlinedTemplates}}
|
|
8
10
|
|
|
9
11
|
---
|
|
@@ -19,9 +19,7 @@ Leave the project ready for the next agent to understand and continue. Artifacts
|
|
|
19
19
|
|
|
20
20
|
## Skills
|
|
21
21
|
|
|
22
|
-
GSD ships with bundled skills.
|
|
23
|
-
|
|
24
|
-
{{bundledSkillsTable}}
|
|
22
|
+
GSD ships with bundled skills. Installed skills are listed in `<available_skills>` in your system prompt — load the relevant skill file with `read` using the path shown there before starting matching work. Use bare skill names in preferences; GSD resolves paths.
|
|
25
23
|
|
|
26
24
|
## Hard Rules
|
|
27
25
|
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* Conflicting depends_on entries are auto-removed on confirm.
|
|
9
9
|
*/
|
|
10
10
|
import { Key, matchesKey, truncateToWidth } from "@gsd/pi-tui";
|
|
11
|
-
import { makeUI } from "../shared/tui.js";
|
|
12
11
|
import { GLYPH } from "../shared/mod.js";
|
|
13
12
|
import { validateQueueOrder } from "./queue-order.js";
|
|
13
|
+
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
14
14
|
/**
|
|
15
15
|
* Show the queue reorder overlay.
|
|
16
16
|
* Returns the new order + deps to remove, or null if cancelled.
|
|
@@ -26,6 +26,7 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
26
26
|
let grabbed = false;
|
|
27
27
|
let scrollOffset = 0;
|
|
28
28
|
let cachedLines;
|
|
29
|
+
let cachedWidth;
|
|
29
30
|
let validation;
|
|
30
31
|
// Mutable deps map — tracks removals during this session
|
|
31
32
|
const liveDeps = new Map();
|
|
@@ -42,6 +43,7 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
42
43
|
revalidate();
|
|
43
44
|
function refresh() {
|
|
44
45
|
cachedLines = undefined;
|
|
46
|
+
cachedWidth = undefined;
|
|
45
47
|
tui.requestRender();
|
|
46
48
|
}
|
|
47
49
|
function swapItems(fromIdx, toIdx) {
|
|
@@ -125,17 +127,14 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
function render(width) {
|
|
128
|
-
if (cachedLines)
|
|
130
|
+
if (cachedLines && cachedWidth === width)
|
|
129
131
|
return cachedLines;
|
|
130
|
-
const
|
|
132
|
+
const contentWidth = Math.max(1, width - 4);
|
|
131
133
|
const lines = [];
|
|
132
134
|
const queueRows = [];
|
|
133
|
-
const
|
|
134
|
-
lines.push(...r); };
|
|
135
|
-
const add = (s) => truncateToWidth(s, width);
|
|
135
|
+
const add = (s) => truncateToWidth(s, contentWidth);
|
|
136
136
|
let cursorQueueRow = 0;
|
|
137
|
-
const headerText = grabbed ? "
|
|
138
|
-
push(ui.bar(), ui.blank(), ui.header(headerText), ui.blank());
|
|
137
|
+
const headerText = grabbed ? "Queue Reorder - Moving Item" : "Queue Reorder";
|
|
139
138
|
// Completed milestones (dimmed)
|
|
140
139
|
if (completed.length > 0) {
|
|
141
140
|
lines.push(add(theme.fg("dim", " Completed:")));
|
|
@@ -143,7 +142,7 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
143
142
|
const label = m.title && m.title !== m.id ? `${m.id} ${m.title}` : m.id;
|
|
144
143
|
lines.push(add(` ${theme.fg("dim", `${GLYPH.statusDone} ${label}`)}`));
|
|
145
144
|
}
|
|
146
|
-
push(
|
|
145
|
+
lines.push("");
|
|
147
146
|
}
|
|
148
147
|
// Pending milestones
|
|
149
148
|
const queueLabel = grabbed ? " Queue (space to release, ↑/↓ to move):" : " Queue (space to grab, ↑/↓ to navigate):";
|
|
@@ -190,7 +189,7 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
190
189
|
// Removed deps feedback
|
|
191
190
|
const trailingLines = [];
|
|
192
191
|
if (removedDeps.length > 0) {
|
|
193
|
-
trailingLines.push(
|
|
192
|
+
trailingLines.push("");
|
|
194
193
|
for (const r of removedDeps) {
|
|
195
194
|
trailingLines.push(add(` ${theme.fg("success", `${GLYPH.statusDone} Removed: ${r.milestone} depends_on ${r.dep}`)}`));
|
|
196
195
|
}
|
|
@@ -198,10 +197,9 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
198
197
|
// Circular warning
|
|
199
198
|
const circ = validation.violations.find(v => v.type === 'circular');
|
|
200
199
|
if (circ) {
|
|
201
|
-
trailingLines.push(
|
|
200
|
+
trailingLines.push("");
|
|
202
201
|
trailingLines.push(add(` ${theme.fg("error", `${GLYPH.statusWarning} ${circ.message}`)}`));
|
|
203
202
|
}
|
|
204
|
-
trailingLines.push(...ui.blank());
|
|
205
203
|
// Hints — context-sensitive based on grab state
|
|
206
204
|
const hints = [];
|
|
207
205
|
if (grabbed) {
|
|
@@ -221,9 +219,9 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
221
219
|
hints.push("enter ok");
|
|
222
220
|
}
|
|
223
221
|
hints.push("esc");
|
|
224
|
-
trailingLines.push(...ui.hints(hints), ...ui.bar());
|
|
225
222
|
const maxOverlayRows = Math.max(10, process.stdout.rows ? Math.floor(process.stdout.rows * 0.8) : 24);
|
|
226
|
-
const
|
|
223
|
+
const frameRows = 4;
|
|
224
|
+
const availableQueueRows = Math.max(1, maxOverlayRows - frameRows - lines.length - trailingLines.length);
|
|
227
225
|
const maxScroll = Math.max(0, queueRows.length - availableQueueRows);
|
|
228
226
|
if (cursorQueueRow < scrollOffset) {
|
|
229
227
|
scrollOffset = cursorQueueRow;
|
|
@@ -232,11 +230,23 @@ export async function showQueueReorder(ctx, completed, pending) {
|
|
|
232
230
|
scrollOffset = cursorQueueRow - availableQueueRows + 1;
|
|
233
231
|
}
|
|
234
232
|
scrollOffset = Math.min(Math.max(scrollOffset, 0), maxScroll);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
233
|
+
const queueStartRow = lines.length;
|
|
234
|
+
const visibleQueueRows = queueRows.slice(scrollOffset, scrollOffset + availableQueueRows);
|
|
235
|
+
lines.push(...visibleQueueRows, ...trailingLines);
|
|
236
|
+
cachedLines = renderDialogFrame(theme, headerText, lines, width, {
|
|
237
|
+
footer: renderKeyHints(theme, hints, contentWidth),
|
|
238
|
+
scroll: {
|
|
239
|
+
offset: scrollOffset,
|
|
240
|
+
visibleRows: availableQueueRows,
|
|
241
|
+
totalRows: queueRows.length,
|
|
242
|
+
trackOffset: queueStartRow,
|
|
243
|
+
trackRows: visibleQueueRows.length,
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
cachedWidth = width;
|
|
247
|
+
return cachedLines;
|
|
238
248
|
}
|
|
239
|
-
return { render, invalidate: () => { cachedLines = undefined; }, handleInput };
|
|
249
|
+
return { render, invalidate: () => { cachedLines = undefined; cachedWidth = undefined; }, handleInput };
|
|
240
250
|
}, {
|
|
241
251
|
overlay: true,
|
|
242
252
|
overlayOptions: { width: "70%", minWidth: 50, maxHeight: "80%", anchor: "center" },
|
|
@@ -50,7 +50,9 @@ function resolveGitWorkingTreeRoot(basePath) {
|
|
|
50
50
|
*/
|
|
51
51
|
export function createRepositoryRegistry(basePath, workspacePrefs) {
|
|
52
52
|
const contract = resolveGsdPathContract(basePath);
|
|
53
|
-
const projectRoot =
|
|
53
|
+
const projectRoot = contract.isWorktree
|
|
54
|
+
? resolveGitWorkingTreeRoot(contract.workRoot) ?? contract.projectRoot
|
|
55
|
+
: contract.projectRoot;
|
|
54
56
|
const mode = workspacePrefs?.mode ?? "project";
|
|
55
57
|
const repoMap = new Map();
|
|
56
58
|
// "project" is reserved: always maps to projectRoot and cannot be overridden.
|
|
@@ -15,14 +15,15 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkS
|
|
|
15
15
|
import { join, dirname } from "node:path";
|
|
16
16
|
import { randomBytes } from "node:crypto";
|
|
17
17
|
const EXECUTION_TOOL_NAMES = new Set([
|
|
18
|
-
"bash",
|
|
19
|
-
"Bash",
|
|
20
|
-
"PowerShell",
|
|
21
18
|
"async_bash",
|
|
19
|
+
"bash",
|
|
20
|
+
"exec_command",
|
|
21
|
+
"functions.exec_command",
|
|
22
22
|
"gsd_exec",
|
|
23
23
|
"gsd_exec_search",
|
|
24
24
|
"mcp__gsd-workflow__gsd_exec",
|
|
25
25
|
"mcp__gsd-workflow__gsd_exec_search",
|
|
26
|
+
"powershell",
|
|
26
27
|
]);
|
|
27
28
|
// ─── Module State ───────────────────────────────────────────────────────────
|
|
28
29
|
let unitEvidence = [];
|
|
@@ -45,6 +46,12 @@ export function getFilePaths() {
|
|
|
45
46
|
.filter((e) => e.kind === "write" || e.kind === "edit")
|
|
46
47
|
.map(e => e.path);
|
|
47
48
|
}
|
|
49
|
+
/** True when a tool name represents a shell/command execution surface. */
|
|
50
|
+
export function isExecutionToolName(name) {
|
|
51
|
+
if (typeof name !== "string")
|
|
52
|
+
return false;
|
|
53
|
+
return EXECUTION_TOOL_NAMES.has(name.trim().toLowerCase());
|
|
54
|
+
}
|
|
48
55
|
// ─── Persistence (Bug #4385 — evidence must survive session restarts) ────────
|
|
49
56
|
/**
|
|
50
57
|
* Build the path for the evidence JSON file for a given unit.
|
|
@@ -139,7 +146,7 @@ export function clearEvidenceFromDisk(basePath, milestoneId, sliceId, taskId) {
|
|
|
139
146
|
* Exit codes and output are filled in by recordToolResult after execution.
|
|
140
147
|
*/
|
|
141
148
|
export function recordToolCall(toolCallId, toolName, input) {
|
|
142
|
-
if (
|
|
149
|
+
if (isExecutionToolName(toolName)) {
|
|
143
150
|
unitEvidence.push({
|
|
144
151
|
kind: "bash",
|
|
145
152
|
toolCallId,
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill activation and discovery prompt blocks for GSD auto-mode units.
|
|
3
|
+
*/
|
|
4
|
+
import { basename } from "node:path";
|
|
5
|
+
import { parseTaskPlanFile } from "./files.js";
|
|
6
|
+
import { loadEffectiveGSDPreferences, resolveAllSkillReferences, resolveSkillDiscoveryMode, } from "./preferences.js";
|
|
7
|
+
import { filterSkillsByManifest, resolveSkillManifest, warnIfManifestHasMissingSkills } from "./skill-manifest.js";
|
|
8
|
+
import { getInstalledSkills } from "./skills.js";
|
|
9
|
+
import { logWarning } from "./workflow-logger.js";
|
|
10
|
+
function normalizeSkillReference(ref) {
|
|
11
|
+
const normalized = ref.replace(/\\/g, "/").trim();
|
|
12
|
+
const base = basename(normalized).replace(/\.md$/i, "");
|
|
13
|
+
const name = /^SKILL$/i.test(base)
|
|
14
|
+
? basename(normalized.replace(/\/SKILL(?:\.md)?$/i, ""))
|
|
15
|
+
: base;
|
|
16
|
+
return name.trim().toLowerCase();
|
|
17
|
+
}
|
|
18
|
+
function tokenizeSkillContext(...parts) {
|
|
19
|
+
const tokens = new Set();
|
|
20
|
+
const addVariants = (raw) => {
|
|
21
|
+
const value = raw.trim().toLowerCase();
|
|
22
|
+
if (!value || value.length < 2)
|
|
23
|
+
return;
|
|
24
|
+
tokens.add(value);
|
|
25
|
+
tokens.add(value.replace(/[-_]+/g, " "));
|
|
26
|
+
tokens.add(value.replace(/\s+/g, "-"));
|
|
27
|
+
tokens.add(value.replace(/\s+/g, ""));
|
|
28
|
+
};
|
|
29
|
+
for (const part of parts) {
|
|
30
|
+
if (!part)
|
|
31
|
+
continue;
|
|
32
|
+
const text = part.toLowerCase();
|
|
33
|
+
const phraseMatches = text.match(/[a-z0-9][a-z0-9+.#/_-]{1,}/g) ?? [];
|
|
34
|
+
for (const match of phraseMatches) {
|
|
35
|
+
addVariants(match);
|
|
36
|
+
for (const piece of match.split(/[^a-z0-9+.#]+/g)) {
|
|
37
|
+
if (piece.length >= 3)
|
|
38
|
+
addVariants(piece);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return tokens;
|
|
43
|
+
}
|
|
44
|
+
function skillMatchesContext(skill, contextTokens) {
|
|
45
|
+
const haystacks = [
|
|
46
|
+
skill.name.toLowerCase(),
|
|
47
|
+
skill.name.toLowerCase().replace(/[-_]+/g, " "),
|
|
48
|
+
skill.description.toLowerCase(),
|
|
49
|
+
];
|
|
50
|
+
return [...contextTokens].some(token => token.length >= 3 && haystacks.some(haystack => haystack.includes(token)));
|
|
51
|
+
}
|
|
52
|
+
function resolvePreferenceSkillNames(refs, base) {
|
|
53
|
+
if (refs.length === 0)
|
|
54
|
+
return [];
|
|
55
|
+
const prefs = { always_use_skills: refs };
|
|
56
|
+
const report = resolveAllSkillReferences(prefs, base);
|
|
57
|
+
return refs.map(ref => {
|
|
58
|
+
const resolution = report.resolutions.get(ref);
|
|
59
|
+
return normalizeSkillReference(resolution?.resolvedPath ?? ref);
|
|
60
|
+
}).filter(Boolean);
|
|
61
|
+
}
|
|
62
|
+
function ruleMatchesContext(when, contextTokens) {
|
|
63
|
+
const whenTokens = tokenizeSkillContext(when);
|
|
64
|
+
return [...whenTokens].some(token => contextTokens.has(token) || [...contextTokens].some(ctx => ctx.includes(token) || token.includes(ctx)));
|
|
65
|
+
}
|
|
66
|
+
function resolveSkillRuleMatches(prefs, contextTokens, base) {
|
|
67
|
+
if (!prefs?.skill_rules?.length)
|
|
68
|
+
return { include: [], avoid: [] };
|
|
69
|
+
const include = [];
|
|
70
|
+
const avoid = [];
|
|
71
|
+
for (const rule of prefs.skill_rules) {
|
|
72
|
+
if (!ruleMatchesContext(rule.when, contextTokens))
|
|
73
|
+
continue;
|
|
74
|
+
include.push(...resolvePreferenceSkillNames([...(rule.use ?? []), ...(rule.prefer ?? [])], base));
|
|
75
|
+
avoid.push(...resolvePreferenceSkillNames(rule.avoid ?? [], base));
|
|
76
|
+
}
|
|
77
|
+
return { include, avoid };
|
|
78
|
+
}
|
|
79
|
+
function resolvePreferredSkillNames(prefs, visibleSkills, contextTokens, base) {
|
|
80
|
+
if (!prefs?.prefer_skills?.length)
|
|
81
|
+
return [];
|
|
82
|
+
const preferred = new Set(resolvePreferenceSkillNames(prefs.prefer_skills, base));
|
|
83
|
+
return visibleSkills
|
|
84
|
+
.filter(skill => preferred.has(normalizeSkillReference(skill.name)) && skillMatchesContext(skill, contextTokens))
|
|
85
|
+
.map(skill => normalizeSkillReference(skill.name));
|
|
86
|
+
}
|
|
87
|
+
/** Skill names must be lowercase alphanumeric with hyphens — reject anything else
|
|
88
|
+
* to prevent prompt injection via crafted directory names. */
|
|
89
|
+
const SAFE_SKILL_NAME = /^[a-z0-9][a-z0-9-]*$/;
|
|
90
|
+
function formatSkillActivationBlock(skillNames) {
|
|
91
|
+
const safe = skillNames.filter(name => SAFE_SKILL_NAME.test(name));
|
|
92
|
+
if (safe.length === 0)
|
|
93
|
+
return "";
|
|
94
|
+
// Use explicit parameter syntax so LLMs pass { skill: "..." } instead of { name: "..." }.
|
|
95
|
+
// The function-call-like syntax `Skill('name')` led LLMs to infer a positional
|
|
96
|
+
// parameter name, causing tool validation failures — see #2224.
|
|
97
|
+
const calls = safe.map(name => `Call Skill({ skill: '${name}' })`).join('. ');
|
|
98
|
+
return `<skill_activation>${calls}.</skill_activation>`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Manifest-driven recommendations block — informational only, does NOT
|
|
102
|
+
* auto-invoke. Lists per-unit-type skills that are installed but not already
|
|
103
|
+
* activated by explicit user intent (always_use_skills / prefer_skills /
|
|
104
|
+
* skill_rules / task-plan skills_used). Surfaces relevant skills to the
|
|
105
|
+
* model so they can be invoked when the model judges them useful.
|
|
106
|
+
*
|
|
107
|
+
* This is the additive complement to the existing activation directive:
|
|
108
|
+
* activation force-invokes (explicit intent), recommendations remind
|
|
109
|
+
* (manifest defaults). User intent is preserved as the stronger signal
|
|
110
|
+
* (RFC #4779 design principle); this block only adds visibility.
|
|
111
|
+
*/
|
|
112
|
+
function formatSkillRecommendationsBlock(unitType, skillNames) {
|
|
113
|
+
if (!unitType)
|
|
114
|
+
return "";
|
|
115
|
+
const safe = skillNames.filter(name => SAFE_SKILL_NAME.test(name));
|
|
116
|
+
if (safe.length === 0)
|
|
117
|
+
return "";
|
|
118
|
+
return `<skill_recommendations unit="${unitType}">For this unit type, also consider invoking: ${safe.join(", ")}. Use Skill({ skill: 'name' }) when relevant — these are recommendations, not requirements.</skill_recommendations>`;
|
|
119
|
+
}
|
|
120
|
+
export function buildSkillActivationBlock(params) {
|
|
121
|
+
const prefs = params.preferences ?? loadEffectiveGSDPreferences(params.base)?.preferences;
|
|
122
|
+
const contextTokens = tokenizeSkillContext(params.milestoneId, params.milestoneTitle, params.sliceId, params.sliceTitle, params.taskId, params.taskTitle);
|
|
123
|
+
const loaded = getInstalledSkills(params.skills).filter(skill => !skill.disableModelInvocation);
|
|
124
|
+
// Skill activation here is driven entirely by explicit sources
|
|
125
|
+
// (always_use_skills, prefer_skills, skill_rules, task-plan skills_used).
|
|
126
|
+
// Every match is an explicit user/project intent and must not be dropped
|
|
127
|
+
// by the unit-type manifest — user intent is stronger signal than
|
|
128
|
+
// defaults. The manifest's real home is the skill catalog rendering
|
|
129
|
+
// layer (pi-coding-agent `formatSkillsForPrompt`); that wiring is tracked
|
|
130
|
+
// as the "load-time short-circuit" follow-up to RFC #4779.
|
|
131
|
+
//
|
|
132
|
+
// `unitType` stays plumbed so the strict-mode warning can surface
|
|
133
|
+
// manifest entries that reference uninstalled skills, and so the
|
|
134
|
+
// activation-block site is ready to opt in once PR B lands.
|
|
135
|
+
const visibleSkills = loaded;
|
|
136
|
+
const manifestScopedSkills = filterSkillsByManifest(visibleSkills, params.unitType);
|
|
137
|
+
const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
|
|
138
|
+
warnIfManifestHasMissingSkills(params.unitType, installedNames);
|
|
139
|
+
const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
|
|
140
|
+
const matched = new Set();
|
|
141
|
+
for (const name of resolvePreferenceSkillNames(prefs?.always_use_skills ?? [], params.base)) {
|
|
142
|
+
matched.add(name);
|
|
143
|
+
}
|
|
144
|
+
const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base);
|
|
145
|
+
for (const name of ruleMatches.include)
|
|
146
|
+
matched.add(name);
|
|
147
|
+
for (const name of ruleMatches.avoid)
|
|
148
|
+
avoided.add(name);
|
|
149
|
+
for (const name of resolvePreferredSkillNames(prefs, visibleSkills, contextTokens, params.base)) {
|
|
150
|
+
matched.add(name);
|
|
151
|
+
}
|
|
152
|
+
if (params.taskPlanContent) {
|
|
153
|
+
try {
|
|
154
|
+
const taskPlan = parseTaskPlanFile(params.taskPlanContent);
|
|
155
|
+
for (const skillName of taskPlan.frontmatter.skills_used) {
|
|
156
|
+
matched.add(normalizeSkillReference(skillName));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
logWarning("prompt", `parseTaskPlanFile failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Heuristic auto-match (gated on skill_discovery: "auto").
|
|
164
|
+
// For each installed skill, check if its name or description appears in the
|
|
165
|
+
// unit's context tokens (milestone/slice/task titles). Only consider skills
|
|
166
|
+
// already on the unit-type manifest allowlist — this keeps the heuristic
|
|
167
|
+
// narrow and avoids wildly off-topic activations.
|
|
168
|
+
// Users who set `skill_discovery: "off"` or "suggest" do not get
|
|
169
|
+
// auto-matched skills (the recommendations block still surfaces manifest
|
|
170
|
+
// skills passively); only "auto" actually adds them to the activation
|
|
171
|
+
// directive set. Default `skill_discovery` is "suggest", so this is opt-in.
|
|
172
|
+
if ((prefs?.skill_discovery ?? "suggest") === "auto") {
|
|
173
|
+
for (const skill of manifestScopedSkills) {
|
|
174
|
+
const normalized = normalizeSkillReference(skill.name);
|
|
175
|
+
if (matched.has(normalized) || avoided.has(normalized))
|
|
176
|
+
continue;
|
|
177
|
+
if (skillMatchesContext(skill, contextTokens)) {
|
|
178
|
+
matched.add(normalized);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const ordered = [...matched]
|
|
183
|
+
.filter(name => installedNames.has(name) && !avoided.has(name))
|
|
184
|
+
.sort();
|
|
185
|
+
const activationBlock = formatSkillActivationBlock(ordered);
|
|
186
|
+
// Omit recommendations when the system catalog is manifest-scoped for this
|
|
187
|
+
// unit — skill names are already listed in <available_skills>.
|
|
188
|
+
let recommendationsBlock = "";
|
|
189
|
+
if (resolveSkillManifest(params.unitType) === null) {
|
|
190
|
+
const matchedSet = new Set(ordered);
|
|
191
|
+
const recommendations = (resolveSkillManifest(params.unitType) ?? [])
|
|
192
|
+
.filter(name => installedNames.has(name) && !avoided.has(name) && !matchedSet.has(name))
|
|
193
|
+
.sort();
|
|
194
|
+
recommendationsBlock = formatSkillRecommendationsBlock(params.unitType, recommendations);
|
|
195
|
+
}
|
|
196
|
+
if (!activationBlock && !recommendationsBlock)
|
|
197
|
+
return "";
|
|
198
|
+
if (!activationBlock)
|
|
199
|
+
return recommendationsBlock;
|
|
200
|
+
if (!recommendationsBlock)
|
|
201
|
+
return activationBlock;
|
|
202
|
+
return `${activationBlock}\n${recommendationsBlock}`;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Build the skill discovery template variables for research prompts.
|
|
206
|
+
* Returns { skillDiscoveryMode, skillDiscoveryInstructions } for template substitution.
|
|
207
|
+
*/
|
|
208
|
+
export function buildSkillDiscoveryVars() {
|
|
209
|
+
const mode = resolveSkillDiscoveryMode();
|
|
210
|
+
if (mode === "off") {
|
|
211
|
+
return {
|
|
212
|
+
skillDiscoveryMode: "off",
|
|
213
|
+
skillDiscoveryInstructions: " Skill discovery is disabled. Skip this step.",
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
if (mode === "suggest") {
|
|
217
|
+
return {
|
|
218
|
+
skillDiscoveryMode: mode,
|
|
219
|
+
skillDiscoveryInstructions: `
|
|
220
|
+
Check \`<available_skills>\` for installed skills matching core technologies. For gaps, run \`npx skills find "<technology>"\` and note promising install commands in your research output — do NOT install.`,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const autoInstall = mode === "auto";
|
|
224
|
+
const instructions = autoInstall
|
|
225
|
+
? `
|
|
226
|
+
Check \`<available_skills>\` first. For missing core-technology skills, run \`npx skills find "<technology>"\`, install relevant matches with \`npx skills add <owner/repo@skill> -g -y\`, and record them in "Skills Discovered".`
|
|
227
|
+
: `
|
|
228
|
+
Check \`<available_skills>\` first. For missing core-technology skills, run \`npx skills find "<technology>"\` and note install commands in your research output — do NOT install.`;
|
|
229
|
+
return {
|
|
230
|
+
skillDiscoveryMode: mode,
|
|
231
|
+
skillDiscoveryInstructions: instructions,
|
|
232
|
+
};
|
|
233
|
+
}
|