@adhdev/daemon-standalone 0.9.82-rc.363 → 0.9.82-rc.365
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/index.js +1810 -1692
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30036,10 +30036,10 @@ var require_dist3 = __commonJS({
|
|
|
30036
30036
|
}
|
|
30037
30037
|
function getDaemonBuildInfo() {
|
|
30038
30038
|
if (cached2) return cached2;
|
|
30039
|
-
const commit = readInjected(true ? "
|
|
30040
|
-
const commitShort = readInjected(true ? "
|
|
30041
|
-
const version2 = readInjected(true ? "0.9.82-rc.
|
|
30042
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
30039
|
+
const commit = readInjected(true ? "fe24f3fb158efc949e806b79bca2479b1c29d753" : void 0) ?? "unknown";
|
|
30040
|
+
const commitShort = readInjected(true ? "fe24f3fb" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
30041
|
+
const version2 = readInjected(true ? "0.9.82-rc.365" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30042
|
+
const builtAt = readInjected(true ? "2026-06-24T00:48:25.762Z" : void 0);
|
|
30043
30043
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
30044
30044
|
return cached2;
|
|
30045
30045
|
}
|
|
@@ -31927,6 +31927,19 @@ ${error48.message || ""}`;
|
|
|
31927
31927
|
MAX_ACTIVITY = 30;
|
|
31928
31928
|
}
|
|
31929
31929
|
});
|
|
31930
|
+
function sha256Hex(input) {
|
|
31931
|
+
return (0, import_node_crypto.createHash)("sha256").update(input).digest("hex");
|
|
31932
|
+
}
|
|
31933
|
+
function shortHash(input, length = 16) {
|
|
31934
|
+
return sha256Hex(input).slice(0, length);
|
|
31935
|
+
}
|
|
31936
|
+
var import_node_crypto;
|
|
31937
|
+
var init_hash = __esm2({
|
|
31938
|
+
"src/system/hash.ts"() {
|
|
31939
|
+
"use strict";
|
|
31940
|
+
import_node_crypto = require("crypto");
|
|
31941
|
+
}
|
|
31942
|
+
});
|
|
31930
31943
|
function readObject(value) {
|
|
31931
31944
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
31932
31945
|
}
|
|
@@ -32201,7 +32214,7 @@ ${error48.message || ""}`;
|
|
|
32201
32214
|
return normalized;
|
|
32202
32215
|
}
|
|
32203
32216
|
function tokenIdForManualPairing(token) {
|
|
32204
|
-
return `tok_${(
|
|
32217
|
+
return `tok_${shortHash(token)}`;
|
|
32205
32218
|
}
|
|
32206
32219
|
function normalizeTokenExpiry(value) {
|
|
32207
32220
|
if (typeof value !== "string" || !value.trim()) return void 0;
|
|
@@ -32440,6 +32453,7 @@ ${error48.message || ""}`;
|
|
|
32440
32453
|
import_fs3 = require("fs");
|
|
32441
32454
|
import_path3 = require("path");
|
|
32442
32455
|
import_crypto3 = require("crypto");
|
|
32456
|
+
init_hash();
|
|
32443
32457
|
init_config();
|
|
32444
32458
|
init_repo_mesh_types();
|
|
32445
32459
|
init_mesh_host_ownership();
|
|
@@ -36860,7 +36874,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
36860
36874
|
function resolveHermesCoordinatorHome(meshId, workspace) {
|
|
36861
36875
|
const key = `${meshId || "mesh"}
|
|
36862
36876
|
${(0, import_node_path.resolve)(workspace || os42.tmpdir())}`;
|
|
36863
|
-
const hash2 = (
|
|
36877
|
+
const hash2 = shortHash(key);
|
|
36864
36878
|
return (0, import_node_path.join)(os42.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash2}`);
|
|
36865
36879
|
}
|
|
36866
36880
|
function resolveMcpConfigPath(configPath, workspace) {
|
|
@@ -37069,7 +37083,6 @@ ${rendered}`, "utf-8");
|
|
|
37069
37083
|
});
|
|
37070
37084
|
});
|
|
37071
37085
|
}
|
|
37072
|
-
var import_node_crypto;
|
|
37073
37086
|
var import_node_fs3;
|
|
37074
37087
|
var os42;
|
|
37075
37088
|
var import_session_host_core4;
|
|
@@ -37081,12 +37094,12 @@ ${rendered}`, "utf-8");
|
|
|
37081
37094
|
var init_mesh_coordinator = __esm2({
|
|
37082
37095
|
"src/commands/mesh-coordinator.ts"() {
|
|
37083
37096
|
"use strict";
|
|
37084
|
-
import_node_crypto = require("crypto");
|
|
37085
37097
|
import_node_fs3 = require("fs");
|
|
37086
37098
|
os42 = __toESM2(require("os"));
|
|
37087
37099
|
import_session_host_core4 = require_dist();
|
|
37088
37100
|
import_node_path = require("path");
|
|
37089
37101
|
init_logger();
|
|
37102
|
+
init_hash();
|
|
37090
37103
|
DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
37091
37104
|
DEFAULT_ADHDEV_MCP_COMMAND = "adhdev";
|
|
37092
37105
|
HERMES_CLI_TYPE = "hermes-cli";
|
|
@@ -37953,6 +37966,46 @@ ${rendered}`, "utf-8");
|
|
|
37953
37966
|
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !liveStaleReason);
|
|
37954
37967
|
return { ledgerOnlyStaleReason, isFreshUnacknowledged };
|
|
37955
37968
|
}
|
|
37969
|
+
function buildLedgerDirectDispatchRecord(dispatch, ctx) {
|
|
37970
|
+
const taskId = directDispatchTaskId(dispatch);
|
|
37971
|
+
const terminal = ctx.terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
37972
|
+
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
37973
|
+
const live = sessionStatusFromNodes(ctx.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
37974
|
+
const status = terminalStatus || live.status || "assigned";
|
|
37975
|
+
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
37976
|
+
const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
|
|
37977
|
+
status,
|
|
37978
|
+
isTerminalRow: terminalRow,
|
|
37979
|
+
hasTerminalStatus: Boolean(terminalStatus),
|
|
37980
|
+
liveStatus: live.status,
|
|
37981
|
+
liveStaleReason: live.staleReason,
|
|
37982
|
+
dispatchedToIdleSession: dispatch.payload?.dispatchedToIdleSession === true
|
|
37983
|
+
});
|
|
37984
|
+
const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
|
|
37985
|
+
const { title, summary } = summarizeMessage(message);
|
|
37986
|
+
const record2 = {
|
|
37987
|
+
taskId,
|
|
37988
|
+
source: "direct",
|
|
37989
|
+
status,
|
|
37990
|
+
nodeId: dispatch.nodeId,
|
|
37991
|
+
sessionId: dispatch.sessionId,
|
|
37992
|
+
providerType: dispatch.providerType || readString6(dispatch.payload?.providerType),
|
|
37993
|
+
taskTitle: readString6(dispatch.payload?.taskTitle) || title,
|
|
37994
|
+
taskSummary: readString6(dispatch.payload?.taskSummary) || summary,
|
|
37995
|
+
message,
|
|
37996
|
+
taskMode: readString6(dispatch.payload?.taskMode),
|
|
37997
|
+
createdAt: dispatch.timestamp,
|
|
37998
|
+
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
37999
|
+
dispatchedAt: dispatch.timestamp,
|
|
38000
|
+
elapsedMs: elapsedSince(dispatch.timestamp, ctx.now),
|
|
38001
|
+
terminal: terminalRow,
|
|
38002
|
+
terminalKind: terminal?.kind,
|
|
38003
|
+
terminalAt: terminal?.timestamp,
|
|
38004
|
+
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
38005
|
+
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
38006
|
+
};
|
|
38007
|
+
return { record: record2, terminalRow };
|
|
38008
|
+
}
|
|
37956
38009
|
function buildMeshActiveWorkSummary(activeWork) {
|
|
37957
38010
|
const statusCounts = {
|
|
37958
38011
|
pending: 0,
|
|
@@ -38058,49 +38111,13 @@ ${rendered}`, "utf-8");
|
|
|
38058
38111
|
const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
38059
38112
|
const terminals = ledgerEntries.filter((entry) => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === "task_approval_needed");
|
|
38060
38113
|
for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
|
|
38061
|
-
|
|
38062
|
-
|
|
38063
|
-
const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
38064
|
-
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
38065
|
-
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
38066
|
-
const status = terminalStatus || live.status || "assigned";
|
|
38067
|
-
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
38068
|
-
const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
|
|
38069
|
-
status,
|
|
38070
|
-
isTerminalRow: terminalRow,
|
|
38071
|
-
hasTerminalStatus: Boolean(terminalStatus),
|
|
38072
|
-
liveStatus: live.status,
|
|
38073
|
-
liveStaleReason: live.staleReason,
|
|
38074
|
-
dispatchedToIdleSession: dispatch.payload?.dispatchedToIdleSession === true
|
|
38075
|
-
});
|
|
38076
|
-
const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
|
|
38077
|
-
const { title, summary: summary2 } = summarizeMessage(message);
|
|
38078
|
-
const record2 = {
|
|
38079
|
-
taskId,
|
|
38080
|
-
source: "direct",
|
|
38081
|
-
status,
|
|
38082
|
-
nodeId: dispatch.nodeId,
|
|
38083
|
-
sessionId: dispatch.sessionId,
|
|
38084
|
-
providerType: dispatch.providerType || readString6(dispatch.payload?.providerType),
|
|
38085
|
-
taskTitle: readString6(dispatch.payload?.taskTitle) || title,
|
|
38086
|
-
taskSummary: readString6(dispatch.payload?.taskSummary) || summary2,
|
|
38087
|
-
message,
|
|
38088
|
-
taskMode: readString6(dispatch.payload?.taskMode),
|
|
38089
|
-
createdAt: dispatch.timestamp,
|
|
38090
|
-
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
38091
|
-
dispatchedAt: dispatch.timestamp,
|
|
38092
|
-
elapsedMs: elapsedSince(dispatch.timestamp, now),
|
|
38093
|
-
terminal: terminalRow,
|
|
38094
|
-
terminalKind: terminal?.kind,
|
|
38095
|
-
terminalAt: terminal?.timestamp,
|
|
38096
|
-
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
38097
|
-
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
38098
|
-
};
|
|
38114
|
+
if (dbTaskIds.has(directDispatchTaskId(dispatch))) continue;
|
|
38115
|
+
const { record: record2, terminalRow } = buildLedgerDirectDispatchRecord(dispatch, { terminals, nodes: opts.nodes, now });
|
|
38099
38116
|
if (terminalRow) {
|
|
38100
38117
|
terminalDirectWork.push(record2);
|
|
38101
38118
|
if (opts.includeTerminalDirect !== true) continue;
|
|
38102
38119
|
}
|
|
38103
|
-
if (
|
|
38120
|
+
if (record2.staleReason && !terminalRow) {
|
|
38104
38121
|
staleDirectWork.push(record2);
|
|
38105
38122
|
continue;
|
|
38106
38123
|
}
|
|
@@ -38110,48 +38127,12 @@ ${rendered}`, "utf-8");
|
|
|
38110
38127
|
const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
38111
38128
|
const terminals = ledgerEntries.filter((entry) => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === "task_approval_needed");
|
|
38112
38129
|
for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
|
|
38113
|
-
const
|
|
38114
|
-
const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
38115
|
-
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
38116
|
-
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
38117
|
-
const status = terminalStatus || live.status || "assigned";
|
|
38118
|
-
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
38119
|
-
const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
|
|
38120
|
-
status,
|
|
38121
|
-
isTerminalRow: terminalRow,
|
|
38122
|
-
hasTerminalStatus: Boolean(terminalStatus),
|
|
38123
|
-
liveStatus: live.status,
|
|
38124
|
-
liveStaleReason: live.staleReason,
|
|
38125
|
-
dispatchedToIdleSession: dispatch.payload?.dispatchedToIdleSession === true
|
|
38126
|
-
});
|
|
38127
|
-
const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
|
|
38128
|
-
const { title, summary: summary2 } = summarizeMessage(message);
|
|
38129
|
-
const record2 = {
|
|
38130
|
-
taskId,
|
|
38131
|
-
source: "direct",
|
|
38132
|
-
status,
|
|
38133
|
-
nodeId: dispatch.nodeId,
|
|
38134
|
-
sessionId: dispatch.sessionId,
|
|
38135
|
-
providerType: dispatch.providerType || readString6(dispatch.payload?.providerType),
|
|
38136
|
-
taskTitle: readString6(dispatch.payload?.taskTitle) || title,
|
|
38137
|
-
taskSummary: readString6(dispatch.payload?.taskSummary) || summary2,
|
|
38138
|
-
message,
|
|
38139
|
-
taskMode: readString6(dispatch.payload?.taskMode),
|
|
38140
|
-
createdAt: dispatch.timestamp,
|
|
38141
|
-
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
38142
|
-
dispatchedAt: dispatch.timestamp,
|
|
38143
|
-
elapsedMs: elapsedSince(dispatch.timestamp, now),
|
|
38144
|
-
terminal: terminalRow,
|
|
38145
|
-
terminalKind: terminal?.kind,
|
|
38146
|
-
terminalAt: terminal?.timestamp,
|
|
38147
|
-
staleReason: live.staleReason || ledgerOnlyStaleReason,
|
|
38148
|
-
...isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}
|
|
38149
|
-
};
|
|
38130
|
+
const { record: record2, terminalRow } = buildLedgerDirectDispatchRecord(dispatch, { terminals, nodes: opts.nodes, now });
|
|
38150
38131
|
if (terminalRow) {
|
|
38151
38132
|
terminalDirectWork.push(record2);
|
|
38152
38133
|
if (opts.includeTerminalDirect !== true) continue;
|
|
38153
38134
|
}
|
|
38154
|
-
if (
|
|
38135
|
+
if (record2.staleReason && !terminalRow) {
|
|
38155
38136
|
staleDirectWork.push(record2);
|
|
38156
38137
|
continue;
|
|
38157
38138
|
}
|
|
@@ -64392,6 +64373,7 @@ ${body}
|
|
|
64392
64373
|
...meshNodeLogsHandlers
|
|
64393
64374
|
})
|
|
64394
64375
|
);
|
|
64376
|
+
init_dist();
|
|
64395
64377
|
var os21 = __toESM2(require("os"));
|
|
64396
64378
|
var path27 = __toESM2(require("path"));
|
|
64397
64379
|
var crypto5 = __toESM2(require("crypto"));
|
|
@@ -64404,6 +64386,7 @@ ${body}
|
|
|
64404
64386
|
init_state_store();
|
|
64405
64387
|
init_workspaces();
|
|
64406
64388
|
init_recent_activity();
|
|
64389
|
+
init_hash();
|
|
64407
64390
|
init_coordinator_registry();
|
|
64408
64391
|
init_summary_metadata();
|
|
64409
64392
|
var os20 = __toESM2(require("os"));
|
|
@@ -64729,6 +64712,11 @@ ${body}
|
|
|
64729
64712
|
lastWin32WriteAt = 0;
|
|
64730
64713
|
/** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
|
|
64731
64714
|
win32WriteTimer = null;
|
|
64715
|
+
/** Timer driving the win32 verification-based modal-confirm CR resend loop (see
|
|
64716
|
+
* scheduleWin32ModalConfirm). A lone CR that confirms an approval/picker choice
|
|
64717
|
+
* is absorbed by ConPTY the same way a send_message submit CR is, so the confirm
|
|
64718
|
+
* must be resent until the modal actually resolves (status leaves 'approval'). */
|
|
64719
|
+
win32ModalConfirmTimer = null;
|
|
64732
64720
|
currentEval = null;
|
|
64733
64721
|
stateHistory = [];
|
|
64734
64722
|
prevStateAt = 0;
|
|
@@ -64853,6 +64841,10 @@ ${body}
|
|
|
64853
64841
|
clearTimeout(this.win32WriteTimer);
|
|
64854
64842
|
this.win32WriteTimer = null;
|
|
64855
64843
|
}
|
|
64844
|
+
if (this.win32ModalConfirmTimer) {
|
|
64845
|
+
clearTimeout(this.win32ModalConfirmTimer);
|
|
64846
|
+
this.win32ModalConfirmTimer = null;
|
|
64847
|
+
}
|
|
64856
64848
|
this.specWatcher?.close();
|
|
64857
64849
|
this.adapter.kill();
|
|
64858
64850
|
}
|
|
@@ -65448,10 +65440,61 @@ ${body}
|
|
|
65448
65440
|
const nav = step.repeat(Math.abs(delta));
|
|
65449
65441
|
const confirm = (rule.key_for_index || "\r").replace(/\{index\}/g, "") || "\r";
|
|
65450
65442
|
if (nav) this.adapter.send_keys(nav);
|
|
65451
|
-
this.
|
|
65443
|
+
this.submitModalConfirm(confirm);
|
|
65452
65444
|
return;
|
|
65453
65445
|
}
|
|
65454
|
-
this.
|
|
65446
|
+
this.submitModalConfirm(btn.key);
|
|
65447
|
+
}
|
|
65448
|
+
/**
|
|
65449
|
+
* Submit a modal-confirm key sequence (the choice key + its trailing CR).
|
|
65450
|
+
*
|
|
65451
|
+
* On win32 the trailing CR is the SAME lone-CR-swallow case as a send_message
|
|
65452
|
+
* submit: ConPTY can absorb a single CR as a literal newline instead of a
|
|
65453
|
+
* confirm, so the approval/picker modal never resolves and the FSM flaps
|
|
65454
|
+
* approval↔busy while auto-approve keeps firing into the void (APPROVESTUCK).
|
|
65455
|
+
* So we split any non-CR prefix (e.g. the "1" of "1\r") off, write it once, and
|
|
65456
|
+
* resend the CR on a fixed cadence until the modal actually resolves (status
|
|
65457
|
+
* leaves 'approval'). Non-win32 keeps the single direct write — its CR submits
|
|
65458
|
+
* on the first try.
|
|
65459
|
+
*/
|
|
65460
|
+
submitModalConfirm(keys) {
|
|
65461
|
+
if (process.platform !== "win32") {
|
|
65462
|
+
this.adapter.send_keys(keys);
|
|
65463
|
+
return;
|
|
65464
|
+
}
|
|
65465
|
+
const m = /^([\s\S]*?)([\r\n]+)$/.exec(keys);
|
|
65466
|
+
const prefix = m ? m[1] : keys;
|
|
65467
|
+
const cr = m ? m[2] : "";
|
|
65468
|
+
if (prefix) this.adapter.send_keys(prefix);
|
|
65469
|
+
if (!cr) return;
|
|
65470
|
+
this.scheduleWin32ModalConfirm(cr);
|
|
65471
|
+
}
|
|
65472
|
+
/**
|
|
65473
|
+
* win32 modal-confirm CR resend loop. Mirrors scheduleWin32Submit's phase-2
|
|
65474
|
+
* verified resend, but gated on still being IN a modal (status 'approval')
|
|
65475
|
+
* rather than still idle: the first CR fires immediately, then resends every
|
|
65476
|
+
* WIN32_SUBMIT_RESEND_GAP_MS while the FSM is still showing the modal, up to
|
|
65477
|
+
* WIN32_SUBMIT_MAX_RESENDS. The instant the modal resolves (status flips to
|
|
65478
|
+
* generating/idle) we stop, so no stray CR leaks into the next turn's composer.
|
|
65479
|
+
*/
|
|
65480
|
+
scheduleWin32ModalConfirm(submitKey) {
|
|
65481
|
+
if (this.win32ModalConfirmTimer) {
|
|
65482
|
+
clearTimeout(this.win32ModalConfirmTimer);
|
|
65483
|
+
this.win32ModalConfirmTimer = null;
|
|
65484
|
+
}
|
|
65485
|
+
const fire = (attempt) => {
|
|
65486
|
+
this.win32ModalConfirmTimer = null;
|
|
65487
|
+
this.adapter.send_keys(submitKey);
|
|
65488
|
+
if (attempt + 1 >= WIN32_SUBMIT_MAX_RESENDS) return;
|
|
65489
|
+
this.win32ModalConfirmTimer = setTimeout(() => {
|
|
65490
|
+
if (this.currentStatus() !== "approval") {
|
|
65491
|
+
this.win32ModalConfirmTimer = null;
|
|
65492
|
+
return;
|
|
65493
|
+
}
|
|
65494
|
+
fire(attempt + 1);
|
|
65495
|
+
}, WIN32_SUBMIT_RESEND_GAP_MS);
|
|
65496
|
+
};
|
|
65497
|
+
fire(0);
|
|
65455
65498
|
}
|
|
65456
65499
|
handleAttachImage(blob, mime) {
|
|
65457
65500
|
const ctl = (this.spec.control_bar ?? []).find((c) => c.action.type === "attach_image");
|
|
@@ -70697,7 +70740,7 @@ ${rawInput}` : rawInput;
|
|
|
70697
70740
|
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
70698
70741
|
const baseDir = path27.join(os21.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
70699
70742
|
(0, import_fs15.mkdirSync)(baseDir, { recursive: true });
|
|
70700
|
-
const workspaceHash =
|
|
70743
|
+
const workspaceHash = shortHash(path27.resolve(workspace || os21.tmpdir()));
|
|
70701
70744
|
const filePath = path27.join(baseDir, `${workspaceHash}.json`);
|
|
70702
70745
|
(0, import_fs15.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
70703
70746
|
return filePath;
|
|
@@ -71664,6 +71707,154 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
71664
71707
|
return null;
|
|
71665
71708
|
}
|
|
71666
71709
|
};
|
|
71710
|
+
init_state_store();
|
|
71711
|
+
init_recent_activity();
|
|
71712
|
+
init_mesh_events_utils();
|
|
71713
|
+
var cliAgentHandlers = {
|
|
71714
|
+
launch_cli: async (ctx, args) => {
|
|
71715
|
+
const launchResult = await ctx.deps.cliManager.handleCliCommand("launch_cli", args);
|
|
71716
|
+
const meshNodeId = readStringValue(args?.settings?.meshNodeId);
|
|
71717
|
+
const meshId = readStringValue(args?.settings?.meshNodeFor);
|
|
71718
|
+
if (meshNodeId && meshId && launchResult?.success !== false) {
|
|
71719
|
+
try {
|
|
71720
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
71721
|
+
const meshObj = getMesh2(meshId) ?? ctx.getCachedInlineMesh(meshId);
|
|
71722
|
+
const nodeObj = Array.isArray(meshObj?.nodes) ? meshObj.nodes.find((n) => meshNodeIdMatches(n, meshNodeId)) : void 0;
|
|
71723
|
+
const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
|
|
71724
|
+
if (bootstrapStatus === "running") {
|
|
71725
|
+
return { success: true, ...launchResult, bootstrapPending: true };
|
|
71726
|
+
}
|
|
71727
|
+
} catch {
|
|
71728
|
+
}
|
|
71729
|
+
}
|
|
71730
|
+
return launchResult;
|
|
71731
|
+
},
|
|
71732
|
+
stop_cli: async (ctx, args) => {
|
|
71733
|
+
return ctx.deps.cliManager.handleCliCommand("stop_cli", args);
|
|
71734
|
+
},
|
|
71735
|
+
set_cli_view_mode: async (ctx, args) => {
|
|
71736
|
+
return ctx.deps.cliManager.handleCliCommand("set_cli_view_mode", args);
|
|
71737
|
+
},
|
|
71738
|
+
record_provider_pty: async (ctx, args) => {
|
|
71739
|
+
return ctx.deps.cliManager.handleCliCommand("record_provider_pty", args);
|
|
71740
|
+
},
|
|
71741
|
+
agent_command: async (ctx, args) => {
|
|
71742
|
+
{
|
|
71743
|
+
const dispatchSessionId = readStringValue(args?.targetSessionId, args?.sessionId, args?.instanceId);
|
|
71744
|
+
const dispatchMeshContext = args?.meshContext;
|
|
71745
|
+
if (dispatchSessionId && dispatchMeshContext) {
|
|
71746
|
+
try {
|
|
71747
|
+
const inst = ctx.deps.instanceManager.getInstance(dispatchSessionId);
|
|
71748
|
+
if (inst && typeof inst.updateSettings === "function") {
|
|
71749
|
+
const stamp = buildMeshWorkerRelayStamp(
|
|
71750
|
+
inst.getState?.()?.settings,
|
|
71751
|
+
{
|
|
71752
|
+
meshId: dispatchMeshContext.meshId,
|
|
71753
|
+
nodeId: dispatchMeshContext.nodeId,
|
|
71754
|
+
coordinatorDaemonId: dispatchMeshContext.coordinatorDaemonId,
|
|
71755
|
+
// Session-level anchor: preserved across the P2P dispatch to a
|
|
71756
|
+
// remote worker so its completion echoes back to the right session.
|
|
71757
|
+
coordinatorSessionId: dispatchMeshContext.coordinatorSessionId
|
|
71758
|
+
}
|
|
71759
|
+
);
|
|
71760
|
+
if (stamp) inst.updateSettings(stamp);
|
|
71761
|
+
}
|
|
71762
|
+
} catch {
|
|
71763
|
+
}
|
|
71764
|
+
}
|
|
71765
|
+
}
|
|
71766
|
+
const agentResult = await ctx.deps.cliManager.handleCliCommand("agent_command", args);
|
|
71767
|
+
const meshCtx = args?.meshContext;
|
|
71768
|
+
const dispatchNodeId = readStringValue(meshCtx?.nodeId);
|
|
71769
|
+
const dispatchMeshId = readStringValue(meshCtx?.meshId);
|
|
71770
|
+
if (dispatchNodeId && dispatchMeshId && agentResult?.success !== false) {
|
|
71771
|
+
try {
|
|
71772
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
71773
|
+
const meshObj = getMesh2(dispatchMeshId) ?? ctx.getCachedInlineMesh(dispatchMeshId);
|
|
71774
|
+
const nodeObj = Array.isArray(meshObj?.nodes) ? meshObj.nodes.find((n) => meshNodeIdMatches(n, dispatchNodeId)) : void 0;
|
|
71775
|
+
const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
|
|
71776
|
+
if (bootstrapStatus === "running") {
|
|
71777
|
+
return {
|
|
71778
|
+
success: true,
|
|
71779
|
+
...agentResult,
|
|
71780
|
+
dispatchAcknowledgementRisk: true,
|
|
71781
|
+
dispatchAcknowledgementRiskReason: "bootstrap_still_running",
|
|
71782
|
+
nextAction: "Wait for worktree_bootstrap_complete event before dispatching work to this node."
|
|
71783
|
+
};
|
|
71784
|
+
}
|
|
71785
|
+
} catch {
|
|
71786
|
+
}
|
|
71787
|
+
}
|
|
71788
|
+
return agentResult;
|
|
71789
|
+
},
|
|
71790
|
+
// ─── Logs ───
|
|
71791
|
+
list_saved_sessions: async (ctx, args) => {
|
|
71792
|
+
const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : typeof args?.agentType === "string" ? args.agentType.trim() : "";
|
|
71793
|
+
const kind = args?.kind === "acp" ? "acp" : "cli";
|
|
71794
|
+
if (!providerType) {
|
|
71795
|
+
return { success: false, error: "providerType required" };
|
|
71796
|
+
}
|
|
71797
|
+
const wantsAll = args?.all === true;
|
|
71798
|
+
const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
|
|
71799
|
+
const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
|
|
71800
|
+
const requestedWorkspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
71801
|
+
const requestedProviderSessionId = typeof args?.providerSessionId === "string" ? args.providerSessionId.trim() : typeof args?.activeProviderSessionId === "string" ? args.activeProviderSessionId.trim() : "";
|
|
71802
|
+
const providerMeta = ctx.deps.providerLoader.resolve?.(providerType) || ctx.deps.providerLoader.getMeta(providerType);
|
|
71803
|
+
const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
|
|
71804
|
+
canonicalHistory: providerMeta?.nativeHistory,
|
|
71805
|
+
offset,
|
|
71806
|
+
limit,
|
|
71807
|
+
historyBehavior: providerMeta?.historyBehavior,
|
|
71808
|
+
scripts: providerMeta?.scripts
|
|
71809
|
+
});
|
|
71810
|
+
const state = loadState();
|
|
71811
|
+
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
71812
|
+
const recentSessions = getRecentActivity(state, 200).filter((entry) => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
71813
|
+
const savedSessionById = new Map(savedSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
71814
|
+
const recentSessionById = new Map(recentSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
71815
|
+
const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
|
|
71816
|
+
return {
|
|
71817
|
+
success: true,
|
|
71818
|
+
sessions: historySessions.map((session) => {
|
|
71819
|
+
const saved = savedSessionById.get(session.historySessionId);
|
|
71820
|
+
const recent = recentSessionById.get(session.historySessionId);
|
|
71821
|
+
const workspace = saved?.workspace || recent?.workspace || session.workspace || (requestedWorkspace && requestedProviderSessionId === session.historySessionId ? requestedWorkspace : void 0);
|
|
71822
|
+
return {
|
|
71823
|
+
id: session.historySessionId,
|
|
71824
|
+
providerSessionId: session.historySessionId,
|
|
71825
|
+
providerType,
|
|
71826
|
+
providerName: saved?.providerName || recent?.providerName || providerType,
|
|
71827
|
+
kind: saved?.kind || recent?.kind || kind,
|
|
71828
|
+
title: saved?.title || recent?.title || session.sessionTitle || session.preview || providerType,
|
|
71829
|
+
workspace,
|
|
71830
|
+
summaryMetadata: saved?.summaryMetadata || recent?.summaryMetadata,
|
|
71831
|
+
preview: session.preview,
|
|
71832
|
+
messageCount: session.messageCount,
|
|
71833
|
+
firstMessageAt: session.firstMessageAt,
|
|
71834
|
+
lastMessageAt: session.lastMessageAt,
|
|
71835
|
+
canResume: !!workspace && canResumeById,
|
|
71836
|
+
historySource: session.source,
|
|
71837
|
+
sourcePath: session.sourcePath,
|
|
71838
|
+
sourceMtimeMs: session.sourceMtimeMs
|
|
71839
|
+
};
|
|
71840
|
+
}),
|
|
71841
|
+
hasMore,
|
|
71842
|
+
source
|
|
71843
|
+
};
|
|
71844
|
+
},
|
|
71845
|
+
// ─── restart_session: IDE / CLI / ACP unified ───
|
|
71846
|
+
restart_session: async (ctx, args) => {
|
|
71847
|
+
const targetType = args?.cliType || args?.agentType || args?.ideType;
|
|
71848
|
+
if (!targetType) throw new Error("cliType or ideType required");
|
|
71849
|
+
const isIde = ctx.deps.cdpManagers.has(targetType) || ctx.deps.providerLoader.getMeta(targetType)?.category === "ide";
|
|
71850
|
+
if (isIde) {
|
|
71851
|
+
await ctx.stopIde(targetType, true);
|
|
71852
|
+
const launchResult = await ctx.launchIde({ ideType: targetType, enableCdp: true, workspace: args?.workspace });
|
|
71853
|
+
return { success: true, restarted: true, ideType: targetType, launch: launchResult };
|
|
71854
|
+
}
|
|
71855
|
+
return ctx.deps.cliManager.handleCliCommand("restart_session", args);
|
|
71856
|
+
}
|
|
71857
|
+
};
|
|
71667
71858
|
var import_child_process9 = require("child_process");
|
|
71668
71859
|
var net3 = __toESM2(require("net"));
|
|
71669
71860
|
var os26 = __toESM2(require("os"));
|
|
@@ -75468,326 +75659,1071 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
75468
75659
|
init_workspaces();
|
|
75469
75660
|
init_recent_activity();
|
|
75470
75661
|
init_cli_detector();
|
|
75471
|
-
init_git_status();
|
|
75472
|
-
init_dist();
|
|
75473
75662
|
init_logger();
|
|
75474
|
-
|
|
75475
|
-
|
|
75476
|
-
|
|
75477
|
-
|
|
75478
|
-
|
|
75479
|
-
|
|
75480
|
-
|
|
75481
|
-
|
|
75482
|
-
|
|
75483
|
-
|
|
75484
|
-
|
|
75485
|
-
|
|
75486
|
-
|
|
75487
|
-
|
|
75488
|
-
|
|
75489
|
-
"
|
|
75490
|
-
|
|
75491
|
-
|
|
75492
|
-
|
|
75493
|
-
|
|
75494
|
-
|
|
75495
|
-
|
|
75496
|
-
|
|
75497
|
-
|
|
75498
|
-
|
|
75499
|
-
|
|
75500
|
-
|
|
75501
|
-
|
|
75502
|
-
}
|
|
75503
|
-
|
|
75504
|
-
|
|
75505
|
-
|
|
75506
|
-
|
|
75507
|
-
|
|
75663
|
+
async function launchIde(ctx, args) {
|
|
75664
|
+
const ideKey = args?.ideId || args?.ideType;
|
|
75665
|
+
const resolvedWorkspace = resolveIdeLaunchWorkspace(
|
|
75666
|
+
{
|
|
75667
|
+
workspace: args?.workspace,
|
|
75668
|
+
workspaceId: args?.workspaceId,
|
|
75669
|
+
useDefaultWorkspace: args?.useDefaultWorkspace
|
|
75670
|
+
},
|
|
75671
|
+
loadConfig2()
|
|
75672
|
+
);
|
|
75673
|
+
const launchArgs = {
|
|
75674
|
+
ideId: ideKey,
|
|
75675
|
+
workspace: resolvedWorkspace,
|
|
75676
|
+
newWindow: args?.newWindow
|
|
75677
|
+
};
|
|
75678
|
+
LOG2.info("LaunchIDE", `target=${ideKey || "auto"}`);
|
|
75679
|
+
const result = await launchWithCdp(launchArgs);
|
|
75680
|
+
if (result.success && result.port && result.ideId && !ctx.deps.cdpManagers.has(result.ideId)) {
|
|
75681
|
+
const logFn = ctx.deps.getCdpLogFn ? ctx.deps.getCdpLogFn(result.ideId) : LOG2.forComponent(`CDP:${result.ideId}`).asLogFn();
|
|
75682
|
+
const provider = ctx.deps.providerLoader.getMeta(result.ideId);
|
|
75683
|
+
const manager = new DaemonCdpManager(result.port, logFn, void 0, provider?.targetFilter);
|
|
75684
|
+
const connected = await manager.connect();
|
|
75685
|
+
if (connected) {
|
|
75686
|
+
registerExtensionProviders(ctx.deps.providerLoader, manager, result.ideId);
|
|
75687
|
+
ctx.deps.cdpManagers.set(result.ideId, manager);
|
|
75688
|
+
LOG2.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
|
|
75689
|
+
LOG2.info("CDP", `${ctx.deps.cdpManagers.size} IDE(s) connected`);
|
|
75690
|
+
ctx.deps.onCdpManagerCreated?.(result.ideId, manager);
|
|
75691
|
+
}
|
|
75692
|
+
}
|
|
75693
|
+
ctx.deps.onIdeConnected?.();
|
|
75694
|
+
try {
|
|
75695
|
+
const results = await detectIDEs(ctx.deps.providerLoader);
|
|
75696
|
+
ctx.deps.detectedIdes.value = results;
|
|
75697
|
+
ctx.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
75698
|
+
} catch {
|
|
75699
|
+
}
|
|
75700
|
+
if (result.success && resolvedWorkspace) {
|
|
75701
|
+
try {
|
|
75702
|
+
const next = appendRecentActivity(loadState(), {
|
|
75703
|
+
kind: "ide",
|
|
75704
|
+
providerType: result.ideId || ideKey,
|
|
75705
|
+
providerName: result.ideId || ideKey,
|
|
75706
|
+
workspace: resolvedWorkspace,
|
|
75707
|
+
title: result.ideId || ideKey
|
|
75708
|
+
});
|
|
75709
|
+
saveState(next);
|
|
75710
|
+
} catch {
|
|
75711
|
+
}
|
|
75712
|
+
} else if (result.success && (result.ideId || ideKey)) {
|
|
75713
|
+
try {
|
|
75714
|
+
saveState(appendRecentActivity(loadState(), {
|
|
75715
|
+
kind: "ide",
|
|
75716
|
+
providerType: result.ideId || ideKey,
|
|
75717
|
+
providerName: result.ideId || ideKey,
|
|
75718
|
+
title: result.ideId || ideKey
|
|
75719
|
+
}));
|
|
75720
|
+
} catch {
|
|
75508
75721
|
}
|
|
75509
75722
|
}
|
|
75510
|
-
return
|
|
75511
|
-
}
|
|
75512
|
-
function getDateStr2() {
|
|
75513
|
-
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
75723
|
+
return { ...result };
|
|
75514
75724
|
}
|
|
75515
|
-
var
|
|
75516
|
-
|
|
75517
|
-
|
|
75518
|
-
|
|
75519
|
-
|
|
75520
|
-
|
|
75521
|
-
|
|
75522
|
-
|
|
75523
|
-
|
|
75725
|
+
var ideHandlers = {
|
|
75726
|
+
// ─── IDE stop ───
|
|
75727
|
+
stop_ide: async (ctx, args) => {
|
|
75728
|
+
const ideType = args?.ideType;
|
|
75729
|
+
if (!ideType) throw new Error("ideType required");
|
|
75730
|
+
const killProcess = args?.killProcess !== false;
|
|
75731
|
+
await ctx.stopIde(ideType, killProcess);
|
|
75732
|
+
try {
|
|
75733
|
+
const results = await detectIDEs(ctx.deps.providerLoader);
|
|
75734
|
+
ctx.deps.detectedIdes.value = results;
|
|
75735
|
+
ctx.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
75736
|
+
} catch {
|
|
75737
|
+
}
|
|
75738
|
+
return { success: true, ideType, stopped: true, processKilled: killProcess };
|
|
75739
|
+
},
|
|
75740
|
+
// ─── IDE restart ───
|
|
75741
|
+
restart_ide: async (ctx, args) => {
|
|
75742
|
+
const ideType = args?.ideType;
|
|
75743
|
+
if (!ideType) throw new Error("ideType required");
|
|
75744
|
+
await ctx.stopIde(ideType, true);
|
|
75745
|
+
const launchResult = await ctx.launchIde({ ideType, enableCdp: true, workspace: args?.workspace });
|
|
75746
|
+
return { success: true, ideType, restarted: true, launch: launchResult };
|
|
75747
|
+
},
|
|
75748
|
+
// ─── IDE launch + CDP connect ───
|
|
75749
|
+
launch_ide: async (ctx, args) => {
|
|
75750
|
+
return launchIde(ctx, args);
|
|
75751
|
+
},
|
|
75752
|
+
// ─── Detect providers ───
|
|
75753
|
+
detect_provider: async (ctx, args) => {
|
|
75754
|
+
const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : "";
|
|
75755
|
+
if (!providerType) return { success: false, error: "providerType is required" };
|
|
75756
|
+
const normalizedType = ctx.deps.providerLoader.resolveAlias(providerType);
|
|
75757
|
+
const provider = ctx.deps.providerLoader.getByAlias(providerType);
|
|
75758
|
+
if (!provider) return { success: false, error: `Provider not found: ${providerType}` };
|
|
75759
|
+
if (provider.category !== "cli" && provider.category !== "acp") {
|
|
75760
|
+
return { success: false, error: `Provider detection is only supported for CLI/ACP providers: ${providerType}` };
|
|
75761
|
+
}
|
|
75762
|
+
if (!ctx.deps.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
75763
|
+
return { success: false, error: `Provider is disabled on this machine: ${providerType}` };
|
|
75764
|
+
}
|
|
75765
|
+
const detected = await detectCLI(normalizedType, ctx.deps.providerLoader, { includeVersion: false });
|
|
75766
|
+
ctx.deps.providerLoader.setCliDetectionResults([{
|
|
75767
|
+
id: normalizedType,
|
|
75768
|
+
installed: !!detected,
|
|
75769
|
+
path: detected?.path
|
|
75770
|
+
}], false);
|
|
75771
|
+
ctx.deps.onStatusChange?.();
|
|
75772
|
+
return {
|
|
75773
|
+
success: true,
|
|
75774
|
+
providerType: normalizedType,
|
|
75775
|
+
detected: !!detected,
|
|
75776
|
+
path: detected?.path || null
|
|
75777
|
+
};
|
|
75778
|
+
},
|
|
75779
|
+
// ─── Detect IDEs ───
|
|
75780
|
+
detect_ides: async (ctx, _args) => {
|
|
75781
|
+
const results = await detectIDEs(ctx.deps.providerLoader);
|
|
75782
|
+
ctx.deps.detectedIdes.value = results;
|
|
75783
|
+
ctx.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
75784
|
+
return { success: true, detectedInfo: results };
|
|
75524
75785
|
}
|
|
75525
|
-
}
|
|
75526
|
-
|
|
75527
|
-
|
|
75528
|
-
|
|
75529
|
-
|
|
75530
|
-
|
|
75531
|
-
|
|
75532
|
-
|
|
75533
|
-
const
|
|
75534
|
-
|
|
75786
|
+
};
|
|
75787
|
+
init_dist();
|
|
75788
|
+
init_mesh_host_ownership();
|
|
75789
|
+
init_mesh_events();
|
|
75790
|
+
init_config();
|
|
75791
|
+
var meshCrudHandlers = {
|
|
75792
|
+
list_meshes: async (_ctx, _args) => {
|
|
75793
|
+
try {
|
|
75794
|
+
const { listMeshes: listMeshes2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
75795
|
+
return { success: true, meshes: listMeshes2() };
|
|
75796
|
+
} catch (e) {
|
|
75797
|
+
return { success: false, error: e.message };
|
|
75798
|
+
}
|
|
75799
|
+
},
|
|
75800
|
+
get_mesh: async (ctx, args) => {
|
|
75801
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
75802
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
75803
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
75804
|
+
if (!meshRecord?.mesh) return { success: false, error: "Mesh not found" };
|
|
75805
|
+
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
75806
|
+
const probeRemotePeers = args?.refresh === true || args?.forceRefresh === true;
|
|
75807
|
+
const directTruth = await hydrateInlineMeshDirectTruth({
|
|
75808
|
+
mesh: meshRecord.mesh,
|
|
75809
|
+
meshSource: meshRecord.source,
|
|
75810
|
+
dispatchMeshCommand: ctx.deps.dispatchMeshCommand,
|
|
75811
|
+
getMeshPeerConnectionStatus: ctx.deps.getMeshPeerConnectionStatus,
|
|
75812
|
+
statusInstanceId: ctx.deps.statusInstanceId,
|
|
75813
|
+
localMachineId: loadConfig2().machineId || "",
|
|
75814
|
+
probeRemotePeers,
|
|
75815
|
+
probeCache: ctx.meshGitProbeCache
|
|
75816
|
+
});
|
|
75817
|
+
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
75818
|
+
const sourceOfTruth = {
|
|
75819
|
+
membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
75820
|
+
coordinatorOwnsLiveTruth: directTruthSatisfied,
|
|
75821
|
+
directPeerTruth: {
|
|
75822
|
+
required: requireDirectPeerTruth,
|
|
75823
|
+
satisfied: directTruthSatisfied,
|
|
75824
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
75825
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
75826
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
75827
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
75828
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
75829
|
+
}
|
|
75830
|
+
};
|
|
75831
|
+
if (requireDirectPeerTruth && !directTruthSatisfied) {
|
|
75832
|
+
return {
|
|
75833
|
+
success: false,
|
|
75834
|
+
code: "mesh_direct_peer_truth_unavailable",
|
|
75835
|
+
error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.",
|
|
75836
|
+
sourceOfTruth
|
|
75837
|
+
};
|
|
75838
|
+
}
|
|
75839
|
+
return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
|
|
75840
|
+
},
|
|
75841
|
+
create_mesh: async (_ctx, args) => {
|
|
75842
|
+
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
75843
|
+
const repoIdentity = typeof args?.repoIdentity === "string" ? args.repoIdentity.trim() : "";
|
|
75844
|
+
const repoRemoteUrl = typeof args?.repoRemoteUrl === "string" ? args.repoRemoteUrl.trim() : void 0;
|
|
75845
|
+
const defaultBranch = typeof args?.defaultBranch === "string" ? args.defaultBranch.trim() : void 0;
|
|
75846
|
+
if (!name) return { success: false, error: "name required" };
|
|
75847
|
+
try {
|
|
75848
|
+
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
75849
|
+
const meshHost = args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost) ? args.meshHost : void 0;
|
|
75850
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy, meshHost });
|
|
75851
|
+
return { success: true, mesh };
|
|
75852
|
+
} catch (e) {
|
|
75853
|
+
return { success: false, error: e.message };
|
|
75854
|
+
}
|
|
75855
|
+
},
|
|
75856
|
+
update_mesh: async (ctx, args) => {
|
|
75857
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
75858
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
75859
|
+
try {
|
|
75860
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
75861
|
+
const patch = {};
|
|
75862
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
75863
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
75864
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
75865
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
75866
|
+
if (args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost)) patch.meshHost = args.meshHost;
|
|
75867
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
75868
|
+
const mesh = updateMesh2(meshId, patch);
|
|
75869
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
75870
|
+
ctx.inlineMeshCache.set(meshId, mesh);
|
|
75871
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
75872
|
+
return { success: true, mesh };
|
|
75873
|
+
} catch (e) {
|
|
75874
|
+
return { success: false, error: e.message };
|
|
75875
|
+
}
|
|
75876
|
+
},
|
|
75877
|
+
delete_mesh: async (_ctx, args) => {
|
|
75878
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
75879
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
75880
|
+
try {
|
|
75881
|
+
const { deleteMesh: deleteMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
75882
|
+
const deleted = deleteMesh2(meshId);
|
|
75883
|
+
return { success: true, deleted };
|
|
75884
|
+
} catch (e) {
|
|
75885
|
+
return { success: false, error: e.message };
|
|
75886
|
+
}
|
|
75887
|
+
},
|
|
75888
|
+
add_mesh_node: async (ctx, args) => {
|
|
75889
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
75890
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
75891
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
75892
|
+
if (!workspace) return { success: false, error: "workspace required" };
|
|
75893
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node addition");
|
|
75894
|
+
if (ownerFailure) return ownerFailure;
|
|
75895
|
+
try {
|
|
75896
|
+
const { addNode: addNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
75897
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
75898
|
+
const readOnly = args?.readOnly === true;
|
|
75899
|
+
const providerRoles = normalizeProviderRoles(args?.providerRoles);
|
|
75900
|
+
const policy = {
|
|
75901
|
+
...readOnly ? { readOnly: true } : {},
|
|
75902
|
+
...providerPriority.length ? { providerPriority } : {},
|
|
75903
|
+
...providerRoles.length ? { providerRoles } : {}
|
|
75904
|
+
};
|
|
75905
|
+
const role = normalizeMeshDaemonRole(args?.role);
|
|
75906
|
+
const daemonId = typeof args?.daemonId === "string" && args.daemonId.trim() ? args.daemonId.trim() : void 0;
|
|
75907
|
+
const machineId = typeof args?.machineId === "string" && args.machineId.trim() ? args.machineId.trim() : void 0;
|
|
75908
|
+
const repoRoot = typeof args?.repoRoot === "string" && args.repoRoot.trim() ? args.repoRoot.trim() : void 0;
|
|
75909
|
+
const node = addNode2(meshId, {
|
|
75910
|
+
workspace,
|
|
75911
|
+
...repoRoot ? { repoRoot } : {},
|
|
75912
|
+
...daemonId ? { daemonId } : {},
|
|
75913
|
+
...machineId ? { machineId } : {},
|
|
75914
|
+
...policy ? { policy } : {},
|
|
75915
|
+
...role ? { role } : {}
|
|
75916
|
+
});
|
|
75917
|
+
if (!node) return { success: false, error: "Mesh not found" };
|
|
75918
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
75919
|
+
return { success: true, node };
|
|
75920
|
+
} catch (e) {
|
|
75921
|
+
return { success: false, error: e.message };
|
|
75922
|
+
}
|
|
75923
|
+
},
|
|
75924
|
+
update_mesh_node: async (ctx, args) => {
|
|
75925
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
75926
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
75927
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
75928
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node update");
|
|
75929
|
+
if (ownerFailure) return ownerFailure;
|
|
75930
|
+
try {
|
|
75931
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
75932
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
75933
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
75934
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
75935
|
+
delete policy.provider_priority;
|
|
75936
|
+
if (providerPriority.length) {
|
|
75937
|
+
policy.providerPriority = providerPriority;
|
|
75938
|
+
} else {
|
|
75939
|
+
delete policy.providerPriority;
|
|
75940
|
+
}
|
|
75941
|
+
}
|
|
75942
|
+
if (Array.isArray(args?.providerRoles)) {
|
|
75943
|
+
const providerRoles = normalizeProviderRoles(args.providerRoles);
|
|
75944
|
+
if (providerRoles.length) {
|
|
75945
|
+
policy.providerRoles = providerRoles;
|
|
75946
|
+
} else {
|
|
75947
|
+
delete policy.providerRoles;
|
|
75948
|
+
}
|
|
75949
|
+
}
|
|
75950
|
+
const patch = { policy };
|
|
75951
|
+
if (typeof args?.systemPrompt === "string") {
|
|
75952
|
+
const trimmed = args.systemPrompt.trim();
|
|
75953
|
+
patch.systemPrompt = trimmed || void 0;
|
|
75954
|
+
} else if (args?.systemPrompt === null) {
|
|
75955
|
+
patch.systemPrompt = void 0;
|
|
75956
|
+
}
|
|
75957
|
+
const node = updateNode2(meshId, nodeId, patch);
|
|
75958
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
75959
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
75960
|
+
return { success: true, node };
|
|
75961
|
+
} catch (e) {
|
|
75962
|
+
return { success: false, error: e.message };
|
|
75963
|
+
}
|
|
75964
|
+
},
|
|
75965
|
+
cleanup_mesh_sessions: async (ctx, args) => {
|
|
75966
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
75967
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
75968
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
75969
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node removal");
|
|
75970
|
+
if (ownerFailure) return ownerFailure;
|
|
75971
|
+
try {
|
|
75972
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
75973
|
+
const mesh = meshRecord?.mesh;
|
|
75974
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
75975
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
75976
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
75977
|
+
const mode = ctx.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
75978
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
75979
|
+
const result = await ctx.cleanupMeshSessions({
|
|
75980
|
+
meshId,
|
|
75981
|
+
nodeId,
|
|
75982
|
+
node,
|
|
75983
|
+
mode,
|
|
75984
|
+
sessionIds,
|
|
75985
|
+
dryRun: args?.dryRun === true,
|
|
75986
|
+
source: "mesh_cleanup_sessions"
|
|
75987
|
+
});
|
|
75988
|
+
return result;
|
|
75989
|
+
} catch (e) {
|
|
75990
|
+
return { success: false, error: e.message };
|
|
75991
|
+
}
|
|
75992
|
+
},
|
|
75993
|
+
remove_mesh_node: async (ctx, args) => {
|
|
75994
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
75995
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
75996
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
75997
|
+
try {
|
|
75998
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
75999
|
+
const mesh = meshRecord?.mesh;
|
|
76000
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
76001
|
+
if (node && !args?._meshDirectDispatch && node.isLocalWorktree !== true && args?.force !== true) {
|
|
76002
|
+
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : "";
|
|
76003
|
+
const nodeMachineId = readMeshNodeMachineId(node) || "";
|
|
76004
|
+
const selfDaemonId = ctx.deps.statusInstanceId || "";
|
|
76005
|
+
const selfMachineId = (() => {
|
|
76006
|
+
try {
|
|
76007
|
+
return loadConfig2().machineId || "";
|
|
76008
|
+
} catch {
|
|
76009
|
+
return "";
|
|
76010
|
+
}
|
|
76011
|
+
})();
|
|
76012
|
+
const isCoordinatorBaseNode = !!selfDaemonId && (nodeDaemonId === selfDaemonId || nodeMachineId === selfDaemonId) || !!selfMachineId && (nodeDaemonId === selfMachineId || nodeMachineId === selfMachineId);
|
|
76013
|
+
if (isCoordinatorBaseNode) {
|
|
76014
|
+
return {
|
|
76015
|
+
success: false,
|
|
76016
|
+
removed: false,
|
|
76017
|
+
code: "mesh_remove_coordinator_base_node_protected",
|
|
76018
|
+
error: `Refusing to remove the coordinator's own base node '${typeof node.workspace === "string" ? node.workspace : nodeId}'. It is the local non-worktree node bound to this coordinator daemon; removing it breaks live mesh membership and forces a restart.`,
|
|
76019
|
+
recoveryHint: "Remove worktree clone nodes instead, or pass force:true only if you are intentionally tearing down this mesh and accept that the coordinator must be re-registered/restarted."
|
|
76020
|
+
};
|
|
76021
|
+
}
|
|
76022
|
+
}
|
|
76023
|
+
const sessionCleanupMode = ctx.normalizeMeshSessionCleanupMode(
|
|
76024
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
76025
|
+
);
|
|
76026
|
+
const explicitSessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
|
|
76027
|
+
let sessionCleanup;
|
|
76028
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
76029
|
+
sessionCleanup = await ctx.cleanupMeshSessions({
|
|
76030
|
+
meshId,
|
|
76031
|
+
nodeId,
|
|
76032
|
+
node,
|
|
76033
|
+
mode: sessionCleanupMode,
|
|
76034
|
+
...explicitSessionIds && explicitSessionIds.length > 0 ? { sessionIds: explicitSessionIds } : {},
|
|
76035
|
+
source: "mesh_remove_node"
|
|
76036
|
+
});
|
|
76037
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
76038
|
+
}
|
|
76039
|
+
let worktreeCleanup;
|
|
76040
|
+
if (node?.isLocalWorktree) {
|
|
76041
|
+
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
76042
|
+
const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, ctx.deps.statusInstanceId) && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
|
|
76043
|
+
if (isRemoteWorktree) {
|
|
76044
|
+
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
|
|
76045
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
76046
|
+
_meshDirectDispatch: true
|
|
76047
|
+
});
|
|
76048
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
76049
|
+
}
|
|
76050
|
+
const cleanupResult = await ctx.cleanupLocalWorktreeNode({ mesh, node, nodeId, force: args?.force === true });
|
|
76051
|
+
if (cleanupResult.success === false) {
|
|
76052
|
+
return {
|
|
76053
|
+
success: false,
|
|
76054
|
+
removed: false,
|
|
76055
|
+
code: cleanupResult.code,
|
|
76056
|
+
error: cleanupResult.error,
|
|
76057
|
+
recoveryHint: cleanupResult.recoveryHint,
|
|
76058
|
+
...sessionCleanup ? { sessionCleanup } : {},
|
|
76059
|
+
worktreeCleanup: cleanupResult
|
|
76060
|
+
};
|
|
76061
|
+
}
|
|
76062
|
+
worktreeCleanup = cleanupResult;
|
|
76063
|
+
}
|
|
76064
|
+
let removed = false;
|
|
76065
|
+
if (meshRecord?.inline) {
|
|
76066
|
+
removed = ctx.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
76067
|
+
if (removed) ctx.invalidateAggregateMeshStatus(meshId);
|
|
76068
|
+
if (!removed && !node) removed = true;
|
|
76069
|
+
} else {
|
|
76070
|
+
const { removeNode: removeNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76071
|
+
removed = removeNode2(meshId, nodeId);
|
|
76072
|
+
if (!removed && !node) removed = true;
|
|
76073
|
+
if (removed) ctx.invalidateAggregateMeshStatus(meshId);
|
|
76074
|
+
}
|
|
76075
|
+
if (removed) {
|
|
75535
76076
|
try {
|
|
75536
|
-
|
|
76077
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
76078
|
+
appendLedgerEntry2(meshId, {
|
|
76079
|
+
kind: "node_removed",
|
|
76080
|
+
nodeId,
|
|
76081
|
+
payload: {
|
|
76082
|
+
worktree: !!node?.isLocalWorktree,
|
|
76083
|
+
sessionCleanupMode,
|
|
76084
|
+
workspace: typeof node?.workspace === "string" ? node.workspace : void 0,
|
|
76085
|
+
daemonId: typeof node?.daemonId === "string" ? node.daemonId : void 0,
|
|
76086
|
+
worktreeBranch: typeof node?.worktreeBranch === "string" ? node.worktreeBranch : void 0,
|
|
76087
|
+
worktreeCleanupFallback: typeof worktreeCleanup?.fallback === "string" ? worktreeCleanup.fallback : void 0,
|
|
76088
|
+
forced: worktreeCleanup?.forced === true ? true : void 0,
|
|
76089
|
+
forceFallbackReason: typeof worktreeCleanup?.reason === "string" ? worktreeCleanup.reason : void 0
|
|
76090
|
+
}
|
|
76091
|
+
});
|
|
75537
76092
|
} catch {
|
|
75538
76093
|
}
|
|
75539
76094
|
}
|
|
76095
|
+
const residueWarning = worktreeCleanup?.residue === true && typeof worktreeCleanup?.residueWarning === "string" ? worktreeCleanup.residueWarning : void 0;
|
|
76096
|
+
return {
|
|
76097
|
+
success: true,
|
|
76098
|
+
removed,
|
|
76099
|
+
...residueWarning ? { residueWarning } : {},
|
|
76100
|
+
...sessionCleanup ? { sessionCleanup } : {},
|
|
76101
|
+
...worktreeCleanup ? { worktreeCleanup } : {}
|
|
76102
|
+
};
|
|
76103
|
+
} catch (e) {
|
|
76104
|
+
return { success: false, error: e.message };
|
|
76105
|
+
}
|
|
76106
|
+
},
|
|
76107
|
+
clone_mesh_node: async (ctx, args) => {
|
|
76108
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76109
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
76110
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
76111
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
76112
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76113
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
76114
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
76115
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "worktree clone");
|
|
76116
|
+
if (ownerFailure) return ownerFailure;
|
|
76117
|
+
try {
|
|
76118
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76119
|
+
const mesh = meshRecord?.mesh;
|
|
76120
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
76121
|
+
const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
|
|
76122
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
76123
|
+
const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
|
|
76124
|
+
if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, ctx.deps.statusInstanceId) && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
76125
|
+
const forwarded = await ctx.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
|
|
76126
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
76127
|
+
_meshDirectDispatch: true
|
|
76128
|
+
});
|
|
76129
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
76130
|
+
}
|
|
76131
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
76132
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
76133
|
+
const result = await createWorktree2({
|
|
76134
|
+
repoRoot,
|
|
76135
|
+
branch,
|
|
76136
|
+
baseBranch,
|
|
76137
|
+
meshName: mesh.name
|
|
76138
|
+
});
|
|
76139
|
+
let node;
|
|
76140
|
+
if (meshRecord.inline) {
|
|
76141
|
+
const { randomUUID: randomUUID15 } = await import("crypto");
|
|
76142
|
+
node = {
|
|
76143
|
+
id: `node_${randomUUID15().replace(/-/g, "")}`,
|
|
76144
|
+
workspace: result.worktreePath,
|
|
76145
|
+
repoRoot: result.worktreePath,
|
|
76146
|
+
daemonId: sourceNode.daemonId,
|
|
76147
|
+
machineId: sourceNode.machineId ?? sourceNode.machine_id,
|
|
76148
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
76149
|
+
policy: { ...sourceNode.policy || {} },
|
|
76150
|
+
isLocalWorktree: true,
|
|
76151
|
+
worktreeBranch: result.branch,
|
|
76152
|
+
clonedFromNodeId: sourceNodeId
|
|
76153
|
+
};
|
|
76154
|
+
ctx.updateInlineMeshNode(meshId, mesh, node);
|
|
76155
|
+
} else {
|
|
76156
|
+
const { addNode: addNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76157
|
+
node = addNode2(meshId, {
|
|
76158
|
+
workspace: result.worktreePath,
|
|
76159
|
+
repoRoot: result.worktreePath,
|
|
76160
|
+
daemonId: sourceNode.daemonId,
|
|
76161
|
+
machineId: sourceNode.machineId ?? sourceNode.machine_id,
|
|
76162
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
76163
|
+
isLocalWorktree: true,
|
|
76164
|
+
worktreeBranch: result.branch,
|
|
76165
|
+
clonedFromNodeId: sourceNodeId,
|
|
76166
|
+
policy: { ...sourceNode.policy || {} }
|
|
76167
|
+
});
|
|
76168
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
76169
|
+
const inlineForReconcile = ctx.getCachedInlineMesh(meshId);
|
|
76170
|
+
if (inlineForReconcile) ctx.updateInlineMeshNode(meshId, inlineForReconcile, node);
|
|
76171
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
76172
|
+
}
|
|
76173
|
+
const persistWorktreeSetupState = async (bootstrapState2) => {
|
|
76174
|
+
node.worktreeBootstrap = bootstrapState2;
|
|
76175
|
+
if (meshRecord.inline) {
|
|
76176
|
+
ctx.updateInlineMeshNode(meshId, mesh, node);
|
|
76177
|
+
return;
|
|
76178
|
+
}
|
|
76179
|
+
try {
|
|
76180
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76181
|
+
updateNode2(meshId, node.id, { worktreeBootstrap: bootstrapState2 });
|
|
76182
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
76183
|
+
} catch {
|
|
76184
|
+
}
|
|
76185
|
+
};
|
|
76186
|
+
const appendCloneLedger = async (initSubmodules2, bootstrapState2) => {
|
|
76187
|
+
try {
|
|
76188
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
76189
|
+
appendLedgerEntry2(meshId, {
|
|
76190
|
+
kind: "node_cloned",
|
|
76191
|
+
nodeId: node.id,
|
|
76192
|
+
payload: {
|
|
76193
|
+
sourceNodeId,
|
|
76194
|
+
branch: result.branch,
|
|
76195
|
+
worktreePath: result.worktreePath,
|
|
76196
|
+
submodulesInitialized: initSubmodules2,
|
|
76197
|
+
worktreeBootstrap: {
|
|
76198
|
+
status: bootstrapState2.status,
|
|
76199
|
+
required: bootstrapState2.required,
|
|
76200
|
+
configSource: bootstrapState2.configSource,
|
|
76201
|
+
configSourceType: bootstrapState2.configSourceType,
|
|
76202
|
+
lastCommand: bootstrapState2.lastCommand,
|
|
76203
|
+
exitCode: bootstrapState2.exitCode
|
|
76204
|
+
}
|
|
76205
|
+
}
|
|
76206
|
+
});
|
|
76207
|
+
} catch {
|
|
76208
|
+
}
|
|
76209
|
+
};
|
|
76210
|
+
const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
|
|
76211
|
+
const loadedBootstrap = loadMeshWorktreeBootstrapConfig(mesh, result.worktreePath);
|
|
76212
|
+
const runningBootstrapState = {
|
|
76213
|
+
status: "running",
|
|
76214
|
+
required: loadedBootstrap.config?.required !== false,
|
|
76215
|
+
configSource: loadedBootstrap.path || loadedBootstrap.source,
|
|
76216
|
+
configSourceType: loadedBootstrap.sourceType,
|
|
76217
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
76218
|
+
};
|
|
76219
|
+
await persistWorktreeSetupState(runningBootstrapState);
|
|
76220
|
+
const finishWorktreeSetup = async () => {
|
|
76221
|
+
let submodulesInitialized2 = false;
|
|
76222
|
+
if (initSubmodules) {
|
|
76223
|
+
try {
|
|
76224
|
+
const { runGit: runGit3 } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
|
|
76225
|
+
await runGit3(
|
|
76226
|
+
{ workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true },
|
|
76227
|
+
["submodule", "update", "--init", "--recursive"],
|
|
76228
|
+
{ timeoutMs: 12e4 }
|
|
76229
|
+
);
|
|
76230
|
+
submodulesInitialized2 = true;
|
|
76231
|
+
const sourceWorkspace = sourceNode.repoRoot || sourceNode.workspace;
|
|
76232
|
+
if (sourceWorkspace) {
|
|
76233
|
+
try {
|
|
76234
|
+
const { runGit: rg } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
|
|
76235
|
+
const sourceCtx = { workspace: sourceWorkspace, repoRoot: sourceWorkspace, isGitRepo: true };
|
|
76236
|
+
const worktreeCtx = { workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true };
|
|
76237
|
+
const sourceStatusOut = await rg(sourceCtx, ["submodule", "status", "oss"], { timeoutMs: 1e4 });
|
|
76238
|
+
const sourceStatusLine = (typeof sourceStatusOut === "string" ? sourceStatusOut : sourceStatusOut?.stdout ?? "").trim();
|
|
76239
|
+
const sourceShaMatch = sourceStatusLine.match(/^[+\- ]?([0-9a-f]{40})/);
|
|
76240
|
+
const sourceSha = sourceShaMatch?.[1];
|
|
76241
|
+
if (sourceSha) {
|
|
76242
|
+
const ossCtx = { workspace: `${result.worktreePath}/oss`, repoRoot: `${result.worktreePath}/oss`, isGitRepo: true };
|
|
76243
|
+
const worktreeOssHeadOut = await rg(ossCtx, ["rev-parse", "HEAD"], { timeoutMs: 1e4 });
|
|
76244
|
+
const worktreeOssSha = (typeof worktreeOssHeadOut === "string" ? worktreeOssHeadOut : worktreeOssHeadOut?.stdout ?? "").trim();
|
|
76245
|
+
if (worktreeOssSha !== sourceSha) {
|
|
76246
|
+
await rg(ossCtx, ["fetch", `${sourceWorkspace}/oss`, "HEAD"], { timeoutMs: 6e4 });
|
|
76247
|
+
await rg(ossCtx, ["checkout", sourceSha], { timeoutMs: 1e4 });
|
|
76248
|
+
await rg(worktreeCtx, ["add", "oss"], { timeoutMs: 1e4 });
|
|
76249
|
+
await rg(worktreeCtx, ["commit", "-m", "chore: sync oss to source node HEAD on clone"], { timeoutMs: 1e4 });
|
|
76250
|
+
console.log(`[mesh] Synced oss submodule to source HEAD ${sourceSha.slice(0, 8)} in worktree`);
|
|
76251
|
+
}
|
|
76252
|
+
}
|
|
76253
|
+
} catch (ossErr) {
|
|
76254
|
+
console.warn("[mesh] oss submodule sync to source HEAD failed (best-effort):", ossErr.message);
|
|
76255
|
+
}
|
|
76256
|
+
}
|
|
76257
|
+
} catch (subErr) {
|
|
76258
|
+
console.warn("[mesh] Submodule init failed for worktree:", subErr.message);
|
|
76259
|
+
}
|
|
76260
|
+
}
|
|
76261
|
+
const bootstrapState2 = await runMeshWorktreeBootstrap(mesh, result.worktreePath);
|
|
76262
|
+
await persistWorktreeSetupState(bootstrapState2);
|
|
76263
|
+
await appendCloneLedger(submodulesInitialized2, bootstrapState2);
|
|
76264
|
+
return { submodulesInitialized: submodulesInitialized2, bootstrapState: bootstrapState2 };
|
|
76265
|
+
};
|
|
76266
|
+
const requestedSetupWaitMs = Number(args?.setupWaitMs ?? args?.bootstrapWaitMs ?? 8e3);
|
|
76267
|
+
const setupWaitMs = Number.isFinite(requestedSetupWaitMs) ? Math.min(Math.max(requestedSetupWaitMs, 0), 14e3) : 8e3;
|
|
76268
|
+
const setupPromise = finishWorktreeSetup();
|
|
76269
|
+
const setupResult = await Promise.race([
|
|
76270
|
+
setupPromise.then((value) => ({ completed: true, value })),
|
|
76271
|
+
new Promise((resolve24) => setTimeout(() => resolve24({ completed: false }), setupWaitMs))
|
|
76272
|
+
]);
|
|
76273
|
+
const emitBootstrapEvent = (eventStatus2, bootstrapState2, startedAtMs, extraPayload) => {
|
|
76274
|
+
try {
|
|
76275
|
+
const durationMs = Date.now() - startedAtMs;
|
|
76276
|
+
const event = `worktree_${eventStatus2}`;
|
|
76277
|
+
const metadataEvent = {
|
|
76278
|
+
source: "clone_mesh_node_bootstrap",
|
|
76279
|
+
nodeId: node.id,
|
|
76280
|
+
status: eventStatus2,
|
|
76281
|
+
worktreePath: result.worktreePath,
|
|
76282
|
+
durationMs,
|
|
76283
|
+
bootstrapStatus: bootstrapState2.status,
|
|
76284
|
+
...bootstrapState2.error ? { error: bootstrapState2.error } : {},
|
|
76285
|
+
...bootstrapState2.exitCode !== void 0 ? { exitCode: bootstrapState2.exitCode } : {},
|
|
76286
|
+
...extraPayload || {}
|
|
76287
|
+
};
|
|
76288
|
+
if (typeof ctx.deps.instanceManager?.getByCategory === "function") {
|
|
76289
|
+
const forwarded = handleMeshForwardEvent(
|
|
76290
|
+
{ instanceManager: ctx.deps.instanceManager },
|
|
76291
|
+
{ event, meshId, nodeId: node.id, workspace: result.worktreePath, metadataEvent }
|
|
76292
|
+
);
|
|
76293
|
+
if (forwarded?.success === true) return;
|
|
76294
|
+
}
|
|
76295
|
+
queuePendingMeshCoordinatorEvent({
|
|
76296
|
+
event,
|
|
76297
|
+
meshId,
|
|
76298
|
+
nodeLabel: node.id,
|
|
76299
|
+
nodeId: node.id,
|
|
76300
|
+
workspace: result.worktreePath,
|
|
76301
|
+
metadataEvent,
|
|
76302
|
+
queuedAt: Date.now()
|
|
76303
|
+
});
|
|
76304
|
+
} catch {
|
|
76305
|
+
}
|
|
76306
|
+
};
|
|
76307
|
+
const bootstrapStartedMs = Date.now();
|
|
76308
|
+
if (!setupResult.completed) {
|
|
76309
|
+
setupPromise.then(({ bootstrapState: bootstrapState2 }) => {
|
|
76310
|
+
emitBootstrapEvent("bootstrap_complete", bootstrapState2, bootstrapStartedMs);
|
|
76311
|
+
}).catch((error48) => {
|
|
76312
|
+
const failedState = {
|
|
76313
|
+
...runningBootstrapState,
|
|
76314
|
+
status: "failed",
|
|
76315
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
76316
|
+
error: error48?.message || String(error48)
|
|
76317
|
+
};
|
|
76318
|
+
void persistWorktreeSetupState(failedState);
|
|
76319
|
+
void appendCloneLedger(false, failedState);
|
|
76320
|
+
emitBootstrapEvent("bootstrap_failed", failedState, bootstrapStartedMs, { error: error48?.message || String(error48) });
|
|
76321
|
+
});
|
|
76322
|
+
return {
|
|
76323
|
+
success: true,
|
|
76324
|
+
async: true,
|
|
76325
|
+
status: "accepted",
|
|
76326
|
+
node,
|
|
76327
|
+
worktreePath: result.worktreePath,
|
|
76328
|
+
branch: result.branch,
|
|
76329
|
+
worktreeBootstrap: runningBootstrapState,
|
|
76330
|
+
worktreeSetup: {
|
|
76331
|
+
status: "running",
|
|
76332
|
+
setupWaitMs,
|
|
76333
|
+
message: "Worktree node is registered; submodule/bootstrap setup is continuing in the background."
|
|
76334
|
+
}
|
|
76335
|
+
};
|
|
76336
|
+
}
|
|
76337
|
+
const { submodulesInitialized, bootstrapState } = setupResult.value;
|
|
76338
|
+
emitBootstrapEvent("bootstrap_complete", bootstrapState, bootstrapStartedMs);
|
|
76339
|
+
return {
|
|
76340
|
+
success: true,
|
|
76341
|
+
node,
|
|
76342
|
+
worktreePath: result.worktreePath,
|
|
76343
|
+
branch: result.branch,
|
|
76344
|
+
submodulesInitialized,
|
|
76345
|
+
worktreeBootstrap: bootstrapState
|
|
76346
|
+
};
|
|
76347
|
+
} catch (e) {
|
|
76348
|
+
return { success: false, error: e.message };
|
|
76349
|
+
}
|
|
76350
|
+
},
|
|
76351
|
+
retry_mesh_node_bootstrap: async (ctx, args) => {
|
|
76352
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76353
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
76354
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76355
|
+
if (!nodeId) return { success: false, error: "nodeId required" };
|
|
76356
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "bootstrap retry");
|
|
76357
|
+
if (ownerFailure) return ownerFailure;
|
|
76358
|
+
try {
|
|
76359
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76360
|
+
const mesh = meshRecord?.mesh;
|
|
76361
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
76362
|
+
const node = mesh.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
76363
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
76364
|
+
if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
|
|
76365
|
+
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
76366
|
+
if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, ctx.deps.statusInstanceId) && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
76367
|
+
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
|
|
76368
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
76369
|
+
_meshDirectDispatch: true
|
|
76370
|
+
});
|
|
76371
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
76372
|
+
}
|
|
76373
|
+
const currentBootstrap = node.worktreeBootstrap;
|
|
76374
|
+
if (currentBootstrap?.status === "running") {
|
|
76375
|
+
return { success: false, error: "Bootstrap is already running for this node" };
|
|
76376
|
+
}
|
|
76377
|
+
const worktreePath = node.workspace || node.repoRoot;
|
|
76378
|
+
if (!worktreePath) return { success: false, error: "Node has no workspace path" };
|
|
76379
|
+
const loadedBootstrap = loadMeshWorktreeBootstrapConfig(mesh, worktreePath);
|
|
76380
|
+
const runningState = {
|
|
76381
|
+
status: "running",
|
|
76382
|
+
required: loadedBootstrap.config?.required !== false,
|
|
76383
|
+
configSource: loadedBootstrap.path || loadedBootstrap.source,
|
|
76384
|
+
configSourceType: loadedBootstrap.sourceType,
|
|
76385
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
76386
|
+
};
|
|
76387
|
+
const persistState = async (bootstrapState2) => {
|
|
76388
|
+
node.worktreeBootstrap = bootstrapState2;
|
|
76389
|
+
if (meshRecord.inline) {
|
|
76390
|
+
ctx.updateInlineMeshNode(meshId, mesh, node);
|
|
76391
|
+
return;
|
|
76392
|
+
}
|
|
76393
|
+
try {
|
|
76394
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76395
|
+
updateNode2(meshId, node.id, { worktreeBootstrap: bootstrapState2 });
|
|
76396
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
76397
|
+
} catch {
|
|
76398
|
+
}
|
|
76399
|
+
};
|
|
76400
|
+
await persistState(runningState);
|
|
76401
|
+
const bootstrapState = await runMeshWorktreeBootstrap(mesh, worktreePath);
|
|
76402
|
+
await persistState(bootstrapState);
|
|
76403
|
+
return { success: true, bootstrapState };
|
|
76404
|
+
} catch (e) {
|
|
76405
|
+
return { success: false, error: e.message };
|
|
75540
76406
|
}
|
|
75541
|
-
} catch {
|
|
75542
76407
|
}
|
|
75543
|
-
}
|
|
75544
|
-
|
|
75545
|
-
|
|
75546
|
-
|
|
75547
|
-
|
|
75548
|
-
|
|
76408
|
+
};
|
|
76409
|
+
init_mesh_host_ownership();
|
|
76410
|
+
var meshHostPairingHandlers = {
|
|
76411
|
+
get_mesh_host_pairing: async (ctx, args) => {
|
|
76412
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76413
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76414
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76415
|
+
const mesh = meshRecord?.mesh;
|
|
76416
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
76417
|
+
const meshHost = resolveMeshHostStatus(mesh);
|
|
76418
|
+
const pairingStatus = meshHost.pairing?.status || "not_configured";
|
|
76419
|
+
return {
|
|
76420
|
+
success: true,
|
|
76421
|
+
code: pairingStatus === "not_configured" ? "mesh_host_pairing_not_configured" : "mesh_host_pairing_pending",
|
|
76422
|
+
meshId,
|
|
76423
|
+
hostAddress: meshHost.hostAddress,
|
|
76424
|
+
meshHost,
|
|
76425
|
+
manualPairing: {
|
|
76426
|
+
status: pairingStatus,
|
|
76427
|
+
joinImplemented: true,
|
|
76428
|
+
protocol: "standalone_command_direct_v1",
|
|
76429
|
+
description: "Standalone manual pairing can save address/token metadata, apply a host join over direct standalone command HTTP or injected mesh command dispatch, and check persisted status. P2P signaling remains outside this slice."
|
|
76430
|
+
}
|
|
76431
|
+
};
|
|
76432
|
+
},
|
|
76433
|
+
configure_mesh_host_pairing: async (ctx, args) => {
|
|
76434
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76435
|
+
const hostAddress = typeof args?.hostAddress === "string" ? args.hostAddress.trim() : "";
|
|
76436
|
+
const token = typeof args?.token === "string" ? args.token.trim() : "";
|
|
76437
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76438
|
+
if (!hostAddress || !token) return { success: false, error: "hostAddress and token required" };
|
|
76439
|
+
try {
|
|
76440
|
+
const { configureMeshHostPairing: configureMeshHostPairing2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76441
|
+
const configured = configureMeshHostPairing2(meshId, { hostAddress, token });
|
|
76442
|
+
if (!configured) return { success: false, error: "Mesh not found" };
|
|
76443
|
+
ctx.inlineMeshCache.set(meshId, configured.mesh);
|
|
76444
|
+
const meshHost = resolveMeshHostStatus(configured.mesh);
|
|
76445
|
+
return {
|
|
76446
|
+
success: true,
|
|
76447
|
+
code: "mesh_host_pairing_pending",
|
|
76448
|
+
meshId,
|
|
76449
|
+
hostAddress: configured.hostAddress,
|
|
76450
|
+
meshHost,
|
|
76451
|
+
manualPairing: {
|
|
76452
|
+
status: meshHost.pairing?.status || "pairing",
|
|
76453
|
+
joinImplemented: true,
|
|
76454
|
+
protocol: "standalone_command_direct_v1",
|
|
76455
|
+
description: "Manual Mesh Host pairing config was saved locally. Use join_mesh_host_pairing to apply it to the host. Raw token was not persisted."
|
|
76456
|
+
}
|
|
76457
|
+
};
|
|
76458
|
+
} catch (e) {
|
|
76459
|
+
return { success: false, code: "mesh_host_pairing_invalid", meshId, hostAddress, error: e.message };
|
|
76460
|
+
}
|
|
76461
|
+
},
|
|
76462
|
+
create_mesh_host_pairing_token: async (ctx, args) => {
|
|
76463
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76464
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76465
|
+
try {
|
|
76466
|
+
const { createMeshHostPairingToken: createMeshHostPairingToken2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76467
|
+
const created = createMeshHostPairingToken2(meshId, {
|
|
76468
|
+
token: typeof args?.token === "string" ? args.token : void 0,
|
|
76469
|
+
expiresAt: typeof args?.expiresAt === "string" ? args.expiresAt : void 0
|
|
76470
|
+
});
|
|
76471
|
+
if (!created) return { success: false, error: "Mesh not found" };
|
|
76472
|
+
ctx.inlineMeshCache.set(meshId, created.mesh);
|
|
76473
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
76474
|
+
return {
|
|
76475
|
+
success: true,
|
|
76476
|
+
code: "mesh_host_pairing_token_created",
|
|
76477
|
+
meshId,
|
|
76478
|
+
token: created.token,
|
|
76479
|
+
tokenId: created.tokenId,
|
|
76480
|
+
expiresAt: created.expiresAt,
|
|
76481
|
+
meshHost: resolveMeshHostStatus(created.mesh),
|
|
76482
|
+
warning: "Raw token is returned once and is not persisted; share it with member daemons over a trusted channel."
|
|
76483
|
+
};
|
|
76484
|
+
} catch (e) {
|
|
76485
|
+
return { success: false, code: "mesh_host_pairing_token_invalid", meshId, error: e.message };
|
|
76486
|
+
}
|
|
76487
|
+
},
|
|
76488
|
+
apply_mesh_host_join: async (ctx, args) => {
|
|
76489
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76490
|
+
const token = typeof args?.token === "string" ? args.token.trim() : "";
|
|
76491
|
+
const memberNode = args?.memberNode && typeof args.memberNode === "object" && !Array.isArray(args.memberNode) ? args.memberNode : null;
|
|
76492
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76493
|
+
if (!token || !memberNode) return { success: false, error: "token and memberNode required" };
|
|
76494
|
+
try {
|
|
76495
|
+
const { applyMeshHostJoinRequest: applyMeshHostJoinRequest2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76496
|
+
const applied = applyMeshHostJoinRequest2(meshId, {
|
|
76497
|
+
token,
|
|
76498
|
+
memberNode,
|
|
76499
|
+
memberMeshId: typeof args?.memberMeshId === "string" ? args.memberMeshId : void 0
|
|
76500
|
+
});
|
|
76501
|
+
if (!applied) return { success: false, error: "Mesh not found" };
|
|
76502
|
+
if (!applied.accepted) {
|
|
76503
|
+
return {
|
|
76504
|
+
success: false,
|
|
76505
|
+
code: "mesh_host_join_rejected",
|
|
76506
|
+
meshId,
|
|
76507
|
+
tokenId: applied.tokenId,
|
|
76508
|
+
meshHost: applied.meshHost ? resolveMeshHostStatus({ meshHost: applied.meshHost }) : void 0,
|
|
76509
|
+
error: applied.reason
|
|
76510
|
+
};
|
|
76511
|
+
}
|
|
76512
|
+
ctx.inlineMeshCache.set(meshId, applied.mesh);
|
|
76513
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
75549
76514
|
try {
|
|
75550
|
-
|
|
76515
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
76516
|
+
appendLedgerEntry2(meshId, {
|
|
76517
|
+
kind: "node_joined",
|
|
76518
|
+
nodeId: applied.node.id,
|
|
76519
|
+
payload: { role: "member", tokenId: applied.tokenId, workspace: applied.node.workspace }
|
|
76520
|
+
});
|
|
75551
76521
|
} catch {
|
|
75552
76522
|
}
|
|
75553
|
-
|
|
76523
|
+
return {
|
|
76524
|
+
success: true,
|
|
76525
|
+
code: "mesh_host_join_accepted",
|
|
76526
|
+
meshId,
|
|
76527
|
+
node: applied.node,
|
|
76528
|
+
tokenId: applied.tokenId,
|
|
76529
|
+
meshHost: resolveMeshHostStatus(applied.mesh)
|
|
76530
|
+
};
|
|
76531
|
+
} catch (e) {
|
|
76532
|
+
return { success: false, code: "mesh_host_join_failed", meshId, error: e.message };
|
|
75554
76533
|
}
|
|
75555
|
-
}
|
|
75556
|
-
|
|
75557
|
-
|
|
75558
|
-
|
|
75559
|
-
|
|
75560
|
-
|
|
75561
|
-
|
|
75562
|
-
|
|
75563
|
-
|
|
75564
|
-
|
|
75565
|
-
|
|
75566
|
-
|
|
75567
|
-
return !SKIP_COMMANDS.has(cmd);
|
|
75568
|
-
}
|
|
75569
|
-
function logCommand(entry) {
|
|
75570
|
-
if (!shouldLogCommand(entry.cmd)) return;
|
|
75571
|
-
try {
|
|
75572
|
-
if (++writeCount2 % 500 === 0) {
|
|
75573
|
-
checkRotation();
|
|
75574
|
-
checkSize();
|
|
76534
|
+
},
|
|
76535
|
+
join_mesh_host_pairing: async (ctx, args) => {
|
|
76536
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76537
|
+
const token = typeof args?.token === "string" ? args.token.trim() : "";
|
|
76538
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76539
|
+
if (!token) return { success: false, error: "token required because raw pairing tokens are not persisted" };
|
|
76540
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76541
|
+
const mesh = meshRecord?.mesh;
|
|
76542
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
76543
|
+
const meshHost = resolveMeshHostStatus(mesh);
|
|
76544
|
+
if (meshHost.role !== "member") {
|
|
76545
|
+
return { success: false, code: "mesh_host_join_not_member", meshId, meshHost, error: "join_mesh_host_pairing must run from a member daemon configured with a Mesh Host address/token." };
|
|
75575
76546
|
}
|
|
75576
|
-
|
|
75577
|
-
|
|
75578
|
-
|
|
75579
|
-
|
|
75580
|
-
|
|
75581
|
-
|
|
75582
|
-
|
|
75583
|
-
|
|
75584
|
-
|
|
75585
|
-
|
|
75586
|
-
|
|
75587
|
-
|
|
75588
|
-
|
|
75589
|
-
|
|
75590
|
-
|
|
75591
|
-
|
|
75592
|
-
|
|
75593
|
-
|
|
75594
|
-
|
|
75595
|
-
|
|
75596
|
-
|
|
75597
|
-
|
|
76547
|
+
try {
|
|
76548
|
+
const { tokenIdForManualPairing: tokenIdForManualPairing2, markMeshHostPairingJoined: markMeshHostPairingJoined2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
76549
|
+
const tokenId = tokenIdForManualPairing2(token);
|
|
76550
|
+
if (meshHost.pairing?.tokenId && meshHost.pairing.tokenId !== tokenId) {
|
|
76551
|
+
return { success: false, code: "mesh_host_join_rejected", meshId, tokenId, meshHost, error: "invalid pairing token" };
|
|
76552
|
+
}
|
|
76553
|
+
const memberNode = buildMemberJoinNode(mesh, args, ctx.deps.statusInstanceId);
|
|
76554
|
+
if (!memberNode) return { success: false, error: "member node metadata unavailable" };
|
|
76555
|
+
const hostMeshId = typeof args?.hostMeshId === "string" && args.hostMeshId.trim() ? args.hostMeshId.trim() : meshId;
|
|
76556
|
+
const hostDaemonId = typeof args?.hostDaemonId === "string" && args.hostDaemonId.trim() ? args.hostDaemonId.trim() : meshHost.hostDaemonId;
|
|
76557
|
+
let hostResult;
|
|
76558
|
+
let transport;
|
|
76559
|
+
if (hostDaemonId && ctx.deps.dispatchMeshCommand) {
|
|
76560
|
+
transport = "mesh_command_dispatch";
|
|
76561
|
+
hostResult = await ctx.deps.dispatchMeshCommand(hostDaemonId, "apply_mesh_host_join", {
|
|
76562
|
+
meshId: hostMeshId,
|
|
76563
|
+
token,
|
|
76564
|
+
memberMeshId: meshId,
|
|
76565
|
+
memberNode
|
|
76566
|
+
});
|
|
76567
|
+
} else if (meshHost.hostAddress) {
|
|
76568
|
+
transport = "standalone_http_command";
|
|
76569
|
+
const commandUrl = normalizeStandaloneHostCommandUrl(meshHost.hostAddress);
|
|
76570
|
+
const response = await fetch(commandUrl, {
|
|
76571
|
+
method: "POST",
|
|
76572
|
+
headers: { "Content-Type": "application/json" },
|
|
76573
|
+
body: JSON.stringify({ type: "apply_mesh_host_join", payload: { meshId: hostMeshId, token, memberMeshId: meshId, memberNode } })
|
|
76574
|
+
});
|
|
76575
|
+
hostResult = await response.json().catch(() => ({ success: false, error: `Host returned HTTP ${response.status}` }));
|
|
76576
|
+
if (!response.ok && hostResult?.success !== false) hostResult = { success: false, error: `Host returned HTTP ${response.status}` };
|
|
76577
|
+
} else {
|
|
75598
76578
|
return {
|
|
75599
|
-
|
|
75600
|
-
|
|
75601
|
-
|
|
75602
|
-
|
|
75603
|
-
|
|
75604
|
-
success: parsed.ok,
|
|
75605
|
-
error: parsed.err,
|
|
75606
|
-
durationMs: parsed.ms
|
|
76579
|
+
success: false,
|
|
76580
|
+
code: "mesh_host_join_transport_unavailable",
|
|
76581
|
+
meshId,
|
|
76582
|
+
meshHost,
|
|
76583
|
+
error: "No hostDaemonId dispatch path or hostAddress HTTP command path is available. P2P signaling join is not implemented in this slice."
|
|
75607
76584
|
};
|
|
75608
|
-
} catch {
|
|
75609
|
-
return { ts: "", cmd: "parse_error", source: "unknown" };
|
|
75610
76585
|
}
|
|
75611
|
-
|
|
75612
|
-
|
|
75613
|
-
|
|
76586
|
+
if (!hostResult?.success) {
|
|
76587
|
+
return { success: false, code: hostResult?.code || "mesh_host_join_rejected", meshId, meshHost, transport, error: hostResult?.error || "Mesh Host rejected join request", hostResult };
|
|
76588
|
+
}
|
|
76589
|
+
const joined = meshRecord.inline ? null : markMeshHostPairingJoined2(meshId, {
|
|
76590
|
+
tokenId: hostResult.tokenId || tokenId,
|
|
76591
|
+
hostDaemonId: hostResult.meshHost?.hostDaemonId || hostDaemonId,
|
|
76592
|
+
hostNodeId: hostResult.meshHost?.hostNodeId,
|
|
76593
|
+
joinedAt: hostResult.meshHost?.pairing?.joinedAt
|
|
76594
|
+
});
|
|
76595
|
+
if (joined) {
|
|
76596
|
+
ctx.inlineMeshCache.set(meshId, joined.mesh);
|
|
76597
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
76598
|
+
}
|
|
76599
|
+
return {
|
|
76600
|
+
success: true,
|
|
76601
|
+
code: "mesh_host_join_applied",
|
|
76602
|
+
meshId,
|
|
76603
|
+
hostMeshId,
|
|
76604
|
+
transport,
|
|
76605
|
+
node: hostResult.node,
|
|
76606
|
+
tokenId: hostResult.tokenId || tokenId,
|
|
76607
|
+
meshHost: joined ? resolveMeshHostStatus(joined.mesh) : { ...meshHost, pairing: { ...meshHost.pairing || {}, status: "paired", tokenId: hostResult.tokenId || tokenId } },
|
|
76608
|
+
hostResult,
|
|
76609
|
+
manualPairing: {
|
|
76610
|
+
status: "paired",
|
|
76611
|
+
joinImplemented: true,
|
|
76612
|
+
protocol: "standalone_command_direct_v1",
|
|
76613
|
+
description: "Mesh Host accepted the join and local member pairing status was marked paired. P2P runtime signaling remains outside this slice."
|
|
76614
|
+
}
|
|
76615
|
+
};
|
|
76616
|
+
} catch (e) {
|
|
76617
|
+
return { success: false, code: "mesh_host_join_failed", meshId, meshHost, error: e.message };
|
|
76618
|
+
}
|
|
75614
76619
|
}
|
|
75615
|
-
}
|
|
75616
|
-
|
|
75617
|
-
|
|
75618
|
-
|
|
75619
|
-
|
|
75620
|
-
init_mesh_events();
|
|
75621
|
-
init_mesh_routing();
|
|
75622
|
-
init_mesh_events_utils();
|
|
75623
|
-
init_mesh_host_ownership();
|
|
75624
|
-
init_mesh_fast_forward();
|
|
75625
|
-
var import_node_child_process4 = require("child_process");
|
|
75626
|
-
var import_node_util4 = require("util");
|
|
75627
|
-
var execFileAsync3 = (0, import_node_util4.promisify)(import_node_child_process4.execFile);
|
|
75628
|
-
var MAX_CHANGED_FILES2 = 500;
|
|
75629
|
-
function topLevel(path422) {
|
|
75630
|
-
const slash = path422.indexOf("/");
|
|
75631
|
-
return slash === -1 ? path422 : path422.slice(0, slash);
|
|
75632
|
-
}
|
|
75633
|
-
async function analyzeMeshRefineNodeChangeArea(args) {
|
|
75634
|
-
const { nodeId, workspace, branch, baseRef, branchRef, diffCwd, submodulePaths } = args;
|
|
75635
|
-
const base = {
|
|
75636
|
-
nodeId,
|
|
75637
|
-
workspace,
|
|
75638
|
-
branch,
|
|
75639
|
-
changedTopLevelPaths: [],
|
|
75640
|
-
changedFiles: [],
|
|
75641
|
-
touchedSubmodulePaths: [],
|
|
75642
|
-
touchesSubmodule: false,
|
|
75643
|
-
aheadCount: 0
|
|
75644
|
-
};
|
|
75645
|
-
try {
|
|
75646
|
-
let mergeBase = baseRef;
|
|
76620
|
+
};
|
|
76621
|
+
var meshQueueHandlers = {
|
|
76622
|
+
get_mesh_queue: async (_ctx, args) => {
|
|
76623
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76624
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
75647
76625
|
try {
|
|
75648
|
-
const {
|
|
75649
|
-
const
|
|
75650
|
-
|
|
75651
|
-
|
|
76626
|
+
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
76627
|
+
const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
|
|
76628
|
+
const rawQueue = getQueue2(meshId, { status });
|
|
76629
|
+
const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
|
|
76630
|
+
const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
|
|
76631
|
+
const summary = getMeshQueueStats2(meshId);
|
|
76632
|
+
return {
|
|
76633
|
+
success: true,
|
|
76634
|
+
queue,
|
|
76635
|
+
summary,
|
|
76636
|
+
sourceOfTruth: {
|
|
76637
|
+
kind: "mesh_work_queue_file",
|
|
76638
|
+
activeStatuses: ["pending", "assigned"],
|
|
76639
|
+
historicalStatuses: ["completed", "failed", "cancelled"],
|
|
76640
|
+
notes: "pending/assigned are active work; completed/failed/cancelled are historical records."
|
|
76641
|
+
}
|
|
76642
|
+
};
|
|
76643
|
+
} catch (e) {
|
|
76644
|
+
return { success: false, error: e.message };
|
|
75652
76645
|
}
|
|
75653
|
-
|
|
75654
|
-
|
|
75655
|
-
|
|
75656
|
-
|
|
75657
|
-
);
|
|
75658
|
-
|
|
75659
|
-
|
|
75660
|
-
|
|
75661
|
-
|
|
75662
|
-
|
|
75663
|
-
|
|
75664
|
-
|
|
75665
|
-
|
|
75666
|
-
|
|
75667
|
-
|
|
75668
|
-
|
|
75669
|
-
|
|
75670
|
-
|
|
75671
|
-
|
|
75672
|
-
|
|
76646
|
+
},
|
|
76647
|
+
cancel_mesh_queue_task: async (ctx, args) => {
|
|
76648
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76649
|
+
const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
|
|
76650
|
+
if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
|
|
76651
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue cancellation");
|
|
76652
|
+
if (ownerFailure) return ownerFailure;
|
|
76653
|
+
try {
|
|
76654
|
+
const { cancelTask: cancelTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
76655
|
+
const reason = typeof args?.reason === "string" ? args.reason : void 0;
|
|
76656
|
+
const task = cancelTask2(meshId, taskId, { reason });
|
|
76657
|
+
if (!task) return { success: false, error: `Queue task '${taskId}' not found` };
|
|
76658
|
+
return { success: true, task };
|
|
76659
|
+
} catch (e) {
|
|
76660
|
+
return { success: false, error: e.message };
|
|
76661
|
+
}
|
|
76662
|
+
},
|
|
76663
|
+
requeue_mesh_queue_task: async (ctx, args) => {
|
|
76664
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76665
|
+
const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
|
|
76666
|
+
if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
|
|
76667
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue requeue");
|
|
76668
|
+
if (ownerFailure) return ownerFailure;
|
|
76669
|
+
try {
|
|
76670
|
+
const { requeueTask: requeueTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
76671
|
+
const task = requeueTask2(meshId, taskId, {
|
|
76672
|
+
reason: typeof args?.reason === "string" ? args.reason : void 0,
|
|
76673
|
+
targetNodeId: typeof args?.targetNodeId === "string" ? args.targetNodeId.trim() : void 0,
|
|
76674
|
+
targetSessionId: typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : void 0,
|
|
76675
|
+
clearTargetNode: args?.clearTargetNode === true,
|
|
76676
|
+
clearTargetSession: args?.clearTargetSession !== false
|
|
76677
|
+
});
|
|
76678
|
+
if (!task) return { success: false, error: `Queue task '${taskId}' not found` };
|
|
76679
|
+
return { success: true, task };
|
|
76680
|
+
} catch (e) {
|
|
76681
|
+
return { success: false, error: e.message };
|
|
76682
|
+
}
|
|
76683
|
+
},
|
|
76684
|
+
trigger_mesh_queue: async (ctx, args) => {
|
|
76685
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76686
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76687
|
+
const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue trigger");
|
|
76688
|
+
if (ownerFailure) return ownerFailure;
|
|
76689
|
+
try {
|
|
76690
|
+
const { triggerMeshQueue: triggerMeshQueue2, tryAssignQueueTask: tryAssignQueueTask2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
|
|
76691
|
+
const preferredNodeId = typeof args?.preferredNodeId === "string" ? args.preferredNodeId.trim() : "";
|
|
76692
|
+
if (preferredNodeId) {
|
|
76693
|
+
const cliInstances = ctx.deps.instanceManager.getByCategory("cli");
|
|
76694
|
+
const sorted = [...cliInstances].sort((a, b) => {
|
|
76695
|
+
const aSettings = a.getState().settings || {};
|
|
76696
|
+
const bSettings = b.getState().settings || {};
|
|
76697
|
+
const aNode = readStringValue(aSettings.meshNodeId, aSettings.nodeId);
|
|
76698
|
+
const bNode = readStringValue(bSettings.meshNodeId, bSettings.nodeId);
|
|
76699
|
+
return (aNode === preferredNodeId ? -1 : 0) - (bNode === preferredNodeId ? -1 : 0);
|
|
76700
|
+
});
|
|
76701
|
+
for (const inst of sorted) {
|
|
76702
|
+
const state = inst.getState();
|
|
76703
|
+
const settings = state.settings || {};
|
|
76704
|
+
const nodeId = readStringValue(settings.meshNodeId, settings.nodeId);
|
|
76705
|
+
if (!nodeId || nodeId !== preferredNodeId) continue;
|
|
76706
|
+
const meshNodeFor = readStringValue(settings.meshNodeFor);
|
|
76707
|
+
if (meshNodeFor !== meshId) continue;
|
|
76708
|
+
const status = (readStringValue(state.status) || "").toLowerCase();
|
|
76709
|
+
if (status !== "idle") continue;
|
|
76710
|
+
const sessionId = typeof state.instanceId === "string" ? state.instanceId : "";
|
|
76711
|
+
const providerType = readStringValue(state.type, settings.providerType) || "";
|
|
76712
|
+
if (sessionId && providerType) {
|
|
76713
|
+
tryAssignQueueTask2(ctx.deps, meshId, nodeId, sessionId, providerType);
|
|
76714
|
+
break;
|
|
76715
|
+
}
|
|
76716
|
+
}
|
|
75673
76717
|
}
|
|
76718
|
+
const trigger = await triggerMeshQueue2(ctx.deps, meshId);
|
|
76719
|
+
return { success: true, trigger };
|
|
76720
|
+
} catch (e) {
|
|
76721
|
+
return { success: false, error: e.message };
|
|
75674
76722
|
}
|
|
75675
|
-
base.changedTopLevelPaths = [...topSet].sort();
|
|
75676
|
-
base.touchedSubmodulePaths = [...submoduleSet].sort();
|
|
75677
|
-
base.touchesSubmodule = submoduleSet.size > 0;
|
|
75678
|
-
return base;
|
|
75679
|
-
} catch (e) {
|
|
75680
|
-
base.error = e?.message || String(e);
|
|
75681
|
-
return base;
|
|
75682
|
-
}
|
|
75683
|
-
}
|
|
75684
|
-
function orderMeshRefineBatchNodes(changeAreas) {
|
|
75685
|
-
const areaById = {};
|
|
75686
|
-
for (const area of changeAreas) areaById[area.nodeId] = area;
|
|
75687
|
-
const ranked = [...changeAreas].sort((a, b) => {
|
|
75688
|
-
const aSub = a.touchesSubmodule ? 1 : 0;
|
|
75689
|
-
const bSub = b.touchesSubmodule ? 1 : 0;
|
|
75690
|
-
if (aSub !== bSub) return aSub - bSub;
|
|
75691
|
-
const aBreadth = a.changedTopLevelPaths.length;
|
|
75692
|
-
const bBreadth = b.changedTopLevelPaths.length;
|
|
75693
|
-
if (aBreadth !== bBreadth) return aBreadth - bBreadth;
|
|
75694
|
-
return a.nodeId.localeCompare(b.nodeId);
|
|
75695
|
-
});
|
|
75696
|
-
const rationale = [];
|
|
75697
|
-
const nonSub = ranked.filter((a) => !a.touchesSubmodule).map((a) => a.nodeId);
|
|
75698
|
-
const sub = ranked.filter((a) => a.touchesSubmodule).map((a) => a.nodeId);
|
|
75699
|
-
if (nonSub.length) {
|
|
75700
|
-
rationale.push(`Non-submodule nodes first (no submodule-main advance, conflict-free ordering): ${nonSub.join(", ")}`);
|
|
75701
|
-
}
|
|
75702
|
-
if (sub.length) {
|
|
75703
|
-
rationale.push(`Submodule-touching nodes last, serialized (each merge advances submodule main, forcing rebase of the next): ${sub.join(", ")}`);
|
|
75704
|
-
}
|
|
75705
|
-
for (const area of ranked) {
|
|
75706
|
-
if (area.error) rationale.push(`Node ${area.nodeId}: change-area analysis degraded (${area.error}); placed with neutral priority.`);
|
|
75707
|
-
}
|
|
75708
|
-
return { order: ranked.map((a) => a.nodeId), changeAreas: areaById, rationale };
|
|
75709
|
-
}
|
|
75710
|
-
var import_node_child_process5 = require("child_process");
|
|
75711
|
-
var import_node_fs4 = require("fs");
|
|
75712
|
-
var import_node_path2 = require("path");
|
|
75713
|
-
var PREVIEW_DEPLOY_RECORD = ".adhdev/preview-deploy.json";
|
|
75714
|
-
function runGit2(repoRoot, args) {
|
|
75715
|
-
try {
|
|
75716
|
-
return (0, import_node_child_process5.execFileSync)("git", args, {
|
|
75717
|
-
cwd: repoRoot,
|
|
75718
|
-
encoding: "utf8",
|
|
75719
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
75720
|
-
timeout: 5e3
|
|
75721
|
-
}).trim();
|
|
75722
|
-
} catch {
|
|
75723
|
-
return "";
|
|
75724
|
-
}
|
|
75725
|
-
}
|
|
75726
|
-
function readRecord5(repoRoot) {
|
|
75727
|
-
const path422 = (0, import_node_path2.resolve)(repoRoot, PREVIEW_DEPLOY_RECORD);
|
|
75728
|
-
if (!(0, import_node_fs4.existsSync)(path422)) return null;
|
|
75729
|
-
try {
|
|
75730
|
-
const parsed = JSON.parse((0, import_node_fs4.readFileSync)(path422, "utf8"));
|
|
75731
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
75732
|
-
} catch {
|
|
75733
|
-
return null;
|
|
75734
|
-
}
|
|
75735
|
-
}
|
|
75736
|
-
function normalizeCommit(value) {
|
|
75737
|
-
return typeof value === "string" && /^[0-9a-f]{7,40}$/i.test(value.trim()) ? value.trim() : null;
|
|
75738
|
-
}
|
|
75739
|
-
function readTargetFreshness(record2, currentCommit) {
|
|
75740
|
-
const targets = record2?.targets && typeof record2.targets === "object" && !Array.isArray(record2.targets) ? record2.targets : {};
|
|
75741
|
-
const result = {};
|
|
75742
|
-
for (const targetName of ["npm", "server", "web"]) {
|
|
75743
|
-
const targetRecord = targets[targetName] && typeof targets[targetName] === "object" && !Array.isArray(targets[targetName]) ? targets[targetName] : {};
|
|
75744
|
-
const commit = normalizeCommit(targetRecord.commit);
|
|
75745
|
-
result[targetName] = {
|
|
75746
|
-
commit,
|
|
75747
|
-
deployedAt: typeof targetRecord.deployedAt === "string" ? targetRecord.deployedAt : void 0,
|
|
75748
|
-
status: commit && currentCommit ? commit === currentCommit ? "fresh" : "stale" : "unknown"
|
|
75749
|
-
};
|
|
75750
|
-
}
|
|
75751
|
-
return result;
|
|
75752
|
-
}
|
|
75753
|
-
function readCurrentMainCommit(repoRoot) {
|
|
75754
|
-
const originMain = runGit2(repoRoot, ["rev-parse", "--verify", "origin/main^{commit}"]);
|
|
75755
|
-
if (originMain) {
|
|
75756
|
-
return { currentMainCommit: originMain, currentMainCommitSource: "origin/main" };
|
|
75757
|
-
}
|
|
75758
|
-
const head = runGit2(repoRoot, ["rev-parse", "--verify", "HEAD"]);
|
|
75759
|
-
if (head) {
|
|
75760
|
-
return { currentMainCommit: head, currentMainCommitSource: "HEAD" };
|
|
75761
76723
|
}
|
|
75762
|
-
|
|
75763
|
-
|
|
75764
|
-
|
|
75765
|
-
const current = readCurrentMainCommit(repoRoot);
|
|
75766
|
-
const record2 = readRecord5(repoRoot);
|
|
75767
|
-
const lastPreviewCommit = normalizeCommit(record2?.lastPreviewCommit);
|
|
75768
|
-
const targets = readTargetFreshness(record2, current.currentMainCommit);
|
|
75769
|
-
let status = "unknown";
|
|
75770
|
-
let nextAction = "Run npm run deploy:preview from the current main commit, then smoke preview.";
|
|
75771
|
-
if (lastPreviewCommit && current.currentMainCommit) {
|
|
75772
|
-
status = lastPreviewCommit === current.currentMainCommit ? "fresh" : "stale";
|
|
75773
|
-
nextAction = status === "fresh" ? "No preview deploy action needed." : "Run npm run deploy:preview from origin/main, then smoke preview.";
|
|
75774
|
-
} else if (!current.currentMainCommit) {
|
|
75775
|
-
nextAction = "Resolve the current main commit before judging preview freshness.";
|
|
75776
|
-
}
|
|
75777
|
-
return {
|
|
75778
|
-
status,
|
|
75779
|
-
lastPreviewCommit,
|
|
75780
|
-
currentMainCommit: current.currentMainCommit,
|
|
75781
|
-
currentMainCommitSource: current.currentMainCommitSource,
|
|
75782
|
-
recordPath: PREVIEW_DEPLOY_RECORD,
|
|
75783
|
-
lastDeployedAt: typeof record2?.updatedAt === "string" ? record2.updatedAt : void 0,
|
|
75784
|
-
lastTarget: typeof record2?.target === "string" ? record2.target : void 0,
|
|
75785
|
-
previewVersion: typeof record2?.previewVersion === "string" ? record2.previewVersion : void 0,
|
|
75786
|
-
targets,
|
|
75787
|
-
nextAction
|
|
75788
|
-
};
|
|
75789
|
-
}
|
|
75790
|
-
init_mesh_refine_status();
|
|
76724
|
+
};
|
|
76725
|
+
init_dist();
|
|
76726
|
+
init_mesh_fast_forward();
|
|
75791
76727
|
var import_fs16 = require("fs");
|
|
75792
76728
|
var import_path11 = require("path");
|
|
75793
76729
|
var MESH_INIT_REFINE_CONFIG_PATH = MESH_REFINE_CONFIG_LOCATIONS[0];
|
|
@@ -75899,6 +76835,462 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
75899
76835
|
const writtenPath = writeConfigFile(workspace, relativePath, suggestedConfig);
|
|
75900
76836
|
return { path: writtenPath, relativePath, written: true, config: suggestedConfig };
|
|
75901
76837
|
}
|
|
76838
|
+
init_cli_detector();
|
|
76839
|
+
var fastForwardHandlers = {
|
|
76840
|
+
mesh_init: async (ctx, args) => {
|
|
76841
|
+
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
76842
|
+
const mesh = args?.inlineMesh || {};
|
|
76843
|
+
try {
|
|
76844
|
+
const detected = await detectCLIs(ctx.deps.providerLoader, { includeVersion: true });
|
|
76845
|
+
return { ...runMeshInit(mesh, workspace, detected, {
|
|
76846
|
+
write: args?.write === true,
|
|
76847
|
+
overwrite: args?.overwrite === true
|
|
76848
|
+
}) };
|
|
76849
|
+
} catch (e) {
|
|
76850
|
+
return { success: false, error: e?.message || String(e) };
|
|
76851
|
+
}
|
|
76852
|
+
},
|
|
76853
|
+
plan_mesh_refine_node: async (ctx, args) => {
|
|
76854
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76855
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
76856
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
76857
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76858
|
+
const mesh = meshRecord?.mesh;
|
|
76859
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
76860
|
+
if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
|
|
76861
|
+
return {
|
|
76862
|
+
success: true,
|
|
76863
|
+
dryRun: true,
|
|
76864
|
+
nodeId,
|
|
76865
|
+
workspace: node.workspace,
|
|
76866
|
+
validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
|
|
76867
|
+
mergeWillRun: false,
|
|
76868
|
+
cleanupWillRun: false
|
|
76869
|
+
};
|
|
76870
|
+
},
|
|
76871
|
+
fast_forward_mesh_node: async (ctx, args) => {
|
|
76872
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76873
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
76874
|
+
let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
76875
|
+
let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
76876
|
+
let nodeDaemonId;
|
|
76877
|
+
let allowAutoPublishSubmoduleMainCommits = false;
|
|
76878
|
+
if (meshId && nodeId) {
|
|
76879
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76880
|
+
const mesh = meshRecord?.mesh;
|
|
76881
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
76882
|
+
if (!workspace) {
|
|
76883
|
+
workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
|
|
76884
|
+
}
|
|
76885
|
+
if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
|
|
76886
|
+
submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
|
|
76887
|
+
}
|
|
76888
|
+
allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
|
|
76889
|
+
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
76890
|
+
}
|
|
76891
|
+
const selfDaemonId = ctx.deps.statusInstanceId;
|
|
76892
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
76893
|
+
if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
76894
|
+
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
76895
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
76896
|
+
workspace,
|
|
76897
|
+
_meshDirectDispatch: true
|
|
76898
|
+
});
|
|
76899
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
76900
|
+
}
|
|
76901
|
+
const result = await fastForwardMeshNode({
|
|
76902
|
+
meshId: meshId || void 0,
|
|
76903
|
+
nodeId: nodeId || void 0,
|
|
76904
|
+
workspace,
|
|
76905
|
+
branch: typeof args?.branch === "string" ? args.branch : void 0,
|
|
76906
|
+
execute: args?.execute === true,
|
|
76907
|
+
dryRun: args?.dryRun === true,
|
|
76908
|
+
updateSubmodules: args?.updateSubmodules === true,
|
|
76909
|
+
submoduleIgnorePaths,
|
|
76910
|
+
mode: args?.mode === "push" ? "push" : "merge",
|
|
76911
|
+
pushSubmodules: args?.pushSubmodules === true,
|
|
76912
|
+
allowAutoPublishSubmoduleMainCommits
|
|
76913
|
+
});
|
|
76914
|
+
return result;
|
|
76915
|
+
},
|
|
76916
|
+
refine_mesh_node: async (ctx, args) => {
|
|
76917
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76918
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
76919
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
76920
|
+
{
|
|
76921
|
+
const meshRecordForForward = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76922
|
+
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
76923
|
+
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
76924
|
+
const selfDaemonId = ctx.deps.statusInstanceId;
|
|
76925
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
76926
|
+
if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
76927
|
+
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
76928
|
+
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
76929
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
76930
|
+
coordinatorDaemonId: callerCoordinatorDaemonId || selfDaemonId,
|
|
76931
|
+
_meshDirectDispatch: true
|
|
76932
|
+
});
|
|
76933
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
76934
|
+
}
|
|
76935
|
+
}
|
|
76936
|
+
const isDryRun = args?.dryRun !== false && args?.execute !== true;
|
|
76937
|
+
if (isDryRun) {
|
|
76938
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
76939
|
+
const mesh = meshRecord?.mesh;
|
|
76940
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
76941
|
+
if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
|
|
76942
|
+
return {
|
|
76943
|
+
success: true,
|
|
76944
|
+
dryRun: true,
|
|
76945
|
+
nodeId,
|
|
76946
|
+
workspace: node.workspace,
|
|
76947
|
+
validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
|
|
76948
|
+
mergeWillRun: false,
|
|
76949
|
+
cleanupWillRun: false,
|
|
76950
|
+
hint: "Dry-run only \u2014 no merge/push/cleanup performed. Re-invoke with execute:true to converge this node."
|
|
76951
|
+
};
|
|
76952
|
+
}
|
|
76953
|
+
return ctx.startMeshRefineJob(meshId, nodeId, args);
|
|
76954
|
+
},
|
|
76955
|
+
batch_refine_mesh_nodes: async (ctx, args) => {
|
|
76956
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76957
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
76958
|
+
const requestedNodeIds = Array.isArray(args?.nodeIds) ? args.nodeIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
|
|
76959
|
+
const isDryRun = args?.dryRun !== false && args?.execute !== true;
|
|
76960
|
+
if (isDryRun) return ctx.batchRefineMeshNodes(meshId, requestedNodeIds, args);
|
|
76961
|
+
return ctx.startMeshRefineBatchJob(meshId, requestedNodeIds, args);
|
|
76962
|
+
}
|
|
76963
|
+
};
|
|
76964
|
+
var medFamilyRegistry = new Map(
|
|
76965
|
+
Object.entries({
|
|
76966
|
+
...cliAgentHandlers,
|
|
76967
|
+
...ideHandlers,
|
|
76968
|
+
...meshCrudHandlers,
|
|
76969
|
+
...meshHostPairingHandlers,
|
|
76970
|
+
...meshQueueHandlers,
|
|
76971
|
+
...fastForwardHandlers
|
|
76972
|
+
})
|
|
76973
|
+
);
|
|
76974
|
+
init_config();
|
|
76975
|
+
init_cli_detector();
|
|
76976
|
+
init_git_status();
|
|
76977
|
+
init_dist();
|
|
76978
|
+
init_logger();
|
|
76979
|
+
var fs26 = __toESM2(require("fs"));
|
|
76980
|
+
var path36 = __toESM2(require("path"));
|
|
76981
|
+
var os27 = __toESM2(require("os"));
|
|
76982
|
+
var ADHDEV_HOME2 = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path36.join(os27.homedir(), ".adhdev");
|
|
76983
|
+
var LOG_DIR2 = path36.join(ADHDEV_HOME2, "logs");
|
|
76984
|
+
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
76985
|
+
var MAX_DAYS = 7;
|
|
76986
|
+
try {
|
|
76987
|
+
fs26.mkdirSync(LOG_DIR2, { recursive: true });
|
|
76988
|
+
} catch {
|
|
76989
|
+
}
|
|
76990
|
+
var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
76991
|
+
"token",
|
|
76992
|
+
"password",
|
|
76993
|
+
"secret",
|
|
76994
|
+
"apiKey",
|
|
76995
|
+
"api_key",
|
|
76996
|
+
"connectionToken",
|
|
76997
|
+
"content",
|
|
76998
|
+
"message",
|
|
76999
|
+
"text"
|
|
77000
|
+
]);
|
|
77001
|
+
function maskArgs(args) {
|
|
77002
|
+
if (!args || typeof args !== "object") return void 0;
|
|
77003
|
+
const masked = {};
|
|
77004
|
+
for (const [key, value] of Object.entries(args)) {
|
|
77005
|
+
if (SENSITIVE_KEYS.has(key)) {
|
|
77006
|
+
masked[key] = typeof value === "string" ? `[${value.length} chars]` : "[masked]";
|
|
77007
|
+
} else if (key.startsWith("_")) {
|
|
77008
|
+
masked[key] = value;
|
|
77009
|
+
} else if (typeof value === "object" && value !== null) {
|
|
77010
|
+
masked[key] = Array.isArray(value) ? `[Array(${value.length})]` : `[Object]`;
|
|
77011
|
+
} else {
|
|
77012
|
+
masked[key] = value;
|
|
77013
|
+
}
|
|
77014
|
+
}
|
|
77015
|
+
return masked;
|
|
77016
|
+
}
|
|
77017
|
+
function getDateStr2() {
|
|
77018
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
77019
|
+
}
|
|
77020
|
+
var currentDate2 = getDateStr2();
|
|
77021
|
+
var currentFile = path36.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
77022
|
+
var writeCount2 = 0;
|
|
77023
|
+
function checkRotation() {
|
|
77024
|
+
const today = getDateStr2();
|
|
77025
|
+
if (today !== currentDate2) {
|
|
77026
|
+
currentDate2 = today;
|
|
77027
|
+
currentFile = path36.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
77028
|
+
cleanOldFiles();
|
|
77029
|
+
}
|
|
77030
|
+
}
|
|
77031
|
+
function cleanOldFiles() {
|
|
77032
|
+
try {
|
|
77033
|
+
const files = fs26.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
|
|
77034
|
+
const cutoff = /* @__PURE__ */ new Date();
|
|
77035
|
+
cutoff.setDate(cutoff.getDate() - MAX_DAYS);
|
|
77036
|
+
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
77037
|
+
for (const file2 of files) {
|
|
77038
|
+
const dateMatch = file2.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
77039
|
+
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
77040
|
+
try {
|
|
77041
|
+
fs26.unlinkSync(path36.join(LOG_DIR2, file2));
|
|
77042
|
+
} catch {
|
|
77043
|
+
}
|
|
77044
|
+
}
|
|
77045
|
+
}
|
|
77046
|
+
} catch {
|
|
77047
|
+
}
|
|
77048
|
+
}
|
|
77049
|
+
function checkSize() {
|
|
77050
|
+
try {
|
|
77051
|
+
const stat2 = fs26.statSync(currentFile);
|
|
77052
|
+
if (stat2.size > MAX_FILE_SIZE) {
|
|
77053
|
+
const backup = currentFile.replace(".jsonl", ".1.jsonl");
|
|
77054
|
+
try {
|
|
77055
|
+
fs26.unlinkSync(backup);
|
|
77056
|
+
} catch {
|
|
77057
|
+
}
|
|
77058
|
+
fs26.renameSync(currentFile, backup);
|
|
77059
|
+
}
|
|
77060
|
+
} catch {
|
|
77061
|
+
}
|
|
77062
|
+
}
|
|
77063
|
+
var SKIP_COMMANDS = /* @__PURE__ */ new Set([
|
|
77064
|
+
"heartbeat",
|
|
77065
|
+
"status_report",
|
|
77066
|
+
"read_chat",
|
|
77067
|
+
"mark_session_seen",
|
|
77068
|
+
"delete_notification",
|
|
77069
|
+
"mark_notification_unread"
|
|
77070
|
+
]);
|
|
77071
|
+
function shouldLogCommand(cmd) {
|
|
77072
|
+
return !SKIP_COMMANDS.has(cmd);
|
|
77073
|
+
}
|
|
77074
|
+
function logCommand(entry) {
|
|
77075
|
+
if (!shouldLogCommand(entry.cmd)) return;
|
|
77076
|
+
try {
|
|
77077
|
+
if (++writeCount2 % 500 === 0) {
|
|
77078
|
+
checkRotation();
|
|
77079
|
+
checkSize();
|
|
77080
|
+
}
|
|
77081
|
+
const line = JSON.stringify({
|
|
77082
|
+
ts: entry.ts,
|
|
77083
|
+
cmd: entry.cmd,
|
|
77084
|
+
src: entry.source,
|
|
77085
|
+
...entry.interactionId ? { interactionId: entry.interactionId } : {},
|
|
77086
|
+
...entry.args ? { args: maskArgs(entry.args) } : {},
|
|
77087
|
+
...entry.success !== void 0 ? { ok: entry.success } : {},
|
|
77088
|
+
...entry.error ? { err: entry.error } : {},
|
|
77089
|
+
...entry.durationMs !== void 0 ? { ms: entry.durationMs } : {}
|
|
77090
|
+
});
|
|
77091
|
+
fs26.appendFileSync(currentFile, line + "\n");
|
|
77092
|
+
} catch {
|
|
77093
|
+
}
|
|
77094
|
+
}
|
|
77095
|
+
function getRecentCommands(count = 50) {
|
|
77096
|
+
try {
|
|
77097
|
+
if (!fs26.existsSync(currentFile)) return [];
|
|
77098
|
+
const content = fs26.readFileSync(currentFile, "utf-8");
|
|
77099
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
77100
|
+
return lines.slice(-count).map((line) => {
|
|
77101
|
+
try {
|
|
77102
|
+
const parsed = JSON.parse(line);
|
|
77103
|
+
return {
|
|
77104
|
+
ts: parsed.ts,
|
|
77105
|
+
cmd: parsed.cmd,
|
|
77106
|
+
source: parsed.src,
|
|
77107
|
+
interactionId: parsed.interactionId,
|
|
77108
|
+
args: parsed.args,
|
|
77109
|
+
success: parsed.ok,
|
|
77110
|
+
error: parsed.err,
|
|
77111
|
+
durationMs: parsed.ms
|
|
77112
|
+
};
|
|
77113
|
+
} catch {
|
|
77114
|
+
return { ts: "", cmd: "parse_error", source: "unknown" };
|
|
77115
|
+
}
|
|
77116
|
+
});
|
|
77117
|
+
} catch {
|
|
77118
|
+
return [];
|
|
77119
|
+
}
|
|
77120
|
+
}
|
|
77121
|
+
cleanOldFiles();
|
|
77122
|
+
var yaml4 = __toESM2(require_js_yaml());
|
|
77123
|
+
init_mesh_coordinator();
|
|
77124
|
+
init_coordinator_registry();
|
|
77125
|
+
init_mesh_events();
|
|
77126
|
+
init_mesh_routing();
|
|
77127
|
+
init_mesh_host_ownership();
|
|
77128
|
+
var import_node_child_process4 = require("child_process");
|
|
77129
|
+
var import_node_util4 = require("util");
|
|
77130
|
+
var execFileAsync3 = (0, import_node_util4.promisify)(import_node_child_process4.execFile);
|
|
77131
|
+
var MAX_CHANGED_FILES2 = 500;
|
|
77132
|
+
function topLevel(path422) {
|
|
77133
|
+
const slash = path422.indexOf("/");
|
|
77134
|
+
return slash === -1 ? path422 : path422.slice(0, slash);
|
|
77135
|
+
}
|
|
77136
|
+
async function analyzeMeshRefineNodeChangeArea(args) {
|
|
77137
|
+
const { nodeId, workspace, branch, baseRef, branchRef, diffCwd, submodulePaths } = args;
|
|
77138
|
+
const base = {
|
|
77139
|
+
nodeId,
|
|
77140
|
+
workspace,
|
|
77141
|
+
branch,
|
|
77142
|
+
changedTopLevelPaths: [],
|
|
77143
|
+
changedFiles: [],
|
|
77144
|
+
touchedSubmodulePaths: [],
|
|
77145
|
+
touchesSubmodule: false,
|
|
77146
|
+
aheadCount: 0
|
|
77147
|
+
};
|
|
77148
|
+
try {
|
|
77149
|
+
let mergeBase = baseRef;
|
|
77150
|
+
try {
|
|
77151
|
+
const { stdout } = await execFileAsync3("git", ["merge-base", baseRef, branchRef], { cwd: diffCwd, encoding: "utf8" });
|
|
77152
|
+
const resolved = stdout.trim();
|
|
77153
|
+
if (resolved) mergeBase = resolved;
|
|
77154
|
+
} catch {
|
|
77155
|
+
}
|
|
77156
|
+
const { stdout: countStdout } = await execFileAsync3(
|
|
77157
|
+
"git",
|
|
77158
|
+
["rev-list", "--count", `${mergeBase}..${branchRef}`],
|
|
77159
|
+
{ cwd: diffCwd, encoding: "utf8" }
|
|
77160
|
+
);
|
|
77161
|
+
base.aheadCount = Number.parseInt(countStdout.trim(), 10) || 0;
|
|
77162
|
+
const { stdout: nameStdout } = await execFileAsync3(
|
|
77163
|
+
"git",
|
|
77164
|
+
["diff", "--name-only", `${mergeBase}..${branchRef}`],
|
|
77165
|
+
{ cwd: diffCwd, encoding: "utf8" }
|
|
77166
|
+
);
|
|
77167
|
+
const files = nameStdout.split("\n").map((line) => line.trim()).filter(Boolean).slice(0, MAX_CHANGED_FILES2);
|
|
77168
|
+
base.changedFiles = files;
|
|
77169
|
+
const topSet = /* @__PURE__ */ new Set();
|
|
77170
|
+
const submoduleSet = /* @__PURE__ */ new Set();
|
|
77171
|
+
for (const file2 of files) {
|
|
77172
|
+
const top = topLevel(file2);
|
|
77173
|
+
topSet.add(top);
|
|
77174
|
+
if (submodulePaths.has(file2) || submodulePaths.has(top)) {
|
|
77175
|
+
submoduleSet.add(submodulePaths.has(file2) ? file2 : top);
|
|
77176
|
+
}
|
|
77177
|
+
}
|
|
77178
|
+
base.changedTopLevelPaths = [...topSet].sort();
|
|
77179
|
+
base.touchedSubmodulePaths = [...submoduleSet].sort();
|
|
77180
|
+
base.touchesSubmodule = submoduleSet.size > 0;
|
|
77181
|
+
return base;
|
|
77182
|
+
} catch (e) {
|
|
77183
|
+
base.error = e?.message || String(e);
|
|
77184
|
+
return base;
|
|
77185
|
+
}
|
|
77186
|
+
}
|
|
77187
|
+
function orderMeshRefineBatchNodes(changeAreas) {
|
|
77188
|
+
const areaById = {};
|
|
77189
|
+
for (const area of changeAreas) areaById[area.nodeId] = area;
|
|
77190
|
+
const ranked = [...changeAreas].sort((a, b) => {
|
|
77191
|
+
const aSub = a.touchesSubmodule ? 1 : 0;
|
|
77192
|
+
const bSub = b.touchesSubmodule ? 1 : 0;
|
|
77193
|
+
if (aSub !== bSub) return aSub - bSub;
|
|
77194
|
+
const aBreadth = a.changedTopLevelPaths.length;
|
|
77195
|
+
const bBreadth = b.changedTopLevelPaths.length;
|
|
77196
|
+
if (aBreadth !== bBreadth) return aBreadth - bBreadth;
|
|
77197
|
+
return a.nodeId.localeCompare(b.nodeId);
|
|
77198
|
+
});
|
|
77199
|
+
const rationale = [];
|
|
77200
|
+
const nonSub = ranked.filter((a) => !a.touchesSubmodule).map((a) => a.nodeId);
|
|
77201
|
+
const sub = ranked.filter((a) => a.touchesSubmodule).map((a) => a.nodeId);
|
|
77202
|
+
if (nonSub.length) {
|
|
77203
|
+
rationale.push(`Non-submodule nodes first (no submodule-main advance, conflict-free ordering): ${nonSub.join(", ")}`);
|
|
77204
|
+
}
|
|
77205
|
+
if (sub.length) {
|
|
77206
|
+
rationale.push(`Submodule-touching nodes last, serialized (each merge advances submodule main, forcing rebase of the next): ${sub.join(", ")}`);
|
|
77207
|
+
}
|
|
77208
|
+
for (const area of ranked) {
|
|
77209
|
+
if (area.error) rationale.push(`Node ${area.nodeId}: change-area analysis degraded (${area.error}); placed with neutral priority.`);
|
|
77210
|
+
}
|
|
77211
|
+
return { order: ranked.map((a) => a.nodeId), changeAreas: areaById, rationale };
|
|
77212
|
+
}
|
|
77213
|
+
var import_node_child_process5 = require("child_process");
|
|
77214
|
+
var import_node_fs4 = require("fs");
|
|
77215
|
+
var import_node_path2 = require("path");
|
|
77216
|
+
var PREVIEW_DEPLOY_RECORD = ".adhdev/preview-deploy.json";
|
|
77217
|
+
function runGit2(repoRoot, args) {
|
|
77218
|
+
try {
|
|
77219
|
+
return (0, import_node_child_process5.execFileSync)("git", args, {
|
|
77220
|
+
cwd: repoRoot,
|
|
77221
|
+
encoding: "utf8",
|
|
77222
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
77223
|
+
timeout: 5e3
|
|
77224
|
+
}).trim();
|
|
77225
|
+
} catch {
|
|
77226
|
+
return "";
|
|
77227
|
+
}
|
|
77228
|
+
}
|
|
77229
|
+
function readRecord5(repoRoot) {
|
|
77230
|
+
const path422 = (0, import_node_path2.resolve)(repoRoot, PREVIEW_DEPLOY_RECORD);
|
|
77231
|
+
if (!(0, import_node_fs4.existsSync)(path422)) return null;
|
|
77232
|
+
try {
|
|
77233
|
+
const parsed = JSON.parse((0, import_node_fs4.readFileSync)(path422, "utf8"));
|
|
77234
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
77235
|
+
} catch {
|
|
77236
|
+
return null;
|
|
77237
|
+
}
|
|
77238
|
+
}
|
|
77239
|
+
function normalizeCommit(value) {
|
|
77240
|
+
return typeof value === "string" && /^[0-9a-f]{7,40}$/i.test(value.trim()) ? value.trim() : null;
|
|
77241
|
+
}
|
|
77242
|
+
function readTargetFreshness(record2, currentCommit) {
|
|
77243
|
+
const targets = record2?.targets && typeof record2.targets === "object" && !Array.isArray(record2.targets) ? record2.targets : {};
|
|
77244
|
+
const result = {};
|
|
77245
|
+
for (const targetName of ["npm", "server", "web"]) {
|
|
77246
|
+
const targetRecord = targets[targetName] && typeof targets[targetName] === "object" && !Array.isArray(targets[targetName]) ? targets[targetName] : {};
|
|
77247
|
+
const commit = normalizeCommit(targetRecord.commit);
|
|
77248
|
+
result[targetName] = {
|
|
77249
|
+
commit,
|
|
77250
|
+
deployedAt: typeof targetRecord.deployedAt === "string" ? targetRecord.deployedAt : void 0,
|
|
77251
|
+
status: commit && currentCommit ? commit === currentCommit ? "fresh" : "stale" : "unknown"
|
|
77252
|
+
};
|
|
77253
|
+
}
|
|
77254
|
+
return result;
|
|
77255
|
+
}
|
|
77256
|
+
function readCurrentMainCommit(repoRoot) {
|
|
77257
|
+
const originMain = runGit2(repoRoot, ["rev-parse", "--verify", "origin/main^{commit}"]);
|
|
77258
|
+
if (originMain) {
|
|
77259
|
+
return { currentMainCommit: originMain, currentMainCommitSource: "origin/main" };
|
|
77260
|
+
}
|
|
77261
|
+
const head = runGit2(repoRoot, ["rev-parse", "--verify", "HEAD"]);
|
|
77262
|
+
if (head) {
|
|
77263
|
+
return { currentMainCommit: head, currentMainCommitSource: "HEAD" };
|
|
77264
|
+
}
|
|
77265
|
+
return { currentMainCommit: null, currentMainCommitSource: "unknown" };
|
|
77266
|
+
}
|
|
77267
|
+
function buildPreviewFreshness(repoRoot) {
|
|
77268
|
+
const current = readCurrentMainCommit(repoRoot);
|
|
77269
|
+
const record2 = readRecord5(repoRoot);
|
|
77270
|
+
const lastPreviewCommit = normalizeCommit(record2?.lastPreviewCommit);
|
|
77271
|
+
const targets = readTargetFreshness(record2, current.currentMainCommit);
|
|
77272
|
+
let status = "unknown";
|
|
77273
|
+
let nextAction = "Run npm run deploy:preview from the current main commit, then smoke preview.";
|
|
77274
|
+
if (lastPreviewCommit && current.currentMainCommit) {
|
|
77275
|
+
status = lastPreviewCommit === current.currentMainCommit ? "fresh" : "stale";
|
|
77276
|
+
nextAction = status === "fresh" ? "No preview deploy action needed." : "Run npm run deploy:preview from origin/main, then smoke preview.";
|
|
77277
|
+
} else if (!current.currentMainCommit) {
|
|
77278
|
+
nextAction = "Resolve the current main commit before judging preview freshness.";
|
|
77279
|
+
}
|
|
77280
|
+
return {
|
|
77281
|
+
status,
|
|
77282
|
+
lastPreviewCommit,
|
|
77283
|
+
currentMainCommit: current.currentMainCommit,
|
|
77284
|
+
currentMainCommitSource: current.currentMainCommitSource,
|
|
77285
|
+
recordPath: PREVIEW_DEPLOY_RECORD,
|
|
77286
|
+
lastDeployedAt: typeof record2?.updatedAt === "string" ? record2.updatedAt : void 0,
|
|
77287
|
+
lastTarget: typeof record2?.target === "string" ? record2.target : void 0,
|
|
77288
|
+
previewVersion: typeof record2?.previewVersion === "string" ? record2.previewVersion : void 0,
|
|
77289
|
+
targets,
|
|
77290
|
+
nextAction
|
|
77291
|
+
};
|
|
77292
|
+
}
|
|
77293
|
+
init_mesh_refine_status();
|
|
75902
77294
|
init_mesh_work_queue();
|
|
75903
77295
|
init_repo_mesh_types();
|
|
75904
77296
|
var import_os3 = require("os");
|
|
@@ -78450,6 +79842,37 @@ ${mergeTreeErr?.stderr || ""}`;
|
|
|
78450
79842
|
this.aggregateMeshStatusCache.delete(meshId);
|
|
78451
79843
|
this.deps.onMeshStateChange?.(meshId);
|
|
78452
79844
|
}
|
|
79845
|
+
/**
|
|
79846
|
+
* Build the MedFamilyContext handed to RF-ROUTER MED family handlers. Binds the
|
|
79847
|
+
* router-private collaborators those handlers need (mesh resolution, owner
|
|
79848
|
+
* gating, inline-cache mutation, worktree / session cleanup, refine job
|
|
79849
|
+
* starters, IDE stop/launch) plus the inline-mesh and git-probe caches. The
|
|
79850
|
+
* `launchIde` field closes over the freshly-built context so restart_session /
|
|
79851
|
+
* restart_ide invoke the IDE launch directly instead of recursing through
|
|
79852
|
+
* executeDaemonCommand('launch_ide').
|
|
79853
|
+
*/
|
|
79854
|
+
buildMedFamilyContext() {
|
|
79855
|
+
const ctx = {
|
|
79856
|
+
deps: this.deps,
|
|
79857
|
+
getMeshForCommand: this.getMeshForCommand.bind(this),
|
|
79858
|
+
getCachedInlineMesh: this.getCachedInlineMesh.bind(this),
|
|
79859
|
+
requireMeshHostMutationOwner: this.requireMeshHostMutationOwner.bind(this),
|
|
79860
|
+
invalidateAggregateMeshStatus: this.invalidateAggregateMeshStatus.bind(this),
|
|
79861
|
+
updateInlineMeshNode: this.updateInlineMeshNode.bind(this),
|
|
79862
|
+
removeInlineMeshNode: this.removeInlineMeshNode.bind(this),
|
|
79863
|
+
normalizeMeshSessionCleanupMode: this.normalizeMeshSessionCleanupMode.bind(this),
|
|
79864
|
+
cleanupMeshSessions: this.cleanupMeshSessions.bind(this),
|
|
79865
|
+
cleanupLocalWorktreeNode: this.cleanupLocalWorktreeNode.bind(this),
|
|
79866
|
+
startMeshRefineJob: this.startMeshRefineJob.bind(this),
|
|
79867
|
+
batchRefineMeshNodes: this.batchRefineMeshNodes.bind(this),
|
|
79868
|
+
startMeshRefineBatchJob: this.startMeshRefineBatchJob.bind(this),
|
|
79869
|
+
stopIde: this.stopIde.bind(this),
|
|
79870
|
+
launchIde: (args) => launchIde(ctx, args),
|
|
79871
|
+
inlineMeshCache: this.inlineMeshCache,
|
|
79872
|
+
meshGitProbeCache: this.meshGitProbeCache
|
|
79873
|
+
};
|
|
79874
|
+
return ctx;
|
|
79875
|
+
}
|
|
78453
79876
|
async requireMeshHostMutationOwner(meshId, inlineMesh, operation) {
|
|
78454
79877
|
const meshRecord = await this.getMeshForCommand(meshId, inlineMesh, { preferInline: true });
|
|
78455
79878
|
const mesh = meshRecord?.mesh;
|
|
@@ -80365,6 +81788,10 @@ ${hintLines.join("\n")}` : "",
|
|
|
80365
81788
|
getMeshForCommand: this.getMeshForCommand.bind(this)
|
|
80366
81789
|
}, args);
|
|
80367
81790
|
}
|
|
81791
|
+
const medFamilyHandler = medFamilyRegistry.get(cmd);
|
|
81792
|
+
if (medFamilyHandler) {
|
|
81793
|
+
return await medFamilyHandler(this.buildMedFamilyContext(), args);
|
|
81794
|
+
}
|
|
80368
81795
|
switch (cmd) {
|
|
80369
81796
|
// ─── CLI / ACP commands ───
|
|
80370
81797
|
case "mesh_forward_event": {
|
|
@@ -80385,1315 +81812,6 @@ ${hintLines.join("\n")}` : "",
|
|
|
80385
81812
|
this.deps.instanceManager.sendEvent(sessionId, "interactive_prompt_response", response);
|
|
80386
81813
|
return { success: true };
|
|
80387
81814
|
}
|
|
80388
|
-
case "launch_cli": {
|
|
80389
|
-
const launchResult = await this.deps.cliManager.handleCliCommand(cmd, args);
|
|
80390
|
-
const meshNodeId = readStringValue(args?.settings?.meshNodeId);
|
|
80391
|
-
const meshId = readStringValue(args?.settings?.meshNodeFor);
|
|
80392
|
-
if (meshNodeId && meshId && launchResult?.success !== false) {
|
|
80393
|
-
try {
|
|
80394
|
-
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80395
|
-
const meshObj = getMesh2(meshId) ?? this.getCachedInlineMesh(meshId);
|
|
80396
|
-
const nodeObj = Array.isArray(meshObj?.nodes) ? meshObj.nodes.find((n) => meshNodeIdMatches(n, meshNodeId)) : void 0;
|
|
80397
|
-
const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
|
|
80398
|
-
if (bootstrapStatus === "running") {
|
|
80399
|
-
return { success: true, ...launchResult, bootstrapPending: true };
|
|
80400
|
-
}
|
|
80401
|
-
} catch {
|
|
80402
|
-
}
|
|
80403
|
-
}
|
|
80404
|
-
return launchResult;
|
|
80405
|
-
}
|
|
80406
|
-
case "stop_cli":
|
|
80407
|
-
case "set_cli_view_mode":
|
|
80408
|
-
case "record_provider_pty": {
|
|
80409
|
-
return this.deps.cliManager.handleCliCommand(cmd, args);
|
|
80410
|
-
}
|
|
80411
|
-
case "agent_command": {
|
|
80412
|
-
{
|
|
80413
|
-
const dispatchSessionId = readStringValue(args?.targetSessionId, args?.sessionId, args?.instanceId);
|
|
80414
|
-
const dispatchMeshContext = args?.meshContext;
|
|
80415
|
-
if (dispatchSessionId && dispatchMeshContext) {
|
|
80416
|
-
try {
|
|
80417
|
-
const inst = this.deps.instanceManager.getInstance(dispatchSessionId);
|
|
80418
|
-
if (inst && typeof inst.updateSettings === "function") {
|
|
80419
|
-
const stamp = buildMeshWorkerRelayStamp(
|
|
80420
|
-
inst.getState?.()?.settings,
|
|
80421
|
-
{
|
|
80422
|
-
meshId: dispatchMeshContext.meshId,
|
|
80423
|
-
nodeId: dispatchMeshContext.nodeId,
|
|
80424
|
-
coordinatorDaemonId: dispatchMeshContext.coordinatorDaemonId,
|
|
80425
|
-
// Session-level anchor: preserved across the P2P dispatch to a
|
|
80426
|
-
// remote worker so its completion echoes back to the right session.
|
|
80427
|
-
coordinatorSessionId: dispatchMeshContext.coordinatorSessionId
|
|
80428
|
-
}
|
|
80429
|
-
);
|
|
80430
|
-
if (stamp) inst.updateSettings(stamp);
|
|
80431
|
-
}
|
|
80432
|
-
} catch {
|
|
80433
|
-
}
|
|
80434
|
-
}
|
|
80435
|
-
}
|
|
80436
|
-
const agentResult = await this.deps.cliManager.handleCliCommand(cmd, args);
|
|
80437
|
-
const meshCtx = args?.meshContext;
|
|
80438
|
-
const dispatchNodeId = readStringValue(meshCtx?.nodeId);
|
|
80439
|
-
const dispatchMeshId = readStringValue(meshCtx?.meshId);
|
|
80440
|
-
if (dispatchNodeId && dispatchMeshId && agentResult?.success !== false) {
|
|
80441
|
-
try {
|
|
80442
|
-
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80443
|
-
const meshObj = getMesh2(dispatchMeshId) ?? this.getCachedInlineMesh(dispatchMeshId);
|
|
80444
|
-
const nodeObj = Array.isArray(meshObj?.nodes) ? meshObj.nodes.find((n) => meshNodeIdMatches(n, dispatchNodeId)) : void 0;
|
|
80445
|
-
const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
|
|
80446
|
-
if (bootstrapStatus === "running") {
|
|
80447
|
-
return {
|
|
80448
|
-
success: true,
|
|
80449
|
-
...agentResult,
|
|
80450
|
-
dispatchAcknowledgementRisk: true,
|
|
80451
|
-
dispatchAcknowledgementRiskReason: "bootstrap_still_running",
|
|
80452
|
-
nextAction: "Wait for worktree_bootstrap_complete event before dispatching work to this node."
|
|
80453
|
-
};
|
|
80454
|
-
}
|
|
80455
|
-
} catch {
|
|
80456
|
-
}
|
|
80457
|
-
}
|
|
80458
|
-
return agentResult;
|
|
80459
|
-
}
|
|
80460
|
-
// ─── Logs ───
|
|
80461
|
-
case "list_saved_sessions": {
|
|
80462
|
-
const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : typeof args?.agentType === "string" ? args.agentType.trim() : "";
|
|
80463
|
-
const kind = args?.kind === "acp" ? "acp" : "cli";
|
|
80464
|
-
if (!providerType) {
|
|
80465
|
-
return { success: false, error: "providerType required" };
|
|
80466
|
-
}
|
|
80467
|
-
const wantsAll = args?.all === true;
|
|
80468
|
-
const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
|
|
80469
|
-
const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
|
|
80470
|
-
const requestedWorkspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
80471
|
-
const requestedProviderSessionId = typeof args?.providerSessionId === "string" ? args.providerSessionId.trim() : typeof args?.activeProviderSessionId === "string" ? args.activeProviderSessionId.trim() : "";
|
|
80472
|
-
const providerMeta = this.deps.providerLoader.resolve?.(providerType) || this.deps.providerLoader.getMeta(providerType);
|
|
80473
|
-
const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
|
|
80474
|
-
canonicalHistory: providerMeta?.nativeHistory,
|
|
80475
|
-
offset,
|
|
80476
|
-
limit,
|
|
80477
|
-
historyBehavior: providerMeta?.historyBehavior,
|
|
80478
|
-
scripts: providerMeta?.scripts
|
|
80479
|
-
});
|
|
80480
|
-
const state = loadState();
|
|
80481
|
-
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
80482
|
-
const recentSessions = getRecentActivity(state, 200).filter((entry) => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
80483
|
-
const savedSessionById = new Map(savedSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
80484
|
-
const recentSessionById = new Map(recentSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
80485
|
-
const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
|
|
80486
|
-
return {
|
|
80487
|
-
success: true,
|
|
80488
|
-
sessions: historySessions.map((session) => {
|
|
80489
|
-
const saved = savedSessionById.get(session.historySessionId);
|
|
80490
|
-
const recent = recentSessionById.get(session.historySessionId);
|
|
80491
|
-
const workspace = saved?.workspace || recent?.workspace || session.workspace || (requestedWorkspace && requestedProviderSessionId === session.historySessionId ? requestedWorkspace : void 0);
|
|
80492
|
-
return {
|
|
80493
|
-
id: session.historySessionId,
|
|
80494
|
-
providerSessionId: session.historySessionId,
|
|
80495
|
-
providerType,
|
|
80496
|
-
providerName: saved?.providerName || recent?.providerName || providerType,
|
|
80497
|
-
kind: saved?.kind || recent?.kind || kind,
|
|
80498
|
-
title: saved?.title || recent?.title || session.sessionTitle || session.preview || providerType,
|
|
80499
|
-
workspace,
|
|
80500
|
-
summaryMetadata: saved?.summaryMetadata || recent?.summaryMetadata,
|
|
80501
|
-
preview: session.preview,
|
|
80502
|
-
messageCount: session.messageCount,
|
|
80503
|
-
firstMessageAt: session.firstMessageAt,
|
|
80504
|
-
lastMessageAt: session.lastMessageAt,
|
|
80505
|
-
canResume: !!workspace && canResumeById,
|
|
80506
|
-
historySource: session.source,
|
|
80507
|
-
sourcePath: session.sourcePath,
|
|
80508
|
-
sourceMtimeMs: session.sourceMtimeMs
|
|
80509
|
-
};
|
|
80510
|
-
}),
|
|
80511
|
-
hasMore,
|
|
80512
|
-
source
|
|
80513
|
-
};
|
|
80514
|
-
}
|
|
80515
|
-
// ─── restart_session: IDE / CLI / ACP unified ───
|
|
80516
|
-
case "restart_session": {
|
|
80517
|
-
const targetType = args?.cliType || args?.agentType || args?.ideType;
|
|
80518
|
-
if (!targetType) throw new Error("cliType or ideType required");
|
|
80519
|
-
const isIde = this.deps.cdpManagers.has(targetType) || this.deps.providerLoader.getMeta(targetType)?.category === "ide";
|
|
80520
|
-
if (isIde) {
|
|
80521
|
-
await this.stopIde(targetType, true);
|
|
80522
|
-
const launchResult = await this.executeDaemonCommand("launch_ide", { ideType: targetType, enableCdp: true, workspace: args?.workspace });
|
|
80523
|
-
return { success: true, restarted: true, ideType: targetType, launch: launchResult };
|
|
80524
|
-
}
|
|
80525
|
-
return this.deps.cliManager.handleCliCommand(cmd, args);
|
|
80526
|
-
}
|
|
80527
|
-
// ─── IDE stop ───
|
|
80528
|
-
case "stop_ide": {
|
|
80529
|
-
const ideType = args?.ideType;
|
|
80530
|
-
if (!ideType) throw new Error("ideType required");
|
|
80531
|
-
const killProcess = args?.killProcess !== false;
|
|
80532
|
-
await this.stopIde(ideType, killProcess);
|
|
80533
|
-
try {
|
|
80534
|
-
const results = await detectIDEs(this.deps.providerLoader);
|
|
80535
|
-
this.deps.detectedIdes.value = results;
|
|
80536
|
-
this.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
80537
|
-
} catch {
|
|
80538
|
-
}
|
|
80539
|
-
return { success: true, ideType, stopped: true, processKilled: killProcess };
|
|
80540
|
-
}
|
|
80541
|
-
// ─── IDE restart ───
|
|
80542
|
-
case "restart_ide": {
|
|
80543
|
-
const ideType = args?.ideType;
|
|
80544
|
-
if (!ideType) throw new Error("ideType required");
|
|
80545
|
-
await this.stopIde(ideType, true);
|
|
80546
|
-
const launchResult = await this.executeDaemonCommand("launch_ide", { ideType, enableCdp: true, workspace: args?.workspace });
|
|
80547
|
-
return { success: true, ideType, restarted: true, launch: launchResult };
|
|
80548
|
-
}
|
|
80549
|
-
// ─── IDE launch + CDP connect ───
|
|
80550
|
-
case "launch_ide": {
|
|
80551
|
-
const ideKey = args?.ideId || args?.ideType;
|
|
80552
|
-
const resolvedWorkspace = resolveIdeLaunchWorkspace(
|
|
80553
|
-
{
|
|
80554
|
-
workspace: args?.workspace,
|
|
80555
|
-
workspaceId: args?.workspaceId,
|
|
80556
|
-
useDefaultWorkspace: args?.useDefaultWorkspace
|
|
80557
|
-
},
|
|
80558
|
-
loadConfig2()
|
|
80559
|
-
);
|
|
80560
|
-
const launchArgs = {
|
|
80561
|
-
ideId: ideKey,
|
|
80562
|
-
workspace: resolvedWorkspace,
|
|
80563
|
-
newWindow: args?.newWindow
|
|
80564
|
-
};
|
|
80565
|
-
LOG2.info("LaunchIDE", `target=${ideKey || "auto"}`);
|
|
80566
|
-
const result = await launchWithCdp(launchArgs);
|
|
80567
|
-
if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
|
|
80568
|
-
const logFn = this.deps.getCdpLogFn ? this.deps.getCdpLogFn(result.ideId) : LOG2.forComponent(`CDP:${result.ideId}`).asLogFn();
|
|
80569
|
-
const provider = this.deps.providerLoader.getMeta(result.ideId);
|
|
80570
|
-
const manager = new DaemonCdpManager(result.port, logFn, void 0, provider?.targetFilter);
|
|
80571
|
-
const connected = await manager.connect();
|
|
80572
|
-
if (connected) {
|
|
80573
|
-
registerExtensionProviders(this.deps.providerLoader, manager, result.ideId);
|
|
80574
|
-
this.deps.cdpManagers.set(result.ideId, manager);
|
|
80575
|
-
LOG2.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
|
|
80576
|
-
LOG2.info("CDP", `${this.deps.cdpManagers.size} IDE(s) connected`);
|
|
80577
|
-
this.deps.onCdpManagerCreated?.(result.ideId, manager);
|
|
80578
|
-
}
|
|
80579
|
-
}
|
|
80580
|
-
this.deps.onIdeConnected?.();
|
|
80581
|
-
try {
|
|
80582
|
-
const results = await detectIDEs(this.deps.providerLoader);
|
|
80583
|
-
this.deps.detectedIdes.value = results;
|
|
80584
|
-
this.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
80585
|
-
} catch {
|
|
80586
|
-
}
|
|
80587
|
-
if (result.success && resolvedWorkspace) {
|
|
80588
|
-
try {
|
|
80589
|
-
const next = appendRecentActivity(loadState(), {
|
|
80590
|
-
kind: "ide",
|
|
80591
|
-
providerType: result.ideId || ideKey,
|
|
80592
|
-
providerName: result.ideId || ideKey,
|
|
80593
|
-
workspace: resolvedWorkspace,
|
|
80594
|
-
title: result.ideId || ideKey
|
|
80595
|
-
});
|
|
80596
|
-
saveState(next);
|
|
80597
|
-
} catch {
|
|
80598
|
-
}
|
|
80599
|
-
} else if (result.success && (result.ideId || ideKey)) {
|
|
80600
|
-
try {
|
|
80601
|
-
saveState(appendRecentActivity(loadState(), {
|
|
80602
|
-
kind: "ide",
|
|
80603
|
-
providerType: result.ideId || ideKey,
|
|
80604
|
-
providerName: result.ideId || ideKey,
|
|
80605
|
-
title: result.ideId || ideKey
|
|
80606
|
-
}));
|
|
80607
|
-
} catch {
|
|
80608
|
-
}
|
|
80609
|
-
}
|
|
80610
|
-
return { ...result };
|
|
80611
|
-
}
|
|
80612
|
-
// ─── Detect providers ───
|
|
80613
|
-
case "detect_provider": {
|
|
80614
|
-
const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : "";
|
|
80615
|
-
if (!providerType) return { success: false, error: "providerType is required" };
|
|
80616
|
-
const normalizedType = this.deps.providerLoader.resolveAlias(providerType);
|
|
80617
|
-
const provider = this.deps.providerLoader.getByAlias(providerType);
|
|
80618
|
-
if (!provider) return { success: false, error: `Provider not found: ${providerType}` };
|
|
80619
|
-
if (provider.category !== "cli" && provider.category !== "acp") {
|
|
80620
|
-
return { success: false, error: `Provider detection is only supported for CLI/ACP providers: ${providerType}` };
|
|
80621
|
-
}
|
|
80622
|
-
if (!this.deps.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
80623
|
-
return { success: false, error: `Provider is disabled on this machine: ${providerType}` };
|
|
80624
|
-
}
|
|
80625
|
-
const detected = await detectCLI(normalizedType, this.deps.providerLoader, { includeVersion: false });
|
|
80626
|
-
this.deps.providerLoader.setCliDetectionResults([{
|
|
80627
|
-
id: normalizedType,
|
|
80628
|
-
installed: !!detected,
|
|
80629
|
-
path: detected?.path
|
|
80630
|
-
}], false);
|
|
80631
|
-
this.deps.onStatusChange?.();
|
|
80632
|
-
return {
|
|
80633
|
-
success: true,
|
|
80634
|
-
providerType: normalizedType,
|
|
80635
|
-
detected: !!detected,
|
|
80636
|
-
path: detected?.path || null
|
|
80637
|
-
};
|
|
80638
|
-
}
|
|
80639
|
-
// ─── Detect IDEs ───
|
|
80640
|
-
case "detect_ides": {
|
|
80641
|
-
const results = await detectIDEs(this.deps.providerLoader);
|
|
80642
|
-
this.deps.detectedIdes.value = results;
|
|
80643
|
-
this.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
80644
|
-
return { success: true, detectedInfo: results };
|
|
80645
|
-
}
|
|
80646
|
-
// ─── Mesh CRUD (local meshes.json) ───
|
|
80647
|
-
case "list_meshes": {
|
|
80648
|
-
try {
|
|
80649
|
-
const { listMeshes: listMeshes2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80650
|
-
return { success: true, meshes: listMeshes2() };
|
|
80651
|
-
} catch (e) {
|
|
80652
|
-
return { success: false, error: e.message };
|
|
80653
|
-
}
|
|
80654
|
-
}
|
|
80655
|
-
case "get_mesh": {
|
|
80656
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80657
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80658
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
80659
|
-
if (!meshRecord?.mesh) return { success: false, error: "Mesh not found" };
|
|
80660
|
-
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
80661
|
-
const probeRemotePeers = args?.refresh === true || args?.forceRefresh === true;
|
|
80662
|
-
const directTruth = await hydrateInlineMeshDirectTruth({
|
|
80663
|
-
mesh: meshRecord.mesh,
|
|
80664
|
-
meshSource: meshRecord.source,
|
|
80665
|
-
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
80666
|
-
getMeshPeerConnectionStatus: this.deps.getMeshPeerConnectionStatus,
|
|
80667
|
-
statusInstanceId: this.deps.statusInstanceId,
|
|
80668
|
-
localMachineId: loadConfig2().machineId || "",
|
|
80669
|
-
probeRemotePeers,
|
|
80670
|
-
probeCache: this.meshGitProbeCache
|
|
80671
|
-
});
|
|
80672
|
-
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
80673
|
-
const sourceOfTruth = {
|
|
80674
|
-
membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
80675
|
-
coordinatorOwnsLiveTruth: directTruthSatisfied,
|
|
80676
|
-
directPeerTruth: {
|
|
80677
|
-
required: requireDirectPeerTruth,
|
|
80678
|
-
satisfied: directTruthSatisfied,
|
|
80679
|
-
directEvidenceCount: directTruth.directEvidenceCount,
|
|
80680
|
-
localConfirmedCount: directTruth.localConfirmedCount,
|
|
80681
|
-
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
80682
|
-
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
80683
|
-
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
80684
|
-
}
|
|
80685
|
-
};
|
|
80686
|
-
if (requireDirectPeerTruth && !directTruthSatisfied) {
|
|
80687
|
-
return {
|
|
80688
|
-
success: false,
|
|
80689
|
-
code: "mesh_direct_peer_truth_unavailable",
|
|
80690
|
-
error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.",
|
|
80691
|
-
sourceOfTruth
|
|
80692
|
-
};
|
|
80693
|
-
}
|
|
80694
|
-
return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
|
|
80695
|
-
}
|
|
80696
|
-
case "create_mesh": {
|
|
80697
|
-
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
80698
|
-
const repoIdentity = typeof args?.repoIdentity === "string" ? args.repoIdentity.trim() : "";
|
|
80699
|
-
const repoRemoteUrl = typeof args?.repoRemoteUrl === "string" ? args.repoRemoteUrl.trim() : void 0;
|
|
80700
|
-
const defaultBranch = typeof args?.defaultBranch === "string" ? args.defaultBranch.trim() : void 0;
|
|
80701
|
-
if (!name) return { success: false, error: "name required" };
|
|
80702
|
-
try {
|
|
80703
|
-
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80704
|
-
const meshHost = args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost) ? args.meshHost : void 0;
|
|
80705
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy, meshHost });
|
|
80706
|
-
return { success: true, mesh };
|
|
80707
|
-
} catch (e) {
|
|
80708
|
-
return { success: false, error: e.message };
|
|
80709
|
-
}
|
|
80710
|
-
}
|
|
80711
|
-
case "update_mesh": {
|
|
80712
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80713
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80714
|
-
try {
|
|
80715
|
-
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80716
|
-
const patch = {};
|
|
80717
|
-
if (typeof args?.name === "string") patch.name = args.name;
|
|
80718
|
-
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
80719
|
-
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
80720
|
-
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
80721
|
-
if (args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost)) patch.meshHost = args.meshHost;
|
|
80722
|
-
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
80723
|
-
const mesh = updateMesh2(meshId, patch);
|
|
80724
|
-
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
80725
|
-
this.inlineMeshCache.set(meshId, mesh);
|
|
80726
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
80727
|
-
return { success: true, mesh };
|
|
80728
|
-
} catch (e) {
|
|
80729
|
-
return { success: false, error: e.message };
|
|
80730
|
-
}
|
|
80731
|
-
}
|
|
80732
|
-
case "get_mesh_host_pairing": {
|
|
80733
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80734
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80735
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
80736
|
-
const mesh = meshRecord?.mesh;
|
|
80737
|
-
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
80738
|
-
const meshHost = resolveMeshHostStatus(mesh);
|
|
80739
|
-
const pairingStatus = meshHost.pairing?.status || "not_configured";
|
|
80740
|
-
return {
|
|
80741
|
-
success: true,
|
|
80742
|
-
code: pairingStatus === "not_configured" ? "mesh_host_pairing_not_configured" : "mesh_host_pairing_pending",
|
|
80743
|
-
meshId,
|
|
80744
|
-
hostAddress: meshHost.hostAddress,
|
|
80745
|
-
meshHost,
|
|
80746
|
-
manualPairing: {
|
|
80747
|
-
status: pairingStatus,
|
|
80748
|
-
joinImplemented: true,
|
|
80749
|
-
protocol: "standalone_command_direct_v1",
|
|
80750
|
-
description: "Standalone manual pairing can save address/token metadata, apply a host join over direct standalone command HTTP or injected mesh command dispatch, and check persisted status. P2P signaling remains outside this slice."
|
|
80751
|
-
}
|
|
80752
|
-
};
|
|
80753
|
-
}
|
|
80754
|
-
case "configure_mesh_host_pairing": {
|
|
80755
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80756
|
-
const hostAddress = typeof args?.hostAddress === "string" ? args.hostAddress.trim() : "";
|
|
80757
|
-
const token = typeof args?.token === "string" ? args.token.trim() : "";
|
|
80758
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80759
|
-
if (!hostAddress || !token) return { success: false, error: "hostAddress and token required" };
|
|
80760
|
-
try {
|
|
80761
|
-
const { configureMeshHostPairing: configureMeshHostPairing2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80762
|
-
const configured = configureMeshHostPairing2(meshId, { hostAddress, token });
|
|
80763
|
-
if (!configured) return { success: false, error: "Mesh not found" };
|
|
80764
|
-
this.inlineMeshCache.set(meshId, configured.mesh);
|
|
80765
|
-
const meshHost = resolveMeshHostStatus(configured.mesh);
|
|
80766
|
-
return {
|
|
80767
|
-
success: true,
|
|
80768
|
-
code: "mesh_host_pairing_pending",
|
|
80769
|
-
meshId,
|
|
80770
|
-
hostAddress: configured.hostAddress,
|
|
80771
|
-
meshHost,
|
|
80772
|
-
manualPairing: {
|
|
80773
|
-
status: meshHost.pairing?.status || "pairing",
|
|
80774
|
-
joinImplemented: true,
|
|
80775
|
-
protocol: "standalone_command_direct_v1",
|
|
80776
|
-
description: "Manual Mesh Host pairing config was saved locally. Use join_mesh_host_pairing to apply it to the host. Raw token was not persisted."
|
|
80777
|
-
}
|
|
80778
|
-
};
|
|
80779
|
-
} catch (e) {
|
|
80780
|
-
return { success: false, code: "mesh_host_pairing_invalid", meshId, hostAddress, error: e.message };
|
|
80781
|
-
}
|
|
80782
|
-
}
|
|
80783
|
-
case "create_mesh_host_pairing_token": {
|
|
80784
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80785
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80786
|
-
try {
|
|
80787
|
-
const { createMeshHostPairingToken: createMeshHostPairingToken2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80788
|
-
const created = createMeshHostPairingToken2(meshId, {
|
|
80789
|
-
token: typeof args?.token === "string" ? args.token : void 0,
|
|
80790
|
-
expiresAt: typeof args?.expiresAt === "string" ? args.expiresAt : void 0
|
|
80791
|
-
});
|
|
80792
|
-
if (!created) return { success: false, error: "Mesh not found" };
|
|
80793
|
-
this.inlineMeshCache.set(meshId, created.mesh);
|
|
80794
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
80795
|
-
return {
|
|
80796
|
-
success: true,
|
|
80797
|
-
code: "mesh_host_pairing_token_created",
|
|
80798
|
-
meshId,
|
|
80799
|
-
token: created.token,
|
|
80800
|
-
tokenId: created.tokenId,
|
|
80801
|
-
expiresAt: created.expiresAt,
|
|
80802
|
-
meshHost: resolveMeshHostStatus(created.mesh),
|
|
80803
|
-
warning: "Raw token is returned once and is not persisted; share it with member daemons over a trusted channel."
|
|
80804
|
-
};
|
|
80805
|
-
} catch (e) {
|
|
80806
|
-
return { success: false, code: "mesh_host_pairing_token_invalid", meshId, error: e.message };
|
|
80807
|
-
}
|
|
80808
|
-
}
|
|
80809
|
-
case "apply_mesh_host_join": {
|
|
80810
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80811
|
-
const token = typeof args?.token === "string" ? args.token.trim() : "";
|
|
80812
|
-
const memberNode = args?.memberNode && typeof args.memberNode === "object" && !Array.isArray(args.memberNode) ? args.memberNode : null;
|
|
80813
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80814
|
-
if (!token || !memberNode) return { success: false, error: "token and memberNode required" };
|
|
80815
|
-
try {
|
|
80816
|
-
const { applyMeshHostJoinRequest: applyMeshHostJoinRequest2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80817
|
-
const applied = applyMeshHostJoinRequest2(meshId, {
|
|
80818
|
-
token,
|
|
80819
|
-
memberNode,
|
|
80820
|
-
memberMeshId: typeof args?.memberMeshId === "string" ? args.memberMeshId : void 0
|
|
80821
|
-
});
|
|
80822
|
-
if (!applied) return { success: false, error: "Mesh not found" };
|
|
80823
|
-
if (!applied.accepted) {
|
|
80824
|
-
return {
|
|
80825
|
-
success: false,
|
|
80826
|
-
code: "mesh_host_join_rejected",
|
|
80827
|
-
meshId,
|
|
80828
|
-
tokenId: applied.tokenId,
|
|
80829
|
-
meshHost: applied.meshHost ? resolveMeshHostStatus({ meshHost: applied.meshHost }) : void 0,
|
|
80830
|
-
error: applied.reason
|
|
80831
|
-
};
|
|
80832
|
-
}
|
|
80833
|
-
this.inlineMeshCache.set(meshId, applied.mesh);
|
|
80834
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
80835
|
-
try {
|
|
80836
|
-
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
80837
|
-
appendLedgerEntry2(meshId, {
|
|
80838
|
-
kind: "node_joined",
|
|
80839
|
-
nodeId: applied.node.id,
|
|
80840
|
-
payload: { role: "member", tokenId: applied.tokenId, workspace: applied.node.workspace }
|
|
80841
|
-
});
|
|
80842
|
-
} catch {
|
|
80843
|
-
}
|
|
80844
|
-
return {
|
|
80845
|
-
success: true,
|
|
80846
|
-
code: "mesh_host_join_accepted",
|
|
80847
|
-
meshId,
|
|
80848
|
-
node: applied.node,
|
|
80849
|
-
tokenId: applied.tokenId,
|
|
80850
|
-
meshHost: resolveMeshHostStatus(applied.mesh)
|
|
80851
|
-
};
|
|
80852
|
-
} catch (e) {
|
|
80853
|
-
return { success: false, code: "mesh_host_join_failed", meshId, error: e.message };
|
|
80854
|
-
}
|
|
80855
|
-
}
|
|
80856
|
-
case "join_mesh_host_pairing": {
|
|
80857
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80858
|
-
const token = typeof args?.token === "string" ? args.token.trim() : "";
|
|
80859
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80860
|
-
if (!token) return { success: false, error: "token required because raw pairing tokens are not persisted" };
|
|
80861
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
80862
|
-
const mesh = meshRecord?.mesh;
|
|
80863
|
-
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
80864
|
-
const meshHost = resolveMeshHostStatus(mesh);
|
|
80865
|
-
if (meshHost.role !== "member") {
|
|
80866
|
-
return { success: false, code: "mesh_host_join_not_member", meshId, meshHost, error: "join_mesh_host_pairing must run from a member daemon configured with a Mesh Host address/token." };
|
|
80867
|
-
}
|
|
80868
|
-
try {
|
|
80869
|
-
const { tokenIdForManualPairing: tokenIdForManualPairing2, markMeshHostPairingJoined: markMeshHostPairingJoined2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80870
|
-
const tokenId = tokenIdForManualPairing2(token);
|
|
80871
|
-
if (meshHost.pairing?.tokenId && meshHost.pairing.tokenId !== tokenId) {
|
|
80872
|
-
return { success: false, code: "mesh_host_join_rejected", meshId, tokenId, meshHost, error: "invalid pairing token" };
|
|
80873
|
-
}
|
|
80874
|
-
const memberNode = buildMemberJoinNode(mesh, args, this.deps.statusInstanceId);
|
|
80875
|
-
if (!memberNode) return { success: false, error: "member node metadata unavailable" };
|
|
80876
|
-
const hostMeshId = typeof args?.hostMeshId === "string" && args.hostMeshId.trim() ? args.hostMeshId.trim() : meshId;
|
|
80877
|
-
const hostDaemonId = typeof args?.hostDaemonId === "string" && args.hostDaemonId.trim() ? args.hostDaemonId.trim() : meshHost.hostDaemonId;
|
|
80878
|
-
let hostResult;
|
|
80879
|
-
let transport;
|
|
80880
|
-
if (hostDaemonId && this.deps.dispatchMeshCommand) {
|
|
80881
|
-
transport = "mesh_command_dispatch";
|
|
80882
|
-
hostResult = await this.deps.dispatchMeshCommand(hostDaemonId, "apply_mesh_host_join", {
|
|
80883
|
-
meshId: hostMeshId,
|
|
80884
|
-
token,
|
|
80885
|
-
memberMeshId: meshId,
|
|
80886
|
-
memberNode
|
|
80887
|
-
});
|
|
80888
|
-
} else if (meshHost.hostAddress) {
|
|
80889
|
-
transport = "standalone_http_command";
|
|
80890
|
-
const commandUrl = normalizeStandaloneHostCommandUrl(meshHost.hostAddress);
|
|
80891
|
-
const response = await fetch(commandUrl, {
|
|
80892
|
-
method: "POST",
|
|
80893
|
-
headers: { "Content-Type": "application/json" },
|
|
80894
|
-
body: JSON.stringify({ type: "apply_mesh_host_join", payload: { meshId: hostMeshId, token, memberMeshId: meshId, memberNode } })
|
|
80895
|
-
});
|
|
80896
|
-
hostResult = await response.json().catch(() => ({ success: false, error: `Host returned HTTP ${response.status}` }));
|
|
80897
|
-
if (!response.ok && hostResult?.success !== false) hostResult = { success: false, error: `Host returned HTTP ${response.status}` };
|
|
80898
|
-
} else {
|
|
80899
|
-
return {
|
|
80900
|
-
success: false,
|
|
80901
|
-
code: "mesh_host_join_transport_unavailable",
|
|
80902
|
-
meshId,
|
|
80903
|
-
meshHost,
|
|
80904
|
-
error: "No hostDaemonId dispatch path or hostAddress HTTP command path is available. P2P signaling join is not implemented in this slice."
|
|
80905
|
-
};
|
|
80906
|
-
}
|
|
80907
|
-
if (!hostResult?.success) {
|
|
80908
|
-
return { success: false, code: hostResult?.code || "mesh_host_join_rejected", meshId, meshHost, transport, error: hostResult?.error || "Mesh Host rejected join request", hostResult };
|
|
80909
|
-
}
|
|
80910
|
-
const joined = meshRecord.inline ? null : markMeshHostPairingJoined2(meshId, {
|
|
80911
|
-
tokenId: hostResult.tokenId || tokenId,
|
|
80912
|
-
hostDaemonId: hostResult.meshHost?.hostDaemonId || hostDaemonId,
|
|
80913
|
-
hostNodeId: hostResult.meshHost?.hostNodeId,
|
|
80914
|
-
joinedAt: hostResult.meshHost?.pairing?.joinedAt
|
|
80915
|
-
});
|
|
80916
|
-
if (joined) {
|
|
80917
|
-
this.inlineMeshCache.set(meshId, joined.mesh);
|
|
80918
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
80919
|
-
}
|
|
80920
|
-
return {
|
|
80921
|
-
success: true,
|
|
80922
|
-
code: "mesh_host_join_applied",
|
|
80923
|
-
meshId,
|
|
80924
|
-
hostMeshId,
|
|
80925
|
-
transport,
|
|
80926
|
-
node: hostResult.node,
|
|
80927
|
-
tokenId: hostResult.tokenId || tokenId,
|
|
80928
|
-
meshHost: joined ? resolveMeshHostStatus(joined.mesh) : { ...meshHost, pairing: { ...meshHost.pairing || {}, status: "paired", tokenId: hostResult.tokenId || tokenId } },
|
|
80929
|
-
hostResult,
|
|
80930
|
-
manualPairing: {
|
|
80931
|
-
status: "paired",
|
|
80932
|
-
joinImplemented: true,
|
|
80933
|
-
protocol: "standalone_command_direct_v1",
|
|
80934
|
-
description: "Mesh Host accepted the join and local member pairing status was marked paired. P2P runtime signaling remains outside this slice."
|
|
80935
|
-
}
|
|
80936
|
-
};
|
|
80937
|
-
} catch (e) {
|
|
80938
|
-
return { success: false, code: "mesh_host_join_failed", meshId, meshHost, error: e.message };
|
|
80939
|
-
}
|
|
80940
|
-
}
|
|
80941
|
-
case "delete_mesh": {
|
|
80942
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80943
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80944
|
-
try {
|
|
80945
|
-
const { deleteMesh: deleteMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
80946
|
-
const deleted = deleteMesh2(meshId);
|
|
80947
|
-
return { success: true, deleted };
|
|
80948
|
-
} catch (e) {
|
|
80949
|
-
return { success: false, error: e.message };
|
|
80950
|
-
}
|
|
80951
|
-
}
|
|
80952
|
-
case "get_mesh_queue": {
|
|
80953
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80954
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
80955
|
-
try {
|
|
80956
|
-
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
80957
|
-
const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
|
|
80958
|
-
const rawQueue = getQueue2(meshId, { status });
|
|
80959
|
-
const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
|
|
80960
|
-
const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
|
|
80961
|
-
const summary = getMeshQueueStats2(meshId);
|
|
80962
|
-
return {
|
|
80963
|
-
success: true,
|
|
80964
|
-
queue,
|
|
80965
|
-
summary,
|
|
80966
|
-
sourceOfTruth: {
|
|
80967
|
-
kind: "mesh_work_queue_file",
|
|
80968
|
-
activeStatuses: ["pending", "assigned"],
|
|
80969
|
-
historicalStatuses: ["completed", "failed", "cancelled"],
|
|
80970
|
-
notes: "pending/assigned are active work; completed/failed/cancelled are historical records."
|
|
80971
|
-
}
|
|
80972
|
-
};
|
|
80973
|
-
} catch (e) {
|
|
80974
|
-
return { success: false, error: e.message };
|
|
80975
|
-
}
|
|
80976
|
-
}
|
|
80977
|
-
case "cancel_mesh_queue_task": {
|
|
80978
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80979
|
-
const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
|
|
80980
|
-
if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
|
|
80981
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue cancellation");
|
|
80982
|
-
if (ownerFailure) return ownerFailure;
|
|
80983
|
-
try {
|
|
80984
|
-
const { cancelTask: cancelTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
80985
|
-
const reason = typeof args?.reason === "string" ? args.reason : void 0;
|
|
80986
|
-
const task = cancelTask2(meshId, taskId, { reason });
|
|
80987
|
-
if (!task) return { success: false, error: `Queue task '${taskId}' not found` };
|
|
80988
|
-
return { success: true, task };
|
|
80989
|
-
} catch (e) {
|
|
80990
|
-
return { success: false, error: e.message };
|
|
80991
|
-
}
|
|
80992
|
-
}
|
|
80993
|
-
case "requeue_mesh_queue_task": {
|
|
80994
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
80995
|
-
const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
|
|
80996
|
-
if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
|
|
80997
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue requeue");
|
|
80998
|
-
if (ownerFailure) return ownerFailure;
|
|
80999
|
-
try {
|
|
81000
|
-
const { requeueTask: requeueTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
81001
|
-
const task = requeueTask2(meshId, taskId, {
|
|
81002
|
-
reason: typeof args?.reason === "string" ? args.reason : void 0,
|
|
81003
|
-
targetNodeId: typeof args?.targetNodeId === "string" ? args.targetNodeId.trim() : void 0,
|
|
81004
|
-
targetSessionId: typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : void 0,
|
|
81005
|
-
clearTargetNode: args?.clearTargetNode === true,
|
|
81006
|
-
clearTargetSession: args?.clearTargetSession !== false
|
|
81007
|
-
});
|
|
81008
|
-
if (!task) return { success: false, error: `Queue task '${taskId}' not found` };
|
|
81009
|
-
return { success: true, task };
|
|
81010
|
-
} catch (e) {
|
|
81011
|
-
return { success: false, error: e.message };
|
|
81012
|
-
}
|
|
81013
|
-
}
|
|
81014
|
-
case "add_mesh_node": {
|
|
81015
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81016
|
-
const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
81017
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
81018
|
-
if (!workspace) return { success: false, error: "workspace required" };
|
|
81019
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node addition");
|
|
81020
|
-
if (ownerFailure) return ownerFailure;
|
|
81021
|
-
try {
|
|
81022
|
-
const { addNode: addNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
81023
|
-
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
81024
|
-
const readOnly = args?.readOnly === true;
|
|
81025
|
-
const providerRoles = normalizeProviderRoles(args?.providerRoles);
|
|
81026
|
-
const policy = {
|
|
81027
|
-
...readOnly ? { readOnly: true } : {},
|
|
81028
|
-
...providerPriority.length ? { providerPriority } : {},
|
|
81029
|
-
...providerRoles.length ? { providerRoles } : {}
|
|
81030
|
-
};
|
|
81031
|
-
const role = normalizeMeshDaemonRole(args?.role);
|
|
81032
|
-
const daemonId = typeof args?.daemonId === "string" && args.daemonId.trim() ? args.daemonId.trim() : void 0;
|
|
81033
|
-
const machineId = typeof args?.machineId === "string" && args.machineId.trim() ? args.machineId.trim() : void 0;
|
|
81034
|
-
const repoRoot = typeof args?.repoRoot === "string" && args.repoRoot.trim() ? args.repoRoot.trim() : void 0;
|
|
81035
|
-
const node = addNode2(meshId, {
|
|
81036
|
-
workspace,
|
|
81037
|
-
...repoRoot ? { repoRoot } : {},
|
|
81038
|
-
...daemonId ? { daemonId } : {},
|
|
81039
|
-
...machineId ? { machineId } : {},
|
|
81040
|
-
...policy ? { policy } : {},
|
|
81041
|
-
...role ? { role } : {}
|
|
81042
|
-
});
|
|
81043
|
-
if (!node) return { success: false, error: "Mesh not found" };
|
|
81044
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
81045
|
-
return { success: true, node };
|
|
81046
|
-
} catch (e) {
|
|
81047
|
-
return { success: false, error: e.message };
|
|
81048
|
-
}
|
|
81049
|
-
}
|
|
81050
|
-
case "update_mesh_node": {
|
|
81051
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81052
|
-
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
81053
|
-
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
81054
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node update");
|
|
81055
|
-
if (ownerFailure) return ownerFailure;
|
|
81056
|
-
try {
|
|
81057
|
-
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
81058
|
-
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
81059
|
-
if (Array.isArray(args?.providerPriority)) {
|
|
81060
|
-
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
81061
|
-
delete policy.provider_priority;
|
|
81062
|
-
if (providerPriority.length) {
|
|
81063
|
-
policy.providerPriority = providerPriority;
|
|
81064
|
-
} else {
|
|
81065
|
-
delete policy.providerPriority;
|
|
81066
|
-
}
|
|
81067
|
-
}
|
|
81068
|
-
if (Array.isArray(args?.providerRoles)) {
|
|
81069
|
-
const providerRoles = normalizeProviderRoles(args.providerRoles);
|
|
81070
|
-
if (providerRoles.length) {
|
|
81071
|
-
policy.providerRoles = providerRoles;
|
|
81072
|
-
} else {
|
|
81073
|
-
delete policy.providerRoles;
|
|
81074
|
-
}
|
|
81075
|
-
}
|
|
81076
|
-
const patch = { policy };
|
|
81077
|
-
if (typeof args?.systemPrompt === "string") {
|
|
81078
|
-
const trimmed = args.systemPrompt.trim();
|
|
81079
|
-
patch.systemPrompt = trimmed || void 0;
|
|
81080
|
-
} else if (args?.systemPrompt === null) {
|
|
81081
|
-
patch.systemPrompt = void 0;
|
|
81082
|
-
}
|
|
81083
|
-
const node = updateNode2(meshId, nodeId, patch);
|
|
81084
|
-
if (!node) return { success: false, error: "Mesh node not found" };
|
|
81085
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
81086
|
-
return { success: true, node };
|
|
81087
|
-
} catch (e) {
|
|
81088
|
-
return { success: false, error: e.message };
|
|
81089
|
-
}
|
|
81090
|
-
}
|
|
81091
|
-
case "cleanup_mesh_sessions": {
|
|
81092
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81093
|
-
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
81094
|
-
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
81095
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node removal");
|
|
81096
|
-
if (ownerFailure) return ownerFailure;
|
|
81097
|
-
try {
|
|
81098
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81099
|
-
const mesh = meshRecord?.mesh;
|
|
81100
|
-
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
81101
|
-
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
81102
|
-
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
81103
|
-
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
81104
|
-
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
81105
|
-
const result = await this.cleanupMeshSessions({
|
|
81106
|
-
meshId,
|
|
81107
|
-
nodeId,
|
|
81108
|
-
node,
|
|
81109
|
-
mode,
|
|
81110
|
-
sessionIds,
|
|
81111
|
-
dryRun: args?.dryRun === true,
|
|
81112
|
-
source: "mesh_cleanup_sessions"
|
|
81113
|
-
});
|
|
81114
|
-
return result;
|
|
81115
|
-
} catch (e) {
|
|
81116
|
-
return { success: false, error: e.message };
|
|
81117
|
-
}
|
|
81118
|
-
}
|
|
81119
|
-
case "mesh_init": {
|
|
81120
|
-
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
81121
|
-
const mesh = args?.inlineMesh || {};
|
|
81122
|
-
try {
|
|
81123
|
-
const detected = await detectCLIs(this.deps.providerLoader, { includeVersion: true });
|
|
81124
|
-
return { ...runMeshInit(mesh, workspace, detected, {
|
|
81125
|
-
write: args?.write === true,
|
|
81126
|
-
overwrite: args?.overwrite === true
|
|
81127
|
-
}) };
|
|
81128
|
-
} catch (e) {
|
|
81129
|
-
return { success: false, error: e?.message || String(e) };
|
|
81130
|
-
}
|
|
81131
|
-
}
|
|
81132
|
-
case "plan_mesh_refine_node": {
|
|
81133
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81134
|
-
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
81135
|
-
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
81136
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81137
|
-
const mesh = meshRecord?.mesh;
|
|
81138
|
-
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
81139
|
-
if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
|
|
81140
|
-
return {
|
|
81141
|
-
success: true,
|
|
81142
|
-
dryRun: true,
|
|
81143
|
-
nodeId,
|
|
81144
|
-
workspace: node.workspace,
|
|
81145
|
-
validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
|
|
81146
|
-
mergeWillRun: false,
|
|
81147
|
-
cleanupWillRun: false
|
|
81148
|
-
};
|
|
81149
|
-
}
|
|
81150
|
-
case "fast_forward_mesh_node": {
|
|
81151
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81152
|
-
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
81153
|
-
let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
81154
|
-
let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
81155
|
-
let nodeDaemonId;
|
|
81156
|
-
let allowAutoPublishSubmoduleMainCommits = false;
|
|
81157
|
-
if (meshId && nodeId) {
|
|
81158
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81159
|
-
const mesh = meshRecord?.mesh;
|
|
81160
|
-
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
81161
|
-
if (!workspace) {
|
|
81162
|
-
workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
|
|
81163
|
-
}
|
|
81164
|
-
if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
|
|
81165
|
-
submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
|
|
81166
|
-
}
|
|
81167
|
-
allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
|
|
81168
|
-
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
81169
|
-
}
|
|
81170
|
-
const selfDaemonId = this.deps.statusInstanceId;
|
|
81171
|
-
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
81172
|
-
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
81173
|
-
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
81174
|
-
...typeof args === "object" && args !== null ? args : {},
|
|
81175
|
-
workspace,
|
|
81176
|
-
_meshDirectDispatch: true
|
|
81177
|
-
});
|
|
81178
|
-
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
81179
|
-
}
|
|
81180
|
-
const result = await fastForwardMeshNode({
|
|
81181
|
-
meshId: meshId || void 0,
|
|
81182
|
-
nodeId: nodeId || void 0,
|
|
81183
|
-
workspace,
|
|
81184
|
-
branch: typeof args?.branch === "string" ? args.branch : void 0,
|
|
81185
|
-
execute: args?.execute === true,
|
|
81186
|
-
dryRun: args?.dryRun === true,
|
|
81187
|
-
updateSubmodules: args?.updateSubmodules === true,
|
|
81188
|
-
submoduleIgnorePaths,
|
|
81189
|
-
mode: args?.mode === "push" ? "push" : "merge",
|
|
81190
|
-
pushSubmodules: args?.pushSubmodules === true,
|
|
81191
|
-
allowAutoPublishSubmoduleMainCommits
|
|
81192
|
-
});
|
|
81193
|
-
return result;
|
|
81194
|
-
}
|
|
81195
|
-
case "refine_mesh_node": {
|
|
81196
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81197
|
-
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
81198
|
-
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
81199
|
-
{
|
|
81200
|
-
const meshRecordForForward = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81201
|
-
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
81202
|
-
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
81203
|
-
const selfDaemonId = this.deps.statusInstanceId;
|
|
81204
|
-
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
81205
|
-
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
81206
|
-
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
81207
|
-
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
81208
|
-
...typeof args === "object" && args !== null ? args : {},
|
|
81209
|
-
coordinatorDaemonId: callerCoordinatorDaemonId || selfDaemonId,
|
|
81210
|
-
_meshDirectDispatch: true
|
|
81211
|
-
});
|
|
81212
|
-
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
81213
|
-
}
|
|
81214
|
-
}
|
|
81215
|
-
const isDryRun = args?.dryRun !== false && args?.execute !== true;
|
|
81216
|
-
if (isDryRun) {
|
|
81217
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81218
|
-
const mesh = meshRecord?.mesh;
|
|
81219
|
-
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
81220
|
-
if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
|
|
81221
|
-
return {
|
|
81222
|
-
success: true,
|
|
81223
|
-
dryRun: true,
|
|
81224
|
-
nodeId,
|
|
81225
|
-
workspace: node.workspace,
|
|
81226
|
-
validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
|
|
81227
|
-
mergeWillRun: false,
|
|
81228
|
-
cleanupWillRun: false,
|
|
81229
|
-
hint: "Dry-run only \u2014 no merge/push/cleanup performed. Re-invoke with execute:true to converge this node."
|
|
81230
|
-
};
|
|
81231
|
-
}
|
|
81232
|
-
return this.startMeshRefineJob(meshId, nodeId, args);
|
|
81233
|
-
}
|
|
81234
|
-
case "batch_refine_mesh_nodes": {
|
|
81235
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81236
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
81237
|
-
const requestedNodeIds = Array.isArray(args?.nodeIds) ? args.nodeIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
|
|
81238
|
-
const isDryRun = args?.dryRun !== false && args?.execute !== true;
|
|
81239
|
-
if (isDryRun) return this.batchRefineMeshNodes(meshId, requestedNodeIds, args);
|
|
81240
|
-
return this.startMeshRefineBatchJob(meshId, requestedNodeIds, args);
|
|
81241
|
-
}
|
|
81242
|
-
case "remove_mesh_node": {
|
|
81243
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81244
|
-
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
81245
|
-
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
81246
|
-
try {
|
|
81247
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81248
|
-
const mesh = meshRecord?.mesh;
|
|
81249
|
-
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
81250
|
-
if (node && !args?._meshDirectDispatch && node.isLocalWorktree !== true && args?.force !== true) {
|
|
81251
|
-
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : "";
|
|
81252
|
-
const nodeMachineId = readMeshNodeMachineId(node) || "";
|
|
81253
|
-
const selfDaemonId = this.deps.statusInstanceId || "";
|
|
81254
|
-
const selfMachineId = (() => {
|
|
81255
|
-
try {
|
|
81256
|
-
return loadConfig2().machineId || "";
|
|
81257
|
-
} catch {
|
|
81258
|
-
return "";
|
|
81259
|
-
}
|
|
81260
|
-
})();
|
|
81261
|
-
const isCoordinatorBaseNode = !!selfDaemonId && (nodeDaemonId === selfDaemonId || nodeMachineId === selfDaemonId) || !!selfMachineId && (nodeDaemonId === selfMachineId || nodeMachineId === selfMachineId);
|
|
81262
|
-
if (isCoordinatorBaseNode) {
|
|
81263
|
-
return {
|
|
81264
|
-
success: false,
|
|
81265
|
-
removed: false,
|
|
81266
|
-
code: "mesh_remove_coordinator_base_node_protected",
|
|
81267
|
-
error: `Refusing to remove the coordinator's own base node '${typeof node.workspace === "string" ? node.workspace : nodeId}'. It is the local non-worktree node bound to this coordinator daemon; removing it breaks live mesh membership and forces a restart.`,
|
|
81268
|
-
recoveryHint: "Remove worktree clone nodes instead, or pass force:true only if you are intentionally tearing down this mesh and accept that the coordinator must be re-registered/restarted."
|
|
81269
|
-
};
|
|
81270
|
-
}
|
|
81271
|
-
}
|
|
81272
|
-
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
81273
|
-
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
81274
|
-
);
|
|
81275
|
-
const explicitSessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
|
|
81276
|
-
let sessionCleanup;
|
|
81277
|
-
if (node && sessionCleanupMode !== "preserve") {
|
|
81278
|
-
sessionCleanup = await this.cleanupMeshSessions({
|
|
81279
|
-
meshId,
|
|
81280
|
-
nodeId,
|
|
81281
|
-
node,
|
|
81282
|
-
mode: sessionCleanupMode,
|
|
81283
|
-
...explicitSessionIds && explicitSessionIds.length > 0 ? { sessionIds: explicitSessionIds } : {},
|
|
81284
|
-
source: "mesh_remove_node"
|
|
81285
|
-
});
|
|
81286
|
-
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
81287
|
-
}
|
|
81288
|
-
let worktreeCleanup;
|
|
81289
|
-
if (node?.isLocalWorktree) {
|
|
81290
|
-
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
81291
|
-
const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
|
|
81292
|
-
if (isRemoteWorktree) {
|
|
81293
|
-
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
|
|
81294
|
-
...typeof args === "object" && args !== null ? args : {},
|
|
81295
|
-
_meshDirectDispatch: true
|
|
81296
|
-
});
|
|
81297
|
-
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
81298
|
-
}
|
|
81299
|
-
const cleanupResult = await this.cleanupLocalWorktreeNode({ mesh, node, nodeId, force: args?.force === true });
|
|
81300
|
-
if (cleanupResult.success === false) {
|
|
81301
|
-
return {
|
|
81302
|
-
success: false,
|
|
81303
|
-
removed: false,
|
|
81304
|
-
code: cleanupResult.code,
|
|
81305
|
-
error: cleanupResult.error,
|
|
81306
|
-
recoveryHint: cleanupResult.recoveryHint,
|
|
81307
|
-
...sessionCleanup ? { sessionCleanup } : {},
|
|
81308
|
-
worktreeCleanup: cleanupResult
|
|
81309
|
-
};
|
|
81310
|
-
}
|
|
81311
|
-
worktreeCleanup = cleanupResult;
|
|
81312
|
-
}
|
|
81313
|
-
let removed = false;
|
|
81314
|
-
if (meshRecord?.inline) {
|
|
81315
|
-
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
81316
|
-
if (removed) this.invalidateAggregateMeshStatus(meshId);
|
|
81317
|
-
if (!removed && !node) removed = true;
|
|
81318
|
-
} else {
|
|
81319
|
-
const { removeNode: removeNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
81320
|
-
removed = removeNode2(meshId, nodeId);
|
|
81321
|
-
if (!removed && !node) removed = true;
|
|
81322
|
-
if (removed) this.invalidateAggregateMeshStatus(meshId);
|
|
81323
|
-
}
|
|
81324
|
-
if (removed) {
|
|
81325
|
-
try {
|
|
81326
|
-
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
81327
|
-
appendLedgerEntry2(meshId, {
|
|
81328
|
-
kind: "node_removed",
|
|
81329
|
-
nodeId,
|
|
81330
|
-
payload: {
|
|
81331
|
-
worktree: !!node?.isLocalWorktree,
|
|
81332
|
-
sessionCleanupMode,
|
|
81333
|
-
workspace: typeof node?.workspace === "string" ? node.workspace : void 0,
|
|
81334
|
-
daemonId: typeof node?.daemonId === "string" ? node.daemonId : void 0,
|
|
81335
|
-
worktreeBranch: typeof node?.worktreeBranch === "string" ? node.worktreeBranch : void 0,
|
|
81336
|
-
worktreeCleanupFallback: typeof worktreeCleanup?.fallback === "string" ? worktreeCleanup.fallback : void 0,
|
|
81337
|
-
forced: worktreeCleanup?.forced === true ? true : void 0,
|
|
81338
|
-
forceFallbackReason: typeof worktreeCleanup?.reason === "string" ? worktreeCleanup.reason : void 0
|
|
81339
|
-
}
|
|
81340
|
-
});
|
|
81341
|
-
} catch {
|
|
81342
|
-
}
|
|
81343
|
-
}
|
|
81344
|
-
const residueWarning = worktreeCleanup?.residue === true && typeof worktreeCleanup?.residueWarning === "string" ? worktreeCleanup.residueWarning : void 0;
|
|
81345
|
-
return {
|
|
81346
|
-
success: true,
|
|
81347
|
-
removed,
|
|
81348
|
-
...residueWarning ? { residueWarning } : {},
|
|
81349
|
-
...sessionCleanup ? { sessionCleanup } : {},
|
|
81350
|
-
...worktreeCleanup ? { worktreeCleanup } : {}
|
|
81351
|
-
};
|
|
81352
|
-
} catch (e) {
|
|
81353
|
-
return { success: false, error: e.message };
|
|
81354
|
-
}
|
|
81355
|
-
}
|
|
81356
|
-
case "clone_mesh_node": {
|
|
81357
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81358
|
-
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
81359
|
-
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
81360
|
-
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
81361
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
81362
|
-
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
81363
|
-
if (!branch) return { success: false, error: "branch required" };
|
|
81364
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "worktree clone");
|
|
81365
|
-
if (ownerFailure) return ownerFailure;
|
|
81366
|
-
try {
|
|
81367
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81368
|
-
const mesh = meshRecord?.mesh;
|
|
81369
|
-
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
81370
|
-
const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
|
|
81371
|
-
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
81372
|
-
const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
|
|
81373
|
-
if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
81374
|
-
const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
|
|
81375
|
-
...typeof args === "object" && args !== null ? args : {},
|
|
81376
|
-
_meshDirectDispatch: true
|
|
81377
|
-
});
|
|
81378
|
-
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
81379
|
-
}
|
|
81380
|
-
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
81381
|
-
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
81382
|
-
const result = await createWorktree2({
|
|
81383
|
-
repoRoot,
|
|
81384
|
-
branch,
|
|
81385
|
-
baseBranch,
|
|
81386
|
-
meshName: mesh.name
|
|
81387
|
-
});
|
|
81388
|
-
let node;
|
|
81389
|
-
if (meshRecord.inline) {
|
|
81390
|
-
const { randomUUID: randomUUID15 } = await import("crypto");
|
|
81391
|
-
node = {
|
|
81392
|
-
id: `node_${randomUUID15().replace(/-/g, "")}`,
|
|
81393
|
-
workspace: result.worktreePath,
|
|
81394
|
-
repoRoot: result.worktreePath,
|
|
81395
|
-
daemonId: sourceNode.daemonId,
|
|
81396
|
-
machineId: sourceNode.machineId ?? sourceNode.machine_id,
|
|
81397
|
-
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
81398
|
-
policy: { ...sourceNode.policy || {} },
|
|
81399
|
-
isLocalWorktree: true,
|
|
81400
|
-
worktreeBranch: result.branch,
|
|
81401
|
-
clonedFromNodeId: sourceNodeId
|
|
81402
|
-
};
|
|
81403
|
-
this.updateInlineMeshNode(meshId, mesh, node);
|
|
81404
|
-
} else {
|
|
81405
|
-
const { addNode: addNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
81406
|
-
node = addNode2(meshId, {
|
|
81407
|
-
workspace: result.worktreePath,
|
|
81408
|
-
repoRoot: result.worktreePath,
|
|
81409
|
-
daemonId: sourceNode.daemonId,
|
|
81410
|
-
machineId: sourceNode.machineId ?? sourceNode.machine_id,
|
|
81411
|
-
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
81412
|
-
isLocalWorktree: true,
|
|
81413
|
-
worktreeBranch: result.branch,
|
|
81414
|
-
clonedFromNodeId: sourceNodeId,
|
|
81415
|
-
policy: { ...sourceNode.policy || {} }
|
|
81416
|
-
});
|
|
81417
|
-
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
81418
|
-
const inlineForReconcile = this.getCachedInlineMesh(meshId);
|
|
81419
|
-
if (inlineForReconcile) this.updateInlineMeshNode(meshId, inlineForReconcile, node);
|
|
81420
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
81421
|
-
}
|
|
81422
|
-
const persistWorktreeSetupState = async (bootstrapState2) => {
|
|
81423
|
-
node.worktreeBootstrap = bootstrapState2;
|
|
81424
|
-
if (meshRecord.inline) {
|
|
81425
|
-
this.updateInlineMeshNode(meshId, mesh, node);
|
|
81426
|
-
return;
|
|
81427
|
-
}
|
|
81428
|
-
try {
|
|
81429
|
-
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
81430
|
-
updateNode2(meshId, node.id, { worktreeBootstrap: bootstrapState2 });
|
|
81431
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
81432
|
-
} catch {
|
|
81433
|
-
}
|
|
81434
|
-
};
|
|
81435
|
-
const appendCloneLedger = async (initSubmodules2, bootstrapState2) => {
|
|
81436
|
-
try {
|
|
81437
|
-
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
81438
|
-
appendLedgerEntry2(meshId, {
|
|
81439
|
-
kind: "node_cloned",
|
|
81440
|
-
nodeId: node.id,
|
|
81441
|
-
payload: {
|
|
81442
|
-
sourceNodeId,
|
|
81443
|
-
branch: result.branch,
|
|
81444
|
-
worktreePath: result.worktreePath,
|
|
81445
|
-
submodulesInitialized: initSubmodules2,
|
|
81446
|
-
worktreeBootstrap: {
|
|
81447
|
-
status: bootstrapState2.status,
|
|
81448
|
-
required: bootstrapState2.required,
|
|
81449
|
-
configSource: bootstrapState2.configSource,
|
|
81450
|
-
configSourceType: bootstrapState2.configSourceType,
|
|
81451
|
-
lastCommand: bootstrapState2.lastCommand,
|
|
81452
|
-
exitCode: bootstrapState2.exitCode
|
|
81453
|
-
}
|
|
81454
|
-
}
|
|
81455
|
-
});
|
|
81456
|
-
} catch {
|
|
81457
|
-
}
|
|
81458
|
-
};
|
|
81459
|
-
const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
|
|
81460
|
-
const loadedBootstrap = loadMeshWorktreeBootstrapConfig(mesh, result.worktreePath);
|
|
81461
|
-
const runningBootstrapState = {
|
|
81462
|
-
status: "running",
|
|
81463
|
-
required: loadedBootstrap.config?.required !== false,
|
|
81464
|
-
configSource: loadedBootstrap.path || loadedBootstrap.source,
|
|
81465
|
-
configSourceType: loadedBootstrap.sourceType,
|
|
81466
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
81467
|
-
};
|
|
81468
|
-
await persistWorktreeSetupState(runningBootstrapState);
|
|
81469
|
-
const finishWorktreeSetup = async () => {
|
|
81470
|
-
let submodulesInitialized2 = false;
|
|
81471
|
-
if (initSubmodules) {
|
|
81472
|
-
try {
|
|
81473
|
-
const { runGit: runGit3 } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
|
|
81474
|
-
await runGit3(
|
|
81475
|
-
{ workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true },
|
|
81476
|
-
["submodule", "update", "--init", "--recursive"],
|
|
81477
|
-
{ timeoutMs: 12e4 }
|
|
81478
|
-
);
|
|
81479
|
-
submodulesInitialized2 = true;
|
|
81480
|
-
const sourceWorkspace = sourceNode.repoRoot || sourceNode.workspace;
|
|
81481
|
-
if (sourceWorkspace) {
|
|
81482
|
-
try {
|
|
81483
|
-
const { runGit: rg } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
|
|
81484
|
-
const sourceCtx = { workspace: sourceWorkspace, repoRoot: sourceWorkspace, isGitRepo: true };
|
|
81485
|
-
const worktreeCtx = { workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true };
|
|
81486
|
-
const sourceStatusOut = await rg(sourceCtx, ["submodule", "status", "oss"], { timeoutMs: 1e4 });
|
|
81487
|
-
const sourceStatusLine = (typeof sourceStatusOut === "string" ? sourceStatusOut : sourceStatusOut?.stdout ?? "").trim();
|
|
81488
|
-
const sourceShaMatch = sourceStatusLine.match(/^[+\- ]?([0-9a-f]{40})/);
|
|
81489
|
-
const sourceSha = sourceShaMatch?.[1];
|
|
81490
|
-
if (sourceSha) {
|
|
81491
|
-
const ossCtx = { workspace: `${result.worktreePath}/oss`, repoRoot: `${result.worktreePath}/oss`, isGitRepo: true };
|
|
81492
|
-
const worktreeOssHeadOut = await rg(ossCtx, ["rev-parse", "HEAD"], { timeoutMs: 1e4 });
|
|
81493
|
-
const worktreeOssSha = (typeof worktreeOssHeadOut === "string" ? worktreeOssHeadOut : worktreeOssHeadOut?.stdout ?? "").trim();
|
|
81494
|
-
if (worktreeOssSha !== sourceSha) {
|
|
81495
|
-
await rg(ossCtx, ["fetch", `${sourceWorkspace}/oss`, "HEAD"], { timeoutMs: 6e4 });
|
|
81496
|
-
await rg(ossCtx, ["checkout", sourceSha], { timeoutMs: 1e4 });
|
|
81497
|
-
await rg(worktreeCtx, ["add", "oss"], { timeoutMs: 1e4 });
|
|
81498
|
-
await rg(worktreeCtx, ["commit", "-m", "chore: sync oss to source node HEAD on clone"], { timeoutMs: 1e4 });
|
|
81499
|
-
console.log(`[mesh] Synced oss submodule to source HEAD ${sourceSha.slice(0, 8)} in worktree`);
|
|
81500
|
-
}
|
|
81501
|
-
}
|
|
81502
|
-
} catch (ossErr) {
|
|
81503
|
-
console.warn("[mesh] oss submodule sync to source HEAD failed (best-effort):", ossErr.message);
|
|
81504
|
-
}
|
|
81505
|
-
}
|
|
81506
|
-
} catch (subErr) {
|
|
81507
|
-
console.warn("[mesh] Submodule init failed for worktree:", subErr.message);
|
|
81508
|
-
}
|
|
81509
|
-
}
|
|
81510
|
-
const bootstrapState2 = await runMeshWorktreeBootstrap(mesh, result.worktreePath);
|
|
81511
|
-
await persistWorktreeSetupState(bootstrapState2);
|
|
81512
|
-
await appendCloneLedger(submodulesInitialized2, bootstrapState2);
|
|
81513
|
-
return { submodulesInitialized: submodulesInitialized2, bootstrapState: bootstrapState2 };
|
|
81514
|
-
};
|
|
81515
|
-
const requestedSetupWaitMs = Number(args?.setupWaitMs ?? args?.bootstrapWaitMs ?? 8e3);
|
|
81516
|
-
const setupWaitMs = Number.isFinite(requestedSetupWaitMs) ? Math.min(Math.max(requestedSetupWaitMs, 0), 14e3) : 8e3;
|
|
81517
|
-
const setupPromise = finishWorktreeSetup();
|
|
81518
|
-
const setupResult = await Promise.race([
|
|
81519
|
-
setupPromise.then((value) => ({ completed: true, value })),
|
|
81520
|
-
new Promise((resolve24) => setTimeout(() => resolve24({ completed: false }), setupWaitMs))
|
|
81521
|
-
]);
|
|
81522
|
-
const emitBootstrapEvent = (eventStatus2, bootstrapState2, startedAtMs, extraPayload) => {
|
|
81523
|
-
try {
|
|
81524
|
-
const durationMs = Date.now() - startedAtMs;
|
|
81525
|
-
const event = `worktree_${eventStatus2}`;
|
|
81526
|
-
const metadataEvent = {
|
|
81527
|
-
source: "clone_mesh_node_bootstrap",
|
|
81528
|
-
nodeId: node.id,
|
|
81529
|
-
status: eventStatus2,
|
|
81530
|
-
worktreePath: result.worktreePath,
|
|
81531
|
-
durationMs,
|
|
81532
|
-
bootstrapStatus: bootstrapState2.status,
|
|
81533
|
-
...bootstrapState2.error ? { error: bootstrapState2.error } : {},
|
|
81534
|
-
...bootstrapState2.exitCode !== void 0 ? { exitCode: bootstrapState2.exitCode } : {},
|
|
81535
|
-
...extraPayload || {}
|
|
81536
|
-
};
|
|
81537
|
-
if (typeof this.deps.instanceManager?.getByCategory === "function") {
|
|
81538
|
-
const forwarded = handleMeshForwardEvent(
|
|
81539
|
-
{ instanceManager: this.deps.instanceManager },
|
|
81540
|
-
{ event, meshId, nodeId: node.id, workspace: result.worktreePath, metadataEvent }
|
|
81541
|
-
);
|
|
81542
|
-
if (forwarded?.success === true) return;
|
|
81543
|
-
}
|
|
81544
|
-
queuePendingMeshCoordinatorEvent({
|
|
81545
|
-
event,
|
|
81546
|
-
meshId,
|
|
81547
|
-
nodeLabel: node.id,
|
|
81548
|
-
nodeId: node.id,
|
|
81549
|
-
workspace: result.worktreePath,
|
|
81550
|
-
metadataEvent,
|
|
81551
|
-
queuedAt: Date.now()
|
|
81552
|
-
});
|
|
81553
|
-
} catch {
|
|
81554
|
-
}
|
|
81555
|
-
};
|
|
81556
|
-
const bootstrapStartedMs = Date.now();
|
|
81557
|
-
if (!setupResult.completed) {
|
|
81558
|
-
setupPromise.then(({ bootstrapState: bootstrapState2 }) => {
|
|
81559
|
-
emitBootstrapEvent("bootstrap_complete", bootstrapState2, bootstrapStartedMs);
|
|
81560
|
-
}).catch((error48) => {
|
|
81561
|
-
const failedState = {
|
|
81562
|
-
...runningBootstrapState,
|
|
81563
|
-
status: "failed",
|
|
81564
|
-
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
81565
|
-
error: error48?.message || String(error48)
|
|
81566
|
-
};
|
|
81567
|
-
void persistWorktreeSetupState(failedState);
|
|
81568
|
-
void appendCloneLedger(false, failedState);
|
|
81569
|
-
emitBootstrapEvent("bootstrap_failed", failedState, bootstrapStartedMs, { error: error48?.message || String(error48) });
|
|
81570
|
-
});
|
|
81571
|
-
return {
|
|
81572
|
-
success: true,
|
|
81573
|
-
async: true,
|
|
81574
|
-
status: "accepted",
|
|
81575
|
-
node,
|
|
81576
|
-
worktreePath: result.worktreePath,
|
|
81577
|
-
branch: result.branch,
|
|
81578
|
-
worktreeBootstrap: runningBootstrapState,
|
|
81579
|
-
worktreeSetup: {
|
|
81580
|
-
status: "running",
|
|
81581
|
-
setupWaitMs,
|
|
81582
|
-
message: "Worktree node is registered; submodule/bootstrap setup is continuing in the background."
|
|
81583
|
-
}
|
|
81584
|
-
};
|
|
81585
|
-
}
|
|
81586
|
-
const { submodulesInitialized, bootstrapState } = setupResult.value;
|
|
81587
|
-
emitBootstrapEvent("bootstrap_complete", bootstrapState, bootstrapStartedMs);
|
|
81588
|
-
return {
|
|
81589
|
-
success: true,
|
|
81590
|
-
node,
|
|
81591
|
-
worktreePath: result.worktreePath,
|
|
81592
|
-
branch: result.branch,
|
|
81593
|
-
submodulesInitialized,
|
|
81594
|
-
worktreeBootstrap: bootstrapState
|
|
81595
|
-
};
|
|
81596
|
-
} catch (e) {
|
|
81597
|
-
return { success: false, error: e.message };
|
|
81598
|
-
}
|
|
81599
|
-
}
|
|
81600
|
-
case "retry_mesh_node_bootstrap": {
|
|
81601
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81602
|
-
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
81603
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
81604
|
-
if (!nodeId) return { success: false, error: "nodeId required" };
|
|
81605
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "bootstrap retry");
|
|
81606
|
-
if (ownerFailure) return ownerFailure;
|
|
81607
|
-
try {
|
|
81608
|
-
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
81609
|
-
const mesh = meshRecord?.mesh;
|
|
81610
|
-
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
81611
|
-
const node = mesh.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
81612
|
-
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
81613
|
-
if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
|
|
81614
|
-
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
81615
|
-
if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
81616
|
-
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
|
|
81617
|
-
...typeof args === "object" && args !== null ? args : {},
|
|
81618
|
-
_meshDirectDispatch: true
|
|
81619
|
-
});
|
|
81620
|
-
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
81621
|
-
}
|
|
81622
|
-
const currentBootstrap = node.worktreeBootstrap;
|
|
81623
|
-
if (currentBootstrap?.status === "running") {
|
|
81624
|
-
return { success: false, error: "Bootstrap is already running for this node" };
|
|
81625
|
-
}
|
|
81626
|
-
const worktreePath = node.workspace || node.repoRoot;
|
|
81627
|
-
if (!worktreePath) return { success: false, error: "Node has no workspace path" };
|
|
81628
|
-
const loadedBootstrap = loadMeshWorktreeBootstrapConfig(mesh, worktreePath);
|
|
81629
|
-
const runningState = {
|
|
81630
|
-
status: "running",
|
|
81631
|
-
required: loadedBootstrap.config?.required !== false,
|
|
81632
|
-
configSource: loadedBootstrap.path || loadedBootstrap.source,
|
|
81633
|
-
configSourceType: loadedBootstrap.sourceType,
|
|
81634
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
81635
|
-
};
|
|
81636
|
-
const persistState = async (bootstrapState2) => {
|
|
81637
|
-
node.worktreeBootstrap = bootstrapState2;
|
|
81638
|
-
if (meshRecord.inline) {
|
|
81639
|
-
this.updateInlineMeshNode(meshId, mesh, node);
|
|
81640
|
-
return;
|
|
81641
|
-
}
|
|
81642
|
-
try {
|
|
81643
|
-
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
81644
|
-
updateNode2(meshId, node.id, { worktreeBootstrap: bootstrapState2 });
|
|
81645
|
-
this.invalidateAggregateMeshStatus(meshId);
|
|
81646
|
-
} catch {
|
|
81647
|
-
}
|
|
81648
|
-
};
|
|
81649
|
-
await persistState(runningState);
|
|
81650
|
-
const bootstrapState = await runMeshWorktreeBootstrap(mesh, worktreePath);
|
|
81651
|
-
await persistState(bootstrapState);
|
|
81652
|
-
return { success: true, bootstrapState };
|
|
81653
|
-
} catch (e) {
|
|
81654
|
-
return { success: false, error: e.message };
|
|
81655
|
-
}
|
|
81656
|
-
}
|
|
81657
|
-
case "trigger_mesh_queue": {
|
|
81658
|
-
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
81659
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
81660
|
-
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue trigger");
|
|
81661
|
-
if (ownerFailure) return ownerFailure;
|
|
81662
|
-
try {
|
|
81663
|
-
const { triggerMeshQueue: triggerMeshQueue2, tryAssignQueueTask: tryAssignQueueTask2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
|
|
81664
|
-
const preferredNodeId = typeof args?.preferredNodeId === "string" ? args.preferredNodeId.trim() : "";
|
|
81665
|
-
if (preferredNodeId) {
|
|
81666
|
-
const cliInstances = this.deps.instanceManager.getByCategory("cli");
|
|
81667
|
-
const sorted = [...cliInstances].sort((a, b) => {
|
|
81668
|
-
const aSettings = a.getState().settings || {};
|
|
81669
|
-
const bSettings = b.getState().settings || {};
|
|
81670
|
-
const aNode = readStringValue(aSettings.meshNodeId, aSettings.nodeId);
|
|
81671
|
-
const bNode = readStringValue(bSettings.meshNodeId, bSettings.nodeId);
|
|
81672
|
-
return (aNode === preferredNodeId ? -1 : 0) - (bNode === preferredNodeId ? -1 : 0);
|
|
81673
|
-
});
|
|
81674
|
-
for (const inst of sorted) {
|
|
81675
|
-
const state = inst.getState();
|
|
81676
|
-
const settings = state.settings || {};
|
|
81677
|
-
const nodeId = readStringValue(settings.meshNodeId, settings.nodeId);
|
|
81678
|
-
if (!nodeId || nodeId !== preferredNodeId) continue;
|
|
81679
|
-
const meshNodeFor = readStringValue(settings.meshNodeFor);
|
|
81680
|
-
if (meshNodeFor !== meshId) continue;
|
|
81681
|
-
const status = (readStringValue(state.status) || "").toLowerCase();
|
|
81682
|
-
if (status !== "idle") continue;
|
|
81683
|
-
const sessionId = typeof state.instanceId === "string" ? state.instanceId : "";
|
|
81684
|
-
const providerType = readStringValue(state.type, settings.providerType) || "";
|
|
81685
|
-
if (sessionId && providerType) {
|
|
81686
|
-
tryAssignQueueTask2(this.deps, meshId, nodeId, sessionId, providerType);
|
|
81687
|
-
break;
|
|
81688
|
-
}
|
|
81689
|
-
}
|
|
81690
|
-
}
|
|
81691
|
-
const trigger = await triggerMeshQueue2(this.deps, meshId);
|
|
81692
|
-
return { success: true, trigger };
|
|
81693
|
-
} catch (e) {
|
|
81694
|
-
return { success: false, error: e.message };
|
|
81695
|
-
}
|
|
81696
|
-
}
|
|
81697
81815
|
// ─── Mesh Coordinator Launch ───
|
|
81698
81816
|
case "launch_mesh_coordinator": {
|
|
81699
81817
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|