@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.74e8dd1

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 (232) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +167 -16
  3. package/dist/resources/extensions/gsd/auto/phases.js +4 -3
  4. package/dist/resources/extensions/gsd/auto-dashboard.js +15 -4
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +39 -0
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +113 -7
  7. package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
  8. package/dist/resources/extensions/gsd/auto-recovery.js +4 -4
  9. package/dist/resources/extensions/gsd/auto-start.js +94 -15
  10. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
  11. package/dist/resources/extensions/gsd/auto.js +22 -4
  12. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +79 -0
  13. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  14. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +30 -9
  15. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
  16. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  17. package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
  18. package/dist/resources/extensions/gsd/commands/handlers/ops.js +7 -3
  19. package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
  20. package/dist/resources/extensions/gsd/commands-mcp-status.js +107 -59
  21. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  22. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  23. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  24. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  25. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  26. package/dist/resources/extensions/gsd/gsd-db.js +37 -4
  27. package/dist/resources/extensions/gsd/guided-flow.js +1 -1
  28. package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
  29. package/dist/resources/extensions/gsd/mcp-project-config.js +67 -8
  30. package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
  31. package/dist/resources/extensions/gsd/prompts/run-uat.md +10 -4
  32. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  33. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  34. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  35. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
  36. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
  37. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  38. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  39. package/dist/resources/extensions/gsd/state.js +15 -12
  40. package/dist/resources/extensions/gsd/tool-presentation-plan.js +120 -0
  41. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  42. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
  43. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  44. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +366 -3
  45. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  46. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  47. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
  48. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
  49. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
  50. package/dist/resources/extensions/mcp-client/manager.js +31 -1
  51. package/dist/web/standalone/.next/BUILD_ID +1 -1
  52. package/dist/web/standalone/.next/app-path-routes-manifest.json +4 -4
  53. package/dist/web/standalone/.next/build-manifest.json +2 -2
  54. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  55. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  56. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.html +1 -1
  72. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app-paths-manifest.json +4 -4
  79. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  80. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  82. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  83. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  84. package/package.json +2 -2
  85. package/packages/cloud-mcp-gateway/package.json +2 -2
  86. package/packages/contracts/dist/workflow.d.ts +14 -0
  87. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  88. package/packages/contracts/dist/workflow.js +16 -0
  89. package/packages/contracts/dist/workflow.js.map +1 -1
  90. package/packages/contracts/package.json +1 -1
  91. package/packages/daemon/package.json +4 -4
  92. package/packages/gsd-agent-core/package.json +5 -5
  93. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  94. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  95. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  96. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  97. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  98. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  99. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +72 -31
  100. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  101. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  102. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
  103. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  104. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  105. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  106. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  107. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  108. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  109. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  110. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  111. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  112. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  113. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  114. package/packages/gsd-agent-modes/package.json +7 -7
  115. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  116. package/packages/mcp-server/dist/workflow-tools.js +82 -0
  117. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  118. package/packages/mcp-server/package.json +3 -3
  119. package/packages/native/package.json +1 -1
  120. package/packages/pi-agent-core/package.json +1 -1
  121. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  122. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  123. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  124. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  125. package/packages/pi-ai/dist/models.generated.d.ts +338 -17
  126. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  127. package/packages/pi-ai/dist/models.generated.js +412 -112
  128. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  129. package/packages/pi-ai/package.json +1 -1
  130. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  131. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  133. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  134. package/packages/pi-coding-agent/package.json +7 -7
  135. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  136. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  137. package/packages/pi-tui/dist/terminal.js +8 -4
  138. package/packages/pi-tui/dist/terminal.js.map +1 -1
  139. package/packages/pi-tui/package.json +1 -1
  140. package/packages/rpc-client/package.json +2 -2
  141. package/pkg/package.json +1 -1
  142. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
  143. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
  144. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  145. package/src/resources/extensions/gsd/auto-dashboard.ts +16 -4
  146. package/src/resources/extensions/gsd/auto-dispatch.ts +48 -0
  147. package/src/resources/extensions/gsd/auto-post-unit.ts +138 -7
  148. package/src/resources/extensions/gsd/auto-prompts.ts +9 -0
  149. package/src/resources/extensions/gsd/auto-recovery.ts +4 -4
  150. package/src/resources/extensions/gsd/auto-start.ts +112 -17
  151. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
  152. package/src/resources/extensions/gsd/auto.ts +35 -3
  153. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +86 -0
  154. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  155. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +51 -14
  156. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
  157. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  158. package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
  159. package/src/resources/extensions/gsd/commands/handlers/ops.ts +7 -3
  160. package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
  161. package/src/resources/extensions/gsd/commands-mcp-status.ts +134 -57
  162. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  163. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  164. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  165. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  166. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  167. package/src/resources/extensions/gsd/gsd-db.ts +41 -6
  168. package/src/resources/extensions/gsd/guided-flow.ts +1 -1
  169. package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
  170. package/src/resources/extensions/gsd/mcp-project-config.ts +92 -10
  171. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  172. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  173. package/src/resources/extensions/gsd/prompts/run-uat.md +10 -4
  174. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  175. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  176. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  177. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
  178. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
  179. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  180. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  181. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  182. package/src/resources/extensions/gsd/state.ts +16 -12
  183. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +51 -0
  184. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +86 -0
  185. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
  186. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
  187. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  188. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  189. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  190. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
  191. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
  192. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  193. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  194. package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
  195. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
  196. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
  197. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
  198. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +68 -0
  199. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +177 -0
  200. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
  201. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  202. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
  203. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -0
  204. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  205. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  206. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
  207. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  208. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  209. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
  210. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
  211. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  212. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  213. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  214. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  215. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  216. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
  217. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +83 -0
  218. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
  219. package/src/resources/extensions/gsd/tool-presentation-plan.ts +167 -0
  220. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  221. package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
  222. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  223. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +440 -2
  224. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  225. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  226. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
  227. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
  228. package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
  229. package/src/resources/extensions/mcp-client/manager.ts +33 -1
  230. package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
  231. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_buildManifest.js +0 -0
  232. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_ssgManifest.js +0 -0
@@ -51,6 +51,7 @@ export function showHelp(ctx, args = "") {
51
51
  " /gsd keys API key manager (LLM + tool keys)",
52
52
  " /gsd doctor Diagnose and repair .gsd/ state",
53
53
  " /gsd closeout Recover failed git closeout actions",
54
+ " /gsd rebuild Rebuild markdown projections from the DB [markdown]",
54
55
  "",
55
56
  "Use /gsd help full for the complete command reference.",
56
57
  ];
@@ -68,7 +69,7 @@ export function showHelp(ctx, args = "") {
68
69
  " /gsd new-milestone Create milestone from headless context (used by gsd headless)",
69
70
  " /gsd new-project Bootstrap a new project (use --deep for staged project-level discovery)",
70
71
  " /gsd quick Execute a quick task without full planning overhead",
71
- " /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|uat|replan]",
72
+ " /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|validate|reassess|uat|replan]",
72
73
  " /gsd verdict <v> Override milestone validation verdict [pass|needs-attention|needs-remediation] [--milestone Mxxx] [--rationale \"...\"]",
73
74
  " /gsd parallel Parallel milestone orchestration [start|status|stop|pause|resume|merge|watch]",
74
75
  " /gsd workflow Custom workflow lifecycle [new|run|list|validate|pause|resume]",
@@ -132,7 +133,7 @@ export function showHelp(ctx, args = "") {
132
133
  " /gsd skill-health Skill lifecycle dashboard",
133
134
  " /gsd extensions Manage extensions [list|enable|disable|info]",
134
135
  " /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
135
- " /gsd mcp MCP server management [status|check|test|enable|disable|import|delete|init]",
136
+ " /gsd mcp MCP server management [status|check|discover|test|enable|disable|import|delete|init]",
136
137
  "",
137
138
  "MAINTENANCE",
138
139
  " /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
@@ -141,6 +142,9 @@ export function showHelp(ctx, args = "") {
141
142
  " /gsd export Alias for /gsd report",
142
143
  " /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
143
144
  " /gsd closeout Recover failed git closeout actions [status|retry|resolve] [unit-id]",
145
+ " /gsd rebuild markdown Rebuild markdown projections from the canonical DB",
146
+ " /gsd rebuild database Reserved for DB-native rebuilds; does not import markdown",
147
+ " /gsd recover --confirm Import markdown into the DB after DB loss/corruption",
144
148
  " /gsd worktree Manage worktrees from the TUI [list|merge|clean|remove]",
145
149
  " /gsd migrate Migrate .planning/ (v1) to DB-backed .gsd/ with backup + audit",
146
150
  " /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
@@ -4,7 +4,7 @@ import { handleDoctor, handleCapture, handleKnowledge, handleRunHook, handleSkil
4
4
  import { handleInspect } from "../../commands-inspect.js";
5
5
  import { handleLogs } from "../../commands-logs.js";
6
6
  import { handleDebug } from "../../commands-debug.js";
7
- import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover } from "../../commands-maintenance.js";
7
+ import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover, handleRebuild } from "../../commands-maintenance.js";
8
8
  import { handleExport } from "../../export.js";
9
9
  import { handleHistory } from "../../history.js";
10
10
  import { handleUndo } from "../../undo.js";
@@ -130,8 +130,12 @@ export async function handleOpsCommand(trimmed, ctx, pi) {
130
130
  await handleSkip(trimmed.replace(/^skip\s*/, "").trim(), ctx, projectRoot());
131
131
  return true;
132
132
  }
133
- if (trimmed === "recover") {
134
- await handleRecover(ctx, projectRoot());
133
+ if (trimmed === "recover" || trimmed.startsWith("recover ")) {
134
+ await handleRecover(ctx, projectRoot(), trimmed.replace(/^recover\s*/, "").trim());
135
+ return true;
136
+ }
137
+ if (trimmed === "rebuild" || trimmed.startsWith("rebuild ")) {
138
+ await handleRebuild(ctx, projectRoot(), trimmed.replace(/^rebuild\s*/, "").trim());
135
139
  return true;
136
140
  }
137
141
  if (trimmed === "closeout" || trimmed.startsWith("closeout ")) {
@@ -1,9 +1,12 @@
1
1
  /**
2
2
  * GSD Maintenance — cleanup, skip, dry-run, and recover handlers.
3
3
  *
4
- * Contains: handleCleanupBranches, handleCleanupSnapshots, handleCleanupWorktrees, handleSkip, handleDryRun, handleRecover
4
+ * Contains: handleCleanupBranches, handleCleanupSnapshots, handleCleanupWorktrees, handleSkip, handleDryRun, handleRecover, handleRebuild
5
5
  */
6
+ import { existsSync, mkdirSync, renameSync } from "node:fs";
7
+ import { dirname, isAbsolute, join, relative } from "node:path";
6
8
  import { deriveState } from "./state.js";
9
+ import { gsdProjectionRoot, gsdRoot } from "./paths.js";
7
10
  import { nativeBranchList, nativeDetectMainBranch, nativeBranchListMerged, nativeBranchDelete, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
8
11
  import { logWarning } from "./workflow-logger.js";
9
12
  export async function handleCleanupBranches(ctx, basePath) {
@@ -439,6 +442,30 @@ export async function handleCleanupProjects(args, ctx) {
439
442
  }
440
443
  ctx.ui.notify(lines.join("\n"), "info");
441
444
  }
445
+ function recoverConfirmed(args) {
446
+ return args
447
+ .split(/\s+/)
448
+ .map((part) => part.trim().toLowerCase())
449
+ .some((part) => part === "--confirm" || part === "--yes" || part === "confirm");
450
+ }
451
+ async function confirmRecover(ctx, args) {
452
+ if (recoverConfirmed(args))
453
+ return true;
454
+ const warning = [
455
+ "gsd recover imports markdown into the database.",
456
+ "It clears and reconstructs milestone, slice, and task hierarchy rows from rendered markdown.",
457
+ "Use /gsd rebuild markdown for normal DB-to-markdown realignment.",
458
+ ].join("\n");
459
+ if (typeof ctx.ui.confirm === "function") {
460
+ const confirmed = await ctx.ui.confirm("Import markdown into the DB?", `${warning}\n\nContinue only if the DB is lost or corrupt and markdown is the source you intend to import.`);
461
+ if (confirmed)
462
+ return true;
463
+ ctx.ui.notify("gsd recover cancelled. No database changes made.", "info");
464
+ return false;
465
+ }
466
+ ctx.ui.notify(`${warning}\n\nNo database changes made. Re-run /gsd recover --confirm to proceed.`, "warning");
467
+ return false;
468
+ }
442
469
  /**
443
470
  * `gsd recover` — Reconstruct DB hierarchy state from rendered markdown on disk.
444
471
  *
@@ -448,7 +475,7 @@ export async function handleCleanupProjects(args, ctx) {
448
475
  *
449
476
  * Prints counts of recovered items and the resulting project phase.
450
477
  */
451
- export async function handleRecover(ctx, basePath) {
478
+ export async function handleRecover(ctx, basePath, args = "") {
452
479
  const { isDbAvailable: dbAvailable, clearEngineHierarchy, transaction: dbTransaction } = await import("./gsd-db.js");
453
480
  const { migrateHierarchyToDb } = await import("./md-importer.js");
454
481
  const { invalidateStateCache } = await import("./state.js");
@@ -456,6 +483,8 @@ export async function handleRecover(ctx, basePath) {
456
483
  ctx.ui.notify("gsd recover: No database open. Run a GSD command first to initialize the DB.", "error");
457
484
  return;
458
485
  }
486
+ if (!(await confirmRecover(ctx, args)))
487
+ return;
459
488
  try {
460
489
  // 1. Delete + re-populate inside a single transaction for atomicity.
461
490
  // clearEngineHierarchy() uses transaction() internally but transaction()
@@ -496,3 +525,144 @@ export async function handleRecover(ctx, basePath) {
496
525
  ctx.ui.notify(`gsd recover failed: ${msg}`, "error");
497
526
  }
498
527
  }
528
+ function normalizeArtifactPath(value) {
529
+ return value.replace(/\\/g, "/");
530
+ }
531
+ function pathWithin(root, candidate) {
532
+ const rel = relative(root, candidate);
533
+ return rel.length === 0 || (!rel.startsWith("..") && !isAbsolute(rel));
534
+ }
535
+ function artifactPathForDb(basePath, absPath) {
536
+ const projectionRoot = gsdProjectionRoot(basePath);
537
+ const root = pathWithin(projectionRoot, absPath) ? projectionRoot : gsdRoot(basePath);
538
+ return normalizeArtifactPath(relative(root, absPath));
539
+ }
540
+ function quarantineRelativePath(basePath, absPath) {
541
+ for (const root of [gsdProjectionRoot(basePath), gsdRoot(basePath)]) {
542
+ if (pathWithin(root, absPath)) {
543
+ return normalizeArtifactPath(relative(root, absPath));
544
+ }
545
+ }
546
+ return normalizeArtifactPath(absPath.replace(/^[/\\]+/, ""));
547
+ }
548
+ function uniquePath(path) {
549
+ if (!existsSync(path))
550
+ return path;
551
+ let idx = 2;
552
+ while (existsSync(`${path}.${idx}`))
553
+ idx++;
554
+ return `${path}.${idx}`;
555
+ }
556
+ function resolveDiskArtifactPath(basePath, artifactPath) {
557
+ if (isAbsolute(artifactPath))
558
+ return artifactPath;
559
+ const candidates = [
560
+ join(gsdProjectionRoot(basePath), artifactPath),
561
+ join(gsdRoot(basePath), artifactPath),
562
+ ];
563
+ return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];
564
+ }
565
+ function quarantineProjectionFile(basePath, absPath, stamp) {
566
+ const rel = quarantineRelativePath(basePath, absPath);
567
+ const target = uniquePath(join(gsdProjectionRoot(basePath), "quarantine", "projections", stamp, rel));
568
+ mkdirSync(dirname(target), { recursive: true });
569
+ renameSync(absPath, target);
570
+ return target;
571
+ }
572
+ function parseRebuildTarget(args) {
573
+ const trimmed = args.trim().toLowerCase();
574
+ if (!trimmed || trimmed === "markdown")
575
+ return "markdown";
576
+ if (trimmed === "database" || trimmed === "db")
577
+ return "database";
578
+ return "usage";
579
+ }
580
+ /**
581
+ * `gsd rebuild markdown` — Re-render markdown projections from the authoritative DB.
582
+ *
583
+ * This is the DB-first realignment command. It does not import markdown into
584
+ * the DB. Completion SUMMARY files that contradict open DB rows are preserved
585
+ * under `.gsd/quarantine/projections/` before DB projections are rendered.
586
+ */
587
+ export async function handleRebuild(ctx, basePath, args = "") {
588
+ const { isDbAvailable: dbAvailable, deleteArtifactByPath } = await import("./gsd-db.js");
589
+ const { detectArtifactDbDrift } = await import("./state-reconciliation/drift/artifact-db.js");
590
+ const { renderAllFromDb } = await import("./markdown-renderer.js");
591
+ const { invalidateStateCache } = await import("./state.js");
592
+ const target = parseRebuildTarget(args);
593
+ if (target === "usage") {
594
+ ctx.ui.notify([
595
+ "Usage:",
596
+ " /gsd rebuild markdown Rebuild markdown projections from the canonical DB",
597
+ " /gsd rebuild database Reserved for DB-native rebuilds; does not import markdown",
598
+ ].join("\n"), "warning");
599
+ return;
600
+ }
601
+ if (target === "database") {
602
+ ctx.ui.notify([
603
+ "gsd rebuild database is reserved for DB-native rebuilds.",
604
+ "It will not import markdown projections into the DB.",
605
+ "For normal realignment, run /gsd rebuild markdown.",
606
+ "If the DB is lost or corrupt and markdown is the source to import, run /gsd recover --confirm.",
607
+ ].join("\n"), "warning");
608
+ return;
609
+ }
610
+ if (!dbAvailable()) {
611
+ ctx.ui.notify("gsd rebuild markdown: No database open. Run a GSD command first to initialize the DB.", "error");
612
+ return;
613
+ }
614
+ try {
615
+ invalidateStateCache();
616
+ const state = await deriveState(basePath);
617
+ const drifts = detectArtifactDbDrift(state, { basePath, state });
618
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
619
+ const quarantined = [];
620
+ const seen = new Set();
621
+ for (const drift of drifts) {
622
+ if (drift.kind !== "artifact-db-status-divergence")
623
+ continue;
624
+ if (drift.artifactType !== "SUMMARY" || !drift.artifactPath)
625
+ continue;
626
+ const absPath = resolveDiskArtifactPath(basePath, drift.artifactPath);
627
+ if (seen.has(absPath) || !existsSync(absPath))
628
+ continue;
629
+ seen.add(absPath);
630
+ const artifactDbPath = artifactPathForDb(basePath, absPath);
631
+ const target = quarantineProjectionFile(basePath, absPath, stamp);
632
+ deleteArtifactByPath(artifactDbPath);
633
+ quarantined.push(target);
634
+ }
635
+ const rendered = await renderAllFromDb(basePath);
636
+ invalidateStateCache();
637
+ const lines = [
638
+ "gsd rebuild markdown: rebuilt markdown projections from the canonical DB",
639
+ ` Rendered: ${rendered.rendered}`,
640
+ ` Skipped: ${rendered.skipped}`,
641
+ ` Quarantined: ${quarantined.length}`,
642
+ ];
643
+ if (rendered.errors.length > 0) {
644
+ lines.push(` Errors: ${rendered.errors.length}`);
645
+ for (const err of rendered.errors.slice(0, 5)) {
646
+ lines.push(` - ${err}`);
647
+ }
648
+ if (rendered.errors.length > 5) {
649
+ lines.push(` - ${rendered.errors.length - 5} more`);
650
+ }
651
+ }
652
+ if (quarantined.length > 0) {
653
+ lines.push("", " Quarantine:");
654
+ for (const target of quarantined.slice(0, 5)) {
655
+ lines.push(` - ${target}`);
656
+ }
657
+ if (quarantined.length > 5) {
658
+ lines.push(` - ${quarantined.length - 5} more`);
659
+ }
660
+ }
661
+ ctx.ui.notify(lines.join("\n"), rendered.errors.length > 0 ? "warning" : "success");
662
+ }
663
+ catch (err) {
664
+ const msg = err instanceof Error ? err.message : String(err);
665
+ logWarning("command", `rebuild failed: ${msg}`);
666
+ ctx.ui.notify(`gsd rebuild failed: ${msg}`, "error");
667
+ }
668
+ }
@@ -7,6 +7,7 @@
7
7
  * /gsd mcp — Overview of all servers (alias: /gsd mcp status)
8
8
  * /gsd mcp status — Same as bare /gsd mcp
9
9
  * /gsd mcp check <srv> — Detailed status for a specific server
10
+ * /gsd mcp discover [srv] — Connect and list tools for a server
10
11
  * /gsd mcp test <srv> — Test handshake + tools/list for a server
11
12
  * /gsd mcp enable <srv> / disable <srv> — Toggle local server exposure
12
13
  * /gsd mcp import <srv> [as <name>] — Copy a discovered server into local config
@@ -15,6 +16,7 @@
15
16
  import { resolve } from "node:path";
16
17
  import { ensureProjectWorkflowMcpConfig } from "./mcp-project-config.js";
17
18
  import { deleteProjectLocalMcpServer, readMcpManagementStatus, setProjectLocalMcpServerDisabled, testMcpServerConnection, upsertProjectLocalMcpServer, } from "../mcp-client/manager.js";
19
+ const MCP_STATUS_PROBE_TIMEOUT_MS = 10_000;
18
20
  export function hasHostMcpTool(systemPrompt, serverName) {
19
21
  const marker = `mcp__${serverName}__`;
20
22
  return systemPrompt.includes(marker);
@@ -48,21 +50,23 @@ export function formatMcpStatusReport(servers) {
48
50
  }
49
51
  const lines = [`MCP Server Status — ${servers.length} server(s)\n`];
50
52
  for (const s of servers) {
51
- const icon = s.disabled ? "⊘" : s.error ? "✗" : s.connected ? "✓" : "○";
53
+ const icon = s.disabled ? "⊘" : s.error ? "✗" : s.connected || s.available ? "✓" : "○";
52
54
  const status = s.disabled
53
55
  ? "disabled"
54
56
  : s.error
55
57
  ? `error: ${s.error}`
56
58
  : s.connected
57
59
  ? `connected — ${s.toolCount} tools`
58
- : "disconnected";
60
+ : s.available
61
+ ? `available — ${s.toolCount} tools`
62
+ : "disconnected";
59
63
  const warningText = s.envWarnings?.length ? ` — ${s.envWarnings.length} warning(s)` : "";
60
64
  lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}${warningText}`);
61
65
  }
62
66
  lines.push("");
63
67
  lines.push("Use /gsd mcp check <server> for details on a specific server.");
68
+ lines.push("Use /gsd mcp discover <server> to connect and list tools.");
64
69
  lines.push("Use /gsd mcp test <server> to verify handshake and tool discovery.");
65
- lines.push("Use mcp_discover to connect and list tools for a server.");
66
70
  return lines.join("\n");
67
71
  }
68
72
  export function formatMcpServerDetail(server) {
@@ -77,8 +81,8 @@ export function formatMcpServerDetail(server) {
77
81
  lines.push(` Status: error`);
78
82
  lines.push(` Error: ${server.error}`);
79
83
  }
80
- else if (server.connected) {
81
- lines.push(` Status: connected`);
84
+ else if (server.connected || server.available) {
85
+ lines.push(` Status: ${server.connected ? "connected" : "available"}`);
82
86
  lines.push(` Tools: ${server.toolCount}`);
83
87
  if (server.tools.length > 0) {
84
88
  lines.push("");
@@ -91,7 +95,7 @@ export function formatMcpServerDetail(server) {
91
95
  else {
92
96
  lines.push(` Status: disconnected`);
93
97
  lines.push("");
94
- lines.push(` Run mcp_discover("${server.name}") to connect and list tools.`);
98
+ lines.push(` Run /gsd mcp discover ${server.name} to connect and list tools.`);
95
99
  }
96
100
  if (server.envWarnings?.length) {
97
101
  lines.push("");
@@ -120,9 +124,70 @@ export function formatMcpConnectionTestResult(result) {
120
124
  ...(result.warnings.length > 0 ? ["", "Warnings:", ...result.warnings.map((warning) => ` - ${warning}`)] : []),
121
125
  ].join("\n");
122
126
  }
127
+ export function formatMcpDiscoveryResult(result) {
128
+ if (result.ok) {
129
+ return [
130
+ `MCP discovery completed for ${result.server}.`,
131
+ "",
132
+ `Transport: ${result.transport}`,
133
+ `Tools: ${result.toolCount}`,
134
+ ...(result.tools.length > 0 ? ["", "Discovered tools:", ...result.tools.map((tool) => ` - ${tool}`)] : []),
135
+ "",
136
+ `Call with: mcp_call(server="${result.server}", tool="<tool_name>", args={...})`,
137
+ ].join("\n");
138
+ }
139
+ return [
140
+ `MCP discovery failed for ${result.server}.`,
141
+ "",
142
+ `Transport: ${result.transport}`,
143
+ `Error: ${result.error ?? "Unknown error"}`,
144
+ ...(result.warnings.length > 0 ? ["", "Warnings:", ...result.warnings.map((warning) => ` - ${warning}`)] : []),
145
+ ].join("\n");
146
+ }
147
+ async function readLiveConnectionStatus(serverName) {
148
+ try {
149
+ const mcpClient = await import("../mcp-client/index.js");
150
+ const mod = mcpClient;
151
+ if (typeof mod.getConnectionStatus === "function") {
152
+ return mod.getConnectionStatus(serverName);
153
+ }
154
+ }
155
+ catch {
156
+ // mcp-client may not expose status helpers in some hosts.
157
+ }
158
+ return { connected: false, tools: [] };
159
+ }
160
+ function shouldProbeConfiguredServer(config) {
161
+ return !config.disabled && config.transport === "stdio" && (config.envWarnings?.length ?? 0) === 0;
162
+ }
163
+ async function resolveMcpRuntimeStatus(config, systemPrompt) {
164
+ const live = await readLiveConnectionStatus(config.name);
165
+ let connected = live.connected;
166
+ let tools = live.tools;
167
+ let error = live.error;
168
+ if (!connected && !error && hasHostMcpTool(systemPrompt, config.name))
169
+ connected = true;
170
+ if (!connected && !error && shouldProbeConfiguredServer(config)) {
171
+ const probed = await testMcpServerConnection(config.name, { timeoutMs: MCP_STATUS_PROBE_TIMEOUT_MS });
172
+ if (probed.ok) {
173
+ return {
174
+ connected: false,
175
+ available: true,
176
+ tools: probed.tools,
177
+ };
178
+ }
179
+ error = probed.error;
180
+ }
181
+ return {
182
+ connected,
183
+ available: false,
184
+ tools,
185
+ error,
186
+ };
187
+ }
123
188
  // ─── Command handler ────────────────────────────────────────────────────────
124
189
  /**
125
- * Handle `/gsd mcp [status|check <server>]`.
190
+ * Handle `/gsd mcp [status|check <server>|discover [server]|...]`.
126
191
  */
127
192
  export async function handleMcpStatus(args, ctx) {
128
193
  const trimmed = args.trim();
@@ -146,6 +211,24 @@ export async function handleMcpStatus(args, ctx) {
146
211
  }
147
212
  return;
148
213
  }
214
+ // /gsd mcp discover [server]
215
+ if (lowered === "discover" || lowered.startsWith("discover ")) {
216
+ const requestedServerName = trimmed.slice("discover".length).trim();
217
+ let serverName = requestedServerName;
218
+ if (!serverName) {
219
+ if (configs.length === 1) {
220
+ serverName = configs[0].name;
221
+ }
222
+ else {
223
+ const available = configs.map((config) => config.name).join(", ") || "(none)";
224
+ ctx.ui.notify(`Usage: /gsd mcp discover <server>\n\nAvailable: ${available}`, "warning");
225
+ return;
226
+ }
227
+ }
228
+ const result = await testMcpServerConnection(serverName);
229
+ ctx.ui.notify(formatMcpDiscoveryResult(result), result.ok ? "info" : "warning");
230
+ return;
231
+ }
149
232
  // /gsd mcp test <server>
150
233
  if (lowered.startsWith("test ")) {
151
234
  const serverName = trimmed.slice("test ".length).trim();
@@ -245,33 +328,15 @@ export async function handleMcpStatus(args, ctx) {
245
328
  ctx.ui.notify(`Unknown MCP server: "${serverName}"\n\nAvailable: ${available}`, "warning");
246
329
  return;
247
330
  }
248
- // Try to get connection/tool info from the mcp-client module if available
249
- let connected = false;
250
- let toolNames = [];
251
- let error;
252
- try {
253
- const mcpClient = await import("../mcp-client/index.js");
254
- // Access the module's connection state if exported; fall back gracefully
255
- const mod = mcpClient;
256
- if (typeof mod.getConnectionStatus === "function") {
257
- const status = mod.getConnectionStatus(serverName);
258
- connected = status.connected;
259
- toolNames = status.tools;
260
- error = status.error;
261
- }
262
- }
263
- catch {
264
- // mcp-client may not expose status helpers — that's fine
265
- }
266
- if (!connected && !error && hasHostMcpTool(systemPrompt, serverName))
267
- connected = true;
331
+ const runtime = await resolveMcpRuntimeStatus(config, systemPrompt);
268
332
  ctx.ui.notify(formatMcpServerDetail({
269
333
  name: config.name,
270
334
  transport: config.transport,
271
- connected,
272
- toolCount: toolNames.length,
273
- tools: toolNames,
274
- error,
335
+ connected: runtime.connected,
336
+ available: runtime.available,
337
+ toolCount: runtime.tools.length,
338
+ tools: runtime.tools,
339
+ error: runtime.error,
275
340
  disabled: config.disabled,
276
341
  sourcePath: config.sourcePath,
277
342
  envWarnings: config.envWarnings,
@@ -280,38 +345,20 @@ export async function handleMcpStatus(args, ctx) {
280
345
  }
281
346
  // /gsd mcp or /gsd mcp status
282
347
  if (!lowered || lowered === "status") {
283
- // Build status for each server
284
- const statuses = [];
285
- for (const config of configs) {
286
- let connected = false;
287
- let toolCount = 0;
288
- let error;
289
- try {
290
- const mcpClient = await import("../mcp-client/index.js");
291
- const mod = mcpClient;
292
- if (typeof mod.getConnectionStatus === "function") {
293
- const status = mod.getConnectionStatus(config.name);
294
- connected = status.connected;
295
- toolCount = status.tools.length;
296
- error = status.error;
297
- }
298
- }
299
- catch {
300
- // Fall back to unknown state
301
- }
302
- if (!connected && !error && hasHostMcpTool(systemPrompt, config.name))
303
- connected = true;
304
- statuses.push({
348
+ const statuses = await Promise.all(configs.map(async (config) => {
349
+ const runtime = await resolveMcpRuntimeStatus(config, systemPrompt);
350
+ return {
305
351
  name: config.name,
306
352
  transport: config.transport,
307
- connected,
308
- toolCount,
309
- error,
353
+ connected: runtime.connected,
354
+ available: runtime.available,
355
+ toolCount: runtime.tools.length,
356
+ error: runtime.error,
310
357
  disabled: config.disabled,
311
358
  sourcePath: config.sourcePath,
312
359
  envWarnings: config.envWarnings,
313
- });
314
- }
360
+ };
361
+ }));
315
362
  const warningLines = [
316
363
  ...management.warnings,
317
364
  ...management.duplicates.map((dup) => `Duplicate "${dup.name}" from ${dup.shadowedSourcePath} is shadowed by ${dup.keptSourcePath}.`),
@@ -323,9 +370,10 @@ export async function handleMcpStatus(args, ctx) {
323
370
  return;
324
371
  }
325
372
  // Unknown subcommand
326
- ctx.ui.notify("Usage: /gsd mcp [status|check <server>|test <server>|enable <server>|disable <server>|delete <server> --confirm|import <server> [as <name>]|init [dir]]\n\n" +
373
+ ctx.ui.notify("Usage: /gsd mcp [status|check <server>|discover [server]|test <server>|enable <server>|disable <server>|delete <server> --confirm|import <server> [as <name>]|init [dir]]\n\n" +
327
374
  " status Show all MCP server statuses (default)\n" +
328
375
  " check <server> Detailed status for a specific server\n" +
376
+ " discover [server] Connect and list tools for a server\n" +
329
377
  " test <server> Verify MCP handshake and tools/list\n" +
330
378
  " enable <server> Enable a local GSD-managed server\n" +
331
379
  " disable <server> Disable a local GSD-managed server\n" +
@@ -11,6 +11,8 @@ import { fileURLToPath } from "node:url";
11
11
  import { getGlobalGSDPreferencesPath, getLegacyGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, loadGlobalGSDPreferences, loadProjectGSDPreferences, loadEffectiveGSDPreferences, normalizePreferencesShape, resolveAllSkillReferences, } from "./preferences.js";
12
12
  import { loadFile, saveFile, splitFrontmatter, parseFrontmatterMap } from "./files.js";
13
13
  import { runClaudeImportFlow } from "./claude-import.js";
14
+ const DEFAULT_WIDGET_MODE = "small";
15
+ const WIDGET_MODE_OPTIONS = [DEFAULT_WIDGET_MODE, "full", "min", "off"];
14
16
  /** Extract body content after frontmatter closing delimiter, or null if none. */
15
17
  function extractBodyAfterFrontmatter(content) {
16
18
  const closingIdx = content.indexOf("\n---", content.indexOf("---"));
@@ -1509,7 +1511,7 @@ async function configureAdvanced(ctx, prefs) {
1509
1511
  else if (minRequestInterval !== undefined) {
1510
1512
  prefs.min_request_interval_ms = minRequestInterval;
1511
1513
  }
1512
- const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode, ["full", "small", "min", "off"], "full");
1514
+ const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode, WIDGET_MODE_OPTIONS, DEFAULT_WIDGET_MODE);
1513
1515
  if (widget !== undefined)
1514
1516
  prefs.widget_mode = widget;
1515
1517
  const experimental = prefs.experimental ?? {};
@@ -166,6 +166,6 @@ export async function handleVerdict(rawArgs, ctx, basePath) {
166
166
  ctx.ui.notify(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})`, "success");
167
167
  }
168
168
  if (effectiveVerdict === "needs-remediation") {
169
- ctx.ui.notify("Follow up with gsd_reassess_roadmap to add remediation slices, then re-run /gsd auto.", "info");
169
+ ctx.ui.notify("Follow up with /gsd dispatch reassess to add remediation slices, then re-run /gsd auto.", "info");
170
170
  }
171
171
  }
@@ -9,6 +9,7 @@
9
9
  import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
10
10
  import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
11
11
  import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, loadProjectGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, resolveDynamicRoutingConfig, resolveEffectiveProfile, resolveModelWithFallbacksForUnit, resolveAutoSupervisorConfig, } from "./preferences.js";
12
+ const DEFAULT_WIDGET_MODE = "small";
12
13
  function collectConfigSections() {
13
14
  const sections = [];
14
15
  const globalPrefs = loadGlobalGSDPreferences();
@@ -157,7 +158,7 @@ function collectConfigSections() {
157
158
  toggleRows.push({ label: "search_provider", value: prefs.search_provider });
158
159
  if (prefs?.context_selection)
159
160
  toggleRows.push({ label: "context_selection", value: prefs.context_selection });
160
- if (prefs?.widget_mode && prefs.widget_mode !== "full")
161
+ if (prefs?.widget_mode && prefs.widget_mode !== DEFAULT_WIDGET_MODE)
161
162
  toggleRows.push({ label: "widget_mode", value: prefs.widget_mode });
162
163
  if (prefs?.experimental?.rtk)
163
164
  toggleRows.push({ label: "experimental.rtk", value: "on" });
@@ -21,9 +21,10 @@ export function resetRetryState(state) {
21
21
  const PERMANENT_RE = /auth|unauthorized|forbidden|invalid.*key|invalid.*api|billing|quota exceeded|account/i;
22
22
  // Include provider-specific quota-window phrasing like:
23
23
  // - "You've hit your limit"
24
+ // - "You've reached your limit"
24
25
  // - "usage limit" / "quota reached"
25
26
  // - "out of extra usage"
26
- const RATE_LIMIT_RE = /rate.?limit|too many requests|429|hit your limit|usage limit|out of extra usage|quota (?:reached|hit)|limit.*resets?/i;
27
+ const RATE_LIMIT_RE = /rate.?limit|too many requests|429|(?:hit|reached) your (?:\w+ )?limit|(?:usage|session|weekly|daily|monthly|quota) limit|out of extra usage|quota (?:reached|hit)|limit.*resets?/i;
27
28
  // OpenRouter affordability-style quota errors should be treated as transient
28
29
  // so core retry logic can lower maxTokens and continue in-session.
29
30
  const AFFORDABILITY_RE = /requires more credits|can only afford|insufficient credits|not enough credits|fewer max_tokens/i;
@@ -247,6 +247,7 @@ function writeMeta(path, result, request, now) {
247
247
  id: result.id,
248
248
  runtime: result.runtime,
249
249
  purpose: request.purpose ?? null,
250
+ ...(request.metadata ? { metadata: request.metadata } : {}),
250
251
  script_chars: request.script.length,
251
252
  started_at: now.toISOString(),
252
253
  finished_at: new Date(now.getTime() + result.duration_ms).toISOString(),
@@ -260,6 +261,7 @@ function writeMeta(path, result, request, now) {
260
261
  stderr_truncated: result.stderr_truncated,
261
262
  stdout_path: result.stdout_path,
262
263
  stderr_path: result.stderr_path,
264
+ ...(request.metadata ? { metadata: request.metadata } : {}),
263
265
  };
264
266
  writeFileSync(path, `${JSON.stringify(meta, null, 2)}\n`);
265
267
  }