@adhdev/daemon-core 0.9.82-rc.49 → 0.9.82-rc.490

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 (473) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +9 -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 +68 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +220 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +137 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
  14. package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
  15. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  16. package/dist/cli-adapters/resolve-executable.d.ts +69 -0
  17. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  18. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  19. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  20. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  21. package/dist/commands/chat-commands-read.d.ts +23 -0
  22. package/dist/commands/chat-commands-scope.d.ts +39 -0
  23. package/dist/commands/chat-commands-shared.d.ts +33 -0
  24. package/dist/commands/chat-commands-write.d.ts +14 -0
  25. package/dist/commands/chat-commands.d.ts +10 -23
  26. package/dist/commands/cli-manager.d.ts +71 -1
  27. package/dist/commands/handler.d.ts +125 -0
  28. package/dist/commands/high-family/index.d.ts +3 -0
  29. package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
  30. package/dist/commands/high-family/mesh-events.d.ts +2 -0
  31. package/dist/commands/high-family/mesh-status.d.ts +2 -0
  32. package/dist/commands/high-family/types.d.ts +64 -0
  33. package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
  34. package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
  35. package/dist/commands/low-family/diagnostics.d.ts +2 -0
  36. package/dist/commands/low-family/index.d.ts +3 -0
  37. package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
  38. package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
  39. package/dist/commands/low-family/notification.d.ts +2 -0
  40. package/dist/commands/low-family/refine-config.d.ts +2 -0
  41. package/dist/commands/low-family/session-host.d.ts +2 -0
  42. package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
  43. package/dist/commands/low-family/status-meta.d.ts +2 -0
  44. package/dist/commands/low-family/types.d.ts +33 -0
  45. package/dist/commands/med-family/cli-agent.d.ts +2 -0
  46. package/dist/commands/med-family/fast-forward.d.ts +2 -0
  47. package/dist/commands/med-family/ide.d.ts +10 -0
  48. package/dist/commands/med-family/index.d.ts +3 -0
  49. package/dist/commands/med-family/mesh-crud.d.ts +48 -0
  50. package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
  51. package/dist/commands/med-family/mesh-queue.d.ts +2 -0
  52. package/dist/commands/med-family/mesh-restart.d.ts +2 -0
  53. package/dist/commands/med-family/types.d.ts +152 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router-aggregate-status.d.ts +24 -0
  56. package/dist/commands/router-mesh-session-owner.d.ts +59 -0
  57. package/dist/commands/router-refine.d.ts +151 -0
  58. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  59. package/dist/commands/router.d.ts +203 -15
  60. package/dist/commands/upgrade-helper.d.ts +41 -1
  61. package/dist/config/chat-history.d.ts +11 -0
  62. package/dist/config/config.d.ts +19 -0
  63. package/dist/config/mesh-config.d.ts +65 -0
  64. package/dist/config/mesh-json-config.d.ts +199 -0
  65. package/dist/config/registry-resolver.d.ts +54 -0
  66. package/dist/config/repo-settings.d.ts +77 -0
  67. package/dist/config/state-store.d.ts +30 -0
  68. package/dist/daemon/dev-server.d.ts +0 -2
  69. package/dist/detection/cli-detector.d.ts +17 -0
  70. package/dist/detection/ide-detector.d.ts +13 -0
  71. package/dist/detection/win32-ide-version.d.ts +37 -0
  72. package/dist/git/change-impact-config.d.ts +159 -0
  73. package/dist/git/git-commands.d.ts +26 -2
  74. package/dist/git/git-diff.d.ts +6 -0
  75. package/dist/git/git-executor.d.ts +11 -0
  76. package/dist/git/git-status.d.ts +80 -0
  77. package/dist/git/git-types.d.ts +2 -50
  78. package/dist/git/git-worktree.d.ts +71 -1
  79. package/dist/git/index.d.ts +3 -1
  80. package/dist/index.d.ts +70 -17
  81. package/dist/index.js +53532 -19073
  82. package/dist/index.js.map +1 -1
  83. package/dist/index.mjs +53283 -18989
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/installer.d.ts +1 -4
  86. package/dist/ipc/local-ipc-server.d.ts +91 -0
  87. package/dist/launch.d.ts +1 -1
  88. package/dist/logging/async-batch-writer.d.ts +10 -0
  89. package/dist/logging/debug-config.d.ts +16 -0
  90. package/dist/logging/log-redactor.d.ts +24 -0
  91. package/dist/logging/log-tail-reader.d.ts +81 -0
  92. package/dist/logging/logger.d.ts +1 -1
  93. package/dist/mesh/contracts.d.ts +256 -0
  94. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  95. package/dist/mesh/coordinator-registry.d.ts +59 -0
  96. package/dist/mesh/mesh-active-work.d.ts +203 -0
  97. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  98. package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
  99. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  100. package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
  101. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  102. package/dist/mesh/mesh-event-forwarding.d.ts +58 -0
  103. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  104. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  105. package/dist/mesh/mesh-events-pending.d.ts +258 -0
  106. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  107. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  108. package/dist/mesh/mesh-events.d.ts +6 -49
  109. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  110. package/dist/mesh/mesh-host-ownership.d.ts +21 -1
  111. package/dist/mesh/mesh-init.d.ts +128 -0
  112. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  113. package/dist/mesh/mesh-ledger.d.ts +139 -1
  114. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  115. package/dist/mesh/mesh-missions.d.ts +281 -0
  116. package/dist/mesh/mesh-node-identity.d.ts +310 -0
  117. package/dist/mesh/mesh-queue-assignment.d.ts +162 -0
  118. package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
  119. package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
  120. package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
  121. package/dist/mesh/mesh-reconcile-loop.d.ts +84 -0
  122. package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
  123. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  124. package/dist/mesh/mesh-refine-gates.d.ts +457 -0
  125. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  126. package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
  127. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  128. package/dist/mesh/mesh-routing.d.ts +70 -0
  129. package/dist/mesh/mesh-runtime-store.d.ts +567 -0
  130. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  131. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  132. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  133. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +34 -0
  134. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  135. package/dist/mesh/mesh-work-queue.d.ts +392 -1
  136. package/dist/mesh/preview-freshness.d.ts +28 -0
  137. package/dist/mesh/refine-config.d.ts +97 -0
  138. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  139. package/dist/providers/acp-provider-instance.d.ts +5 -0
  140. package/dist/providers/approval-utils.d.ts +46 -0
  141. package/dist/providers/chat-message-normalization.d.ts +58 -1
  142. package/dist/providers/cli-provider-effect-format.d.ts +30 -0
  143. package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
  144. package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
  145. package/dist/providers/cli-provider-instance-types.d.ts +45 -0
  146. package/dist/providers/cli-provider-instance.d.ts +426 -30
  147. package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
  148. package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
  149. package/dist/providers/contracts.d.ts +196 -6
  150. package/dist/providers/external-sources.d.ts +71 -0
  151. package/dist/providers/manual-attendance.d.ts +79 -0
  152. package/dist/providers/native-history/antigravity-claim-registry.d.ts +39 -0
  153. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  154. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  155. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  156. package/dist/providers/native-history/constants.d.ts +12 -0
  157. package/dist/providers/native-history/dispatcher.d.ts +44 -0
  158. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  159. package/dist/providers/native-history/index.d.ts +13 -0
  160. package/dist/providers/provider-instance-manager.d.ts +30 -0
  161. package/dist/providers/provider-instance.d.ts +31 -1
  162. package/dist/providers/provider-loader.d.ts +42 -5
  163. package/dist/providers/provider-trust.d.ts +31 -0
  164. package/dist/providers/read-chat-contract.d.ts +29 -0
  165. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  166. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  167. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  168. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  169. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  170. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  171. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  172. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  173. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  174. package/dist/providers/sdk/v1/index.d.ts +30 -0
  175. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  176. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  177. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  178. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  179. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  180. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  181. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  182. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  183. package/dist/providers/spec/adapter.d.ts +98 -0
  184. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  185. package/dist/providers/spec/evaluator.d.ts +45 -0
  186. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  187. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  188. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  189. package/dist/providers/spec/fsm-types.d.ts +202 -0
  190. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  191. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  192. package/dist/providers/spec/route.d.ts +4 -0
  193. package/dist/providers/spec/types.d.ts +244 -0
  194. package/dist/providers/status-monitor.d.ts +7 -7
  195. package/dist/providers/transcript-v2.d.ts +176 -0
  196. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  197. package/dist/providers/working-dir.d.ts +17 -0
  198. package/dist/repo-mesh-types.d.ts +616 -12
  199. package/dist/runtime-defaults.d.ts +2 -0
  200. package/dist/session-host/managed-host.d.ts +64 -0
  201. package/dist/session-host/runtime-surface.d.ts +10 -16
  202. package/dist/sessions/registry.d.ts +26 -0
  203. package/dist/shared-types-extra.d.ts +2 -4
  204. package/dist/shared-types.d.ts +110 -55
  205. package/dist/status/chat-tail-hot-sessions.d.ts +40 -0
  206. package/dist/status/normalize.d.ts +1 -1
  207. package/dist/status/normalize.js +1 -0
  208. package/dist/status/normalize.js.map +1 -1
  209. package/dist/status/normalize.mjs +1 -0
  210. package/dist/status/normalize.mjs.map +1 -1
  211. package/dist/status/reporter.d.ts +2 -0
  212. package/dist/status/snapshot.d.ts +27 -0
  213. package/dist/system/hash.d.ts +8 -0
  214. package/dist/system/load-better-sqlite3.d.ts +21 -0
  215. package/dist/types.d.ts +20 -6
  216. package/package.json +11 -4
  217. package/src/agent-stream/poller.ts +2 -3
  218. package/src/agent-stream/provider-adapter.ts +1 -1
  219. package/src/boot/daemon-lifecycle.ts +80 -14
  220. package/src/boot/process-hardening.ts +89 -0
  221. package/src/build-info.ts +73 -0
  222. package/src/chat/source-machine.ts +534 -0
  223. package/src/chat/source-resolver.ts +0 -0
  224. package/src/chat/subscription-updates.ts +20 -1
  225. package/src/cli-adapter-types.d.ts +3 -1
  226. package/src/cli-adapter-types.ts +68 -2
  227. package/src/cli-adapters/cli-script-runner.ts +421 -0
  228. package/src/cli-adapters/cli-state-engine.ts +1282 -0
  229. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  230. package/src/cli-adapters/provider-cli-adapter.ts +1048 -1143
  231. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  232. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  233. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  234. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  235. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  236. package/src/cli-adapters/pty-transport.ts +2 -1
  237. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  238. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  239. package/src/cli-adapters/resolve-executable.ts +204 -0
  240. package/src/cli-adapters/session-host-transport.ts +2 -1
  241. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  242. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  243. package/src/cli-adapters/terminal-screen.ts +16 -81
  244. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  245. package/src/commands/chat-commands-read.ts +2788 -0
  246. package/src/commands/chat-commands-scope.ts +54 -0
  247. package/src/commands/chat-commands-shared.ts +114 -0
  248. package/src/commands/chat-commands-write.ts +891 -0
  249. package/src/commands/chat-commands.ts +19 -1841
  250. package/src/commands/cli-manager.d.ts +2 -0
  251. package/src/commands/cli-manager.ts +724 -27
  252. package/src/commands/handler.ts +865 -2
  253. package/src/commands/high-family/index.ts +28 -0
  254. package/src/commands/high-family/mesh-coordinator-launch.ts +696 -0
  255. package/src/commands/high-family/mesh-events.ts +102 -0
  256. package/src/commands/high-family/mesh-status.ts +857 -0
  257. package/src/commands/high-family/types.ts +80 -0
  258. package/src/commands/low-family/coordinator-prompt.ts +125 -0
  259. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  260. package/src/commands/low-family/diagnostics.ts +57 -0
  261. package/src/commands/low-family/index.ts +37 -0
  262. package/src/commands/low-family/mesh-ledger.ts +62 -0
  263. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  264. package/src/commands/low-family/notification.ts +116 -0
  265. package/src/commands/low-family/refine-config.ts +106 -0
  266. package/src/commands/low-family/session-host.ts +282 -0
  267. package/src/commands/low-family/spec-providerdev.ts +217 -0
  268. package/src/commands/low-family/status-meta.ts +112 -0
  269. package/src/commands/low-family/types.ts +39 -0
  270. package/src/commands/med-family/cli-agent.ts +270 -0
  271. package/src/commands/med-family/fast-forward.ts +230 -0
  272. package/src/commands/med-family/ide.ts +163 -0
  273. package/src/commands/med-family/index.ts +37 -0
  274. package/src/commands/med-family/mesh-crud.ts +1268 -0
  275. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  276. package/src/commands/med-family/mesh-queue.ts +167 -0
  277. package/src/commands/med-family/mesh-restart.ts +92 -0
  278. package/src/commands/med-family/types.ts +153 -0
  279. package/src/commands/mesh-coordinator.ts +334 -124
  280. package/src/commands/router-aggregate-status.ts +209 -0
  281. package/src/commands/router-mesh-session-owner.ts +114 -0
  282. package/src/commands/router-refine.ts +1794 -0
  283. package/src/commands/router-worktree-cleanup.ts +870 -0
  284. package/src/commands/router.ts +567 -4149
  285. package/src/commands/stream-commands.ts +8 -0
  286. package/src/commands/upgrade-helper.ts +310 -45
  287. package/src/config/chat-history.ts +517 -24
  288. package/src/config/config.ts +30 -0
  289. package/src/config/mesh-config.ts +300 -24
  290. package/src/config/mesh-json-config.ts +376 -0
  291. package/src/config/recent-activity.ts +8 -2
  292. package/src/config/registry-resolver.ts +100 -0
  293. package/src/config/repo-settings.ts +111 -0
  294. package/src/config/state-store.ts +55 -0
  295. package/src/daemon/dev-auto-implement.ts +3 -2
  296. package/src/daemon/dev-cli-debug.ts +10 -1
  297. package/src/daemon/dev-server.ts +0 -541
  298. package/src/detection/cli-detector.ts +94 -9
  299. package/src/detection/ide-detector.ts +55 -16
  300. package/src/detection/win32-ide-version.ts +106 -0
  301. package/src/git/change-impact-config.ts +354 -0
  302. package/src/git/git-commands.ts +112 -16
  303. package/src/git/git-diff.ts +81 -11
  304. package/src/git/git-executor.ts +12 -0
  305. package/src/git/git-status.ts +822 -48
  306. package/src/git/git-types.ts +14 -62
  307. package/src/git/git-worktree.ts +261 -4
  308. package/src/git/index.ts +17 -0
  309. package/src/index.ts +190 -13
  310. package/src/installer.d.ts +1 -1
  311. package/src/installer.ts +8 -6
  312. package/src/ipc/local-ipc-server.ts +278 -0
  313. package/src/launch.d.ts +1 -1
  314. package/src/launch.ts +37 -28
  315. package/src/logging/async-batch-writer.ts +55 -0
  316. package/src/logging/command-log.ts +7 -5
  317. package/src/logging/debug-config.ts +25 -0
  318. package/src/logging/debug-trace.ts +7 -2
  319. package/src/logging/log-redactor.ts +100 -0
  320. package/src/logging/log-tail-reader.ts +341 -0
  321. package/src/logging/logger.ts +14 -7
  322. package/src/mesh/contracts.ts +510 -0
  323. package/src/mesh/coordinator-prompt.ts +627 -34
  324. package/src/mesh/coordinator-registry.ts +121 -0
  325. package/src/mesh/mesh-active-work.ts +706 -0
  326. package/src/mesh/mesh-clone-grace.ts +68 -0
  327. package/src/mesh/mesh-completion-synthesis.ts +416 -0
  328. package/src/mesh/mesh-coordinator-config.ts +97 -0
  329. package/src/mesh/mesh-delivery-policy.ts +284 -0
  330. package/src/mesh/mesh-event-classify.ts +78 -0
  331. package/src/mesh/mesh-event-forwarding.ts +2030 -0
  332. package/src/mesh/mesh-event-trace.ts +67 -0
  333. package/src/mesh/mesh-events-coordinator.ts +32 -0
  334. package/src/mesh/mesh-events-pending.ts +1548 -0
  335. package/src/mesh/mesh-events-stale.ts +452 -0
  336. package/src/mesh/mesh-events-utils.ts +443 -0
  337. package/src/mesh/mesh-events.ts +43 -1035
  338. package/src/mesh/mesh-fast-forward.ts +856 -0
  339. package/src/mesh/mesh-host-ownership.ts +41 -3
  340. package/src/mesh/mesh-init.ts +350 -0
  341. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  342. package/src/mesh/mesh-ledger.ts +897 -102
  343. package/src/mesh/mesh-magi-status.ts +223 -0
  344. package/src/mesh/mesh-missions.ts +695 -0
  345. package/src/mesh/mesh-node-identity.ts +2065 -0
  346. package/src/mesh/mesh-queue-assignment.ts +2498 -0
  347. package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
  348. package/src/mesh/mesh-reconcile-config.ts +66 -0
  349. package/src/mesh/mesh-reconcile-identity.ts +103 -0
  350. package/src/mesh/mesh-reconcile-loop.ts +1696 -0
  351. package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
  352. package/src/mesh/mesh-refine-batch.ts +205 -0
  353. package/src/mesh/mesh-refine-gates.ts +1792 -0
  354. package/src/mesh/mesh-refine-status.ts +231 -0
  355. package/src/mesh/mesh-remote-event-pull.ts +279 -0
  356. package/src/mesh/mesh-review-inbox.ts +308 -0
  357. package/src/mesh/mesh-routing.ts +291 -0
  358. package/src/mesh/mesh-runtime-store.ts +2292 -0
  359. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  360. package/src/mesh/mesh-task-inflight.ts +70 -0
  361. package/src/mesh/mesh-task-stats.ts +161 -0
  362. package/src/mesh/mesh-unresolved-forward-outbox.ts +215 -0
  363. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  364. package/src/mesh/mesh-work-queue.ts +1489 -145
  365. package/src/mesh/preview-freshness.ts +163 -0
  366. package/src/mesh/refine-config.ts +129 -12
  367. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  368. package/src/providers/acp-provider-instance.ts +43 -10
  369. package/src/providers/approval-utils.d.ts +5 -0
  370. package/src/providers/approval-utils.ts +100 -6
  371. package/src/providers/chat-message-normalization.ts +126 -4
  372. package/src/providers/cli-provider-effect-format.ts +53 -0
  373. package/src/providers/cli-provider-history-dedup.ts +75 -0
  374. package/src/providers/cli-provider-input-prompt.ts +133 -0
  375. package/src/providers/cli-provider-instance-types.ts +131 -0
  376. package/src/providers/cli-provider-instance.ts +2771 -499
  377. package/src/providers/cli-provider-status-helpers.ts +123 -0
  378. package/src/providers/cli-provider-transcript-merge.ts +114 -0
  379. package/src/providers/contracts.d.ts +55 -0
  380. package/src/providers/contracts.ts +207 -6
  381. package/src/providers/extension-provider-instance.ts +12 -7
  382. package/src/providers/external-sources.ts +218 -0
  383. package/src/providers/ide-provider-instance.ts +35 -12
  384. package/src/providers/manual-attendance.ts +105 -0
  385. package/src/providers/native-history/antigravity-claim-registry.ts +138 -0
  386. package/src/providers/native-history/antigravity-cli-transcript.ts +1275 -0
  387. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  388. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  389. package/src/providers/native-history/constants.ts +19 -0
  390. package/src/providers/native-history/dispatcher.ts +617 -0
  391. package/src/providers/native-history/hermes-cli-transcript.ts +312 -0
  392. package/src/providers/native-history/index.ts +30 -0
  393. package/src/providers/provider-instance-manager.ts +71 -0
  394. package/src/providers/provider-instance.ts +24 -1
  395. package/src/providers/provider-loader.ts +700 -55
  396. package/src/providers/provider-schema.ts +93 -14
  397. package/src/providers/provider-trust.ts +114 -0
  398. package/src/providers/read-chat-contract.ts +76 -16
  399. package/src/providers/sdk/README.md +49 -0
  400. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  401. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  402. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  403. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  404. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  405. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  406. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  407. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  408. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  409. package/src/providers/sdk/v1/index.ts +152 -0
  410. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  411. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  412. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  413. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +538 -0
  414. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  415. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  416. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  417. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  418. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  419. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  420. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  421. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  422. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  423. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  424. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  425. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  426. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  427. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  428. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  429. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  430. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  431. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  432. package/src/providers/sdk/v1/validators/index.ts +19 -0
  433. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  434. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  435. package/src/providers/spec/adapter.ts +246 -0
  436. package/src/providers/spec/cli-adapter.ts +1064 -0
  437. package/src/providers/spec/evaluator.ts +407 -0
  438. package/src/providers/spec/fsm-driver.ts +1528 -0
  439. package/src/providers/spec/fsm-evaluator.ts +290 -0
  440. package/src/providers/spec/fsm-loader.ts +128 -0
  441. package/src/providers/spec/fsm-types.ts +301 -0
  442. package/src/providers/spec/native-history-executor.ts +1241 -0
  443. package/src/providers/spec/pre-launch-trust.ts +104 -0
  444. package/src/providers/spec/route.ts +51 -0
  445. package/src/providers/spec/types.ts +284 -0
  446. package/src/providers/status-monitor.d.ts +7 -7
  447. package/src/providers/status-monitor.ts +37 -22
  448. package/src/providers/transcript-v2.ts +567 -0
  449. package/src/providers/types/interactive-prompt.ts +536 -0
  450. package/src/providers/version-archive.ts +64 -24
  451. package/src/providers/working-dir.ts +23 -0
  452. package/src/repo-mesh-types.ts +861 -14
  453. package/src/runtime-defaults.ts +39 -0
  454. package/src/session-host/managed-host.ts +218 -0
  455. package/src/session-host/runtime-surface.ts +20 -80
  456. package/src/sessions/registry.ts +44 -0
  457. package/src/shared-types-extra.ts +2 -4
  458. package/src/shared-types.d.ts +8 -0
  459. package/src/shared-types.ts +148 -55
  460. package/src/status/builders.ts +69 -6
  461. package/src/status/chat-tail-hot-sessions.ts +117 -2
  462. package/src/status/normalize.ts +2 -0
  463. package/src/status/reporter.ts +19 -1
  464. package/src/status/snapshot.ts +100 -27
  465. package/src/system/hash.ts +23 -0
  466. package/src/system/host-memory.ts +29 -12
  467. package/src/system/load-better-sqlite3.ts +68 -0
  468. package/src/types.ts +26 -6
  469. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  470. package/dist/mesh/mesh-sync.d.ts +0 -53
  471. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  472. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  473. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,856 @@
1
+ import type { GitRepoStatus, GitSubmoduleStatus } from '../git/git-types.js';
2
+ import { getGitRepoStatus } from '../git/git-status.js';
3
+ import { GitCommandError, runGit } from '../git/git-executor.js';
4
+ import { resolveSubmoduleDefaultBranch } from './worktree-bootstrap-config.js';
5
+
6
+ export interface MeshFastForwardNodeArgs {
7
+ nodeId?: string;
8
+ meshId?: string;
9
+ workspace: string;
10
+ branch?: string;
11
+ execute?: boolean;
12
+ dryRun?: boolean;
13
+ updateSubmodules?: boolean;
14
+ submoduleIgnorePaths?: string[];
15
+ timeoutMs?: number;
16
+ trigger?: 'manual' | 'idle_auto' | string;
17
+ /**
18
+ * Operation mode. 'merge' (default) absorbs upstream commits into the local
19
+ * branch via git merge --ff-only (requires ahead=0, behind>0). 'push' publishes
20
+ * local commits to origin via a strict ff-only push (requires HEAD to be a
21
+ * descendant of origin/<branch>); it never force-pushes, resets, or rebases.
22
+ */
23
+ mode?: 'merge' | 'push';
24
+ /**
25
+ * When mode='push', also fast-forward push submodule (e.g. oss) HEADs to their
26
+ * origin main branch. Gated by allowAutoPublishSubmoduleMainCommits — skipped
27
+ * unless that policy is true. Each submodule must still pass the descendant gate.
28
+ * Defaults false (root push only).
29
+ */
30
+ pushSubmodules?: boolean;
31
+ /**
32
+ * Mesh policy flag mirrored from RepoMeshPolicy.allowAutoPublishSubmoduleMainCommits.
33
+ * Submodule pushes are refused unless this is true.
34
+ */
35
+ allowAutoPublishSubmoduleMainCommits?: boolean;
36
+ }
37
+
38
+ export interface MeshFastForwardPlannedStep {
39
+ operation: 'refresh_upstream' | 'verify_clean_worktree' | 'verify_fast_forward' | 'merge_ff_only'
40
+ | 'submodule_update' | 'verify_post_status' | 'verify_push_descendant' | 'push_ff_only' | 'push_submodules_ff_only';
41
+ description: string;
42
+ safe: true;
43
+ willMutateWorktree: boolean;
44
+ }
45
+
46
+ export interface MeshFastForwardSubmodulePushResult {
47
+ path: string;
48
+ commit?: string;
49
+ remote: string;
50
+ remoteBranch: string;
51
+ pushed: boolean;
52
+ skipped: boolean;
53
+ code: string;
54
+ refspec?: string;
55
+ error?: string;
56
+ }
57
+
58
+ export interface MeshFastForwardResult {
59
+ success: boolean;
60
+ code: string;
61
+ nodeId?: string;
62
+ meshId?: string;
63
+ workspace: string;
64
+ mode: 'merge' | 'push';
65
+ allowed: boolean;
66
+ dryRun: boolean;
67
+ willRun: boolean;
68
+ executed: boolean;
69
+ updateSubmodules: boolean;
70
+ blockingReasons: string[];
71
+ plannedSteps: MeshFastForwardPlannedStep[];
72
+ current?: GitRepoStatus;
73
+ preStatus?: GitRepoStatus;
74
+ postStatus?: GitRepoStatus;
75
+ /** Push target derived from the tracked upstream (mode='push'). */
76
+ pushTarget?: { remote: string; remoteBranch: string; refspec: string };
77
+ /** Submodule ff-only push outcomes (mode='push' with pushSubmodules). */
78
+ submodulePushes?: MeshFastForwardSubmodulePushResult[];
79
+ finalBranchConvergenceState?: Record<string, unknown>;
80
+ operationError?: string;
81
+ ledgerError?: string;
82
+ nextStep?: string;
83
+ trigger?: string;
84
+ }
85
+
86
+ type MeshFastForwardBase = Pick<
87
+ MeshFastForwardResult,
88
+ 'workspace' | 'mode' | 'dryRun' | 'updateSubmodules' | 'plannedSteps' | 'trigger'
89
+ > & Pick<Partial<MeshFastForwardResult>, 'nodeId' | 'meshId'>;
90
+
91
+ // forceFresh: fast-forward is a mutating/decision path — its preflight blockers and its
92
+ // post-merge re-reads MUST see live git state, never a TTL-cached status from a
93
+ // concurrent reconcile/mesh_status probe. It also bypasses the fetch throttle so
94
+ // ahead/behind reflects a true upstream at decision time.
95
+ const STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15_000, forceFresh: true } as const;
96
+
97
+ export async function fastForwardMeshNode(args: MeshFastForwardNodeArgs): Promise<MeshFastForwardResult> {
98
+ const workspace = typeof args.workspace === 'string' ? args.workspace.trim() : '';
99
+ const nodeId = normalizeOptionalString(args.nodeId);
100
+ const meshId = normalizeOptionalString(args.meshId);
101
+ const requestedBranch = normalizeOptionalString(args.branch);
102
+ const trigger = normalizeOptionalString(args.trigger) || 'manual';
103
+ const updateSubmodules = args.updateSubmodules === true;
104
+ const dryRun = args.dryRun === true || args.execute !== true;
105
+ const mode: 'merge' | 'push' = args.mode === 'push' ? 'push' : 'merge';
106
+ const pushSubmodules = mode === 'push' && args.pushSubmodules === true;
107
+ const plannedSteps = buildPlannedSteps(mode, updateSubmodules, pushSubmodules);
108
+ const base: MeshFastForwardBase = {
109
+ ...(nodeId ? { nodeId } : {}),
110
+ ...(meshId ? { meshId } : {}),
111
+ workspace,
112
+ mode,
113
+ dryRun,
114
+ updateSubmodules,
115
+ plannedSteps,
116
+ trigger,
117
+ };
118
+
119
+ if (!workspace) {
120
+ return block(base, 'invalid_workspace', ['workspace_required']);
121
+ }
122
+
123
+ const current = await getGitRepoStatus(workspace, {
124
+ ...STATUS_OPTIONS,
125
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
126
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs,
127
+ });
128
+
129
+ if (mode === 'push') {
130
+ return pushMeshNode(base, args, current, {
131
+ pushSubmodules,
132
+ allowAutoPublishSubmoduleMainCommits: args.allowAutoPublishSubmoduleMainCommits === true,
133
+ });
134
+ }
135
+
136
+ const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
137
+ if (earlyBlockers.length > 0) {
138
+ const blockCode = chooseBlockCode(current, earlyBlockers);
139
+ const result: MeshFastForwardResult = {
140
+ ...block(base, blockCode, earlyBlockers),
141
+ current,
142
+ finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(blockCode)),
143
+ };
144
+ // Pure ahead (local commits not yet on origin, nothing to merge in) is not a
145
+ // hard failure — it's a push-needed case. Reclassify so the coordinator can
146
+ // route to push mode without launching an agent session.
147
+ if (blockCode === 'branch_ahead' && current.ahead > 0 && current.behind === 0 && otherBlockersAreOnlyAhead(earlyBlockers)) {
148
+ result.code = 'ahead_needs_push';
149
+ result.nextStep = 'Local branch is ahead of origin with nothing to merge. Re-run mesh_fast_forward_node with mode="push" (execute=true) to ff-only push the local commits to origin.';
150
+ }
151
+ await appendFastForwardLedger(result, 'blocked');
152
+ return result;
153
+ }
154
+
155
+ if (current.behind === 0) {
156
+ const result: MeshFastForwardResult = {
157
+ ...base,
158
+ success: true,
159
+ code: 'already_up_to_date',
160
+ allowed: true,
161
+ willRun: false,
162
+ executed: false,
163
+ blockingReasons: [],
164
+ current,
165
+ preStatus: current,
166
+ postStatus: current,
167
+ finalBranchConvergenceState: buildConvergenceState(current, 'up_to_date'),
168
+ };
169
+ await appendFastForwardLedger(result, 'noop');
170
+ return result;
171
+ }
172
+
173
+ const ancestorCheck = await verifyHeadIsAncestorOfUpstream(workspace, current.upstream || '', args.timeoutMs);
174
+ if (!ancestorCheck.ok) {
175
+ const result: MeshFastForwardResult = {
176
+ ...block(base, 'non_fast_forward', ['head_is_not_ancestor_of_upstream']),
177
+ current,
178
+ preStatus: current,
179
+ operationError: ancestorCheck.error,
180
+ finalBranchConvergenceState: buildConvergenceState(current, 'not_mergeable'),
181
+ };
182
+ await appendFastForwardLedger(result, 'blocked');
183
+ return result;
184
+ }
185
+
186
+ if (dryRun) {
187
+ const result: MeshFastForwardResult = {
188
+ ...base,
189
+ success: true,
190
+ code: 'fast_forward_available',
191
+ allowed: true,
192
+ willRun: false,
193
+ executed: false,
194
+ blockingReasons: [],
195
+ current,
196
+ preStatus: current,
197
+ finalBranchConvergenceState: buildConvergenceState(current, 'fast_forward_available'),
198
+ };
199
+ await appendFastForwardLedger(result, 'dry_run');
200
+ return result;
201
+ }
202
+
203
+ try {
204
+ await runGit(workspace, ['merge', '--ff-only', current.upstream || ''], { timeoutMs: args.timeoutMs ?? 30_000 });
205
+ } catch (error) {
206
+ const result: MeshFastForwardResult = {
207
+ ...block(base, 'merge_ff_only_failed', ['merge_ff_only_failed']),
208
+ current,
209
+ preStatus: current,
210
+ operationError: formatGitError(error),
211
+ finalBranchConvergenceState: buildConvergenceState(current, 'not_mergeable'),
212
+ };
213
+ await appendFastForwardLedger(result, 'failed');
214
+ return result;
215
+ }
216
+
217
+ let postStatus = await getGitRepoStatus(workspace, {
218
+ ...STATUS_OPTIONS,
219
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
220
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs,
221
+ });
222
+
223
+ const submoduleIssues = collectSubmoduleBlockers(postStatus, 'post');
224
+ let submoduleFollowUpRequired = false;
225
+ let operationError: string | undefined;
226
+ if (submoduleIssues.length > 0) {
227
+ if (updateSubmodules) {
228
+ try {
229
+ await runGit(workspace, ['submodule', 'update', '--init', '--recursive'], { timeoutMs: args.timeoutMs ?? 60_000 });
230
+ postStatus = await getGitRepoStatus(workspace, {
231
+ ...STATUS_OPTIONS,
232
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
233
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs,
234
+ });
235
+ } catch (error) {
236
+ operationError = formatGitError(error);
237
+ }
238
+ } else {
239
+ submoduleFollowUpRequired = true;
240
+ }
241
+ }
242
+
243
+ const postBlockers = collectPostExecutionBlockers(postStatus);
244
+ if (operationError) postBlockers.push('submodule_update_failed');
245
+ if (submoduleFollowUpRequired) postBlockers.push('submodule_update_required');
246
+
247
+ const success = postBlockers.length === 0 || submoduleFollowUpRequired;
248
+ const code = postBlockers.length === 0
249
+ ? 'fast_forward_applied'
250
+ : submoduleFollowUpRequired
251
+ ? 'fast_forward_applied_submodule_update_required'
252
+ : 'post_verify_failed';
253
+ const result: MeshFastForwardResult = {
254
+ ...base,
255
+ success,
256
+ code,
257
+ allowed: true,
258
+ willRun: true,
259
+ executed: true,
260
+ blockingReasons: postBlockers,
261
+ current,
262
+ preStatus: current,
263
+ postStatus,
264
+ ...(operationError ? { operationError } : {}),
265
+ finalBranchConvergenceState: buildConvergenceState(
266
+ postStatus,
267
+ postBlockers.length === 0 ? 'fast_forwarded' : submoduleFollowUpRequired ? 'follow_up_required' : 'post_verify_failed',
268
+ ),
269
+ };
270
+ await appendFastForwardLedger(result, success ? 'executed' : 'failed');
271
+ return result;
272
+ }
273
+
274
+ interface PushOptions {
275
+ pushSubmodules: boolean;
276
+ allowAutoPublishSubmoduleMainCommits: boolean;
277
+ }
278
+
279
+ /**
280
+ * Strict ff-only push of a node's local commits to origin/<branch>. Only proceeds
281
+ * when HEAD is a descendant of origin/<branch> (origin/<branch> is an ancestor of
282
+ * HEAD). Never force-pushes, resets, rebases, cleans, or checks out. Optionally
283
+ * ff-only pushes submodule HEADs to their origin main when policy allows.
284
+ */
285
+ async function pushMeshNode(
286
+ base: MeshFastForwardBase,
287
+ args: MeshFastForwardNodeArgs,
288
+ current: GitRepoStatus,
289
+ options: PushOptions,
290
+ ): Promise<MeshFastForwardResult> {
291
+ const workspace = base.workspace;
292
+ const requestedBranch = normalizeOptionalString(args.branch);
293
+ const dryRun = base.dryRun;
294
+
295
+ const blockers = collectPushPreflightBlockers(current, requestedBranch);
296
+ if (blockers.length > 0) {
297
+ const code = choosePushBlockCode(current, blockers);
298
+ const result: MeshFastForwardResult = {
299
+ ...block(base, code, blockers),
300
+ current,
301
+ preStatus: current,
302
+ finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(code)),
303
+ };
304
+ await appendFastForwardLedger(result, 'blocked');
305
+ return result;
306
+ }
307
+
308
+ const target = parseUpstreamTarget(current.upstream || '');
309
+ if (!target) {
310
+ const result: MeshFastForwardResult = {
311
+ ...block(base, 'upstream_unparseable', ['upstream_unparseable']),
312
+ current,
313
+ preStatus: current,
314
+ finalBranchConvergenceState: buildConvergenceState(current, 'blocked'),
315
+ };
316
+ await appendFastForwardLedger(result, 'blocked');
317
+ return result;
318
+ }
319
+ const refspec = `HEAD:refs/heads/${target.remoteBranch}`;
320
+ const pushTarget = { remote: target.remote, remoteBranch: target.remoteBranch, refspec };
321
+
322
+ if (current.ahead <= 0) {
323
+ // Nothing local to publish.
324
+ const result: MeshFastForwardResult = {
325
+ ...base,
326
+ success: true,
327
+ code: 'nothing_to_push',
328
+ allowed: true,
329
+ willRun: false,
330
+ executed: false,
331
+ blockingReasons: [],
332
+ current,
333
+ preStatus: current,
334
+ postStatus: current,
335
+ pushTarget,
336
+ finalBranchConvergenceState: buildConvergenceState(current, 'up_to_date'),
337
+ };
338
+ await appendFastForwardLedger(result, 'noop');
339
+ return result;
340
+ }
341
+
342
+ // Strict ff-only gate: origin/<branch> must be an ancestor of HEAD.
343
+ const descendant = await verifyUpstreamIsAncestorOfHead(workspace, current.upstream || '', args.timeoutMs);
344
+ if (!descendant.ok) {
345
+ const result: MeshFastForwardResult = {
346
+ ...block(base, 'non_fast_forward_push', ['head_is_not_descendant_of_upstream']),
347
+ current,
348
+ preStatus: current,
349
+ pushTarget,
350
+ operationError: descendant.error,
351
+ nextStep: 'origin/<branch> has commits not in local HEAD; a ff-only push would lose them. Converge by rebasing onto origin first, then re-run. This operation never force-pushes.',
352
+ finalBranchConvergenceState: buildConvergenceState(current, 'not_mergeable'),
353
+ };
354
+ await appendFastForwardLedger(result, 'blocked');
355
+ return result;
356
+ }
357
+
358
+ if (dryRun) {
359
+ const result: MeshFastForwardResult = {
360
+ ...base,
361
+ success: true,
362
+ code: 'push_available',
363
+ allowed: true,
364
+ willRun: false,
365
+ executed: false,
366
+ blockingReasons: [],
367
+ current,
368
+ preStatus: current,
369
+ pushTarget,
370
+ ...(options.pushSubmodules ? { submodulePushes: await planSubmodulePushes(current, options, args.timeoutMs) } : {}),
371
+ finalBranchConvergenceState: buildConvergenceState(current, 'push_available'),
372
+ };
373
+ await appendFastForwardLedger(result, 'dry_run');
374
+ return result;
375
+ }
376
+
377
+ // Execute the root ff-only push.
378
+ try {
379
+ await runGit(workspace, ['push', target.remote, refspec], { timeoutMs: args.timeoutMs ?? 30_000 });
380
+ } catch (error) {
381
+ const result: MeshFastForwardResult = {
382
+ ...block(base, 'push_ff_only_failed', ['push_ff_only_failed']),
383
+ current,
384
+ preStatus: current,
385
+ pushTarget,
386
+ operationError: formatGitError(error),
387
+ finalBranchConvergenceState: buildConvergenceState(current, 'not_mergeable'),
388
+ };
389
+ await appendFastForwardLedger(result, 'failed');
390
+ return result;
391
+ }
392
+
393
+ let submodulePushes: MeshFastForwardSubmodulePushResult[] | undefined;
394
+ if (options.pushSubmodules) {
395
+ submodulePushes = await executeSubmodulePushes(current, options, args.timeoutMs);
396
+ }
397
+
398
+ const postStatus = await getGitRepoStatus(workspace, {
399
+ ...STATUS_OPTIONS,
400
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
401
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs,
402
+ });
403
+
404
+ const submodulePushFailed = (submodulePushes || []).some((entry) => !entry.pushed && !entry.skipped);
405
+ const blockingReasons: string[] = [];
406
+ if (postStatus.ahead !== 0) blockingReasons.push('post_branch_ahead');
407
+ if (submodulePushFailed) blockingReasons.push('submodule_push_failed');
408
+
409
+ const success = blockingReasons.length === 0;
410
+ const code = success
411
+ ? 'push_applied'
412
+ : submodulePushFailed && postStatus.ahead === 0
413
+ ? 'push_applied_submodule_push_failed'
414
+ : 'post_push_verify_failed';
415
+ const result: MeshFastForwardResult = {
416
+ ...base,
417
+ success,
418
+ code,
419
+ allowed: true,
420
+ willRun: true,
421
+ executed: true,
422
+ blockingReasons,
423
+ current,
424
+ preStatus: current,
425
+ postStatus,
426
+ pushTarget,
427
+ ...(submodulePushes ? { submodulePushes } : {}),
428
+ finalBranchConvergenceState: buildConvergenceState(postStatus, success ? 'pushed' : 'post_verify_failed'),
429
+ };
430
+ await appendFastForwardLedger(result, success ? 'executed' : 'failed');
431
+ return result;
432
+ }
433
+
434
+ function collectPushPreflightBlockers(status: GitRepoStatus, requestedBranch?: string): string[] {
435
+ const blockers: string[] = [];
436
+ if (!status.isGitRepo) blockers.push('not_git_repo');
437
+ if (!status.branch) blockers.push('detached_head_or_unknown_branch');
438
+ if (requestedBranch && status.branch !== requestedBranch) blockers.push('branch_mismatch');
439
+ if (!status.upstream) blockers.push('upstream_missing');
440
+ if (status.upstreamStatus !== 'fresh') blockers.push('upstream_not_fresh');
441
+ if (status.hasConflicts) blockers.push('conflicts_present');
442
+ if (status.staged > 0) blockers.push('staged_changes_present');
443
+ if (status.modified > 0) blockers.push('modified_changes_present');
444
+ if (status.untracked > 0) blockers.push('untracked_changes_present');
445
+ if (status.deleted > 0) blockers.push('deleted_changes_present');
446
+ if (status.renamed > 0) blockers.push('renamed_changes_present');
447
+ if (status.stashCount > 0) blockers.push('stash_entries_present');
448
+ // A diverged branch (ahead>0 AND behind>0) cannot ff-only push: origin has
449
+ // commits not in HEAD. The descendant gate also catches this, but flagging it
450
+ // in preflight gives a clearer code.
451
+ if (status.ahead > 0 && status.behind > 0) blockers.push('branch_diverged_from_upstream');
452
+ else if (status.behind > 0) blockers.push('branch_behind_upstream');
453
+ return blockers;
454
+ }
455
+
456
+ function choosePushBlockCode(status: GitRepoStatus, blockers: string[]): string {
457
+ if (blockers.includes('not_git_repo')) return 'not_git_repo';
458
+ if (blockers.includes('branch_mismatch')) return 'branch_mismatch';
459
+ if (blockers.includes('upstream_missing')) return 'upstream_missing';
460
+ if (blockers.includes('upstream_not_fresh')) return 'upstream_not_fresh';
461
+ if (blockers.includes('branch_diverged_from_upstream')) return 'branch_diverged';
462
+ if (blockers.includes('branch_behind_upstream')) return 'non_fast_forward_push';
463
+ if (blockers.some((reason) => reason.includes('changes') || reason.includes('conflicts') || reason.includes('stash'))) return 'dirty_worktree';
464
+ return 'preflight_blocked';
465
+ }
466
+
467
+ /** Parse an upstream ref like "origin/main" into { remote, remoteBranch }. */
468
+ function parseUpstreamTarget(upstream: string): { remote: string; remoteBranch: string } | null {
469
+ const trimmed = upstream.trim();
470
+ const slash = trimmed.indexOf('/');
471
+ if (slash <= 0 || slash >= trimmed.length - 1) return null;
472
+ return { remote: trimmed.slice(0, slash), remoteBranch: trimmed.slice(slash + 1) };
473
+ }
474
+
475
+ async function verifyUpstreamIsAncestorOfHead(workspace: string, upstream: string, timeoutMs?: number): Promise<{ ok: boolean; error?: string }> {
476
+ if (!upstream) return { ok: false, error: 'missing upstream' };
477
+ try {
478
+ await runGit(workspace, ['merge-base', '--is-ancestor', upstream, 'HEAD'], { timeoutMs: timeoutMs ?? 15_000 });
479
+ return { ok: true };
480
+ } catch (error) {
481
+ return { ok: false, error: formatGitError(error) };
482
+ }
483
+ }
484
+
485
+ /** Dry-run plan for submodule pushes: classify each as would-push / skipped / blocked. */
486
+ async function planSubmodulePushes(status: GitRepoStatus, options: PushOptions, timeoutMs?: number): Promise<MeshFastForwardSubmodulePushResult[]> {
487
+ return resolveSubmodulePushes(status, options, false, timeoutMs);
488
+ }
489
+
490
+ async function executeSubmodulePushes(status: GitRepoStatus, options: PushOptions, timeoutMs?: number): Promise<MeshFastForwardSubmodulePushResult[]> {
491
+ return resolveSubmodulePushes(status, options, true, timeoutMs);
492
+ }
493
+
494
+ async function resolveSubmodulePushes(
495
+ status: GitRepoStatus,
496
+ options: PushOptions,
497
+ execute: boolean,
498
+ timeoutMs?: number,
499
+ ): Promise<MeshFastForwardSubmodulePushResult[]> {
500
+ const submodules = Array.isArray(status.submodules) ? status.submodules : [];
501
+ const results: MeshFastForwardSubmodulePushResult[] = [];
502
+ for (const submodule of submodules) {
503
+ const base: MeshFastForwardSubmodulePushResult = {
504
+ path: submodule.path,
505
+ commit: submodule.commit,
506
+ remote: 'origin',
507
+ remoteBranch: 'main',
508
+ pushed: false,
509
+ skipped: true,
510
+ code: 'submodule_push_skipped',
511
+ };
512
+ if (!options.allowAutoPublishSubmoduleMainCommits) {
513
+ results.push({ ...base, code: 'submodule_push_policy_disabled', error: 'allowAutoPublishSubmoduleMainCommits is not enabled' });
514
+ continue;
515
+ }
516
+ if (submodule.error || submodule.dirty) {
517
+ results.push({ ...base, code: 'submodule_not_clean', error: submodule.error || 'submodule worktree is dirty' });
518
+ continue;
519
+ }
520
+ const repoPath = submodule.repoPath;
521
+ if (!repoPath || !submodule.commit) {
522
+ results.push({ ...base, code: 'submodule_status_incomplete' });
523
+ continue;
524
+ }
525
+ // Generalize the submodule's default branch (F18): '.gitmodules' branch →
526
+ // local remote HEAD → remote-advertised HEAD → 'main'. On a main-default
527
+ // submodule this resolves to 'main', keeping every ref below byte-identical.
528
+ const remoteBranch = await resolveSubmoduleDefaultBranch({
529
+ submoduleRepoPath: repoPath,
530
+ superprojectWorkspace: status.repoRoot ?? status.workspace,
531
+ submodulePath: submodule.path,
532
+ timeoutMs,
533
+ });
534
+ base.remoteBranch = remoteBranch;
535
+ const remoteRef = `refs/remotes/origin/${remoteBranch}`;
536
+ const fetchRefspec = `refs/heads/${remoteBranch}:${remoteRef}`;
537
+ // Refresh the submodule's origin/<branch>, then require it to be an ancestor of
538
+ // the gitlink commit (strict ff-only).
539
+ try {
540
+ await runGit(repoPath, ['-c', 'protocol.file.allow=always', 'fetch', 'origin', fetchRefspec], { timeoutMs: timeoutMs ?? 30_000 });
541
+ } catch (error) {
542
+ results.push({ ...base, code: 'submodule_fetch_failed', error: formatGitError(error) });
543
+ continue;
544
+ }
545
+ let alreadyReachable = false;
546
+ try {
547
+ await runGit(repoPath, ['merge-base', '--is-ancestor', submodule.commit, remoteRef], { timeoutMs: timeoutMs ?? 15_000 });
548
+ alreadyReachable = true;
549
+ } catch { /* not yet on origin/<branch> — candidate for push */ }
550
+ if (alreadyReachable) {
551
+ results.push({ ...base, pushed: false, skipped: true, code: 'submodule_already_reachable' });
552
+ continue;
553
+ }
554
+ // Strict ff-only: origin/<branch> must be an ancestor of the commit we publish.
555
+ try {
556
+ await runGit(repoPath, ['merge-base', '--is-ancestor', remoteRef, submodule.commit], { timeoutMs: timeoutMs ?? 15_000 });
557
+ } catch (error) {
558
+ results.push({ ...base, pushed: false, skipped: false, code: 'submodule_non_fast_forward', error: formatGitError(error) });
559
+ continue;
560
+ }
561
+ const refspec = `${submodule.commit}:refs/heads/${remoteBranch}`;
562
+ if (!execute) {
563
+ results.push({ ...base, pushed: false, skipped: false, code: 'submodule_push_available', refspec });
564
+ continue;
565
+ }
566
+ try {
567
+ await runGit(repoPath, ['push', 'origin', refspec], { timeoutMs: timeoutMs ?? 30_000 });
568
+ // Verify reachability after the push.
569
+ await runGit(repoPath, ['-c', 'protocol.file.allow=always', 'fetch', 'origin', fetchRefspec], { timeoutMs: timeoutMs ?? 30_000 });
570
+ await runGit(repoPath, ['merge-base', '--is-ancestor', submodule.commit, remoteRef], { timeoutMs: timeoutMs ?? 15_000 });
571
+ results.push({ ...base, pushed: true, skipped: false, code: 'submodule_pushed', refspec });
572
+ } catch (error) {
573
+ results.push({ ...base, pushed: false, skipped: false, code: 'submodule_push_failed', refspec, error: formatGitError(error) });
574
+ }
575
+ }
576
+ return results;
577
+ }
578
+
579
+ function buildPlannedSteps(mode: 'merge' | 'push', updateSubmodules: boolean, pushSubmodules: boolean): MeshFastForwardPlannedStep[] {
580
+ const steps: MeshFastForwardPlannedStep[] = [
581
+ {
582
+ operation: 'refresh_upstream',
583
+ description: 'Refresh the tracked upstream remote ref before trusting ahead/behind state.',
584
+ safe: true,
585
+ willMutateWorktree: false,
586
+ },
587
+ {
588
+ operation: 'verify_clean_worktree',
589
+ description: 'Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.',
590
+ safe: true,
591
+ willMutateWorktree: false,
592
+ },
593
+ ];
594
+ if (mode === 'push') {
595
+ steps.push({
596
+ operation: 'verify_push_descendant',
597
+ description: 'Require HEAD to be a descendant of origin/<branch> (origin/<branch> is an ancestor of HEAD); refuse any non-fast-forward push.',
598
+ safe: true,
599
+ willMutateWorktree: false,
600
+ });
601
+ steps.push({
602
+ operation: 'push_ff_only',
603
+ description: 'Run git push origin HEAD:<branch> as a strict ff-only push; never --force, --force-with-lease, reset, or rebase. Does not mutate the worktree.',
604
+ safe: true,
605
+ willMutateWorktree: false,
606
+ });
607
+ if (pushSubmodules) {
608
+ steps.push({
609
+ operation: 'push_submodules_ff_only',
610
+ description: 'For each submodule, if allowAutoPublishSubmoduleMainCommits is enabled and the submodule HEAD is a descendant of its origin main, ff-only push it to submodule origin main; otherwise skip.',
611
+ safe: true,
612
+ willMutateWorktree: false,
613
+ });
614
+ }
615
+ steps.push({
616
+ operation: 'verify_post_status',
617
+ description: 'Re-read daemon-owned git status and report final branch convergence state.',
618
+ safe: true,
619
+ willMutateWorktree: false,
620
+ });
621
+ return steps;
622
+ }
623
+ steps.push({
624
+ operation: 'verify_fast_forward',
625
+ description: 'Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.',
626
+ safe: true,
627
+ willMutateWorktree: false,
628
+ });
629
+ steps.push({
630
+ operation: 'merge_ff_only',
631
+ description: 'Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.',
632
+ safe: true,
633
+ willMutateWorktree: true,
634
+ });
635
+ if (updateSubmodules) {
636
+ steps.push({
637
+ operation: 'submodule_update',
638
+ description: 'If the fast-forward changes gitlinks, run git submodule update --init --recursive and re-verify submodules.',
639
+ safe: true,
640
+ willMutateWorktree: true,
641
+ });
642
+ }
643
+ steps.push({
644
+ operation: 'verify_post_status',
645
+ description: 'Re-read daemon-owned git status and report final branch convergence state.',
646
+ safe: true,
647
+ willMutateWorktree: false,
648
+ });
649
+ return steps;
650
+ }
651
+
652
+ /**
653
+ * True when every preflight blocker is attributable purely to the branch being
654
+ * ahead of its upstream (local commits not yet pushed) — i.e. nothing dirty,
655
+ * diverged, or submodule-broken. Used to reclassify branch_ahead → ahead_needs_push.
656
+ */
657
+ function otherBlockersAreOnlyAhead(blockers: string[]): boolean {
658
+ const aheadOnly = new Set(['branch_has_local_commits']);
659
+ return blockers.every((reason) => aheadOnly.has(reason));
660
+ }
661
+
662
+ function collectPreflightBlockers(status: GitRepoStatus, requestedBranch?: string): string[] {
663
+ const blockers: string[] = [];
664
+ if (!status.isGitRepo) blockers.push('not_git_repo');
665
+ if (!status.branch) blockers.push('detached_head_or_unknown_branch');
666
+ if (requestedBranch && status.branch !== requestedBranch) blockers.push('branch_mismatch');
667
+ if (!status.upstream) blockers.push('upstream_missing');
668
+ if (status.upstreamStatus !== 'fresh') blockers.push('upstream_not_fresh');
669
+ if (status.hasConflicts) blockers.push('conflicts_present');
670
+ if (status.staged > 0) blockers.push('staged_changes_present');
671
+ if (status.modified > 0) blockers.push('modified_changes_present');
672
+ if (status.untracked > 0) blockers.push('untracked_changes_present');
673
+ if (status.deleted > 0) blockers.push('deleted_changes_present');
674
+ if (status.renamed > 0) blockers.push('renamed_changes_present');
675
+ if (status.stashCount > 0) blockers.push('stash_entries_present');
676
+ blockers.push(...collectSubmoduleBlockers(status, 'pre'));
677
+ if (status.ahead > 0 && status.behind > 0) {
678
+ blockers.push('branch_diverged_from_upstream');
679
+ blockers.push('branch_has_local_commits');
680
+ } else if (status.ahead > 0) blockers.push('branch_has_local_commits');
681
+ return blockers;
682
+ }
683
+
684
+ function collectPostExecutionBlockers(status: GitRepoStatus): string[] {
685
+ const blockers: string[] = [];
686
+ if (!status.isGitRepo) blockers.push('post_not_git_repo');
687
+ if (status.hasConflicts) blockers.push('post_conflicts_present');
688
+ if (status.ahead !== 0) blockers.push('post_branch_ahead');
689
+ if (status.behind !== 0) blockers.push('post_branch_still_behind');
690
+ if (status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0) {
691
+ blockers.push('post_working_tree_not_clean');
692
+ }
693
+ if (status.stashCount > 0) blockers.push('post_stash_entries_present');
694
+ blockers.push(...collectSubmoduleBlockers(status, 'post'));
695
+ return blockers;
696
+ }
697
+
698
+ function collectSubmoduleBlockers(status: GitRepoStatus, phase: 'pre' | 'post'): string[] {
699
+ const submodules = Array.isArray(status.submodules) ? status.submodules : [];
700
+ const blockers: string[] = [];
701
+ for (const submodule of submodules) {
702
+ if (submodule.error) blockers.push(`${phase}_submodule_status_error:${submodule.path}`);
703
+ if (submodule.dirty) blockers.push(`${phase}_submodule_dirty:${submodule.path}`);
704
+ if (submodule.outOfSync) blockers.push(`${phase}_submodule_out_of_sync:${submodule.path}`);
705
+ }
706
+ return blockers;
707
+ }
708
+
709
+ function chooseBlockCode(status: GitRepoStatus, blockers: string[]): string {
710
+ if (blockers.includes('not_git_repo')) return 'not_git_repo';
711
+ if (blockers.includes('branch_mismatch')) return 'branch_mismatch';
712
+ if (blockers.includes('upstream_missing')) return 'upstream_missing';
713
+ if (blockers.includes('upstream_not_fresh')) return 'upstream_not_fresh';
714
+ if (blockers.some((reason) => reason.includes('submodule'))) return 'submodule_not_clean';
715
+ if (blockers.includes('branch_diverged_from_upstream')) return 'branch_diverged';
716
+ if (blockers.includes('branch_has_local_commits') || status.ahead > 0) return 'branch_ahead';
717
+ if (blockers.some((reason) => reason.includes('changes') || reason.includes('conflicts') || reason.includes('stash'))) return 'dirty_worktree';
718
+ return 'preflight_blocked';
719
+ }
720
+
721
+ function codeToConvergenceStatus(code: string): string {
722
+ if (code === 'branch_diverged' || code === 'branch_ahead' || code === 'non_fast_forward'
723
+ || code === 'non_fast_forward_push' || code === 'upstream_unparseable') return 'not_mergeable';
724
+ if (code === 'dirty_worktree' || code === 'submodule_not_clean') return 'blocked_review';
725
+ return 'blocked';
726
+ }
727
+
728
+ async function verifyHeadIsAncestorOfUpstream(workspace: string, upstream: string, timeoutMs?: number): Promise<{ ok: boolean; error?: string }> {
729
+ if (!upstream) return { ok: false, error: 'missing upstream' };
730
+ try {
731
+ await runGit(workspace, ['merge-base', '--is-ancestor', 'HEAD', upstream], { timeoutMs: timeoutMs ?? 15_000 });
732
+ return { ok: true };
733
+ } catch (error) {
734
+ return { ok: false, error: formatGitError(error) };
735
+ }
736
+ }
737
+
738
+ function block(
739
+ base: MeshFastForwardBase,
740
+ code: string,
741
+ blockingReasons: string[],
742
+ ): MeshFastForwardResult {
743
+ const normalizedReasons = normalizeBlockingReasons(blockingReasons);
744
+ return {
745
+ ...base,
746
+ success: false,
747
+ code,
748
+ allowed: false,
749
+ willRun: false,
750
+ executed: false,
751
+ blockingReasons: normalizedReasons,
752
+ };
753
+ }
754
+
755
+ function normalizeBlockingReasons(reasons: string[]): string[] {
756
+ const normalized = new Set<string>();
757
+ for (const reason of reasons) {
758
+ normalized.add(reason);
759
+ }
760
+ if ([
761
+ 'conflicts_present',
762
+ 'staged_changes_present',
763
+ 'modified_changes_present',
764
+ 'untracked_changes_present',
765
+ 'deleted_changes_present',
766
+ 'renamed_changes_present',
767
+ ].some((reason) => normalized.has(reason))) {
768
+ normalized.add('working_tree_not_clean');
769
+ }
770
+ return Array.from(normalized);
771
+ }
772
+
773
+ function buildConvergenceState(status: GitRepoStatus, convergenceStatus: string): Record<string, unknown> {
774
+ return {
775
+ status: convergenceStatus,
776
+ branch: status.branch,
777
+ headCommit: status.headCommit,
778
+ upstream: status.upstream,
779
+ ahead: status.ahead,
780
+ behind: status.behind,
781
+ dirty: status.staged + status.modified + status.untracked + status.deleted + status.renamed > 0 || status.hasConflicts,
782
+ stashCount: status.stashCount,
783
+ submodules: summarizeSubmodules(status.submodules),
784
+ };
785
+ }
786
+
787
+ function summarizeSubmodules(submodules: GitSubmoduleStatus[] | undefined): Array<Record<string, unknown>> {
788
+ return (submodules || []).map((submodule) => ({
789
+ path: submodule.path,
790
+ commit: submodule.commit,
791
+ dirty: submodule.dirty,
792
+ outOfSync: submodule.outOfSync,
793
+ ...(submodule.error ? { error: submodule.error } : {}),
794
+ }));
795
+ }
796
+
797
+ function normalizeOptionalString(value: unknown): string | undefined {
798
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
799
+ }
800
+
801
+ function formatGitError(error: unknown): string {
802
+ if (error instanceof GitCommandError) {
803
+ return error.stderr || error.stdout || error.message;
804
+ }
805
+ if (error instanceof Error) return error.message;
806
+ return String(error);
807
+ }
808
+
809
+ async function appendFastForwardLedger(result: MeshFastForwardResult, outcome: 'noop' | 'blocked' | 'dry_run' | 'executed' | 'failed'): Promise<void> {
810
+ if (!result.meshId) return;
811
+ try {
812
+ const { appendLedgerEntry } = await import('./mesh-ledger.js');
813
+ appendLedgerEntry(result.meshId, {
814
+ kind: 'direct_fast_forward',
815
+ ...(result.nodeId ? { nodeId: result.nodeId } : {}),
816
+ payload: {
817
+ operation: 'mesh_fast_forward_node',
818
+ mode: result.mode,
819
+ trigger: result.trigger || 'manual',
820
+ outcome,
821
+ code: result.code,
822
+ workspace: result.workspace,
823
+ allowed: result.allowed,
824
+ dryRun: result.dryRun,
825
+ willRun: result.willRun,
826
+ executed: result.executed,
827
+ branch: result.postStatus?.branch ?? result.current?.branch,
828
+ upstream: result.postStatus?.upstream ?? result.current?.upstream,
829
+ ...(result.pushTarget ? { pushTarget: result.pushTarget } : {}),
830
+ before: result.current ? {
831
+ headCommit: result.current.headCommit,
832
+ ahead: result.current.ahead,
833
+ behind: result.current.behind,
834
+ } : undefined,
835
+ after: result.postStatus ? {
836
+ headCommit: result.postStatus.headCommit,
837
+ ahead: result.postStatus.ahead,
838
+ behind: result.postStatus.behind,
839
+ } : undefined,
840
+ ...(result.submodulePushes ? {
841
+ submodulePushes: result.submodulePushes.map((entry) => ({
842
+ path: entry.path,
843
+ commit: entry.commit,
844
+ pushed: entry.pushed,
845
+ skipped: entry.skipped,
846
+ code: entry.code,
847
+ ...(entry.refspec ? { refspec: entry.refspec } : {}),
848
+ })),
849
+ } : {}),
850
+ blockingReasons: result.blockingReasons,
851
+ },
852
+ });
853
+ } catch (error) {
854
+ result.ledgerError = error instanceof Error ? error.message : String(error);
855
+ }
856
+ }