gsd-pi 2.79.0-dev.ece5fd8ba → 2.80.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 (193) hide show
  1. package/dist/loader.js +0 -0
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/contracts.js +1 -0
  4. package/dist/resources/extensions/gsd/auto/orchestrator.js +146 -0
  5. package/dist/resources/extensions/gsd/auto/phases.js +55 -6
  6. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  7. package/dist/resources/extensions/gsd/auto-recovery.js +45 -52
  8. package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -0
  9. package/dist/resources/extensions/gsd/auto.js +159 -2
  10. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  11. package/dist/resources/extensions/gsd/gsd-db.js +34 -1
  12. package/dist/resources/extensions/gsd/post-execution-checks.js +25 -6
  13. package/dist/resources/extensions/shared/interview-ui.js +15 -4
  14. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  15. package/dist/web/standalone/.next/BUILD_ID +1 -1
  16. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  17. package/dist/web/standalone/.next/build-manifest.json +3 -3
  18. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  19. package/dist/web/standalone/.next/required-server-files.json +3 -3
  20. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  21. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  22. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  23. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  31. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  33. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  34. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  35. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  47. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  59. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  79. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  89. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  95. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  111. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  115. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/index.html +1 -1
  125. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  126. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  127. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  128. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  130. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/page.js +2 -2
  132. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  134. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  135. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  136. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/middleware.js +2 -2
  138. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  140. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  141. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  142. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  143. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
  144. package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
  145. package/dist/web/standalone/.next/static/chunks/app/page-ff639266d978f2a0.js +1 -0
  146. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
  147. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
  148. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  149. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  150. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  151. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  152. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  153. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  154. package/dist/web/standalone/server.js +1 -1
  155. package/package.json +1 -1
  156. package/packages/daemon/package.json +2 -2
  157. package/packages/mcp-server/package.json +2 -2
  158. package/packages/native/package.json +1 -1
  159. package/packages/pi-agent-core/package.json +1 -1
  160. package/packages/pi-ai/package.json +1 -1
  161. package/packages/pi-coding-agent/package.json +1 -1
  162. package/packages/pi-tui/package.json +1 -1
  163. package/packages/rpc-client/package.json +1 -1
  164. package/pkg/package.json +1 -1
  165. package/src/resources/extensions/gsd/auto/contracts.ts +87 -0
  166. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -3
  167. package/src/resources/extensions/gsd/auto/orchestrator.ts +161 -0
  168. package/src/resources/extensions/gsd/auto/phases.ts +82 -8
  169. package/src/resources/extensions/gsd/auto/session.ts +11 -0
  170. package/src/resources/extensions/gsd/auto-recovery.ts +42 -50
  171. package/src/resources/extensions/gsd/auto-runtime-state.ts +7 -0
  172. package/src/resources/extensions/gsd/auto.ts +167 -1
  173. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +14 -1
  174. package/src/resources/extensions/gsd/gsd-db.ts +35 -1
  175. package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
  176. package/src/resources/extensions/gsd/post-execution-checks.ts +31 -6
  177. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +32 -0
  178. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +353 -0
  179. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +39 -0
  180. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +3 -0
  181. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +95 -0
  182. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +79 -0
  183. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +134 -0
  184. package/src/resources/extensions/gsd/tests/paused-session-via-db.test.ts +2 -0
  185. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +27 -0
  186. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +46 -0
  187. package/src/resources/extensions/shared/interview-ui.ts +18 -5
  188. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +41 -0
  189. package/dist/web/standalone/.next/static/chunks/app/page-fab3ebb85b006001.js +0 -1
  190. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
  191. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
  192. /package/dist/web/standalone/.next/static/{TzEVJ1Lh8vbez4n4Q9TqQ → V-3Ehy4B24f9FCGiLPWIM}/_buildManifest.js +0 -0
  193. /package/dist/web/standalone/.next/static/{TzEVJ1Lh8vbez4n4Q9TqQ → V-3Ehy4B24f9FCGiLPWIM}/_ssgManifest.js +0 -0
@@ -31,7 +31,7 @@ import { selectAndApplyModel, resolveModelId, clearToolBaseline } from "./auto-m
31
31
  import { resetRoutingHistory, recordOutcome } from "./routing-history.js";
32
32
  import { resetHookState, runPreDispatchHooks, restoreHookState, clearPersistedHookState, } from "./post-unit-hooks.js";
33
33
  import { runGSDDoctor, rebuildState } from "./doctor.js";
34
- import { preDispatchHealthGate, resetProactiveHealing, setLevelChangeCallback, } from "./doctor-proactive.js";
34
+ import { preDispatchHealthGate, recordHealthSnapshot, resetProactiveHealing, setLevelChangeCallback, } from "./doctor-proactive.js";
35
35
  import { clearSkillSnapshot } from "./skill-discovery.js";
36
36
  import { captureAvailableSkills, resetSkillTelemetry, } from "./skill-telemetry.js";
37
37
  import { getRtkSessionSavings } from "../shared/rtk-session-stats.js";
@@ -43,7 +43,7 @@ import { isAbsolute, join } from "node:path";
43
43
  import { pathToFileURL } from "node:url";
44
44
  import { readFileSync, existsSync, mkdirSync } from "node:fs";
45
45
  import { atomicWriteSync } from "./atomic-write.js";
46
- import { autoCommitCurrentBranch, captureIntegrationBranch, detectWorktreeName, getCurrentBranch, getMainBranch, setActiveMilestoneId, } from "./worktree.js";
46
+ import { autoCommitCurrentBranch, captureIntegrationBranch, detectWorktreeName, getCurrentBranch, getMainBranch, setActiveMilestoneId, resolveProjectRoot, } from "./worktree.js";
47
47
  import { GitServiceImpl } from "./git-service.js";
48
48
  import { getPriorSliceCompletionBlocker } from "./dispatch-guard.js";
49
49
  import { createAutoWorktree, enterAutoWorktree, enterBranchModeForMilestone, teardownAutoWorktree, isInAutoWorktree, getAutoWorktreePath, mergeMilestoneToMain, autoWorktreeBranch, syncWorktreeStateBack, syncProjectRootToWorktree, checkResourcesStale, escapeStaleWorktree, } from "./auto-worktree.js";
@@ -82,6 +82,7 @@ import { resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSess
82
82
  import { runAutoLoopWithUok } from "./uok/kernel.js";
83
83
  import { resolveUokFlags } from "./uok/flags.js";
84
84
  import { validateDirectory } from "./validate-directory.js";
85
+ import { createAutoOrchestrator } from "./auto/orchestrator.js";
85
86
  import { WorktreeResolver, } from "./worktree-resolver.js";
86
87
  import { reorderForCaching } from "./prompt-ordering.js";
87
88
  export { STUB_RECOVERY_THRESHOLD, NEW_SESSION_TIMEOUT_MS, } from "./auto/session.js";
@@ -904,6 +905,12 @@ export async function stopAuto(ctx, pi, reason) {
904
905
  // changes the user made between sessions (#4959 / CodeRabbit).
905
906
  if (pi)
906
907
  clearToolBaseline(pi);
908
+ try {
909
+ await s.orchestration?.stop(reason ?? "stop");
910
+ }
911
+ catch (err) {
912
+ debugLog("stop-orchestration-stop", { error: err instanceof Error ? err.message : String(err) });
913
+ }
907
914
  // Reset all session state in one call
908
915
  s.reset();
909
916
  }
@@ -953,6 +960,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
953
960
  activeRunDir: s.activeRunDir,
954
961
  autoStartTime: s.autoStartTime,
955
962
  milestoneLock: s.sessionMilestoneLock ?? undefined,
963
+ pauseReason: _errorContext?.message,
956
964
  };
957
965
  setRuntimeKv("global", "", PAUSED_SESSION_KV_KEY, pausedMeta);
958
966
  }
@@ -992,6 +1000,12 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
992
1000
  // Unblock pending unitPromise so autoLoop exits cleanly (#1799)
993
1001
  resolveAgentEnd({ messages: [] });
994
1002
  _resetPendingResolve();
1003
+ try {
1004
+ await s.orchestration?.stop("pause");
1005
+ }
1006
+ catch (err) {
1007
+ debugLog("pause-orchestration-stop", { error: err instanceof Error ? err.message : String(err) });
1008
+ }
995
1009
  s.active = false;
996
1010
  s.paused = true;
997
1011
  deactivateGSD();
@@ -1041,6 +1055,132 @@ function buildResolverDeps() {
1041
1055
  function buildResolver() {
1042
1056
  return new WorktreeResolver(s, buildResolverDeps());
1043
1057
  }
1058
+ /**
1059
+ * Thin entry glue for the new Auto Orchestration module.
1060
+ *
1061
+ * This intentionally wires only dispatch + error notification today, with
1062
+ * no behavior changes to the existing auto loop. It provides a concrete seam
1063
+ * the next refactor steps can adopt incrementally.
1064
+ */
1065
+ export function createWiredAutoOrchestrationModule(ctx, _pi, dispatchBasePath, runtimeBasePath = resolveProjectRoot(dispatchBasePath)) {
1066
+ const flowId = `auto-orchestrator-${Date.now()}`;
1067
+ let seq = 0;
1068
+ const deps = {
1069
+ dispatch: {
1070
+ async decideNextUnit() {
1071
+ const state = await deriveState(dispatchBasePath);
1072
+ const active = state.activeMilestone;
1073
+ if (!active)
1074
+ return null;
1075
+ const prefs = loadEffectiveGSDPreferences(dispatchBasePath)?.preferences;
1076
+ const action = await resolveDispatch({
1077
+ basePath: dispatchBasePath,
1078
+ mid: active.id,
1079
+ midTitle: active.title,
1080
+ state,
1081
+ prefs,
1082
+ });
1083
+ if (action.action !== "dispatch")
1084
+ return null;
1085
+ return {
1086
+ unitType: action.unitType,
1087
+ unitId: action.unitId,
1088
+ reason: action.matchedRule ?? "dispatch",
1089
+ preconditions: [],
1090
+ };
1091
+ },
1092
+ },
1093
+ recovery: {
1094
+ async classifyAndRecover(input) {
1095
+ const reason = input.error instanceof Error ? input.error.message : String(input.error ?? "unknown auto error");
1096
+ return { action: "escalate", reason };
1097
+ },
1098
+ },
1099
+ worktree: {
1100
+ async prepareForUnit() { },
1101
+ async syncAfterUnit() { },
1102
+ async cleanupOnStop() { },
1103
+ },
1104
+ health: {
1105
+ async preAdvanceGate() {
1106
+ const gate = await preDispatchHealthGate(dispatchBasePath);
1107
+ return {
1108
+ allow: gate.proceed,
1109
+ reason: gate.reason,
1110
+ };
1111
+ },
1112
+ async postAdvanceRecord(result) {
1113
+ if (result.kind === "error") {
1114
+ recordHealthSnapshot(1, 0, 0, [{
1115
+ code: "orchestration-error",
1116
+ message: result.reason ?? "orchestration error",
1117
+ severity: "error",
1118
+ unitId: "orchestration",
1119
+ }], [], "orchestration");
1120
+ }
1121
+ else if (result.kind === "blocked") {
1122
+ recordHealthSnapshot(0, 1, 0, [{
1123
+ code: "orchestration-blocked",
1124
+ message: result.reason ?? "orchestration blocked",
1125
+ severity: "warning",
1126
+ unitId: "orchestration",
1127
+ }], [], "orchestration");
1128
+ }
1129
+ },
1130
+ },
1131
+ runtime: {
1132
+ async ensureLockOwnership() {
1133
+ const status = getSessionLockStatus(runtimeBasePath);
1134
+ if (!status.valid || status.failureReason === "pid-mismatch") {
1135
+ throw new Error("session lock held by another process");
1136
+ }
1137
+ },
1138
+ async journalTransition(event) {
1139
+ const eventType = event.name === "start"
1140
+ ? "iteration-start"
1141
+ : event.name === "resume"
1142
+ ? "iteration-start"
1143
+ : event.name === "advance"
1144
+ ? "dispatch-match"
1145
+ : event.name === "advance-blocked"
1146
+ ? "guard-block"
1147
+ : event.name === "advance-stopped"
1148
+ ? "dispatch-stop"
1149
+ : event.name === "advance-error"
1150
+ ? "iteration-end"
1151
+ : event.name === "advance-paused" || event.name === "advance-retry"
1152
+ ? "guard-block"
1153
+ : event.name === "stop"
1154
+ ? "terminal"
1155
+ : "iteration-end";
1156
+ _emitJournalEvent(runtimeBasePath, {
1157
+ ts: new Date().toISOString(),
1158
+ flowId,
1159
+ seq: ++seq,
1160
+ eventType,
1161
+ data: {
1162
+ source: "auto-orchestrator",
1163
+ name: event.name,
1164
+ reason: event.reason,
1165
+ unitType: event.unitType,
1166
+ unitId: event.unitId,
1167
+ },
1168
+ });
1169
+ },
1170
+ },
1171
+ notifications: {
1172
+ async notifyLifecycle(event) {
1173
+ if (event.name === "error") {
1174
+ ctx.ui.notify(event.detail ?? "auto orchestration error", "error");
1175
+ }
1176
+ },
1177
+ },
1178
+ };
1179
+ return createAutoOrchestrator(deps);
1180
+ }
1181
+ function ensureOrchestrationModule(ctx, pi, basePath) {
1182
+ s.orchestration = createWiredAutoOrchestrationModule(ctx, pi, basePath, lockBase());
1183
+ }
1044
1184
  /**
1045
1185
  * Build the LoopDeps object from auto.ts private scope.
1046
1186
  * This bundles all private functions that autoLoop needs without exporting them.
@@ -1398,6 +1538,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1398
1538
  // s.basePath may have been updated to a worktree path by enterMilestone.
1399
1539
  rebuildScope(s.basePath, s.currentMilestoneId);
1400
1540
  }
1541
+ ensureOrchestrationModule(ctx, pi, s.basePath || base);
1401
1542
  registerSigtermHandler(lockBase());
1402
1543
  ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
1403
1544
  ctx.ui.setWidget("gsd-health", undefined);
@@ -1457,6 +1598,12 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1457
1598
  clearPausedSession("paused-session DB cleanup failed (resume activation)");
1458
1599
  }
1459
1600
  pi.events.emit(CMUX_CHANNELS.LOG, { preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, message: s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", level: "progress" });
1601
+ try {
1602
+ await s.orchestration?.resume();
1603
+ }
1604
+ catch (err) {
1605
+ debugLog("resume-orchestration-resume", { error: err instanceof Error ? err.message : String(err) });
1606
+ }
1460
1607
  startAutoCommandPolling(s.basePath);
1461
1608
  await runAutoLoopWithUok({
1462
1609
  ctx,
@@ -1482,6 +1629,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1482
1629
  // Build scope after bootstrap has populated s.basePath / s.originalBasePath /
1483
1630
  // s.currentMilestoneId (including worktree setup inside bootstrapAutoSession).
1484
1631
  rebuildScope(s.basePath, s.currentMilestoneId);
1632
+ ensureOrchestrationModule(ctx, pi, s.basePath || base);
1485
1633
  captureProjectRootEnv(s.originalBasePath || s.basePath);
1486
1634
  registerAutoWorkerForSession(s);
1487
1635
  try {
@@ -1492,6 +1640,12 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1492
1640
  logWarning("engine", `cmux sync failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1493
1641
  }
1494
1642
  pi.events.emit(CMUX_CHANNELS.LOG, { preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, message: requestedStepMode ? "Step-mode started." : "Auto-mode started.", level: "progress" });
1643
+ try {
1644
+ await s.orchestration?.start({ basePath: s.basePath, trigger: "auto-loop" });
1645
+ }
1646
+ catch (err) {
1647
+ debugLog("start-orchestration-start", { error: err instanceof Error ? err.message : String(err) });
1648
+ }
1495
1649
  startAutoCommandPolling(s.basePath);
1496
1650
  // Dispatch the first unit
1497
1651
  await runAutoLoopWithUok({
@@ -1576,6 +1730,9 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
1576
1730
  s.pendingQuickTasks = [];
1577
1731
  }
1578
1732
  s.basePath = targetBasePath;
1733
+ if (!s.orchestration) {
1734
+ ensureOrchestrationModule(ctx, pi, s.basePath);
1735
+ }
1579
1736
  const hookUnitType = `hook/${hookName}`;
1580
1737
  const hookStartedAt = Date.now();
1581
1738
  s.currentUnit = {
@@ -39,6 +39,14 @@ function resolveAgentEndBasePath() {
39
39
  return undefined;
40
40
  }
41
41
  }
42
+ export function _buildAbortedPauseContext(lastMsg) {
43
+ const hasErrorMessage = Object.prototype.hasOwnProperty.call(lastMsg, "errorMessage") && !!lastMsg.errorMessage;
44
+ return {
45
+ message: hasErrorMessage ? String(lastMsg.errorMessage) : "Operation aborted",
46
+ category: "aborted",
47
+ isTransient: true,
48
+ };
49
+ }
42
50
  async function pauseTransientWithBackoff(cls, pi, ctx, errorDetail, isRateLimit) {
43
51
  retryState.consecutiveTransientCount += 1;
44
52
  const baseRetryAfterMs = "retryAfterMs" in cls ? cls.retryAfterMs : 15_000;
@@ -134,7 +142,7 @@ export async function handleAgentEnd(pi, event, ctx) {
134
142
  }
135
143
  return;
136
144
  }
137
- await pauseAuto(ctx, pi);
145
+ await pauseAuto(ctx, pi, _buildAbortedPauseContext(lastMsg));
138
146
  return;
139
147
  }
140
148
  if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
@@ -669,6 +669,10 @@ function columnExists(db, table, column) {
669
669
  const rows = db.prepare(`PRAGMA table_info(${table})`).all();
670
670
  return rows.some((row) => row["name"] === column);
671
671
  }
672
+ function formatFtsUnavailableError(err) {
673
+ const message = err instanceof Error ? err.message : String(err);
674
+ return message.replace(/\bmoduel\s*:\s*/gi, "module: ");
675
+ }
672
676
  /**
673
677
  * Create the FTS5 virtual table for memories plus the triggers that keep it
674
678
  * in sync with the base table. FTS5 may be unavailable on stripped-down
@@ -704,7 +708,7 @@ export function tryCreateMemoriesFts(db) {
704
708
  return true;
705
709
  }
706
710
  catch (err) {
707
- logWarning("db", `FTS5 unavailable — memory queries will use LIKE fallback: ${err.message}`);
711
+ logWarning("db", `FTS5 unavailable — memory queries will use LIKE fallback: ${formatFtsUnavailableError(err)}`);
708
712
  return false;
709
713
  }
710
714
  }
@@ -1653,6 +1657,35 @@ export function closeDatabase() {
1653
1657
  _lastDbError = null;
1654
1658
  _lastDbPhase = null;
1655
1659
  }
1660
+ /**
1661
+ * Re-open the active database connection from disk.
1662
+ *
1663
+ * Auto-mode can observe artifacts written by a workflow server running in a
1664
+ * different process before its long-lived singleton has re-synchronized. The
1665
+ * recovery path uses this to force the next state derivation to read from the
1666
+ * current on-disk database instead of continuing with a possibly stale handle.
1667
+ */
1668
+ export function refreshOpenDatabaseFromDisk() {
1669
+ if (!currentDb || !currentPath)
1670
+ return false;
1671
+ if (currentPath === ":memory:")
1672
+ return false;
1673
+ const dbPath = currentPath;
1674
+ const identityKey = _currentIdentityKey;
1675
+ try {
1676
+ closeDatabase();
1677
+ const opened = openDatabase(dbPath);
1678
+ if (opened && identityKey && currentDb) {
1679
+ _dbCache.set(identityKey, { dbPath, db: currentDb });
1680
+ _currentIdentityKey = identityKey;
1681
+ }
1682
+ return opened;
1683
+ }
1684
+ catch (e) {
1685
+ logWarning("db", `database refresh failed: ${e.message}`);
1686
+ return false;
1687
+ }
1688
+ }
1656
1689
  /** Run a full VACUUM — call sparingly (e.g. after milestone completion). */
1657
1690
  export function vacuumDatabase() {
1658
1691
  if (!currentDb)
@@ -96,12 +96,25 @@ export function resolveImportPath(importPath, sourceFile, basePath) {
96
96
  if (existsSync(directPath)) {
97
97
  return { exists: true, resolvedPath: directPath };
98
98
  }
99
- // Only .js/.jsx/.mjs/.cjs imports legitimately fall through for the TS
100
- // ESM convention (.js .ts). Any other explicit extension (.css, .json,
101
- // .svg, images, fonts, .ts, .tsx, …) must stay unresolved when the direct
102
- // path is missing — otherwise a stray `./missing.css.ts` could shadow a
103
- // genuinely missing `./missing.css` import.
104
- if (![".js", ".jsx", ".mjs", ".cjs"].includes(explicitExt)) {
99
+ // Known concrete extensions that should NOT fall through to code-shadow
100
+ // probing when missing. This preserves the "missing.css must stay missing"
101
+ // guarantee while still allowing dotted module stems like ./route.server
102
+ // to resolve as ./route.server.ts.
103
+ const nonFallbackExtensions = new Set([
104
+ ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
105
+ ".json", ".css", ".scss", ".sass", ".less", ".styl",
106
+ ".svg", ".png", ".jpg", ".jpeg", ".gif", ".webp", ".avif", ".ico", ".bmp",
107
+ ".woff", ".woff2", ".ttf", ".otf", ".eot",
108
+ ]);
109
+ const runtimeFallbackExtensions = new Set([".js", ".jsx", ".mjs", ".cjs"]);
110
+ const dottedStemFallbackExtensions = new Set([".server", ".client", ".webhook"]);
111
+ if (explicitExt !== "" &&
112
+ !runtimeFallbackExtensions.has(explicitExt) &&
113
+ !nonFallbackExtensions.has(explicitExt) &&
114
+ !dottedStemFallbackExtensions.has(explicitExt)) {
115
+ return { exists: false, resolvedPath: null };
116
+ }
117
+ if (nonFallbackExtensions.has(explicitExt) && !runtimeFallbackExtensions.has(explicitExt)) {
105
118
  return { exists: false, resolvedPath: null };
106
119
  }
107
120
  }
@@ -163,6 +176,12 @@ export function checkImportResolution(taskRow, _priorTasks, basePath) {
163
176
  }
164
177
  const imports = extractRelativeImports(source);
165
178
  for (const { importPath, lineNum } of imports) {
179
+ // React Router generated +types modules may not exist on disk during
180
+ // post-exec checks (generated during framework build). Don't block task
181
+ // completion on these imports.
182
+ if (/^\.{1,2}\/\+types\//.test(importPath)) {
183
+ continue;
184
+ }
166
185
  const resolution = resolveImportPath(importPath, file, basePath);
167
186
  if (!resolution.exists) {
168
187
  results.push({
@@ -1,3 +1,4 @@
1
+ // GSD2 — Shared interview round UI widget
1
2
  /**
2
3
  * Shared interview round UI widget.
3
4
  *
@@ -128,14 +129,24 @@ export async function showInterviewRound(questions, opts, ctx) {
128
129
  let showingExitConfirm = false;
129
130
  let exitCursor = 0; // 0 = keep going (default), 1 = end interview
130
131
  let cachedLines;
132
+ let completed = false;
133
+ let removeAbortListener;
134
+ function finish(result) {
135
+ if (completed)
136
+ return;
137
+ completed = true;
138
+ removeAbortListener?.();
139
+ done(result);
140
+ }
131
141
  // External cancellation (e.g. remote channel won the race)
132
142
  if (opts.signal) {
133
- const onAbort = () => done({ endInterview: false, answers: {} });
143
+ const onAbort = () => finish({ endInterview: false, answers: {} });
134
144
  if (opts.signal.aborted) {
135
145
  onAbort();
136
146
  }
137
147
  else {
138
148
  opts.signal.addEventListener("abort", onAbort, { once: true });
149
+ removeAbortListener = () => opts.signal?.removeEventListener("abort", onAbort);
139
150
  }
140
151
  }
141
152
  // Editor is created once; editorTheme comes from the design system
@@ -212,7 +223,7 @@ export async function showInterviewRound(questions, opts, ctx) {
212
223
  }
213
224
  function submit() {
214
225
  saveEditorToState();
215
- done(buildResult());
226
+ finish(buildResult());
216
227
  }
217
228
  function goNextOrSubmit() {
218
229
  if (!isMultiSelect(currentIdx)) {
@@ -267,7 +278,7 @@ export async function showInterviewRound(questions, opts, ctx) {
267
278
  return;
268
279
  }
269
280
  if (data === "2") {
270
- done({ endInterview: false, answers: {} });
281
+ finish({ endInterview: false, answers: {} });
271
282
  return;
272
283
  }
273
284
  if (matchesKey(data, Key.enter) || matchesKey(data, Key.space)) {
@@ -276,7 +287,7 @@ export async function showInterviewRound(questions, opts, ctx) {
276
287
  refresh();
277
288
  }
278
289
  else {
279
- done({ endInterview: false, answers: {} });
290
+ finish({ endInterview: false, answers: {} });
280
291
  }
281
292
  return;
282
293
  }