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
@@ -3,7 +3,7 @@
3
3
  // Discovery order (D003): preference → task plan verify → package.json scripts.
4
4
  // First non-empty source wins.
5
5
  import { spawnSync } from "node:child_process";
6
- import { existsSync, readFileSync } from "node:fs";
6
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
7
7
  import { join, basename } from "node:path";
8
8
  import { DEFAULT_COMMAND_TIMEOUT_MS } from "./constants.js";
9
9
  import { rewriteCommandWithRtk } from "../shared/rtk.js";
@@ -27,7 +27,8 @@ const PACKAGE_SCRIPT_KEYS = ["typecheck", "lint", "test"];
27
27
  * 1. Explicit preference commands
28
28
  * 2. Task plan verify field (split on &&)
29
29
  * 3. package.json scripts (typecheck, lint, test)
30
- * 4. None found
30
+ * 4. Python pytest project markers
31
+ * 5. None found
31
32
  */
32
33
  export function discoverCommands(options) {
33
34
  // 1. Preference commands
@@ -72,9 +73,57 @@ export function discoverCommands(options) {
72
73
  // Malformed package.json — fall through to "none"
73
74
  }
74
75
  }
75
- // 4. Nothing found
76
+ const pythonCommand = discoverPythonPytestCommand(options.cwd);
77
+ if (pythonCommand) {
78
+ return { commands: [pythonCommand], source: "python-project" };
79
+ }
80
+ // 5. Nothing found
76
81
  return { commands: [], source: "none" };
77
82
  }
83
+ function discoverPythonPytestCommand(cwd) {
84
+ const hasPythonTestFiles = hasPythonTests(join(cwd, "tests"));
85
+ const hasPytestConfig = existsSync(join(cwd, "pytest.ini"));
86
+ const pyprojectPath = join(cwd, "pyproject.toml");
87
+ const hasPyproject = existsSync(pyprojectPath);
88
+ if (!hasPythonTestFiles && !hasPytestConfig && !hasPyproject) {
89
+ return null;
90
+ }
91
+ if (hasPytestConfig || hasPythonTestFiles) {
92
+ return "python3 -m pytest";
93
+ }
94
+ try {
95
+ const pyproject = readFileSync(pyprojectPath, "utf-8");
96
+ if (pyproject.includes("[tool.pytest]") ||
97
+ pyproject.includes("[tool.pytest.") ||
98
+ pyproject.includes("[pytest]") ||
99
+ pyproject.includes("[tool:pytest]")) {
100
+ return "python3 -m pytest";
101
+ }
102
+ }
103
+ catch {
104
+ // Ignore unreadable pyproject.toml and fall through.
105
+ }
106
+ return null;
107
+ }
108
+ function hasPythonTests(dir) {
109
+ let entries;
110
+ try {
111
+ entries = readdirSync(dir, { withFileTypes: true });
112
+ }
113
+ catch {
114
+ return false;
115
+ }
116
+ for (const entry of entries) {
117
+ const path = join(dir, entry.name);
118
+ if (entry.isDirectory() && hasPythonTests(path)) {
119
+ return true;
120
+ }
121
+ if (entry.isFile() && /^test_.*\.py$|^.*_test\.py$/.test(entry.name)) {
122
+ return true;
123
+ }
124
+ }
125
+ return false;
126
+ }
78
127
  // ─── Failure Context Formatting ──────────────────────────────────────────────
79
128
  /** Maximum chars of stderr to include per failed check in failure context. */
80
129
  const MAX_STDERR_PER_CHECK = 2_000;
@@ -112,7 +161,7 @@ export function formatFailureContext(result) {
112
161
  }
113
162
  // ─── Gate Execution ─────────────────────────────────────────────────────────
114
163
  /** Characters that indicate shell injection when found in a command string. */
115
- const SHELL_INJECTION_PATTERN = /[;|`]|\$\(/;
164
+ const SHELL_INJECTION_PATTERN = /[;|`<>]|\$\(/;
116
165
  /**
117
166
  * Known executable first-tokens that are safe to run.
118
167
  * Lowercase commands, common build/test tools, and npm/yarn/pnpm invocations.
@@ -148,6 +197,7 @@ const KNOWN_COMMAND_PREFIXES = new Set([
148
197
  * Heuristics (any true → prose-like):
149
198
  * 1. First token starts with an uppercase letter and the string has 4+ words
150
199
  * 2. String contains commas followed by spaces (prose clause structure)
200
+ * 3. First token has no ASCII letters or digits and the string has 4+ words
151
201
  */
152
202
  export function isLikelyCommand(cmd) {
153
203
  const trimmed = cmd.trim();
@@ -173,16 +223,27 @@ export function isLikelyCommand(cmd) {
173
223
  // First token has uppercase letters and no path separators → prose
174
224
  if (/[A-Z]/.test(firstToken) && !firstToken.includes("/"))
175
225
  return false;
226
+ // Non-ASCII prose with multiple words should not be executed as a command.
227
+ if (!/[A-Za-z0-9]/.test(firstToken) && tokens.length >= 4)
228
+ return false;
176
229
  return true;
177
230
  }
178
231
  /**
179
232
  * Validate a command string for obvious shell injection patterns.
180
233
  * Returns the command unchanged if safe, or null if suspicious.
181
234
  */
235
+ export function validateVerificationCommand(cmd) {
236
+ if (SHELL_INJECTION_PATTERN.test(cmd)) {
237
+ return { ok: false, reason: "contains shell control syntax such as pipes, redirects, semicolons, backticks, or command substitution" };
238
+ }
239
+ if (!isLikelyCommand(cmd)) {
240
+ return { ok: false, reason: "does not look like a runnable command" };
241
+ }
242
+ return { ok: true };
243
+ }
182
244
  function sanitizeCommand(cmd) {
183
- if (SHELL_INJECTION_PATTERN.test(cmd))
184
- return null;
185
- if (!isLikelyCommand(cmd))
245
+ const validation = validateVerificationCommand(cmd);
246
+ if (!validation.ok)
186
247
  return null;
187
248
  return cmd;
188
249
  }
@@ -150,11 +150,11 @@ export function renderSummaryContent(taskRow, sliceId, milestoneId, evidence) {
150
150
  }
151
151
  // ── Frontmatter (YAML list format, matches parseSummary() expectations) ──
152
152
  const keyFilesYaml = taskRow.key_files && taskRow.key_files.length > 0
153
- ? taskRow.key_files.map(f => ` - ${f}`).join("\n")
154
- : " - (none)";
153
+ ? `\n${taskRow.key_files.map(f => ` - ${f}`).join("\n")}`
154
+ : " []";
155
155
  const keyDecisionsYaml = taskRow.key_decisions && taskRow.key_decisions.length > 0
156
- ? taskRow.key_decisions.map(d => ` - ${d}`).join("\n")
157
- : " - (none)";
156
+ ? `\n${taskRow.key_decisions.map(d => ` - ${d}`).join("\n")}`
157
+ : " []";
158
158
  // Derive verification_result from evidence if available
159
159
  const evidenceList = evidence ?? [];
160
160
  const allPassed = evidenceList.length > 0 &&
@@ -182,10 +182,8 @@ export function renderSummaryContent(taskRow, sliceId, milestoneId, evidence) {
182
182
  id: ${taskRow.id}
183
183
  parent: ${sliceId}
184
184
  milestone: ${milestoneId}
185
- key_files:
186
- ${keyFilesYaml}
187
- key_decisions:
188
- ${keyDecisionsYaml}
185
+ key_files:${keyFilesYaml}
186
+ key_decisions:${keyDecisionsYaml}
189
187
  duration: ${taskRow.duration || ""}
190
188
  verification_result: ${verificationResult}
191
189
  completed_at: ${taskRow.completed_at || ""}
@@ -20,6 +20,7 @@ import { existsSync, readFileSync, unlinkSync } from "node:fs";
20
20
  import { randomUUID } from "node:crypto";
21
21
  import { join } from "node:path";
22
22
  import { debugLog } from "./debug-logger.js";
23
+ import { logWarning } from "./workflow-logger.js";
23
24
  import { emitJournalEvent } from "./journal.js";
24
25
  import { emitWorktreeCreated, emitWorktreeMerged } from "./worktree-telemetry.js";
25
26
  import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare, } from "./worktree-root.js";
@@ -48,6 +49,11 @@ import { nativeCheckoutBranch } from "./native-git-bridge.js";
48
49
  // is the only Module that calls them, and they live alongside the Module's
49
50
  // other primitives in `auto-worktree.ts`.
50
51
  import { autoWorktreeBranch, createAutoWorktree, enterAutoWorktree, enterBranchModeForMilestone, getAutoWorktreePath, isInAutoWorktree, teardownAutoWorktree, } from "./auto-worktree.js";
52
+ const recentWorktreeMergeFailures = new Map();
53
+ const MERGE_FAILURE_DEDUPE_MS = 60_000;
54
+ export function resetRecentWorktreeMergeFailuresForTest() {
55
+ recentWorktreeMergeFailures.clear();
56
+ }
51
57
  /**
52
58
  * Internal sentinel — thrown by `_mergeBranchMode` when it has already
53
59
  * emitted a user-visible error. The outer `mergeAndExit` catches the type
@@ -208,7 +214,7 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
208
214
  }
209
215
  // Phase B: claim a milestone lease before any worktree mutation. Two
210
216
  // workers cannot enter the same milestone concurrently. Best-effort:
211
- // skip if no worker registered (single-worker fallback) or DB
217
+ // warn if no worker registered (single-worker fallback) or skip if DB
212
218
  // unavailable; reuse existing lease if we already hold it on this
213
219
  // milestone (re-entry within the same session).
214
220
  if (s.workerId) {
@@ -288,6 +294,9 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
288
294
  }
289
295
  }
290
296
  }
297
+ else {
298
+ logWarning("worktree", `enterMilestone(${milestoneId}) ran before auto worker registration; milestone lease was not claimed.`);
299
+ }
291
300
  // Resolve the project root for worktree operations via shared helper.
292
301
  // Handles the case where originalBasePath is falsy and basePath is itself
293
302
  // a worktree path — prevents double-nested worktree paths (#3729).
@@ -477,6 +486,28 @@ function rebuildGitService(s, deps) {
477
486
  // GitService cast.
478
487
  s.gitService = deps.gitServiceFactory(s.basePath);
479
488
  }
489
+ function emitWorktreeMergeFailedOnce(basePath, milestoneId, err) {
490
+ const msg = err instanceof Error ? err.message : String(err);
491
+ const errorCategory = err instanceof Error ? err.name : "Error";
492
+ const now = Date.now();
493
+ const key = `${basePath}\0${milestoneId}\0${errorCategory}`;
494
+ const previous = recentWorktreeMergeFailures.get(key);
495
+ if (previous && now - previous < MERGE_FAILURE_DEDUPE_MS)
496
+ return;
497
+ for (const [candidate, ts] of recentWorktreeMergeFailures) {
498
+ if (now - ts >= MERGE_FAILURE_DEDUPE_MS) {
499
+ recentWorktreeMergeFailures.delete(candidate);
500
+ }
501
+ }
502
+ emitJournalEvent(basePath, {
503
+ ts: new Date().toISOString(),
504
+ flowId: randomUUID(),
505
+ seq: 0,
506
+ eventType: "worktree-merge-failed",
507
+ data: { milestoneId, error: msg },
508
+ });
509
+ recentWorktreeMergeFailures.set(key, now);
510
+ }
480
511
  // ─── Session-less merge entry (ADR-016 phase 2 / A1) ─────────────────────
481
512
  /**
482
513
  * Worktree-mode merge body. Session-less — operates on a `MergeContext`.
@@ -590,13 +621,7 @@ function _mergeWorktreeModeImpl(deps, mctx) {
590
621
  error: msg,
591
622
  fallback: "chdir-to-project-root",
592
623
  });
593
- emitJournalEvent(originalBasePath || worktreeBasePath, {
594
- ts: new Date().toISOString(),
595
- flowId: randomUUID(),
596
- seq: 0,
597
- eventType: "worktree-merge-failed",
598
- data: { milestoneId, error: msg },
599
- });
624
+ emitWorktreeMergeFailedOnce(originalBasePath || worktreeBasePath, milestoneId, err);
600
625
  // Surface a clear, actionable error. Worktree and milestone branch
601
626
  // are intentionally preserved — nothing has been deleted. User can
602
627
  // retry /gsd dispatch complete-milestone or merge manually once the
@@ -0,0 +1,388 @@
1
+ export function renderHtmlShell(options) {
2
+ const version = options.version ? `v${esc(options.version)}` : "";
3
+ const documentTitle = options.documentTitle ?? `${options.kind} - ${options.title}`;
4
+ const subtitle = options.subtitle ? `<span class="header-path">${esc(options.subtitle)}</span>` : "";
5
+ const toc = options.toc?.length
6
+ ? `<nav class="toc" aria-label="Report sections">
7
+ <ul>
8
+ ${options.toc.map((item) => ` <li><a href="${esc(item.href)}">${esc(item.label)}</a></li>`).join("\n")}
9
+ </ul>
10
+ </nav>`
11
+ : "";
12
+ const actions = options.headerActionsHtml ? `${options.headerActionsHtml}` : "";
13
+ const footerNote = options.footerNote ? `<span class="sep">/</span>\n <span>${esc(options.footerNote)}</span>` : "";
14
+ return `<!DOCTYPE html>
15
+ <html lang="en">
16
+ <head>
17
+ <meta charset="UTF-8">
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ <title>${esc(documentTitle)}</title>
20
+ <style>${HTML_SHELL_CSS}</style>
21
+ </head>
22
+ <body>
23
+ <header>
24
+ <div class="header-inner">
25
+ <div class="branding">
26
+ <span class="logo">GSD</span>
27
+ ${version ? `<span class="version">${version}</span>` : ""}
28
+ </div>
29
+ <div class="header-meta">
30
+ <h1>${esc(options.title)}</h1>
31
+ ${subtitle}
32
+ </div>
33
+ <div class="header-right">
34
+ ${actions}
35
+ <span class="kind-chip">${esc(options.kind)}</span>
36
+ <div class="generated">${formatDateLong(options.generatedAt)}</div>
37
+ </div>
38
+ </div>
39
+ </header>
40
+ ${toc}
41
+ <main>
42
+ ${options.mainHtml}
43
+ </main>
44
+ <footer>
45
+ <div class="footer-inner">
46
+ <span>GSD${version ? ` ${version}` : ""}</span>
47
+ <span class="sep">/</span>
48
+ <span>${esc(options.kind)}</span>
49
+ ${footerNote}
50
+ <span class="sep">/</span>
51
+ <span>${formatDateLong(options.generatedAt)}</span>
52
+ </div>
53
+ </footer>
54
+ <script>${HTML_SHELL_JS}</script>
55
+ </body>
56
+ </html>`;
57
+ }
58
+ export function renderHtmlShellTemplate(options) {
59
+ return renderHtmlShell({
60
+ ...options,
61
+ generatedAt: options.generatedAtPlaceholder ?? "{{GENERATED_AT}}",
62
+ mainHtml: options.mainPlaceholder,
63
+ });
64
+ }
65
+ export function formatDateLong(iso) {
66
+ if (/^\{\{[A-Z_]+\}\}$/.test(iso))
67
+ return iso;
68
+ try {
69
+ const d = new Date(iso);
70
+ return d.toLocaleString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' });
71
+ }
72
+ catch {
73
+ return iso;
74
+ }
75
+ }
76
+ export function esc(s) {
77
+ if (s == null)
78
+ return '';
79
+ return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
80
+ }
81
+ export const HTML_SHELL_CSS = `
82
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
83
+ :root{
84
+ --bg-0:#0f1115;--bg-1:#16181d;--bg-2:#1e2028;--bg-3:#272a33;
85
+ --border-1:#2b2e38;--border-2:#3b3f4c;
86
+ --text-0:#ededef;--text-1:#a1a1aa;--text-2:#71717a;
87
+ --accent:#5e6ad2;--accent-subtle:rgba(94,106,210,.12);
88
+ --ok:#22c55e;--ok-subtle:rgba(34,197,94,.12);--warn:#ef4444;--caution:#eab308;
89
+ /* Chart palette - 6 hues for bar charts */
90
+ --c0:#5e6ad2;--c1:#e5796d;--c2:#14b8a6;--c3:#a78bfa;--c4:#f59e0b;--c5:#10b981;
91
+ /* Token breakdown - 4 distinct hues */
92
+ --tk-input:#5e6ad2;--tk-output:#e5796d;--tk-cache-r:#2dd4bf;--tk-cache-w:#64748b;
93
+ --font:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
94
+ --mono:'JetBrains Mono','Fira Code',ui-monospace,SFMono-Regular,monospace;
95
+ }
96
+ html{scroll-behavior:smooth;font-size:13px}
97
+ body{background:var(--bg-0);color:var(--text-0);font-family:var(--font);line-height:1.6;-webkit-font-smoothing:antialiased}
98
+ a{color:var(--accent);text-decoration:none}
99
+ a:hover{text-decoration:underline}
100
+ code{font-family:var(--mono);font-size:12px;background:var(--bg-3);padding:1px 5px;border-radius:3px}
101
+ .mono{font-family:var(--mono);font-size:12px}
102
+ .muted{color:var(--text-2)}
103
+ .accent{color:var(--accent)}
104
+ .sep{color:var(--border-2);margin:0 4px}
105
+ .empty{color:var(--text-2);padding:8px 0;font-size:13px}
106
+ .indent{padding-left:12px}
107
+ .num{font-variant-numeric:tabular-nums;text-align:right}
108
+ .dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0;vertical-align:middle}
109
+ .dot-sm{width:6px;height:6px}
110
+ .dot-complete{background:var(--ok);opacity:.6}
111
+ .dot-active{background:var(--accent)}
112
+ .dot-pending{background:transparent;border:1.5px solid var(--border-2)}
113
+ .dot-parked{background:var(--warn);opacity:.5}
114
+ header{background:var(--bg-1);border-bottom:1px solid var(--border-1);padding:12px 32px;position:sticky;top:0;z-index:200}
115
+ .header-inner{display:flex;align-items:center;gap:16px;max-width:1280px;margin:0 auto}
116
+ .branding{display:flex;align-items:baseline;gap:6px;flex-shrink:0}
117
+ .logo{font-size:18px;font-weight:800;letter-spacing:-.5px;color:var(--text-0)}
118
+ .version{font-size:10px;color:var(--text-2);font-family:var(--mono)}
119
+ .header-meta{flex:1;min-width:0}
120
+ .header-meta h1{font-size:15px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
121
+ .header-path{font-size:11px;color:var(--text-2);font-family:var(--mono);display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
122
+ .header-right{text-align:right;flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:4px}
123
+ .generated{font-size:11px;color:var(--text-2)}
124
+ .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}
125
+ .back-link{font-size:12px;color:var(--text-1)}
126
+ .back-link:hover{color:var(--accent)}
127
+ .toc{background:var(--bg-1);border-bottom:1px solid var(--border-1);overflow-x:auto}
128
+ .toc ul{display:flex;list-style:none;max-width:1280px;margin:0 auto;padding:0 32px}
129
+ .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}
130
+ .toc a:hover{color:var(--text-0);border-bottom-color:var(--border-2)}
131
+ .toc a.active{color:var(--text-0);border-bottom-color:var(--accent)}
132
+ main{max-width:1280px;margin:0 auto;padding:32px;display:flex;flex-direction:column;gap:48px}
133
+ section{scroll-margin-top:82px}
134
+ 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}
135
+ h3{font-size:13px;font-weight:600;color:var(--text-1);margin:20px 0 8px}
136
+ .count{font-size:11px;font-weight:500;color:var(--text-2);background:var(--bg-3);border-radius:3px;padding:1px 6px}
137
+ .count-warn{color:var(--caution)}
138
+ .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}
139
+ .kv{background:var(--bg-1);padding:10px 16px;display:flex;flex-direction:column;gap:2px;min-width:110px;flex:1}
140
+ .kv-val{font-size:18px;font-weight:600;color:var(--text-0);font-variant-numeric:tabular-nums}
141
+ .kv-lbl{font-size:10px;color:var(--text-2);text-transform:uppercase;letter-spacing:.4px}
142
+ .progress-wrap{display:flex;align-items:center;gap:10px;margin-bottom:12px}
143
+ .progress-track{flex:1;height:4px;background:var(--bg-3);border-radius:2px;overflow:hidden}
144
+ .progress-fill{height:100%;background:var(--accent);border-radius:2px}
145
+ .progress-label{font-size:12px;font-weight:600;color:var(--text-1);min-width:40px;text-align:right}
146
+ .active-info{font-size:12px;color:var(--text-1);margin-bottom:4px}
147
+ .activity-line{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--text-1);padding:6px 0}
148
+ .tbl{width:100%;border-collapse:collapse;font-size:12px}
149
+ .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}
150
+ .tbl td{padding:6px 12px;border-bottom:1px solid var(--border-1);vertical-align:top}
151
+ .tbl tr:last-child td{border-bottom:none}
152
+ .tbl tbody tr:hover td{background:var(--accent-subtle)}
153
+ .tbl-kv td:first-child{color:var(--text-2);width:180px}
154
+ .table-scroll{overflow-x:auto;border:1px solid var(--border-1);border-radius:4px}
155
+ .table-scroll .tbl{border:none}
156
+ .h-ok td:first-child{color:var(--text-1)}
157
+ .h-caution td{color:var(--caution)}
158
+ .h-warn td{color:var(--warn)}
159
+ .label{font-size:10px;font-weight:500;color:var(--accent);text-transform:uppercase;letter-spacing:.4px}
160
+ .risk{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.3px;flex-shrink:0}
161
+ .risk-low{color:var(--text-2)}
162
+ .risk-medium{color:var(--caution)}
163
+ .risk-high{color:var(--warn)}
164
+ .risk-unknown{color:var(--text-2)}
165
+ .tag-row{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px}
166
+ .tag{font-size:11px;font-family:var(--mono);color:var(--text-2);background:var(--bg-3);border-radius:3px;padding:1px 6px}
167
+ .verif{font-size:12px;color:var(--text-1);padding:4px 0;margin-bottom:6px}
168
+ .verif-blocker{color:var(--warn)}
169
+ .detail-block{font-size:12px;color:var(--text-2);margin-bottom:6px}
170
+ .detail-label{font-weight:600;color:var(--text-1);display:block;margin-bottom:2px}
171
+ .detail-block ul{padding-left:16px;margin-top:2px}
172
+ .detail-block li{margin-bottom:1px}
173
+ .ms-block{border:1px solid var(--border-1);border-radius:4px;overflow:hidden;margin-bottom:8px}
174
+ .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}
175
+ .ms-summary:hover{background:var(--bg-2)}
176
+ .ms-summary::-webkit-details-marker{display:none}
177
+ .ms-id{font-weight:600}
178
+ .ms-title{flex:1;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
179
+ .ms-body{padding:6px 12px 8px 24px;display:flex;flex-direction:column;gap:4px}
180
+ .sl-block{border:1px solid var(--border-1);border-radius:3px;overflow:hidden}
181
+ .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}
182
+ .sl-summary:hover{background:var(--bg-3)}
183
+ .sl-summary::-webkit-details-marker{display:none}
184
+ .sl-crit{border-left:2px solid var(--accent)}
185
+ .sl-deps::before{content:'\\2190 ';color:var(--border-2)}
186
+ .sl-detail{padding:8px 12px;background:var(--bg-0);border-top:1px solid var(--border-1)}
187
+ .task-list{list-style:none;padding:4px 0 0;display:flex;flex-direction:column;gap:2px}
188
+ .task-row{display:flex;align-items:center;gap:6px;font-size:12px;padding:3px 6px;border-radius:2px}
189
+ .dep-block{margin-bottom:28px}
190
+ .dep-legend{display:flex;gap:14px;font-size:12px;color:var(--text-2);margin-bottom:8px;align-items:center}
191
+ .dep-legend span{display:flex;align-items:center;gap:4px}
192
+ .dep-wrap{overflow-x:auto;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:16px}
193
+ .dep-svg{display:block}
194
+ .edge{fill:none;stroke:var(--border-2);stroke-width:1.5}
195
+ .edge-crit{stroke:var(--accent);stroke-width:2}
196
+ .node rect{fill:var(--bg-2);stroke:var(--border-2);stroke-width:1}
197
+ .n-done rect{fill:var(--ok-subtle);stroke:rgba(34,197,94,.4)}
198
+ .n-active rect{fill:var(--accent-subtle);stroke:var(--accent)}
199
+ .n-crit rect{stroke:var(--accent)!important;stroke-width:1.5!important}
200
+ .n-id{font-family:var(--mono);font-size:10px;fill:var(--text-1);font-weight:600;text-anchor:middle}
201
+ .n-title{font-size:9px;fill:var(--text-2);text-anchor:middle}
202
+ .n-active .n-id{fill:var(--accent)}
203
+ .token-block{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px;margin-bottom:16px}
204
+ .token-bar{display:flex;height:16px;border-radius:2px;overflow:hidden;gap:1px;margin-bottom:8px}
205
+ .tseg{height:100%;min-width:2px}
206
+ .seg-1{background:var(--tk-input)}
207
+ .seg-2{background:var(--tk-output)}
208
+ .seg-3{background:var(--tk-cache-r)}
209
+ .seg-4{background:var(--tk-cache-w)}
210
+ .token-legend{display:flex;flex-wrap:wrap;gap:12px}
211
+ .leg-item{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-2)}
212
+ .leg-dot{width:8px;height:8px;border-radius:2px;flex-shrink:0}
213
+ .chart-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px;margin-bottom:16px}
214
+ .chart-block{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px}
215
+ .bar-row{display:grid;grid-template-columns:120px 1fr 68px;align-items:center;gap:6px;margin-bottom:2px}
216
+ .bar-lbl{font-size:12px;color:var(--text-2);text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
217
+ .bar-track{height:14px;background:var(--bg-3);border-radius:2px;overflow:hidden}
218
+ .bar-fill{height:100%;border-radius:2px;background:var(--c0)}
219
+ .bar-c0{background:var(--c0)}.bar-c1{background:var(--c1)}.bar-c2{background:var(--c2)}
220
+ .bar-c3{background:var(--c3)}.bar-c4{background:var(--c4)}.bar-c5{background:var(--c5)}
221
+ .bar-val{font-size:11px;font-variant-numeric:tabular-nums;color:var(--text-1)}
222
+ .bar-sub{font-size:10px;color:var(--text-2);padding-left:128px;margin-bottom:6px}
223
+ .cl-entry{border-bottom:1px solid var(--border-1);padding:12px 0}
224
+ .cl-entry:last-child{border-bottom:none}
225
+ .cl-header{display:flex;align-items:center;gap:8px;margin-bottom:4px}
226
+ .cl-title{flex:1;font-weight:500}
227
+ .cl-date{margin-left:auto;white-space:nowrap}
228
+ .cl-liner{font-size:13px;color:var(--text-1);margin-bottom:6px}
229
+ .files-detail summary{font-size:12px;cursor:pointer}
230
+ .file-list{list-style:none;padding-left:10px;margin-top:4px;display:flex;flex-direction:column;gap:2px}
231
+ .file-list li{font-size:12px;color:var(--text-1)}
232
+ footer{border-top:1px solid var(--border-1);padding:20px 32px;margin-top:40px}
233
+ .footer-inner{display:flex;align-items:center;gap:6px;justify-content:center;font-size:11px;color:var(--text-2);flex-wrap:wrap}
234
+ .exec-summary{font-size:13px;color:var(--text-1);margin-bottom:12px;line-height:1.7}
235
+ .eta-line{font-size:12px;color:var(--accent);margin-top:4px}
236
+ .cost-svg{display:block;margin:8px 0;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px}
237
+ .cost-line{fill:none;stroke:var(--accent);stroke-width:2}
238
+ .cost-area{fill:var(--accent-subtle);stroke:none}
239
+ .cost-axis{fill:var(--text-2);font-family:var(--mono);font-size:10px}
240
+ .cost-grid{stroke:var(--border-1);stroke-width:1;stroke-dasharray:4,4}
241
+ .burndown-wrap{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px;margin-bottom:16px}
242
+ .burndown-bar{display:flex;height:20px;border-radius:3px;overflow:hidden;gap:1px;margin-bottom:8px}
243
+ .burndown-spent{background:var(--accent);height:100%}
244
+ .burndown-projected{background:var(--caution);height:100%;opacity:.6}
245
+ .burndown-overshoot{background:var(--warn);height:100%;opacity:.7}
246
+ .burndown-legend{display:flex;flex-wrap:wrap;gap:12px;font-size:11px;color:var(--text-2)}
247
+ .burndown-legend span{display:flex;align-items:center;gap:4px}
248
+ .burndown-dot{display:inline-block;width:8px;height:8px;border-radius:2px}
249
+ .blocker-card{border-left:3px solid var(--warn);background:var(--bg-1);border-radius:0 4px 4px 0;padding:10px 14px;margin-bottom:8px}
250
+ .blocker-id{font-family:var(--mono);font-size:12px;color:var(--warn);margin-bottom:2px}
251
+ .blocker-text{font-size:12px;color:var(--text-1)}
252
+ .blocker-risk{font-size:11px;color:var(--caution);margin-top:2px}
253
+ .gantt-wrap{overflow-x:auto;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:16px;margin-top:16px}
254
+ .gantt-svg{display:block}
255
+ .gantt-bar-done{fill:var(--ok);opacity:.7}
256
+ .gantt-bar-active{fill:var(--accent)}
257
+ .gantt-bar-pending{fill:var(--border-2)}
258
+ .gantt-label{fill:var(--text-2);font-family:var(--mono);font-size:10px}
259
+ .gantt-axis{fill:var(--text-2);font-family:var(--mono);font-size:9px}
260
+ .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}
261
+ .tl-filter:focus{border-color:var(--accent)}
262
+ .tl-filter::placeholder{color:var(--text-2)}
263
+ .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}
264
+ .sec-toggle:hover{border-color:var(--text-1);color:var(--text-1)}
265
+ .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)}
266
+ .theme-toggle:hover{border-color:var(--accent);color:var(--accent)}
267
+ .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}
268
+ .callout-warn{border-left-color:var(--caution)}
269
+ .callout-ok{border-left-color:var(--ok)}
270
+ .card-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
271
+ .card{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px}
272
+ .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}
273
+ @media(max-width:768px){
274
+ header{padding:10px 16px}
275
+ .header-inner{flex-wrap:wrap;gap:8px}
276
+ .header-meta h1{font-size:13px}
277
+ main{padding:16px}
278
+ .kv-grid{gap:1px}
279
+ .kv{min-width:80px;padding:8px 10px}
280
+ .kv-val{font-size:14px}
281
+ .chart-row{grid-template-columns:1fr}
282
+ .toc ul{padding:0 16px}
283
+ .toc a{padding:6px 8px;font-size:11px}
284
+ .bar-row{grid-template-columns:80px 1fr 56px}
285
+ .ms-body{padding-left:12px}
286
+ }
287
+ @media(max-width:480px){
288
+ .kv{min-width:60px;padding:6px 8px}
289
+ .kv-val{font-size:12px}
290
+ .kv-lbl{font-size:9px}
291
+ .bar-row{grid-template-columns:60px 1fr 48px}
292
+ .bar-lbl{font-size:10px}
293
+ .toc ul{flex-wrap:wrap}
294
+ .header-right{display:none}
295
+ .gantt-wrap{overflow-x:auto}
296
+ }
297
+ @media print{
298
+ header,nav.toc{position:static}
299
+ body{background:#fff;color:#1a1a1a}
300
+ :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}
301
+ section{page-break-inside:avoid}
302
+ .table-scroll{overflow:visible}
303
+ }
304
+ `;
305
+ export const HTML_SHELL_JS = `
306
+ (function(){
307
+ const sections=document.querySelectorAll('section[id]');
308
+ const links=document.querySelectorAll('.toc a');
309
+ if(!sections.length||!links.length)return;
310
+ const obs=new IntersectionObserver(entries=>{
311
+ for(const e of entries){
312
+ if(!e.isIntersecting)continue;
313
+ for(const l of links)l.classList.remove('active');
314
+ const a=document.querySelector('.toc a[href="#'+e.target.id+'"]');
315
+ if(a)a.classList.add('active');
316
+ }
317
+ },{rootMargin:'-10% 0px -80% 0px',threshold:0});
318
+ for(const s of sections)obs.observe(s);
319
+ })();
320
+ (function(){
321
+ var tl=document.getElementById('timeline');
322
+ if(!tl)return;
323
+ var table=tl.querySelector('.tbl');
324
+ if(!table)return;
325
+ var input=document.createElement('input');
326
+ input.className='tl-filter';
327
+ input.placeholder='Filter timeline\\u2026';
328
+ input.type='text';
329
+ table.parentNode.insertBefore(input,table);
330
+ var rows=table.querySelectorAll('tbody tr');
331
+ input.addEventListener('input',function(){
332
+ var q=this.value.toLowerCase();
333
+ for(var i=0;i<rows.length;i++){
334
+ rows[i].style.display=rows[i].textContent.toLowerCase().indexOf(q)>-1?'':'none';
335
+ }
336
+ });
337
+ })();
338
+ function safeLocalStorageSet(key,value){
339
+ try{localStorage.setItem(key,value)}catch(e){}
340
+ }
341
+ function safeLocalStorageGet(key){
342
+ try{return localStorage.getItem(key)}catch(e){return null}
343
+ }
344
+ (function(){
345
+ var saved={};
346
+ try{saved=JSON.parse(safeLocalStorageGet('gsd-collapsed')||'{}')}catch(e){}
347
+ document.querySelectorAll('section[id]').forEach(function(sec){
348
+ var h2=sec.querySelector('h2');
349
+ if(!h2)return;
350
+ var btn=document.createElement('button');
351
+ btn.className='sec-toggle';
352
+ btn.textContent=saved[sec.id]?'+':'-';
353
+ btn.setAttribute('aria-label','Toggle section');
354
+ h2.prepend(btn);
355
+ if(saved[sec.id])toggleSection(sec,true);
356
+ btn.addEventListener('click',function(e){
357
+ e.preventDefault();
358
+ var collapsed=btn.textContent==='-';
359
+ toggleSection(sec,collapsed);
360
+ btn.textContent=collapsed?'+':'-';
361
+ saved[sec.id]=collapsed;
362
+ safeLocalStorageSet('gsd-collapsed',JSON.stringify(saved));
363
+ });
364
+ });
365
+ function toggleSection(sec,hide){
366
+ var children=sec.children;
367
+ for(var i=0;i<children.length;i++){
368
+ if(children[i].tagName!=='H2')children[i].style.display=hide?'none':'';
369
+ }
370
+ }
371
+ })();
372
+ (function(){
373
+ var hr=document.querySelector('.header-right');
374
+ if(!hr)return;
375
+ var stored=safeLocalStorageGet('gsd-theme');
376
+ var btn=document.createElement('button');
377
+ btn.className='theme-toggle';
378
+ btn.textContent=stored==='light'?'Dark':'Light';
379
+ if(stored==='light')document.documentElement.classList.add('light-theme');
380
+ btn.addEventListener('click',function(){
381
+ document.documentElement.classList.toggle('light-theme');
382
+ var isLight=document.documentElement.classList.contains('light-theme');
383
+ btn.textContent=isLight?'Dark':'Light';
384
+ safeLocalStorageSet('gsd-theme',isLight?'light':'dark');
385
+ });
386
+ hr.prepend(btn);
387
+ })();
388
+ `;
@@ -115,6 +115,8 @@ export function getVisualBriefModeProfile(mode, slides) {
115
115
  "Assumptions, limitations, and source references",
116
116
  ],
117
117
  };
118
+ default:
119
+ throw new Error(`Unknown visual brief mode: ${mode}`);
118
120
  }
119
121
  }
120
122
  export function formatPageRules(rules = VISUAL_BRIEF_PAGE_RULES) {