gsd-pi 2.68.1-dev.362687a → 2.68.1-dev.c1497ab
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/resources/extensions/gsd/bootstrap/write-gate.js +1 -5
- package/dist/resources/extensions/gsd/guided-flow.js +25 -70
- package/dist/resources/extensions/gsd/model-router.js +32 -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 +13 -13
- 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 +13 -13
- 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/src/resources/extensions/gsd/auto-model-selection.ts +1 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -5
- package/src/resources/extensions/gsd/guided-flow.ts +22 -84
- package/src/resources/extensions/gsd/model-router.ts +44 -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/model-router.test.ts +2 -2
- 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/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/{VkiZZ5UjK7EfSjrWWd5RC → 5D80IWYltFwlAJiCZ84MC}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{VkiZZ5UjK7EfSjrWWd5RC → 5D80IWYltFwlAJiCZ84MC}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-6e4d7e9a4f57bed4.js"/><script src="/_next/static/chunks/4bd1b696-e356ca5ba0218e27.js" async=""></script><script src="/_next/static/chunks/3794-42fdce068d44fa4f.js" async=""></script><script src="/_next/static/chunks/main-app-fdab67f7802d7832.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: This page couldn’t load</title><style>:root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }</style><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;display:flex;align-items:center;justify-content:center"><div style="margin-top:-32px;max-width:325px;padding:32px 28px;text-align:left"><svg width="32" height="32" viewBox="-0.2 -1.5 32 32" fill="none" style="margin-bottom:24px"><path d="M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z" fill="var(--next-error-title)"></path></svg><h1 style="font-size:24px;font-weight:500;letter-spacing:-0.02em;line-height:32px;margin:0 0 12px 0;color:var(--next-error-title)">This page couldn’t load</h1><p style="font-size:14px;font-weight:400;line-height:21px;margin:0 0 20px 0;color:var(--next-error-message)">A server error occurred. Reload to try again.</p><form style="margin:0"><button type="submit" style="display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;font-size:14px;font-weight:500;line-height:20px;border-radius:6px;cursor:pointer;color:var(--next-error-btn-text);background:var(--next-error-btn-bg);border:var(--next-error-btn-border)">Reload</button></form></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-6e4d7e9a4f57bed4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57121,[],\"\"]\n3:I[74581,[],\"\"]\n4:I[90484,[],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[90484,[],\"ViewportBoundary\"]\na:I[90484,[],\"MetadataBoundary\"]\nc:I[27123,[],\"default\",1]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"_global-error\",{\"children\":[\"__PAGE__\",{}]}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[[\"$\",\"title\",null,{\"children\":\"500: This page couldn’t load\"}],[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }\"}}]]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"display\":\"flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"marginTop\":\"-32px\",\"maxWidth\":\"325px\",\"padding\":\"32px 28px\",\"textAlign\":\"left\"},\"children\":[[\"$\",\"svg\",null,{\"width\":\"32\",\"height\":\"32\",\"viewBox\":\"-0.2 -1.5 32 32\",\"fill\":\"none\",\"style\":{\"marginBottom\":\"24px\"},\"children\":[\"$\",\"path\",null,{\"d\":\"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z\",\"fill\":\"var(--next-error-title)\"}]}],[\"$\",\"h1\",null,{\"style\":{\"fontSize\":\"24px\",\"fontWeight\":500,\"letterSpacing\":\"-0.02em\",\"lineHeight\":\"32px\",\"margin\":\"0 0 12px 0\",\"color\":\"var(--next-error-title)\"},\"children\":\"This page couldn’t load\"}],[\"$\",\"p\",null,{\"style\":{\"fontSize\":\"14px\",\"fontWeight\":400,\"lineHeight\":\"21px\",\"margin\":\"0 0 20px 0\",\"color\":\"var(--next-error-message)\"},\"children\":\"A server error occurred. Reload to try again.\"}],[\"$\",\"form\",null,{\"style\":{\"margin\":0},\"children\":[\"$\",\"button\",null,{\"type\":\"submit\",\"style\":{\"display\":\"inline-flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\",\"height\":\"32px\",\"padding\":\"0 12px\",\"fontSize\":\"14px\",\"fontWeight\":500,\"lineHeight\":\"20px\",\"borderRadius\":\"6px\",\"cursor\":\"pointer\",\"color\":\"var(--next-error-btn-text)\",\"background\":\"var(--next-error-btn-bg)\",\"border\":\"var(--next-error-btn-border)\"},\"children\":\"Reload\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$@7\"]},null,false,\"$@7\"],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"
|
|
1
|
+
<!DOCTYPE html><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-6e4d7e9a4f57bed4.js"/><script src="/_next/static/chunks/4bd1b696-e356ca5ba0218e27.js" async=""></script><script src="/_next/static/chunks/3794-42fdce068d44fa4f.js" async=""></script><script src="/_next/static/chunks/main-app-fdab67f7802d7832.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: This page couldn’t load</title><style>:root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }</style><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;display:flex;align-items:center;justify-content:center"><div style="margin-top:-32px;max-width:325px;padding:32px 28px;text-align:left"><svg width="32" height="32" viewBox="-0.2 -1.5 32 32" fill="none" style="margin-bottom:24px"><path d="M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z" fill="var(--next-error-title)"></path></svg><h1 style="font-size:24px;font-weight:500;letter-spacing:-0.02em;line-height:32px;margin:0 0 12px 0;color:var(--next-error-title)">This page couldn’t load</h1><p style="font-size:14px;font-weight:400;line-height:21px;margin:0 0 20px 0;color:var(--next-error-message)">A server error occurred. Reload to try again.</p><form style="margin:0"><button type="submit" style="display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;font-size:14px;font-weight:500;line-height:20px;border-radius:6px;cursor:pointer;color:var(--next-error-btn-text);background:var(--next-error-btn-bg);border:var(--next-error-btn-border)">Reload</button></form></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-6e4d7e9a4f57bed4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57121,[],\"\"]\n3:I[74581,[],\"\"]\n4:I[90484,[],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[90484,[],\"ViewportBoundary\"]\na:I[90484,[],\"MetadataBoundary\"]\nc:I[27123,[],\"default\",1]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"_global-error\",{\"children\":[\"__PAGE__\",{}]}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[[\"$\",\"title\",null,{\"children\":\"500: This page couldn’t load\"}],[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }\"}}]]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"display\":\"flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"marginTop\":\"-32px\",\"maxWidth\":\"325px\",\"padding\":\"32px 28px\",\"textAlign\":\"left\"},\"children\":[[\"$\",\"svg\",null,{\"width\":\"32\",\"height\":\"32\",\"viewBox\":\"-0.2 -1.5 32 32\",\"fill\":\"none\",\"style\":{\"marginBottom\":\"24px\"},\"children\":[\"$\",\"path\",null,{\"d\":\"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z\",\"fill\":\"var(--next-error-title)\"}]}],[\"$\",\"h1\",null,{\"style\":{\"fontSize\":\"24px\",\"fontWeight\":500,\"letterSpacing\":\"-0.02em\",\"lineHeight\":\"32px\",\"margin\":\"0 0 12px 0\",\"color\":\"var(--next-error-title)\"},\"children\":\"This page couldn’t load\"}],[\"$\",\"p\",null,{\"style\":{\"fontSize\":\"14px\",\"fontWeight\":400,\"lineHeight\":\"21px\",\"margin\":\"0 0 20px 0\",\"color\":\"var(--next-error-message)\"},\"children\":\"A server error occurred. Reload to try again.\"}],[\"$\",\"form\",null,{\"style\":{\"margin\":0},\"children\":[\"$\",\"button\",null,{\"type\":\"submit\",\"style\":{\"display\":\"inline-flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\",\"height\":\"32px\",\"padding\":\"0 12px\",\"fontSize\":\"14px\",\"fontWeight\":500,\"lineHeight\":\"20px\",\"borderRadius\":\"6px\",\"cursor\":\"pointer\",\"color\":\"var(--next-error-btn-text)\",\"background\":\"var(--next-error-btn-bg)\",\"border\":\"var(--next-error-btn-border)\"},\"children\":\"Reload\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$@7\"]},null,false,\"$@7\"],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"5D80IWYltFwlAJiCZ84MC\"}\n"])</script><script>self.__next_f.push([1,"d:[]\n7:\"$Wd\"\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\nb:[]\n"])</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"node":{},"edge":{},"encryptionKey":"
|
|
1
|
+
{"node":{},"edge":{},"encryptionKey":"ImH7aNfUO2RRkkY1URhjN33kUDO+hFzWdB/jMCBiNZI="}
|
package/package.json
CHANGED
|
@@ -132,9 +132,7 @@ export async function selectAndApplyModel(
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// Load user capability overrides from preferences (D-17: deep-merged with built-in profiles)
|
|
135
|
-
const capabilityOverrides = loadCapabilityOverrides(
|
|
136
|
-
(prefs as { modelOverrides?: Record<string, { capabilities?: Record<string, number> }> } | undefined) ?? {},
|
|
137
|
-
);
|
|
135
|
+
const capabilityOverrides = loadCapabilityOverrides(prefs ?? {});
|
|
138
136
|
|
|
139
137
|
// Fire before_model_select hook (ADR-004, D-03)
|
|
140
138
|
// Hook can override model selection entirely by returning { modelId }
|
|
@@ -47,13 +47,9 @@ let pendingGateId: string | null = null;
|
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Recognized gate question ID patterns.
|
|
50
|
-
* These appear in
|
|
50
|
+
* These appear in discuss.md (depth/requirements/roadmap).
|
|
51
51
|
*/
|
|
52
52
|
const GATE_QUESTION_PATTERNS = [
|
|
53
|
-
"layer1_scope_gate",
|
|
54
|
-
"layer2_architecture_gate",
|
|
55
|
-
"layer3_error_gate",
|
|
56
|
-
"layer4_quality_gate",
|
|
57
53
|
"depth_verification",
|
|
58
54
|
] as const;
|
|
59
55
|
|
|
@@ -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
|
/**
|
|
@@ -58,7 +58,7 @@ export interface ModelCapabilities {
|
|
|
58
58
|
// Maps known model IDs to their capability tier. Used when tier_models is not
|
|
59
59
|
// explicitly configured to pick the best available model for each tier.
|
|
60
60
|
|
|
61
|
-
const MODEL_CAPABILITY_TIER: Record<string, ComplexityTier> = {
|
|
61
|
+
export const MODEL_CAPABILITY_TIER: Record<string, ComplexityTier> = {
|
|
62
62
|
// Light-tier models (cheapest)
|
|
63
63
|
"claude-haiku-4-5": "light",
|
|
64
64
|
"claude-3-5-haiku-latest": "light",
|
|
@@ -139,15 +139,49 @@ const MODEL_COST_PER_1K_INPUT: Record<string, number> = {
|
|
|
139
139
|
// model selection within an eligible tier set.
|
|
140
140
|
|
|
141
141
|
export const MODEL_CAPABILITY_PROFILES: Record<string, ModelCapabilities> = {
|
|
142
|
-
|
|
143
|
-
"claude-
|
|
144
|
-
"claude-
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
142
|
+
// ── Anthropic ──────────────────────────────────────────────────────────────
|
|
143
|
+
"claude-opus-4-6": { coding: 95, debugging: 90, research: 85, reasoning: 95, speed: 30, longContext: 80, instruction: 90 },
|
|
144
|
+
"claude-sonnet-4-6": { coding: 85, debugging: 80, research: 75, reasoning: 80, speed: 60, longContext: 75, instruction: 85 },
|
|
145
|
+
"claude-sonnet-4-5-20250514": { coding: 85, debugging: 80, research: 75, reasoning: 80, speed: 60, longContext: 75, instruction: 85 },
|
|
146
|
+
"claude-3-5-sonnet-latest": { coding: 82, debugging: 78, research: 72, reasoning: 78, speed: 62, longContext: 70, instruction: 82 },
|
|
147
|
+
"claude-haiku-4-5": { coding: 60, debugging: 50, research: 45, reasoning: 50, speed: 95, longContext: 50, instruction: 75 },
|
|
148
|
+
"claude-3-5-haiku-latest": { coding: 60, debugging: 50, research: 45, reasoning: 50, speed: 95, longContext: 50, instruction: 75 },
|
|
149
|
+
"claude-3-haiku-20240307": { coding: 50, debugging: 40, research: 35, reasoning: 40, speed: 95, longContext: 40, instruction: 65 },
|
|
150
|
+
"claude-3-opus-latest": { coding: 90, debugging: 85, research: 82, reasoning: 90, speed: 35, longContext: 75, instruction: 88 },
|
|
151
|
+
|
|
152
|
+
// ── OpenAI GPT ─────────────────────────────────────────────────────────────
|
|
153
|
+
"gpt-4o": { coding: 80, debugging: 75, research: 70, reasoning: 75, speed: 65, longContext: 70, instruction: 80 },
|
|
154
|
+
"gpt-4o-mini": { coding: 55, debugging: 45, research: 40, reasoning: 45, speed: 90, longContext: 45, instruction: 70 },
|
|
155
|
+
"gpt-4-turbo": { coding: 78, debugging: 72, research: 68, reasoning: 72, speed: 50, longContext: 65, instruction: 78 },
|
|
156
|
+
"gpt-4.1": { coding: 82, debugging: 78, research: 72, reasoning: 78, speed: 62, longContext: 72, instruction: 82 },
|
|
157
|
+
"gpt-4.1-mini": { coding: 58, debugging: 48, research: 42, reasoning: 48, speed: 88, longContext: 48, instruction: 72 },
|
|
158
|
+
"gpt-4.1-nano": { coding: 40, debugging: 30, research: 25, reasoning: 30, speed: 95, longContext: 30, instruction: 60 },
|
|
159
|
+
"gpt-5": { coding: 92, debugging: 88, research: 85, reasoning: 92, speed: 40, longContext: 85, instruction: 90 },
|
|
160
|
+
"gpt-5-mini": { coding: 62, debugging: 52, research: 48, reasoning: 52, speed: 88, longContext: 52, instruction: 74 },
|
|
161
|
+
"gpt-5-nano": { coding: 42, debugging: 32, research: 28, reasoning: 32, speed: 95, longContext: 32, instruction: 62 },
|
|
162
|
+
"gpt-5-pro": { coding: 94, debugging: 90, research: 88, reasoning: 94, speed: 35, longContext: 88, instruction: 92 },
|
|
163
|
+
"gpt-5.1": { coding: 93, debugging: 89, research: 86, reasoning: 93, speed: 42, longContext: 86, instruction: 91 },
|
|
164
|
+
"gpt-5.1-codex-max": { coding: 90, debugging: 85, research: 70, reasoning: 85, speed: 55, longContext: 75, instruction: 85 },
|
|
165
|
+
"gpt-5.1-codex-mini": { coding: 65, debugging: 55, research: 40, reasoning: 50, speed: 88, longContext: 48, instruction: 72 },
|
|
166
|
+
"gpt-5.2": { coding: 93, debugging: 90, research: 87, reasoning: 93, speed: 42, longContext: 87, instruction: 91 },
|
|
167
|
+
"gpt-5.2-codex": { coding: 93, debugging: 90, research: 72, reasoning: 88, speed: 50, longContext: 78, instruction: 88 },
|
|
168
|
+
"gpt-5.3-codex": { coding: 94, debugging: 91, research: 74, reasoning: 89, speed: 50, longContext: 80, instruction: 89 },
|
|
169
|
+
"gpt-5.3-codex-spark": { coding: 68, debugging: 58, research: 42, reasoning: 52, speed: 90, longContext: 50, instruction: 74 },
|
|
170
|
+
"gpt-5.4": { coding: 95, debugging: 92, research: 88, reasoning: 94, speed: 42, longContext: 88, instruction: 92 },
|
|
171
|
+
|
|
172
|
+
// ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
|
|
173
|
+
"o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
|
|
174
|
+
"o3": { coding: 80, debugging: 85, research: 80, reasoning: 92, speed: 25, longContext: 70, instruction: 85 },
|
|
175
|
+
"o4-mini": { coding: 75, debugging: 80, research: 72, reasoning: 88, speed: 60, longContext: 65, instruction: 80 },
|
|
176
|
+
"o4-mini-deep-research": { coding: 75, debugging: 80, research: 85, reasoning: 88, speed: 30, longContext: 80, instruction: 80 },
|
|
177
|
+
|
|
178
|
+
// ── Google ─────────────────────────────────────────────────────────────────
|
|
179
|
+
"gemini-2.5-pro": { coding: 75, debugging: 70, research: 85, reasoning: 75, speed: 55, longContext: 90, instruction: 75 },
|
|
180
|
+
"gemini-2.0-flash": { coding: 50, debugging: 40, research: 50, reasoning: 40, speed: 95, longContext: 60, instruction: 65 },
|
|
181
|
+
"gemini-flash-2.0": { coding: 50, debugging: 40, research: 50, reasoning: 40, speed: 95, longContext: 60, instruction: 65 },
|
|
182
|
+
|
|
183
|
+
// ── DeepSeek ───────────────────────────────────────────────────────────────
|
|
184
|
+
"deepseek-chat": { coding: 75, debugging: 65, research: 55, reasoning: 70, speed: 70, longContext: 55, instruction: 65 },
|
|
151
185
|
};
|
|
152
186
|
|
|
153
187
|
// ─── Base Task Requirements Data Table ───────────────────────────────────────
|
|
@@ -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
|
+
});
|
|
@@ -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
|
});
|
|
@@ -230,16 +230,13 @@ import {
|
|
|
230
230
|
// ─── Scenario 19: isGateQuestionId recognizes all gate patterns ──
|
|
231
231
|
|
|
232
232
|
test('write-gate: isGateQuestionId recognizes all gate patterns', () => {
|
|
233
|
-
assert.strictEqual(isGateQuestionId('layer1_scope_gate'), true);
|
|
234
|
-
assert.strictEqual(isGateQuestionId('layer2_architecture_gate'), true);
|
|
235
|
-
assert.strictEqual(isGateQuestionId('layer3_error_gate'), true);
|
|
236
|
-
assert.strictEqual(isGateQuestionId('layer4_quality_gate'), true);
|
|
237
233
|
assert.strictEqual(isGateQuestionId('depth_verification'), true);
|
|
238
234
|
assert.strictEqual(isGateQuestionId('depth_verification_M002'), true);
|
|
239
|
-
assert.strictEqual(isGateQuestionId('
|
|
235
|
+
assert.strictEqual(isGateQuestionId('depth_verification_confirm'), true);
|
|
240
236
|
// Non-gate question IDs
|
|
241
237
|
assert.strictEqual(isGateQuestionId('project_intent'), false);
|
|
242
238
|
assert.strictEqual(isGateQuestionId('feature_priority'), false);
|
|
239
|
+
assert.strictEqual(isGateQuestionId('layer1_scope_gate'), false);
|
|
243
240
|
assert.strictEqual(isGateQuestionId(''), false);
|
|
244
241
|
});
|
|
245
242
|
|
|
@@ -249,14 +246,14 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => {
|
|
|
249
246
|
clearDiscussionFlowState();
|
|
250
247
|
assert.strictEqual(getPendingGate(), null, 'starts null');
|
|
251
248
|
|
|
252
|
-
setPendingGate('
|
|
253
|
-
assert.strictEqual(getPendingGate(), '
|
|
249
|
+
setPendingGate('depth_verification');
|
|
250
|
+
assert.strictEqual(getPendingGate(), 'depth_verification', 'set correctly');
|
|
254
251
|
|
|
255
252
|
clearPendingGate();
|
|
256
253
|
assert.strictEqual(getPendingGate(), null, 'cleared correctly');
|
|
257
254
|
|
|
258
255
|
// clearDiscussionFlowState also clears pending gate
|
|
259
|
-
setPendingGate('
|
|
256
|
+
setPendingGate('depth_verification_M002');
|
|
260
257
|
clearDiscussionFlowState();
|
|
261
258
|
assert.strictEqual(getPendingGate(), null, 'clearDiscussionFlowState clears pending gate');
|
|
262
259
|
});
|
|
@@ -265,12 +262,12 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => {
|
|
|
265
262
|
|
|
266
263
|
test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate', () => {
|
|
267
264
|
clearDiscussionFlowState();
|
|
268
|
-
setPendingGate('
|
|
265
|
+
setPendingGate('depth_verification');
|
|
269
266
|
|
|
270
267
|
// write should be blocked during discussion
|
|
271
268
|
const writeResult = shouldBlockPendingGate('write', 'M001', false);
|
|
272
269
|
assert.strictEqual(writeResult.block, true, 'write should be blocked');
|
|
273
|
-
assert.ok(writeResult.reason!.includes('
|
|
270
|
+
assert.ok(writeResult.reason!.includes('depth_verification'), 'reason mentions the gate');
|
|
274
271
|
|
|
275
272
|
// edit should be blocked
|
|
276
273
|
const editResult = shouldBlockPendingGate('edit', 'M001', false);
|
|
@@ -287,7 +284,7 @@ test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate',
|
|
|
287
284
|
|
|
288
285
|
test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions during pending gate', () => {
|
|
289
286
|
clearDiscussionFlowState();
|
|
290
|
-
setPendingGate('
|
|
287
|
+
setPendingGate('depth_verification');
|
|
291
288
|
|
|
292
289
|
// ask_user_questions is always safe (model needs to re-ask)
|
|
293
290
|
assert.strictEqual(shouldBlockPendingGate('ask_user_questions', 'M001').block, false);
|
|
@@ -304,7 +301,7 @@ test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions
|
|
|
304
301
|
|
|
305
302
|
test('write-gate: shouldBlockPendingGate blocks outside discussion when a gate is pending', () => {
|
|
306
303
|
clearDiscussionFlowState();
|
|
307
|
-
setPendingGate('
|
|
304
|
+
setPendingGate('depth_verification');
|
|
308
305
|
|
|
309
306
|
// No milestoneId and no queue phase — still block because the gate is pending
|
|
310
307
|
const result = shouldBlockPendingGate('write', null, false);
|
|
@@ -330,7 +327,7 @@ test('write-gate: shouldBlockPendingGate blocks in queue mode when gate is pendi
|
|
|
330
327
|
|
|
331
328
|
test('write-gate: shouldBlockPendingGateBash allows read-only commands during pending gate', () => {
|
|
332
329
|
clearDiscussionFlowState();
|
|
333
|
-
setPendingGate('
|
|
330
|
+
setPendingGate('depth_verification');
|
|
334
331
|
|
|
335
332
|
assert.strictEqual(shouldBlockPendingGateBash('cat file.txt', 'M001').block, false);
|
|
336
333
|
assert.strictEqual(shouldBlockPendingGateBash('git log --oneline', 'M001').block, false);
|
|
@@ -344,11 +341,11 @@ test('write-gate: shouldBlockPendingGateBash allows read-only commands during pe
|
|
|
344
341
|
|
|
345
342
|
test('write-gate: shouldBlockPendingGateBash blocks mutating commands during pending gate', () => {
|
|
346
343
|
clearDiscussionFlowState();
|
|
347
|
-
setPendingGate('
|
|
344
|
+
setPendingGate('depth_verification');
|
|
348
345
|
|
|
349
346
|
const result = shouldBlockPendingGateBash('npm run build', 'M001');
|
|
350
347
|
assert.strictEqual(result.block, true, 'mutating bash should be blocked');
|
|
351
|
-
assert.ok(result.reason!.includes('
|
|
348
|
+
assert.ok(result.reason!.includes('depth_verification'));
|
|
352
349
|
|
|
353
350
|
clearDiscussionFlowState();
|
|
354
351
|
});
|
|
@@ -365,7 +362,7 @@ test('write-gate: no pending gate means no blocking', () => {
|
|
|
365
362
|
// ─── Scenario 28: resetWriteGateState clears pending gate ──
|
|
366
363
|
|
|
367
364
|
test('write-gate: resetWriteGateState clears pending gate', () => {
|
|
368
|
-
setPendingGate('
|
|
365
|
+
setPendingGate('depth_verification');
|
|
369
366
|
resetWriteGateState();
|
|
370
367
|
assert.strictEqual(getPendingGate(), null);
|
|
371
368
|
});
|