gsd-pi 2.76.0 → 2.77.0

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 (536) hide show
  1. package/README.md +45 -25
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/mcp-server.d.ts +7 -0
  4. package/dist/mcp-server.js +35 -1
  5. package/dist/onboarding.js +45 -0
  6. package/dist/resource-loader.d.ts +1 -1
  7. package/dist/resource-loader.js +2 -8
  8. package/dist/resources/agents/researcher.md +1 -1
  9. package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  11. package/dist/resources/extensions/gsd/auto/loop.js +9 -0
  12. package/dist/resources/extensions/gsd/auto/phases.js +104 -11
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
  14. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  19. package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/auto-start.js +58 -57
  21. package/dist/resources/extensions/gsd/auto-verification.js +33 -0
  22. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  23. package/dist/resources/extensions/gsd/auto.js +70 -28
  24. package/dist/resources/extensions/gsd/blocked-models.js +68 -0
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  27. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  28. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
  30. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  33. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  34. package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  36. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  37. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  38. package/dist/resources/extensions/gsd/db-writer.js +88 -16
  39. package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
  40. package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
  41. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
  42. package/dist/resources/extensions/gsd/error-classifier.js +31 -3
  43. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  44. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  45. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +168 -23
  47. package/dist/resources/extensions/gsd/guided-flow.js +190 -1
  48. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  49. package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
  50. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  51. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  52. package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
  53. package/dist/resources/extensions/gsd/memory-store.js +19 -0
  54. package/dist/resources/extensions/gsd/model-router.js +36 -3
  55. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  56. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  57. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  58. package/dist/resources/extensions/gsd/preferences.js +17 -17
  59. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  60. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  62. package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  63. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  64. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  65. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  66. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  67. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  68. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
  69. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  70. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  71. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  72. package/dist/resources/extensions/gsd/state.js +43 -4
  73. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  74. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  75. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  76. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  77. package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
  78. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  79. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  81. package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  82. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  83. package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
  84. package/dist/resources/extensions/search-the-web/native-search.js +45 -13
  85. package/dist/resources/skills/api-design/SKILL.md +190 -0
  86. package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
  87. package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
  88. package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
  89. package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
  90. package/dist/resources/skills/forensics/SKILL.md +153 -0
  91. package/dist/resources/skills/grill-me/SKILL.md +93 -0
  92. package/dist/resources/skills/handoff/SKILL.md +121 -0
  93. package/dist/resources/skills/observability/SKILL.md +174 -0
  94. package/dist/resources/skills/security-review/SKILL.md +181 -0
  95. package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
  96. package/dist/resources/skills/tdd/SKILL.md +112 -0
  97. package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
  98. package/dist/resources/skills/write-docs/SKILL.md +82 -0
  99. package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  103. package/dist/web/standalone/.next/build-manifest.json +2 -2
  104. package/dist/web/standalone/.next/required-server-files.json +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  129. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  130. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware-manifest.json +1 -1
  132. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  133. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  134. package/dist/web/standalone/server.js +1 -1
  135. package/dist/welcome-screen.js +6 -1
  136. package/dist/wizard.js +2 -0
  137. package/package.json +1 -1
  138. package/packages/daemon/package.json +2 -2
  139. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  140. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  141. package/packages/mcp-server/dist/remote-questions.js +732 -0
  142. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  143. package/packages/mcp-server/dist/server.d.ts +7 -0
  144. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  145. package/packages/mcp-server/dist/server.js +70 -8
  146. package/packages/mcp-server/dist/server.js.map +1 -1
  147. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  148. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/session-manager.js +49 -1
  150. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  152. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  153. package/packages/mcp-server/dist/workflow-tools.js +163 -25
  154. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  155. package/packages/mcp-server/package.json +4 -3
  156. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  157. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  158. package/packages/mcp-server/src/remote-questions.ts +916 -0
  159. package/packages/mcp-server/src/server.ts +89 -14
  160. package/packages/mcp-server/src/session-manager.ts +43 -1
  161. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  162. package/packages/mcp-server/src/workflow-tools.ts +215 -43
  163. package/packages/mcp-server/tsconfig.test.json +19 -0
  164. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  165. package/packages/native/package.json +1 -1
  166. package/packages/pi-agent-core/dist/agent-loop.js +12 -0
  167. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  168. package/packages/pi-agent-core/dist/types.d.ts +30 -0
  169. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  170. package/packages/pi-agent-core/dist/types.js.map +1 -1
  171. package/packages/pi-agent-core/package.json +1 -1
  172. package/packages/pi-agent-core/src/agent-loop.ts +14 -0
  173. package/packages/pi-agent-core/src/types.ts +34 -0
  174. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  176. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models/custom.js +41 -0
  178. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  179. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  180. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  181. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
  182. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
  184. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
  185. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  187. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/anthropic.js +13 -4
  190. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  194. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  197. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  198. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  199. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  200. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  201. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  202. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  203. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  204. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  205. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  206. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  207. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  208. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  209. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  210. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
  212. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
  214. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  215. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  216. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
  217. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
  219. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
  224. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  225. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
  226. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
  228. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
  229. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
  230. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
  232. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
  233. package/packages/pi-ai/package.json +1 -1
  234. package/packages/pi-ai/src/models/custom.ts +42 -0
  235. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  236. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
  237. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  238. package/packages/pi-ai/src/providers/anthropic.ts +15 -4
  239. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  240. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  241. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  242. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  243. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  244. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
  245. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
  246. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
  247. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
  248. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
  249. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
  250. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
  251. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  252. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  253. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
  257. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  259. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  260. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
  263. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
  274. package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
  275. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
  276. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
  277. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
  278. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
  279. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  280. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  282. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  284. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  286. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  288. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
  290. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
  291. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
  292. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
  293. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  294. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  295. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  296. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  297. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  298. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  300. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  302. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  304. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  305. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  306. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  308. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  310. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  313. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  315. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
  317. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  320. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  321. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  336. package/packages/pi-coding-agent/package.json +1 -1
  337. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
  339. package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
  340. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  341. package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
  342. package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
  343. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
  344. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  345. package/packages/pi-coding-agent/src/core/index.ts +10 -0
  346. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  347. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  348. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  349. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  350. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  351. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  352. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  353. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  354. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  355. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  356. package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
  357. package/packages/pi-coding-agent/src/index.ts +16 -0
  358. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  359. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  360. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  361. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  362. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  363. package/packages/pi-tui/package.json +1 -1
  364. package/packages/rpc-client/package.json +1 -1
  365. package/pkg/package.json +1 -1
  366. package/scripts/link-workspace-packages.cjs +1 -0
  367. package/src/resources/agents/researcher.md +1 -1
  368. package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
  369. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  370. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  371. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
  372. package/src/resources/extensions/gsd/auto/loop.ts +9 -0
  373. package/src/resources/extensions/gsd/auto/phases.ts +131 -10
  374. package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
  375. package/src/resources/extensions/gsd/auto/session.ts +35 -2
  376. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  377. package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
  378. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  379. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  380. package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
  381. package/src/resources/extensions/gsd/auto-start.ts +60 -68
  382. package/src/resources/extensions/gsd/auto-verification.ts +33 -0
  383. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  384. package/src/resources/extensions/gsd/auto.ts +73 -28
  385. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  386. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
  387. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  388. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  389. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
  390. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
  391. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
  392. package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
  393. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  394. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  395. package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
  396. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  397. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  398. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  399. package/src/resources/extensions/gsd/db-writer.ts +88 -17
  400. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
  401. package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
  402. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
  403. package/src/resources/extensions/gsd/error-classifier.ts +36 -3
  404. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  405. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  406. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  407. package/src/resources/extensions/gsd/gsd-db.ts +186 -23
  408. package/src/resources/extensions/gsd/guided-flow.ts +222 -1
  409. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  410. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  411. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  412. package/src/resources/extensions/gsd/journal.ts +2 -1
  413. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  414. package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
  415. package/src/resources/extensions/gsd/memory-store.ts +26 -0
  416. package/src/resources/extensions/gsd/model-router.ts +42 -1
  417. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  418. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  419. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  420. package/src/resources/extensions/gsd/preferences.ts +17 -17
  421. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  422. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  423. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  424. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  425. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  426. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  427. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  428. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  429. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  430. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
  431. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  432. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  433. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  434. package/src/resources/extensions/gsd/state.ts +45 -4
  435. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
  436. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
  437. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  439. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  440. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  441. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  442. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  444. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
  445. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  446. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
  447. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  448. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  449. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  450. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  451. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  452. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  453. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
  454. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
  455. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
  456. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  457. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
  458. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  459. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  460. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  461. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  462. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
  463. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
  464. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  465. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  466. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
  467. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
  468. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
  469. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  470. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  471. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
  472. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  473. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  474. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
  475. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  476. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  477. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  479. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  480. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  481. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  482. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  483. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  484. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  485. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  486. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  487. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  488. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
  489. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  490. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  491. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  492. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  493. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  494. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  495. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  496. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  497. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  498. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  499. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  500. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
  501. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  502. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  503. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  504. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  505. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  506. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  507. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  508. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  509. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  510. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  511. package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
  512. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  513. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  514. package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
  515. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  516. package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  517. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  518. package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
  519. package/src/resources/extensions/search-the-web/native-search.ts +48 -12
  520. package/src/resources/skills/api-design/SKILL.md +190 -0
  521. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  522. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  523. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  524. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  525. package/src/resources/skills/forensics/SKILL.md +153 -0
  526. package/src/resources/skills/grill-me/SKILL.md +93 -0
  527. package/src/resources/skills/handoff/SKILL.md +121 -0
  528. package/src/resources/skills/observability/SKILL.md +174 -0
  529. package/src/resources/skills/security-review/SKILL.md +181 -0
  530. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  531. package/src/resources/skills/tdd/SKILL.md +112 -0
  532. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  533. package/src/resources/skills/write-docs/SKILL.md +82 -0
  534. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
  535. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
  536. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
@@ -34,6 +34,144 @@ function tryParsePercentage(val) {
34
34
  const n = Number(val);
35
35
  return !isNaN(n) && n >= 0 && n <= 100 ? n : null;
36
36
  }
37
+ // ─── Prompt helpers (reduce boilerplate across configure* functions) ─────────
38
+ /** Ask for a boolean; returns the chosen value, or undefined if user kept current/escaped. */
39
+ async function promptBoolean(ctx, label, current, defaultVal) {
40
+ const currentStr = typeof current === "boolean" ? String(current) : "";
41
+ const suffix = currentStr
42
+ ? ` (current: ${currentStr})`
43
+ : defaultVal !== undefined ? ` (default: ${defaultVal})` : "";
44
+ const choice = await ctx.ui.select(`${label}${suffix}:`, ["true", "false", "(keep current)"]);
45
+ if (!choice || choice === "(keep current)")
46
+ return undefined;
47
+ return choice === "true";
48
+ }
49
+ /** Ask for an enum-style value; returns the chosen string, or undefined if kept. */
50
+ async function promptEnum(ctx, label, current, values, defaultVal) {
51
+ const currentStr = typeof current === "string" ? current : "";
52
+ const suffix = currentStr
53
+ ? ` (current: ${currentStr})`
54
+ : defaultVal ? ` (default: ${defaultVal})` : "";
55
+ const options = [...values, "(keep current)"];
56
+ const choice = await ctx.ui.select(`${label}${suffix}:`, options);
57
+ if (!choice || typeof choice !== "string" || choice === "(keep current)")
58
+ return undefined;
59
+ return choice;
60
+ }
61
+ /**
62
+ * Ask for a non-negative integer.
63
+ * Returns parsed number on success; "clear" when the user explicitly cleared an existing value;
64
+ * undefined on escape, empty-with-no-existing-value, or invalid input (warning emitted in the invalid case).
65
+ */
66
+ async function promptInteger(ctx, label, current, defaultVal) {
67
+ const hadValue = current !== undefined && current !== null;
68
+ const currentStr = hadValue ? String(current) : "";
69
+ const suffix = currentStr ? ` (current: ${currentStr})` : defaultVal ? ` (default: ${defaultVal})` : "";
70
+ const input = await ctx.ui.input(`${label}${suffix}:`, currentStr || (defaultVal ?? ""));
71
+ if (input === null || input === undefined)
72
+ return undefined;
73
+ const val = input.trim();
74
+ if (!val)
75
+ return hadValue ? "clear" : undefined;
76
+ const parsed = tryParseInteger(val);
77
+ if (parsed === null) {
78
+ ctx.ui.notify(`Invalid value "${val}" for ${label} — must be a whole number. Keeping previous value.`, "warning");
79
+ return undefined;
80
+ }
81
+ return parsed;
82
+ }
83
+ /** Ask for a finite number. See promptInteger for return semantics. */
84
+ async function promptNumber(ctx, label, current, defaultVal) {
85
+ const hadValue = current !== undefined && current !== null;
86
+ const currentStr = hadValue ? String(current) : "";
87
+ const suffix = currentStr ? ` (current: ${currentStr})` : defaultVal ? ` (default: ${defaultVal})` : "";
88
+ const input = await ctx.ui.input(`${label}${suffix}:`, currentStr || (defaultVal ?? ""));
89
+ if (input === null || input === undefined)
90
+ return undefined;
91
+ const val = input.trim();
92
+ if (!val)
93
+ return hadValue ? "clear" : undefined;
94
+ const parsed = tryParseNumber(val);
95
+ if (parsed === null) {
96
+ ctx.ui.notify(`Invalid value "${val}" for ${label} — must be a number. Keeping previous value.`, "warning");
97
+ return undefined;
98
+ }
99
+ return parsed;
100
+ }
101
+ /** Apply a promptInteger/promptNumber result to a prefs dict. */
102
+ function applyNumber(prefs, key, result) {
103
+ if (result === undefined)
104
+ return;
105
+ if (result === "clear")
106
+ delete prefs[key];
107
+ else
108
+ prefs[key] = result;
109
+ }
110
+ /** Ask for a free-form string; returns the trimmed value, empty string to clear, or undefined if escaped. */
111
+ async function promptString(ctx, label, current, defaultVal) {
112
+ const currentStr = typeof current === "string" ? current : "";
113
+ const suffix = currentStr ? ` (current: ${currentStr})` : defaultVal ? ` (default: ${defaultVal})` : "";
114
+ const input = await ctx.ui.input(`${label}${suffix}:`, currentStr || (defaultVal ?? ""));
115
+ if (input === null || input === undefined)
116
+ return undefined;
117
+ return input.trim();
118
+ }
119
+ /** Parse comma- or newline-separated input into a deduplicated string array. */
120
+ function parseStringList(input) {
121
+ return input
122
+ .split(/[,\n]/)
123
+ .map(s => s.trim())
124
+ .filter(s => s.length > 0);
125
+ }
126
+ /** Sub-menu to edit a string list field (add / remove / clear / done). Mutates the parent prefs object. */
127
+ async function editStringListField(ctx, prefs, key, label) {
128
+ const current = Array.isArray(prefs[key]) ? [...prefs[key]] : [];
129
+ let list = current;
130
+ while (true) {
131
+ const summary = list.length === 0 ? "(empty)" : `${list.length} item(s): ${list.slice(0, 3).join(", ")}${list.length > 3 ? "…" : ""}`;
132
+ const choice = await ctx.ui.select(`${label} — ${summary}`, ["Add entries", "Remove entry", "Clear all", "Done"]);
133
+ const pick = typeof choice === "string" ? choice : "";
134
+ if (!pick || pick === "Done")
135
+ break;
136
+ if (pick === "Add entries") {
137
+ const input = await ctx.ui.input(`Add to ${label} (comma- or newline-separated):`, "");
138
+ if (input) {
139
+ for (const item of parseStringList(input)) {
140
+ if (!list.includes(item))
141
+ list.push(item);
142
+ }
143
+ }
144
+ }
145
+ else if (pick === "Remove entry") {
146
+ if (list.length === 0)
147
+ continue;
148
+ const removeChoice = await ctx.ui.select(`Remove which entry?`, [...list, "(cancel)"]);
149
+ const removeStr = typeof removeChoice === "string" ? removeChoice : "";
150
+ if (removeStr && removeStr !== "(cancel)") {
151
+ list = list.filter(x => x !== removeStr);
152
+ }
153
+ }
154
+ else if (pick === "Clear all") {
155
+ list = [];
156
+ }
157
+ }
158
+ if (list.length > 0) {
159
+ prefs[key] = list;
160
+ }
161
+ else if (prefs[key] !== undefined) {
162
+ delete prefs[key];
163
+ }
164
+ }
165
+ /** Set a nested object key, creating the parent object if needed, and deleting on undefined/empty. */
166
+ function setNested(parent, parentKey, childKey, value) {
167
+ let child = parent[parentKey];
168
+ if (!child || typeof child !== "object")
169
+ child = {};
170
+ if (value === undefined)
171
+ return;
172
+ child[childKey] = value;
173
+ parent[parentKey] = child;
174
+ }
37
175
  export async function handlePrefs(args, ctx) {
38
176
  const trimmed = args.trim();
39
177
  if (trimmed === "" || trimmed === "global" || trimmed === "wizard" || trimmed === "setup"
@@ -135,10 +273,26 @@ export function buildCategorySummaries(prefs) {
135
273
  const modeSummary = mode ?? "(not set)";
136
274
  // Models
137
275
  const models = prefs.models;
276
+ const tokenProfile = prefs.token_profile;
277
+ const serviceTier = prefs.service_tier;
278
+ const flatRate = Array.isArray(prefs.flat_rate_providers) ? prefs.flat_rate_providers.length : 0;
279
+ const dynRouting = prefs.dynamic_routing;
138
280
  let modelsSummary = "(not configured)";
139
- if (models && Object.keys(models).length > 0) {
140
- const parts = Object.entries(models).map(([phase, model]) => `${phase}: ${formatConfiguredModel(model)}`);
141
- modelsSummary = parts.join(", ");
281
+ {
282
+ const parts = [];
283
+ if (models && Object.keys(models).length > 0) {
284
+ parts.push(`${Object.keys(models).length} phase(s)`);
285
+ }
286
+ if (tokenProfile)
287
+ parts.push(`profile: ${tokenProfile}`);
288
+ if (serviceTier)
289
+ parts.push(`tier: ${serviceTier}`);
290
+ if (flatRate)
291
+ parts.push(`flat-rate: ${flatRate}`);
292
+ if (dynRouting?.enabled)
293
+ parts.push("routing: on");
294
+ if (parts.length > 0)
295
+ modelsSummary = parts.join(", ");
142
296
  }
143
297
  // Timeouts
144
298
  const autoSup = prefs.auto_supervisor;
@@ -173,14 +327,32 @@ export function buildCategorySummaries(prefs) {
173
327
  // Skills
174
328
  const discovery = prefs.skill_discovery;
175
329
  const uat = prefs.uat_dispatch;
330
+ const alwaysUse = Array.isArray(prefs.always_use_skills) ? prefs.always_use_skills.length : 0;
331
+ const preferS = Array.isArray(prefs.prefer_skills) ? prefs.prefer_skills.length : 0;
332
+ const avoidS = Array.isArray(prefs.avoid_skills) ? prefs.avoid_skills.length : 0;
333
+ const rulesCount = Array.isArray(prefs.skill_rules) ? prefs.skill_rules.length : 0;
334
+ const customInstr = Array.isArray(prefs.custom_instructions) ? prefs.custom_instructions.length : 0;
176
335
  let skillsSummary = "(not configured)";
177
- if (discovery || uat !== undefined) {
336
+ {
178
337
  const parts = [];
179
338
  if (discovery)
180
339
  parts.push(`discovery: ${discovery}`);
181
340
  if (uat !== undefined)
182
341
  parts.push(`uat: ${uat}`);
183
- skillsSummary = parts.join(", ");
342
+ if (alwaysUse)
343
+ parts.push(`always: ${alwaysUse}`);
344
+ if (preferS)
345
+ parts.push(`prefer: ${preferS}`);
346
+ if (avoidS)
347
+ parts.push(`avoid: ${avoidS}`);
348
+ if (rulesCount)
349
+ parts.push(`rules: ${rulesCount}`);
350
+ if (customInstr)
351
+ parts.push(`custom: ${customInstr}`);
352
+ if (prefs.skill_staleness_days !== undefined)
353
+ parts.push(`stale: ${prefs.skill_staleness_days}d`);
354
+ if (parts.length > 0)
355
+ skillsSummary = parts.join(", ");
184
356
  }
185
357
  // Budget
186
358
  const ceiling = prefs.budget_ceiling;
@@ -204,9 +376,145 @@ export function buildCategorySummaries(prefs) {
204
376
  }
205
377
  // Advanced
206
378
  const uniqueIds = prefs.unique_milestone_ids;
379
+ const experimentalRtk = prefs.experimental?.rtk;
207
380
  let advancedSummary = "(defaults)";
208
- if (uniqueIds !== undefined) {
209
- advancedSummary = `unique IDs: ${uniqueIds ? "on" : "off"}`;
381
+ {
382
+ const parts = [];
383
+ if (uniqueIds !== undefined)
384
+ parts.push(`unique: ${uniqueIds ? "on" : "off"}`);
385
+ if (prefs.auto_visualize !== undefined)
386
+ parts.push(`viz: ${prefs.auto_visualize ? "on" : "off"}`);
387
+ if (prefs.auto_report !== undefined)
388
+ parts.push(`report: ${prefs.auto_report ? "on" : "off"}`);
389
+ if (prefs.show_token_cost)
390
+ parts.push("cost-display");
391
+ if (prefs.forensics_dedup)
392
+ parts.push("forensics-dedup");
393
+ if (prefs.widget_mode)
394
+ parts.push(`widget: ${prefs.widget_mode}`);
395
+ if (experimentalRtk)
396
+ parts.push("rtk");
397
+ if (parts.length > 0)
398
+ advancedSummary = parts.join(", ");
399
+ }
400
+ // Phases
401
+ const phases = prefs.phases;
402
+ let phasesSummary = "(defaults)";
403
+ if (phases && Object.keys(phases).length > 0) {
404
+ const activeFlags = Object.entries(phases).filter(([, v]) => v === true).map(([k]) => k);
405
+ phasesSummary = activeFlags.length === 0 ? "(no flags)" : `${activeFlags.length} flag(s): ${activeFlags.slice(0, 2).join(", ")}${activeFlags.length > 2 ? "…" : ""}`;
406
+ }
407
+ // Parallelism
408
+ const parallel = prefs.parallel;
409
+ const sliceParallel = prefs.slice_parallel;
410
+ let parallelismSummary = "(defaults)";
411
+ {
412
+ const parts = [];
413
+ if (parallel?.enabled)
414
+ parts.push(`milestone: ${parallel.max_workers ?? 2}w`);
415
+ if (sliceParallel?.enabled)
416
+ parts.push(`slice: ${sliceParallel.max_workers ?? 2}w`);
417
+ if (parts.length > 0)
418
+ parallelismSummary = parts.join(", ");
419
+ }
420
+ // Verification
421
+ const verifyCmds = Array.isArray(prefs.verification_commands) ? prefs.verification_commands.length : 0;
422
+ const safety = prefs.safety_harness;
423
+ let verificationSummary = "(defaults)";
424
+ {
425
+ const parts = [];
426
+ if (verifyCmds)
427
+ parts.push(`${verifyCmds} cmd(s)`);
428
+ if (prefs.verification_auto_fix)
429
+ parts.push("auto-fix");
430
+ if (prefs.enhanced_verification === false)
431
+ parts.push("enhanced: off");
432
+ if (prefs.enhanced_verification_strict)
433
+ parts.push("strict");
434
+ if (safety?.enabled === false)
435
+ parts.push("harness: off");
436
+ else if (safety && Object.keys(safety).length > 0)
437
+ parts.push("harness: custom");
438
+ if (parts.length > 0)
439
+ verificationSummary = parts.join(", ");
440
+ }
441
+ // Discuss
442
+ let discussSummary = "(defaults)";
443
+ {
444
+ const parts = [];
445
+ if (prefs.discuss_preparation === false)
446
+ parts.push("prep: off");
447
+ if (prefs.discuss_web_research === false)
448
+ parts.push("web: off");
449
+ if (prefs.discuss_depth)
450
+ parts.push(`depth: ${prefs.discuss_depth}`);
451
+ if (parts.length > 0)
452
+ discussSummary = parts.join(", ");
453
+ }
454
+ // Context & Codebase
455
+ const ctxMgmt = prefs.context_management;
456
+ const codebase = prefs.codebase;
457
+ let contextSummary = "(defaults)";
458
+ {
459
+ const parts = [];
460
+ if (prefs.context_selection)
461
+ parts.push(`selection: ${prefs.context_selection}`);
462
+ if (ctxMgmt && Object.keys(ctxMgmt).length > 0)
463
+ parts.push(`mgmt: ${Object.keys(ctxMgmt).length} field(s)`);
464
+ if (prefs.context_window_override !== undefined)
465
+ parts.push(`override: ${prefs.context_window_override}`);
466
+ if (codebase && Object.keys(codebase).length > 0)
467
+ parts.push("codebase: custom");
468
+ if (parts.length > 0)
469
+ contextSummary = parts.join(", ");
470
+ }
471
+ // Hooks & Reactive
472
+ const reactive = prefs.reactive_execution;
473
+ const gateEval = prefs.gate_evaluation;
474
+ const postHooks = Array.isArray(prefs.post_unit_hooks) ? prefs.post_unit_hooks.length : 0;
475
+ const preHooks = Array.isArray(prefs.pre_dispatch_hooks) ? prefs.pre_dispatch_hooks.length : 0;
476
+ let hooksSummary = "(defaults)";
477
+ {
478
+ const parts = [];
479
+ if (postHooks)
480
+ parts.push(`post: ${postHooks}`);
481
+ if (preHooks)
482
+ parts.push(`pre: ${preHooks}`);
483
+ if (reactive?.enabled)
484
+ parts.push("reactive: on");
485
+ if (gateEval?.enabled)
486
+ parts.push("gate-eval: on");
487
+ if (parts.length > 0)
488
+ hooksSummary = parts.join(", ");
489
+ }
490
+ // UoK
491
+ const uok = prefs.uok;
492
+ let uokSummary = "(defaults)";
493
+ if (uok && Object.keys(uok).length > 0) {
494
+ if (uok.enabled === false)
495
+ uokSummary = "off";
496
+ else
497
+ uokSummary = `${Object.keys(uok).length} setting(s)`;
498
+ }
499
+ // Integrations
500
+ const cmux = prefs.cmux;
501
+ const remote = prefs.remote_questions;
502
+ const github = prefs.github;
503
+ let integrationsSummary = "(defaults)";
504
+ {
505
+ const parts = [];
506
+ if (prefs.language)
507
+ parts.push(`lang: ${prefs.language}`);
508
+ if (prefs.search_provider)
509
+ parts.push(`search: ${prefs.search_provider}`);
510
+ if (cmux?.enabled)
511
+ parts.push("cmux");
512
+ if (remote?.channel)
513
+ parts.push(`remote: ${remote.channel}`);
514
+ if (github?.enabled)
515
+ parts.push("github");
516
+ if (parts.length > 0)
517
+ integrationsSummary = parts.join(", ");
210
518
  }
211
519
  return {
212
520
  mode: modeSummary,
@@ -217,6 +525,14 @@ export function buildCategorySummaries(prefs) {
217
525
  budget: budgetSummary,
218
526
  notifications: notifSummary,
219
527
  advanced: advancedSummary,
528
+ phases: phasesSummary,
529
+ parallelism: parallelismSummary,
530
+ verification: verificationSummary,
531
+ discuss: discussSummary,
532
+ context: contextSummary,
533
+ hooks: hooksSummary,
534
+ uok: uokSummary,
535
+ integrations: integrationsSummary,
220
536
  };
221
537
  }
222
538
  // ─── Category configuration functions ────────────────────────────────────────
@@ -342,6 +658,62 @@ async function configureModels(ctx, prefs) {
342
658
  else {
343
659
  delete prefs.models;
344
660
  }
661
+ // ─── Extra routing-level model preferences ────────────────────────────────
662
+ const tokenProfile = await promptEnum(ctx, "Token profile (cost/quality tradeoff)", prefs.token_profile, ["budget", "balanced", "quality", "burn-max"]);
663
+ if (tokenProfile !== undefined)
664
+ prefs.token_profile = tokenProfile;
665
+ const serviceTier = await promptEnum(ctx, "OpenAI service tier (gpt-5.4 only)", prefs.service_tier, ["priority", "flex"]);
666
+ if (serviceTier !== undefined)
667
+ prefs.service_tier = serviceTier;
668
+ await editStringListField(ctx, prefs, "flat_rate_providers", "Flat-rate providers (suppress dynamic routing)");
669
+ await configureDynamicRouting(ctx, prefs);
670
+ }
671
+ async function configureDynamicRouting(ctx, prefs) {
672
+ const dr = prefs.dynamic_routing ?? {};
673
+ const enabled = await promptBoolean(ctx, "Enable dynamic routing (tier-based model selection)", dr.enabled);
674
+ if (enabled !== undefined)
675
+ dr.enabled = enabled;
676
+ if (dr.enabled !== true) {
677
+ // If routing is disabled / kept-off, still let the user configure sub-fields (they may enable later).
678
+ }
679
+ const cap = await promptBoolean(ctx, "Capability-aware routing", dr.capability_routing, false);
680
+ if (cap !== undefined)
681
+ dr.capability_routing = cap;
682
+ const escalate = await promptBoolean(ctx, "Escalate to heavier tier on failure", dr.escalate_on_failure, true);
683
+ if (escalate !== undefined)
684
+ dr.escalate_on_failure = escalate;
685
+ const pressure = await promptBoolean(ctx, "Downgrade under budget pressure", dr.budget_pressure, true);
686
+ if (pressure !== undefined)
687
+ dr.budget_pressure = pressure;
688
+ const cross = await promptBoolean(ctx, "Cross-provider routing", dr.cross_provider, true);
689
+ if (cross !== undefined)
690
+ dr.cross_provider = cross;
691
+ const hooks = await promptBoolean(ctx, "Route hook sessions dynamically", dr.hooks, true);
692
+ if (hooks !== undefined)
693
+ dr.hooks = hooks;
694
+ const flatRate = await promptBoolean(ctx, "Allow dynamic routing for flat-rate providers", dr.allow_flat_rate_providers, false);
695
+ if (flatRate !== undefined)
696
+ dr.allow_flat_rate_providers = flatRate;
697
+ // tier_models.light / standard / heavy — optional model IDs
698
+ const tierModels = dr.tier_models ?? {};
699
+ for (const tier of ["light", "standard", "heavy"]) {
700
+ const current = typeof tierModels[tier] === "string" ? tierModels[tier] : "";
701
+ const input = await promptString(ctx, `Model for ${tier} tier (e.g. claude-haiku-4-5)`, current);
702
+ if (input === undefined)
703
+ continue;
704
+ if (input)
705
+ tierModels[tier] = input;
706
+ else if (current)
707
+ delete tierModels[tier];
708
+ }
709
+ if (Object.keys(tierModels).length > 0)
710
+ dr.tier_models = tierModels;
711
+ else
712
+ delete dr.tier_models;
713
+ if (Object.keys(dr).length > 0)
714
+ prefs.dynamic_routing = dr;
715
+ else if (prefs.dynamic_routing !== undefined)
716
+ delete prefs.dynamic_routing;
345
717
  }
346
718
  async function configureTimeouts(ctx, prefs) {
347
719
  const autoSup = prefs.auto_supervisor ?? {};
@@ -477,17 +849,90 @@ async function configureGit(ctx, prefs) {
477
849
  }
478
850
  async function configureSkills(ctx, prefs) {
479
851
  // Skill discovery mode
480
- const currentDiscovery = prefs.skill_discovery ?? "";
481
- const discoveryChoice = await ctx.ui.select(`Skill discovery mode${currentDiscovery ? ` (current: ${currentDiscovery})` : ""}:`, ["auto", "suggest", "off", "(keep current)"]);
482
- if (discoveryChoice && discoveryChoice !== "(keep current)") {
483
- prefs.skill_discovery = discoveryChoice;
484
- }
852
+ const discovery = await promptEnum(ctx, "Skill discovery mode", prefs.skill_discovery, ["auto", "suggest", "off"]);
853
+ if (discovery !== undefined)
854
+ prefs.skill_discovery = discovery;
485
855
  // UAT dispatch
486
- const currentUat = prefs.uat_dispatch;
487
- const uatChoice = await ctx.ui.select(`UAT dispatch mode${currentUat !== undefined ? ` (current: ${currentUat})` : " (default: false)"}:`, ["true", "false", "(keep current)"]);
488
- if (uatChoice && uatChoice !== "(keep current)") {
489
- prefs.uat_dispatch = uatChoice === "true";
856
+ const uat = await promptBoolean(ctx, "UAT dispatch mode", prefs.uat_dispatch, false);
857
+ if (uat !== undefined)
858
+ prefs.uat_dispatch = uat;
859
+ // Skill lists edit via sub-menus
860
+ await editStringListField(ctx, prefs, "always_use_skills", "Always-use skills");
861
+ await editStringListField(ctx, prefs, "prefer_skills", "Preferred skills");
862
+ await editStringListField(ctx, prefs, "avoid_skills", "Avoided skills");
863
+ await editStringListField(ctx, prefs, "custom_instructions", "Custom instructions");
864
+ // Skill rules (array of {when, use?, prefer?, avoid?})
865
+ await configureSkillRules(ctx, prefs);
866
+ // Skill staleness days
867
+ const staleness = await promptInteger(ctx, "Skill staleness days (0 to disable)", prefs.skill_staleness_days, "60");
868
+ applyNumber(prefs, "skill_staleness_days", staleness);
869
+ }
870
+ async function configureSkillRules(ctx, prefs) {
871
+ let rules = Array.isArray(prefs.skill_rules) ? [...prefs.skill_rules] : [];
872
+ while (true) {
873
+ const summary = rules.length === 0
874
+ ? "(no rules)"
875
+ : `${rules.length} rule(s)`;
876
+ const listLabels = rules.map((r, i) => `#${i + 1} when: ${r.when}`);
877
+ const options = [...listLabels, "Add rule", "Done"];
878
+ const choice = await ctx.ui.select(`Skill rules — ${summary}`, options);
879
+ const pick = typeof choice === "string" ? choice : "";
880
+ if (!pick || pick === "Done")
881
+ break;
882
+ if (pick === "Add rule") {
883
+ const whenInput = await ctx.ui.input("Rule condition (free text, e.g. 'frontend tasks'):", "");
884
+ const when = typeof whenInput === "string" ? whenInput.trim() : "";
885
+ if (!when)
886
+ continue;
887
+ const rule = { when };
888
+ for (const field of ["use", "prefer", "avoid"]) {
889
+ const listInput = await ctx.ui.input(`Skills to ${field} (comma- or newline-separated, blank to skip):`, "");
890
+ if (listInput) {
891
+ const parsed = parseStringList(listInput);
892
+ if (parsed.length > 0)
893
+ rule[field] = parsed;
894
+ }
895
+ }
896
+ if (rule.use || rule.prefer || rule.avoid)
897
+ rules.push(rule);
898
+ else
899
+ ctx.ui.notify("Rule discarded — must have at least one of use/prefer/avoid.", "warning");
900
+ }
901
+ else if (pick.startsWith("#")) {
902
+ const idx = Number(pick.slice(1, pick.indexOf(" "))) - 1;
903
+ if (idx < 0 || idx >= rules.length)
904
+ continue;
905
+ const editChoice = await ctx.ui.select(`Rule #${idx + 1}`, ["Edit condition", "Edit use list", "Edit prefer list", "Edit avoid list", "Delete rule", "Cancel"]);
906
+ const ec = typeof editChoice === "string" ? editChoice : "";
907
+ if (!ec || ec === "Cancel")
908
+ continue;
909
+ if (ec === "Delete rule") {
910
+ rules = rules.filter((_, i) => i !== idx);
911
+ continue;
912
+ }
913
+ if (ec === "Edit condition") {
914
+ const newWhen = await promptString(ctx, "Rule condition", rules[idx].when);
915
+ if (newWhen !== undefined && newWhen !== "")
916
+ rules[idx].when = newWhen;
917
+ }
918
+ else {
919
+ const fieldKey = ec === "Edit use list" ? "use" : ec === "Edit prefer list" ? "prefer" : "avoid";
920
+ const currentList = rules[idx][fieldKey] ?? [];
921
+ const listInput = await ctx.ui.input(`${fieldKey} list (comma- or newline-separated, blank to clear):`, currentList.join(", "));
922
+ if (listInput === null || listInput === undefined)
923
+ continue;
924
+ const parsed = parseStringList(listInput);
925
+ if (parsed.length > 0)
926
+ rules[idx][fieldKey] = parsed;
927
+ else
928
+ delete rules[idx][fieldKey];
929
+ }
930
+ }
490
931
  }
932
+ if (rules.length > 0)
933
+ prefs.skill_rules = rules;
934
+ else if (prefs.skill_rules !== undefined)
935
+ delete prefs.skill_rules;
491
936
  }
492
937
  async function configureBudget(ctx, prefs) {
493
938
  const currentCeiling = prefs.budget_ceiling;
@@ -552,6 +997,451 @@ async function configureNotifications(ctx, prefs) {
552
997
  prefs.notifications = notif;
553
998
  }
554
999
  }
1000
+ async function configurePhases(ctx, prefs) {
1001
+ const phases = prefs.phases ?? {};
1002
+ const fields = [
1003
+ { key: "skip_research", label: "Skip research phase" },
1004
+ { key: "skip_reassess", label: "Skip roadmap reassessment" },
1005
+ { key: "skip_slice_research", label: "Skip slice-level research" },
1006
+ { key: "skip_milestone_validation", label: "Skip milestone validation" },
1007
+ { key: "reassess_after_slice", label: "Reassess roadmap after each slice" },
1008
+ { key: "require_slice_discussion", label: "Pause for discussion before each slice" },
1009
+ { key: "mid_execution_escalation", label: "Allow mid-execution escalation (ADR-011 P2)" },
1010
+ { key: "progressive_planning", label: "Progressive planning (S01 full, S02+ sketches)" },
1011
+ ];
1012
+ for (const field of fields) {
1013
+ const val = await promptBoolean(ctx, field.label, phases[field.key]);
1014
+ if (val !== undefined)
1015
+ phases[field.key] = val;
1016
+ }
1017
+ if (Object.keys(phases).length > 0)
1018
+ prefs.phases = phases;
1019
+ else if (prefs.phases !== undefined)
1020
+ delete prefs.phases;
1021
+ }
1022
+ async function configureParallelism(ctx, prefs) {
1023
+ // parallel: milestone-level
1024
+ const parallel = prefs.parallel ?? {};
1025
+ const pEnabled = await promptBoolean(ctx, "Parallel milestone execution", parallel.enabled, false);
1026
+ if (pEnabled !== undefined)
1027
+ parallel.enabled = pEnabled;
1028
+ const pWorkers = await promptInteger(ctx, "Max parallel workers (1–4)", parallel.max_workers, "2");
1029
+ if (pWorkers !== undefined && pWorkers !== "clear")
1030
+ parallel.max_workers = Math.max(1, Math.min(4, pWorkers));
1031
+ else if (pWorkers === "clear")
1032
+ delete parallel.max_workers;
1033
+ const pBudget = await promptNumber(ctx, "Per-worker budget ceiling (USD, blank = no limit)", parallel.budget_ceiling);
1034
+ if (pBudget !== undefined && pBudget !== "clear")
1035
+ parallel.budget_ceiling = pBudget;
1036
+ else if (pBudget === "clear")
1037
+ delete parallel.budget_ceiling;
1038
+ const pMerge = await promptEnum(ctx, "Parallel merge strategy", parallel.merge_strategy, ["per-slice", "per-milestone"]);
1039
+ if (pMerge !== undefined)
1040
+ parallel.merge_strategy = pMerge;
1041
+ const pAuto = await promptEnum(ctx, "Auto-merge mode", parallel.auto_merge, ["auto", "confirm", "manual"]);
1042
+ if (pAuto !== undefined)
1043
+ parallel.auto_merge = pAuto;
1044
+ const pWorkerModel = await promptString(ctx, "Worker model override (e.g. claude-haiku-4-5)", parallel.worker_model);
1045
+ if (pWorkerModel !== undefined) {
1046
+ if (pWorkerModel)
1047
+ parallel.worker_model = pWorkerModel;
1048
+ else
1049
+ delete parallel.worker_model;
1050
+ }
1051
+ if (Object.keys(parallel).length > 0)
1052
+ prefs.parallel = parallel;
1053
+ else if (prefs.parallel !== undefined)
1054
+ delete prefs.parallel;
1055
+ // slice_parallel: slice-level
1056
+ const sp = prefs.slice_parallel ?? {};
1057
+ const spEnabled = await promptBoolean(ctx, "Slice-level parallel execution", sp.enabled, false);
1058
+ if (spEnabled !== undefined)
1059
+ sp.enabled = spEnabled;
1060
+ const spWorkers = await promptInteger(ctx, "Slice max workers", sp.max_workers, "2");
1061
+ if (spWorkers !== undefined && spWorkers !== "clear")
1062
+ sp.max_workers = spWorkers;
1063
+ else if (spWorkers === "clear")
1064
+ delete sp.max_workers;
1065
+ if (Object.keys(sp).length > 0)
1066
+ prefs.slice_parallel = sp;
1067
+ else if (prefs.slice_parallel !== undefined)
1068
+ delete prefs.slice_parallel;
1069
+ }
1070
+ async function configureVerification(ctx, prefs) {
1071
+ await editStringListField(ctx, prefs, "verification_commands", "Verification commands");
1072
+ const autoFix = await promptBoolean(ctx, "Auto-fix on verification failure", prefs.verification_auto_fix);
1073
+ if (autoFix !== undefined)
1074
+ prefs.verification_auto_fix = autoFix;
1075
+ const maxRetries = await promptInteger(ctx, "Verification max retries", prefs.verification_max_retries, "2");
1076
+ applyNumber(prefs, "verification_max_retries", maxRetries);
1077
+ const ev = await promptBoolean(ctx, "Enhanced verification (master toggle)", prefs.enhanced_verification, true);
1078
+ if (ev !== undefined)
1079
+ prefs.enhanced_verification = ev;
1080
+ const evPre = await promptBoolean(ctx, "Enhanced verification — pre-execution checks", prefs.enhanced_verification_pre, true);
1081
+ if (evPre !== undefined)
1082
+ prefs.enhanced_verification_pre = evPre;
1083
+ const evPost = await promptBoolean(ctx, "Enhanced verification — post-execution checks", prefs.enhanced_verification_post, true);
1084
+ if (evPost !== undefined)
1085
+ prefs.enhanced_verification_post = evPost;
1086
+ const evStrict = await promptBoolean(ctx, "Enhanced verification — strict mode (fail on any issue)", prefs.enhanced_verification_strict, false);
1087
+ if (evStrict !== undefined)
1088
+ prefs.enhanced_verification_strict = evStrict;
1089
+ // safety_harness
1090
+ const sh = prefs.safety_harness ?? {};
1091
+ const shFields = [
1092
+ { key: "enabled", label: "Safety harness enabled" },
1093
+ { key: "evidence_collection", label: "Collect tool evidence" },
1094
+ { key: "file_change_validation", label: "Validate file change descriptions" },
1095
+ { key: "evidence_cross_reference", label: "Cross-reference evidence across tools" },
1096
+ { key: "destructive_command_warnings", label: "Warn on destructive commands" },
1097
+ { key: "content_validation", label: "Validate written content" },
1098
+ { key: "checkpoints", label: "Create safety checkpoints" },
1099
+ { key: "auto_rollback", label: "Auto-rollback on safety violation" },
1100
+ ];
1101
+ for (const field of shFields) {
1102
+ const val = await promptBoolean(ctx, `Safety harness — ${field.label}`, sh[field.key]);
1103
+ if (val !== undefined)
1104
+ sh[field.key] = val;
1105
+ }
1106
+ const cap = await promptNumber(ctx, "Safety harness timeout scale cap", sh.timeout_scale_cap);
1107
+ if (cap !== undefined && cap !== "clear")
1108
+ sh.timeout_scale_cap = cap;
1109
+ else if (cap === "clear")
1110
+ delete sh.timeout_scale_cap;
1111
+ if (Object.keys(sh).length > 0)
1112
+ prefs.safety_harness = sh;
1113
+ else if (prefs.safety_harness !== undefined)
1114
+ delete prefs.safety_harness;
1115
+ }
1116
+ async function configureDiscuss(ctx, prefs) {
1117
+ const prep = await promptBoolean(ctx, "Discuss — run preparation phase", prefs.discuss_preparation, true);
1118
+ if (prep !== undefined)
1119
+ prefs.discuss_preparation = prep;
1120
+ const web = await promptBoolean(ctx, "Discuss — web research during preparation", prefs.discuss_web_research, true);
1121
+ if (web !== undefined)
1122
+ prefs.discuss_web_research = web;
1123
+ const depth = await promptEnum(ctx, "Discuss preparation depth", prefs.discuss_depth, ["quick", "standard", "thorough"], "standard");
1124
+ if (depth !== undefined)
1125
+ prefs.discuss_depth = depth;
1126
+ }
1127
+ async function configureContextCodebase(ctx, prefs) {
1128
+ const sel = await promptEnum(ctx, "Context selection mode", prefs.context_selection, ["full", "smart"]);
1129
+ if (sel !== undefined)
1130
+ prefs.context_selection = sel;
1131
+ // context_management nested
1132
+ const cm = prefs.context_management ?? {};
1133
+ const mask = await promptBoolean(ctx, "Observation masking (hide stale tool outputs)", cm.observation_masking, true);
1134
+ if (mask !== undefined)
1135
+ cm.observation_masking = mask;
1136
+ const maskTurns = await promptInteger(ctx, "Observation mask turns (1–50)", cm.observation_mask_turns, "8");
1137
+ if (maskTurns !== undefined && maskTurns !== "clear")
1138
+ cm.observation_mask_turns = maskTurns;
1139
+ else if (maskTurns === "clear")
1140
+ delete cm.observation_mask_turns;
1141
+ const thresh = await promptNumber(ctx, "Compaction threshold percent (0.5–0.95)", cm.compaction_threshold_percent, "0.70");
1142
+ if (thresh !== undefined && thresh !== "clear")
1143
+ cm.compaction_threshold_percent = thresh;
1144
+ else if (thresh === "clear")
1145
+ delete cm.compaction_threshold_percent;
1146
+ const toolMax = await promptInteger(ctx, "Tool result max chars (200–10000)", cm.tool_result_max_chars, "800");
1147
+ if (toolMax !== undefined && toolMax !== "clear")
1148
+ cm.tool_result_max_chars = toolMax;
1149
+ else if (toolMax === "clear")
1150
+ delete cm.tool_result_max_chars;
1151
+ if (Object.keys(cm).length > 0)
1152
+ prefs.context_management = cm;
1153
+ else if (prefs.context_management !== undefined)
1154
+ delete prefs.context_management;
1155
+ const override = await promptInteger(ctx, "Context window override (tokens, blank = use model default)", prefs.context_window_override);
1156
+ applyNumber(prefs, "context_window_override", override);
1157
+ // codebase map
1158
+ const cb = prefs.codebase ?? {};
1159
+ const currentExcludes = Array.isArray(cb.exclude_patterns) ? cb.exclude_patterns : [];
1160
+ const excludesInput = await ctx.ui.input(`Codebase map — extra exclude patterns (comma- or newline-separated, blank to keep)${currentExcludes.length ? ` (current: ${currentExcludes.join(", ")})` : ""}:`, currentExcludes.join(", "));
1161
+ if (excludesInput !== null && excludesInput !== undefined) {
1162
+ const parsed = parseStringList(excludesInput);
1163
+ if (parsed.length > 0)
1164
+ cb.exclude_patterns = parsed;
1165
+ else if (currentExcludes.length > 0 && excludesInput.trim() === "")
1166
+ delete cb.exclude_patterns;
1167
+ }
1168
+ const maxFiles = await promptInteger(ctx, "Codebase map — max files", cb.max_files, "500");
1169
+ if (maxFiles !== undefined && maxFiles !== "clear")
1170
+ cb.max_files = maxFiles;
1171
+ else if (maxFiles === "clear")
1172
+ delete cb.max_files;
1173
+ const collapse = await promptInteger(ctx, "Codebase map — collapse threshold", cb.collapse_threshold, "20");
1174
+ if (collapse !== undefined && collapse !== "clear")
1175
+ cb.collapse_threshold = collapse;
1176
+ else if (collapse === "clear")
1177
+ delete cb.collapse_threshold;
1178
+ if (Object.keys(cb).length > 0)
1179
+ prefs.codebase = cb;
1180
+ else if (prefs.codebase !== undefined)
1181
+ delete prefs.codebase;
1182
+ }
1183
+ async function configureHooks(ctx, prefs) {
1184
+ // reactive_execution
1185
+ const re = prefs.reactive_execution ?? {};
1186
+ const reEnabled = await promptBoolean(ctx, "Reactive (graph-parallel) task execution", re.enabled, false);
1187
+ if (reEnabled !== undefined)
1188
+ re.enabled = reEnabled;
1189
+ const reMax = await promptInteger(ctx, "Reactive max parallel (1–8)", re.max_parallel, "3");
1190
+ if (reMax !== undefined && reMax !== "clear")
1191
+ re.max_parallel = Math.max(1, Math.min(8, reMax));
1192
+ else if (reMax === "clear")
1193
+ delete re.max_parallel;
1194
+ const reModel = await promptString(ctx, "Reactive subagent model override", re.subagent_model);
1195
+ if (reModel !== undefined) {
1196
+ if (reModel)
1197
+ re.subagent_model = reModel;
1198
+ else
1199
+ delete re.subagent_model;
1200
+ }
1201
+ if (Object.keys(re).length > 0) {
1202
+ // isolation_mode is currently only "same-tree"; set it when enabled to satisfy the schema.
1203
+ if (re.enabled === true && !re.isolation_mode)
1204
+ re.isolation_mode = "same-tree";
1205
+ prefs.reactive_execution = re;
1206
+ }
1207
+ else if (prefs.reactive_execution !== undefined) {
1208
+ delete prefs.reactive_execution;
1209
+ }
1210
+ // gate_evaluation
1211
+ const ge = prefs.gate_evaluation ?? {};
1212
+ const geEnabled = await promptBoolean(ctx, "Parallel gate evaluation during planning", ge.enabled, false);
1213
+ if (geEnabled !== undefined)
1214
+ ge.enabled = geEnabled;
1215
+ const currentSliceGates = Array.isArray(ge.slice_gates) ? ge.slice_gates : [];
1216
+ const sgInput = await ctx.ui.input(`Slice gates to evaluate (comma-separated, blank keeps)${currentSliceGates.length ? ` (current: ${currentSliceGates.join(", ")})` : " (default: Q3,Q4)"}:`, currentSliceGates.join(", "));
1217
+ if (sgInput !== null && sgInput !== undefined) {
1218
+ const parsed = parseStringList(sgInput);
1219
+ if (parsed.length > 0)
1220
+ ge.slice_gates = parsed;
1221
+ else if (currentSliceGates.length > 0 && sgInput.trim() === "")
1222
+ delete ge.slice_gates;
1223
+ }
1224
+ const geTask = await promptBoolean(ctx, "Evaluate task-level gates (Q5/Q6/Q7)", ge.task_gates, true);
1225
+ if (geTask !== undefined)
1226
+ ge.task_gates = geTask;
1227
+ if (Object.keys(ge).length > 0)
1228
+ prefs.gate_evaluation = ge;
1229
+ else if (prefs.gate_evaluation !== undefined)
1230
+ delete prefs.gate_evaluation;
1231
+ // post_unit_hooks[]
1232
+ await configureHookList(ctx, prefs, "post_unit_hooks", "Post-unit hooks", "after");
1233
+ // pre_dispatch_hooks[]
1234
+ await configureHookList(ctx, prefs, "pre_dispatch_hooks", "Pre-dispatch hooks", "before");
1235
+ }
1236
+ async function configureHookList(ctx, prefs, key, label, triggerField) {
1237
+ let hooks = Array.isArray(prefs[key]) ? [...prefs[key]] : [];
1238
+ while (true) {
1239
+ const summary = hooks.length === 0 ? "(none)" : `${hooks.length} hook(s)`;
1240
+ const labels = hooks.map((h, i) => `#${i + 1} ${h.name ?? "(unnamed)"}${h.enabled === false ? " [disabled]" : ""}`);
1241
+ const choice = await ctx.ui.select(`${label} — ${summary}`, [...labels, "Add hook", "Done"]);
1242
+ const pick = typeof choice === "string" ? choice : "";
1243
+ if (!pick || pick === "Done")
1244
+ break;
1245
+ if (pick === "Add hook") {
1246
+ const nameInput = await ctx.ui.input("Hook name (unique identifier):", "");
1247
+ const name = typeof nameInput === "string" ? nameInput.trim() : "";
1248
+ if (!name)
1249
+ continue;
1250
+ const triggerInput = await ctx.ui.input(`Unit types this hook ${triggerField === "after" ? "runs after" : "intercepts before"} (comma-separated, e.g. execute-task):`, "");
1251
+ const triggers = triggerInput ? parseStringList(triggerInput) : [];
1252
+ if (triggers.length === 0) {
1253
+ ctx.ui.notify("Hook discarded — trigger list cannot be empty.", "warning");
1254
+ continue;
1255
+ }
1256
+ const hook = { name, [triggerField]: triggers, enabled: true };
1257
+ if (key === "post_unit_hooks") {
1258
+ const promptInput = await ctx.ui.input("Hook prompt (sent to LLM; supports {milestoneId}, {sliceId}, {taskId}):", "");
1259
+ if (promptInput)
1260
+ hook.prompt = promptInput;
1261
+ }
1262
+ else {
1263
+ const actionChoice = await ctx.ui.select("Action:", ["modify", "skip", "replace"]);
1264
+ if (actionChoice)
1265
+ hook.action = actionChoice;
1266
+ }
1267
+ hooks.push(hook);
1268
+ }
1269
+ else if (pick.startsWith("#")) {
1270
+ const idx = Number(pick.slice(1, pick.indexOf(" "))) - 1;
1271
+ if (idx < 0 || idx >= hooks.length)
1272
+ continue;
1273
+ const editChoice = await ctx.ui.select(`Hook #${idx + 1}: ${hooks[idx].name ?? ""}`, ["Toggle enabled", "Edit prompt/action", "Edit model override", "Delete hook", "Cancel"]);
1274
+ const ec = typeof editChoice === "string" ? editChoice : "";
1275
+ if (!ec || ec === "Cancel")
1276
+ continue;
1277
+ if (ec === "Delete hook") {
1278
+ hooks = hooks.filter((_, i) => i !== idx);
1279
+ }
1280
+ else if (ec === "Toggle enabled") {
1281
+ hooks[idx].enabled = hooks[idx].enabled === false;
1282
+ }
1283
+ else if (ec === "Edit prompt/action") {
1284
+ if (key === "post_unit_hooks") {
1285
+ const newPrompt = await promptString(ctx, "Prompt", hooks[idx].prompt);
1286
+ if (newPrompt !== undefined && newPrompt)
1287
+ hooks[idx].prompt = newPrompt;
1288
+ }
1289
+ else {
1290
+ const newAction = await promptEnum(ctx, "Action", hooks[idx].action, ["modify", "skip", "replace"]);
1291
+ if (newAction !== undefined)
1292
+ hooks[idx].action = newAction;
1293
+ }
1294
+ }
1295
+ else if (ec === "Edit model override") {
1296
+ const m = await promptString(ctx, "Model override (blank to clear)", hooks[idx].model);
1297
+ if (m !== undefined) {
1298
+ if (m)
1299
+ hooks[idx].model = m;
1300
+ else
1301
+ delete hooks[idx].model;
1302
+ }
1303
+ }
1304
+ }
1305
+ }
1306
+ if (hooks.length > 0)
1307
+ prefs[key] = hooks;
1308
+ else if (prefs[key] !== undefined)
1309
+ delete prefs[key];
1310
+ }
1311
+ async function configureUoK(ctx, prefs) {
1312
+ const uok = prefs.uok ?? {};
1313
+ const enabled = await promptBoolean(ctx, "UoK (Unified Orchestration Kernel) enabled", uok.enabled);
1314
+ if (enabled !== undefined)
1315
+ uok.enabled = enabled;
1316
+ const subsections = ["legacy_fallback", "gates", "model_policy", "execution_graph", "audit_unified", "plan_v2"];
1317
+ for (const sub of subsections) {
1318
+ const existing = uok[sub] ?? {};
1319
+ const val = await promptBoolean(ctx, `UoK — ${sub.replace(/_/g, " ")} enabled`, existing.enabled);
1320
+ if (val !== undefined) {
1321
+ existing.enabled = val;
1322
+ uok[sub] = existing;
1323
+ }
1324
+ else if (Object.keys(existing).length > 0) {
1325
+ uok[sub] = existing;
1326
+ }
1327
+ }
1328
+ // gitops has extra fields
1329
+ const gitops = uok.gitops ?? {};
1330
+ const gitopsEnabled = await promptBoolean(ctx, "UoK — gitops enabled", gitops.enabled);
1331
+ if (gitopsEnabled !== undefined)
1332
+ gitops.enabled = gitopsEnabled;
1333
+ const turnAction = await promptEnum(ctx, "UoK gitops — turn action", gitops.turn_action, ["commit", "snapshot", "status-only"]);
1334
+ if (turnAction !== undefined)
1335
+ gitops.turn_action = turnAction;
1336
+ const turnPush = await promptBoolean(ctx, "UoK gitops — turn push", gitops.turn_push);
1337
+ if (turnPush !== undefined)
1338
+ gitops.turn_push = turnPush;
1339
+ if (Object.keys(gitops).length > 0)
1340
+ uok.gitops = gitops;
1341
+ if (Object.keys(uok).length > 0)
1342
+ prefs.uok = uok;
1343
+ else if (prefs.uok !== undefined)
1344
+ delete prefs.uok;
1345
+ }
1346
+ async function configureIntegrations(ctx, prefs) {
1347
+ // Language
1348
+ const lang = await promptString(ctx, "Response language (e.g. Chinese, zh, German — blank to clear)", prefs.language);
1349
+ if (lang !== undefined) {
1350
+ if (lang)
1351
+ prefs.language = lang;
1352
+ else
1353
+ delete prefs.language;
1354
+ }
1355
+ // Search provider
1356
+ const search = await promptEnum(ctx, "Search provider", prefs.search_provider, ["auto", "brave", "tavily", "ollama", "native"], "auto");
1357
+ if (search !== undefined)
1358
+ prefs.search_provider = search;
1359
+ // cmux
1360
+ const cmux = prefs.cmux ?? {};
1361
+ for (const field of ["enabled", "notifications", "sidebar", "splits", "browser"]) {
1362
+ const val = await promptBoolean(ctx, `cmux — ${field}`, cmux[field]);
1363
+ if (val !== undefined)
1364
+ cmux[field] = val;
1365
+ }
1366
+ if (Object.keys(cmux).length > 0)
1367
+ prefs.cmux = cmux;
1368
+ else if (prefs.cmux !== undefined)
1369
+ delete prefs.cmux;
1370
+ // remote_questions
1371
+ await configureRemoteQuestions(ctx, prefs);
1372
+ // github sync
1373
+ await configureGitHubSync(ctx, prefs);
1374
+ }
1375
+ async function configureRemoteQuestions(ctx, prefs) {
1376
+ const existing = prefs.remote_questions ?? {};
1377
+ const channel = await promptEnum(ctx, "Remote questions channel", existing.channel, ["slack", "discord", "telegram"]);
1378
+ const channelId = await promptString(ctx, "Remote questions channel_id", existing.channel_id);
1379
+ const timeout = await promptInteger(ctx, "Remote questions timeout (minutes, 1–30)", existing.timeout_minutes, "10");
1380
+ const poll = await promptInteger(ctx, "Remote questions poll interval (seconds, 2–30)", existing.poll_interval_seconds, "5");
1381
+ if (channel !== undefined)
1382
+ existing.channel = channel;
1383
+ if (channelId !== undefined) {
1384
+ if (channelId)
1385
+ existing.channel_id = channelId;
1386
+ else
1387
+ delete existing.channel_id;
1388
+ }
1389
+ applyNumber(existing, "timeout_minutes", timeout);
1390
+ applyNumber(existing, "poll_interval_seconds", poll);
1391
+ // Required pair: channel + channel_id. If either is missing, keep whatever existed unchanged.
1392
+ if (existing.channel && existing.channel_id) {
1393
+ prefs.remote_questions = existing;
1394
+ }
1395
+ else if (!existing.channel && !existing.channel_id) {
1396
+ if (prefs.remote_questions !== undefined)
1397
+ delete prefs.remote_questions;
1398
+ }
1399
+ else {
1400
+ // Partial config — hold it so user can finish, but warn.
1401
+ ctx.ui.notify("remote_questions requires both channel and channel_id; keeping partial config.", "warning");
1402
+ prefs.remote_questions = existing;
1403
+ }
1404
+ }
1405
+ async function configureGitHubSync(ctx, prefs) {
1406
+ const gh = prefs.github ?? {};
1407
+ const enabled = await promptBoolean(ctx, "GitHub sync enabled", gh.enabled, false);
1408
+ if (enabled !== undefined)
1409
+ gh.enabled = enabled;
1410
+ const repo = await promptString(ctx, "GitHub repo (owner/repo, blank = auto-detect from git remote)", gh.repo);
1411
+ if (repo !== undefined) {
1412
+ if (repo)
1413
+ gh.repo = repo;
1414
+ else
1415
+ delete gh.repo;
1416
+ }
1417
+ const project = await promptInteger(ctx, "GitHub Projects v2 number (blank = none)", gh.project);
1418
+ if (project !== undefined && project !== "clear")
1419
+ gh.project = project;
1420
+ else if (project === "clear")
1421
+ delete gh.project;
1422
+ // labels
1423
+ const currentLabels = Array.isArray(gh.labels) ? gh.labels : [];
1424
+ const labelsInput = await ctx.ui.input(`GitHub default labels (comma-separated)${currentLabels.length ? ` (current: ${currentLabels.join(", ")})` : ""}:`, currentLabels.join(", "));
1425
+ if (labelsInput !== null && labelsInput !== undefined) {
1426
+ const parsed = parseStringList(labelsInput);
1427
+ if (parsed.length > 0)
1428
+ gh.labels = parsed;
1429
+ else if (currentLabels.length > 0 && labelsInput.trim() === "")
1430
+ delete gh.labels;
1431
+ }
1432
+ const autoLink = await promptBoolean(ctx, "GitHub — auto-link commits with Resolves #N", gh.auto_link_commits, true);
1433
+ if (autoLink !== undefined)
1434
+ gh.auto_link_commits = autoLink;
1435
+ const slicePrs = await promptBoolean(ctx, "GitHub — create per-slice draft PRs", gh.slice_prs, true);
1436
+ if (slicePrs !== undefined)
1437
+ gh.slice_prs = slicePrs;
1438
+ if (gh.enabled === true || Object.keys(gh).length > 1)
1439
+ prefs.github = gh;
1440
+ else if (prefs.github !== undefined && Object.keys(gh).length === 0)
1441
+ delete prefs.github;
1442
+ else if (Object.keys(gh).length > 0)
1443
+ prefs.github = gh;
1444
+ }
555
1445
  export async function configureMode(ctx, prefs) {
556
1446
  const currentMode = prefs.mode;
557
1447
  const modeChoice = await ctx.ui.select(`Workflow mode${currentMode ? ` (current: ${currentMode})` : ""}:`, [
@@ -576,11 +1466,32 @@ export async function configureMode(ctx, prefs) {
576
1466
  }
577
1467
  }
578
1468
  async function configureAdvanced(ctx, prefs) {
579
- const currentUnique = prefs.unique_milestone_ids;
580
- const uniqueChoice = await ctx.ui.select(`Unique milestone IDs${currentUnique !== undefined ? ` (current: ${currentUnique})` : ""}:`, ["true", "false", "(keep current)"]);
581
- if (uniqueChoice && uniqueChoice !== "(keep current)") {
582
- prefs.unique_milestone_ids = uniqueChoice === "true";
583
- }
1469
+ const unique = await promptBoolean(ctx, "Unique milestone IDs", prefs.unique_milestone_ids);
1470
+ if (unique !== undefined)
1471
+ prefs.unique_milestone_ids = unique;
1472
+ const autoViz = await promptBoolean(ctx, "Auto-visualize milestones (open HTML visualizer)", prefs.auto_visualize);
1473
+ if (autoViz !== undefined)
1474
+ prefs.auto_visualize = autoViz;
1475
+ const autoReport = await promptBoolean(ctx, "Auto-generate milestone HTML report", prefs.auto_report, true);
1476
+ if (autoReport !== undefined)
1477
+ prefs.auto_report = autoReport;
1478
+ const forensics = await promptBoolean(ctx, "Forensics dedup (search GitHub before filing)", prefs.forensics_dedup, false);
1479
+ if (forensics !== undefined)
1480
+ prefs.forensics_dedup = forensics;
1481
+ const tokenCost = await promptBoolean(ctx, "Show token cost in footer", prefs.show_token_cost, false);
1482
+ if (tokenCost !== undefined)
1483
+ prefs.show_token_cost = tokenCost;
1484
+ const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode, ["full", "small", "min", "off"], "full");
1485
+ if (widget !== undefined)
1486
+ prefs.widget_mode = widget;
1487
+ const experimental = prefs.experimental ?? {};
1488
+ const rtk = await promptBoolean(ctx, "Experimental: RTK shell-command compression", experimental.rtk, false);
1489
+ if (rtk !== undefined)
1490
+ experimental.rtk = rtk;
1491
+ if (Object.keys(experimental).length > 0)
1492
+ prefs.experimental = experimental;
1493
+ else if (prefs.experimental !== undefined)
1494
+ delete prefs.experimental;
584
1495
  }
585
1496
  // ─── Main wizard with category menu ─────────────────────────────────────────
586
1497
  export async function handlePrefsWizard(ctx, scope, prefill, opts) {
@@ -608,6 +1519,14 @@ export async function handlePrefsWizard(ctx, scope, prefill, opts) {
608
1519
  `Skills ${summaries.skills}`,
609
1520
  `Budget ${summaries.budget}`,
610
1521
  `Notifications ${summaries.notifications}`,
1522
+ `Phases ${summaries.phases}`,
1523
+ `Parallelism ${summaries.parallelism}`,
1524
+ `Verification ${summaries.verification}`,
1525
+ `Discuss ${summaries.discuss}`,
1526
+ `Context ${summaries.context}`,
1527
+ `Hooks ${summaries.hooks}`,
1528
+ `UoK ${summaries.uok}`,
1529
+ `Integrations ${summaries.integrations}`,
611
1530
  `Advanced ${summaries.advanced}`,
612
1531
  `── Save & Exit ──`,
613
1532
  ];
@@ -629,6 +1548,22 @@ export async function handlePrefsWizard(ctx, scope, prefill, opts) {
629
1548
  await configureBudget(ctx, prefs);
630
1549
  else if (choice.startsWith("Notifications"))
631
1550
  await configureNotifications(ctx, prefs);
1551
+ else if (choice.startsWith("Phases"))
1552
+ await configurePhases(ctx, prefs);
1553
+ else if (choice.startsWith("Parallelism"))
1554
+ await configureParallelism(ctx, prefs);
1555
+ else if (choice.startsWith("Verification"))
1556
+ await configureVerification(ctx, prefs);
1557
+ else if (choice.startsWith("Discuss"))
1558
+ await configureDiscuss(ctx, prefs);
1559
+ else if (choice.startsWith("Context"))
1560
+ await configureContextCodebase(ctx, prefs);
1561
+ else if (choice.startsWith("Hooks"))
1562
+ await configureHooks(ctx, prefs);
1563
+ else if (choice.startsWith("UoK"))
1564
+ await configureUoK(ctx, prefs);
1565
+ else if (choice.startsWith("Integrations"))
1566
+ await configureIntegrations(ctx, prefs);
632
1567
  else if (choice.startsWith("Advanced"))
633
1568
  await configureAdvanced(ctx, prefs);
634
1569
  }
@@ -732,11 +1667,21 @@ export function serializePreferencesToFrontmatter(prefs) {
732
1667
  "skill_staleness_days", "auto_supervisor", "uat_dispatch", "unique_milestone_ids",
733
1668
  "budget_ceiling", "budget_enforcement", "context_pause_threshold",
734
1669
  "notifications", "cmux", "remote_questions", "git",
1670
+ "stale_commit_threshold_minutes",
735
1671
  "post_unit_hooks", "pre_dispatch_hooks",
736
- "dynamic_routing", "uok", "token_profile", "phases", "parallel",
1672
+ "dynamic_routing", "uok", "token_profile", "service_tier", "flat_rate_providers",
1673
+ "phases", "parallel", "slice_parallel",
1674
+ "reactive_execution", "gate_evaluation",
737
1675
  "auto_visualize", "auto_report",
738
1676
  "verification_commands", "verification_auto_fix", "verification_max_retries",
739
- "search_provider", "context_selection", "language",
1677
+ "enhanced_verification", "enhanced_verification_pre",
1678
+ "enhanced_verification_post", "enhanced_verification_strict",
1679
+ "safety_harness",
1680
+ "discuss_preparation", "discuss_web_research", "discuss_depth",
1681
+ "search_provider", "context_selection", "context_management", "context_window_override",
1682
+ "codebase", "widget_mode", "forensics_dedup", "show_token_cost",
1683
+ "github", "experimental",
1684
+ "language",
740
1685
  ];
741
1686
  const seen = new Set();
742
1687
  for (const key of orderedKeys) {