@adhdev/daemon-core 0.9.82-rc.36 → 0.9.82-rc.360

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 (325) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +8 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/build-info.d.ts +37 -0
  4. package/dist/chat/source-machine.d.ts +166 -0
  5. package/dist/chat/source-resolver.d.ts +104 -0
  6. package/dist/chat/subscription-updates.d.ts +1 -0
  7. package/dist/cli-adapter-types.d.ts +55 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +198 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +116 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +53 -0
  14. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  15. package/dist/cli-adapters/resolve-executable.d.ts +14 -0
  16. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  17. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  18. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  19. package/dist/commands/cli-manager.d.ts +2 -1
  20. package/dist/commands/handler.d.ts +125 -0
  21. package/dist/commands/mesh-coordinator.d.ts +85 -1
  22. package/dist/commands/router.d.ts +336 -1
  23. package/dist/commands/upgrade-helper.d.ts +41 -1
  24. package/dist/config/chat-history.d.ts +9 -0
  25. package/dist/config/config.d.ts +5 -0
  26. package/dist/config/mesh-config.d.ts +77 -1
  27. package/dist/detection/ide-detector.d.ts +13 -0
  28. package/dist/detection/win32-ide-version.d.ts +37 -0
  29. package/dist/git/change-impact-config.d.ts +159 -0
  30. package/dist/git/git-commands.d.ts +11 -1
  31. package/dist/git/git-diff.d.ts +6 -0
  32. package/dist/git/git-executor.d.ts +11 -0
  33. package/dist/git/git-status.d.ts +23 -0
  34. package/dist/git/git-types.d.ts +2 -50
  35. package/dist/git/index.d.ts +2 -0
  36. package/dist/index.d.ts +54 -13
  37. package/dist/index.js +44143 -17595
  38. package/dist/index.js.map +1 -1
  39. package/dist/index.mjs +43858 -17438
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/installer.d.ts +1 -4
  42. package/dist/ipc/local-ipc-server.d.ts +91 -0
  43. package/dist/launch.d.ts +1 -1
  44. package/dist/logging/async-batch-writer.d.ts +10 -0
  45. package/dist/logging/log-redactor.d.ts +24 -0
  46. package/dist/logging/log-tail-reader.d.ts +46 -0
  47. package/dist/logging/logger.d.ts +1 -1
  48. package/dist/mesh/contracts.d.ts +164 -0
  49. package/dist/mesh/coordinator-prompt.d.ts +36 -0
  50. package/dist/mesh/coordinator-registry.d.ts +59 -0
  51. package/dist/mesh/mesh-active-work.d.ts +174 -0
  52. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  53. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  54. package/dist/mesh/mesh-events-coordinator.d.ts +170 -0
  55. package/dist/mesh/mesh-events-pending.d.ts +55 -0
  56. package/dist/mesh/mesh-events-stale.d.ts +40 -0
  57. package/dist/mesh/mesh-events-utils.d.ts +62 -0
  58. package/dist/mesh/mesh-events.d.ts +6 -49
  59. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  60. package/dist/mesh/mesh-host-ownership.d.ts +9 -0
  61. package/dist/mesh/mesh-init.d.ts +86 -0
  62. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -3
  63. package/dist/mesh/mesh-ledger.d.ts +77 -1
  64. package/dist/mesh/mesh-missions.d.ts +164 -0
  65. package/dist/mesh/mesh-reconcile-loop.d.ts +7 -0
  66. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  67. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  68. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  69. package/dist/mesh/mesh-routing.d.ts +70 -0
  70. package/dist/mesh/mesh-runtime-store.d.ts +429 -0
  71. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  72. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  73. package/dist/mesh/mesh-work-queue.d.ts +246 -5
  74. package/dist/mesh/preview-freshness.d.ts +18 -0
  75. package/dist/mesh/refine-config.d.ts +216 -0
  76. package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
  77. package/dist/providers/acp-provider-instance.d.ts +5 -0
  78. package/dist/providers/approval-utils.d.ts +20 -0
  79. package/dist/providers/chat-message-normalization.d.ts +12 -0
  80. package/dist/providers/cli-provider-instance.d.ts +106 -3
  81. package/dist/providers/contracts.d.ts +139 -6
  82. package/dist/providers/external-sources.d.ts +71 -0
  83. package/dist/providers/manual-attendance.d.ts +63 -0
  84. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
  85. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  86. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  87. package/dist/providers/native-history/dispatcher.d.ts +27 -0
  88. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  89. package/dist/providers/native-history/index.d.ts +13 -0
  90. package/dist/providers/provider-instance-manager.d.ts +14 -0
  91. package/dist/providers/provider-instance.d.ts +23 -1
  92. package/dist/providers/provider-loader.d.ts +26 -4
  93. package/dist/providers/provider-trust.d.ts +31 -0
  94. package/dist/providers/read-chat-contract.d.ts +29 -0
  95. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  96. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  97. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  98. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  99. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  100. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  101. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  102. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  103. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  104. package/dist/providers/sdk/v1/index.d.ts +30 -0
  105. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  106. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  107. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  108. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  109. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  110. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  111. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  112. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  113. package/dist/providers/spec/adapter.d.ts +91 -0
  114. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  115. package/dist/providers/spec/evaluator.d.ts +45 -0
  116. package/dist/providers/spec/fsm-driver.d.ts +368 -0
  117. package/dist/providers/spec/fsm-evaluator.d.ts +76 -0
  118. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  119. package/dist/providers/spec/fsm-types.d.ts +174 -0
  120. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  121. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  122. package/dist/providers/spec/route.d.ts +4 -0
  123. package/dist/providers/spec/types.d.ts +222 -0
  124. package/dist/providers/status-monitor.d.ts +7 -7
  125. package/dist/providers/transcript-v2.d.ts +176 -0
  126. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  127. package/dist/providers/working-dir.d.ts +17 -0
  128. package/dist/repo-mesh-types.d.ts +295 -13
  129. package/dist/sessions/registry.d.ts +6 -0
  130. package/dist/shared-types-extra.d.ts +2 -4
  131. package/dist/shared-types.d.ts +59 -2
  132. package/dist/status/normalize.d.ts +1 -1
  133. package/dist/status/normalize.js +1 -0
  134. package/dist/status/normalize.js.map +1 -1
  135. package/dist/status/normalize.mjs +1 -0
  136. package/dist/status/normalize.mjs.map +1 -1
  137. package/dist/status/reporter.d.ts +2 -0
  138. package/dist/status/snapshot.d.ts +26 -0
  139. package/dist/system/load-better-sqlite3.d.ts +21 -0
  140. package/dist/types.d.ts +5 -0
  141. package/package.json +7 -3
  142. package/src/agent-stream/poller.ts +2 -3
  143. package/src/agent-stream/provider-adapter.ts +1 -1
  144. package/src/boot/daemon-lifecycle.ts +55 -12
  145. package/src/boot/process-hardening.ts +89 -0
  146. package/src/build-info.ts +73 -0
  147. package/src/chat/source-machine.ts +534 -0
  148. package/src/chat/source-resolver.ts +0 -0
  149. package/src/chat/subscription-updates.ts +20 -1
  150. package/src/cli-adapter-types.d.ts +1 -0
  151. package/src/cli-adapter-types.ts +56 -2
  152. package/src/cli-adapters/cli-script-runner.ts +421 -0
  153. package/src/cli-adapters/cli-state-engine.ts +1215 -0
  154. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  155. package/src/cli-adapters/provider-cli-adapter.ts +774 -1141
  156. package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
  157. package/src/cli-adapters/provider-cli-parse.ts +13 -0
  158. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  159. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  160. package/src/cli-adapters/provider-cli-shared.ts +100 -11
  161. package/src/cli-adapters/pty-transport.ts +2 -1
  162. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  163. package/src/cli-adapters/resolve-executable.ts +90 -0
  164. package/src/cli-adapters/session-host-transport.ts +2 -1
  165. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +53 -29
  166. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  167. package/src/cli-adapters/terminal-screen.ts +16 -81
  168. package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
  169. package/src/commands/chat-commands.ts +1823 -62
  170. package/src/commands/cli-manager.ts +336 -19
  171. package/src/commands/handler.ts +841 -2
  172. package/src/commands/mesh-coordinator.ts +332 -122
  173. package/src/commands/router.ts +7624 -1312
  174. package/src/commands/stream-commands.ts +8 -0
  175. package/src/commands/upgrade-helper.ts +310 -45
  176. package/src/config/chat-history.ts +483 -24
  177. package/src/config/config.ts +12 -0
  178. package/src/config/mesh-config.ts +388 -6
  179. package/src/config/recent-activity.ts +8 -2
  180. package/src/daemon/dev-auto-implement.ts +3 -2
  181. package/src/daemon/dev-cli-debug.ts +10 -1
  182. package/src/detection/cli-detector.ts +28 -9
  183. package/src/detection/ide-detector.ts +55 -16
  184. package/src/detection/win32-ide-version.ts +106 -0
  185. package/src/git/change-impact-config.ts +354 -0
  186. package/src/git/git-commands.ts +55 -14
  187. package/src/git/git-diff.ts +81 -11
  188. package/src/git/git-executor.ts +12 -0
  189. package/src/git/git-status.ts +574 -43
  190. package/src/git/git-types.ts +14 -62
  191. package/src/git/git-worktree.ts +8 -1
  192. package/src/git/index.ts +16 -0
  193. package/src/index.ts +156 -12
  194. package/src/installer.d.ts +1 -1
  195. package/src/installer.ts +8 -6
  196. package/src/ipc/local-ipc-server.ts +278 -0
  197. package/src/launch.d.ts +1 -1
  198. package/src/launch.ts +37 -28
  199. package/src/logging/async-batch-writer.ts +55 -0
  200. package/src/logging/command-log.ts +7 -5
  201. package/src/logging/log-redactor.ts +100 -0
  202. package/src/logging/log-tail-reader.ts +220 -0
  203. package/src/logging/logger.ts +14 -7
  204. package/src/mesh/contracts.ts +329 -0
  205. package/src/mesh/coordinator-prompt.ts +234 -31
  206. package/src/mesh/coordinator-registry.ts +121 -0
  207. package/src/mesh/mesh-active-work.ts +667 -0
  208. package/src/mesh/mesh-delivery-policy.ts +315 -0
  209. package/src/mesh/mesh-event-trace.ts +67 -0
  210. package/src/mesh/mesh-events-coordinator.ts +2572 -0
  211. package/src/mesh/mesh-events-pending.ts +599 -0
  212. package/src/mesh/mesh-events-stale.ts +309 -0
  213. package/src/mesh/mesh-events-utils.ts +381 -0
  214. package/src/mesh/mesh-events.ts +30 -1035
  215. package/src/mesh/mesh-fast-forward.ts +839 -0
  216. package/src/mesh/mesh-host-ownership.ts +73 -0
  217. package/src/mesh/mesh-init.ts +260 -0
  218. package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
  219. package/src/mesh/mesh-ledger.ts +591 -102
  220. package/src/mesh/mesh-missions.ts +322 -0
  221. package/src/mesh/mesh-reconcile-loop.ts +1096 -0
  222. package/src/mesh/mesh-refine-batch.ts +197 -0
  223. package/src/mesh/mesh-refine-status.ts +231 -0
  224. package/src/mesh/mesh-review-inbox.ts +307 -0
  225. package/src/mesh/mesh-routing.ts +291 -0
  226. package/src/mesh/mesh-runtime-store.ts +1697 -0
  227. package/src/mesh/mesh-task-stats.ts +161 -0
  228. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  229. package/src/mesh/mesh-work-queue.ts +997 -141
  230. package/src/mesh/preview-freshness.ts +118 -0
  231. package/src/mesh/refine-config.ts +423 -0
  232. package/src/mesh/worktree-bootstrap-config.ts +331 -0
  233. package/src/providers/acp-provider-instance.ts +43 -10
  234. package/src/providers/approval-utils.d.ts +5 -0
  235. package/src/providers/approval-utils.ts +57 -5
  236. package/src/providers/chat-message-normalization.ts +45 -5
  237. package/src/providers/cli-provider-instance.ts +1254 -101
  238. package/src/providers/contracts.d.ts +55 -0
  239. package/src/providers/contracts.ts +150 -6
  240. package/src/providers/extension-provider-instance.ts +12 -7
  241. package/src/providers/external-sources.ts +218 -0
  242. package/src/providers/ide-provider-instance.ts +35 -12
  243. package/src/providers/manual-attendance.ts +85 -0
  244. package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
  245. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  246. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  247. package/src/providers/native-history/dispatcher.ts +340 -0
  248. package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
  249. package/src/providers/native-history/index.ts +30 -0
  250. package/src/providers/provider-instance-manager.ts +30 -0
  251. package/src/providers/provider-instance.ts +19 -1
  252. package/src/providers/provider-loader.ts +670 -50
  253. package/src/providers/provider-schema.ts +87 -14
  254. package/src/providers/provider-trust.ts +114 -0
  255. package/src/providers/read-chat-contract.ts +76 -16
  256. package/src/providers/sdk/README.md +49 -0
  257. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  258. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  259. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  260. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  261. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  262. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  263. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  264. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  265. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  266. package/src/providers/sdk/v1/index.ts +152 -0
  267. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  268. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  269. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  270. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
  271. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  272. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  273. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  274. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  275. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  276. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  277. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  278. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  279. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  280. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  281. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  282. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  283. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  284. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  285. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  286. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  287. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  288. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  289. package/src/providers/sdk/v1/validators/index.ts +19 -0
  290. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  291. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  292. package/src/providers/spec/adapter.ts +235 -0
  293. package/src/providers/spec/cli-adapter.ts +1051 -0
  294. package/src/providers/spec/evaluator.ts +407 -0
  295. package/src/providers/spec/fsm-driver.ts +1251 -0
  296. package/src/providers/spec/fsm-evaluator.ts +272 -0
  297. package/src/providers/spec/fsm-loader.ts +120 -0
  298. package/src/providers/spec/fsm-types.ts +273 -0
  299. package/src/providers/spec/native-history-executor.ts +1136 -0
  300. package/src/providers/spec/pre-launch-trust.ts +104 -0
  301. package/src/providers/spec/route.ts +51 -0
  302. package/src/providers/spec/types.ts +262 -0
  303. package/src/providers/status-monitor.d.ts +7 -7
  304. package/src/providers/status-monitor.ts +37 -22
  305. package/src/providers/transcript-v2.ts +567 -0
  306. package/src/providers/types/interactive-prompt.ts +536 -0
  307. package/src/providers/version-archive.ts +64 -24
  308. package/src/providers/working-dir.ts +23 -0
  309. package/src/repo-mesh-types.ts +378 -14
  310. package/src/sessions/registry.ts +6 -0
  311. package/src/shared-types-extra.ts +2 -4
  312. package/src/shared-types.d.ts +8 -0
  313. package/src/shared-types.ts +64 -1
  314. package/src/status/builders.ts +26 -6
  315. package/src/status/normalize.ts +2 -0
  316. package/src/status/reporter.ts +19 -1
  317. package/src/status/snapshot.ts +95 -26
  318. package/src/system/host-memory.ts +29 -12
  319. package/src/system/load-better-sqlite3.ts +68 -0
  320. package/src/types.ts +5 -0
  321. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  322. package/dist/mesh/mesh-sync.d.ts +0 -53
  323. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  324. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  325. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,197 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+
4
+ const execFileAsync = promisify(execFile);
5
+
6
+ /**
7
+ * Change-area analysis for one worktree node, used to order sibling nodes for
8
+ * batch refinement so that nodes least likely to conflict merge first.
9
+ *
10
+ * The heuristic is deliberately git-only and side-effect-free: it inspects the
11
+ * commits the node's branch adds on top of the base (`base..branch`) and records
12
+ * - whether any submodule gitlink path is touched (high-conflict signal: the
13
+ * batch must rebase later siblings onto the advanced submodule main), and
14
+ * - the set of changed top-level paths (so siblings touching disjoint trees can
15
+ * be ordered ahead of ones that overlap).
16
+ */
17
+ export interface MeshRefineBatchNodeChangeArea {
18
+ nodeId: string;
19
+ workspace: string;
20
+ branch: string;
21
+ /** Top-level path segments changed by the branch vs. base (e.g. 'oss', 'packages'). */
22
+ changedTopLevelPaths: string[];
23
+ /** Full changed file list (bounded) for overlap detection. */
24
+ changedFiles: string[];
25
+ /** Submodule gitlink paths touched by the branch (subset of changedTopLevelPaths). */
26
+ touchedSubmodulePaths: string[];
27
+ /** True when the branch touches at least one submodule gitlink. */
28
+ touchesSubmodule: boolean;
29
+ /** Number of commits the branch is ahead of base; 0 means nothing to merge. */
30
+ aheadCount: number;
31
+ /** Non-fatal analysis error (e.g. base/branch unresolved); ordering falls back to neutral. */
32
+ error?: string;
33
+ }
34
+
35
+ export interface MeshRefineBatchOrderingResult {
36
+ /** Node IDs in the order they should be refined. */
37
+ order: string[];
38
+ /** Per-node change areas, keyed by node id, for plan transparency. */
39
+ changeAreas: Record<string, MeshRefineBatchNodeChangeArea>;
40
+ /** Human-readable explanation of why the order was chosen. */
41
+ rationale: string[];
42
+ }
43
+
44
+ const MAX_CHANGED_FILES = 500;
45
+
46
+ function topLevel(path: string): string {
47
+ const slash = path.indexOf('/');
48
+ return slash === -1 ? path : path.slice(0, slash);
49
+ }
50
+
51
+ /**
52
+ * Resolve the set of submodule gitlink paths declared in a repo's .gitmodules,
53
+ * relative to the repo root. Used to classify which changed paths are submodule
54
+ * pointer bumps vs. ordinary file edits.
55
+ */
56
+ async function resolveSubmodulePaths(repoRoot: string): Promise<Set<string>> {
57
+ try {
58
+ const { stdout } = await execFileAsync(
59
+ 'git',
60
+ ['config', '--file', '.gitmodules', '--get-regexp', 'path'],
61
+ { cwd: repoRoot, encoding: 'utf8' },
62
+ );
63
+ const paths = new Set<string>();
64
+ for (const line of stdout.split('\n')) {
65
+ const trimmed = line.trim();
66
+ if (!trimmed) continue;
67
+ // Format: "submodule.<name>.path <path>"
68
+ const spaceIdx = trimmed.indexOf(' ');
69
+ if (spaceIdx === -1) continue;
70
+ const value = trimmed.slice(spaceIdx + 1).trim();
71
+ if (value) paths.add(value);
72
+ }
73
+ return paths;
74
+ } catch {
75
+ // No .gitmodules (or git error) → repo has no submodules to classify.
76
+ return new Set();
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Analyze one worktree node's change area against its merge base.
82
+ *
83
+ * @param baseRef ref that the node will merge into (e.g. 'origin/main' or a SHA)
84
+ * @param branchRef the node's branch tip
85
+ * @param diffCwd repo to run the diff in (the worktree itself is authoritative for
86
+ * `branch` resolution, but the diff `base..branch` is symmetric, so
87
+ * the worktree cwd works for both refs once base is a reachable SHA).
88
+ */
89
+ export async function analyzeMeshRefineNodeChangeArea(args: {
90
+ nodeId: string;
91
+ workspace: string;
92
+ branch: string;
93
+ baseRef: string;
94
+ branchRef: string;
95
+ diffCwd: string;
96
+ submodulePaths: Set<string>;
97
+ }): Promise<MeshRefineBatchNodeChangeArea> {
98
+ const { nodeId, workspace, branch, baseRef, branchRef, diffCwd, submodulePaths } = args;
99
+ const base: MeshRefineBatchNodeChangeArea = {
100
+ nodeId,
101
+ workspace,
102
+ branch,
103
+ changedTopLevelPaths: [],
104
+ changedFiles: [],
105
+ touchedSubmodulePaths: [],
106
+ touchesSubmodule: false,
107
+ aheadCount: 0,
108
+ };
109
+ try {
110
+ // Use the merge-base so we compare only the node's own commits, not changes
111
+ // that already landed on base via a sibling earlier in the batch.
112
+ let mergeBase = baseRef;
113
+ try {
114
+ const { stdout } = await execFileAsync('git', ['merge-base', baseRef, branchRef], { cwd: diffCwd, encoding: 'utf8' });
115
+ const resolved = stdout.trim();
116
+ if (resolved) mergeBase = resolved;
117
+ } catch { /* fall back to baseRef directly */ }
118
+
119
+ const { stdout: countStdout } = await execFileAsync(
120
+ 'git',
121
+ ['rev-list', '--count', `${mergeBase}..${branchRef}`],
122
+ { cwd: diffCwd, encoding: 'utf8' },
123
+ );
124
+ base.aheadCount = Number.parseInt(countStdout.trim(), 10) || 0;
125
+
126
+ const { stdout: nameStdout } = await execFileAsync(
127
+ 'git',
128
+ ['diff', '--name-only', `${mergeBase}..${branchRef}`],
129
+ { cwd: diffCwd, encoding: 'utf8' },
130
+ );
131
+ const files = nameStdout.split('\n').map(line => line.trim()).filter(Boolean).slice(0, MAX_CHANGED_FILES);
132
+ base.changedFiles = files;
133
+ const topSet = new Set<string>();
134
+ const submoduleSet = new Set<string>();
135
+ for (const file of files) {
136
+ const top = topLevel(file);
137
+ topSet.add(top);
138
+ // A changed path is a submodule touch if the file path IS a declared
139
+ // submodule path (gitlink bumps surface as the submodule path itself).
140
+ if (submodulePaths.has(file) || submodulePaths.has(top)) {
141
+ submoduleSet.add(submodulePaths.has(file) ? file : top);
142
+ }
143
+ }
144
+ base.changedTopLevelPaths = [...topSet].sort();
145
+ base.touchedSubmodulePaths = [...submoduleSet].sort();
146
+ base.touchesSubmodule = submoduleSet.size > 0;
147
+ return base;
148
+ } catch (e: any) {
149
+ base.error = e?.message || String(e);
150
+ return base;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Order nodes for batch refinement to minimize cross-sibling conflicts.
156
+ *
157
+ * Heuristic (deterministic, stable):
158
+ * 1. Nodes that do NOT touch any submodule come first — they cannot advance the
159
+ * submodule main, so they never force a later submodule rebase.
160
+ * 2. Within each group, fewer touched top-level paths first (smaller blast radius).
161
+ * 3. Tie-break by node id for determinism.
162
+ *
163
+ * Submodule-touching siblings are intrinsically serial: each one that merges
164
+ * advances oss main, so the next must rebase. Ordering them last keeps the
165
+ * non-submodule merges (which never need a submodule rebase) clean and up front.
166
+ */
167
+ export function orderMeshRefineBatchNodes(
168
+ changeAreas: MeshRefineBatchNodeChangeArea[],
169
+ ): MeshRefineBatchOrderingResult {
170
+ const areaById: Record<string, MeshRefineBatchNodeChangeArea> = {};
171
+ for (const area of changeAreas) areaById[area.nodeId] = area;
172
+
173
+ const ranked = [...changeAreas].sort((a, b) => {
174
+ const aSub = a.touchesSubmodule ? 1 : 0;
175
+ const bSub = b.touchesSubmodule ? 1 : 0;
176
+ if (aSub !== bSub) return aSub - bSub;
177
+ const aBreadth = a.changedTopLevelPaths.length;
178
+ const bBreadth = b.changedTopLevelPaths.length;
179
+ if (aBreadth !== bBreadth) return aBreadth - bBreadth;
180
+ return a.nodeId.localeCompare(b.nodeId);
181
+ });
182
+
183
+ const rationale: string[] = [];
184
+ const nonSub = ranked.filter(a => !a.touchesSubmodule).map(a => a.nodeId);
185
+ const sub = ranked.filter(a => a.touchesSubmodule).map(a => a.nodeId);
186
+ if (nonSub.length) {
187
+ rationale.push(`Non-submodule nodes first (no submodule-main advance, conflict-free ordering): ${nonSub.join(', ')}`);
188
+ }
189
+ if (sub.length) {
190
+ rationale.push(`Submodule-touching nodes last, serialized (each merge advances submodule main, forcing rebase of the next): ${sub.join(', ')}`);
191
+ }
192
+ for (const area of ranked) {
193
+ if (area.error) rationale.push(`Node ${area.nodeId}: change-area analysis degraded (${area.error}); placed with neutral priority.`);
194
+ }
195
+
196
+ return { order: ranked.map(a => a.nodeId), changeAreas: areaById, rationale };
197
+ }
@@ -0,0 +1,231 @@
1
+ import type { MeshLedgerEntry } from './mesh-ledger.js';
2
+ import type { PendingMeshCoordinatorEvent } from './mesh-events.js';
3
+ import type { MeshAsyncJobLifecycle } from '../repo-mesh-types.js';
4
+
5
+ export type MeshAsyncRefineJobStatus = 'accepted' | 'running' | 'completed' | 'failed';
6
+
7
+ export interface MeshAsyncRefineJobSummary extends MeshAsyncJobLifecycle {
8
+ jobId: string;
9
+ interactionId?: string;
10
+ status: MeshAsyncRefineJobStatus;
11
+ meshId?: string;
12
+ nodeId?: string;
13
+ targetNodeId?: string;
14
+ targetDaemonId?: string;
15
+ workspace?: string;
16
+ branch?: string;
17
+ into?: string;
18
+ retryOfJobId?: string;
19
+ lastEvent?: string;
20
+ lastLedgerKind?: string;
21
+ lastUpdatedAt?: string;
22
+ instruction: string;
23
+ }
24
+
25
+ function readString(value: unknown): string | undefined {
26
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
27
+ }
28
+
29
+ function readRecord(value: unknown): Record<string, unknown> | undefined {
30
+ return value && typeof value === 'object' && !Array.isArray(value)
31
+ ? value as Record<string, unknown>
32
+ : undefined;
33
+ }
34
+
35
+ function eventStatus(event: string | undefined, fallback?: string): MeshAsyncRefineJobStatus | undefined {
36
+ if (event === 'refine:accepted') return 'accepted';
37
+ if (event === 'refine:completed') return 'completed';
38
+ if (event === 'refine:failed') return 'failed';
39
+ if (fallback === 'completed' || fallback === 'failed' || fallback === 'accepted') return fallback;
40
+ return undefined;
41
+ }
42
+
43
+ function ledgerStatus(kind: string, fallback?: string): MeshAsyncRefineJobStatus {
44
+ if (kind === 'task_completed') return 'completed';
45
+ if (kind === 'task_failed') return 'failed';
46
+ if (fallback === 'accepted') return 'accepted';
47
+ return 'running';
48
+ }
49
+
50
+ function instructionForStatus(status: MeshAsyncRefineJobStatus): string {
51
+ if (status === 'accepted') return 'Refine job is accepted; wait for asyncRefineJobs or pendingCoordinatorEvents to report running/completed/failed.';
52
+ if (status === 'running') return 'Refine job is running; do not poll the ledger repeatedly. Watch asyncRefineJobs or pendingCoordinatorEvents for the terminal result.';
53
+ if (status === 'completed') return 'Refine job completed; inspect branch convergence and cleanup evidence before reporting final merge state.';
54
+ return 'Refine job failed; inspect result/finalBranchConvergenceState in mesh_task_history, fix the blocker, then rerun mesh_refine_node when ready.';
55
+ }
56
+
57
+ function mergeJob(
58
+ jobs: Map<string, MeshAsyncRefineJobSummary>,
59
+ patch: Partial<MeshAsyncRefineJobSummary> & { jobId?: string },
60
+ ): void {
61
+ const jobId = readString(patch.jobId);
62
+ if (!jobId) return;
63
+ const previous = jobs.get(jobId);
64
+ const status = patch.status || previous?.status || 'running';
65
+ const definedPatch = Object.fromEntries(
66
+ Object.entries(patch).filter(([, value]) => value !== undefined),
67
+ ) as Partial<MeshAsyncRefineJobSummary>;
68
+ jobs.set(jobId, {
69
+ ...previous,
70
+ ...definedPatch,
71
+ jobId,
72
+ status,
73
+ instruction: instructionForStatus(status),
74
+ });
75
+ }
76
+
77
+ export function buildMeshAsyncRefineJobs(args: {
78
+ meshId?: string;
79
+ ledgerEntries?: MeshLedgerEntry[];
80
+ pendingEvents?: PendingMeshCoordinatorEvent[];
81
+ }): MeshAsyncRefineJobSummary[] {
82
+ const jobs = new Map<string, MeshAsyncRefineJobSummary>();
83
+
84
+ for (const entry of args.ledgerEntries || []) {
85
+ const payload = readRecord(entry.payload);
86
+ if (payload?.source !== 'refine_mesh_node_async_job') continue;
87
+ const refineJob = readRecord(payload.refineJob);
88
+ const result = readRecord(payload.result);
89
+ const finalState = readRecord(payload.finalBranchConvergenceState) || readRecord(result?.finalBranchConvergenceState);
90
+ const jobId = readString(refineJob?.jobId);
91
+ if (!jobId) continue;
92
+ const status = ledgerStatus(entry.kind, readString(refineJob?.status));
93
+ mergeJob(jobs, {
94
+ jobId,
95
+ interactionId: readString(refineJob?.interactionId),
96
+ status,
97
+ meshId: readString(refineJob?.meshId) || args.meshId,
98
+ nodeId: readString(refineJob?.nodeId) || entry.nodeId,
99
+ targetNodeId: readString(refineJob?.nodeId) || entry.nodeId,
100
+ targetDaemonId: readString(refineJob?.targetDaemonId),
101
+ workspace: readString(refineJob?.workspace),
102
+ branch: readString(result?.branch) || readString(finalState?.branch),
103
+ into: readString(result?.into) || readString(finalState?.baseBranch),
104
+ startedAt: readString(refineJob?.startedAt),
105
+ completedAt: readString(refineJob?.completedAt),
106
+ retryOfJobId: readString(refineJob?.retryOfJobId) || readString(payload.retryOfJobId),
107
+ lastLedgerKind: entry.kind,
108
+ lastUpdatedAt: entry.timestamp,
109
+ });
110
+ }
111
+
112
+ for (const event of args.pendingEvents || []) {
113
+ const metadata = readRecord(event.metadataEvent);
114
+ if (metadata?.source !== 'refine_mesh_node_async_job') continue;
115
+ const result = readRecord(metadata.result);
116
+ const finalState = readRecord(result?.finalBranchConvergenceState);
117
+ const jobId = readString(metadata.jobId);
118
+ if (!jobId) continue;
119
+ const status = eventStatus(event.event, readString(metadata.status));
120
+ mergeJob(jobs, {
121
+ jobId,
122
+ interactionId: readString(metadata.interactionId),
123
+ ...(status ? { status } : {}),
124
+ meshId: readString(metadata.meshId) || event.meshId || args.meshId,
125
+ nodeId: readString(metadata.nodeId) || event.nodeId,
126
+ targetNodeId: readString(metadata.nodeId) || event.nodeId,
127
+ targetDaemonId: readString(metadata.targetDaemonId),
128
+ workspace: readString(metadata.workspace) || event.workspace,
129
+ branch: readString(result?.branch) || readString(finalState?.branch),
130
+ into: readString(result?.into) || readString(finalState?.baseBranch),
131
+ startedAt: readString(metadata.startedAt),
132
+ completedAt: readString(metadata.completedAt),
133
+ retryOfJobId: readString(metadata.retryOfJobId),
134
+ lastEvent: event.event,
135
+ lastUpdatedAt: new Date(event.queuedAt).toISOString(),
136
+ });
137
+ }
138
+
139
+ return Array.from(jobs.values()).sort((a, b) => {
140
+ const aTime = new Date(a.lastUpdatedAt || a.startedAt || '').getTime();
141
+ const bTime = new Date(b.lastUpdatedAt || b.startedAt || '').getTime();
142
+ return (Number.isFinite(bTime) ? bTime : 0) - (Number.isFinite(aTime) ? aTime : 0);
143
+ });
144
+ }
145
+
146
+ const TERMINAL_REFINE_STATUSES = new Set<MeshAsyncRefineJobStatus>(['completed', 'failed']);
147
+
148
+ /** Terminal refine jobs older than this (relative to the newest job in the set) are
149
+ * "stale" — already-resolved historical refinery rejections/successes that should not
150
+ * keep inflating the status counts in mesh_status. 6h covers a long working session
151
+ * while still folding multi-day-old residue. */
152
+ export const STALE_TERMINAL_REFINE_WINDOW_MS = 6 * 60 * 60 * 1000;
153
+
154
+ /** Cap on how many recent terminal jobs are counted even if all fall inside the freshness
155
+ * window — prevents a burst of refines from dominating the summary. */
156
+ export const RECENT_TERMINAL_REFINE_CAP = 8;
157
+
158
+ export interface MeshAsyncRefineJobsSummary {
159
+ /** Count of jobs reflected in `byStatus` (active jobs + recent terminal jobs). */
160
+ total: number;
161
+ byStatus: Record<string, number>;
162
+ /** Terminal jobs dropped from the counts because they are stale residue. */
163
+ staleTerminal: number;
164
+ /** Non-terminal (accepted/running) jobs still in flight. */
165
+ activeJobs: MeshAsyncRefineJobSummary[];
166
+ }
167
+
168
+ function jobActivityTime(job: MeshAsyncRefineJobSummary): number {
169
+ const raw = job.lastUpdatedAt || job.completedAt || job.startedAt || '';
170
+ const t = new Date(raw).getTime();
171
+ return Number.isFinite(t) ? t : 0;
172
+ }
173
+
174
+ /**
175
+ * Build a compact summary of refine jobs that folds stale terminal jobs.
176
+ *
177
+ * The full job list (from `buildMeshAsyncRefineJobs`) is derived from a recent ledger
178
+ * window and deduped by jobId, but it still includes every terminal (completed/failed)
179
+ * job that happens to fall in that window — including multi-day-old refinery rejections
180
+ * that have long since been resolved. Those stale terminals inflate `byStatus.failed`
181
+ * and read as "current breakage" when they are historical noise.
182
+ *
183
+ * Active (accepted/running) jobs are always counted. Terminal jobs are counted only when
184
+ * they are recent: within `STALE_TERMINAL_REFINE_WINDOW_MS` of the newest job's activity
185
+ * time AND among the `RECENT_TERMINAL_REFINE_CAP` most-recent terminals. Everything else
186
+ * is folded into `staleTerminal` and excluded from `byStatus`.
187
+ *
188
+ * Freshness is measured relative to the newest job in the set (not wall-clock), so the
189
+ * result is deterministic for a given input — important for tests and for stale-clock
190
+ * environments.
191
+ */
192
+ export function summarizeMeshAsyncRefineJobs(
193
+ jobs: MeshAsyncRefineJobSummary[],
194
+ ): MeshAsyncRefineJobsSummary {
195
+ const activeJobs: MeshAsyncRefineJobSummary[] = [];
196
+ const terminalJobs: MeshAsyncRefineJobSummary[] = [];
197
+ for (const job of jobs) {
198
+ if (TERMINAL_REFINE_STATUSES.has(job.status)) terminalJobs.push(job);
199
+ else activeJobs.push(job);
200
+ }
201
+
202
+ // Newest activity across ALL jobs anchors the freshness window.
203
+ let newest = 0;
204
+ for (const job of jobs) newest = Math.max(newest, jobActivityTime(job));
205
+ const cutoff = newest - STALE_TERMINAL_REFINE_WINDOW_MS;
206
+
207
+ const terminalByRecency = [...terminalJobs].sort(
208
+ (a, b) => jobActivityTime(b) - jobActivityTime(a),
209
+ );
210
+ const freshTerminal = terminalByRecency
211
+ .filter(job => jobActivityTime(job) >= cutoff)
212
+ .slice(0, RECENT_TERMINAL_REFINE_CAP);
213
+ const freshTerminalIds = new Set(freshTerminal.map(job => job.jobId));
214
+
215
+ const byStatus: Record<string, number> = {};
216
+ for (const job of activeJobs) {
217
+ byStatus[job.status] = (byStatus[job.status] ?? 0) + 1;
218
+ }
219
+ for (const job of freshTerminal) {
220
+ byStatus[job.status] = (byStatus[job.status] ?? 0) + 1;
221
+ }
222
+
223
+ const staleTerminal = terminalJobs.length - freshTerminalIds.size;
224
+
225
+ return {
226
+ total: activeJobs.length + freshTerminal.length,
227
+ byStatus,
228
+ staleTerminal,
229
+ activeJobs,
230
+ };
231
+ }