gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.98ea09b1e

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.
Files changed (277) hide show
  1. package/README.md +2 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +7 -0
  4. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  5. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  6. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  7. package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
  8. package/dist/resources/extensions/gsd/auto/phases.js +8 -1
  9. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
  11. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  12. package/dist/resources/extensions/gsd/auto-post-unit.js +70 -9
  13. package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
  14. package/dist/resources/extensions/gsd/auto-start.js +85 -12
  15. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  16. package/dist/resources/extensions/gsd/auto.js +30 -3
  17. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
  18. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  19. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
  20. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +13 -1
  21. package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
  22. package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
  23. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  24. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  25. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  26. package/dist/resources/extensions/gsd/doctor.js +2 -28
  27. package/dist/resources/extensions/gsd/export-html.js +27 -425
  28. package/dist/resources/extensions/gsd/git-service.js +39 -1
  29. package/dist/resources/extensions/gsd/gsd-db.js +1 -0
  30. package/dist/resources/extensions/gsd/guided-flow.js +13 -6
  31. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  32. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  33. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  34. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  35. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  36. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  37. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  38. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  39. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  40. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  41. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  42. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  43. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  44. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  45. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  46. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  47. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  48. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  49. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  50. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  51. package/dist/resources/extensions/gsd/status-guards.js +4 -0
  52. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  53. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  54. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  55. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  56. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  57. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  58. package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
  59. package/dist/resources/extensions/gsd/validation.js +23 -1
  60. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  61. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  62. package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
  63. package/dist/resources/extensions/shared/html-shell.js +388 -0
  64. package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
  65. package/dist/resources/extensions/visual-brief/prompts.js +29 -0
  66. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  67. package/dist/web/standalone/.next/BUILD_ID +1 -1
  68. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  69. package/dist/web/standalone/.next/build-manifest.json +3 -3
  70. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  71. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  81. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  91. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/index.html +1 -1
  93. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  94. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  96. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  98. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  99. package/dist/web/standalone/.next/server/app/page.js +2 -2
  100. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  101. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  103. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  104. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  107. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  108. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  109. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  110. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  111. package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
  112. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  113. package/package.json +2 -2
  114. package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
  115. package/packages/native/tsconfig.json +2 -1
  116. package/packages/native/tsconfig.tsbuildinfo +1 -1
  117. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  118. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  119. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  120. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  121. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  122. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  123. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  124. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  125. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  126. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  127. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  128. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  129. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  130. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  131. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  132. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  133. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  134. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  135. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  136. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  137. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  138. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  139. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  140. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  141. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  142. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  143. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  144. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  145. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  146. package/src/resources/GSD-WORKFLOW.md +7 -0
  147. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  148. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  149. package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
  150. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  151. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  152. package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
  153. package/src/resources/extensions/gsd/auto/phases.ts +7 -1
  154. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  155. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
  156. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  157. package/src/resources/extensions/gsd/auto-post-unit.ts +77 -7
  158. package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
  159. package/src/resources/extensions/gsd/auto-start.ts +92 -9
  160. package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
  161. package/src/resources/extensions/gsd/auto.ts +32 -3
  162. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
  163. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  164. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
  165. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +16 -1
  166. package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
  167. package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
  168. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  169. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  170. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  171. package/src/resources/extensions/gsd/doctor.ts +2 -27
  172. package/src/resources/extensions/gsd/export-html.ts +27 -427
  173. package/src/resources/extensions/gsd/git-service.ts +45 -1
  174. package/src/resources/extensions/gsd/gsd-db.ts +3 -0
  175. package/src/resources/extensions/gsd/guided-flow.ts +14 -7
  176. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  177. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  178. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  179. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  180. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  181. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  182. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  183. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  184. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  185. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  186. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  187. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  188. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  189. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  190. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  191. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  192. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  193. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  194. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  195. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  196. package/src/resources/extensions/gsd/status-guards.ts +5 -0
  197. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  198. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  199. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  200. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
  201. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
  202. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -6
  203. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  204. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
  205. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  206. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  207. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  208. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  209. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  210. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
  211. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  212. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  213. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
  214. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  215. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  216. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  217. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  218. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
  219. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  220. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  221. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  222. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  223. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
  224. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  225. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  226. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  227. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  228. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  229. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  230. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  231. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  232. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  233. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  234. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  235. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  236. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  237. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  238. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
  239. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  240. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
  241. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  242. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  243. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  244. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +65 -7
  245. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  246. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
  247. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  248. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  249. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  250. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  251. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
  252. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  253. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  254. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  255. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  256. package/src/resources/extensions/gsd/types.ts +1 -1
  257. package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
  258. package/src/resources/extensions/gsd/validation.ts +23 -1
  259. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  260. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  261. package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
  262. package/src/resources/extensions/shared/html-shell.ts +412 -0
  263. package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
  264. package/src/resources/extensions/visual-brief/prompts.ts +37 -1
  265. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
  266. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  267. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  268. package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
  269. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  270. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  271. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  272. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  273. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  274. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  275. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  276. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
  277. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@
4
4
  // First non-empty source wins.
5
5
 
6
6
  import { spawnSync, type SpawnSyncReturns } from "node:child_process";
7
- import { existsSync, readFileSync } from "node:fs";
7
+ import { existsSync, readFileSync, readdirSync, type Dirent } from "node:fs";
8
8
  import { join, basename } from "node:path";
9
9
  import type { AuditWarning, RuntimeError, VerificationCheck, VerificationResult } from "./types.js";
10
10
  import { DEFAULT_COMMAND_TIMEOUT_MS } from "./constants.js";
@@ -44,7 +44,8 @@ const PACKAGE_SCRIPT_KEYS = ["typecheck", "lint", "test"] as const;
44
44
  * 1. Explicit preference commands
45
45
  * 2. Task plan verify field (split on &&)
46
46
  * 3. package.json scripts (typecheck, lint, test)
47
- * 4. None found
47
+ * 4. Python pytest project markers
48
+ * 5. None found
48
49
  */
49
50
  export function discoverCommands(options: DiscoverCommandsOptions): DiscoveredCommands {
50
51
  // 1. Preference commands
@@ -91,10 +92,67 @@ export function discoverCommands(options: DiscoverCommandsOptions): DiscoveredCo
91
92
  }
92
93
  }
93
94
 
94
- // 4. Nothing found
95
+ const pythonCommand = discoverPythonPytestCommand(options.cwd);
96
+ if (pythonCommand) {
97
+ return { commands: [pythonCommand], source: "python-project" };
98
+ }
99
+
100
+ // 5. Nothing found
95
101
  return { commands: [], source: "none" };
96
102
  }
97
103
 
104
+ function discoverPythonPytestCommand(cwd: string): string | null {
105
+ const hasPythonTestFiles = hasPythonTests(join(cwd, "tests"));
106
+ const hasPytestConfig = existsSync(join(cwd, "pytest.ini"));
107
+ const pyprojectPath = join(cwd, "pyproject.toml");
108
+ const hasPyproject = existsSync(pyprojectPath);
109
+
110
+ if (!hasPythonTestFiles && !hasPytestConfig && !hasPyproject) {
111
+ return null;
112
+ }
113
+
114
+ if (hasPytestConfig || hasPythonTestFiles) {
115
+ return "python3 -m pytest";
116
+ }
117
+
118
+ try {
119
+ const pyproject = readFileSync(pyprojectPath, "utf-8");
120
+ if (
121
+ pyproject.includes("[tool.pytest]") ||
122
+ pyproject.includes("[tool.pytest.") ||
123
+ pyproject.includes("[pytest]") ||
124
+ pyproject.includes("[tool:pytest]")
125
+ ) {
126
+ return "python3 -m pytest";
127
+ }
128
+ } catch {
129
+ // Ignore unreadable pyproject.toml and fall through.
130
+ }
131
+
132
+ return null;
133
+ }
134
+
135
+ function hasPythonTests(dir: string): boolean {
136
+ let entries: Dirent[];
137
+ try {
138
+ entries = readdirSync(dir, { withFileTypes: true });
139
+ } catch {
140
+ return false;
141
+ }
142
+
143
+ for (const entry of entries) {
144
+ const path = join(dir, entry.name);
145
+ if (entry.isDirectory() && hasPythonTests(path)) {
146
+ return true;
147
+ }
148
+ if (entry.isFile() && /^test_.*\.py$|^.*_test\.py$/.test(entry.name)) {
149
+ return true;
150
+ }
151
+ }
152
+
153
+ return false;
154
+ }
155
+
98
156
  // ─── Failure Context Formatting ──────────────────────────────────────────────
99
157
 
100
158
  /** Maximum chars of stderr to include per failed check in failure context. */
@@ -144,7 +202,7 @@ export function formatFailureContext(result: VerificationResult): string {
144
202
  // ─── Gate Execution ─────────────────────────────────────────────────────────
145
203
 
146
204
  /** Characters that indicate shell injection when found in a command string. */
147
- const SHELL_INJECTION_PATTERN = /[;|`]|\$\(/;
205
+ const SHELL_INJECTION_PATTERN = /[;|`<>]|\$\(/;
148
206
 
149
207
  /**
150
208
  * Known executable first-tokens that are safe to run.
@@ -182,6 +240,7 @@ const KNOWN_COMMAND_PREFIXES = new Set([
182
240
  * Heuristics (any true → prose-like):
183
241
  * 1. First token starts with an uppercase letter and the string has 4+ words
184
242
  * 2. String contains commas followed by spaces (prose clause structure)
243
+ * 3. First token has no ASCII letters or digits and the string has 4+ words
185
244
  */
186
245
  export function isLikelyCommand(cmd: string): boolean {
187
246
  const trimmed = cmd.trim();
@@ -208,6 +267,9 @@ export function isLikelyCommand(cmd: string): boolean {
208
267
  // First token has uppercase letters and no path separators → prose
209
268
  if (/[A-Z]/.test(firstToken) && !firstToken.includes("/")) return false;
210
269
 
270
+ // Non-ASCII prose with multiple words should not be executed as a command.
271
+ if (!/[A-Za-z0-9]/.test(firstToken) && tokens.length >= 4) return false;
272
+
211
273
  return true;
212
274
  }
213
275
 
@@ -215,9 +277,19 @@ export function isLikelyCommand(cmd: string): boolean {
215
277
  * Validate a command string for obvious shell injection patterns.
216
278
  * Returns the command unchanged if safe, or null if suspicious.
217
279
  */
280
+ export function validateVerificationCommand(cmd: string): { ok: true } | { ok: false; reason: string } {
281
+ if (SHELL_INJECTION_PATTERN.test(cmd)) {
282
+ return { ok: false, reason: "contains shell control syntax such as pipes, redirects, semicolons, backticks, or command substitution" };
283
+ }
284
+ if (!isLikelyCommand(cmd)) {
285
+ return { ok: false, reason: "does not look like a runnable command" };
286
+ }
287
+ return { ok: true };
288
+ }
289
+
218
290
  function sanitizeCommand(cmd: string): string | null {
219
- if (SHELL_INJECTION_PATTERN.test(cmd)) return null;
220
- if (!isLikelyCommand(cmd)) return null;
291
+ const validation = validateVerificationCommand(cmd);
292
+ if (!validation.ok) return null;
221
293
  return cmd;
222
294
  }
223
295
 
@@ -195,11 +195,11 @@ export function renderSummaryContent(
195
195
 
196
196
  // ── Frontmatter (YAML list format, matches parseSummary() expectations) ──
197
197
  const keyFilesYaml = taskRow.key_files && taskRow.key_files.length > 0
198
- ? taskRow.key_files.map(f => ` - ${f}`).join("\n")
199
- : " - (none)";
198
+ ? `\n${taskRow.key_files.map(f => ` - ${f}`).join("\n")}`
199
+ : " []";
200
200
  const keyDecisionsYaml = taskRow.key_decisions && taskRow.key_decisions.length > 0
201
- ? taskRow.key_decisions.map(d => ` - ${d}`).join("\n")
202
- : " - (none)";
201
+ ? `\n${taskRow.key_decisions.map(d => ` - ${d}`).join("\n")}`
202
+ : " []";
203
203
 
204
204
  // Derive verification_result from evidence if available
205
205
  const evidenceList = evidence ?? [];
@@ -230,10 +230,8 @@ export function renderSummaryContent(
230
230
  id: ${taskRow.id}
231
231
  parent: ${sliceId}
232
232
  milestone: ${milestoneId}
233
- key_files:
234
- ${keyFilesYaml}
235
- key_decisions:
236
- ${keyDecisionsYaml}
233
+ key_files:${keyFilesYaml}
234
+ key_decisions:${keyDecisionsYaml}
237
235
  duration: ${taskRow.duration || ""}
238
236
  verification_result: ${verificationResult}
239
237
  completed_at: ${taskRow.completed_at || ""}
@@ -23,6 +23,7 @@ import { join } from "node:path";
23
23
 
24
24
  import type { AutoSession } from "./auto/session.js";
25
25
  import { debugLog } from "./debug-logger.js";
26
+ import { logWarning } from "./workflow-logger.js";
26
27
  import { emitJournalEvent } from "./journal.js";
27
28
  import { emitWorktreeCreated, emitWorktreeMerged } from "./worktree-telemetry.js";
28
29
  import {
@@ -76,6 +77,13 @@ import {
76
77
  teardownAutoWorktree,
77
78
  } from "./auto-worktree.js";
78
79
 
80
+ const recentWorktreeMergeFailures = new Map<string, number>();
81
+ const MERGE_FAILURE_DEDUPE_MS = 60_000;
82
+
83
+ export function resetRecentWorktreeMergeFailuresForTest(): void {
84
+ recentWorktreeMergeFailures.clear();
85
+ }
86
+
79
87
  // ─── Types ───────────────────────────────────────────────────────────────
80
88
 
81
89
  export interface NotifyCtx {
@@ -525,7 +533,7 @@ export function _enterMilestoneCore(
525
533
 
526
534
  // Phase B: claim a milestone lease before any worktree mutation. Two
527
535
  // workers cannot enter the same milestone concurrently. Best-effort:
528
- // skip if no worker registered (single-worker fallback) or DB
536
+ // warn if no worker registered (single-worker fallback) or skip if DB
529
537
  // unavailable; reuse existing lease if we already hold it on this
530
538
  // milestone (re-entry within the same session).
531
539
  if (s.workerId) {
@@ -618,6 +626,11 @@ export function _enterMilestoneCore(
618
626
  });
619
627
  }
620
628
  }
629
+ } else {
630
+ logWarning(
631
+ "worktree",
632
+ `enterMilestone(${milestoneId}) ran before auto worker registration; milestone lease was not claimed.`,
633
+ );
621
634
  }
622
635
 
623
636
  // Resolve the project root for worktree operations via shared helper.
@@ -836,6 +849,32 @@ function rebuildGitService(
836
849
  s.gitService = deps.gitServiceFactory(s.basePath);
837
850
  }
838
851
 
852
+ function emitWorktreeMergeFailedOnce(
853
+ basePath: string,
854
+ milestoneId: string,
855
+ err: unknown,
856
+ ): void {
857
+ const msg = err instanceof Error ? err.message : String(err);
858
+ const errorCategory = err instanceof Error ? err.name : "Error";
859
+ const now = Date.now();
860
+ const key = `${basePath}\0${milestoneId}\0${errorCategory}`;
861
+ const previous = recentWorktreeMergeFailures.get(key);
862
+ if (previous && now - previous < MERGE_FAILURE_DEDUPE_MS) return;
863
+ for (const [candidate, ts] of recentWorktreeMergeFailures) {
864
+ if (now - ts >= MERGE_FAILURE_DEDUPE_MS) {
865
+ recentWorktreeMergeFailures.delete(candidate);
866
+ }
867
+ }
868
+ emitJournalEvent(basePath, {
869
+ ts: new Date().toISOString(),
870
+ flowId: randomUUID(),
871
+ seq: 0,
872
+ eventType: "worktree-merge-failed",
873
+ data: { milestoneId, error: msg },
874
+ });
875
+ recentWorktreeMergeFailures.set(key, now);
876
+ }
877
+
839
878
  // ─── Session-less merge entry (ADR-016 phase 2 / A1) ─────────────────────
840
879
 
841
880
  /**
@@ -985,13 +1024,7 @@ function _mergeWorktreeModeImpl(
985
1024
  error: msg,
986
1025
  fallback: "chdir-to-project-root",
987
1026
  });
988
- emitJournalEvent(originalBasePath || worktreeBasePath, {
989
- ts: new Date().toISOString(),
990
- flowId: randomUUID(),
991
- seq: 0,
992
- eventType: "worktree-merge-failed",
993
- data: { milestoneId, error: msg },
994
- });
1027
+ emitWorktreeMergeFailedOnce(originalBasePath || worktreeBasePath, milestoneId, err);
995
1028
  // Surface a clear, actionable error. Worktree and milestone branch
996
1029
  // are intentionally preserved — nothing has been deleted. User can
997
1030
  // retry /gsd dispatch complete-milestone or merge manually once the
@@ -0,0 +1,412 @@
1
+ export interface HtmlShellLink {
2
+ href: string;
3
+ label: string;
4
+ }
5
+
6
+ export interface HtmlShellOptions {
7
+ title: string;
8
+ documentTitle?: string;
9
+ subtitle?: string;
10
+ kind: string;
11
+ version?: string;
12
+ generatedAt: string;
13
+ mainHtml: string;
14
+ toc?: readonly HtmlShellLink[];
15
+ headerActionsHtml?: string;
16
+ footerNote?: string;
17
+ }
18
+
19
+ export interface HtmlShellTemplateOptions extends Omit<HtmlShellOptions, "mainHtml" | "generatedAt"> {
20
+ mainPlaceholder: string;
21
+ generatedAtPlaceholder?: string;
22
+ }
23
+
24
+ export function renderHtmlShell(options: HtmlShellOptions): string {
25
+ const version = options.version ? `v${esc(options.version)}` : "";
26
+ const documentTitle = options.documentTitle ?? `${options.kind} - ${options.title}`;
27
+ const subtitle = options.subtitle ? `<span class="header-path">${esc(options.subtitle)}</span>` : "";
28
+ const toc = options.toc?.length
29
+ ? `<nav class="toc" aria-label="Report sections">
30
+ <ul>
31
+ ${options.toc.map((item) => ` <li><a href="${esc(item.href)}">${esc(item.label)}</a></li>`).join("\n")}
32
+ </ul>
33
+ </nav>`
34
+ : "";
35
+ const actions = options.headerActionsHtml ? `${options.headerActionsHtml}` : "";
36
+ const footerNote = options.footerNote ? `<span class="sep">/</span>\n <span>${esc(options.footerNote)}</span>` : "";
37
+
38
+ return `<!DOCTYPE html>
39
+ <html lang="en">
40
+ <head>
41
+ <meta charset="UTF-8">
42
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
43
+ <title>${esc(documentTitle)}</title>
44
+ <style>${HTML_SHELL_CSS}</style>
45
+ </head>
46
+ <body>
47
+ <header>
48
+ <div class="header-inner">
49
+ <div class="branding">
50
+ <span class="logo">GSD</span>
51
+ ${version ? `<span class="version">${version}</span>` : ""}
52
+ </div>
53
+ <div class="header-meta">
54
+ <h1>${esc(options.title)}</h1>
55
+ ${subtitle}
56
+ </div>
57
+ <div class="header-right">
58
+ ${actions}
59
+ <span class="kind-chip">${esc(options.kind)}</span>
60
+ <div class="generated">${formatDateLong(options.generatedAt)}</div>
61
+ </div>
62
+ </div>
63
+ </header>
64
+ ${toc}
65
+ <main>
66
+ ${options.mainHtml}
67
+ </main>
68
+ <footer>
69
+ <div class="footer-inner">
70
+ <span>GSD${version ? ` ${version}` : ""}</span>
71
+ <span class="sep">/</span>
72
+ <span>${esc(options.kind)}</span>
73
+ ${footerNote}
74
+ <span class="sep">/</span>
75
+ <span>${formatDateLong(options.generatedAt)}</span>
76
+ </div>
77
+ </footer>
78
+ <script>${HTML_SHELL_JS}</script>
79
+ </body>
80
+ </html>`;
81
+ }
82
+
83
+ export function renderHtmlShellTemplate(options: HtmlShellTemplateOptions): string {
84
+ return renderHtmlShell({
85
+ ...options,
86
+ generatedAt: options.generatedAtPlaceholder ?? "{{GENERATED_AT}}",
87
+ mainHtml: options.mainPlaceholder,
88
+ });
89
+ }
90
+
91
+ export function formatDateLong(iso: string): string {
92
+ if (/^\{\{[A-Z_]+\}\}$/.test(iso)) return iso;
93
+ try {
94
+ const d = new Date(iso);
95
+ return d.toLocaleString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' });
96
+ } catch { return iso; }
97
+ }
98
+
99
+ export function esc(s: string | undefined | null): string {
100
+ if (s == null) return '';
101
+ return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
102
+ }
103
+
104
+ export const HTML_SHELL_CSS = `
105
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
106
+ :root{
107
+ --bg-0:#0f1115;--bg-1:#16181d;--bg-2:#1e2028;--bg-3:#272a33;
108
+ --border-1:#2b2e38;--border-2:#3b3f4c;
109
+ --text-0:#ededef;--text-1:#a1a1aa;--text-2:#71717a;
110
+ --accent:#5e6ad2;--accent-subtle:rgba(94,106,210,.12);
111
+ --ok:#22c55e;--ok-subtle:rgba(34,197,94,.12);--warn:#ef4444;--caution:#eab308;
112
+ /* Chart palette - 6 hues for bar charts */
113
+ --c0:#5e6ad2;--c1:#e5796d;--c2:#14b8a6;--c3:#a78bfa;--c4:#f59e0b;--c5:#10b981;
114
+ /* Token breakdown - 4 distinct hues */
115
+ --tk-input:#5e6ad2;--tk-output:#e5796d;--tk-cache-r:#2dd4bf;--tk-cache-w:#64748b;
116
+ --font:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
117
+ --mono:'JetBrains Mono','Fira Code',ui-monospace,SFMono-Regular,monospace;
118
+ }
119
+ html{scroll-behavior:smooth;font-size:13px}
120
+ body{background:var(--bg-0);color:var(--text-0);font-family:var(--font);line-height:1.6;-webkit-font-smoothing:antialiased}
121
+ a{color:var(--accent);text-decoration:none}
122
+ a:hover{text-decoration:underline}
123
+ code{font-family:var(--mono);font-size:12px;background:var(--bg-3);padding:1px 5px;border-radius:3px}
124
+ .mono{font-family:var(--mono);font-size:12px}
125
+ .muted{color:var(--text-2)}
126
+ .accent{color:var(--accent)}
127
+ .sep{color:var(--border-2);margin:0 4px}
128
+ .empty{color:var(--text-2);padding:8px 0;font-size:13px}
129
+ .indent{padding-left:12px}
130
+ .num{font-variant-numeric:tabular-nums;text-align:right}
131
+ .dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0;vertical-align:middle}
132
+ .dot-sm{width:6px;height:6px}
133
+ .dot-complete{background:var(--ok);opacity:.6}
134
+ .dot-active{background:var(--accent)}
135
+ .dot-pending{background:transparent;border:1.5px solid var(--border-2)}
136
+ .dot-parked{background:var(--warn);opacity:.5}
137
+ header{background:var(--bg-1);border-bottom:1px solid var(--border-1);padding:12px 32px;position:sticky;top:0;z-index:200}
138
+ .header-inner{display:flex;align-items:center;gap:16px;max-width:1280px;margin:0 auto}
139
+ .branding{display:flex;align-items:baseline;gap:6px;flex-shrink:0}
140
+ .logo{font-size:18px;font-weight:800;letter-spacing:-.5px;color:var(--text-0)}
141
+ .version{font-size:10px;color:var(--text-2);font-family:var(--mono)}
142
+ .header-meta{flex:1;min-width:0}
143
+ .header-meta h1{font-size:15px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
144
+ .header-path{font-size:11px;color:var(--text-2);font-family:var(--mono);display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
145
+ .header-right{text-align:right;flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:4px}
146
+ .generated{font-size:11px;color:var(--text-2)}
147
+ .kind-chip{font-size:10px;font-weight:600;color:var(--accent);background:var(--accent-subtle);border:1px solid rgba(94,106,210,.25);border-radius:3px;padding:2px 7px;text-transform:uppercase;letter-spacing:.4px}
148
+ .back-link{font-size:12px;color:var(--text-1)}
149
+ .back-link:hover{color:var(--accent)}
150
+ .toc{background:var(--bg-1);border-bottom:1px solid var(--border-1);overflow-x:auto}
151
+ .toc ul{display:flex;list-style:none;max-width:1280px;margin:0 auto;padding:0 32px}
152
+ .toc a{display:inline-block;padding:8px 12px;color:var(--text-2);font-size:12px;font-weight:500;border-bottom:2px solid transparent;transition:color .12s,border-color .12s;white-space:nowrap;text-decoration:none}
153
+ .toc a:hover{color:var(--text-0);border-bottom-color:var(--border-2)}
154
+ .toc a.active{color:var(--text-0);border-bottom-color:var(--accent)}
155
+ main{max-width:1280px;margin:0 auto;padding:32px;display:flex;flex-direction:column;gap:48px}
156
+ section{scroll-margin-top:82px}
157
+ section>h2{font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--text-1);margin-bottom:16px;padding-bottom:8px;border-bottom:1px solid var(--border-1);display:flex;align-items:center;gap:8px}
158
+ h3{font-size:13px;font-weight:600;color:var(--text-1);margin:20px 0 8px}
159
+ .count{font-size:11px;font-weight:500;color:var(--text-2);background:var(--bg-3);border-radius:3px;padding:1px 6px}
160
+ .count-warn{color:var(--caution)}
161
+ .kv-grid{display:flex;flex-wrap:wrap;gap:1px;background:var(--border-1);border:1px solid var(--border-1);border-radius:4px;overflow:hidden;margin-bottom:16px}
162
+ .kv{background:var(--bg-1);padding:10px 16px;display:flex;flex-direction:column;gap:2px;min-width:110px;flex:1}
163
+ .kv-val{font-size:18px;font-weight:600;color:var(--text-0);font-variant-numeric:tabular-nums}
164
+ .kv-lbl{font-size:10px;color:var(--text-2);text-transform:uppercase;letter-spacing:.4px}
165
+ .progress-wrap{display:flex;align-items:center;gap:10px;margin-bottom:12px}
166
+ .progress-track{flex:1;height:4px;background:var(--bg-3);border-radius:2px;overflow:hidden}
167
+ .progress-fill{height:100%;background:var(--accent);border-radius:2px}
168
+ .progress-label{font-size:12px;font-weight:600;color:var(--text-1);min-width:40px;text-align:right}
169
+ .active-info{font-size:12px;color:var(--text-1);margin-bottom:4px}
170
+ .activity-line{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--text-1);padding:6px 0}
171
+ .tbl{width:100%;border-collapse:collapse;font-size:12px}
172
+ .tbl th{color:var(--text-2);font-weight:500;padding:6px 12px;text-align:left;border-bottom:1px solid var(--border-1);font-size:11px;text-transform:uppercase;letter-spacing:.3px;white-space:nowrap}
173
+ .tbl td{padding:6px 12px;border-bottom:1px solid var(--border-1);vertical-align:top}
174
+ .tbl tr:last-child td{border-bottom:none}
175
+ .tbl tbody tr:hover td{background:var(--accent-subtle)}
176
+ .tbl-kv td:first-child{color:var(--text-2);width:180px}
177
+ .table-scroll{overflow-x:auto;border:1px solid var(--border-1);border-radius:4px}
178
+ .table-scroll .tbl{border:none}
179
+ .h-ok td:first-child{color:var(--text-1)}
180
+ .h-caution td{color:var(--caution)}
181
+ .h-warn td{color:var(--warn)}
182
+ .label{font-size:10px;font-weight:500;color:var(--accent);text-transform:uppercase;letter-spacing:.4px}
183
+ .risk{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.3px;flex-shrink:0}
184
+ .risk-low{color:var(--text-2)}
185
+ .risk-medium{color:var(--caution)}
186
+ .risk-high{color:var(--warn)}
187
+ .risk-unknown{color:var(--text-2)}
188
+ .tag-row{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px}
189
+ .tag{font-size:11px;font-family:var(--mono);color:var(--text-2);background:var(--bg-3);border-radius:3px;padding:1px 6px}
190
+ .verif{font-size:12px;color:var(--text-1);padding:4px 0;margin-bottom:6px}
191
+ .verif-blocker{color:var(--warn)}
192
+ .detail-block{font-size:12px;color:var(--text-2);margin-bottom:6px}
193
+ .detail-label{font-weight:600;color:var(--text-1);display:block;margin-bottom:2px}
194
+ .detail-block ul{padding-left:16px;margin-top:2px}
195
+ .detail-block li{margin-bottom:1px}
196
+ .ms-block{border:1px solid var(--border-1);border-radius:4px;overflow:hidden;margin-bottom:8px}
197
+ .ms-summary{display:flex;align-items:center;gap:8px;padding:10px 14px;cursor:pointer;list-style:none;background:var(--bg-1);user-select:none;font-size:13px}
198
+ .ms-summary:hover{background:var(--bg-2)}
199
+ .ms-summary::-webkit-details-marker{display:none}
200
+ .ms-id{font-weight:600}
201
+ .ms-title{flex:1;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
202
+ .ms-body{padding:6px 12px 8px 24px;display:flex;flex-direction:column;gap:4px}
203
+ .sl-block{border:1px solid var(--border-1);border-radius:3px;overflow:hidden}
204
+ .sl-summary{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;list-style:none;background:var(--bg-2);font-size:12px;user-select:none}
205
+ .sl-summary:hover{background:var(--bg-3)}
206
+ .sl-summary::-webkit-details-marker{display:none}
207
+ .sl-crit{border-left:2px solid var(--accent)}
208
+ .sl-deps::before{content:'\\2190 ';color:var(--border-2)}
209
+ .sl-detail{padding:8px 12px;background:var(--bg-0);border-top:1px solid var(--border-1)}
210
+ .task-list{list-style:none;padding:4px 0 0;display:flex;flex-direction:column;gap:2px}
211
+ .task-row{display:flex;align-items:center;gap:6px;font-size:12px;padding:3px 6px;border-radius:2px}
212
+ .dep-block{margin-bottom:28px}
213
+ .dep-legend{display:flex;gap:14px;font-size:12px;color:var(--text-2);margin-bottom:8px;align-items:center}
214
+ .dep-legend span{display:flex;align-items:center;gap:4px}
215
+ .dep-wrap{overflow-x:auto;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:16px}
216
+ .dep-svg{display:block}
217
+ .edge{fill:none;stroke:var(--border-2);stroke-width:1.5}
218
+ .edge-crit{stroke:var(--accent);stroke-width:2}
219
+ .node rect{fill:var(--bg-2);stroke:var(--border-2);stroke-width:1}
220
+ .n-done rect{fill:var(--ok-subtle);stroke:rgba(34,197,94,.4)}
221
+ .n-active rect{fill:var(--accent-subtle);stroke:var(--accent)}
222
+ .n-crit rect{stroke:var(--accent)!important;stroke-width:1.5!important}
223
+ .n-id{font-family:var(--mono);font-size:10px;fill:var(--text-1);font-weight:600;text-anchor:middle}
224
+ .n-title{font-size:9px;fill:var(--text-2);text-anchor:middle}
225
+ .n-active .n-id{fill:var(--accent)}
226
+ .token-block{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px;margin-bottom:16px}
227
+ .token-bar{display:flex;height:16px;border-radius:2px;overflow:hidden;gap:1px;margin-bottom:8px}
228
+ .tseg{height:100%;min-width:2px}
229
+ .seg-1{background:var(--tk-input)}
230
+ .seg-2{background:var(--tk-output)}
231
+ .seg-3{background:var(--tk-cache-r)}
232
+ .seg-4{background:var(--tk-cache-w)}
233
+ .token-legend{display:flex;flex-wrap:wrap;gap:12px}
234
+ .leg-item{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-2)}
235
+ .leg-dot{width:8px;height:8px;border-radius:2px;flex-shrink:0}
236
+ .chart-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px;margin-bottom:16px}
237
+ .chart-block{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px}
238
+ .bar-row{display:grid;grid-template-columns:120px 1fr 68px;align-items:center;gap:6px;margin-bottom:2px}
239
+ .bar-lbl{font-size:12px;color:var(--text-2);text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
240
+ .bar-track{height:14px;background:var(--bg-3);border-radius:2px;overflow:hidden}
241
+ .bar-fill{height:100%;border-radius:2px;background:var(--c0)}
242
+ .bar-c0{background:var(--c0)}.bar-c1{background:var(--c1)}.bar-c2{background:var(--c2)}
243
+ .bar-c3{background:var(--c3)}.bar-c4{background:var(--c4)}.bar-c5{background:var(--c5)}
244
+ .bar-val{font-size:11px;font-variant-numeric:tabular-nums;color:var(--text-1)}
245
+ .bar-sub{font-size:10px;color:var(--text-2);padding-left:128px;margin-bottom:6px}
246
+ .cl-entry{border-bottom:1px solid var(--border-1);padding:12px 0}
247
+ .cl-entry:last-child{border-bottom:none}
248
+ .cl-header{display:flex;align-items:center;gap:8px;margin-bottom:4px}
249
+ .cl-title{flex:1;font-weight:500}
250
+ .cl-date{margin-left:auto;white-space:nowrap}
251
+ .cl-liner{font-size:13px;color:var(--text-1);margin-bottom:6px}
252
+ .files-detail summary{font-size:12px;cursor:pointer}
253
+ .file-list{list-style:none;padding-left:10px;margin-top:4px;display:flex;flex-direction:column;gap:2px}
254
+ .file-list li{font-size:12px;color:var(--text-1)}
255
+ footer{border-top:1px solid var(--border-1);padding:20px 32px;margin-top:40px}
256
+ .footer-inner{display:flex;align-items:center;gap:6px;justify-content:center;font-size:11px;color:var(--text-2);flex-wrap:wrap}
257
+ .exec-summary{font-size:13px;color:var(--text-1);margin-bottom:12px;line-height:1.7}
258
+ .eta-line{font-size:12px;color:var(--accent);margin-top:4px}
259
+ .cost-svg{display:block;margin:8px 0;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px}
260
+ .cost-line{fill:none;stroke:var(--accent);stroke-width:2}
261
+ .cost-area{fill:var(--accent-subtle);stroke:none}
262
+ .cost-axis{fill:var(--text-2);font-family:var(--mono);font-size:10px}
263
+ .cost-grid{stroke:var(--border-1);stroke-width:1;stroke-dasharray:4,4}
264
+ .burndown-wrap{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px;margin-bottom:16px}
265
+ .burndown-bar{display:flex;height:20px;border-radius:3px;overflow:hidden;gap:1px;margin-bottom:8px}
266
+ .burndown-spent{background:var(--accent);height:100%}
267
+ .burndown-projected{background:var(--caution);height:100%;opacity:.6}
268
+ .burndown-overshoot{background:var(--warn);height:100%;opacity:.7}
269
+ .burndown-legend{display:flex;flex-wrap:wrap;gap:12px;font-size:11px;color:var(--text-2)}
270
+ .burndown-legend span{display:flex;align-items:center;gap:4px}
271
+ .burndown-dot{display:inline-block;width:8px;height:8px;border-radius:2px}
272
+ .blocker-card{border-left:3px solid var(--warn);background:var(--bg-1);border-radius:0 4px 4px 0;padding:10px 14px;margin-bottom:8px}
273
+ .blocker-id{font-family:var(--mono);font-size:12px;color:var(--warn);margin-bottom:2px}
274
+ .blocker-text{font-size:12px;color:var(--text-1)}
275
+ .blocker-risk{font-size:11px;color:var(--caution);margin-top:2px}
276
+ .gantt-wrap{overflow-x:auto;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:16px;margin-top:16px}
277
+ .gantt-svg{display:block}
278
+ .gantt-bar-done{fill:var(--ok);opacity:.7}
279
+ .gantt-bar-active{fill:var(--accent)}
280
+ .gantt-bar-pending{fill:var(--border-2)}
281
+ .gantt-label{fill:var(--text-2);font-family:var(--mono);font-size:10px}
282
+ .gantt-axis{fill:var(--text-2);font-family:var(--mono);font-size:9px}
283
+ .tl-filter{display:block;width:100%;padding:6px 10px;margin-bottom:8px;background:var(--bg-2);border:1px solid var(--border-1);border-radius:4px;color:var(--text-0);font-size:12px;font-family:var(--font);outline:none}
284
+ .tl-filter:focus{border-color:var(--accent)}
285
+ .tl-filter::placeholder{color:var(--text-2)}
286
+ .sec-toggle{background:none;border:1px solid var(--border-2);color:var(--text-2);width:20px;height:20px;border-radius:3px;cursor:pointer;font-size:14px;line-height:1;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
287
+ .sec-toggle:hover{border-color:var(--text-1);color:var(--text-1)}
288
+ .theme-toggle{background:var(--bg-3);border:1px solid var(--border-2);color:var(--text-1);padding:4px 10px;border-radius:4px;cursor:pointer;font-size:11px;font-family:var(--font)}
289
+ .theme-toggle:hover{border-color:var(--accent);color:var(--accent)}
290
+ .callout-info,.callout-warn,.callout-ok{border-left:3px solid var(--accent);background:var(--bg-1);border-radius:0 4px 4px 0;padding:10px 14px}
291
+ .callout-warn{border-left-color:var(--caution)}
292
+ .callout-ok{border-left-color:var(--ok)}
293
+ .card-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
294
+ .card{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px}
295
+ .light-theme{--bg-0:#fff;--bg-1:#fafafa;--bg-2:#f5f5f5;--bg-3:#ebebeb;--border-1:#e5e5e5;--border-2:#d4d4d4;--text-0:#1a1a1a;--text-1:#525252;--text-2:#a3a3a3;--accent:#4f46e5;--accent-subtle:rgba(79,70,229,.08);--ok:#16a34a;--ok-subtle:rgba(22,163,74,.08);--warn:#dc2626;--caution:#ca8a04;--c0:#4f46e5;--c1:#dc2626;--c2:#0d9488;--c3:#7c3aed;--c4:#d97706;--c5:#059669;--tk-input:#4f46e5;--tk-output:#dc2626;--tk-cache-r:#0d9488;--tk-cache-w:#64748b}
296
+ @media(max-width:768px){
297
+ header{padding:10px 16px}
298
+ .header-inner{flex-wrap:wrap;gap:8px}
299
+ .header-meta h1{font-size:13px}
300
+ main{padding:16px}
301
+ .kv-grid{gap:1px}
302
+ .kv{min-width:80px;padding:8px 10px}
303
+ .kv-val{font-size:14px}
304
+ .chart-row{grid-template-columns:1fr}
305
+ .toc ul{padding:0 16px}
306
+ .toc a{padding:6px 8px;font-size:11px}
307
+ .bar-row{grid-template-columns:80px 1fr 56px}
308
+ .ms-body{padding-left:12px}
309
+ }
310
+ @media(max-width:480px){
311
+ .kv{min-width:60px;padding:6px 8px}
312
+ .kv-val{font-size:12px}
313
+ .kv-lbl{font-size:9px}
314
+ .bar-row{grid-template-columns:60px 1fr 48px}
315
+ .bar-lbl{font-size:10px}
316
+ .toc ul{flex-wrap:wrap}
317
+ .header-right{display:none}
318
+ .gantt-wrap{overflow-x:auto}
319
+ }
320
+ @media print{
321
+ header,nav.toc{position:static}
322
+ body{background:#fff;color:#1a1a1a}
323
+ :root{--bg-0:#fff;--bg-1:#fafafa;--bg-2:#f5f5f5;--bg-3:#ebebeb;--border-1:#e5e5e5;--border-2:#d4d4d4;--text-0:#1a1a1a;--text-1:#525252;--text-2:#a3a3a3;--accent:#4f46e5;--ok:#16a34a;--ok-subtle:rgba(22,163,74,.08);--c0:#4f46e5;--c1:#dc2626;--c2:#0d9488;--c3:#7c3aed;--c4:#d97706;--c5:#059669;--tk-input:#4f46e5;--tk-output:#dc2626;--tk-cache-r:#0d9488;--tk-cache-w:#64748b}
324
+ section{page-break-inside:avoid}
325
+ .table-scroll{overflow:visible}
326
+ }
327
+ `;
328
+
329
+ export const HTML_SHELL_JS = `
330
+ (function(){
331
+ const sections=document.querySelectorAll('section[id]');
332
+ const links=document.querySelectorAll('.toc a');
333
+ if(!sections.length||!links.length)return;
334
+ const obs=new IntersectionObserver(entries=>{
335
+ for(const e of entries){
336
+ if(!e.isIntersecting)continue;
337
+ for(const l of links)l.classList.remove('active');
338
+ const a=document.querySelector('.toc a[href="#'+e.target.id+'"]');
339
+ if(a)a.classList.add('active');
340
+ }
341
+ },{rootMargin:'-10% 0px -80% 0px',threshold:0});
342
+ for(const s of sections)obs.observe(s);
343
+ })();
344
+ (function(){
345
+ var tl=document.getElementById('timeline');
346
+ if(!tl)return;
347
+ var table=tl.querySelector('.tbl');
348
+ if(!table)return;
349
+ var input=document.createElement('input');
350
+ input.className='tl-filter';
351
+ input.placeholder='Filter timeline\\u2026';
352
+ input.type='text';
353
+ table.parentNode.insertBefore(input,table);
354
+ var rows=table.querySelectorAll('tbody tr');
355
+ input.addEventListener('input',function(){
356
+ var q=this.value.toLowerCase();
357
+ for(var i=0;i<rows.length;i++){
358
+ rows[i].style.display=rows[i].textContent.toLowerCase().indexOf(q)>-1?'':'none';
359
+ }
360
+ });
361
+ })();
362
+ function safeLocalStorageSet(key,value){
363
+ try{localStorage.setItem(key,value)}catch(e){}
364
+ }
365
+ function safeLocalStorageGet(key){
366
+ try{return localStorage.getItem(key)}catch(e){return null}
367
+ }
368
+ (function(){
369
+ var saved={};
370
+ try{saved=JSON.parse(safeLocalStorageGet('gsd-collapsed')||'{}')}catch(e){}
371
+ document.querySelectorAll('section[id]').forEach(function(sec){
372
+ var h2=sec.querySelector('h2');
373
+ if(!h2)return;
374
+ var btn=document.createElement('button');
375
+ btn.className='sec-toggle';
376
+ btn.textContent=saved[sec.id]?'+':'-';
377
+ btn.setAttribute('aria-label','Toggle section');
378
+ h2.prepend(btn);
379
+ if(saved[sec.id])toggleSection(sec,true);
380
+ btn.addEventListener('click',function(e){
381
+ e.preventDefault();
382
+ var collapsed=btn.textContent==='-';
383
+ toggleSection(sec,collapsed);
384
+ btn.textContent=collapsed?'+':'-';
385
+ saved[sec.id]=collapsed;
386
+ safeLocalStorageSet('gsd-collapsed',JSON.stringify(saved));
387
+ });
388
+ });
389
+ function toggleSection(sec,hide){
390
+ var children=sec.children;
391
+ for(var i=0;i<children.length;i++){
392
+ if(children[i].tagName!=='H2')children[i].style.display=hide?'none':'';
393
+ }
394
+ }
395
+ })();
396
+ (function(){
397
+ var hr=document.querySelector('.header-right');
398
+ if(!hr)return;
399
+ var stored=safeLocalStorageGet('gsd-theme');
400
+ var btn=document.createElement('button');
401
+ btn.className='theme-toggle';
402
+ btn.textContent=stored==='light'?'Dark':'Light';
403
+ if(stored==='light')document.documentElement.classList.add('light-theme');
404
+ btn.addEventListener('click',function(){
405
+ document.documentElement.classList.toggle('light-theme');
406
+ var isLight=document.documentElement.classList.contains('light-theme');
407
+ btn.textContent=isLight?'Dark':'Light';
408
+ safeLocalStorageSet('gsd-theme',isLight?'light':'dark');
409
+ });
410
+ hr.prepend(btn);
411
+ })();
412
+ `;
@@ -126,6 +126,8 @@ export function getVisualBriefModeProfile(mode: VisualBriefMode, slides: boolean
126
126
  "Assumptions, limitations, and source references",
127
127
  ],
128
128
  };
129
+ default:
130
+ throw new Error(`Unknown visual brief mode: ${mode as string}`);
129
131
  }
130
132
  }
131
133