gsd-pi 2.68.0 → 2.68.1-dev.58193fa
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 +66 -70
- package/dist/resources/extensions/gsd/auto-model-selection.js +27 -1
- package/dist/resources/extensions/gsd/auto.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -5
- package/dist/resources/extensions/gsd/codebase-generator.js +12 -0
- package/dist/resources/extensions/gsd/guided-flow.js +25 -70
- package/dist/resources/extensions/gsd/model-router.js +85 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/templates/context.md +34 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-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/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/index.d.ts +3 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +2 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +2 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -2
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +2 -2
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/mistral.js +2 -2
- package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +2 -2
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.js +2 -2
- package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/provider-capabilities.d.ts +59 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.js +173 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.js.map +1 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.js +132 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.js +172 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +34 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +73 -2
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/src/index.ts +3 -0
- package/packages/pi-ai/src/providers/amazon-bedrock.ts +2 -2
- package/packages/pi-ai/src/providers/anthropic-shared.ts +2 -2
- package/packages/pi-ai/src/providers/google-shared.ts +2 -2
- package/packages/pi-ai/src/providers/mistral.ts +2 -2
- package/packages/pi-ai/src/providers/openai-completions.ts +2 -2
- package/packages/pi-ai/src/providers/openai-responses-shared.ts +2 -2
- package/packages/pi-ai/src/providers/provider-capabilities.test.ts +174 -0
- package/packages/pi-ai/src/providers/provider-capabilities.ts +215 -0
- package/packages/pi-ai/src/providers/transform-messages-report.test.ts +189 -0
- package/packages/pi-ai/src/providers/transform-messages.ts +94 -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 +10 -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 +2 -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 +15 -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 +41 -0
- 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/tools/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts +27 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js +69 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +2 -2
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +3 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +11 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +18 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +45 -0
- package/packages/pi-coding-agent/src/core/tools/index.ts +7 -0
- package/packages/pi-coding-agent/src/core/tools/tool-compatibility-registry.ts +83 -0
- package/packages/pi-coding-agent/src/index.ts +9 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +36 -4
- package/src/resources/extensions/gsd/auto.ts +8 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -5
- package/src/resources/extensions/gsd/codebase-generator.ts +16 -0
- package/src/resources/extensions/gsd/guided-flow.ts +22 -84
- package/src/resources/extensions/gsd/model-router.ts +117 -10
- package/src/resources/extensions/gsd/preferences-types.ts +3 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/templates/context.md +34 -2
- package/src/resources/extensions/gsd/tests/capability-router.test.ts +31 -7
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +13 -16
- package/dist/resources/extensions/gsd/prompt-validation.js +0 -67
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +0 -138
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/src/resources/extensions/gsd/prompt-validation.ts +0 -88
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
- package/src/resources/extensions/gsd/templates/context-enhanced.md +0 -138
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +0 -223
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +0 -53
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +0 -525
- package/src/resources/extensions/gsd/tests/preparation.test.ts +0 -1211
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +0 -669
- /package/dist/web/standalone/.next/static/{ka3ShQTakcliYL-EXRRb6 → YFZaRxYFkrifCiWU3AcrJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ka3ShQTakcliYL-EXRRb6 → YFZaRxYFkrifCiWU3AcrJ}/_ssgManifest.js +0 -0
|
@@ -53,25 +53,8 @@ import {
|
|
|
53
53
|
runPreparation,
|
|
54
54
|
formatCodebaseBrief,
|
|
55
55
|
formatPriorContextBrief,
|
|
56
|
-
formatEcosystemBrief,
|
|
57
|
-
type PreparationResult,
|
|
58
56
|
} from "./preparation.js";
|
|
59
57
|
|
|
60
|
-
// ─── Preparation result storage ─────────────────────────────────────────────
|
|
61
|
-
// Stores the most recent preparation result for injection into discuss prompts.
|
|
62
|
-
// S02 will consume this when building the prepared discussion prompt.
|
|
63
|
-
let lastPreparationResult: PreparationResult | null = null;
|
|
64
|
-
|
|
65
|
-
/** Get the most recent preparation result (for S02 prompt building). */
|
|
66
|
-
export function getLastPreparationResult(): PreparationResult | null {
|
|
67
|
-
return lastPreparationResult;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Clear the preparation result (called after discussion completes). */
|
|
71
|
-
export function clearPreparationResult(): void {
|
|
72
|
-
lastPreparationResult = null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
58
|
// ─── Re-exports (preserve public API for existing importers) ────────────────
|
|
76
59
|
export {
|
|
77
60
|
MILESTONE_ID_RE, generateMilestoneSuffix, nextMilestoneId,
|
|
@@ -427,7 +410,7 @@ function resolveAvailableModel<T extends { id: string; provider: string }>(
|
|
|
427
410
|
* Build the discuss-and-plan prompt for a new milestone.
|
|
428
411
|
* Used by all three "new milestone" paths (first ever, no active, all complete).
|
|
429
412
|
*/
|
|
430
|
-
function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string): string {
|
|
413
|
+
function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string, preparationContext?: string): string {
|
|
431
414
|
const milestoneRel = `.gsd/milestones/${nextId}`;
|
|
432
415
|
const inlinedTemplates = [
|
|
433
416
|
inlineTemplate("project", "Project"),
|
|
@@ -439,6 +422,7 @@ function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string)
|
|
|
439
422
|
return loadPrompt("discuss", {
|
|
440
423
|
milestoneId: nextId,
|
|
441
424
|
preamble,
|
|
425
|
+
preparationContext: preparationContext ?? "",
|
|
442
426
|
contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
|
|
443
427
|
roadmapPath: `${milestoneRel}/${nextId}-ROADMAP.md`,
|
|
444
428
|
inlinedTemplates,
|
|
@@ -471,59 +455,12 @@ function buildHeadlessDiscussPrompt(nextId: string, seedContext: string, _basePa
|
|
|
471
455
|
});
|
|
472
456
|
}
|
|
473
457
|
|
|
474
|
-
/**
|
|
475
|
-
* Build the prepared discuss prompt with brief injection.
|
|
476
|
-
* Uses the discuss-prepared template which encodes the 4-layer discussion protocol.
|
|
477
|
-
*
|
|
478
|
-
* @param nextId - The milestone ID being discussed
|
|
479
|
-
* @param preamble - Preamble text for the discuss prompt
|
|
480
|
-
* @param _basePath - Root directory of the project (unused, kept for signature consistency)
|
|
481
|
-
* @param prepResult - Preparation result containing briefs to inject
|
|
482
|
-
* @returns The prepared discuss prompt string
|
|
483
|
-
*/
|
|
484
|
-
function buildPreparedPrompt(
|
|
485
|
-
nextId: string,
|
|
486
|
-
preamble: string,
|
|
487
|
-
_basePath: string,
|
|
488
|
-
prepResult: PreparationResult,
|
|
489
|
-
): string {
|
|
490
|
-
const milestoneRel = `.gsd/milestones/${nextId}`;
|
|
491
|
-
|
|
492
|
-
// Use context-enhanced instead of context for prepared discussions
|
|
493
|
-
const inlinedTemplates = [
|
|
494
|
-
inlineTemplate("project", "Project"),
|
|
495
|
-
inlineTemplate("requirements", "Requirements"),
|
|
496
|
-
inlineTemplate("context-enhanced", "Context Enhanced"),
|
|
497
|
-
inlineTemplate("roadmap", "Roadmap"),
|
|
498
|
-
inlineTemplate("decisions", "Decisions"),
|
|
499
|
-
].join("\n\n---\n\n");
|
|
500
|
-
|
|
501
|
-
// Format the briefs from the preparation result
|
|
502
|
-
const codebaseBrief = prepResult.codebaseBrief || formatCodebaseBrief(prepResult.codebase);
|
|
503
|
-
const priorContextBrief = prepResult.priorContextBrief || formatPriorContextBrief(prepResult.priorContext);
|
|
504
|
-
const ecosystemBrief = prepResult.ecosystemBrief || formatEcosystemBrief(prepResult.ecosystem);
|
|
505
|
-
|
|
506
|
-
return loadPrompt("discuss-prepared", {
|
|
507
|
-
milestoneId: nextId,
|
|
508
|
-
preamble,
|
|
509
|
-
codebaseBrief,
|
|
510
|
-
priorContextBrief,
|
|
511
|
-
ecosystemBrief,
|
|
512
|
-
contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
|
|
513
|
-
roadmapPath: `${milestoneRel}/${nextId}-ROADMAP.md`,
|
|
514
|
-
inlinedTemplates,
|
|
515
|
-
commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): context, requirements, and roadmap`),
|
|
516
|
-
multiMilestoneCommitInstruction: buildDocsCommitInstruction("docs: project plan — N milestones"),
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
|
|
520
458
|
/**
|
|
521
459
|
* Run preparation phase if enabled, then build the discuss prompt.
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
* Falls back to the standard discuss template when preparation is disabled or fails.
|
|
460
|
+
* Preparation analyzes the codebase and prior context, injecting the results
|
|
461
|
+
* as supplementary context into the standard discuss template. The discuss
|
|
462
|
+
* template drives the conversation (asks "What's the vision?" first), while
|
|
463
|
+
* the preparation briefs give the agent grounding in the existing codebase.
|
|
527
464
|
*
|
|
528
465
|
* @param ctx - Extension command context with UI for progress notifications
|
|
529
466
|
* @param nextId - The milestone ID being discussed
|
|
@@ -537,14 +474,13 @@ async function prepareAndBuildDiscussPrompt(
|
|
|
537
474
|
preamble: string,
|
|
538
475
|
basePath: string,
|
|
539
476
|
): Promise<string> {
|
|
540
|
-
// Clear stale preparation result immediately to prevent cross-session/project
|
|
541
|
-
// state leaks. This ensures data from a prior milestone/project never leaks
|
|
542
|
-
// into subsequent discussions (adversarial review fix #3602).
|
|
543
|
-
lastPreparationResult = null;
|
|
544
|
-
|
|
545
477
|
const prefs = loadEffectiveGSDPreferences()?.preferences ?? {};
|
|
546
478
|
|
|
547
|
-
// Run preparation if enabled (default: true)
|
|
479
|
+
// Run preparation if enabled (default: true) — results are injected as
|
|
480
|
+
// supplementary context into the standard discuss prompt, NOT as a
|
|
481
|
+
// replacement template. The discuss prompt always leads with "What's the
|
|
482
|
+
// vision?" so the user defines the scope, not the codebase analysis.
|
|
483
|
+
let preparationContext = "";
|
|
548
484
|
if (prefs.discuss_preparation !== false) {
|
|
549
485
|
try {
|
|
550
486
|
const prepResult = await runPreparation(basePath, ctx.ui, {
|
|
@@ -552,21 +488,23 @@ async function prepareAndBuildDiscussPrompt(
|
|
|
552
488
|
discuss_web_research: prefs.discuss_web_research,
|
|
553
489
|
discuss_depth: prefs.discuss_depth,
|
|
554
490
|
});
|
|
555
|
-
lastPreparationResult = prepResult;
|
|
556
491
|
|
|
557
|
-
// Use prepared prompt if preparation was enabled and produced results
|
|
558
492
|
if (prepResult.enabled) {
|
|
559
|
-
|
|
493
|
+
const codebaseBrief = prepResult.codebaseBrief || formatCodebaseBrief(prepResult.codebase);
|
|
494
|
+
const priorContextBrief = prepResult.priorContextBrief || formatPriorContextBrief(prepResult.priorContext);
|
|
495
|
+
const parts: string[] = [];
|
|
496
|
+
if (codebaseBrief) parts.push(`### Codebase Brief\n\n${codebaseBrief}`);
|
|
497
|
+
if (priorContextBrief) parts.push(`### Prior Context Brief\n\n${priorContextBrief}`);
|
|
498
|
+
if (parts.length > 0) {
|
|
499
|
+
preparationContext = `\n\n## Preparation Context\n\nThe system analyzed the codebase before this discussion. Use these findings as background context — they describe what already exists, NOT what the user wants to build. Always ask the user what they want to build first.\n\n${parts.join("\n\n")}`;
|
|
500
|
+
}
|
|
560
501
|
}
|
|
561
|
-
} catch {
|
|
562
|
-
|
|
563
|
-
lastPreparationResult = null;
|
|
502
|
+
} catch (err) {
|
|
503
|
+
logWarning("guided", `preparation failed, proceeding without context: ${(err as Error).message}`);
|
|
564
504
|
}
|
|
565
505
|
}
|
|
566
506
|
|
|
567
|
-
|
|
568
|
-
// lastPreparationResult is already null (cleared at entry or on error)
|
|
569
|
-
return buildDiscussPrompt(nextId, preamble, basePath);
|
|
507
|
+
return buildDiscussPrompt(nextId, preamble, basePath, preparationContext);
|
|
570
508
|
}
|
|
571
509
|
|
|
572
510
|
/**
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
import type { ComplexityTier, ClassificationResult, TaskMetadata } from "./complexity-classifier.js";
|
|
6
6
|
import { tierOrdinal } from "./complexity-classifier.js";
|
|
7
7
|
import type { ResolvedModelConfig } from "./preferences.js";
|
|
8
|
+
import { getProviderCapabilities, type ProviderCapabilities } from "@gsd/pi-ai";
|
|
9
|
+
import { getToolCompatibility, getAllToolCompatibility } from "@gsd/pi-coding-agent";
|
|
10
|
+
import type { ToolCompatibility } from "@gsd/pi-coding-agent";
|
|
8
11
|
|
|
9
12
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
10
13
|
|
|
@@ -37,6 +40,8 @@ export interface RoutingDecision {
|
|
|
37
40
|
selectionMethod: "tier-only" | "capability-scored";
|
|
38
41
|
/** Capability scores per eligible model (capability-scored path only) */
|
|
39
42
|
capabilityScores?: Record<string, number>;
|
|
43
|
+
/** Tools filtered out due to provider incompatibility (ADR-005) */
|
|
44
|
+
filteredTools?: string[];
|
|
40
45
|
/** Task requirement vector used for scoring */
|
|
41
46
|
taskRequirements?: Partial<Record<string, number>>;
|
|
42
47
|
}
|
|
@@ -58,7 +63,7 @@ export interface ModelCapabilities {
|
|
|
58
63
|
// Maps known model IDs to their capability tier. Used when tier_models is not
|
|
59
64
|
// explicitly configured to pick the best available model for each tier.
|
|
60
65
|
|
|
61
|
-
const MODEL_CAPABILITY_TIER: Record<string, ComplexityTier> = {
|
|
66
|
+
export const MODEL_CAPABILITY_TIER: Record<string, ComplexityTier> = {
|
|
62
67
|
// Light-tier models (cheapest)
|
|
63
68
|
"claude-haiku-4-5": "light",
|
|
64
69
|
"claude-3-5-haiku-latest": "light",
|
|
@@ -139,15 +144,49 @@ const MODEL_COST_PER_1K_INPUT: Record<string, number> = {
|
|
|
139
144
|
// model selection within an eligible tier set.
|
|
140
145
|
|
|
141
146
|
export const MODEL_CAPABILITY_PROFILES: Record<string, ModelCapabilities> = {
|
|
142
|
-
|
|
143
|
-
"claude-
|
|
144
|
-
"claude-
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
147
|
+
// ── Anthropic ──────────────────────────────────────────────────────────────
|
|
148
|
+
"claude-opus-4-6": { coding: 95, debugging: 90, research: 85, reasoning: 95, speed: 30, longContext: 80, instruction: 90 },
|
|
149
|
+
"claude-sonnet-4-6": { coding: 85, debugging: 80, research: 75, reasoning: 80, speed: 60, longContext: 75, instruction: 85 },
|
|
150
|
+
"claude-sonnet-4-5-20250514": { coding: 85, debugging: 80, research: 75, reasoning: 80, speed: 60, longContext: 75, instruction: 85 },
|
|
151
|
+
"claude-3-5-sonnet-latest": { coding: 82, debugging: 78, research: 72, reasoning: 78, speed: 62, longContext: 70, instruction: 82 },
|
|
152
|
+
"claude-haiku-4-5": { coding: 60, debugging: 50, research: 45, reasoning: 50, speed: 95, longContext: 50, instruction: 75 },
|
|
153
|
+
"claude-3-5-haiku-latest": { coding: 60, debugging: 50, research: 45, reasoning: 50, speed: 95, longContext: 50, instruction: 75 },
|
|
154
|
+
"claude-3-haiku-20240307": { coding: 50, debugging: 40, research: 35, reasoning: 40, speed: 95, longContext: 40, instruction: 65 },
|
|
155
|
+
"claude-3-opus-latest": { coding: 90, debugging: 85, research: 82, reasoning: 90, speed: 35, longContext: 75, instruction: 88 },
|
|
156
|
+
|
|
157
|
+
// ── OpenAI GPT ─────────────────────────────────────────────────────────────
|
|
158
|
+
"gpt-4o": { coding: 80, debugging: 75, research: 70, reasoning: 75, speed: 65, longContext: 70, instruction: 80 },
|
|
159
|
+
"gpt-4o-mini": { coding: 55, debugging: 45, research: 40, reasoning: 45, speed: 90, longContext: 45, instruction: 70 },
|
|
160
|
+
"gpt-4-turbo": { coding: 78, debugging: 72, research: 68, reasoning: 72, speed: 50, longContext: 65, instruction: 78 },
|
|
161
|
+
"gpt-4.1": { coding: 82, debugging: 78, research: 72, reasoning: 78, speed: 62, longContext: 72, instruction: 82 },
|
|
162
|
+
"gpt-4.1-mini": { coding: 58, debugging: 48, research: 42, reasoning: 48, speed: 88, longContext: 48, instruction: 72 },
|
|
163
|
+
"gpt-4.1-nano": { coding: 40, debugging: 30, research: 25, reasoning: 30, speed: 95, longContext: 30, instruction: 60 },
|
|
164
|
+
"gpt-5": { coding: 92, debugging: 88, research: 85, reasoning: 92, speed: 40, longContext: 85, instruction: 90 },
|
|
165
|
+
"gpt-5-mini": { coding: 62, debugging: 52, research: 48, reasoning: 52, speed: 88, longContext: 52, instruction: 74 },
|
|
166
|
+
"gpt-5-nano": { coding: 42, debugging: 32, research: 28, reasoning: 32, speed: 95, longContext: 32, instruction: 62 },
|
|
167
|
+
"gpt-5-pro": { coding: 94, debugging: 90, research: 88, reasoning: 94, speed: 35, longContext: 88, instruction: 92 },
|
|
168
|
+
"gpt-5.1": { coding: 93, debugging: 89, research: 86, reasoning: 93, speed: 42, longContext: 86, instruction: 91 },
|
|
169
|
+
"gpt-5.1-codex-max": { coding: 90, debugging: 85, research: 70, reasoning: 85, speed: 55, longContext: 75, instruction: 85 },
|
|
170
|
+
"gpt-5.1-codex-mini": { coding: 65, debugging: 55, research: 40, reasoning: 50, speed: 88, longContext: 48, instruction: 72 },
|
|
171
|
+
"gpt-5.2": { coding: 93, debugging: 90, research: 87, reasoning: 93, speed: 42, longContext: 87, instruction: 91 },
|
|
172
|
+
"gpt-5.2-codex": { coding: 93, debugging: 90, research: 72, reasoning: 88, speed: 50, longContext: 78, instruction: 88 },
|
|
173
|
+
"gpt-5.3-codex": { coding: 94, debugging: 91, research: 74, reasoning: 89, speed: 50, longContext: 80, instruction: 89 },
|
|
174
|
+
"gpt-5.3-codex-spark": { coding: 68, debugging: 58, research: 42, reasoning: 52, speed: 90, longContext: 50, instruction: 74 },
|
|
175
|
+
"gpt-5.4": { coding: 95, debugging: 92, research: 88, reasoning: 94, speed: 42, longContext: 88, instruction: 92 },
|
|
176
|
+
|
|
177
|
+
// ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
|
|
178
|
+
"o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
|
|
179
|
+
"o3": { coding: 80, debugging: 85, research: 80, reasoning: 92, speed: 25, longContext: 70, instruction: 85 },
|
|
180
|
+
"o4-mini": { coding: 75, debugging: 80, research: 72, reasoning: 88, speed: 60, longContext: 65, instruction: 80 },
|
|
181
|
+
"o4-mini-deep-research": { coding: 75, debugging: 80, research: 85, reasoning: 88, speed: 30, longContext: 80, instruction: 80 },
|
|
182
|
+
|
|
183
|
+
// ── Google ─────────────────────────────────────────────────────────────────
|
|
184
|
+
"gemini-2.5-pro": { coding: 75, debugging: 70, research: 85, reasoning: 75, speed: 55, longContext: 90, instruction: 75 },
|
|
185
|
+
"gemini-2.0-flash": { coding: 50, debugging: 40, research: 50, reasoning: 40, speed: 95, longContext: 60, instruction: 65 },
|
|
186
|
+
"gemini-flash-2.0": { coding: 50, debugging: 40, research: 50, reasoning: 40, speed: 95, longContext: 60, instruction: 65 },
|
|
187
|
+
|
|
188
|
+
// ── DeepSeek ───────────────────────────────────────────────────────────────
|
|
189
|
+
"deepseek-chat": { coding: 75, debugging: 65, research: 55, reasoning: 70, speed: 70, longContext: 55, instruction: 65 },
|
|
151
190
|
};
|
|
152
191
|
|
|
153
192
|
// ─── Base Task Requirements Data Table ───────────────────────────────────────
|
|
@@ -502,3 +541,71 @@ function getModelCost(modelId: string): number {
|
|
|
502
541
|
// Unknown cost — assume expensive to avoid routing to unknown cheap models
|
|
503
542
|
return 999;
|
|
504
543
|
}
|
|
544
|
+
|
|
545
|
+
// ─── Tool Compatibility Filter (ADR-005 Phase 3) ───────────────────────────
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Check if a tool is compatible with a provider's capabilities.
|
|
549
|
+
* Returns true if the tool can be used with the provider.
|
|
550
|
+
*/
|
|
551
|
+
export function isToolCompatibleWithProvider(
|
|
552
|
+
toolName: string,
|
|
553
|
+
providerCaps: ProviderCapabilities,
|
|
554
|
+
): boolean {
|
|
555
|
+
const compat = getToolCompatibility(toolName);
|
|
556
|
+
if (!compat) return true; // no metadata = always compatible
|
|
557
|
+
|
|
558
|
+
// Hard filter: provider doesn't support image tool results
|
|
559
|
+
if (compat.producesImages && !providerCaps.imageToolResults) return false;
|
|
560
|
+
|
|
561
|
+
// Hard filter: tool uses schema features provider doesn't support
|
|
562
|
+
if (compat.schemaFeatures?.some(f => providerCaps.unsupportedSchemaFeatures.includes(f))) {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return true;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Filter a list of tool names to only those compatible with a provider.
|
|
571
|
+
* Used by the routing pipeline to adjust tool sets when switching providers.
|
|
572
|
+
*/
|
|
573
|
+
export function filterToolsForProvider(
|
|
574
|
+
toolNames: string[],
|
|
575
|
+
providerApi: string,
|
|
576
|
+
): { compatible: string[]; filtered: string[] } {
|
|
577
|
+
const providerCaps = getProviderCapabilities(providerApi);
|
|
578
|
+
|
|
579
|
+
// Provider doesn't support tool calling at all
|
|
580
|
+
if (!providerCaps.toolCalling) {
|
|
581
|
+
return { compatible: [], filtered: toolNames };
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const compatible: string[] = [];
|
|
585
|
+
const filtered: string[] = [];
|
|
586
|
+
|
|
587
|
+
for (const name of toolNames) {
|
|
588
|
+
if (isToolCompatibleWithProvider(name, providerCaps)) {
|
|
589
|
+
compatible.push(name);
|
|
590
|
+
} else {
|
|
591
|
+
filtered.push(name);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return { compatible, filtered };
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Adjust the active tool set for a selected model's provider capabilities.
|
|
600
|
+
* Returns tool names that should be active — removes incompatible tools.
|
|
601
|
+
*
|
|
602
|
+
* This is a hard filter only — it removes tools that would fail at the
|
|
603
|
+
* provider level. It does NOT remove tools based on soft heuristics.
|
|
604
|
+
*/
|
|
605
|
+
export function adjustToolSet(
|
|
606
|
+
activeToolNames: string[],
|
|
607
|
+
selectedModelApi: string,
|
|
608
|
+
): { toolNames: string[]; removedTools: string[] } {
|
|
609
|
+
const { compatible, filtered } = filterToolsForProvider(activeToolNames, selectedModelApi);
|
|
610
|
+
return { toolNames: compatible, removedTools: filtered };
|
|
611
|
+
}
|
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
ReactiveExecutionConfig,
|
|
21
21
|
GateEvaluationConfig,
|
|
22
22
|
} from "./types.js";
|
|
23
|
-
import type { DynamicRoutingConfig } from "./model-router.js";
|
|
23
|
+
import type { DynamicRoutingConfig, ModelCapabilities } from "./model-router.js";
|
|
24
24
|
|
|
25
25
|
export interface ContextManagementConfig {
|
|
26
26
|
observation_masking?: boolean; // default: true
|
|
@@ -255,6 +255,8 @@ export interface GSDPreferences {
|
|
|
255
255
|
post_unit_hooks?: PostUnitHookConfig[];
|
|
256
256
|
pre_dispatch_hooks?: PreDispatchHookConfig[];
|
|
257
257
|
dynamic_routing?: DynamicRoutingConfig;
|
|
258
|
+
/** Per-model capability overrides. Deep-merged with built-in profiles for capability-aware routing (ADR-004). */
|
|
259
|
+
modelOverrides?: Record<string, { capabilities?: Partial<ModelCapabilities> }>;
|
|
258
260
|
context_management?: ContextManagementConfig;
|
|
259
261
|
token_profile?: TokenProfile;
|
|
260
262
|
phases?: PhaseSkipPreferences;
|
|
@@ -28,6 +28,8 @@ After reflection is confirmed, decide the approach based on the actual scope —
|
|
|
28
28
|
|
|
29
29
|
**Anti-reduction rule:** If the user describes a big vision, plan the big vision. Do not ask "what's the minimum viable version?" or try to reduce scope unless the user explicitly asks for an MVP or minimal version. When something is complex or risky, phase it into a later milestone — do not cut it. The user's ambition is the target, and your job is to sequence it intelligently, not shrink it.
|
|
30
30
|
|
|
31
|
+
{{preparationContext}}
|
|
32
|
+
|
|
31
33
|
## Mandatory Investigation Before First Question Round
|
|
32
34
|
|
|
33
35
|
Before asking your first question, do a mandatory investigation pass. This is not optional.
|
|
@@ -38,6 +38,28 @@ To call this milestone complete, we must prove:
|
|
|
38
38
|
- {{one real end-to-end scenario}}
|
|
39
39
|
- {{what cannot be simulated if this milestone is to be considered truly done}}
|
|
40
40
|
|
|
41
|
+
## Architectural Decisions
|
|
42
|
+
|
|
43
|
+
### {{decisionTitle}}
|
|
44
|
+
|
|
45
|
+
**Decision:** {{decisionStatement}}
|
|
46
|
+
|
|
47
|
+
**Rationale:** {{rationale}}
|
|
48
|
+
|
|
49
|
+
**Alternatives Considered:**
|
|
50
|
+
- {{alternative}} — {{whyNotChosen}}
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
> Add additional decisions as separate `### Decision Title` blocks following the same structure above.
|
|
55
|
+
> See `.gsd/DECISIONS.md` for the full append-only register of all project decisions.
|
|
56
|
+
|
|
57
|
+
## Error Handling Strategy
|
|
58
|
+
|
|
59
|
+
{{errorHandlingStrategy}}
|
|
60
|
+
|
|
61
|
+
> Describe the approach for handling failures, edge cases, and error propagation. Include retry policies, fallback behaviors, and user-facing error messages where relevant.
|
|
62
|
+
|
|
41
63
|
## Risks and Unknowns
|
|
42
64
|
|
|
43
65
|
- {{riskOrUnknown}} — {{whyItMatters}}
|
|
@@ -47,8 +69,6 @@ To call this milestone complete, we must prove:
|
|
|
47
69
|
- `{{fileOrModule}}` — {{howItRelates}}
|
|
48
70
|
- `{{fileOrModule}}` — {{howItRelates}}
|
|
49
71
|
|
|
50
|
-
> See `.gsd/DECISIONS.md` for all architectural and pattern decisions — it is an append-only register; read it during planning, append to it during execution.
|
|
51
|
-
|
|
52
72
|
## Relevant Requirements
|
|
53
73
|
|
|
54
74
|
- {{requirementId}} — {{howThisMilestoneAdvancesIt}}
|
|
@@ -71,6 +91,18 @@ To call this milestone complete, we must prove:
|
|
|
71
91
|
|
|
72
92
|
- {{systemOrService}} — {{howThisMilestoneInteractsWithIt}}
|
|
73
93
|
|
|
94
|
+
## Testing Requirements
|
|
95
|
+
|
|
96
|
+
{{testingRequirements}}
|
|
97
|
+
|
|
98
|
+
> Specify test types (unit, integration, e2e), coverage expectations, and specific test scenarios that must pass.
|
|
99
|
+
|
|
100
|
+
## Acceptance Criteria
|
|
101
|
+
|
|
102
|
+
{{acceptanceCriteria}}
|
|
103
|
+
|
|
104
|
+
> Per-slice acceptance criteria gathered during discussion. Each slice should have clear, testable criteria.
|
|
105
|
+
|
|
74
106
|
## Open Questions
|
|
75
107
|
|
|
76
108
|
- {{question}} — {{currentThinking}}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getEligibleModels,
|
|
12
12
|
resolveModelForComplexity,
|
|
13
13
|
MODEL_CAPABILITY_PROFILES,
|
|
14
|
+
MODEL_CAPABILITY_TIER,
|
|
14
15
|
BASE_REQUIREMENTS,
|
|
15
16
|
defaultRoutingConfig,
|
|
16
17
|
} from "../model-router.js";
|
|
@@ -125,13 +126,9 @@ describe("computeTaskRequirements", () => {
|
|
|
125
126
|
// ─── MODEL_CAPABILITY_PROFILES ───────────────────────────────────────────────
|
|
126
127
|
|
|
127
128
|
describe("MODEL_CAPABILITY_PROFILES", () => {
|
|
128
|
-
test("contains all
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
"gpt-4o", "gpt-4o-mini", "gemini-2.5-pro", "gemini-2.0-flash",
|
|
132
|
-
"deepseek-chat", "o3",
|
|
133
|
-
];
|
|
134
|
-
for (const model of required) {
|
|
129
|
+
test("contains profiles for all tier-mapped models", () => {
|
|
130
|
+
const tierModels = Object.keys(MODEL_CAPABILITY_TIER);
|
|
131
|
+
for (const model of tierModels) {
|
|
135
132
|
assert.ok(MODEL_CAPABILITY_PROFILES[model], `Missing profile for ${model}`);
|
|
136
133
|
}
|
|
137
134
|
});
|
|
@@ -345,3 +342,30 @@ describe("RoutingDecision.selectionMethod", () => {
|
|
|
345
342
|
assert.equal(result.selectionMethod, "tier-only");
|
|
346
343
|
});
|
|
347
344
|
});
|
|
345
|
+
|
|
346
|
+
// ─── ADR-004: Profile Completeness Lint ─────────────────────────────────────
|
|
347
|
+
// Every model in MODEL_CAPABILITY_TIER must have an entry in
|
|
348
|
+
// MODEL_CAPABILITY_PROFILES. This prevents profile staleness as new models
|
|
349
|
+
// are added to the tier map without corresponding capability data.
|
|
350
|
+
|
|
351
|
+
describe("profile completeness (ADR-004 lint)", () => {
|
|
352
|
+
test("every model in MODEL_CAPABILITY_TIER has a MODEL_CAPABILITY_PROFILES entry", () => {
|
|
353
|
+
const tierModels = Object.keys(MODEL_CAPABILITY_TIER);
|
|
354
|
+
const missing = tierModels.filter(id => !MODEL_CAPABILITY_PROFILES[id]);
|
|
355
|
+
assert.equal(
|
|
356
|
+
missing.length,
|
|
357
|
+
0,
|
|
358
|
+
`Models in MODEL_CAPABILITY_TIER but missing from MODEL_CAPABILITY_PROFILES:\n ${missing.join("\n ")}\n\nAdd capability profiles for these models in model-router.ts.`,
|
|
359
|
+
);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
test("MODEL_CAPABILITY_PROFILES does not contain models absent from MODEL_CAPABILITY_TIER", () => {
|
|
363
|
+
const profileModels = Object.keys(MODEL_CAPABILITY_PROFILES);
|
|
364
|
+
const orphaned = profileModels.filter(id => !MODEL_CAPABILITY_TIER[id]);
|
|
365
|
+
assert.equal(
|
|
366
|
+
orphaned.length,
|
|
367
|
+
0,
|
|
368
|
+
`Models in MODEL_CAPABILITY_PROFILES but not in MODEL_CAPABILITY_TIER:\n ${orphaned.join("\n ")}\n\nEither add these to MODEL_CAPABILITY_TIER or remove stale profiles.`,
|
|
369
|
+
);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
@@ -162,6 +162,34 @@ test("generateCodebaseMap: excludes .claude/ and other tool directories", () =>
|
|
|
162
162
|
}
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
+
test("generateCodebaseMap: excludes .agents/ and other tooling directories", () => {
|
|
166
|
+
const base = makeTmpRepo();
|
|
167
|
+
try {
|
|
168
|
+
addFile(base, "src/main.ts");
|
|
169
|
+
addFile(base, ".agents/skills/pdf/SKILL.md");
|
|
170
|
+
addFile(base, ".agents/skills/find-skills/SKILL.md");
|
|
171
|
+
addFile(base, ".bg-shell/session.json");
|
|
172
|
+
addFile(base, ".idea/workspace.xml");
|
|
173
|
+
addFile(base, ".cache/data.bin");
|
|
174
|
+
addFile(base, "tmp/scratch.ts");
|
|
175
|
+
addFile(base, "target/debug/build.rs");
|
|
176
|
+
addFile(base, "venv/lib/site.py");
|
|
177
|
+
|
|
178
|
+
const result = generateCodebaseMap(base);
|
|
179
|
+
assert.ok(result.content.includes("`src/main.ts`"), "should include src/main.ts");
|
|
180
|
+
assert.ok(!result.content.includes("SKILL.md"), "should exclude .agents/ files");
|
|
181
|
+
assert.ok(!result.content.includes(".bg-shell"), "should exclude .bg-shell/ files");
|
|
182
|
+
assert.ok(!result.content.includes(".idea"), "should exclude .idea/ files");
|
|
183
|
+
assert.ok(!result.content.includes(".cache"), "should exclude .cache/ files");
|
|
184
|
+
assert.ok(!result.content.includes("tmp/"), "should exclude tmp/ files");
|
|
185
|
+
assert.ok(!result.content.includes("target"), "should exclude target/ files");
|
|
186
|
+
assert.ok(!result.content.includes("venv"), "should exclude venv/ files");
|
|
187
|
+
assert.equal(result.fileCount, 1);
|
|
188
|
+
} finally {
|
|
189
|
+
cleanup(base);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
165
193
|
test("generateCodebaseMap: excludes binary and lock files", () => {
|
|
166
194
|
const base = makeTmpRepo();
|
|
167
195
|
try {
|
|
@@ -18,7 +18,7 @@ const VALID_INVITE = "https://discord.com/invite/nKXTsAcmbT";
|
|
|
18
18
|
/** Files that contain user-facing Discord invite links. */
|
|
19
19
|
const FILES_WITH_INVITE_LINKS: string[] = [
|
|
20
20
|
"README.md",
|
|
21
|
-
"docs/what-is-pi/15-pi-packages-the-ecosystem.md",
|
|
21
|
+
"docs/dev/what-is-pi/15-pi-packages-the-ecosystem.md",
|
|
22
22
|
];
|
|
23
23
|
|
|
24
24
|
describe("Discord invite links (#2699)", () => {
|
|
@@ -287,9 +287,9 @@ test("resolveModelForComplexity falls back to tier-only when capability_routing
|
|
|
287
287
|
assert.ok(!result.selectionMethod || result.selectionMethod === "tier-only");
|
|
288
288
|
});
|
|
289
289
|
|
|
290
|
-
test("MODEL_CAPABILITY_PROFILES has entries for
|
|
290
|
+
test("MODEL_CAPABILITY_PROFILES has entries for all tier-mapped models", () => {
|
|
291
291
|
const profiledModels = Object.keys(MODEL_CAPABILITY_PROFILES);
|
|
292
|
-
assert.ok(profiledModels.length >=
|
|
292
|
+
assert.ok(profiledModels.length >= 30, `Expected ≥30 profiles, got ${profiledModels.length}`);
|
|
293
293
|
assert.ok(MODEL_CAPABILITY_PROFILES["claude-opus-4-6"]);
|
|
294
294
|
assert.ok(MODEL_CAPABILITY_PROFILES["claude-haiku-4-5"]);
|
|
295
295
|
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// GSD2 — Regression test for broken resource-loader import path
|
|
2
|
+
// Ensures auto.ts imports resource-loader via package resolution, not a
|
|
3
|
+
// relative path that breaks when deployed to ~/.gsd/agent/extensions/gsd/.
|
|
4
|
+
|
|
5
|
+
import { describe, test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
const autoSrc = readFileSync(join(import.meta.dirname, "..", "auto.ts"), "utf-8");
|
|
11
|
+
|
|
12
|
+
describe("resource-loader import path", () => {
|
|
13
|
+
test("must not use relative import reaching above extensions/", () => {
|
|
14
|
+
// The old broken pattern: import("../../../" + "resource-loader.js")
|
|
15
|
+
// This resolves to ~/.gsd/resource-loader.js from deployed location, which
|
|
16
|
+
// doesn't exist. Regression introduced in #3899.
|
|
17
|
+
const brokenPattern = /import\(\s*["']\.\.\/\.\.\/\.\..*resource-loader/;
|
|
18
|
+
assert.ok(
|
|
19
|
+
!brokenPattern.test(autoSrc),
|
|
20
|
+
"auto.ts must not import resource-loader via relative path above extensions/ — " +
|
|
21
|
+
"breaks when deployed to ~/.gsd/agent/extensions/gsd/ (see #3899)",
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("uses createRequire to resolve resource-loader from package root", () => {
|
|
26
|
+
// The fix uses createRequire to find gsd-pi/package.json, then imports
|
|
27
|
+
// dist/resource-loader.js from there — works in both source and deployed.
|
|
28
|
+
assert.ok(
|
|
29
|
+
autoSrc.includes('createRequire(import.meta.url)'),
|
|
30
|
+
"auto.ts should use createRequire to resolve resource-loader",
|
|
31
|
+
);
|
|
32
|
+
assert.ok(
|
|
33
|
+
autoSrc.includes('resolve("gsd-pi/package.json")'),
|
|
34
|
+
"auto.ts should resolve gsd-pi package root via package.json",
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
});
|