@adhdev/daemon-standalone 0.9.77-rc.44 → 0.9.77-rc.46
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 +941 -179
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/vendor/mcp-server/index.js +1121 -200
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -22210,7 +22210,33 @@ var require_dist2 = __commonJS({
|
|
|
22210
22210
|
});
|
|
22211
22211
|
} catch (error48) {
|
|
22212
22212
|
const stderr = typeof error48.stderr === "string" ? error48.stderr : "";
|
|
22213
|
-
|
|
22213
|
+
const stdout = typeof error48.stdout === "string" ? error48.stdout : "";
|
|
22214
|
+
const detail = `${stderr}
|
|
22215
|
+
${stdout}
|
|
22216
|
+
${error48.message || ""}`;
|
|
22217
|
+
if (opts.allowSubmoduleForceFallback && SUBMODULE_WORKTREE_REMOVE_RE.test(detail)) {
|
|
22218
|
+
try {
|
|
22219
|
+
await execFileAsync2("git", ["worktree", "remove", "--force", worktreePath], {
|
|
22220
|
+
cwd: repoRoot,
|
|
22221
|
+
encoding: "utf8",
|
|
22222
|
+
timeout: GIT_TIMEOUT_MS,
|
|
22223
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
22224
|
+
windowsHide: true
|
|
22225
|
+
});
|
|
22226
|
+
} catch (forceError) {
|
|
22227
|
+
const forceStderr = typeof forceError.stderr === "string" ? forceError.stderr : "";
|
|
22228
|
+
const forceStdout = typeof forceError.stdout === "string" ? forceError.stdout : "";
|
|
22229
|
+
throw new Error(`git worktree remove --force fallback failed: ${forceStderr.trim() || forceStdout.trim() || forceError.message}`);
|
|
22230
|
+
}
|
|
22231
|
+
return {
|
|
22232
|
+
success: true,
|
|
22233
|
+
removedPath: worktreePath,
|
|
22234
|
+
fallback: "git_worktree_remove_force_submodule",
|
|
22235
|
+
forced: true,
|
|
22236
|
+
reason: "working_trees_containing_submodules"
|
|
22237
|
+
};
|
|
22238
|
+
}
|
|
22239
|
+
throw new Error(`git worktree remove failed: ${stderr.trim() || stdout.trim() || error48.message}`);
|
|
22214
22240
|
}
|
|
22215
22241
|
return { success: true, removedPath: worktreePath };
|
|
22216
22242
|
}
|
|
@@ -22269,6 +22295,7 @@ var require_dist2 = __commonJS({
|
|
|
22269
22295
|
var WORKTREE_DIR_NAME;
|
|
22270
22296
|
var GIT_TIMEOUT_MS;
|
|
22271
22297
|
var GIT_MAX_BUFFER;
|
|
22298
|
+
var SUBMODULE_WORKTREE_REMOVE_RE;
|
|
22272
22299
|
var init_git_worktree = __esm2({
|
|
22273
22300
|
"src/git/git-worktree.ts"() {
|
|
22274
22301
|
"use strict";
|
|
@@ -22281,6 +22308,7 @@ var require_dist2 = __commonJS({
|
|
|
22281
22308
|
WORKTREE_DIR_NAME = ".adhdev-worktrees";
|
|
22282
22309
|
GIT_TIMEOUT_MS = 3e4;
|
|
22283
22310
|
GIT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
22311
|
+
SUBMODULE_WORKTREE_REMOVE_RE = /working trees containing submodules cannot be moved or removed/i;
|
|
22284
22312
|
}
|
|
22285
22313
|
});
|
|
22286
22314
|
var config_exports = {};
|
|
@@ -22388,7 +22416,8 @@ var require_dist2 = __commonJS({
|
|
|
22388
22416
|
};
|
|
22389
22417
|
}
|
|
22390
22418
|
function getConfigDir() {
|
|
22391
|
-
const
|
|
22419
|
+
const override = process.env.ADHDEV_CONFIG_DIR;
|
|
22420
|
+
const dir = override && override.trim() ? override.trim() : (0, import_path2.join)((0, import_os2.homedir)(), ".adhdev");
|
|
22392
22421
|
if (!(0, import_fs.existsSync)(dir)) {
|
|
22393
22422
|
(0, import_fs.mkdirSync)(dir, { recursive: true });
|
|
22394
22423
|
}
|
|
@@ -23112,6 +23141,7 @@ Follow these recovery rules:
|
|
|
23112
23141
|
enqueueTask: () => enqueueTask,
|
|
23113
23142
|
getMeshQueueStats: () => getMeshQueueStats,
|
|
23114
23143
|
getQueue: () => getQueue,
|
|
23144
|
+
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
23115
23145
|
requeueTask: () => requeueTask,
|
|
23116
23146
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
23117
23147
|
updateTaskStatus: () => updateTaskStatus
|
|
@@ -23187,6 +23217,19 @@ Follow these recovery rules:
|
|
|
23187
23217
|
writeQueue(meshId, queue);
|
|
23188
23218
|
return queue[idx];
|
|
23189
23219
|
}
|
|
23220
|
+
function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
|
|
23221
|
+
const queue = readQueue(meshId);
|
|
23222
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
23223
|
+
if (idx === -1) return null;
|
|
23224
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23225
|
+
queue[idx].autoLaunch = {
|
|
23226
|
+
...autoLaunch,
|
|
23227
|
+
updatedAt: now
|
|
23228
|
+
};
|
|
23229
|
+
queue[idx].updatedAt = now;
|
|
23230
|
+
writeQueue(meshId, queue);
|
|
23231
|
+
return queue[idx];
|
|
23232
|
+
}
|
|
23190
23233
|
function cancelTask(meshId, taskId, opts) {
|
|
23191
23234
|
const queue = readQueue(meshId);
|
|
23192
23235
|
const idx = queue.findIndex((q) => q.id === taskId);
|
|
@@ -23235,12 +23278,20 @@ Follow these recovery rules:
|
|
|
23235
23278
|
}
|
|
23236
23279
|
function getMeshQueueStats(meshId) {
|
|
23237
23280
|
const queue = readQueue(meshId);
|
|
23281
|
+
const pending = queue.filter((q) => q.status === "pending").length;
|
|
23282
|
+
const assigned = queue.filter((q) => q.status === "assigned").length;
|
|
23283
|
+
const completed = queue.filter((q) => q.status === "completed").length;
|
|
23284
|
+
const failed = queue.filter((q) => q.status === "failed").length;
|
|
23285
|
+
const cancelled = queue.filter((q) => q.status === "cancelled").length;
|
|
23238
23286
|
return {
|
|
23239
|
-
|
|
23240
|
-
|
|
23241
|
-
|
|
23242
|
-
|
|
23243
|
-
|
|
23287
|
+
total: queue.length,
|
|
23288
|
+
active: pending + assigned,
|
|
23289
|
+
historical: completed + failed + cancelled,
|
|
23290
|
+
pending,
|
|
23291
|
+
assigned,
|
|
23292
|
+
completed,
|
|
23293
|
+
failed,
|
|
23294
|
+
cancelled,
|
|
23244
23295
|
activeAssignments: queue.filter((q) => q.status === "assigned").map((q) => ({
|
|
23245
23296
|
id: q.id,
|
|
23246
23297
|
nodeId: q.assignedNodeId,
|
|
@@ -23261,6 +23312,142 @@ Follow these recovery rules:
|
|
|
23261
23312
|
init_mesh_ledger();
|
|
23262
23313
|
}
|
|
23263
23314
|
});
|
|
23315
|
+
function parseVersion(raw) {
|
|
23316
|
+
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
23317
|
+
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
23318
|
+
}
|
|
23319
|
+
function shellQuote(value) {
|
|
23320
|
+
if (/^[a-zA-Z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
23321
|
+
return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
23322
|
+
}
|
|
23323
|
+
function expandHome(value) {
|
|
23324
|
+
const trimmed = value.trim();
|
|
23325
|
+
if (!trimmed.startsWith("~")) return trimmed;
|
|
23326
|
+
return path8.join(os22.homedir(), trimmed.slice(1));
|
|
23327
|
+
}
|
|
23328
|
+
function isExplicitCommandPath(command) {
|
|
23329
|
+
const trimmed = command.trim();
|
|
23330
|
+
return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
23331
|
+
}
|
|
23332
|
+
function resolveCommandPath(command) {
|
|
23333
|
+
const trimmed = command.trim();
|
|
23334
|
+
if (!trimmed) return null;
|
|
23335
|
+
if (isExplicitCommandPath(trimmed)) {
|
|
23336
|
+
const expanded = expandHome(trimmed);
|
|
23337
|
+
const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
|
|
23338
|
+
return (0, import_fs5.existsSync)(candidate) ? candidate : null;
|
|
23339
|
+
}
|
|
23340
|
+
return null;
|
|
23341
|
+
}
|
|
23342
|
+
function execAsync(cmd, timeoutMs = 5e3) {
|
|
23343
|
+
return new Promise((resolve16) => {
|
|
23344
|
+
const child = (0, import_child_process.exec)(cmd, {
|
|
23345
|
+
encoding: "utf-8",
|
|
23346
|
+
timeout: timeoutMs,
|
|
23347
|
+
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
23348
|
+
}, (err, stdout) => {
|
|
23349
|
+
if (err || !stdout?.trim()) {
|
|
23350
|
+
resolve16(null);
|
|
23351
|
+
} else {
|
|
23352
|
+
resolve16(stdout.trim());
|
|
23353
|
+
}
|
|
23354
|
+
});
|
|
23355
|
+
child.on("error", () => resolve16(null));
|
|
23356
|
+
});
|
|
23357
|
+
}
|
|
23358
|
+
async function detectCLIs(providerLoader, options) {
|
|
23359
|
+
const platform10 = os22.platform();
|
|
23360
|
+
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
23361
|
+
const includeVersion = options?.includeVersion !== false;
|
|
23362
|
+
const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
|
|
23363
|
+
const results = await Promise.all(
|
|
23364
|
+
cliList.map(async (cli) => {
|
|
23365
|
+
try {
|
|
23366
|
+
const explicitPath = resolveCommandPath(cli.command);
|
|
23367
|
+
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(cli.command)}`);
|
|
23368
|
+
if (!pathResult) return { ...cli, installed: false };
|
|
23369
|
+
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
23370
|
+
let version2;
|
|
23371
|
+
if (includeVersion) {
|
|
23372
|
+
const versionCommands = [
|
|
23373
|
+
`"${firstPath}" --version`,
|
|
23374
|
+
`"${firstPath}" -V`,
|
|
23375
|
+
`"${firstPath}" -v`,
|
|
23376
|
+
cli.versionCommand
|
|
23377
|
+
].filter((v) => !!v);
|
|
23378
|
+
try {
|
|
23379
|
+
for (const versionCommand of versionCommands) {
|
|
23380
|
+
const versionResult = await execAsync(versionCommand, 3e3);
|
|
23381
|
+
if (versionResult) {
|
|
23382
|
+
version2 = parseVersion(versionResult);
|
|
23383
|
+
break;
|
|
23384
|
+
}
|
|
23385
|
+
}
|
|
23386
|
+
} catch {
|
|
23387
|
+
}
|
|
23388
|
+
}
|
|
23389
|
+
return { ...cli, installed: true, version: version2, path: firstPath };
|
|
23390
|
+
} catch {
|
|
23391
|
+
return { ...cli, installed: false };
|
|
23392
|
+
}
|
|
23393
|
+
})
|
|
23394
|
+
);
|
|
23395
|
+
return results;
|
|
23396
|
+
}
|
|
23397
|
+
async function detectCLI(cliId, providerLoader, options) {
|
|
23398
|
+
const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
|
|
23399
|
+
if (providerLoader) {
|
|
23400
|
+
const cliList = providerLoader.getCliDetectionList();
|
|
23401
|
+
const target = cliList.find((c) => c.id === resolvedId);
|
|
23402
|
+
if (target) {
|
|
23403
|
+
const platform10 = os22.platform();
|
|
23404
|
+
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
23405
|
+
try {
|
|
23406
|
+
const explicitPath = resolveCommandPath(target.command);
|
|
23407
|
+
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
|
|
23408
|
+
if (!pathResult) return null;
|
|
23409
|
+
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
23410
|
+
let version2;
|
|
23411
|
+
if (options?.includeVersion !== false) {
|
|
23412
|
+
const versionCommands = [
|
|
23413
|
+
`"${firstPath}" --version`,
|
|
23414
|
+
`"${firstPath}" -V`,
|
|
23415
|
+
`"${firstPath}" -v`,
|
|
23416
|
+
target.versionCommand
|
|
23417
|
+
].filter((v) => !!v);
|
|
23418
|
+
try {
|
|
23419
|
+
for (const versionCommand of versionCommands) {
|
|
23420
|
+
const versionResult = await execAsync(versionCommand, 3e3);
|
|
23421
|
+
if (versionResult) {
|
|
23422
|
+
version2 = parseVersion(versionResult);
|
|
23423
|
+
break;
|
|
23424
|
+
}
|
|
23425
|
+
}
|
|
23426
|
+
} catch {
|
|
23427
|
+
}
|
|
23428
|
+
}
|
|
23429
|
+
return { ...target, installed: true, version: version2, path: firstPath };
|
|
23430
|
+
} catch {
|
|
23431
|
+
return null;
|
|
23432
|
+
}
|
|
23433
|
+
}
|
|
23434
|
+
}
|
|
23435
|
+
const all = await detectCLIs(providerLoader, options);
|
|
23436
|
+
return all.find((c) => c.id === resolvedId && c.installed) || null;
|
|
23437
|
+
}
|
|
23438
|
+
var import_child_process;
|
|
23439
|
+
var os22;
|
|
23440
|
+
var path8;
|
|
23441
|
+
var import_fs5;
|
|
23442
|
+
var init_cli_detector = __esm2({
|
|
23443
|
+
"src/detection/cli-detector.ts"() {
|
|
23444
|
+
"use strict";
|
|
23445
|
+
import_child_process = require("child_process");
|
|
23446
|
+
os22 = __toESM2(require("os"));
|
|
23447
|
+
path8 = __toESM2(require("path"));
|
|
23448
|
+
import_fs5 = require("fs");
|
|
23449
|
+
}
|
|
23450
|
+
});
|
|
23264
23451
|
function setLogLevel(level) {
|
|
23265
23452
|
currentLevel = level;
|
|
23266
23453
|
daemonLog("Logger", `Log level set to: ${level}`, "info");
|
|
@@ -23275,13 +23462,13 @@ Follow these recovery rules:
|
|
|
23275
23462
|
return LOG_DIR;
|
|
23276
23463
|
}
|
|
23277
23464
|
function getCurrentDaemonLogPath(date5 = /* @__PURE__ */ new Date()) {
|
|
23278
|
-
return
|
|
23465
|
+
return path9.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
|
|
23279
23466
|
}
|
|
23280
23467
|
function checkDateRotation() {
|
|
23281
23468
|
const today = getDateStr();
|
|
23282
23469
|
if (today !== currentDate) {
|
|
23283
23470
|
currentDate = today;
|
|
23284
|
-
currentLogFile =
|
|
23471
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
23285
23472
|
cleanOldLogs();
|
|
23286
23473
|
}
|
|
23287
23474
|
}
|
|
@@ -23295,7 +23482,7 @@ Follow these recovery rules:
|
|
|
23295
23482
|
const dateMatch = file2.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
23296
23483
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
23297
23484
|
try {
|
|
23298
|
-
fs22.unlinkSync(
|
|
23485
|
+
fs22.unlinkSync(path9.join(LOG_DIR, file2));
|
|
23299
23486
|
} catch {
|
|
23300
23487
|
}
|
|
23301
23488
|
}
|
|
@@ -23412,8 +23599,8 @@ Follow these recovery rules:
|
|
|
23412
23599
|
writeToFile(`Log level: ${currentLevel}`);
|
|
23413
23600
|
}
|
|
23414
23601
|
var fs22;
|
|
23415
|
-
var
|
|
23416
|
-
var
|
|
23602
|
+
var path9;
|
|
23603
|
+
var os32;
|
|
23417
23604
|
var LEVEL_NUM;
|
|
23418
23605
|
var LEVEL_LABEL;
|
|
23419
23606
|
var currentLevel;
|
|
@@ -23435,12 +23622,12 @@ Follow these recovery rules:
|
|
|
23435
23622
|
"src/logging/logger.ts"() {
|
|
23436
23623
|
"use strict";
|
|
23437
23624
|
fs22 = __toESM2(require("fs"));
|
|
23438
|
-
|
|
23439
|
-
|
|
23625
|
+
path9 = __toESM2(require("path"));
|
|
23626
|
+
os32 = __toESM2(require("os"));
|
|
23440
23627
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
23441
23628
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
23442
23629
|
currentLevel = "info";
|
|
23443
|
-
LOG_DIR = process.platform === "win32" ?
|
|
23630
|
+
LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os32.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os32.homedir(), "Library", "Logs", "adhdev") : path9.join(os32.homedir(), ".local", "share", "adhdev", "logs");
|
|
23444
23631
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
23445
23632
|
MAX_LOG_DAYS = 7;
|
|
23446
23633
|
try {
|
|
@@ -23448,16 +23635,16 @@ Follow these recovery rules:
|
|
|
23448
23635
|
} catch {
|
|
23449
23636
|
}
|
|
23450
23637
|
currentDate = getDateStr();
|
|
23451
|
-
currentLogFile =
|
|
23638
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
23452
23639
|
cleanOldLogs();
|
|
23453
23640
|
try {
|
|
23454
|
-
const oldLog =
|
|
23641
|
+
const oldLog = path9.join(LOG_DIR, "daemon.log");
|
|
23455
23642
|
if (fs22.existsSync(oldLog)) {
|
|
23456
23643
|
const stat2 = fs22.statSync(oldLog);
|
|
23457
23644
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
23458
|
-
fs22.renameSync(oldLog,
|
|
23645
|
+
fs22.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
23459
23646
|
}
|
|
23460
|
-
const oldLogBackup =
|
|
23647
|
+
const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
|
|
23461
23648
|
if (fs22.existsSync(oldLogBackup)) {
|
|
23462
23649
|
fs22.unlinkSync(oldLogBackup);
|
|
23463
23650
|
}
|
|
@@ -23489,7 +23676,7 @@ Follow these recovery rules:
|
|
|
23489
23676
|
}
|
|
23490
23677
|
};
|
|
23491
23678
|
interceptorInstalled = false;
|
|
23492
|
-
LOG_PATH =
|
|
23679
|
+
LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
23493
23680
|
}
|
|
23494
23681
|
});
|
|
23495
23682
|
var mesh_events_exports = {};
|
|
@@ -23559,7 +23746,235 @@ Follow these recovery rules:
|
|
|
23559
23746
|
});
|
|
23560
23747
|
return true;
|
|
23561
23748
|
}
|
|
23562
|
-
function
|
|
23749
|
+
function normalizeProviderPriority(policy) {
|
|
23750
|
+
const raw = policy && typeof policy === "object" && !Array.isArray(policy) ? policy.providerPriority : void 0;
|
|
23751
|
+
if (!Array.isArray(raw)) return [];
|
|
23752
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23753
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
23754
|
+
if (seen.has(type)) return false;
|
|
23755
|
+
seen.add(type);
|
|
23756
|
+
return true;
|
|
23757
|
+
});
|
|
23758
|
+
}
|
|
23759
|
+
function isTerminalSessionStatus(status) {
|
|
23760
|
+
return ["stopped", "failed", "terminated", "exited", "closed"].includes(status);
|
|
23761
|
+
}
|
|
23762
|
+
function isIdleSessionState(state) {
|
|
23763
|
+
const status = readNonEmptyString(state?.status).toLowerCase();
|
|
23764
|
+
if (isTerminalSessionStatus(status)) return false;
|
|
23765
|
+
return status === "idle" || state?.activeChat?.status === "waiting_input";
|
|
23766
|
+
}
|
|
23767
|
+
function isDirtyNode(node) {
|
|
23768
|
+
return node?.health === "dirty" || node?.git?.dirty === true;
|
|
23769
|
+
}
|
|
23770
|
+
function isLaunchableNode(node) {
|
|
23771
|
+
if (!node || node.status === "disabled" || node.status === "removed") return false;
|
|
23772
|
+
const health = readNonEmptyString(node.health).toLowerCase();
|
|
23773
|
+
if (!health) return true;
|
|
23774
|
+
return health === "online" || health === "unknown";
|
|
23775
|
+
}
|
|
23776
|
+
function localAutoLaunchSkipReason(node) {
|
|
23777
|
+
const daemonId = readNonEmptyString(node?.daemonId);
|
|
23778
|
+
const machineId = readNonEmptyString(node?.machineId);
|
|
23779
|
+
const appConfig = loadConfig2();
|
|
23780
|
+
const localMachineId = readNonEmptyString(appConfig.machineId) || readNonEmptyString(appConfig.registeredMachineId);
|
|
23781
|
+
const cloudDaemonId = localMachineId ? `daemon_${localMachineId}` : "";
|
|
23782
|
+
const standaloneDaemonId = localMachineId ? `standalone_${localMachineId}` : "";
|
|
23783
|
+
const daemonMatchesLocal = !daemonId || daemonId === cloudDaemonId || daemonId === standaloneDaemonId;
|
|
23784
|
+
const machineMatchesLocal = !machineId || localMachineId && machineId === localMachineId;
|
|
23785
|
+
if (node?.isLocalWorktree === true) {
|
|
23786
|
+
return daemonMatchesLocal && machineMatchesLocal ? null : "remote_auto_launch_unsupported";
|
|
23787
|
+
}
|
|
23788
|
+
if (daemonId || machineId) {
|
|
23789
|
+
return daemonMatchesLocal && machineMatchesLocal ? null : "remote_auto_launch_unsupported";
|
|
23790
|
+
}
|
|
23791
|
+
return null;
|
|
23792
|
+
}
|
|
23793
|
+
function activeAssignedCount(meshId) {
|
|
23794
|
+
return getQueue(meshId, { status: ["assigned"] }).length;
|
|
23795
|
+
}
|
|
23796
|
+
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
23797
|
+
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
|
|
23798
|
+
}
|
|
23799
|
+
function liveSessionCountForNode(components, meshId, nodeId) {
|
|
23800
|
+
return components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
23801
|
+
const state = inst.getState();
|
|
23802
|
+
const settings = state.settings || {};
|
|
23803
|
+
if (readNonEmptyString(settings.meshNodeFor) !== meshId) return false;
|
|
23804
|
+
const instNodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
23805
|
+
if (instNodeId !== nodeId) return false;
|
|
23806
|
+
const status = readNonEmptyString(state.status).toLowerCase();
|
|
23807
|
+
return !isTerminalSessionStatus(status);
|
|
23808
|
+
}).length;
|
|
23809
|
+
}
|
|
23810
|
+
function recordAutoLaunchEvent(meshId, args) {
|
|
23811
|
+
try {
|
|
23812
|
+
appendLedgerEntry(meshId, {
|
|
23813
|
+
kind: "session_auto_launch",
|
|
23814
|
+
nodeId: args.nodeId,
|
|
23815
|
+
sessionId: args.sessionId,
|
|
23816
|
+
providerType: args.providerType,
|
|
23817
|
+
payload: {
|
|
23818
|
+
phase: args.phase,
|
|
23819
|
+
taskId: args.taskId,
|
|
23820
|
+
reason: args.reason,
|
|
23821
|
+
error: args.error
|
|
23822
|
+
}
|
|
23823
|
+
});
|
|
23824
|
+
} catch (e) {
|
|
23825
|
+
LOG2.warn("MeshQueue", `Failed to record auto-launch ledger event: ${e?.message || e}`);
|
|
23826
|
+
}
|
|
23827
|
+
}
|
|
23828
|
+
function markAutoLaunch(meshId, taskId, args) {
|
|
23829
|
+
recordTaskAutoLaunch(meshId, taskId, {
|
|
23830
|
+
status: args.status,
|
|
23831
|
+
reason: args.reason || args.error,
|
|
23832
|
+
nodeId: args.nodeId,
|
|
23833
|
+
providerType: args.providerType,
|
|
23834
|
+
sessionId: args.sessionId
|
|
23835
|
+
});
|
|
23836
|
+
recordAutoLaunchEvent(meshId, {
|
|
23837
|
+
phase: args.status,
|
|
23838
|
+
taskId,
|
|
23839
|
+
nodeId: args.nodeId,
|
|
23840
|
+
providerType: args.providerType,
|
|
23841
|
+
sessionId: args.sessionId,
|
|
23842
|
+
reason: args.reason,
|
|
23843
|
+
error: args.error
|
|
23844
|
+
});
|
|
23845
|
+
}
|
|
23846
|
+
async function resolveUsableProvider(components, nodeId, node) {
|
|
23847
|
+
const providerPriority = normalizeProviderPriority(node?.policy);
|
|
23848
|
+
if (!providerPriority.length) return { reason: "missing_provider_priority" };
|
|
23849
|
+
const providerLoader = components.providerLoader;
|
|
23850
|
+
if (!providerLoader) return { reason: "provider_loader_unavailable" };
|
|
23851
|
+
const failed = [];
|
|
23852
|
+
for (const requestedType of providerPriority) {
|
|
23853
|
+
const normalizedType = typeof providerLoader.resolveAlias === "function" ? providerLoader.resolveAlias(requestedType) : requestedType;
|
|
23854
|
+
if (typeof providerLoader.isMachineProviderEnabled === "function" && !providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
23855
|
+
failed.push(`${requestedType}: disabled`);
|
|
23856
|
+
continue;
|
|
23857
|
+
}
|
|
23858
|
+
let detected;
|
|
23859
|
+
try {
|
|
23860
|
+
detected = await detectCLI(normalizedType, providerLoader, { includeVersion: false });
|
|
23861
|
+
} catch (e) {
|
|
23862
|
+
failed.push(`${requestedType}: detect failed: ${e?.message || e}`);
|
|
23863
|
+
continue;
|
|
23864
|
+
}
|
|
23865
|
+
if (typeof providerLoader.setCliDetectionResults === "function") {
|
|
23866
|
+
providerLoader.setCliDetectionResults([{
|
|
23867
|
+
id: normalizedType,
|
|
23868
|
+
installed: !!detected,
|
|
23869
|
+
path: detected?.path
|
|
23870
|
+
}], false);
|
|
23871
|
+
}
|
|
23872
|
+
components.onStatusChange?.();
|
|
23873
|
+
if (detected) return { providerType: normalizedType };
|
|
23874
|
+
failed.push(`${requestedType}: not detected`);
|
|
23875
|
+
}
|
|
23876
|
+
return { reason: `provider_priority_unusable: ${failed.join("; ") || nodeId}` };
|
|
23877
|
+
}
|
|
23878
|
+
async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
23879
|
+
const queue = getQueue(meshId);
|
|
23880
|
+
const pending = queue.filter((task) => task.status === "pending");
|
|
23881
|
+
if (!pending.length) return false;
|
|
23882
|
+
const maxParallelTasks = Math.max(1, Math.floor(Number(mesh?.policy?.maxParallelTasks) || 2));
|
|
23883
|
+
for (const task of pending) {
|
|
23884
|
+
if (activeAssignedCount(meshId) >= maxParallelTasks) {
|
|
23885
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_parallel_tasks_reached" });
|
|
23886
|
+
return false;
|
|
23887
|
+
}
|
|
23888
|
+
if (task.targetSessionId) {
|
|
23889
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_constraint" });
|
|
23890
|
+
continue;
|
|
23891
|
+
}
|
|
23892
|
+
const candidateNodes = Array.isArray(mesh?.nodes) ? mesh.nodes.filter((node) => task.targetNodeId ? node?.id === task.targetNodeId : true) : [];
|
|
23893
|
+
if (!candidateNodes.length) {
|
|
23894
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "no_matching_node", nodeId: task.targetNodeId });
|
|
23895
|
+
continue;
|
|
23896
|
+
}
|
|
23897
|
+
for (const node of candidateNodes) {
|
|
23898
|
+
const nodeId = readNonEmptyString(node?.id);
|
|
23899
|
+
if (!nodeId) continue;
|
|
23900
|
+
const launchKey = `${meshId}:${nodeId}`;
|
|
23901
|
+
const cooldownUntil = autoLaunchCooldownUntil.get(launchKey) || 0;
|
|
23902
|
+
if (autoLaunchInProgress.has(launchKey)) {
|
|
23903
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "auto_launch_in_progress", nodeId });
|
|
23904
|
+
continue;
|
|
23905
|
+
}
|
|
23906
|
+
if (Date.now() < cooldownUntil) {
|
|
23907
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "auto_launch_cooldown", nodeId });
|
|
23908
|
+
continue;
|
|
23909
|
+
}
|
|
23910
|
+
if (isDirtyNode(node)) {
|
|
23911
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "dirty_workspace", nodeId });
|
|
23912
|
+
continue;
|
|
23913
|
+
}
|
|
23914
|
+
if (!isLaunchableNode(node)) {
|
|
23915
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_not_launch_ready", nodeId });
|
|
23916
|
+
continue;
|
|
23917
|
+
}
|
|
23918
|
+
const localSkipReason = localAutoLaunchSkipReason(node);
|
|
23919
|
+
if (localSkipReason) {
|
|
23920
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: localSkipReason, nodeId });
|
|
23921
|
+
continue;
|
|
23922
|
+
}
|
|
23923
|
+
if (nodeHasActiveAssignment(meshId, nodeId)) {
|
|
23924
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_has_active_assignment", nodeId });
|
|
23925
|
+
continue;
|
|
23926
|
+
}
|
|
23927
|
+
const maxConcurrentSessions = Number(node?.policy?.maxConcurrentSessions);
|
|
23928
|
+
if (Number.isFinite(maxConcurrentSessions) && maxConcurrentSessions >= 0 && liveSessionCountForNode(components, meshId, nodeId) >= maxConcurrentSessions) {
|
|
23929
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_concurrent_sessions_reached", nodeId });
|
|
23930
|
+
continue;
|
|
23931
|
+
}
|
|
23932
|
+
autoLaunchInProgress.add(launchKey);
|
|
23933
|
+
try {
|
|
23934
|
+
const resolved = await resolveUsableProvider(components, nodeId, node);
|
|
23935
|
+
if (!resolved.providerType) {
|
|
23936
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: resolved.reason || "provider_unusable", nodeId });
|
|
23937
|
+
continue;
|
|
23938
|
+
}
|
|
23939
|
+
markAutoLaunch(meshId, task.id, { status: "started", nodeId, providerType: resolved.providerType });
|
|
23940
|
+
const launchResult = await components.cliManager.handleCliCommand("launch_cli", {
|
|
23941
|
+
cliType: resolved.providerType,
|
|
23942
|
+
dir: node.workspace,
|
|
23943
|
+
settings: {
|
|
23944
|
+
meshNodeFor: meshId,
|
|
23945
|
+
meshNodeId: nodeId,
|
|
23946
|
+
spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || "hidden",
|
|
23947
|
+
launchedByCoordinator: true,
|
|
23948
|
+
autoLaunchedForQueueTaskId: task.id
|
|
23949
|
+
}
|
|
23950
|
+
});
|
|
23951
|
+
if (!launchResult?.success) {
|
|
23952
|
+
const reason = launchResult?.error || "launch_cli_failed";
|
|
23953
|
+
markAutoLaunch(meshId, task.id, { status: "failed", reason, nodeId, providerType: resolved.providerType });
|
|
23954
|
+
autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
|
|
23955
|
+
return false;
|
|
23956
|
+
}
|
|
23957
|
+
const sessionId = readNonEmptyString(launchResult.sessionId) || readNonEmptyString(launchResult.id) || readNonEmptyString(launchResult.runtimeSessionId);
|
|
23958
|
+
if (!sessionId) {
|
|
23959
|
+
markAutoLaunch(meshId, task.id, { status: "failed", reason: "launch_missing_session_id", nodeId, providerType: resolved.providerType });
|
|
23960
|
+
autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
|
|
23961
|
+
return false;
|
|
23962
|
+
}
|
|
23963
|
+
markAutoLaunch(meshId, task.id, { status: "completed", nodeId, providerType: resolved.providerType, sessionId });
|
|
23964
|
+
tryAssignQueueTask(components, meshId, nodeId, sessionId, resolved.providerType);
|
|
23965
|
+
return true;
|
|
23966
|
+
} catch (e) {
|
|
23967
|
+
markAutoLaunch(meshId, task.id, { status: "failed", error: e?.message || String(e), nodeId });
|
|
23968
|
+
autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
|
|
23969
|
+
return false;
|
|
23970
|
+
} finally {
|
|
23971
|
+
autoLaunchInProgress.delete(launchKey);
|
|
23972
|
+
}
|
|
23973
|
+
}
|
|
23974
|
+
}
|
|
23975
|
+
return false;
|
|
23976
|
+
}
|
|
23977
|
+
async function triggerMeshQueue(components, meshId) {
|
|
23563
23978
|
const mesh = getMeshWithCache(components, meshId);
|
|
23564
23979
|
if (!mesh) return;
|
|
23565
23980
|
const cliInstances = components.instanceManager.getByCategory("cli");
|
|
@@ -23570,9 +23985,7 @@ Follow these recovery rules:
|
|
|
23570
23985
|
if (instMeshId !== meshId) continue;
|
|
23571
23986
|
const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
23572
23987
|
if (!nodeId) continue;
|
|
23573
|
-
|
|
23574
|
-
if (["stopped", "failed", "terminated", "exited", "closed"].includes(status)) continue;
|
|
23575
|
-
if (status !== "idle" && state.activeChat?.status !== "waiting_input") continue;
|
|
23988
|
+
if (!isIdleSessionState(state)) continue;
|
|
23576
23989
|
const sessionId = state.instanceId;
|
|
23577
23990
|
const providerType = state.type || readNonEmptyString(settings.providerType);
|
|
23578
23991
|
if (providerType) {
|
|
@@ -23588,6 +24001,7 @@ Follow these recovery rules:
|
|
|
23588
24001
|
}
|
|
23589
24002
|
}
|
|
23590
24003
|
}
|
|
24004
|
+
await maybeAutoLaunchOneQueueSession(components, meshId, mesh);
|
|
23591
24005
|
}
|
|
23592
24006
|
function buildMeshSystemMessage(args) {
|
|
23593
24007
|
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
@@ -23869,10 +24283,15 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
23869
24283
|
var pendingMeshCoordinatorEvents;
|
|
23870
24284
|
var MESH_COORDINATOR_EVENTS;
|
|
23871
24285
|
var EVENT_TO_LEDGER_KIND;
|
|
24286
|
+
var autoLaunchInProgress;
|
|
24287
|
+
var autoLaunchCooldownUntil;
|
|
24288
|
+
var AUTO_LAUNCH_COOLDOWN_MS;
|
|
23872
24289
|
var init_mesh_events = __esm2({
|
|
23873
24290
|
"src/mesh/mesh-events.ts"() {
|
|
23874
24291
|
"use strict";
|
|
24292
|
+
init_config();
|
|
23875
24293
|
init_mesh_config();
|
|
24294
|
+
init_cli_detector();
|
|
23876
24295
|
init_logger();
|
|
23877
24296
|
init_mesh_ledger();
|
|
23878
24297
|
init_mesh_work_queue();
|
|
@@ -23893,6 +24312,9 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
23893
24312
|
"agent:stopped": "task_failed",
|
|
23894
24313
|
"monitor:long_generating": "task_stalled"
|
|
23895
24314
|
};
|
|
24315
|
+
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
24316
|
+
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
24317
|
+
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
23896
24318
|
}
|
|
23897
24319
|
});
|
|
23898
24320
|
function normalizeCategories(categories) {
|
|
@@ -27011,6 +27433,7 @@ ${lastSnapshot}`;
|
|
|
27011
27433
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS2,
|
|
27012
27434
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS2,
|
|
27013
27435
|
NodePtyTransportFactory: () => NodePtyTransportFactory,
|
|
27436
|
+
P2pRelayFailureError: () => P2pRelayFailureError,
|
|
27014
27437
|
ProviderCliAdapter: () => ProviderCliAdapter,
|
|
27015
27438
|
ProviderInstanceManager: () => ProviderInstanceManager,
|
|
27016
27439
|
ProviderLoader: () => ProviderLoader,
|
|
@@ -27027,6 +27450,7 @@ ${lastSnapshot}`;
|
|
|
27027
27450
|
buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
|
|
27028
27451
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
|
|
27029
27452
|
buildMachineInfo: () => buildMachineInfo2,
|
|
27453
|
+
buildP2pRelayFailurePayload: () => buildP2pRelayFailurePayload,
|
|
27030
27454
|
buildPinnedGlobalInstallCommand: () => buildPinnedGlobalInstallCommand,
|
|
27031
27455
|
buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
|
|
27032
27456
|
buildSessionEntries: () => buildSessionEntries,
|
|
@@ -27041,6 +27465,7 @@ ${lastSnapshot}`;
|
|
|
27041
27465
|
claimNextTask: () => claimNextTask,
|
|
27042
27466
|
classifyChatMessageVisibility: () => classifyChatMessageVisibility,
|
|
27043
27467
|
classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush2,
|
|
27468
|
+
classifyP2pRelayFailure: () => classifyP2pRelayFailure,
|
|
27044
27469
|
clearDebugTrace: () => clearDebugTrace,
|
|
27045
27470
|
compareGitSnapshots: () => compareGitSnapshots,
|
|
27046
27471
|
configureDebugTraceStore: () => configureDebugTraceStore,
|
|
@@ -27108,6 +27533,7 @@ ${lastSnapshot}`;
|
|
|
27108
27533
|
isInternalChatMessage: () => isInternalChatMessage,
|
|
27109
27534
|
isManagedStatusWaiting: () => isManagedStatusWaiting,
|
|
27110
27535
|
isManagedStatusWorking: () => isManagedStatusWorking,
|
|
27536
|
+
isP2pRelayTransportFailure: () => isP2pRelayTransportFailure,
|
|
27111
27537
|
isPathInside: () => isPathInside,
|
|
27112
27538
|
isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
|
|
27113
27539
|
isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
|
|
@@ -28642,7 +29068,7 @@ ${lastSnapshot}`;
|
|
|
28642
29068
|
}
|
|
28643
29069
|
}
|
|
28644
29070
|
const v = validateWorkspacePath(abs);
|
|
28645
|
-
if (
|
|
29071
|
+
if (v.ok !== true) return { error: v.error };
|
|
28646
29072
|
const list = [...config2.workspaces || []];
|
|
28647
29073
|
if (list.some((w) => path52.resolve(w.path) === abs)) {
|
|
28648
29074
|
return { error: "Workspace already in list" };
|
|
@@ -29036,7 +29462,115 @@ ${lastSnapshot}`;
|
|
|
29036
29462
|
init_mesh_ledger();
|
|
29037
29463
|
init_mesh_work_queue();
|
|
29038
29464
|
init_mesh_events();
|
|
29039
|
-
var
|
|
29465
|
+
var NO_FALLBACK_REASON = "Repo Mesh command/data-plane is P2P-only; WS/REST command fallback is intentionally disabled to preserve the transport boundary.";
|
|
29466
|
+
var P2P_NEXT_ACTION = "Check daemon/P2P health, wait briefly for connection establishment, then do one bounded retry or requeue the mesh task after clearing stale target session metadata.";
|
|
29467
|
+
var NON_P2P_NEXT_ACTION = "Inspect the provider/command error and fix the underlying logic or configuration before retrying.";
|
|
29468
|
+
function messageFromError(error48) {
|
|
29469
|
+
if (error48 instanceof Error) return error48.message;
|
|
29470
|
+
if (typeof error48 === "string") return error48;
|
|
29471
|
+
if (error48 && typeof error48 === "object") {
|
|
29472
|
+
const candidate = error48.error ?? error48.message ?? error48.reason;
|
|
29473
|
+
if (typeof candidate === "string") return candidate;
|
|
29474
|
+
}
|
|
29475
|
+
return String(error48 || "mesh relay command failed");
|
|
29476
|
+
}
|
|
29477
|
+
function classifyP2pRelayFailure(error48, _context = {}) {
|
|
29478
|
+
const message = messageFromError(error48);
|
|
29479
|
+
const lower = message.toLowerCase();
|
|
29480
|
+
const hasP2pSignal = /p2p|datachannel|node-datachannel|webrtc|ice|mesh_relay_command|daemon_mesh_p2p_transport/i.test(message);
|
|
29481
|
+
const hasFailureSignal = /unavailable|missing|failed|failure|timeout|timed out|not connected|closed|disconnected|offline|no route|route unavailable|cannot send|cannot establish/i.test(message);
|
|
29482
|
+
if (/requires targetdaemonid and command|providerpriority|no inference provider|permission denied|read-only|not a member/i.test(message)) {
|
|
29483
|
+
return {
|
|
29484
|
+
code: "mesh_logic_or_provider_failure",
|
|
29485
|
+
reason: "mesh_logic_or_provider_failure",
|
|
29486
|
+
transport: "unknown",
|
|
29487
|
+
recoverable: false,
|
|
29488
|
+
retryRecommended: false,
|
|
29489
|
+
nextAction: NON_P2P_NEXT_ACTION,
|
|
29490
|
+
noFallbackReason: NO_FALLBACK_REASON
|
|
29491
|
+
};
|
|
29492
|
+
}
|
|
29493
|
+
let code = null;
|
|
29494
|
+
let reason = "";
|
|
29495
|
+
if (/timeout|timed out/i.test(message) && (hasP2pSignal || /mesh transport/i.test(message))) {
|
|
29496
|
+
code = "p2p_timeout";
|
|
29497
|
+
reason = "daemon_mesh_p2p_timeout";
|
|
29498
|
+
} else if (/no route|route unavailable/i.test(message)) {
|
|
29499
|
+
code = "p2p_no_route";
|
|
29500
|
+
reason = "daemon_mesh_p2p_no_route";
|
|
29501
|
+
} else if (/offline|not owned|not found|not connected to server/i.test(message) && /daemon|peer|target/i.test(message)) {
|
|
29502
|
+
code = "p2p_daemon_offline";
|
|
29503
|
+
reason = "daemon_mesh_target_offline";
|
|
29504
|
+
} else if (/closed|disconnected/i.test(message) && (hasP2pSignal || /state changed/i.test(message))) {
|
|
29505
|
+
code = "p2p_datachannel_closed";
|
|
29506
|
+
reason = "daemon_mesh_p2p_datachannel_closed";
|
|
29507
|
+
} else if (/not connected|cannot send|cannot establish/i.test(message) && hasP2pSignal) {
|
|
29508
|
+
code = "p2p_not_connected";
|
|
29509
|
+
reason = "daemon_mesh_p2p_not_connected";
|
|
29510
|
+
} else if (hasP2pSignal && hasFailureSignal) {
|
|
29511
|
+
code = "p2p_unavailable";
|
|
29512
|
+
reason = "daemon_mesh_p2p_transport_unavailable";
|
|
29513
|
+
}
|
|
29514
|
+
if (!code) {
|
|
29515
|
+
return {
|
|
29516
|
+
code: "mesh_logic_or_provider_failure",
|
|
29517
|
+
reason: "mesh_logic_or_provider_failure",
|
|
29518
|
+
transport: "unknown",
|
|
29519
|
+
recoverable: false,
|
|
29520
|
+
retryRecommended: false,
|
|
29521
|
+
nextAction: NON_P2P_NEXT_ACTION,
|
|
29522
|
+
noFallbackReason: NO_FALLBACK_REASON
|
|
29523
|
+
};
|
|
29524
|
+
}
|
|
29525
|
+
return {
|
|
29526
|
+
code,
|
|
29527
|
+
reason,
|
|
29528
|
+
transport: "p2p",
|
|
29529
|
+
recoverable: true,
|
|
29530
|
+
retryRecommended: true,
|
|
29531
|
+
nextAction: P2P_NEXT_ACTION,
|
|
29532
|
+
noFallbackReason: NO_FALLBACK_REASON
|
|
29533
|
+
};
|
|
29534
|
+
}
|
|
29535
|
+
function isP2pRelayTransportFailure(error48) {
|
|
29536
|
+
return classifyP2pRelayFailure(error48).recoverable === true;
|
|
29537
|
+
}
|
|
29538
|
+
function buildP2pRelayFailurePayload(error48, context = {}) {
|
|
29539
|
+
const classification = classifyP2pRelayFailure(error48, context);
|
|
29540
|
+
return {
|
|
29541
|
+
success: false,
|
|
29542
|
+
...classification,
|
|
29543
|
+
error: messageFromError(error48),
|
|
29544
|
+
...context.command ? { command: context.command } : {},
|
|
29545
|
+
...context.targetDaemonId ? { targetDaemonId: context.targetDaemonId } : {}
|
|
29546
|
+
};
|
|
29547
|
+
}
|
|
29548
|
+
var P2pRelayFailureError = class extends Error {
|
|
29549
|
+
code;
|
|
29550
|
+
reason;
|
|
29551
|
+
transport;
|
|
29552
|
+
recoverable;
|
|
29553
|
+
retryRecommended;
|
|
29554
|
+
nextAction;
|
|
29555
|
+
noFallbackReason;
|
|
29556
|
+
command;
|
|
29557
|
+
targetDaemonId;
|
|
29558
|
+
constructor(message, context = {}) {
|
|
29559
|
+
super(message);
|
|
29560
|
+
this.name = "P2pRelayFailureError";
|
|
29561
|
+
const payload = buildP2pRelayFailurePayload(message, context);
|
|
29562
|
+
this.code = payload.code;
|
|
29563
|
+
this.reason = payload.reason;
|
|
29564
|
+
this.transport = payload.transport;
|
|
29565
|
+
this.recoverable = payload.recoverable;
|
|
29566
|
+
this.retryRecommended = payload.retryRecommended;
|
|
29567
|
+
this.nextAction = payload.nextAction;
|
|
29568
|
+
this.noFallbackReason = payload.noFallbackReason;
|
|
29569
|
+
this.command = context.command;
|
|
29570
|
+
this.targetDaemonId = context.targetDaemonId;
|
|
29571
|
+
}
|
|
29572
|
+
};
|
|
29573
|
+
var import_fs6 = require("fs");
|
|
29040
29574
|
var import_path5 = require("path");
|
|
29041
29575
|
init_config();
|
|
29042
29576
|
var DEFAULT_STATE = {
|
|
@@ -29087,11 +29621,11 @@ ${lastSnapshot}`;
|
|
|
29087
29621
|
}
|
|
29088
29622
|
function loadState() {
|
|
29089
29623
|
const statePath = getStatePath();
|
|
29090
|
-
if (!(0,
|
|
29624
|
+
if (!(0, import_fs6.existsSync)(statePath)) {
|
|
29091
29625
|
return { ...DEFAULT_STATE };
|
|
29092
29626
|
}
|
|
29093
29627
|
try {
|
|
29094
|
-
const raw = (0,
|
|
29628
|
+
const raw = (0, import_fs6.readFileSync)(statePath, "utf-8");
|
|
29095
29629
|
return normalizeState(JSON.parse(raw));
|
|
29096
29630
|
} catch {
|
|
29097
29631
|
return { ...DEFAULT_STATE };
|
|
@@ -29100,15 +29634,15 @@ ${lastSnapshot}`;
|
|
|
29100
29634
|
function saveState(state) {
|
|
29101
29635
|
const statePath = getStatePath();
|
|
29102
29636
|
const normalized = normalizeState(state);
|
|
29103
|
-
(0,
|
|
29637
|
+
(0, import_fs6.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
29104
29638
|
}
|
|
29105
29639
|
function resetState() {
|
|
29106
29640
|
saveState({ ...DEFAULT_STATE });
|
|
29107
29641
|
}
|
|
29108
|
-
var
|
|
29109
|
-
var
|
|
29642
|
+
var import_child_process2 = require("child_process");
|
|
29643
|
+
var import_fs7 = require("fs");
|
|
29110
29644
|
var import_os22 = require("os");
|
|
29111
|
-
var
|
|
29645
|
+
var path10 = __toESM2(require("path"));
|
|
29112
29646
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
29113
29647
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
29114
29648
|
function registerIDEDefinition(def) {
|
|
@@ -29127,13 +29661,13 @@ ${lastSnapshot}`;
|
|
|
29127
29661
|
function findCliCommand(command) {
|
|
29128
29662
|
const trimmed = String(command || "").trim();
|
|
29129
29663
|
if (!trimmed) return null;
|
|
29130
|
-
if (
|
|
29131
|
-
const candidate = trimmed.startsWith("~") ?
|
|
29132
|
-
const resolved =
|
|
29133
|
-
return (0,
|
|
29664
|
+
if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
29665
|
+
const candidate = trimmed.startsWith("~") ? path10.join((0, import_os22.homedir)(), trimmed.slice(1)) : trimmed;
|
|
29666
|
+
const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
|
|
29667
|
+
return (0, import_fs7.existsSync)(resolved) ? resolved : null;
|
|
29134
29668
|
}
|
|
29135
29669
|
try {
|
|
29136
|
-
const result = (0,
|
|
29670
|
+
const result = (0, import_child_process2.execSync)(
|
|
29137
29671
|
(0, import_os22.platform)() === "win32" ? `where ${trimmed}` : `which ${trimmed}`,
|
|
29138
29672
|
{ encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }
|
|
29139
29673
|
).trim();
|
|
@@ -29144,7 +29678,7 @@ ${lastSnapshot}`;
|
|
|
29144
29678
|
}
|
|
29145
29679
|
function getIdeVersion(cliCommand) {
|
|
29146
29680
|
try {
|
|
29147
|
-
const result = (0,
|
|
29681
|
+
const result = (0, import_child_process2.execSync)(`"${cliCommand}" --version`, {
|
|
29148
29682
|
encoding: "utf-8",
|
|
29149
29683
|
timeout: 1e4,
|
|
29150
29684
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -29157,13 +29691,13 @@ ${lastSnapshot}`;
|
|
|
29157
29691
|
function checkPathExists(paths) {
|
|
29158
29692
|
const home = (0, import_os22.homedir)();
|
|
29159
29693
|
for (const p of paths) {
|
|
29160
|
-
const normalized = p.startsWith("~") ?
|
|
29694
|
+
const normalized = p.startsWith("~") ? path10.join(home, p.slice(1)) : p;
|
|
29161
29695
|
if (normalized.includes("*")) {
|
|
29162
29696
|
const username = home.split(/[\\/]/).pop() || "";
|
|
29163
29697
|
const resolved = normalized.replace("*", username);
|
|
29164
|
-
if ((0,
|
|
29698
|
+
if ((0, import_fs7.existsSync)(resolved)) return resolved;
|
|
29165
29699
|
} else {
|
|
29166
|
-
if ((0,
|
|
29700
|
+
if ((0, import_fs7.existsSync)(normalized)) return normalized;
|
|
29167
29701
|
}
|
|
29168
29702
|
}
|
|
29169
29703
|
return null;
|
|
@@ -29177,7 +29711,7 @@ ${lastSnapshot}`;
|
|
|
29177
29711
|
let resolvedCli = cliPath;
|
|
29178
29712
|
if (!resolvedCli && appPath && os222 === "darwin") {
|
|
29179
29713
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
29180
|
-
if ((0,
|
|
29714
|
+
if ((0, import_fs7.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
29181
29715
|
}
|
|
29182
29716
|
if (!resolvedCli && appPath && os222 === "win32") {
|
|
29183
29717
|
const { dirname: dirname9 } = await import("path");
|
|
@@ -29190,7 +29724,7 @@ ${lastSnapshot}`;
|
|
|
29190
29724
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
29191
29725
|
];
|
|
29192
29726
|
for (const c of candidates) {
|
|
29193
|
-
if ((0,
|
|
29727
|
+
if ((0, import_fs7.existsSync)(c)) {
|
|
29194
29728
|
resolvedCli = c;
|
|
29195
29729
|
break;
|
|
29196
29730
|
}
|
|
@@ -29211,133 +29745,7 @@ ${lastSnapshot}`;
|
|
|
29211
29745
|
}
|
|
29212
29746
|
return results;
|
|
29213
29747
|
}
|
|
29214
|
-
|
|
29215
|
-
var os32 = __toESM2(require("os"));
|
|
29216
|
-
var path10 = __toESM2(require("path"));
|
|
29217
|
-
var import_fs7 = require("fs");
|
|
29218
|
-
function parseVersion(raw) {
|
|
29219
|
-
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
29220
|
-
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
29221
|
-
}
|
|
29222
|
-
function shellQuote(value) {
|
|
29223
|
-
if (/^[a-zA-Z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
29224
|
-
return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
29225
|
-
}
|
|
29226
|
-
function expandHome(value) {
|
|
29227
|
-
const trimmed = value.trim();
|
|
29228
|
-
if (!trimmed.startsWith("~")) return trimmed;
|
|
29229
|
-
return path10.join(os32.homedir(), trimmed.slice(1));
|
|
29230
|
-
}
|
|
29231
|
-
function isExplicitCommandPath(command) {
|
|
29232
|
-
const trimmed = command.trim();
|
|
29233
|
-
return path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
29234
|
-
}
|
|
29235
|
-
function resolveCommandPath(command) {
|
|
29236
|
-
const trimmed = command.trim();
|
|
29237
|
-
if (!trimmed) return null;
|
|
29238
|
-
if (isExplicitCommandPath(trimmed)) {
|
|
29239
|
-
const expanded = expandHome(trimmed);
|
|
29240
|
-
const candidate = path10.isAbsolute(expanded) ? expanded : path10.resolve(expanded);
|
|
29241
|
-
return (0, import_fs7.existsSync)(candidate) ? candidate : null;
|
|
29242
|
-
}
|
|
29243
|
-
return null;
|
|
29244
|
-
}
|
|
29245
|
-
function execAsync(cmd, timeoutMs = 5e3) {
|
|
29246
|
-
return new Promise((resolve16) => {
|
|
29247
|
-
const child = (0, import_child_process2.exec)(cmd, {
|
|
29248
|
-
encoding: "utf-8",
|
|
29249
|
-
timeout: timeoutMs,
|
|
29250
|
-
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
29251
|
-
}, (err, stdout) => {
|
|
29252
|
-
if (err || !stdout?.trim()) {
|
|
29253
|
-
resolve16(null);
|
|
29254
|
-
} else {
|
|
29255
|
-
resolve16(stdout.trim());
|
|
29256
|
-
}
|
|
29257
|
-
});
|
|
29258
|
-
child.on("error", () => resolve16(null));
|
|
29259
|
-
});
|
|
29260
|
-
}
|
|
29261
|
-
async function detectCLIs(providerLoader, options) {
|
|
29262
|
-
const platform10 = os32.platform();
|
|
29263
|
-
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
29264
|
-
const includeVersion = options?.includeVersion !== false;
|
|
29265
|
-
const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
|
|
29266
|
-
const results = await Promise.all(
|
|
29267
|
-
cliList.map(async (cli) => {
|
|
29268
|
-
try {
|
|
29269
|
-
const explicitPath = resolveCommandPath(cli.command);
|
|
29270
|
-
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(cli.command)}`);
|
|
29271
|
-
if (!pathResult) return { ...cli, installed: false };
|
|
29272
|
-
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
29273
|
-
let version2;
|
|
29274
|
-
if (includeVersion) {
|
|
29275
|
-
const versionCommands = [
|
|
29276
|
-
`"${firstPath}" --version`,
|
|
29277
|
-
`"${firstPath}" -V`,
|
|
29278
|
-
`"${firstPath}" -v`,
|
|
29279
|
-
cli.versionCommand
|
|
29280
|
-
].filter((v) => !!v);
|
|
29281
|
-
try {
|
|
29282
|
-
for (const versionCommand of versionCommands) {
|
|
29283
|
-
const versionResult = await execAsync(versionCommand, 3e3);
|
|
29284
|
-
if (versionResult) {
|
|
29285
|
-
version2 = parseVersion(versionResult);
|
|
29286
|
-
break;
|
|
29287
|
-
}
|
|
29288
|
-
}
|
|
29289
|
-
} catch {
|
|
29290
|
-
}
|
|
29291
|
-
}
|
|
29292
|
-
return { ...cli, installed: true, version: version2, path: firstPath };
|
|
29293
|
-
} catch {
|
|
29294
|
-
return { ...cli, installed: false };
|
|
29295
|
-
}
|
|
29296
|
-
})
|
|
29297
|
-
);
|
|
29298
|
-
return results;
|
|
29299
|
-
}
|
|
29300
|
-
async function detectCLI(cliId, providerLoader, options) {
|
|
29301
|
-
const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
|
|
29302
|
-
if (providerLoader) {
|
|
29303
|
-
const cliList = providerLoader.getCliDetectionList();
|
|
29304
|
-
const target = cliList.find((c) => c.id === resolvedId);
|
|
29305
|
-
if (target) {
|
|
29306
|
-
const platform10 = os32.platform();
|
|
29307
|
-
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
29308
|
-
try {
|
|
29309
|
-
const explicitPath = resolveCommandPath(target.command);
|
|
29310
|
-
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
|
|
29311
|
-
if (!pathResult) return null;
|
|
29312
|
-
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
29313
|
-
let version2;
|
|
29314
|
-
if (options?.includeVersion !== false) {
|
|
29315
|
-
const versionCommands = [
|
|
29316
|
-
`"${firstPath}" --version`,
|
|
29317
|
-
`"${firstPath}" -V`,
|
|
29318
|
-
`"${firstPath}" -v`,
|
|
29319
|
-
target.versionCommand
|
|
29320
|
-
].filter((v) => !!v);
|
|
29321
|
-
try {
|
|
29322
|
-
for (const versionCommand of versionCommands) {
|
|
29323
|
-
const versionResult = await execAsync(versionCommand, 3e3);
|
|
29324
|
-
if (versionResult) {
|
|
29325
|
-
version2 = parseVersion(versionResult);
|
|
29326
|
-
break;
|
|
29327
|
-
}
|
|
29328
|
-
}
|
|
29329
|
-
} catch {
|
|
29330
|
-
}
|
|
29331
|
-
}
|
|
29332
|
-
return { ...target, installed: true, version: version2, path: firstPath };
|
|
29333
|
-
} catch {
|
|
29334
|
-
return null;
|
|
29335
|
-
}
|
|
29336
|
-
}
|
|
29337
|
-
}
|
|
29338
|
-
const all = await detectCLIs(providerLoader, options);
|
|
29339
|
-
return all.find((c) => c.id === resolvedId && c.installed) || null;
|
|
29340
|
-
}
|
|
29748
|
+
init_cli_detector();
|
|
29341
29749
|
var os42 = __toESM2(require("os"));
|
|
29342
29750
|
var import_child_process3 = require("child_process");
|
|
29343
29751
|
function parseDarwinAvailableBytes(totalMem) {
|
|
@@ -38361,6 +38769,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
38361
38769
|
var import_child_process6 = require("child_process");
|
|
38362
38770
|
var import_chalk = __toESM2((init_source(), __toCommonJS(source_exports)));
|
|
38363
38771
|
init_provider_cli_adapter();
|
|
38772
|
+
init_cli_detector();
|
|
38364
38773
|
init_config();
|
|
38365
38774
|
var os12 = __toESM2(require("os"));
|
|
38366
38775
|
var path16 = __toESM2(require("path"));
|
|
@@ -43914,6 +44323,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
43914
44323
|
return getProviderLoader().getAvailableIdeTypes();
|
|
43915
44324
|
}
|
|
43916
44325
|
init_config();
|
|
44326
|
+
init_cli_detector();
|
|
43917
44327
|
init_logger();
|
|
43918
44328
|
var fs8 = __toESM2(require("fs"));
|
|
43919
44329
|
var path21 = __toESM2(require("path"));
|
|
@@ -45046,6 +45456,209 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
45046
45456
|
}
|
|
45047
45457
|
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
45048
45458
|
}
|
|
45459
|
+
var REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
|
|
45460
|
+
var REFINE_VALIDATION_TIMEOUT_MS = 12e4;
|
|
45461
|
+
var REFINE_VALIDATION_OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
45462
|
+
var REFINE_VALIDATION_SUMMARY_CHARS = 2e3;
|
|
45463
|
+
var REFINE_VALIDATION_MAX_COMMANDS = 4;
|
|
45464
|
+
function truncateValidationOutput(value) {
|
|
45465
|
+
const text = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
45466
|
+
if (text.length <= REFINE_VALIDATION_SUMMARY_CHARS) return text;
|
|
45467
|
+
return `${text.slice(0, REFINE_VALIDATION_SUMMARY_CHARS)}
|
|
45468
|
+
[truncated ${text.length - REFINE_VALIDATION_SUMMARY_CHARS} chars]`;
|
|
45469
|
+
}
|
|
45470
|
+
function readPackageScripts(workspace) {
|
|
45471
|
+
try {
|
|
45472
|
+
const packageJsonPath = (0, import_path6.join)(workspace, "package.json");
|
|
45473
|
+
const parsed = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
|
|
45474
|
+
return parsed?.scripts && typeof parsed.scripts === "object" && !Array.isArray(parsed.scripts) ? parsed.scripts : {};
|
|
45475
|
+
} catch {
|
|
45476
|
+
return {};
|
|
45477
|
+
}
|
|
45478
|
+
}
|
|
45479
|
+
function tokenizeValidationCommand(command) {
|
|
45480
|
+
const trimmed = command.trim();
|
|
45481
|
+
if (!trimmed) return null;
|
|
45482
|
+
if (/[;&|<>`$\\\n\r'\"]/.test(trimmed)) return null;
|
|
45483
|
+
const tokens = trimmed.split(/\s+/).filter(Boolean);
|
|
45484
|
+
if (!tokens.length) return null;
|
|
45485
|
+
if (tokens.some((token) => !/^[A-Za-z0-9_@./:=+-]+$/.test(token))) return null;
|
|
45486
|
+
return tokens;
|
|
45487
|
+
}
|
|
45488
|
+
function scriptMatchesValidationCategory(scriptName, category) {
|
|
45489
|
+
return scriptName === category || scriptName.startsWith(`${category}:`);
|
|
45490
|
+
}
|
|
45491
|
+
function parsePackageManagerValidationCommand(rawCommand, category, scripts, source) {
|
|
45492
|
+
const tokens = tokenizeValidationCommand(rawCommand);
|
|
45493
|
+
if (!tokens) {
|
|
45494
|
+
return { rejected: { command: rawCommand, category, source, reason: "unsafe command string is not allowlisted" } };
|
|
45495
|
+
}
|
|
45496
|
+
const [binary, second, third, ...rest] = tokens;
|
|
45497
|
+
let scriptName = "";
|
|
45498
|
+
let command = binary;
|
|
45499
|
+
let args = [];
|
|
45500
|
+
if ((binary === "npm" || binary === "pnpm" || binary === "bun") && second === "run" && third) {
|
|
45501
|
+
scriptName = third;
|
|
45502
|
+
args = ["run", scriptName, ...rest];
|
|
45503
|
+
} else if (binary === "npm" && second === "test" && !third) {
|
|
45504
|
+
scriptName = "test";
|
|
45505
|
+
args = ["test"];
|
|
45506
|
+
} else if (binary === "yarn" && second === "run" && third) {
|
|
45507
|
+
scriptName = third;
|
|
45508
|
+
args = ["run", scriptName, ...rest];
|
|
45509
|
+
} else if (binary === "yarn" && second && !third) {
|
|
45510
|
+
scriptName = second;
|
|
45511
|
+
args = [scriptName];
|
|
45512
|
+
} else {
|
|
45513
|
+
return { rejected: { command: rawCommand, category, source, reason: "command is not a supported package-manager script invocation" } };
|
|
45514
|
+
}
|
|
45515
|
+
if (!scriptName || !Object.prototype.hasOwnProperty.call(scripts, scriptName)) {
|
|
45516
|
+
return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script is not declared in package.json" } };
|
|
45517
|
+
}
|
|
45518
|
+
if (!scriptMatchesValidationCategory(scriptName, category)) {
|
|
45519
|
+
return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script name is outside the validation category allowlist" } };
|
|
45520
|
+
}
|
|
45521
|
+
return {
|
|
45522
|
+
command: {
|
|
45523
|
+
command,
|
|
45524
|
+
args,
|
|
45525
|
+
displayCommand: [command, ...args].join(" "),
|
|
45526
|
+
category,
|
|
45527
|
+
source
|
|
45528
|
+
}
|
|
45529
|
+
};
|
|
45530
|
+
}
|
|
45531
|
+
function collectProjectContextValidationCandidates(mesh) {
|
|
45532
|
+
const commands = mesh?.projectContext?.commands;
|
|
45533
|
+
if (!commands || typeof commands !== "object" || Array.isArray(commands)) return [];
|
|
45534
|
+
const candidates = [];
|
|
45535
|
+
for (const category of REFINE_VALIDATION_CATEGORIES) {
|
|
45536
|
+
const entries = Array.isArray(commands[category]) ? commands[category] : [];
|
|
45537
|
+
for (const entry of entries) {
|
|
45538
|
+
if (typeof entry?.command !== "string") continue;
|
|
45539
|
+
candidates.push({
|
|
45540
|
+
command: entry.command,
|
|
45541
|
+
category,
|
|
45542
|
+
source: typeof entry.sourcePath === "string" ? entry.sourcePath : "projectContext.commands",
|
|
45543
|
+
confidence: typeof entry.confidence === "string" ? entry.confidence : void 0
|
|
45544
|
+
});
|
|
45545
|
+
}
|
|
45546
|
+
}
|
|
45547
|
+
return candidates.sort((a, b) => {
|
|
45548
|
+
const rank = (value) => value === "high" ? 0 : value === "medium" ? 1 : 2;
|
|
45549
|
+
return rank(a.confidence) - rank(b.confidence);
|
|
45550
|
+
});
|
|
45551
|
+
}
|
|
45552
|
+
function collectPolicyValidationCandidates(mesh) {
|
|
45553
|
+
const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
|
|
45554
|
+
const configured = Array.isArray(policy.validationCommands) ? policy.validationCommands : Array.isArray(policy.validationGate?.commands) ? policy.validationGate.commands : [];
|
|
45555
|
+
return configured.map((entry) => typeof entry === "string" ? { command: entry, category: "", source: "mesh.policy.validationCommands" } : entry).filter((entry) => entry && typeof entry.command === "string").map((entry) => {
|
|
45556
|
+
const commandText = entry.command.trim();
|
|
45557
|
+
const category = REFINE_VALIDATION_CATEGORIES.find((cat) => commandText.includes(` ${cat}`)) ?? "";
|
|
45558
|
+
return { command: commandText, category, source: "mesh.policy.validationCommands" };
|
|
45559
|
+
}).filter((entry) => !!entry.category);
|
|
45560
|
+
}
|
|
45561
|
+
function selectMeshRefineValidationCommands(mesh, workspace) {
|
|
45562
|
+
const scripts = readPackageScripts(workspace);
|
|
45563
|
+
const rejectedCommands = [];
|
|
45564
|
+
const selected = [];
|
|
45565
|
+
const seen = /* @__PURE__ */ new Set();
|
|
45566
|
+
const candidates = [
|
|
45567
|
+
...collectPolicyValidationCandidates(mesh),
|
|
45568
|
+
...collectProjectContextValidationCandidates(mesh)
|
|
45569
|
+
];
|
|
45570
|
+
for (const candidate of candidates) {
|
|
45571
|
+
const parsed = parsePackageManagerValidationCommand(candidate.command, candidate.category, scripts, candidate.source);
|
|
45572
|
+
if (parsed.rejected) {
|
|
45573
|
+
rejectedCommands.push(parsed.rejected);
|
|
45574
|
+
continue;
|
|
45575
|
+
}
|
|
45576
|
+
if (!parsed.command || seen.has(parsed.command.displayCommand)) continue;
|
|
45577
|
+
selected.push(parsed.command);
|
|
45578
|
+
seen.add(parsed.command.displayCommand);
|
|
45579
|
+
if (selected.length >= REFINE_VALIDATION_MAX_COMMANDS) break;
|
|
45580
|
+
}
|
|
45581
|
+
if (!selected.length && candidates.length === 0) {
|
|
45582
|
+
for (const category of REFINE_VALIDATION_CATEGORIES) {
|
|
45583
|
+
if (!Object.prototype.hasOwnProperty.call(scripts, category)) continue;
|
|
45584
|
+
const fallback = parsePackageManagerValidationCommand(`npm run ${category}`, category, scripts, "package.json:scripts");
|
|
45585
|
+
if (fallback.command && !seen.has(fallback.command.displayCommand)) {
|
|
45586
|
+
selected.push(fallback.command);
|
|
45587
|
+
seen.add(fallback.command.displayCommand);
|
|
45588
|
+
} else if (fallback.rejected) {
|
|
45589
|
+
rejectedCommands.push(fallback.rejected);
|
|
45590
|
+
}
|
|
45591
|
+
if (selected.length >= 2) break;
|
|
45592
|
+
}
|
|
45593
|
+
}
|
|
45594
|
+
return {
|
|
45595
|
+
commands: selected,
|
|
45596
|
+
rejectedCommands,
|
|
45597
|
+
source: selected.some((command) => command.source === "mesh.policy.validationCommands") ? "mesh_policy" : selected.some((command) => command.source !== "package.json:scripts") ? "project_context" : selected.length ? "package_json_scripts" : "unavailable"
|
|
45598
|
+
};
|
|
45599
|
+
}
|
|
45600
|
+
async function runMeshRefineValidationGate(mesh, workspace) {
|
|
45601
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
45602
|
+
const { promisify: promisify3 } = await import("util");
|
|
45603
|
+
const execFileAsync3 = promisify3(execFile3);
|
|
45604
|
+
const selection = selectMeshRefineValidationCommands(mesh, workspace);
|
|
45605
|
+
const summary = {
|
|
45606
|
+
status: "skipped",
|
|
45607
|
+
required: true,
|
|
45608
|
+
commandsRun: [],
|
|
45609
|
+
rejectedCommands: selection.rejectedCommands,
|
|
45610
|
+
skippedReason: void 0,
|
|
45611
|
+
timeoutMs: REFINE_VALIDATION_TIMEOUT_MS,
|
|
45612
|
+
outputLimitBytes: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES
|
|
45613
|
+
};
|
|
45614
|
+
if (!selection.commands.length) {
|
|
45615
|
+
summary.skippedReason = "validation_unavailable: no allowlisted projectContext, mesh policy, or package.json build/test/typecheck/lint command was available";
|
|
45616
|
+
return summary;
|
|
45617
|
+
}
|
|
45618
|
+
for (const candidate of selection.commands) {
|
|
45619
|
+
const startedAt = Date.now();
|
|
45620
|
+
try {
|
|
45621
|
+
const result = await execFileAsync3(candidate.command, candidate.args, {
|
|
45622
|
+
cwd: workspace,
|
|
45623
|
+
encoding: "utf8",
|
|
45624
|
+
timeout: REFINE_VALIDATION_TIMEOUT_MS,
|
|
45625
|
+
maxBuffer: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES,
|
|
45626
|
+
env: { ...process.env, CI: process.env.CI || "1" }
|
|
45627
|
+
});
|
|
45628
|
+
summary.commandsRun.push({
|
|
45629
|
+
command: candidate.command,
|
|
45630
|
+
args: candidate.args,
|
|
45631
|
+
displayCommand: candidate.displayCommand,
|
|
45632
|
+
category: candidate.category,
|
|
45633
|
+
source: candidate.source,
|
|
45634
|
+
passed: true,
|
|
45635
|
+
exitCode: 0,
|
|
45636
|
+
durationMs: Date.now() - startedAt,
|
|
45637
|
+
stdout: truncateValidationOutput(result.stdout),
|
|
45638
|
+
stderr: truncateValidationOutput(result.stderr)
|
|
45639
|
+
});
|
|
45640
|
+
} catch (error48) {
|
|
45641
|
+
summary.commandsRun.push({
|
|
45642
|
+
command: candidate.command,
|
|
45643
|
+
args: candidate.args,
|
|
45644
|
+
displayCommand: candidate.displayCommand,
|
|
45645
|
+
category: candidate.category,
|
|
45646
|
+
source: candidate.source,
|
|
45647
|
+
passed: false,
|
|
45648
|
+
exitCode: typeof error48?.code === "number" ? error48.code : null,
|
|
45649
|
+
signal: typeof error48?.signal === "string" ? error48.signal : null,
|
|
45650
|
+
timedOut: error48?.killed === true || /timed out/i.test(String(error48?.message || "")),
|
|
45651
|
+
durationMs: Date.now() - startedAt,
|
|
45652
|
+
stdout: truncateValidationOutput(error48?.stdout),
|
|
45653
|
+
stderr: truncateValidationOutput(error48?.stderr || error48?.message)
|
|
45654
|
+
});
|
|
45655
|
+
summary.status = "failed";
|
|
45656
|
+
return summary;
|
|
45657
|
+
}
|
|
45658
|
+
}
|
|
45659
|
+
summary.status = "passed";
|
|
45660
|
+
return summary;
|
|
45661
|
+
}
|
|
45049
45662
|
function loadYamlModule() {
|
|
45050
45663
|
return yaml;
|
|
45051
45664
|
}
|
|
@@ -45329,20 +45942,98 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
45329
45942
|
recoveryHint: "Inspect the worktree branch and mesh metadata before retrying cleanup."
|
|
45330
45943
|
};
|
|
45331
45944
|
}
|
|
45945
|
+
const forceFallbackConvergence = await this.getWorktreeForceCleanupConvergence({
|
|
45946
|
+
repoRoot,
|
|
45947
|
+
workspace,
|
|
45948
|
+
node: args.node
|
|
45949
|
+
});
|
|
45332
45950
|
try {
|
|
45333
|
-
const result = await removeWorktree2(repoRoot, workspace, {
|
|
45334
|
-
|
|
45951
|
+
const result = await removeWorktree2(repoRoot, workspace, {
|
|
45952
|
+
requireClean: true,
|
|
45953
|
+
allowSubmoduleForceFallback: forceFallbackConvergence.allow
|
|
45954
|
+
});
|
|
45955
|
+
return {
|
|
45956
|
+
success: true,
|
|
45957
|
+
removedPath: result.removedPath,
|
|
45958
|
+
repoRoot,
|
|
45959
|
+
...result.fallback ? {
|
|
45960
|
+
fallback: result.fallback,
|
|
45961
|
+
forced: result.forced,
|
|
45962
|
+
reason: result.reason,
|
|
45963
|
+
convergence: forceFallbackConvergence
|
|
45964
|
+
} : {}
|
|
45965
|
+
};
|
|
45335
45966
|
} catch (e) {
|
|
45336
45967
|
const message = String(e?.message || e || "worktree cleanup failed");
|
|
45337
45968
|
const dirty = message.includes("dirty worktree") || message.includes("local changes");
|
|
45969
|
+
const submoduleForceBlocked = /working trees containing submodules cannot be moved or removed/i.test(message) && !forceFallbackConvergence.allow;
|
|
45338
45970
|
return {
|
|
45339
45971
|
success: false,
|
|
45340
|
-
code: dirty ? "mesh_worktree_cleanup_dirty" : "mesh_worktree_cleanup_failed",
|
|
45341
|
-
error: message,
|
|
45342
|
-
recoveryHint: dirty ? "Commit, stash, or intentionally discard the worktree changes before retrying mesh_remove_node. The mesh registry entry is preserved until cleanup is safe." : "Inspect git worktree status/list from the source repo and retry after resolving the reported cleanup failure."
|
|
45972
|
+
code: dirty ? "mesh_worktree_cleanup_dirty" : submoduleForceBlocked ? "mesh_worktree_cleanup_force_fallback_blocked" : "mesh_worktree_cleanup_failed",
|
|
45973
|
+
error: submoduleForceBlocked ? `${message}; refusing --force fallback because convergence could not be verified: ${forceFallbackConvergence.error || "unknown convergence state"}` : message,
|
|
45974
|
+
recoveryHint: dirty ? "Commit, stash, or intentionally discard the worktree changes before retrying mesh_remove_node. The mesh registry entry is preserved until cleanup is safe." : submoduleForceBlocked ? "Verify the worktree branch is merged/contained in the source default branch (for example origin/main) or mark the node with a safe branchConvergence final state before retrying. The mesh registry entry is preserved." : "Inspect git worktree status/list from the source repo and retry after resolving the reported cleanup failure.",
|
|
45975
|
+
...submoduleForceBlocked ? { convergence: forceFallbackConvergence } : {}
|
|
45343
45976
|
};
|
|
45344
45977
|
}
|
|
45345
45978
|
}
|
|
45979
|
+
async getWorktreeForceCleanupConvergence(args) {
|
|
45980
|
+
const metadataStatus = typeof args.node?.branchConvergence?.status === "string" ? args.node.branchConvergence.status : "";
|
|
45981
|
+
if (metadataStatus === "merged_to_main" || metadataStatus === "cleanup_candidate") {
|
|
45982
|
+
return { allow: true, status: metadataStatus, source: "node_branch_convergence" };
|
|
45983
|
+
}
|
|
45984
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
45985
|
+
const { promisify: promisify3 } = await import("util");
|
|
45986
|
+
const execFileAsync3 = promisify3(execFile3);
|
|
45987
|
+
const runGit2 = async (gitArgs, cwd) => {
|
|
45988
|
+
const { stdout } = await execFileAsync3("git", gitArgs, {
|
|
45989
|
+
cwd,
|
|
45990
|
+
encoding: "utf8",
|
|
45991
|
+
timeout: 3e4,
|
|
45992
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
45993
|
+
windowsHide: true
|
|
45994
|
+
});
|
|
45995
|
+
return String(stdout || "").trim();
|
|
45996
|
+
};
|
|
45997
|
+
let head = "";
|
|
45998
|
+
try {
|
|
45999
|
+
head = await runGit2(["rev-parse", "HEAD"], args.workspace);
|
|
46000
|
+
} catch (e) {
|
|
46001
|
+
return { allow: false, error: `could not resolve worktree HEAD: ${e?.message || e}` };
|
|
46002
|
+
}
|
|
46003
|
+
if (!head) return { allow: false, error: "worktree HEAD is empty" };
|
|
46004
|
+
const candidateRefs = [];
|
|
46005
|
+
try {
|
|
46006
|
+
const defaultBranch = await runGit2(["branch", "--show-current"], args.repoRoot);
|
|
46007
|
+
if (defaultBranch) {
|
|
46008
|
+
candidateRefs.push(defaultBranch, `origin/${defaultBranch}`);
|
|
46009
|
+
}
|
|
46010
|
+
} catch {
|
|
46011
|
+
}
|
|
46012
|
+
candidateRefs.push("origin/main", "origin/master", "main", "master");
|
|
46013
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46014
|
+
const checkedRefs = [];
|
|
46015
|
+
for (const ref of candidateRefs) {
|
|
46016
|
+
if (!ref || seen.has(ref)) continue;
|
|
46017
|
+
seen.add(ref);
|
|
46018
|
+
let commit = "";
|
|
46019
|
+
try {
|
|
46020
|
+
commit = await runGit2(["rev-parse", "--verify", `${ref}^{commit}`], args.repoRoot);
|
|
46021
|
+
} catch {
|
|
46022
|
+
continue;
|
|
46023
|
+
}
|
|
46024
|
+
checkedRefs.push(ref);
|
|
46025
|
+
try {
|
|
46026
|
+
await runGit2(["merge-base", "--is-ancestor", head, commit], args.repoRoot);
|
|
46027
|
+
return { allow: true, status: "merged_to_default_ref", source: "git_merge_base", ref };
|
|
46028
|
+
} catch {
|
|
46029
|
+
}
|
|
46030
|
+
}
|
|
46031
|
+
return {
|
|
46032
|
+
allow: false,
|
|
46033
|
+
status: metadataStatus || void 0,
|
|
46034
|
+
error: checkedRefs.length ? `worktree HEAD is not contained in checked refs: ${checkedRefs.join(", ")}` : "no default/main refs were available for convergence verification"
|
|
46035
|
+
};
|
|
46036
|
+
}
|
|
45346
46037
|
isCompletedHostedSession(record2) {
|
|
45347
46038
|
return record2?.lifecycle === "stopped" || record2?.lifecycle === "failed" || record2?.lifecycle === "interrupted";
|
|
45348
46039
|
}
|
|
@@ -46302,10 +46993,61 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
46302
46993
|
if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
|
|
46303
46994
|
const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
|
|
46304
46995
|
const baseBranch = baseBranchStdout.trim();
|
|
46996
|
+
const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace);
|
|
46997
|
+
if (validationSummary.status === "failed") {
|
|
46998
|
+
return {
|
|
46999
|
+
success: false,
|
|
47000
|
+
code: "validation_failed",
|
|
47001
|
+
convergenceStatus: "blocked_review",
|
|
47002
|
+
error: "Refinery validation gate failed; merge/refine was not attempted.",
|
|
47003
|
+
branch,
|
|
47004
|
+
into: baseBranch,
|
|
47005
|
+
validationSummary,
|
|
47006
|
+
finalBranchConvergenceState: {
|
|
47007
|
+
branch,
|
|
47008
|
+
baseBranch,
|
|
47009
|
+
merged: false,
|
|
47010
|
+
removed: false,
|
|
47011
|
+
validation: "failed",
|
|
47012
|
+
status: "blocked_review"
|
|
47013
|
+
}
|
|
47014
|
+
};
|
|
47015
|
+
}
|
|
47016
|
+
if (validationSummary.status === "skipped") {
|
|
47017
|
+
return {
|
|
47018
|
+
success: false,
|
|
47019
|
+
code: "validation_unavailable",
|
|
47020
|
+
convergenceStatus: "blocked_review",
|
|
47021
|
+
error: "Refinery validation gate is required but no allowlisted validation command was available; merge/refine was not attempted.",
|
|
47022
|
+
branch,
|
|
47023
|
+
into: baseBranch,
|
|
47024
|
+
validationSummary,
|
|
47025
|
+
finalBranchConvergenceState: {
|
|
47026
|
+
branch,
|
|
47027
|
+
baseBranch,
|
|
47028
|
+
merged: false,
|
|
47029
|
+
removed: false,
|
|
47030
|
+
validation: "unavailable",
|
|
47031
|
+
status: "blocked_review"
|
|
47032
|
+
}
|
|
47033
|
+
};
|
|
47034
|
+
}
|
|
46305
47035
|
try {
|
|
46306
47036
|
await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
|
|
46307
47037
|
} catch (e) {
|
|
46308
|
-
return {
|
|
47038
|
+
return {
|
|
47039
|
+
success: false,
|
|
47040
|
+
error: `Merge failed (conflicts?): ${e.message}`,
|
|
47041
|
+
validationSummary,
|
|
47042
|
+
finalBranchConvergenceState: {
|
|
47043
|
+
branch,
|
|
47044
|
+
baseBranch,
|
|
47045
|
+
merged: false,
|
|
47046
|
+
removed: false,
|
|
47047
|
+
validation: "passed",
|
|
47048
|
+
status: "not_mergeable"
|
|
47049
|
+
}
|
|
47050
|
+
};
|
|
46309
47051
|
}
|
|
46310
47052
|
const removeResult = await this.execute("remove_mesh_node", {
|
|
46311
47053
|
meshId,
|
|
@@ -46318,11 +47060,27 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
46318
47060
|
appendLedgerEntry2(meshId, {
|
|
46319
47061
|
kind: "node_removed",
|
|
46320
47062
|
nodeId,
|
|
46321
|
-
payload: { refined: true, mergedBranch: branch, into: baseBranch }
|
|
47063
|
+
payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary }
|
|
46322
47064
|
});
|
|
46323
47065
|
} catch {
|
|
46324
47066
|
}
|
|
46325
|
-
return {
|
|
47067
|
+
return {
|
|
47068
|
+
success: true,
|
|
47069
|
+
merged: true,
|
|
47070
|
+
branch,
|
|
47071
|
+
into: baseBranch,
|
|
47072
|
+
removeResult,
|
|
47073
|
+
validationSummary,
|
|
47074
|
+
finalBranchConvergenceState: {
|
|
47075
|
+
branch: baseBranch,
|
|
47076
|
+
mergedBranch: branch,
|
|
47077
|
+
baseBranch,
|
|
47078
|
+
merged: true,
|
|
47079
|
+
removed: removeResult?.success !== false,
|
|
47080
|
+
validation: "passed",
|
|
47081
|
+
status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
|
|
47082
|
+
}
|
|
47083
|
+
};
|
|
46326
47084
|
} catch (e) {
|
|
46327
47085
|
return { success: false, error: e.message };
|
|
46328
47086
|
}
|
|
@@ -46377,7 +47135,10 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
46377
47135
|
sessionCleanupMode,
|
|
46378
47136
|
workspace: typeof node?.workspace === "string" ? node.workspace : void 0,
|
|
46379
47137
|
daemonId: typeof node?.daemonId === "string" ? node.daemonId : void 0,
|
|
46380
|
-
worktreeBranch: typeof node?.worktreeBranch === "string" ? node.worktreeBranch : void 0
|
|
47138
|
+
worktreeBranch: typeof node?.worktreeBranch === "string" ? node.worktreeBranch : void 0,
|
|
47139
|
+
worktreeCleanupFallback: typeof worktreeCleanup?.fallback === "string" ? worktreeCleanup.fallback : void 0,
|
|
47140
|
+
forced: worktreeCleanup?.forced === true ? true : void 0,
|
|
47141
|
+
forceFallbackReason: typeof worktreeCleanup?.reason === "string" ? worktreeCleanup.reason : void 0
|
|
46381
47142
|
}
|
|
46382
47143
|
});
|
|
46383
47144
|
} catch {
|
|
@@ -54460,6 +55221,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
54460
55221
|
return false;
|
|
54461
55222
|
}
|
|
54462
55223
|
}
|
|
55224
|
+
init_cli_detector();
|
|
54463
55225
|
var SessionRegistry = class {
|
|
54464
55226
|
bySessionId = /* @__PURE__ */ new Map();
|
|
54465
55227
|
byManagerKey = /* @__PURE__ */ new Map();
|