@adhdev/daemon-core 0.9.82-rc.21 → 0.9.82-rc.210

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 (269) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +1 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/chat/source-machine.d.ts +166 -0
  4. package/dist/chat/source-resolver.d.ts +104 -0
  5. package/dist/chat/subscription-updates.d.ts +1 -0
  6. package/dist/cli-adapter-types.d.ts +23 -2
  7. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  8. package/dist/cli-adapters/cli-state-engine.d.ts +178 -0
  9. package/dist/cli-adapters/provider-cli-adapter.d.ts +106 -63
  10. package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
  11. package/dist/cli-adapters/provider-cli-shared.d.ts +29 -0
  12. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  13. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +3 -3
  14. package/dist/cli-adapters/terminal-backends/types.d.ts +1 -2
  15. package/dist/cli-adapters/terminal-screen.d.ts +2 -11
  16. package/dist/commands/cli-manager.d.ts +2 -1
  17. package/dist/commands/handler.d.ts +110 -0
  18. package/dist/commands/mesh-coordinator.d.ts +85 -1
  19. package/dist/commands/router.d.ts +32 -1
  20. package/dist/config/chat-history.d.ts +9 -0
  21. package/dist/config/config.d.ts +5 -0
  22. package/dist/config/mesh-config.d.ts +72 -1
  23. package/dist/git/git-commands.d.ts +9 -1
  24. package/dist/git/git-diff.d.ts +6 -0
  25. package/dist/git/git-types.d.ts +2 -0
  26. package/dist/index.d.ts +46 -11
  27. package/dist/index.js +35171 -15756
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +34878 -15556
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/installer.d.ts +1 -4
  32. package/dist/ipc/local-ipc-server.d.ts +91 -0
  33. package/dist/launch.d.ts +1 -1
  34. package/dist/logging/async-batch-writer.d.ts +10 -0
  35. package/dist/mesh/contracts.d.ts +164 -0
  36. package/dist/mesh/coordinator-prompt.d.ts +36 -0
  37. package/dist/mesh/coordinator-registry.d.ts +59 -0
  38. package/dist/mesh/mesh-active-work.d.ts +90 -0
  39. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  40. package/dist/mesh/mesh-events-coordinator.d.ts +151 -0
  41. package/dist/mesh/mesh-events-pending.d.ts +33 -0
  42. package/dist/mesh/mesh-events-stale.d.ts +40 -0
  43. package/dist/mesh/mesh-events-utils.d.ts +14 -0
  44. package/dist/mesh/mesh-events.d.ts +5 -40
  45. package/dist/mesh/mesh-fast-forward.d.ts +41 -0
  46. package/dist/mesh/mesh-host-ownership.d.ts +9 -0
  47. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -3
  48. package/dist/mesh/mesh-ledger.d.ts +77 -1
  49. package/dist/mesh/mesh-missions.d.ts +58 -0
  50. package/dist/mesh/mesh-refine-status.d.ts +26 -0
  51. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  52. package/dist/mesh/mesh-runtime-store.d.ts +324 -0
  53. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  54. package/dist/mesh/mesh-work-queue.d.ts +137 -6
  55. package/dist/mesh/preview-freshness.d.ts +18 -0
  56. package/dist/mesh/refine-config.d.ts +215 -0
  57. package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
  58. package/dist/providers/acp-provider-instance.d.ts +2 -0
  59. package/dist/providers/approval-utils.d.ts +13 -0
  60. package/dist/providers/cli-provider-instance.d.ts +39 -3
  61. package/dist/providers/contracts.d.ts +130 -6
  62. package/dist/providers/external-sources.d.ts +71 -0
  63. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
  64. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  65. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  66. package/dist/providers/native-history/dispatcher.d.ts +27 -0
  67. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  68. package/dist/providers/native-history/index.d.ts +13 -0
  69. package/dist/providers/provider-instance-manager.d.ts +12 -0
  70. package/dist/providers/provider-instance.d.ts +13 -1
  71. package/dist/providers/provider-loader.d.ts +26 -4
  72. package/dist/providers/provider-trust.d.ts +31 -0
  73. package/dist/providers/read-chat-contract.d.ts +29 -0
  74. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  75. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +85 -0
  76. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  77. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  78. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  79. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  80. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  81. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  82. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  83. package/dist/providers/sdk/v1/index.d.ts +30 -0
  84. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  85. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  86. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  87. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  88. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  89. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  90. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  91. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  92. package/dist/providers/spec/adapter.d.ts +52 -0
  93. package/dist/providers/spec/cli-adapter.d.ts +101 -0
  94. package/dist/providers/spec/driver.d.ts +225 -0
  95. package/dist/providers/spec/evaluator.d.ts +54 -0
  96. package/dist/providers/spec/loader.d.ts +15 -0
  97. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  98. package/dist/providers/spec/route.d.ts +4 -0
  99. package/dist/providers/spec/schema.gen.d.ts +2025 -0
  100. package/dist/providers/spec/types.d.ts +302 -0
  101. package/dist/providers/transcript-v2.d.ts +176 -0
  102. package/dist/providers/types/interactive-prompt.d.ts +48 -0
  103. package/dist/repo-mesh-types.d.ts +109 -1
  104. package/dist/sessions/registry.d.ts +3 -0
  105. package/dist/shared-types-extra.d.ts +2 -4
  106. package/dist/shared-types.d.ts +42 -1
  107. package/dist/status/normalize.d.ts +1 -1
  108. package/dist/status/normalize.js +1 -0
  109. package/dist/status/normalize.js.map +1 -1
  110. package/dist/status/normalize.mjs +1 -0
  111. package/dist/status/normalize.mjs.map +1 -1
  112. package/dist/status/reporter.d.ts +2 -0
  113. package/dist/status/snapshot.d.ts +1 -0
  114. package/dist/types.d.ts +5 -0
  115. package/package.json +6 -3
  116. package/src/agent-stream/poller.ts +2 -3
  117. package/src/boot/daemon-lifecycle.ts +22 -10
  118. package/src/boot/process-hardening.ts +89 -0
  119. package/src/chat/source-machine.ts +534 -0
  120. package/src/chat/source-resolver.ts +0 -0
  121. package/src/chat/subscription-updates.ts +20 -1
  122. package/src/cli-adapter-types.d.ts +1 -0
  123. package/src/cli-adapter-types.ts +22 -2
  124. package/src/cli-adapters/cli-script-runner.ts +421 -0
  125. package/src/cli-adapters/cli-state-engine.ts +1138 -0
  126. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  127. package/src/cli-adapters/provider-cli-adapter.ts +673 -1139
  128. package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
  129. package/src/cli-adapters/provider-cli-parse.ts +13 -0
  130. package/src/cli-adapters/provider-cli-runtime.ts +3 -1
  131. package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
  132. package/src/cli-adapters/provider-cli-shared.ts +59 -11
  133. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  134. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +35 -29
  135. package/src/cli-adapters/terminal-backends/types.ts +1 -3
  136. package/src/cli-adapters/terminal-screen.ts +11 -81
  137. package/src/commands/chat-commands.ts +1787 -60
  138. package/src/commands/cli-manager.ts +283 -14
  139. package/src/commands/handler.ts +809 -2
  140. package/src/commands/mesh-coordinator.ts +332 -122
  141. package/src/commands/router.ts +4198 -557
  142. package/src/config/chat-history.ts +95 -24
  143. package/src/config/config.ts +12 -0
  144. package/src/config/mesh-config.ts +280 -2
  145. package/src/config/recent-activity.ts +8 -2
  146. package/src/daemon/dev-auto-implement.ts +3 -2
  147. package/src/daemon/dev-cli-debug.ts +10 -1
  148. package/src/detection/ide-detector.ts +26 -16
  149. package/src/git/git-commands.ts +42 -12
  150. package/src/git/git-diff.ts +53 -0
  151. package/src/git/git-status.ts +35 -6
  152. package/src/git/git-types.ts +2 -0
  153. package/src/git/git-worktree.ts +8 -1
  154. package/src/index.ts +126 -10
  155. package/src/installer.d.ts +1 -1
  156. package/src/installer.ts +8 -6
  157. package/src/ipc/local-ipc-server.ts +278 -0
  158. package/src/launch.d.ts +1 -1
  159. package/src/launch.ts +37 -28
  160. package/src/logging/async-batch-writer.ts +55 -0
  161. package/src/logging/logger.ts +2 -1
  162. package/src/mesh/contracts.ts +329 -0
  163. package/src/mesh/coordinator-prompt.ts +218 -31
  164. package/src/mesh/coordinator-registry.ts +121 -0
  165. package/src/mesh/mesh-active-work.ts +437 -0
  166. package/src/mesh/mesh-delivery-policy.ts +315 -0
  167. package/src/mesh/mesh-events-coordinator.ts +1404 -0
  168. package/src/mesh/mesh-events-pending.ts +371 -0
  169. package/src/mesh/mesh-events-stale.ts +283 -0
  170. package/src/mesh/mesh-events-utils.ts +161 -0
  171. package/src/mesh/mesh-events.ts +24 -908
  172. package/src/mesh/mesh-fast-forward.ts +438 -0
  173. package/src/mesh/mesh-host-ownership.ts +73 -0
  174. package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
  175. package/src/mesh/mesh-ledger.ts +587 -102
  176. package/src/mesh/mesh-missions.ts +151 -0
  177. package/src/mesh/mesh-refine-status.ts +144 -0
  178. package/src/mesh/mesh-review-inbox.ts +307 -0
  179. package/src/mesh/mesh-runtime-store.ts +1305 -0
  180. package/src/mesh/mesh-task-stats.ts +154 -0
  181. package/src/mesh/mesh-work-queue.ts +490 -166
  182. package/src/mesh/preview-freshness.ts +118 -0
  183. package/src/mesh/refine-config.ts +403 -0
  184. package/src/mesh/worktree-bootstrap-config.ts +326 -0
  185. package/src/providers/acp-provider-instance.ts +15 -1
  186. package/src/providers/approval-utils.d.ts +4 -0
  187. package/src/providers/approval-utils.ts +47 -5
  188. package/src/providers/chat-message-normalization.ts +4 -11
  189. package/src/providers/cli-provider-instance.ts +833 -64
  190. package/src/providers/contracts.d.ts +55 -0
  191. package/src/providers/contracts.ts +141 -6
  192. package/src/providers/external-sources.ts +218 -0
  193. package/src/providers/ide-provider-instance.ts +19 -5
  194. package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
  195. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  196. package/src/providers/native-history/codex-cli-transcript.ts +419 -0
  197. package/src/providers/native-history/dispatcher.ts +340 -0
  198. package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
  199. package/src/providers/native-history/index.ts +30 -0
  200. package/src/providers/provider-instance-manager.ts +30 -0
  201. package/src/providers/provider-instance.ts +10 -1
  202. package/src/providers/provider-loader.ts +582 -50
  203. package/src/providers/provider-schema.ts +87 -14
  204. package/src/providers/provider-trust.ts +114 -0
  205. package/src/providers/read-chat-contract.ts +76 -16
  206. package/src/providers/sdk/README.md +49 -0
  207. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  208. package/src/providers/sdk/v1/builders/cli/detect-status.ts +262 -0
  209. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  210. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  211. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  212. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  213. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  214. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  215. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  216. package/src/providers/sdk/v1/index.ts +152 -0
  217. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  218. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  219. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  220. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
  221. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  222. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  223. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  224. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  225. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  226. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  227. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  228. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  229. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  230. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  231. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  232. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  233. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  234. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  235. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  236. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  237. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  238. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  239. package/src/providers/sdk/v1/validators/index.ts +19 -0
  240. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  241. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  242. package/src/providers/spec/adapter.ts +138 -0
  243. package/src/providers/spec/cli-adapter.ts +626 -0
  244. package/src/providers/spec/driver.ts +912 -0
  245. package/src/providers/spec/evaluator.ts +597 -0
  246. package/src/providers/spec/loader.ts +324 -0
  247. package/src/providers/spec/native-history-executor.ts +939 -0
  248. package/src/providers/spec/route.ts +51 -0
  249. package/src/providers/spec/schema.gen.ts +691 -0
  250. package/src/providers/spec/schema.json +341 -0
  251. package/src/providers/spec/types.ts +356 -0
  252. package/src/providers/transcript-v2.ts +567 -0
  253. package/src/providers/types/interactive-prompt.ts +425 -0
  254. package/src/providers/version-archive.ts +38 -20
  255. package/src/repo-mesh-types.ts +119 -1
  256. package/src/sessions/registry.ts +3 -0
  257. package/src/shared-types-extra.ts +2 -4
  258. package/src/shared-types.ts +45 -1
  259. package/src/status/builders.ts +24 -6
  260. package/src/status/normalize.ts +2 -0
  261. package/src/status/reporter.ts +15 -0
  262. package/src/status/snapshot.ts +84 -25
  263. package/src/system/host-memory.ts +29 -12
  264. package/src/types.ts +5 -0
  265. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  266. package/dist/mesh/mesh-sync.d.ts +0 -53
  267. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  268. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  269. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,438 @@
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
+
5
+ export interface MeshFastForwardNodeArgs {
6
+ nodeId?: string;
7
+ meshId?: string;
8
+ workspace: string;
9
+ branch?: string;
10
+ execute?: boolean;
11
+ dryRun?: boolean;
12
+ updateSubmodules?: boolean;
13
+ submoduleIgnorePaths?: string[];
14
+ timeoutMs?: number;
15
+ trigger?: 'manual' | 'idle_auto' | string;
16
+ }
17
+
18
+ export interface MeshFastForwardPlannedStep {
19
+ operation: 'refresh_upstream' | 'verify_clean_worktree' | 'verify_fast_forward' | 'merge_ff_only' | 'submodule_update' | 'verify_post_status';
20
+ description: string;
21
+ safe: true;
22
+ willMutateWorktree: boolean;
23
+ }
24
+
25
+ export interface MeshFastForwardResult {
26
+ success: boolean;
27
+ code: string;
28
+ nodeId?: string;
29
+ meshId?: string;
30
+ workspace: string;
31
+ allowed: boolean;
32
+ dryRun: boolean;
33
+ willRun: boolean;
34
+ executed: boolean;
35
+ updateSubmodules: boolean;
36
+ blockingReasons: string[];
37
+ plannedSteps: MeshFastForwardPlannedStep[];
38
+ current?: GitRepoStatus;
39
+ preStatus?: GitRepoStatus;
40
+ postStatus?: GitRepoStatus;
41
+ finalBranchConvergenceState?: Record<string, unknown>;
42
+ operationError?: string;
43
+ ledgerError?: string;
44
+ trigger?: string;
45
+ }
46
+
47
+ type MeshFastForwardBase = Pick<
48
+ MeshFastForwardResult,
49
+ 'workspace' | 'dryRun' | 'updateSubmodules' | 'plannedSteps' | 'trigger'
50
+ > & Pick<Partial<MeshFastForwardResult>, 'nodeId' | 'meshId'>;
51
+
52
+ const STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15_000 } as const;
53
+
54
+ export async function fastForwardMeshNode(args: MeshFastForwardNodeArgs): Promise<MeshFastForwardResult> {
55
+ const workspace = typeof args.workspace === 'string' ? args.workspace.trim() : '';
56
+ const nodeId = normalizeOptionalString(args.nodeId);
57
+ const meshId = normalizeOptionalString(args.meshId);
58
+ const requestedBranch = normalizeOptionalString(args.branch);
59
+ const trigger = normalizeOptionalString(args.trigger) || 'manual';
60
+ const updateSubmodules = args.updateSubmodules === true;
61
+ const dryRun = args.dryRun === true || args.execute !== true;
62
+ const plannedSteps = buildPlannedSteps(updateSubmodules);
63
+ const base: MeshFastForwardBase = {
64
+ ...(nodeId ? { nodeId } : {}),
65
+ ...(meshId ? { meshId } : {}),
66
+ workspace,
67
+ dryRun,
68
+ updateSubmodules,
69
+ plannedSteps,
70
+ trigger,
71
+ };
72
+
73
+ if (!workspace) {
74
+ return block(base, 'invalid_workspace', ['workspace_required']);
75
+ }
76
+
77
+ const current = await getGitRepoStatus(workspace, {
78
+ ...STATUS_OPTIONS,
79
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
80
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs,
81
+ });
82
+
83
+ const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
84
+ if (earlyBlockers.length > 0) {
85
+ const result: MeshFastForwardResult = {
86
+ ...block(base, chooseBlockCode(current, earlyBlockers), earlyBlockers),
87
+ current,
88
+ finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(chooseBlockCode(current, earlyBlockers))),
89
+ };
90
+ await appendFastForwardLedger(result, 'blocked');
91
+ return result;
92
+ }
93
+
94
+ if (current.behind === 0) {
95
+ const result: MeshFastForwardResult = {
96
+ ...base,
97
+ success: true,
98
+ code: 'already_up_to_date',
99
+ allowed: true,
100
+ willRun: false,
101
+ executed: false,
102
+ blockingReasons: [],
103
+ current,
104
+ preStatus: current,
105
+ postStatus: current,
106
+ finalBranchConvergenceState: buildConvergenceState(current, 'up_to_date'),
107
+ };
108
+ await appendFastForwardLedger(result, 'noop');
109
+ return result;
110
+ }
111
+
112
+ const ancestorCheck = await verifyHeadIsAncestorOfUpstream(workspace, current.upstream || '', args.timeoutMs);
113
+ if (!ancestorCheck.ok) {
114
+ const result: MeshFastForwardResult = {
115
+ ...block(base, 'non_fast_forward', ['head_is_not_ancestor_of_upstream']),
116
+ current,
117
+ preStatus: current,
118
+ operationError: ancestorCheck.error,
119
+ finalBranchConvergenceState: buildConvergenceState(current, 'not_mergeable'),
120
+ };
121
+ await appendFastForwardLedger(result, 'blocked');
122
+ return result;
123
+ }
124
+
125
+ if (dryRun) {
126
+ const result: MeshFastForwardResult = {
127
+ ...base,
128
+ success: true,
129
+ code: 'fast_forward_available',
130
+ allowed: true,
131
+ willRun: false,
132
+ executed: false,
133
+ blockingReasons: [],
134
+ current,
135
+ preStatus: current,
136
+ finalBranchConvergenceState: buildConvergenceState(current, 'fast_forward_available'),
137
+ };
138
+ await appendFastForwardLedger(result, 'dry_run');
139
+ return result;
140
+ }
141
+
142
+ try {
143
+ await runGit(workspace, ['merge', '--ff-only', current.upstream || ''], { timeoutMs: args.timeoutMs ?? 30_000 });
144
+ } catch (error) {
145
+ const result: MeshFastForwardResult = {
146
+ ...block(base, 'merge_ff_only_failed', ['merge_ff_only_failed']),
147
+ current,
148
+ preStatus: current,
149
+ operationError: formatGitError(error),
150
+ finalBranchConvergenceState: buildConvergenceState(current, 'not_mergeable'),
151
+ };
152
+ await appendFastForwardLedger(result, 'failed');
153
+ return result;
154
+ }
155
+
156
+ let postStatus = await getGitRepoStatus(workspace, {
157
+ ...STATUS_OPTIONS,
158
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
159
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs,
160
+ });
161
+
162
+ const submoduleIssues = collectSubmoduleBlockers(postStatus, 'post');
163
+ let submoduleFollowUpRequired = false;
164
+ let operationError: string | undefined;
165
+ if (submoduleIssues.length > 0) {
166
+ if (updateSubmodules) {
167
+ try {
168
+ await runGit(workspace, ['submodule', 'update', '--init', '--recursive'], { timeoutMs: args.timeoutMs ?? 60_000 });
169
+ postStatus = await getGitRepoStatus(workspace, {
170
+ ...STATUS_OPTIONS,
171
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
172
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs,
173
+ });
174
+ } catch (error) {
175
+ operationError = formatGitError(error);
176
+ }
177
+ } else {
178
+ submoduleFollowUpRequired = true;
179
+ }
180
+ }
181
+
182
+ const postBlockers = collectPostExecutionBlockers(postStatus);
183
+ if (operationError) postBlockers.push('submodule_update_failed');
184
+ if (submoduleFollowUpRequired) postBlockers.push('submodule_update_required');
185
+
186
+ const success = postBlockers.length === 0 || submoduleFollowUpRequired;
187
+ const code = postBlockers.length === 0
188
+ ? 'fast_forward_applied'
189
+ : submoduleFollowUpRequired
190
+ ? 'fast_forward_applied_submodule_update_required'
191
+ : 'post_verify_failed';
192
+ const result: MeshFastForwardResult = {
193
+ ...base,
194
+ success,
195
+ code,
196
+ allowed: true,
197
+ willRun: true,
198
+ executed: true,
199
+ blockingReasons: postBlockers,
200
+ current,
201
+ preStatus: current,
202
+ postStatus,
203
+ ...(operationError ? { operationError } : {}),
204
+ finalBranchConvergenceState: buildConvergenceState(
205
+ postStatus,
206
+ postBlockers.length === 0 ? 'fast_forwarded' : submoduleFollowUpRequired ? 'follow_up_required' : 'post_verify_failed',
207
+ ),
208
+ };
209
+ await appendFastForwardLedger(result, success ? 'executed' : 'failed');
210
+ return result;
211
+ }
212
+
213
+ function buildPlannedSteps(updateSubmodules: boolean): MeshFastForwardPlannedStep[] {
214
+ const steps: MeshFastForwardPlannedStep[] = [
215
+ {
216
+ operation: 'refresh_upstream',
217
+ description: 'Refresh the tracked upstream remote ref before trusting ahead/behind state.',
218
+ safe: true,
219
+ willMutateWorktree: false,
220
+ },
221
+ {
222
+ operation: 'verify_clean_worktree',
223
+ description: 'Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.',
224
+ safe: true,
225
+ willMutateWorktree: false,
226
+ },
227
+ {
228
+ operation: 'verify_fast_forward',
229
+ description: 'Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.',
230
+ safe: true,
231
+ willMutateWorktree: false,
232
+ },
233
+ {
234
+ operation: 'merge_ff_only',
235
+ description: 'Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.',
236
+ safe: true,
237
+ willMutateWorktree: true,
238
+ },
239
+ ];
240
+ if (updateSubmodules) {
241
+ steps.push({
242
+ operation: 'submodule_update',
243
+ description: 'If the fast-forward changes gitlinks, run git submodule update --init --recursive and re-verify submodules.',
244
+ safe: true,
245
+ willMutateWorktree: true,
246
+ });
247
+ }
248
+ steps.push({
249
+ operation: 'verify_post_status',
250
+ description: 'Re-read daemon-owned git status and report final branch convergence state.',
251
+ safe: true,
252
+ willMutateWorktree: false,
253
+ });
254
+ return steps;
255
+ }
256
+
257
+ function collectPreflightBlockers(status: GitRepoStatus, requestedBranch?: string): string[] {
258
+ const blockers: string[] = [];
259
+ if (!status.isGitRepo) blockers.push('not_git_repo');
260
+ if (!status.branch) blockers.push('detached_head_or_unknown_branch');
261
+ if (requestedBranch && status.branch !== requestedBranch) blockers.push('branch_mismatch');
262
+ if (!status.upstream) blockers.push('upstream_missing');
263
+ if (status.upstreamStatus !== 'fresh') blockers.push('upstream_not_fresh');
264
+ if (status.hasConflicts) blockers.push('conflicts_present');
265
+ if (status.staged > 0) blockers.push('staged_changes_present');
266
+ if (status.modified > 0) blockers.push('modified_changes_present');
267
+ if (status.untracked > 0) blockers.push('untracked_changes_present');
268
+ if (status.deleted > 0) blockers.push('deleted_changes_present');
269
+ if (status.renamed > 0) blockers.push('renamed_changes_present');
270
+ if (status.stashCount > 0) blockers.push('stash_entries_present');
271
+ blockers.push(...collectSubmoduleBlockers(status, 'pre'));
272
+ if (status.ahead > 0 && status.behind > 0) {
273
+ blockers.push('branch_diverged_from_upstream');
274
+ blockers.push('branch_has_local_commits');
275
+ } else if (status.ahead > 0) blockers.push('branch_has_local_commits');
276
+ return blockers;
277
+ }
278
+
279
+ function collectPostExecutionBlockers(status: GitRepoStatus): string[] {
280
+ const blockers: string[] = [];
281
+ if (!status.isGitRepo) blockers.push('post_not_git_repo');
282
+ if (status.hasConflicts) blockers.push('post_conflicts_present');
283
+ if (status.ahead !== 0) blockers.push('post_branch_ahead');
284
+ if (status.behind !== 0) blockers.push('post_branch_still_behind');
285
+ if (status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0) {
286
+ blockers.push('post_working_tree_not_clean');
287
+ }
288
+ if (status.stashCount > 0) blockers.push('post_stash_entries_present');
289
+ blockers.push(...collectSubmoduleBlockers(status, 'post'));
290
+ return blockers;
291
+ }
292
+
293
+ function collectSubmoduleBlockers(status: GitRepoStatus, phase: 'pre' | 'post'): string[] {
294
+ const submodules = Array.isArray(status.submodules) ? status.submodules : [];
295
+ const blockers: string[] = [];
296
+ for (const submodule of submodules) {
297
+ if (submodule.error) blockers.push(`${phase}_submodule_status_error:${submodule.path}`);
298
+ if (submodule.dirty) blockers.push(`${phase}_submodule_dirty:${submodule.path}`);
299
+ if (submodule.outOfSync) blockers.push(`${phase}_submodule_out_of_sync:${submodule.path}`);
300
+ }
301
+ return blockers;
302
+ }
303
+
304
+ function chooseBlockCode(status: GitRepoStatus, blockers: string[]): string {
305
+ if (blockers.includes('not_git_repo')) return 'not_git_repo';
306
+ if (blockers.includes('branch_mismatch')) return 'branch_mismatch';
307
+ if (blockers.includes('upstream_missing')) return 'upstream_missing';
308
+ if (blockers.includes('upstream_not_fresh')) return 'upstream_not_fresh';
309
+ if (blockers.some((reason) => reason.includes('submodule'))) return 'submodule_not_clean';
310
+ if (blockers.includes('branch_diverged_from_upstream')) return 'branch_diverged';
311
+ if (blockers.includes('branch_has_local_commits') || status.ahead > 0) return 'branch_ahead';
312
+ if (blockers.some((reason) => reason.includes('changes') || reason.includes('conflicts') || reason.includes('stash'))) return 'dirty_worktree';
313
+ return 'preflight_blocked';
314
+ }
315
+
316
+ function codeToConvergenceStatus(code: string): string {
317
+ if (code === 'branch_diverged' || code === 'branch_ahead' || code === 'non_fast_forward') return 'not_mergeable';
318
+ if (code === 'dirty_worktree' || code === 'submodule_not_clean') return 'blocked_review';
319
+ return 'blocked';
320
+ }
321
+
322
+ async function verifyHeadIsAncestorOfUpstream(workspace: string, upstream: string, timeoutMs?: number): Promise<{ ok: boolean; error?: string }> {
323
+ if (!upstream) return { ok: false, error: 'missing upstream' };
324
+ try {
325
+ await runGit(workspace, ['merge-base', '--is-ancestor', 'HEAD', upstream], { timeoutMs: timeoutMs ?? 15_000 });
326
+ return { ok: true };
327
+ } catch (error) {
328
+ return { ok: false, error: formatGitError(error) };
329
+ }
330
+ }
331
+
332
+ function block(
333
+ base: MeshFastForwardBase,
334
+ code: string,
335
+ blockingReasons: string[],
336
+ ): MeshFastForwardResult {
337
+ const normalizedReasons = normalizeBlockingReasons(blockingReasons);
338
+ return {
339
+ ...base,
340
+ success: false,
341
+ code,
342
+ allowed: false,
343
+ willRun: false,
344
+ executed: false,
345
+ blockingReasons: normalizedReasons,
346
+ };
347
+ }
348
+
349
+ function normalizeBlockingReasons(reasons: string[]): string[] {
350
+ const normalized = new Set<string>();
351
+ for (const reason of reasons) {
352
+ normalized.add(reason);
353
+ }
354
+ if ([
355
+ 'conflicts_present',
356
+ 'staged_changes_present',
357
+ 'modified_changes_present',
358
+ 'untracked_changes_present',
359
+ 'deleted_changes_present',
360
+ 'renamed_changes_present',
361
+ ].some((reason) => normalized.has(reason))) {
362
+ normalized.add('working_tree_not_clean');
363
+ }
364
+ return Array.from(normalized);
365
+ }
366
+
367
+ function buildConvergenceState(status: GitRepoStatus, convergenceStatus: string): Record<string, unknown> {
368
+ return {
369
+ status: convergenceStatus,
370
+ branch: status.branch,
371
+ headCommit: status.headCommit,
372
+ upstream: status.upstream,
373
+ ahead: status.ahead,
374
+ behind: status.behind,
375
+ dirty: status.staged + status.modified + status.untracked + status.deleted + status.renamed > 0 || status.hasConflicts,
376
+ stashCount: status.stashCount,
377
+ submodules: summarizeSubmodules(status.submodules),
378
+ };
379
+ }
380
+
381
+ function summarizeSubmodules(submodules: GitSubmoduleStatus[] | undefined): Array<Record<string, unknown>> {
382
+ return (submodules || []).map((submodule) => ({
383
+ path: submodule.path,
384
+ commit: submodule.commit,
385
+ dirty: submodule.dirty,
386
+ outOfSync: submodule.outOfSync,
387
+ ...(submodule.error ? { error: submodule.error } : {}),
388
+ }));
389
+ }
390
+
391
+ function normalizeOptionalString(value: unknown): string | undefined {
392
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
393
+ }
394
+
395
+ function formatGitError(error: unknown): string {
396
+ if (error instanceof GitCommandError) {
397
+ return error.stderr || error.stdout || error.message;
398
+ }
399
+ if (error instanceof Error) return error.message;
400
+ return String(error);
401
+ }
402
+
403
+ async function appendFastForwardLedger(result: MeshFastForwardResult, outcome: 'noop' | 'blocked' | 'dry_run' | 'executed' | 'failed'): Promise<void> {
404
+ if (!result.meshId) return;
405
+ try {
406
+ const { appendLedgerEntry } = await import('./mesh-ledger.js');
407
+ appendLedgerEntry(result.meshId, {
408
+ kind: 'direct_fast_forward',
409
+ ...(result.nodeId ? { nodeId: result.nodeId } : {}),
410
+ payload: {
411
+ operation: 'mesh_fast_forward_node',
412
+ trigger: result.trigger || 'manual',
413
+ outcome,
414
+ code: result.code,
415
+ workspace: result.workspace,
416
+ allowed: result.allowed,
417
+ dryRun: result.dryRun,
418
+ willRun: result.willRun,
419
+ executed: result.executed,
420
+ branch: result.postStatus?.branch ?? result.current?.branch,
421
+ upstream: result.postStatus?.upstream ?? result.current?.upstream,
422
+ before: result.current ? {
423
+ headCommit: result.current.headCommit,
424
+ ahead: result.current.ahead,
425
+ behind: result.current.behind,
426
+ } : undefined,
427
+ after: result.postStatus ? {
428
+ headCommit: result.postStatus.headCommit,
429
+ ahead: result.postStatus.ahead,
430
+ behind: result.postStatus.behind,
431
+ } : undefined,
432
+ blockingReasons: result.blockingReasons,
433
+ },
434
+ });
435
+ } catch (error) {
436
+ result.ledgerError = error instanceof Error ? error.message : String(error);
437
+ }
438
+ }
@@ -0,0 +1,73 @@
1
+ import type { RepoMeshDaemonRole, RepoMeshHostMetadata, RepoMeshHostStatus } from '../repo-mesh-types.js';
2
+
3
+ function readObject(value: unknown): Record<string, unknown> | null {
4
+ return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null;
5
+ }
6
+
7
+ function readString(value: unknown): string | undefined {
8
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
9
+ }
10
+
11
+ export function normalizeMeshDaemonRole(value: unknown): RepoMeshDaemonRole | undefined {
12
+ return value === 'host' || value === 'member' ? value : undefined;
13
+ }
14
+
15
+ export function resolveMeshHostStatus(mesh: unknown): RepoMeshHostStatus {
16
+ const meshRecord = readObject(mesh);
17
+ const raw = readObject(meshRecord?.meshHost);
18
+ const role = normalizeMeshDaemonRole(raw?.role) ?? 'host';
19
+ const pairing = readObject(raw?.pairing);
20
+ const normalized: RepoMeshHostStatus = {
21
+ role,
22
+ canOwnCoordinator: role === 'host',
23
+ canOwnQueue: role === 'host',
24
+ defaulted: !raw,
25
+ };
26
+ const hostDaemonId = readString(raw?.hostDaemonId);
27
+ const hostNodeId = readString(raw?.hostNodeId);
28
+ const hostAddress = readString(raw?.hostAddress);
29
+ if (hostDaemonId) normalized.hostDaemonId = hostDaemonId;
30
+ if (hostNodeId) normalized.hostNodeId = hostNodeId;
31
+ if (hostAddress) normalized.hostAddress = hostAddress;
32
+ if (pairing) {
33
+ const status = pairing.status === 'pairing' || pairing.status === 'paired' || pairing.status === 'rejected' || pairing.status === 'revoked'
34
+ ? pairing.status
35
+ : 'not_configured';
36
+ normalized.pairing = {
37
+ status,
38
+ ...(readString(pairing.tokenId) ? { tokenId: readString(pairing.tokenId) } : {}),
39
+ ...(readString(pairing.joinedAt) ? { joinedAt: readString(pairing.joinedAt) } : {}),
40
+ ...(readString(pairing.lastPairedAt) ? { lastPairedAt: readString(pairing.lastPairedAt) } : {}),
41
+ ...(readString(pairing.lastRejectedAt) ? { lastRejectedAt: readString(pairing.lastRejectedAt) } : {}),
42
+ ...(readString(pairing.expiresAt) ? { expiresAt: readString(pairing.expiresAt) } : {}),
43
+ };
44
+ }
45
+ return normalized;
46
+ }
47
+
48
+ export function isMeshHostOwner(mesh: unknown): boolean {
49
+ return resolveMeshHostStatus(mesh).role === 'host';
50
+ }
51
+
52
+ export function buildMeshHostRequiredFailure(mesh: unknown, operation: string): Record<string, unknown> {
53
+ const meshHost = resolveMeshHostStatus(mesh);
54
+ return {
55
+ success: false,
56
+ code: 'mesh_host_required',
57
+ error: `Mesh Host daemon required for ${operation}; member daemons must pair with the host and cannot own coordinator/queue mutations.`,
58
+ meshHost,
59
+ };
60
+ }
61
+
62
+ export function requireMeshHostQueueOwner(opts?: { ownerRole?: RepoMeshDaemonRole }): void {
63
+ if (opts?.ownerRole === 'member') {
64
+ throw new Error('Mesh Host daemon required to mutate mesh queue; member daemons must use the host-owned queue.');
65
+ }
66
+ }
67
+
68
+ export function createDefaultMeshHostMetadata(): RepoMeshHostMetadata {
69
+ return {
70
+ role: 'host',
71
+ pairing: { status: 'not_configured' },
72
+ };
73
+ }
@@ -1,5 +1,12 @@
1
1
  import type { AppendRemoteLedgerResult, MeshLedgerSlice, MeshLedgerSummary } from './mesh-ledger.js';
2
2
 
3
+ /** Minimal ledger slice shape accepted by buildMeshLedgerReplicaEvidence. Covers both JSONL and SQLite slices. */
4
+ export interface AnyLedgerSlice {
5
+ entries: Array<{ id: string; meshId: string; timestamp: string; kind: string; nodeId?: string | null; sessionId?: string | null; providerType?: string | null; payload: unknown }>;
6
+ cursor: { afterId: string | null; nextAfterId: string | null; limit: number; hasMore: boolean };
7
+ summary?: MeshLedgerSummary;
8
+ }
9
+
3
10
  export type MeshLedgerReplicaStatus = 'local' | 'queried' | 'imported' | 'failed';
4
11
 
5
12
  export interface MeshLedgerReplicaEvidence {
@@ -25,7 +32,7 @@ export interface MeshLedgerReconciliationEvidence {
25
32
  meshId: string;
26
33
  generatedAt: string;
27
34
  sourceOfTruth: {
28
- kind: 'coordinator_local_jsonl';
35
+ kind: 'coordinator_local_sqlite';
29
36
  p2pOnly: true;
30
37
  cloudD1LedgerSync: false;
31
38
  notes: string;
@@ -47,7 +54,7 @@ export interface MeshLedgerReconciliationEvidence {
47
54
  };
48
55
  }
49
56
 
50
- function lastTimestamp(slice?: MeshLedgerSlice): string | null {
57
+ function lastTimestamp(slice?: AnyLedgerSlice): string | null {
51
58
  const entries = Array.isArray(slice?.entries) ? slice!.entries : [];
52
59
  return entries.length ? entries[entries.length - 1].timestamp : null;
53
60
  }
@@ -56,7 +63,7 @@ export function buildMeshLedgerReplicaEvidence(args: {
56
63
  nodeId: string;
57
64
  daemonId?: string;
58
65
  transport: 'local' | 'p2p_datachannel';
59
- slice?: MeshLedgerSlice;
66
+ slice?: AnyLedgerSlice;
60
67
  importResult?: AppendRemoteLedgerResult;
61
68
  status?: MeshLedgerReplicaStatus;
62
69
  error?: string;
@@ -91,10 +98,10 @@ export function buildMeshLedgerReconciliationEvidence(meshId: string, replicas:
91
98
  meshId,
92
99
  generatedAt: new Date().toISOString(),
93
100
  sourceOfTruth: {
94
- kind: 'coordinator_local_jsonl',
101
+ kind: 'coordinator_local_sqlite',
95
102
  p2pOnly: true,
96
103
  cloudD1LedgerSync: false,
97
- notes: 'Coordinator reconciles bounded slices from daemon-local JSONL ledgers over P2P DataChannel; Cloud/D1 is not a ledger source of truth.',
104
+ notes: 'Coordinator reconciles bounded slices from daemon-local SQLite event ledgers (mesh_event_ledger table) over P2P DataChannel; Cloud/D1 is not a ledger source of truth.',
98
105
  },
99
106
  replicas,
100
107
  totals: {