@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.
- package/dist/boot/daemon-lifecycle.d.ts +1 -0
- package/dist/boot/process-hardening.d.ts +50 -0
- package/dist/chat/source-machine.d.ts +166 -0
- package/dist/chat/source-resolver.d.ts +104 -0
- package/dist/chat/subscription-updates.d.ts +1 -0
- package/dist/cli-adapter-types.d.ts +23 -2
- package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
- package/dist/cli-adapters/cli-state-engine.d.ts +178 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +106 -63
- package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +29 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +3 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +1 -2
- package/dist/cli-adapters/terminal-screen.d.ts +2 -11
- package/dist/commands/cli-manager.d.ts +2 -1
- package/dist/commands/handler.d.ts +110 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router.d.ts +32 -1
- package/dist/config/chat-history.d.ts +9 -0
- package/dist/config/config.d.ts +5 -0
- package/dist/config/mesh-config.d.ts +72 -1
- package/dist/git/git-commands.d.ts +9 -1
- package/dist/git/git-diff.d.ts +6 -0
- package/dist/git/git-types.d.ts +2 -0
- package/dist/index.d.ts +46 -11
- package/dist/index.js +35171 -15756
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34878 -15556
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/ipc/local-ipc-server.d.ts +91 -0
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/mesh/contracts.d.ts +164 -0
- package/dist/mesh/coordinator-prompt.d.ts +36 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +90 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +151 -0
- package/dist/mesh/mesh-events-pending.d.ts +33 -0
- package/dist/mesh/mesh-events-stale.d.ts +40 -0
- package/dist/mesh/mesh-events-utils.d.ts +14 -0
- package/dist/mesh/mesh-events.d.ts +5 -40
- package/dist/mesh/mesh-fast-forward.d.ts +41 -0
- package/dist/mesh/mesh-host-ownership.d.ts +9 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -3
- package/dist/mesh/mesh-ledger.d.ts +77 -1
- package/dist/mesh/mesh-missions.d.ts +58 -0
- package/dist/mesh/mesh-refine-status.d.ts +26 -0
- package/dist/mesh/mesh-review-inbox.d.ts +90 -0
- package/dist/mesh/mesh-runtime-store.d.ts +324 -0
- package/dist/mesh/mesh-task-stats.d.ts +49 -0
- package/dist/mesh/mesh-work-queue.d.ts +137 -6
- package/dist/mesh/preview-freshness.d.ts +18 -0
- package/dist/mesh/refine-config.d.ts +215 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
- package/dist/providers/acp-provider-instance.d.ts +2 -0
- package/dist/providers/approval-utils.d.ts +13 -0
- package/dist/providers/cli-provider-instance.d.ts +39 -3
- package/dist/providers/contracts.d.ts +130 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
- package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
- package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
- package/dist/providers/native-history/dispatcher.d.ts +27 -0
- package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
- package/dist/providers/native-history/index.d.ts +13 -0
- package/dist/providers/provider-instance-manager.d.ts +12 -0
- package/dist/providers/provider-instance.d.ts +13 -1
- package/dist/providers/provider-loader.d.ts +26 -4
- package/dist/providers/provider-trust.d.ts +31 -0
- package/dist/providers/read-chat-contract.d.ts +29 -0
- package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +85 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
- package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
- package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
- package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
- package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
- package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
- package/dist/providers/sdk/v1/index.d.ts +30 -0
- package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
- package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
- package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
- package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
- package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
- package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
- package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
- package/dist/providers/spec/adapter.d.ts +52 -0
- package/dist/providers/spec/cli-adapter.d.ts +101 -0
- package/dist/providers/spec/driver.d.ts +225 -0
- package/dist/providers/spec/evaluator.d.ts +54 -0
- package/dist/providers/spec/loader.d.ts +15 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/schema.gen.d.ts +2025 -0
- package/dist/providers/spec/types.d.ts +302 -0
- package/dist/providers/transcript-v2.d.ts +176 -0
- package/dist/providers/types/interactive-prompt.d.ts +48 -0
- package/dist/repo-mesh-types.d.ts +109 -1
- package/dist/sessions/registry.d.ts +3 -0
- package/dist/shared-types-extra.d.ts +2 -4
- package/dist/shared-types.d.ts +42 -1
- package/dist/status/normalize.d.ts +1 -1
- package/dist/status/normalize.js +1 -0
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +1 -0
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/reporter.d.ts +2 -0
- package/dist/status/snapshot.d.ts +1 -0
- package/dist/types.d.ts +5 -0
- package/package.json +6 -3
- package/src/agent-stream/poller.ts +2 -3
- package/src/boot/daemon-lifecycle.ts +22 -10
- package/src/boot/process-hardening.ts +89 -0
- package/src/chat/source-machine.ts +534 -0
- package/src/chat/source-resolver.ts +0 -0
- package/src/chat/subscription-updates.ts +20 -1
- package/src/cli-adapter-types.d.ts +1 -0
- package/src/cli-adapter-types.ts +22 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1138 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +673 -1139
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +13 -0
- package/src/cli-adapters/provider-cli-runtime.ts +3 -1
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +59 -11
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +35 -29
- package/src/cli-adapters/terminal-backends/types.ts +1 -3
- package/src/cli-adapters/terminal-screen.ts +11 -81
- package/src/commands/chat-commands.ts +1787 -60
- package/src/commands/cli-manager.ts +283 -14
- package/src/commands/handler.ts +809 -2
- package/src/commands/mesh-coordinator.ts +332 -122
- package/src/commands/router.ts +4198 -557
- package/src/config/chat-history.ts +95 -24
- package/src/config/config.ts +12 -0
- package/src/config/mesh-config.ts +280 -2
- package/src/config/recent-activity.ts +8 -2
- package/src/daemon/dev-auto-implement.ts +3 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/ide-detector.ts +26 -16
- package/src/git/git-commands.ts +42 -12
- package/src/git/git-diff.ts +53 -0
- package/src/git/git-status.ts +35 -6
- package/src/git/git-types.ts +2 -0
- package/src/git/git-worktree.ts +8 -1
- package/src/index.ts +126 -10
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/ipc/local-ipc-server.ts +278 -0
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/logger.ts +2 -1
- package/src/mesh/contracts.ts +329 -0
- package/src/mesh/coordinator-prompt.ts +218 -31
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +437 -0
- package/src/mesh/mesh-delivery-policy.ts +315 -0
- package/src/mesh/mesh-events-coordinator.ts +1404 -0
- package/src/mesh/mesh-events-pending.ts +371 -0
- package/src/mesh/mesh-events-stale.ts +283 -0
- package/src/mesh/mesh-events-utils.ts +161 -0
- package/src/mesh/mesh-events.ts +24 -908
- package/src/mesh/mesh-fast-forward.ts +438 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
- package/src/mesh/mesh-ledger.ts +587 -102
- package/src/mesh/mesh-missions.ts +151 -0
- package/src/mesh/mesh-refine-status.ts +144 -0
- package/src/mesh/mesh-review-inbox.ts +307 -0
- package/src/mesh/mesh-runtime-store.ts +1305 -0
- package/src/mesh/mesh-task-stats.ts +154 -0
- package/src/mesh/mesh-work-queue.ts +490 -166
- package/src/mesh/preview-freshness.ts +118 -0
- package/src/mesh/refine-config.ts +403 -0
- package/src/mesh/worktree-bootstrap-config.ts +326 -0
- package/src/providers/acp-provider-instance.ts +15 -1
- package/src/providers/approval-utils.d.ts +4 -0
- package/src/providers/approval-utils.ts +47 -5
- package/src/providers/chat-message-normalization.ts +4 -11
- package/src/providers/cli-provider-instance.ts +833 -64
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +141 -6
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +19 -5
- package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
- package/src/providers/native-history/claude-cli-transcript.ts +396 -0
- package/src/providers/native-history/codex-cli-transcript.ts +419 -0
- package/src/providers/native-history/dispatcher.ts +340 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
- package/src/providers/native-history/index.ts +30 -0
- package/src/providers/provider-instance-manager.ts +30 -0
- package/src/providers/provider-instance.ts +10 -1
- package/src/providers/provider-loader.ts +582 -50
- package/src/providers/provider-schema.ts +87 -14
- package/src/providers/provider-trust.ts +114 -0
- package/src/providers/read-chat-contract.ts +76 -16
- package/src/providers/sdk/README.md +49 -0
- package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +262 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
- package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
- package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
- package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
- package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
- package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
- package/src/providers/sdk/v1/index.ts +152 -0
- package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
- package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
- package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
- package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
- package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
- package/src/providers/sdk/v1/types/cli/index.ts +365 -0
- package/src/providers/sdk/v1/types/common/index.ts +229 -0
- package/src/providers/sdk/v1/validators/index.ts +19 -0
- package/src/providers/sdk/v1/validators/manifest.ts +110 -0
- package/src/providers/sdk/v1/validators/taint.ts +309 -0
- package/src/providers/spec/adapter.ts +138 -0
- package/src/providers/spec/cli-adapter.ts +626 -0
- package/src/providers/spec/driver.ts +912 -0
- package/src/providers/spec/evaluator.ts +597 -0
- package/src/providers/spec/loader.ts +324 -0
- package/src/providers/spec/native-history-executor.ts +939 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/schema.gen.ts +691 -0
- package/src/providers/spec/schema.json +341 -0
- package/src/providers/spec/types.ts +356 -0
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +425 -0
- package/src/providers/version-archive.ts +38 -20
- package/src/repo-mesh-types.ts +119 -1
- package/src/sessions/registry.ts +3 -0
- package/src/shared-types-extra.ts +2 -4
- package/src/shared-types.ts +45 -1
- package/src/status/builders.ts +24 -6
- package/src/status/normalize.ts +2 -0
- package/src/status/reporter.ts +15 -0
- package/src/status/snapshot.ts +84 -25
- package/src/system/host-memory.ts +29 -12
- package/src/types.ts +5 -0
- package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
- package/dist/mesh/mesh-sync.d.ts +0 -53
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
- 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: '
|
|
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?:
|
|
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?:
|
|
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: '
|
|
101
|
+
kind: 'coordinator_local_sqlite',
|
|
95
102
|
p2pOnly: true,
|
|
96
103
|
cloudD1LedgerSync: false,
|
|
97
|
-
notes: 'Coordinator reconciles bounded slices from daemon-local
|
|
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: {
|