gsd-pi 2.59.0-dev.d77b3dd → 2.60.0-dev.2580e65

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 (198) hide show
  1. package/dist/resources/extensions/ask-user-questions.js +7 -4
  2. package/dist/resources/extensions/gsd/auto/phases.js +15 -7
  3. package/dist/resources/extensions/gsd/auto-dashboard.js +21 -8
  4. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -3
  5. package/dist/resources/extensions/gsd/auto-model-selection.js +58 -9
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +3 -2
  7. package/dist/resources/extensions/gsd/auto-prompts.js +36 -20
  8. package/dist/resources/extensions/gsd/auto-recovery.js +37 -18
  9. package/dist/resources/extensions/gsd/auto-start.js +9 -5
  10. package/dist/resources/extensions/gsd/auto-timers.js +11 -5
  11. package/dist/resources/extensions/gsd/auto-unit-closeout.js +5 -3
  12. package/dist/resources/extensions/gsd/auto-verification.js +3 -2
  13. package/dist/resources/extensions/gsd/auto-worktree.js +120 -55
  14. package/dist/resources/extensions/gsd/auto.js +39 -17
  15. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +6 -3
  16. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -2
  17. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +4 -10
  18. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +2 -1
  19. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
  20. package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -10
  21. package/dist/resources/extensions/gsd/commands/catalog.js +2 -0
  22. package/dist/resources/extensions/gsd/commands-codebase.js +48 -21
  23. package/dist/resources/extensions/gsd/commands-inspect.js +2 -1
  24. package/dist/resources/extensions/gsd/commands-maintenance.js +32 -19
  25. package/dist/resources/extensions/gsd/complexity-classifier.js +8 -4
  26. package/dist/resources/extensions/gsd/custom-verification.js +3 -2
  27. package/dist/resources/extensions/gsd/gsd-db.js +33 -13
  28. package/dist/resources/extensions/gsd/guided-flow.js +19 -9
  29. package/dist/resources/extensions/gsd/init-wizard.js +12 -0
  30. package/dist/resources/extensions/gsd/markdown-renderer.js +11 -9
  31. package/dist/resources/extensions/gsd/md-importer.js +5 -4
  32. package/dist/resources/extensions/gsd/milestone-actions.js +3 -2
  33. package/dist/resources/extensions/gsd/milestone-ids.js +2 -1
  34. package/dist/resources/extensions/gsd/model-router.js +156 -121
  35. package/dist/resources/extensions/gsd/parallel-merge.js +5 -3
  36. package/dist/resources/extensions/gsd/parallel-orchestrator.js +26 -14
  37. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  38. package/dist/resources/extensions/gsd/preferences-validation.js +45 -0
  39. package/dist/resources/extensions/gsd/preferences.js +15 -3
  40. package/dist/resources/extensions/gsd/prompt-loader.js +3 -2
  41. package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
  42. package/dist/resources/extensions/gsd/rule-registry.js +7 -6
  43. package/dist/resources/extensions/gsd/safe-fs.js +6 -8
  44. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
  45. package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -2
  46. package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
  47. package/dist/resources/extensions/gsd/tools/plan-milestone.js +3 -2
  48. package/dist/resources/extensions/gsd/tools/plan-slice.js +3 -2
  49. package/dist/resources/extensions/gsd/tools/plan-task.js +2 -1
  50. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +4 -4
  51. package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -1
  52. package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -1
  53. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -1
  54. package/dist/resources/extensions/gsd/tools/validate-milestone.js +2 -1
  55. package/dist/resources/extensions/gsd/triage-resolution.js +11 -4
  56. package/dist/resources/extensions/gsd/workflow-events.js +2 -1
  57. package/dist/resources/extensions/gsd/workflow-logger.js +37 -4
  58. package/dist/resources/extensions/gsd/workflow-migration.js +14 -12
  59. package/dist/resources/extensions/gsd/workflow-projections.js +2 -2
  60. package/dist/resources/extensions/gsd/workflow-reconcile.js +2 -2
  61. package/dist/resources/extensions/gsd/worktree-manager.js +26 -14
  62. package/dist/resources/extensions/shared/interview-ui.js +3 -1
  63. package/dist/web/standalone/.next/BUILD_ID +1 -1
  64. package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
  65. package/dist/web/standalone/.next/build-manifest.json +2 -2
  66. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  67. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  68. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.html +1 -1
  84. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app-paths-manifest.json +19 -19
  91. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  92. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  93. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  94. package/package.json +1 -1
  95. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
  97. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -1
  99. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  100. package/packages/pi-coding-agent/dist/core/extensions/runner.js +16 -0
  101. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  102. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +26 -0
  103. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  104. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  105. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  106. package/packages/pi-coding-agent/dist/core/lsp/config.js +6 -1
  107. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  108. package/packages/pi-coding-agent/dist/core/lsp/defaults.json +2 -2
  109. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts +2 -0
  110. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts.map +1 -0
  111. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js +47 -0
  112. package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js.map +1 -0
  113. package/packages/pi-coding-agent/package.json +1 -1
  114. package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
  115. package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -0
  116. package/packages/pi-coding-agent/src/core/extensions/types.ts +26 -0
  117. package/packages/pi-coding-agent/src/core/lsp/config.ts +7 -1
  118. package/packages/pi-coding-agent/src/core/lsp/defaults.json +2 -2
  119. package/packages/pi-coding-agent/src/core/lsp/lsp-legacy-alias.test.ts +70 -0
  120. package/pkg/package.json +1 -1
  121. package/src/resources/extensions/ask-user-questions.ts +7 -3
  122. package/src/resources/extensions/gsd/auto/phases.ts +17 -7
  123. package/src/resources/extensions/gsd/auto-dashboard.ts +22 -8
  124. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -3
  125. package/src/resources/extensions/gsd/auto-model-selection.ts +77 -15
  126. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -4
  127. package/src/resources/extensions/gsd/auto-prompts.ts +37 -20
  128. package/src/resources/extensions/gsd/auto-recovery.ts +38 -18
  129. package/src/resources/extensions/gsd/auto-start.ts +10 -9
  130. package/src/resources/extensions/gsd/auto-timers.ts +12 -5
  131. package/src/resources/extensions/gsd/auto-unit-closeout.ts +6 -2
  132. package/src/resources/extensions/gsd/auto-verification.ts +3 -6
  133. package/src/resources/extensions/gsd/auto-worktree.ts +121 -55
  134. package/src/resources/extensions/gsd/auto.ts +40 -17
  135. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +4 -3
  136. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +2 -2
  137. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +4 -16
  138. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +2 -1
  139. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
  140. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -10
  141. package/src/resources/extensions/gsd/commands/catalog.ts +2 -0
  142. package/src/resources/extensions/gsd/commands-codebase.ts +52 -20
  143. package/src/resources/extensions/gsd/commands-inspect.ts +2 -1
  144. package/src/resources/extensions/gsd/commands-maintenance.ts +28 -19
  145. package/src/resources/extensions/gsd/complexity-classifier.ts +9 -4
  146. package/src/resources/extensions/gsd/custom-verification.ts +3 -2
  147. package/src/resources/extensions/gsd/gsd-db.ts +12 -14
  148. package/src/resources/extensions/gsd/guided-flow.ts +9 -8
  149. package/src/resources/extensions/gsd/init-wizard.ts +12 -0
  150. package/src/resources/extensions/gsd/markdown-renderer.ts +11 -17
  151. package/src/resources/extensions/gsd/md-importer.ts +5 -4
  152. package/src/resources/extensions/gsd/milestone-actions.ts +3 -2
  153. package/src/resources/extensions/gsd/milestone-ids.ts +2 -1
  154. package/src/resources/extensions/gsd/model-router.ts +199 -173
  155. package/src/resources/extensions/gsd/parallel-merge.ts +5 -3
  156. package/src/resources/extensions/gsd/parallel-orchestrator.ts +18 -14
  157. package/src/resources/extensions/gsd/preferences-types.ts +13 -0
  158. package/src/resources/extensions/gsd/preferences-validation.ts +45 -0
  159. package/src/resources/extensions/gsd/preferences.ts +16 -3
  160. package/src/resources/extensions/gsd/prompt-loader.ts +3 -2
  161. package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
  162. package/src/resources/extensions/gsd/rule-registry.ts +7 -6
  163. package/src/resources/extensions/gsd/safe-fs.ts +6 -5
  164. package/src/resources/extensions/gsd/tests/capability-router.test.ts +347 -0
  165. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +63 -0
  166. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +27 -2
  167. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
  168. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1188 -0
  169. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +841 -0
  170. package/src/resources/extensions/gsd/tests/model-router.test.ts +403 -3
  171. package/src/resources/extensions/gsd/tests/preferences.test.ts +62 -0
  172. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +21 -0
  173. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +284 -0
  174. package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +120 -0
  175. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +6 -6
  176. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -6
  177. package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -6
  178. package/src/resources/extensions/gsd/tools/complete-task.ts +3 -6
  179. package/src/resources/extensions/gsd/tools/plan-milestone.ts +3 -6
  180. package/src/resources/extensions/gsd/tools/plan-slice.ts +3 -6
  181. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -3
  182. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +4 -6
  183. package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -3
  184. package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -3
  185. package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -3
  186. package/src/resources/extensions/gsd/tools/validate-milestone.ts +2 -3
  187. package/src/resources/extensions/gsd/triage-resolution.ts +11 -4
  188. package/src/resources/extensions/gsd/types.ts +1 -0
  189. package/src/resources/extensions/gsd/workflow-events.ts +2 -1
  190. package/src/resources/extensions/gsd/workflow-logger.ts +52 -5
  191. package/src/resources/extensions/gsd/workflow-migration.ts +14 -12
  192. package/src/resources/extensions/gsd/workflow-projections.ts +2 -2
  193. package/src/resources/extensions/gsd/workflow-reconcile.ts +2 -2
  194. package/src/resources/extensions/gsd/worktree-manager.ts +16 -14
  195. package/src/resources/extensions/shared/interview-ui.ts +3 -1
  196. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +144 -0
  197. /package/dist/web/standalone/.next/static/{t_cBZAENjaOJIRST3dw08 → ogyMN7M-3bGGuRY08L5HR}/_buildManifest.js +0 -0
  198. /package/dist/web/standalone/.next/static/{t_cBZAENjaOJIRST3dw08 → ogyMN7M-3bGGuRY08L5HR}/_ssgManifest.js +0 -0
@@ -34,7 +34,7 @@ import { clearSkillSnapshot } from "./skill-discovery.js";
34
34
  import { captureAvailableSkills, resetSkillTelemetry, } from "./skill-telemetry.js";
35
35
  import { getRtkSessionSavings } from "../shared/rtk-session-stats.js";
36
36
  import { initMetrics, resetMetrics, getLedger, getProjectTotals, formatCost, formatTokenCount, } from "./metrics.js";
37
- import { setLogBasePath } from "./workflow-logger.js";
37
+ import { setLogBasePath, logWarning } from "./workflow-logger.js";
38
38
  import { join } from "node:path";
39
39
  import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
40
40
  import { atomicWriteSync } from "./atomic-write.js";
@@ -137,8 +137,9 @@ export function getAutoDashboardData() {
137
137
  pendingCaptureCount = countPendingCaptures(s.basePath);
138
138
  }
139
139
  }
140
- catch {
140
+ catch (err) {
141
141
  // Non-fatal — captures module may not be loaded
142
+ logWarning("engine", `capture count failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
142
143
  }
143
144
  return {
144
145
  active: s.active,
@@ -340,8 +341,9 @@ function cleanupAfterLoopExit(ctx) {
340
341
  if (lockBase())
341
342
  releaseSessionLock(lockBase());
342
343
  }
343
- catch {
344
+ catch (err) {
344
345
  /* best-effort — mirror stopAuto cleanup */
346
+ logWarning("session", `lock cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
345
347
  }
346
348
  ctx.ui.setStatus("gsd-auto", undefined);
347
349
  ctx.ui.setWidget("gsd-progress", undefined);
@@ -352,8 +354,9 @@ function cleanupAfterLoopExit(ctx) {
352
354
  try {
353
355
  process.chdir(s.basePath);
354
356
  }
355
- catch {
357
+ catch (err) {
356
358
  /* best-effort */
359
+ logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
357
360
  }
358
361
  }
359
362
  }
@@ -415,8 +418,9 @@ export async function stopAuto(ctx, pi, reason) {
415
418
  milestoneComplete = true;
416
419
  }
417
420
  }
418
- catch {
421
+ catch (err) {
419
422
  // Non-fatal — fall through to preserveBranch path
423
+ logWarning("engine", `milestone summary check failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
420
424
  }
421
425
  if (milestoneComplete) {
422
426
  // Milestone is complete — merge worktree branch back to main
@@ -452,8 +456,9 @@ export async function stopAuto(ctx, pi, reason) {
452
456
  try {
453
457
  process.chdir(s.basePath);
454
458
  }
455
- catch {
459
+ catch (err) {
456
460
  /* best-effort */
461
+ logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
457
462
  }
458
463
  }
459
464
  }
@@ -522,7 +527,9 @@ export async function stopAuto(ctx, pi, reason) {
522
527
  if (existsSync(pausedPath))
523
528
  unlinkSync(pausedPath);
524
529
  }
525
- catch { /* non-fatal */ }
530
+ catch (err) { /* non-fatal */
531
+ logWarning("engine", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
532
+ }
526
533
  // ── Step 13: Restore original model (before reset clears IDs) ──
527
534
  try {
528
535
  if (pi && ctx && s.originalModelId && s.originalModelProvider) {
@@ -556,7 +563,9 @@ export async function stopAuto(ctx, pi, reason) {
556
563
  await closeBrowser();
557
564
  }
558
565
  }
559
- catch { /* non-fatal: browser-tools may not be loaded */ }
566
+ catch (err) { /* non-fatal: browser-tools may not be loaded */
567
+ logWarning("engine", `browser teardown failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
568
+ }
560
569
  // External cleanup (not covered by session reset)
561
570
  clearInFlightTools();
562
571
  clearSliceProgressCache();
@@ -602,16 +611,18 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
602
611
  mkdirSync(runtimeDir, { recursive: true });
603
612
  writeFileSync(join(runtimeDir, "paused-session.json"), JSON.stringify(pausedMeta, null, 2), "utf-8");
604
613
  }
605
- catch {
614
+ catch (err) {
606
615
  // Non-fatal — resume will still work via full bootstrap, just without worktree context
616
+ logWarning("engine", `paused-session file write failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
607
617
  }
608
618
  // Close out the current unit so its runtime record doesn't stay at "dispatched"
609
619
  if (s.currentUnit && ctx) {
610
620
  try {
611
621
  await closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt);
612
622
  }
613
- catch {
623
+ catch (err) {
614
624
  // Non-fatal — best-effort closeout on pause
625
+ logWarning("engine", `unit closeout on pause failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
615
626
  }
616
627
  s.currentUnit = null;
617
628
  }
@@ -798,7 +809,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
798
809
  try {
799
810
  unlinkSync(pausedPath);
800
811
  }
801
- catch { /* non-fatal */ }
812
+ catch (err) { /* non-fatal */
813
+ logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
814
+ }
802
815
  ctx.ui.notify(`Resuming paused custom workflow${meta.activeRunDir ? ` (${meta.activeRunDir})` : ""}.`, "info");
803
816
  }
804
817
  else if (meta.milestoneId) {
@@ -810,7 +823,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
810
823
  try {
811
824
  unlinkSync(pausedPath);
812
825
  }
813
- catch { /* non-fatal */ }
826
+ catch (err) { /* non-fatal */
827
+ logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
828
+ }
814
829
  ctx.ui.notify(`Paused milestone ${meta.milestoneId} is ${!mDir ? "missing" : "already complete"}. Starting fresh.`, "info");
815
830
  }
816
831
  else {
@@ -822,14 +837,17 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
822
837
  try {
823
838
  unlinkSync(pausedPath);
824
839
  }
825
- catch { /* non-fatal */ }
840
+ catch (err) { /* non-fatal */
841
+ logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
842
+ }
826
843
  ctx.ui.notify(`Resuming paused session for ${meta.milestoneId}${meta.worktreePath ? ` (worktree)` : ""}.`, "info");
827
844
  }
828
845
  }
829
846
  }
830
847
  }
831
- catch {
848
+ catch (err) {
832
849
  // Malformed or missing — proceed with fresh bootstrap
850
+ logWarning("session", `paused-session restore failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
833
851
  }
834
852
  }
835
853
  if (s.paused) {
@@ -917,8 +935,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
917
935
  try {
918
936
  syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
919
937
  }
920
- catch {
938
+ catch (err) {
921
939
  // Best-effort only — sidebar sync must never block auto-mode startup
940
+ logWarning("engine", `cmux sync failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
922
941
  }
923
942
  logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
924
943
  // Dispatch the first unit
@@ -1043,8 +1062,9 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
1043
1062
  try {
1044
1063
  await pi.setModel(match);
1045
1064
  }
1046
- catch {
1065
+ catch (err) {
1047
1066
  /* non-fatal */
1067
+ logWarning("dispatch", `hook model set failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1048
1068
  }
1049
1069
  }
1050
1070
  else {
@@ -1072,7 +1092,9 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
1072
1092
  if (process.cwd() !== s.basePath)
1073
1093
  process.chdir(s.basePath);
1074
1094
  }
1075
- catch { }
1095
+ catch (err) {
1096
+ logWarning("engine", `chdir failed before hook dispatch: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1097
+ }
1076
1098
  debugLog("dispatchHookUnit", {
1077
1099
  phase: "send-message",
1078
1100
  promptLength: hookPrompt.length,
@@ -1,3 +1,4 @@
1
+ import { logWarning } from "../workflow-logger.js";
1
2
  import { checkAutoStartAfterDiscuss } from "../guided-flow.js";
2
3
  import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto } from "../auto.js";
3
4
  import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
@@ -68,7 +69,9 @@ export async function handleAgentEnd(pi, event, ctx) {
68
69
  try {
69
70
  await pauseAuto(ctx, pi);
70
71
  }
71
- catch { /* best-effort */ }
72
+ catch (e) {
73
+ logWarning("bootstrap", `pauseAuto failed after empty-content abort: ${e.message}`);
74
+ }
72
75
  }
73
76
  return;
74
77
  }
@@ -184,8 +187,8 @@ export async function handleAgentEnd(pi, event, ctx) {
184
187
  try {
185
188
  await pauseAuto(ctx, pi);
186
189
  }
187
- catch {
188
- // best-effort
190
+ catch (e) {
191
+ logWarning("bootstrap", `pauseAuto failed in agent_end handler: ${e.message}`);
189
192
  }
190
193
  }
191
194
  }
@@ -403,8 +403,8 @@ export function registerDbTools(pi) {
403
403
  const { insertMilestone } = await import("../gsd-db.js");
404
404
  insertMilestone({ id: milestoneId, status: "queued" });
405
405
  }
406
- catch {
407
- // Non-fatal the safety-net in deriveStateFromDb will catch this
406
+ catch (e) {
407
+ logError("tool", `insertMilestone failed for ${milestoneId}: ${e.message}`);
408
408
  }
409
409
  }
410
410
  const milestoneGenerateIdTool = {
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { join, sep } from "node:path";
3
3
  import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@gsd/pi-coding-agent";
4
4
  import { DEFAULT_BASH_TIMEOUT_SECS } from "../constants.js";
5
- import { setLogBasePath } from "../workflow-logger.js";
5
+ import { setLogBasePath, logWarning } from "../workflow-logger.js";
6
6
  /**
7
7
  * Resolve the correct DB path for the current working directory.
8
8
  * If `basePath` is inside a `.gsd/worktrees/<MID>/` directory, returns
@@ -82,7 +82,7 @@ export async function ensureDbOpen() {
82
82
  migrateFromMarkdown(basePath);
83
83
  }
84
84
  catch (err) {
85
- process.stderr.write(`gsd-db: ensureDbOpen auto-migration failed: ${err.message}\n`);
85
+ logWarning("bootstrap", `ensureDbOpen auto-migration failed: ${err.message}`);
86
86
  }
87
87
  }
88
88
  return opened;
@@ -93,17 +93,11 @@ export async function ensureDbOpen() {
93
93
  setLogBasePath(projectRoot);
94
94
  return opened;
95
95
  }
96
- process.stderr.write(`gsd-db: ensureDbOpen failed — no .gsd directory found (resolvedPath=${resolveProjectRootDbPath(basePath)}, cwd=${basePath})\n`);
96
+ logWarning("bootstrap", "ensureDbOpen failed — no .gsd directory found");
97
97
  return false;
98
98
  }
99
99
  catch (err) {
100
- const basePath = process.cwd();
101
- const diagnostic = {
102
- resolvedPath: resolveProjectRootDbPath(basePath),
103
- cwd: basePath,
104
- error: err.message ?? String(err),
105
- };
106
- process.stderr.write(`gsd-db: ensureDbOpen failed — ${JSON.stringify(diagnostic)}\n`);
100
+ logWarning("bootstrap", `ensureDbOpen failed: ${err.message ?? String(err)}`);
107
101
  return false;
108
102
  }
109
103
  }
@@ -1,5 +1,6 @@
1
1
  import { Type } from "@sinclair/typebox";
2
2
  import { queryJournal } from "../journal.js";
3
+ import { logWarning } from "../workflow-logger.js";
3
4
  export function registerJournalTools(pi) {
4
5
  pi.registerTool({
5
6
  name: "gsd_journal_query",
@@ -51,7 +52,7 @@ export function registerJournalTools(pi) {
51
52
  }
52
53
  catch (err) {
53
54
  const msg = err instanceof Error ? err.message : String(err);
54
- process.stderr.write(`gsd-journal: gsd_journal_query tool failed: ${msg}\n`);
55
+ logWarning("tool", `gsd_journal_query tool failed: ${msg}`);
55
56
  return {
56
57
  content: [{ type: "text", text: `Error querying journal: ${msg}` }],
57
58
  details: { operation: "journal_query", error: msg },
@@ -303,4 +303,11 @@ export function registerHooks(pi) {
303
303
  payload.service_tier = tier;
304
304
  return payload;
305
305
  });
306
+ // Capability-aware model routing hook (ADR-004)
307
+ // Extensions can override model selection by returning { modelId: "..." }
308
+ // Return undefined to let the built-in capability scoring proceed.
309
+ pi.on("before_model_select", async (_event) => {
310
+ // Default: no override — let capability scoring handle selection
311
+ return undefined;
312
+ });
306
313
  }
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync, unlinkSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
+ import { logWarning } from "../workflow-logger.js";
4
5
  import { debugTime } from "../debug-logger.js";
5
6
  import { loadPrompt } from "../prompt-loader.js";
6
7
  import { readForensicsMarker } from "../forensics.js";
@@ -61,8 +62,8 @@ export async function buildBeforeAgentStartResult(event, ctx) {
61
62
  }
62
63
  }
63
64
  }
64
- catch {
65
- // non-fatal
65
+ catch (e) {
66
+ logWarning("bootstrap", `memory block fetch failed: ${e.message}`);
66
67
  }
67
68
  let newSkillsBlock = "";
68
69
  if (hasSkillSnapshot()) {
@@ -88,8 +89,8 @@ export async function buildBeforeAgentStartResult(event, ctx) {
88
89
  codebaseBlock = `\n\n[PROJECT CODEBASE — File structure and descriptions (generated ${generatedAt}, may be stale — run /gsd codebase update to refresh)]\n\n${content}`;
89
90
  }
90
91
  }
91
- catch {
92
- // skip
92
+ catch (e) {
93
+ logWarning("bootstrap", `CODEBASE file read failed: ${e.message}`);
93
94
  }
94
95
  }
95
96
  warnDeprecatedAgentInstructions();
@@ -128,8 +129,8 @@ export function loadKnowledgeBlock(gsdHomeDir, cwd) {
128
129
  globalKnowledge = content;
129
130
  }
130
131
  }
131
- catch {
132
- // skip
132
+ catch (e) {
133
+ logWarning("bootstrap", `global knowledge file read failed: ${e.message}`);
133
134
  }
134
135
  }
135
136
  // 2. Project knowledge (.gsd/KNOWLEDGE.md) — project-specific
@@ -141,8 +142,8 @@ export function loadKnowledgeBlock(gsdHomeDir, cwd) {
141
142
  if (content)
142
143
  projectKnowledge = content;
143
144
  }
144
- catch {
145
- // skip
145
+ catch (e) {
146
+ logWarning("bootstrap", `project knowledge file read failed: ${e.message}`);
146
147
  }
147
148
  }
148
149
  if (!globalKnowledge && !projectKnowledge) {
@@ -381,8 +382,8 @@ export function clearForensicsMarker(basePath) {
381
382
  try {
382
383
  unlinkSync(markerPath);
383
384
  }
384
- catch {
385
- // non-fatal
385
+ catch (e) {
386
+ logWarning("bootstrap", `unlinkSync forensics marker failed: ${e.message}`);
386
387
  }
387
388
  }
388
389
  }
@@ -216,8 +216,10 @@ const NESTED_COMPLETIONS = {
216
216
  codebase: [
217
217
  { cmd: "generate", desc: "Generate or regenerate CODEBASE.md" },
218
218
  { cmd: "generate --max-files", desc: "Generate with custom file limit (default: 500)" },
219
+ { cmd: "generate --collapse-threshold", desc: "Generate with custom collapse threshold (default: 20)" },
219
220
  { cmd: "update", desc: "Incremental update (preserves descriptions)" },
220
221
  { cmd: "update --max-files", desc: "Update with custom file limit" },
222
+ { cmd: "update --collapse-threshold", desc: "Update with custom collapse threshold" },
221
223
  { cmd: "stats", desc: "Show file count, description coverage, and generation time" },
222
224
  { cmd: "help", desc: "Show usage and available subcommands" },
223
225
  ],
@@ -5,26 +5,32 @@
5
5
  * Subcommands: generate, update, stats, help
6
6
  */
7
7
  import { generateCodebaseMap, updateCodebaseMap, writeCodebaseMap, getCodebaseMapStats, readCodebaseMap, } from "./codebase-generator.js";
8
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
8
9
  const USAGE = "Usage: /gsd codebase [generate|update|stats]\n\n" +
9
- " generate [--max-files N] — Generate or regenerate CODEBASE.md\n" +
10
- " update — Incremental update (preserves descriptions)\n" +
11
- " stats — Show file count, coverage, and generation time\n" +
12
- " help — Show this help\n\n" +
13
- "With no subcommand, shows stats if a map exists or help if not.";
10
+ " generate [--max-files N] [--collapse-threshold N] — Generate or regenerate CODEBASE.md\n" +
11
+ " update [--max-files N] [--collapse-threshold N] — Incremental update (preserves descriptions)\n" +
12
+ " stats — Show file count, coverage, and generation time\n" +
13
+ " help — Show this help\n\n" +
14
+ "With no subcommand, shows stats if a map exists or help if not.\n\n" +
15
+ "Configure defaults via preferences.md:\n" +
16
+ " codebase:\n" +
17
+ " exclude_patterns: [\"docs/\", \"fixtures/\"]\n" +
18
+ " max_files: 1000\n" +
19
+ " collapse_threshold: 15";
14
20
  export async function handleCodebase(args, ctx, _pi) {
15
21
  const basePath = process.cwd();
16
22
  const parts = args.trim().split(/\s+/);
17
23
  const sub = parts[0] ?? "";
18
24
  switch (sub) {
19
25
  case "generate": {
20
- const maxFiles = parseMaxFiles(args, ctx);
21
- if (maxFiles === false)
26
+ const options = resolveCodebaseOptions(args, ctx);
27
+ if (options === false)
22
28
  return; // validation failed, message already shown
23
29
  const existing = readCodebaseMap(basePath);
24
30
  const existingDescriptions = existing
25
31
  ? (await import("./codebase-generator.js")).parseCodebaseMap(existing)
26
32
  : undefined;
27
- const result = generateCodebaseMap(basePath, { maxFiles: maxFiles ?? undefined }, existingDescriptions);
33
+ const result = generateCodebaseMap(basePath, options, existingDescriptions);
28
34
  if (result.fileCount === 0) {
29
35
  ctx.ui.notify("Codebase map generated with 0 files.\n" +
30
36
  "Is this a git repository? Run 'git ls-files' to verify.", "warning");
@@ -42,10 +48,10 @@ export async function handleCodebase(args, ctx, _pi) {
42
48
  ctx.ui.notify("No codebase map found. Run /gsd codebase generate to create one.", "warning");
43
49
  return;
44
50
  }
45
- const maxFiles = parseMaxFiles(args, ctx);
46
- if (maxFiles === false)
51
+ const options = resolveCodebaseOptions(args, ctx);
52
+ if (options === false)
47
53
  return;
48
- const result = updateCodebaseMap(basePath, { maxFiles: maxFiles ?? undefined });
54
+ const result = updateCodebaseMap(basePath, options);
49
55
  writeCodebaseMap(basePath, result.content);
50
56
  ctx.ui.notify(`Codebase map updated: ${result.fileCount} files\n` +
51
57
  ` Added: ${result.added} | Removed: ${result.removed} | Unchanged: ${result.unchanged}` +
@@ -93,19 +99,40 @@ function showStats(basePath, ctx) {
93
99
  : `Coverage is complete.`), "info");
94
100
  }
95
101
  /**
96
- * Parse and validate --max-files flag.
97
- * Returns the parsed number, undefined if flag not present, or false if invalid.
102
+ * Resolve codebase map options by merging preferences with CLI flags.
103
+ * CLI flags override preferences; preferences override built-in defaults.
104
+ * Returns false if validation failed (error already shown to user).
98
105
  */
99
- function parseMaxFiles(args, ctx) {
106
+ function resolveCodebaseOptions(args, ctx) {
107
+ // Load preferences defaults
108
+ const prefs = loadEffectiveGSDPreferences()?.preferences?.codebase;
109
+ // Parse CLI flags
100
110
  const maxFilesStr = extractFlag(args, "--max-files");
101
- if (!maxFilesStr)
102
- return undefined;
103
- const maxFiles = parseInt(maxFilesStr, 10);
104
- if (isNaN(maxFiles) || maxFiles < 1) {
105
- ctx.ui.notify("--max-files must be a positive integer (e.g. --max-files 200).", "warning");
106
- return false;
111
+ const collapseStr = extractFlag(args, "--collapse-threshold");
112
+ // Validate --max-files
113
+ let maxFiles;
114
+ if (maxFilesStr) {
115
+ maxFiles = parseInt(maxFilesStr, 10);
116
+ if (isNaN(maxFiles) || maxFiles < 1) {
117
+ ctx.ui.notify("--max-files must be a positive integer (e.g. --max-files 200).", "warning");
118
+ return false;
119
+ }
120
+ }
121
+ // Validate --collapse-threshold
122
+ let collapseThreshold;
123
+ if (collapseStr) {
124
+ collapseThreshold = parseInt(collapseStr, 10);
125
+ if (isNaN(collapseThreshold) || collapseThreshold < 1) {
126
+ ctx.ui.notify("--collapse-threshold must be a positive integer (e.g. --collapse-threshold 15).", "warning");
127
+ return false;
128
+ }
107
129
  }
108
- return maxFiles;
130
+ return {
131
+ // CLI flags override preferences
132
+ maxFiles: maxFiles ?? prefs?.max_files,
133
+ collapseThreshold: collapseThreshold ?? prefs?.collapse_threshold,
134
+ excludePatterns: prefs?.exclude_patterns,
135
+ };
109
136
  }
110
137
  function extractFlag(args, flag) {
111
138
  const escaped = flag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -6,6 +6,7 @@
6
6
  import { existsSync } from "node:fs";
7
7
  import { join } from "node:path";
8
8
  import { gsdRoot } from "./paths.js";
9
+ import { logWarning } from "./workflow-logger.js";
9
10
  import { getErrorMessage } from "./error-utils.js";
10
11
  export function formatInspectOutput(data) {
11
12
  const lines = [];
@@ -71,7 +72,7 @@ export async function handleInspect(ctx) {
71
72
  ctx.ui.notify(formatInspectOutput(data), "info");
72
73
  }
73
74
  catch (err) {
74
- process.stderr.write(`gsd-db: /gsd inspect failed: ${getErrorMessage(err)}\n`);
75
+ logWarning("command", `/gsd inspect failed: ${getErrorMessage(err)}`);
75
76
  ctx.ui.notify("Failed to inspect GSD database. Check stderr for details.", "error");
76
77
  }
77
78
  }
@@ -5,12 +5,14 @@
5
5
  */
6
6
  import { deriveState } from "./state.js";
7
7
  import { nativeBranchList, nativeDetectMainBranch, nativeBranchListMerged, nativeBranchDelete, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
8
+ import { logWarning } from "./workflow-logger.js";
8
9
  export async function handleCleanupBranches(ctx, basePath) {
9
10
  let branches;
10
11
  try {
11
12
  branches = nativeBranchList(basePath, "gsd/*");
12
13
  }
13
- catch {
14
+ catch (e) {
15
+ logWarning("command", `branch list failed: ${e.message}`);
14
16
  ctx.ui.notify("No GSD branches to clean up.", "info");
15
17
  return;
16
18
  }
@@ -20,7 +22,8 @@ export async function handleCleanupBranches(ctx, basePath) {
20
22
  try {
21
23
  merged = nativeBranchListMerged(basePath, mainBranch, "gsd/*");
22
24
  }
23
- catch {
25
+ catch (e) {
26
+ logWarning("command", `merged branch list failed: ${e.message}`);
24
27
  merged = [];
25
28
  }
26
29
  const mergedNonQuick = merged.filter((b) => !b.startsWith("gsd/quick/"));
@@ -30,8 +33,8 @@ export async function handleCleanupBranches(ctx, basePath) {
30
33
  nativeBranchDelete(basePath, branch, false);
31
34
  deletedMerged++;
32
35
  }
33
- catch {
34
- /* skip branches that cannot be deleted */
36
+ catch (e) {
37
+ logWarning("command", `branch delete failed for ${branch}: ${e.message}`);
35
38
  }
36
39
  }
37
40
  // Also delete stale milestone branches for completed milestones when detached
@@ -61,7 +64,9 @@ export async function handleCleanupBranches(ctx, basePath) {
61
64
  nativeBranchDelete(basePath, branch, true);
62
65
  deletedStaleMilestones++;
63
66
  }
64
- catch { /* non-fatal */ }
67
+ catch (e) {
68
+ logWarning("command", `stale milestone branch delete failed for ${branch}: ${e.message}`);
69
+ }
65
70
  continue;
66
71
  }
67
72
  }
@@ -73,7 +78,8 @@ export async function handleCleanupBranches(ctx, basePath) {
73
78
  try {
74
79
  roadmapContent = await loadFile(roadmapPath);
75
80
  }
76
- catch {
81
+ catch (e) {
82
+ logWarning("command", `loadFile failed for ${roadmapPath}: ${e.message}`);
77
83
  roadmapContent = null;
78
84
  }
79
85
  if (!roadmapContent)
@@ -84,13 +90,13 @@ export async function handleCleanupBranches(ctx, basePath) {
84
90
  nativeBranchDelete(basePath, branch, true);
85
91
  deletedStaleMilestones++;
86
92
  }
87
- catch {
88
- /* non-fatal */
93
+ catch (e) {
94
+ logWarning("command", `milestone branch delete failed for ${branch}: ${e.message}`);
89
95
  }
90
96
  }
91
97
  }
92
- catch {
93
- /* non-fatal */
98
+ catch (e) {
99
+ logWarning("command", `stale milestone cleanup failed: ${e.message}`);
94
100
  }
95
101
  const summary = [];
96
102
  if (deletedMerged > 0) {
@@ -116,7 +122,8 @@ export async function handleCleanupSnapshots(ctx, basePath) {
116
122
  try {
117
123
  refs = nativeForEachRef(basePath, "refs/gsd/snapshots/");
118
124
  }
119
- catch {
125
+ catch (e) {
126
+ logWarning("command", `snapshot ref list failed: ${e.message}`);
120
127
  ctx.ui.notify("No snapshot refs to clean up.", "info");
121
128
  return;
122
129
  }
@@ -140,8 +147,8 @@ export async function handleCleanupSnapshots(ctx, basePath) {
140
147
  nativeUpdateRef(basePath, old);
141
148
  pruned++;
142
149
  }
143
- catch {
144
- /* skip individual failures */
150
+ catch (e) {
151
+ logWarning("command", `snapshot ref update failed for ${old}: ${e.message}`);
145
152
  }
146
153
  }
147
154
  }
@@ -155,7 +162,8 @@ export async function handleCleanupWorktrees(ctx, basePath) {
155
162
  try {
156
163
  statuses = getAllWorktreeHealth(basePath);
157
164
  }
158
- catch {
165
+ catch (e) {
166
+ logWarning("command", `worktree health inspection failed: ${e.message}`);
159
167
  ctx.ui.notify("Failed to inspect worktrees.", "error");
160
168
  return;
161
169
  }
@@ -185,7 +193,8 @@ export async function handleCleanupWorktrees(ctx, basePath) {
185
193
  lines.push(` ✓ ${wt.name} removed (branch ${wt.branch} deleted)`);
186
194
  removed++;
187
195
  }
188
- catch {
196
+ catch (e) {
197
+ logWarning("command", `worktree removal failed for ${wt.name}: ${e.message}`);
189
198
  lines.push(` ✗ ${wt.name} failed to remove`);
190
199
  }
191
200
  }
@@ -228,7 +237,9 @@ export async function handleSkip(unitArg, ctx, basePath) {
228
237
  keys = JSON.parse(readFile(completedKeysFile, "utf-8"));
229
238
  }
230
239
  }
231
- catch { /* start fresh */ }
240
+ catch (e) {
241
+ logWarning("command", `completed-units.json parse failed: ${e.message}`);
242
+ }
232
243
  // Normalize: accept "execute-task/M001/S01/T03", "M001/S01/T03", or just "T03"
233
244
  let skipKey = unitArg;
234
245
  if (!skipKey.includes("execute-task") && !skipKey.includes("plan-") && !skipKey.includes("research-") && !skipKey.includes("complete-")) {
@@ -339,7 +350,8 @@ export async function handleCleanupProjects(args, ctx) {
339
350
  .filter(e => e.isDirectory())
340
351
  .map(e => e.name);
341
352
  }
342
- catch {
353
+ catch (e) {
354
+ logWarning("command", `readdir failed for project-state directory: ${e.message}`);
343
355
  ctx.ui.notify(`Failed to read project-state directory at ${projectsDir}.`, "error");
344
356
  return;
345
357
  }
@@ -413,7 +425,8 @@ export async function handleCleanupProjects(args, ctx) {
413
425
  fsRmSync(pathJoin(projectsDir, e.hash), { recursive: true, force: true });
414
426
  removed++;
415
427
  }
416
- catch {
428
+ catch (err) {
429
+ logWarning("command", `project cleanup rm failed for ${e.hash}: ${err.message}`);
417
430
  failed.push(e.hash);
418
431
  }
419
432
  }
@@ -479,7 +492,7 @@ export async function handleRecover(ctx, basePath) {
479
492
  }
480
493
  catch (err) {
481
494
  const msg = err instanceof Error ? err.message : String(err);
482
- process.stderr.write(`gsd-recover: failed: ${msg}\n`);
495
+ logWarning("command", `recover failed: ${msg}`);
483
496
  ctx.ui.notify(`gsd recover failed: ${msg}`, "error");
484
497
  }
485
498
  }