@adhdev/daemon-standalone 0.9.77-rc.44 → 0.9.77-rc.45
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 +925 -172
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/vendor/mcp-server/index.js +995 -187
- 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 = {};
|
|
@@ -23112,6 +23140,7 @@ Follow these recovery rules:
|
|
|
23112
23140
|
enqueueTask: () => enqueueTask,
|
|
23113
23141
|
getMeshQueueStats: () => getMeshQueueStats,
|
|
23114
23142
|
getQueue: () => getQueue,
|
|
23143
|
+
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
23115
23144
|
requeueTask: () => requeueTask,
|
|
23116
23145
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
23117
23146
|
updateTaskStatus: () => updateTaskStatus
|
|
@@ -23187,6 +23216,19 @@ Follow these recovery rules:
|
|
|
23187
23216
|
writeQueue(meshId, queue);
|
|
23188
23217
|
return queue[idx];
|
|
23189
23218
|
}
|
|
23219
|
+
function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
|
|
23220
|
+
const queue = readQueue(meshId);
|
|
23221
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
23222
|
+
if (idx === -1) return null;
|
|
23223
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23224
|
+
queue[idx].autoLaunch = {
|
|
23225
|
+
...autoLaunch,
|
|
23226
|
+
updatedAt: now
|
|
23227
|
+
};
|
|
23228
|
+
queue[idx].updatedAt = now;
|
|
23229
|
+
writeQueue(meshId, queue);
|
|
23230
|
+
return queue[idx];
|
|
23231
|
+
}
|
|
23190
23232
|
function cancelTask(meshId, taskId, opts) {
|
|
23191
23233
|
const queue = readQueue(meshId);
|
|
23192
23234
|
const idx = queue.findIndex((q) => q.id === taskId);
|
|
@@ -23261,6 +23303,142 @@ Follow these recovery rules:
|
|
|
23261
23303
|
init_mesh_ledger();
|
|
23262
23304
|
}
|
|
23263
23305
|
});
|
|
23306
|
+
function parseVersion(raw) {
|
|
23307
|
+
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
23308
|
+
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
23309
|
+
}
|
|
23310
|
+
function shellQuote(value) {
|
|
23311
|
+
if (/^[a-zA-Z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
23312
|
+
return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
23313
|
+
}
|
|
23314
|
+
function expandHome(value) {
|
|
23315
|
+
const trimmed = value.trim();
|
|
23316
|
+
if (!trimmed.startsWith("~")) return trimmed;
|
|
23317
|
+
return path8.join(os22.homedir(), trimmed.slice(1));
|
|
23318
|
+
}
|
|
23319
|
+
function isExplicitCommandPath(command) {
|
|
23320
|
+
const trimmed = command.trim();
|
|
23321
|
+
return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
23322
|
+
}
|
|
23323
|
+
function resolveCommandPath(command) {
|
|
23324
|
+
const trimmed = command.trim();
|
|
23325
|
+
if (!trimmed) return null;
|
|
23326
|
+
if (isExplicitCommandPath(trimmed)) {
|
|
23327
|
+
const expanded = expandHome(trimmed);
|
|
23328
|
+
const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
|
|
23329
|
+
return (0, import_fs5.existsSync)(candidate) ? candidate : null;
|
|
23330
|
+
}
|
|
23331
|
+
return null;
|
|
23332
|
+
}
|
|
23333
|
+
function execAsync(cmd, timeoutMs = 5e3) {
|
|
23334
|
+
return new Promise((resolve16) => {
|
|
23335
|
+
const child = (0, import_child_process.exec)(cmd, {
|
|
23336
|
+
encoding: "utf-8",
|
|
23337
|
+
timeout: timeoutMs,
|
|
23338
|
+
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
23339
|
+
}, (err, stdout) => {
|
|
23340
|
+
if (err || !stdout?.trim()) {
|
|
23341
|
+
resolve16(null);
|
|
23342
|
+
} else {
|
|
23343
|
+
resolve16(stdout.trim());
|
|
23344
|
+
}
|
|
23345
|
+
});
|
|
23346
|
+
child.on("error", () => resolve16(null));
|
|
23347
|
+
});
|
|
23348
|
+
}
|
|
23349
|
+
async function detectCLIs(providerLoader, options) {
|
|
23350
|
+
const platform10 = os22.platform();
|
|
23351
|
+
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
23352
|
+
const includeVersion = options?.includeVersion !== false;
|
|
23353
|
+
const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
|
|
23354
|
+
const results = await Promise.all(
|
|
23355
|
+
cliList.map(async (cli) => {
|
|
23356
|
+
try {
|
|
23357
|
+
const explicitPath = resolveCommandPath(cli.command);
|
|
23358
|
+
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(cli.command)}`);
|
|
23359
|
+
if (!pathResult) return { ...cli, installed: false };
|
|
23360
|
+
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
23361
|
+
let version2;
|
|
23362
|
+
if (includeVersion) {
|
|
23363
|
+
const versionCommands = [
|
|
23364
|
+
`"${firstPath}" --version`,
|
|
23365
|
+
`"${firstPath}" -V`,
|
|
23366
|
+
`"${firstPath}" -v`,
|
|
23367
|
+
cli.versionCommand
|
|
23368
|
+
].filter((v) => !!v);
|
|
23369
|
+
try {
|
|
23370
|
+
for (const versionCommand of versionCommands) {
|
|
23371
|
+
const versionResult = await execAsync(versionCommand, 3e3);
|
|
23372
|
+
if (versionResult) {
|
|
23373
|
+
version2 = parseVersion(versionResult);
|
|
23374
|
+
break;
|
|
23375
|
+
}
|
|
23376
|
+
}
|
|
23377
|
+
} catch {
|
|
23378
|
+
}
|
|
23379
|
+
}
|
|
23380
|
+
return { ...cli, installed: true, version: version2, path: firstPath };
|
|
23381
|
+
} catch {
|
|
23382
|
+
return { ...cli, installed: false };
|
|
23383
|
+
}
|
|
23384
|
+
})
|
|
23385
|
+
);
|
|
23386
|
+
return results;
|
|
23387
|
+
}
|
|
23388
|
+
async function detectCLI(cliId, providerLoader, options) {
|
|
23389
|
+
const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
|
|
23390
|
+
if (providerLoader) {
|
|
23391
|
+
const cliList = providerLoader.getCliDetectionList();
|
|
23392
|
+
const target = cliList.find((c) => c.id === resolvedId);
|
|
23393
|
+
if (target) {
|
|
23394
|
+
const platform10 = os22.platform();
|
|
23395
|
+
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
23396
|
+
try {
|
|
23397
|
+
const explicitPath = resolveCommandPath(target.command);
|
|
23398
|
+
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
|
|
23399
|
+
if (!pathResult) return null;
|
|
23400
|
+
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
23401
|
+
let version2;
|
|
23402
|
+
if (options?.includeVersion !== false) {
|
|
23403
|
+
const versionCommands = [
|
|
23404
|
+
`"${firstPath}" --version`,
|
|
23405
|
+
`"${firstPath}" -V`,
|
|
23406
|
+
`"${firstPath}" -v`,
|
|
23407
|
+
target.versionCommand
|
|
23408
|
+
].filter((v) => !!v);
|
|
23409
|
+
try {
|
|
23410
|
+
for (const versionCommand of versionCommands) {
|
|
23411
|
+
const versionResult = await execAsync(versionCommand, 3e3);
|
|
23412
|
+
if (versionResult) {
|
|
23413
|
+
version2 = parseVersion(versionResult);
|
|
23414
|
+
break;
|
|
23415
|
+
}
|
|
23416
|
+
}
|
|
23417
|
+
} catch {
|
|
23418
|
+
}
|
|
23419
|
+
}
|
|
23420
|
+
return { ...target, installed: true, version: version2, path: firstPath };
|
|
23421
|
+
} catch {
|
|
23422
|
+
return null;
|
|
23423
|
+
}
|
|
23424
|
+
}
|
|
23425
|
+
}
|
|
23426
|
+
const all = await detectCLIs(providerLoader, options);
|
|
23427
|
+
return all.find((c) => c.id === resolvedId && c.installed) || null;
|
|
23428
|
+
}
|
|
23429
|
+
var import_child_process;
|
|
23430
|
+
var os22;
|
|
23431
|
+
var path8;
|
|
23432
|
+
var import_fs5;
|
|
23433
|
+
var init_cli_detector = __esm2({
|
|
23434
|
+
"src/detection/cli-detector.ts"() {
|
|
23435
|
+
"use strict";
|
|
23436
|
+
import_child_process = require("child_process");
|
|
23437
|
+
os22 = __toESM2(require("os"));
|
|
23438
|
+
path8 = __toESM2(require("path"));
|
|
23439
|
+
import_fs5 = require("fs");
|
|
23440
|
+
}
|
|
23441
|
+
});
|
|
23264
23442
|
function setLogLevel(level) {
|
|
23265
23443
|
currentLevel = level;
|
|
23266
23444
|
daemonLog("Logger", `Log level set to: ${level}`, "info");
|
|
@@ -23275,13 +23453,13 @@ Follow these recovery rules:
|
|
|
23275
23453
|
return LOG_DIR;
|
|
23276
23454
|
}
|
|
23277
23455
|
function getCurrentDaemonLogPath(date5 = /* @__PURE__ */ new Date()) {
|
|
23278
|
-
return
|
|
23456
|
+
return path9.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
|
|
23279
23457
|
}
|
|
23280
23458
|
function checkDateRotation() {
|
|
23281
23459
|
const today = getDateStr();
|
|
23282
23460
|
if (today !== currentDate) {
|
|
23283
23461
|
currentDate = today;
|
|
23284
|
-
currentLogFile =
|
|
23462
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
23285
23463
|
cleanOldLogs();
|
|
23286
23464
|
}
|
|
23287
23465
|
}
|
|
@@ -23295,7 +23473,7 @@ Follow these recovery rules:
|
|
|
23295
23473
|
const dateMatch = file2.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
23296
23474
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
23297
23475
|
try {
|
|
23298
|
-
fs22.unlinkSync(
|
|
23476
|
+
fs22.unlinkSync(path9.join(LOG_DIR, file2));
|
|
23299
23477
|
} catch {
|
|
23300
23478
|
}
|
|
23301
23479
|
}
|
|
@@ -23412,8 +23590,8 @@ Follow these recovery rules:
|
|
|
23412
23590
|
writeToFile(`Log level: ${currentLevel}`);
|
|
23413
23591
|
}
|
|
23414
23592
|
var fs22;
|
|
23415
|
-
var
|
|
23416
|
-
var
|
|
23593
|
+
var path9;
|
|
23594
|
+
var os32;
|
|
23417
23595
|
var LEVEL_NUM;
|
|
23418
23596
|
var LEVEL_LABEL;
|
|
23419
23597
|
var currentLevel;
|
|
@@ -23435,12 +23613,12 @@ Follow these recovery rules:
|
|
|
23435
23613
|
"src/logging/logger.ts"() {
|
|
23436
23614
|
"use strict";
|
|
23437
23615
|
fs22 = __toESM2(require("fs"));
|
|
23438
|
-
|
|
23439
|
-
|
|
23616
|
+
path9 = __toESM2(require("path"));
|
|
23617
|
+
os32 = __toESM2(require("os"));
|
|
23440
23618
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
23441
23619
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
23442
23620
|
currentLevel = "info";
|
|
23443
|
-
LOG_DIR = process.platform === "win32" ?
|
|
23621
|
+
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
23622
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
23445
23623
|
MAX_LOG_DAYS = 7;
|
|
23446
23624
|
try {
|
|
@@ -23448,16 +23626,16 @@ Follow these recovery rules:
|
|
|
23448
23626
|
} catch {
|
|
23449
23627
|
}
|
|
23450
23628
|
currentDate = getDateStr();
|
|
23451
|
-
currentLogFile =
|
|
23629
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
23452
23630
|
cleanOldLogs();
|
|
23453
23631
|
try {
|
|
23454
|
-
const oldLog =
|
|
23632
|
+
const oldLog = path9.join(LOG_DIR, "daemon.log");
|
|
23455
23633
|
if (fs22.existsSync(oldLog)) {
|
|
23456
23634
|
const stat2 = fs22.statSync(oldLog);
|
|
23457
23635
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
23458
|
-
fs22.renameSync(oldLog,
|
|
23636
|
+
fs22.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
23459
23637
|
}
|
|
23460
|
-
const oldLogBackup =
|
|
23638
|
+
const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
|
|
23461
23639
|
if (fs22.existsSync(oldLogBackup)) {
|
|
23462
23640
|
fs22.unlinkSync(oldLogBackup);
|
|
23463
23641
|
}
|
|
@@ -23489,7 +23667,7 @@ Follow these recovery rules:
|
|
|
23489
23667
|
}
|
|
23490
23668
|
};
|
|
23491
23669
|
interceptorInstalled = false;
|
|
23492
|
-
LOG_PATH =
|
|
23670
|
+
LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
23493
23671
|
}
|
|
23494
23672
|
});
|
|
23495
23673
|
var mesh_events_exports = {};
|
|
@@ -23559,7 +23737,235 @@ Follow these recovery rules:
|
|
|
23559
23737
|
});
|
|
23560
23738
|
return true;
|
|
23561
23739
|
}
|
|
23562
|
-
function
|
|
23740
|
+
function normalizeProviderPriority(policy) {
|
|
23741
|
+
const raw = policy && typeof policy === "object" && !Array.isArray(policy) ? policy.providerPriority : void 0;
|
|
23742
|
+
if (!Array.isArray(raw)) return [];
|
|
23743
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23744
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
23745
|
+
if (seen.has(type)) return false;
|
|
23746
|
+
seen.add(type);
|
|
23747
|
+
return true;
|
|
23748
|
+
});
|
|
23749
|
+
}
|
|
23750
|
+
function isTerminalSessionStatus(status) {
|
|
23751
|
+
return ["stopped", "failed", "terminated", "exited", "closed"].includes(status);
|
|
23752
|
+
}
|
|
23753
|
+
function isIdleSessionState(state) {
|
|
23754
|
+
const status = readNonEmptyString(state?.status).toLowerCase();
|
|
23755
|
+
if (isTerminalSessionStatus(status)) return false;
|
|
23756
|
+
return status === "idle" || state?.activeChat?.status === "waiting_input";
|
|
23757
|
+
}
|
|
23758
|
+
function isDirtyNode(node) {
|
|
23759
|
+
return node?.health === "dirty" || node?.git?.dirty === true;
|
|
23760
|
+
}
|
|
23761
|
+
function isLaunchableNode(node) {
|
|
23762
|
+
if (!node || node.status === "disabled" || node.status === "removed") return false;
|
|
23763
|
+
const health = readNonEmptyString(node.health).toLowerCase();
|
|
23764
|
+
if (!health) return true;
|
|
23765
|
+
return health === "online" || health === "unknown";
|
|
23766
|
+
}
|
|
23767
|
+
function localAutoLaunchSkipReason(node) {
|
|
23768
|
+
const daemonId = readNonEmptyString(node?.daemonId);
|
|
23769
|
+
const machineId = readNonEmptyString(node?.machineId);
|
|
23770
|
+
const appConfig = loadConfig2();
|
|
23771
|
+
const localMachineId = readNonEmptyString(appConfig.machineId) || readNonEmptyString(appConfig.registeredMachineId);
|
|
23772
|
+
const cloudDaemonId = localMachineId ? `daemon_${localMachineId}` : "";
|
|
23773
|
+
const standaloneDaemonId = localMachineId ? `standalone_${localMachineId}` : "";
|
|
23774
|
+
const daemonMatchesLocal = !daemonId || daemonId === cloudDaemonId || daemonId === standaloneDaemonId;
|
|
23775
|
+
const machineMatchesLocal = !machineId || localMachineId && machineId === localMachineId;
|
|
23776
|
+
if (node?.isLocalWorktree === true) {
|
|
23777
|
+
return daemonMatchesLocal && machineMatchesLocal ? null : "remote_auto_launch_unsupported";
|
|
23778
|
+
}
|
|
23779
|
+
if (daemonId || machineId) {
|
|
23780
|
+
return daemonMatchesLocal && machineMatchesLocal ? null : "remote_auto_launch_unsupported";
|
|
23781
|
+
}
|
|
23782
|
+
return null;
|
|
23783
|
+
}
|
|
23784
|
+
function activeAssignedCount(meshId) {
|
|
23785
|
+
return getQueue(meshId, { status: ["assigned"] }).length;
|
|
23786
|
+
}
|
|
23787
|
+
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
23788
|
+
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
|
|
23789
|
+
}
|
|
23790
|
+
function liveSessionCountForNode(components, meshId, nodeId) {
|
|
23791
|
+
return components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
23792
|
+
const state = inst.getState();
|
|
23793
|
+
const settings = state.settings || {};
|
|
23794
|
+
if (readNonEmptyString(settings.meshNodeFor) !== meshId) return false;
|
|
23795
|
+
const instNodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
23796
|
+
if (instNodeId !== nodeId) return false;
|
|
23797
|
+
const status = readNonEmptyString(state.status).toLowerCase();
|
|
23798
|
+
return !isTerminalSessionStatus(status);
|
|
23799
|
+
}).length;
|
|
23800
|
+
}
|
|
23801
|
+
function recordAutoLaunchEvent(meshId, args) {
|
|
23802
|
+
try {
|
|
23803
|
+
appendLedgerEntry(meshId, {
|
|
23804
|
+
kind: "session_auto_launch",
|
|
23805
|
+
nodeId: args.nodeId,
|
|
23806
|
+
sessionId: args.sessionId,
|
|
23807
|
+
providerType: args.providerType,
|
|
23808
|
+
payload: {
|
|
23809
|
+
phase: args.phase,
|
|
23810
|
+
taskId: args.taskId,
|
|
23811
|
+
reason: args.reason,
|
|
23812
|
+
error: args.error
|
|
23813
|
+
}
|
|
23814
|
+
});
|
|
23815
|
+
} catch (e) {
|
|
23816
|
+
LOG2.warn("MeshQueue", `Failed to record auto-launch ledger event: ${e?.message || e}`);
|
|
23817
|
+
}
|
|
23818
|
+
}
|
|
23819
|
+
function markAutoLaunch(meshId, taskId, args) {
|
|
23820
|
+
recordTaskAutoLaunch(meshId, taskId, {
|
|
23821
|
+
status: args.status,
|
|
23822
|
+
reason: args.reason || args.error,
|
|
23823
|
+
nodeId: args.nodeId,
|
|
23824
|
+
providerType: args.providerType,
|
|
23825
|
+
sessionId: args.sessionId
|
|
23826
|
+
});
|
|
23827
|
+
recordAutoLaunchEvent(meshId, {
|
|
23828
|
+
phase: args.status,
|
|
23829
|
+
taskId,
|
|
23830
|
+
nodeId: args.nodeId,
|
|
23831
|
+
providerType: args.providerType,
|
|
23832
|
+
sessionId: args.sessionId,
|
|
23833
|
+
reason: args.reason,
|
|
23834
|
+
error: args.error
|
|
23835
|
+
});
|
|
23836
|
+
}
|
|
23837
|
+
async function resolveUsableProvider(components, nodeId, node) {
|
|
23838
|
+
const providerPriority = normalizeProviderPriority(node?.policy);
|
|
23839
|
+
if (!providerPriority.length) return { reason: "missing_provider_priority" };
|
|
23840
|
+
const providerLoader = components.providerLoader;
|
|
23841
|
+
if (!providerLoader) return { reason: "provider_loader_unavailable" };
|
|
23842
|
+
const failed = [];
|
|
23843
|
+
for (const requestedType of providerPriority) {
|
|
23844
|
+
const normalizedType = typeof providerLoader.resolveAlias === "function" ? providerLoader.resolveAlias(requestedType) : requestedType;
|
|
23845
|
+
if (typeof providerLoader.isMachineProviderEnabled === "function" && !providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
23846
|
+
failed.push(`${requestedType}: disabled`);
|
|
23847
|
+
continue;
|
|
23848
|
+
}
|
|
23849
|
+
let detected;
|
|
23850
|
+
try {
|
|
23851
|
+
detected = await detectCLI(normalizedType, providerLoader, { includeVersion: false });
|
|
23852
|
+
} catch (e) {
|
|
23853
|
+
failed.push(`${requestedType}: detect failed: ${e?.message || e}`);
|
|
23854
|
+
continue;
|
|
23855
|
+
}
|
|
23856
|
+
if (typeof providerLoader.setCliDetectionResults === "function") {
|
|
23857
|
+
providerLoader.setCliDetectionResults([{
|
|
23858
|
+
id: normalizedType,
|
|
23859
|
+
installed: !!detected,
|
|
23860
|
+
path: detected?.path
|
|
23861
|
+
}], false);
|
|
23862
|
+
}
|
|
23863
|
+
components.onStatusChange?.();
|
|
23864
|
+
if (detected) return { providerType: normalizedType };
|
|
23865
|
+
failed.push(`${requestedType}: not detected`);
|
|
23866
|
+
}
|
|
23867
|
+
return { reason: `provider_priority_unusable: ${failed.join("; ") || nodeId}` };
|
|
23868
|
+
}
|
|
23869
|
+
async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
23870
|
+
const queue = getQueue(meshId);
|
|
23871
|
+
const pending = queue.filter((task) => task.status === "pending");
|
|
23872
|
+
if (!pending.length) return false;
|
|
23873
|
+
const maxParallelTasks = Math.max(1, Math.floor(Number(mesh?.policy?.maxParallelTasks) || 2));
|
|
23874
|
+
for (const task of pending) {
|
|
23875
|
+
if (activeAssignedCount(meshId) >= maxParallelTasks) {
|
|
23876
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_parallel_tasks_reached" });
|
|
23877
|
+
return false;
|
|
23878
|
+
}
|
|
23879
|
+
if (task.targetSessionId) {
|
|
23880
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_constraint" });
|
|
23881
|
+
continue;
|
|
23882
|
+
}
|
|
23883
|
+
const candidateNodes = Array.isArray(mesh?.nodes) ? mesh.nodes.filter((node) => task.targetNodeId ? node?.id === task.targetNodeId : true) : [];
|
|
23884
|
+
if (!candidateNodes.length) {
|
|
23885
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "no_matching_node", nodeId: task.targetNodeId });
|
|
23886
|
+
continue;
|
|
23887
|
+
}
|
|
23888
|
+
for (const node of candidateNodes) {
|
|
23889
|
+
const nodeId = readNonEmptyString(node?.id);
|
|
23890
|
+
if (!nodeId) continue;
|
|
23891
|
+
const launchKey = `${meshId}:${nodeId}`;
|
|
23892
|
+
const cooldownUntil = autoLaunchCooldownUntil.get(launchKey) || 0;
|
|
23893
|
+
if (autoLaunchInProgress.has(launchKey)) {
|
|
23894
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "auto_launch_in_progress", nodeId });
|
|
23895
|
+
continue;
|
|
23896
|
+
}
|
|
23897
|
+
if (Date.now() < cooldownUntil) {
|
|
23898
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "auto_launch_cooldown", nodeId });
|
|
23899
|
+
continue;
|
|
23900
|
+
}
|
|
23901
|
+
if (isDirtyNode(node)) {
|
|
23902
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "dirty_workspace", nodeId });
|
|
23903
|
+
continue;
|
|
23904
|
+
}
|
|
23905
|
+
if (!isLaunchableNode(node)) {
|
|
23906
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_not_launch_ready", nodeId });
|
|
23907
|
+
continue;
|
|
23908
|
+
}
|
|
23909
|
+
const localSkipReason = localAutoLaunchSkipReason(node);
|
|
23910
|
+
if (localSkipReason) {
|
|
23911
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: localSkipReason, nodeId });
|
|
23912
|
+
continue;
|
|
23913
|
+
}
|
|
23914
|
+
if (nodeHasActiveAssignment(meshId, nodeId)) {
|
|
23915
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_has_active_assignment", nodeId });
|
|
23916
|
+
continue;
|
|
23917
|
+
}
|
|
23918
|
+
const maxConcurrentSessions = Number(node?.policy?.maxConcurrentSessions);
|
|
23919
|
+
if (Number.isFinite(maxConcurrentSessions) && maxConcurrentSessions >= 0 && liveSessionCountForNode(components, meshId, nodeId) >= maxConcurrentSessions) {
|
|
23920
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_concurrent_sessions_reached", nodeId });
|
|
23921
|
+
continue;
|
|
23922
|
+
}
|
|
23923
|
+
autoLaunchInProgress.add(launchKey);
|
|
23924
|
+
try {
|
|
23925
|
+
const resolved = await resolveUsableProvider(components, nodeId, node);
|
|
23926
|
+
if (!resolved.providerType) {
|
|
23927
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: resolved.reason || "provider_unusable", nodeId });
|
|
23928
|
+
continue;
|
|
23929
|
+
}
|
|
23930
|
+
markAutoLaunch(meshId, task.id, { status: "started", nodeId, providerType: resolved.providerType });
|
|
23931
|
+
const launchResult = await components.cliManager.handleCliCommand("launch_cli", {
|
|
23932
|
+
cliType: resolved.providerType,
|
|
23933
|
+
dir: node.workspace,
|
|
23934
|
+
settings: {
|
|
23935
|
+
meshNodeFor: meshId,
|
|
23936
|
+
meshNodeId: nodeId,
|
|
23937
|
+
spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || "hidden",
|
|
23938
|
+
launchedByCoordinator: true,
|
|
23939
|
+
autoLaunchedForQueueTaskId: task.id
|
|
23940
|
+
}
|
|
23941
|
+
});
|
|
23942
|
+
if (!launchResult?.success) {
|
|
23943
|
+
const reason = launchResult?.error || "launch_cli_failed";
|
|
23944
|
+
markAutoLaunch(meshId, task.id, { status: "failed", reason, nodeId, providerType: resolved.providerType });
|
|
23945
|
+
autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
|
|
23946
|
+
return false;
|
|
23947
|
+
}
|
|
23948
|
+
const sessionId = readNonEmptyString(launchResult.sessionId) || readNonEmptyString(launchResult.id) || readNonEmptyString(launchResult.runtimeSessionId);
|
|
23949
|
+
if (!sessionId) {
|
|
23950
|
+
markAutoLaunch(meshId, task.id, { status: "failed", reason: "launch_missing_session_id", nodeId, providerType: resolved.providerType });
|
|
23951
|
+
autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
|
|
23952
|
+
return false;
|
|
23953
|
+
}
|
|
23954
|
+
markAutoLaunch(meshId, task.id, { status: "completed", nodeId, providerType: resolved.providerType, sessionId });
|
|
23955
|
+
tryAssignQueueTask(components, meshId, nodeId, sessionId, resolved.providerType);
|
|
23956
|
+
return true;
|
|
23957
|
+
} catch (e) {
|
|
23958
|
+
markAutoLaunch(meshId, task.id, { status: "failed", error: e?.message || String(e), nodeId });
|
|
23959
|
+
autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
|
|
23960
|
+
return false;
|
|
23961
|
+
} finally {
|
|
23962
|
+
autoLaunchInProgress.delete(launchKey);
|
|
23963
|
+
}
|
|
23964
|
+
}
|
|
23965
|
+
}
|
|
23966
|
+
return false;
|
|
23967
|
+
}
|
|
23968
|
+
async function triggerMeshQueue(components, meshId) {
|
|
23563
23969
|
const mesh = getMeshWithCache(components, meshId);
|
|
23564
23970
|
if (!mesh) return;
|
|
23565
23971
|
const cliInstances = components.instanceManager.getByCategory("cli");
|
|
@@ -23570,9 +23976,7 @@ Follow these recovery rules:
|
|
|
23570
23976
|
if (instMeshId !== meshId) continue;
|
|
23571
23977
|
const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
23572
23978
|
if (!nodeId) continue;
|
|
23573
|
-
|
|
23574
|
-
if (["stopped", "failed", "terminated", "exited", "closed"].includes(status)) continue;
|
|
23575
|
-
if (status !== "idle" && state.activeChat?.status !== "waiting_input") continue;
|
|
23979
|
+
if (!isIdleSessionState(state)) continue;
|
|
23576
23980
|
const sessionId = state.instanceId;
|
|
23577
23981
|
const providerType = state.type || readNonEmptyString(settings.providerType);
|
|
23578
23982
|
if (providerType) {
|
|
@@ -23588,6 +23992,7 @@ Follow these recovery rules:
|
|
|
23588
23992
|
}
|
|
23589
23993
|
}
|
|
23590
23994
|
}
|
|
23995
|
+
await maybeAutoLaunchOneQueueSession(components, meshId, mesh);
|
|
23591
23996
|
}
|
|
23592
23997
|
function buildMeshSystemMessage(args) {
|
|
23593
23998
|
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
@@ -23869,10 +24274,15 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
23869
24274
|
var pendingMeshCoordinatorEvents;
|
|
23870
24275
|
var MESH_COORDINATOR_EVENTS;
|
|
23871
24276
|
var EVENT_TO_LEDGER_KIND;
|
|
24277
|
+
var autoLaunchInProgress;
|
|
24278
|
+
var autoLaunchCooldownUntil;
|
|
24279
|
+
var AUTO_LAUNCH_COOLDOWN_MS;
|
|
23872
24280
|
var init_mesh_events = __esm2({
|
|
23873
24281
|
"src/mesh/mesh-events.ts"() {
|
|
23874
24282
|
"use strict";
|
|
24283
|
+
init_config();
|
|
23875
24284
|
init_mesh_config();
|
|
24285
|
+
init_cli_detector();
|
|
23876
24286
|
init_logger();
|
|
23877
24287
|
init_mesh_ledger();
|
|
23878
24288
|
init_mesh_work_queue();
|
|
@@ -23893,6 +24303,9 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
23893
24303
|
"agent:stopped": "task_failed",
|
|
23894
24304
|
"monitor:long_generating": "task_stalled"
|
|
23895
24305
|
};
|
|
24306
|
+
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
24307
|
+
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
24308
|
+
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
23896
24309
|
}
|
|
23897
24310
|
});
|
|
23898
24311
|
function normalizeCategories(categories) {
|
|
@@ -27011,6 +27424,7 @@ ${lastSnapshot}`;
|
|
|
27011
27424
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS2,
|
|
27012
27425
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS2,
|
|
27013
27426
|
NodePtyTransportFactory: () => NodePtyTransportFactory,
|
|
27427
|
+
P2pRelayFailureError: () => P2pRelayFailureError,
|
|
27014
27428
|
ProviderCliAdapter: () => ProviderCliAdapter,
|
|
27015
27429
|
ProviderInstanceManager: () => ProviderInstanceManager,
|
|
27016
27430
|
ProviderLoader: () => ProviderLoader,
|
|
@@ -27027,6 +27441,7 @@ ${lastSnapshot}`;
|
|
|
27027
27441
|
buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
|
|
27028
27442
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
|
|
27029
27443
|
buildMachineInfo: () => buildMachineInfo2,
|
|
27444
|
+
buildP2pRelayFailurePayload: () => buildP2pRelayFailurePayload,
|
|
27030
27445
|
buildPinnedGlobalInstallCommand: () => buildPinnedGlobalInstallCommand,
|
|
27031
27446
|
buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
|
|
27032
27447
|
buildSessionEntries: () => buildSessionEntries,
|
|
@@ -27041,6 +27456,7 @@ ${lastSnapshot}`;
|
|
|
27041
27456
|
claimNextTask: () => claimNextTask,
|
|
27042
27457
|
classifyChatMessageVisibility: () => classifyChatMessageVisibility,
|
|
27043
27458
|
classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush2,
|
|
27459
|
+
classifyP2pRelayFailure: () => classifyP2pRelayFailure,
|
|
27044
27460
|
clearDebugTrace: () => clearDebugTrace,
|
|
27045
27461
|
compareGitSnapshots: () => compareGitSnapshots,
|
|
27046
27462
|
configureDebugTraceStore: () => configureDebugTraceStore,
|
|
@@ -27108,6 +27524,7 @@ ${lastSnapshot}`;
|
|
|
27108
27524
|
isInternalChatMessage: () => isInternalChatMessage,
|
|
27109
27525
|
isManagedStatusWaiting: () => isManagedStatusWaiting,
|
|
27110
27526
|
isManagedStatusWorking: () => isManagedStatusWorking,
|
|
27527
|
+
isP2pRelayTransportFailure: () => isP2pRelayTransportFailure,
|
|
27111
27528
|
isPathInside: () => isPathInside,
|
|
27112
27529
|
isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
|
|
27113
27530
|
isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
|
|
@@ -29036,7 +29453,115 @@ ${lastSnapshot}`;
|
|
|
29036
29453
|
init_mesh_ledger();
|
|
29037
29454
|
init_mesh_work_queue();
|
|
29038
29455
|
init_mesh_events();
|
|
29039
|
-
var
|
|
29456
|
+
var NO_FALLBACK_REASON = "Repo Mesh command/data-plane is P2P-only; WS/REST command fallback is intentionally disabled to preserve the transport boundary.";
|
|
29457
|
+
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.";
|
|
29458
|
+
var NON_P2P_NEXT_ACTION = "Inspect the provider/command error and fix the underlying logic or configuration before retrying.";
|
|
29459
|
+
function messageFromError(error48) {
|
|
29460
|
+
if (error48 instanceof Error) return error48.message;
|
|
29461
|
+
if (typeof error48 === "string") return error48;
|
|
29462
|
+
if (error48 && typeof error48 === "object") {
|
|
29463
|
+
const candidate = error48.error ?? error48.message ?? error48.reason;
|
|
29464
|
+
if (typeof candidate === "string") return candidate;
|
|
29465
|
+
}
|
|
29466
|
+
return String(error48 || "mesh relay command failed");
|
|
29467
|
+
}
|
|
29468
|
+
function classifyP2pRelayFailure(error48, _context = {}) {
|
|
29469
|
+
const message = messageFromError(error48);
|
|
29470
|
+
const lower = message.toLowerCase();
|
|
29471
|
+
const hasP2pSignal = /p2p|datachannel|node-datachannel|webrtc|ice|mesh_relay_command|daemon_mesh_p2p_transport/i.test(message);
|
|
29472
|
+
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);
|
|
29473
|
+
if (/requires targetdaemonid and command|providerpriority|no inference provider|permission denied|read-only|not a member/i.test(message)) {
|
|
29474
|
+
return {
|
|
29475
|
+
code: "mesh_logic_or_provider_failure",
|
|
29476
|
+
reason: "mesh_logic_or_provider_failure",
|
|
29477
|
+
transport: "unknown",
|
|
29478
|
+
recoverable: false,
|
|
29479
|
+
retryRecommended: false,
|
|
29480
|
+
nextAction: NON_P2P_NEXT_ACTION,
|
|
29481
|
+
noFallbackReason: NO_FALLBACK_REASON
|
|
29482
|
+
};
|
|
29483
|
+
}
|
|
29484
|
+
let code = null;
|
|
29485
|
+
let reason = "";
|
|
29486
|
+
if (/timeout|timed out/i.test(message) && (hasP2pSignal || /mesh transport/i.test(message))) {
|
|
29487
|
+
code = "p2p_timeout";
|
|
29488
|
+
reason = "daemon_mesh_p2p_timeout";
|
|
29489
|
+
} else if (/no route|route unavailable/i.test(message)) {
|
|
29490
|
+
code = "p2p_no_route";
|
|
29491
|
+
reason = "daemon_mesh_p2p_no_route";
|
|
29492
|
+
} else if (/offline|not owned|not found|not connected to server/i.test(message) && /daemon|peer|target/i.test(message)) {
|
|
29493
|
+
code = "p2p_daemon_offline";
|
|
29494
|
+
reason = "daemon_mesh_target_offline";
|
|
29495
|
+
} else if (/closed|disconnected/i.test(message) && (hasP2pSignal || /state changed/i.test(message))) {
|
|
29496
|
+
code = "p2p_datachannel_closed";
|
|
29497
|
+
reason = "daemon_mesh_p2p_datachannel_closed";
|
|
29498
|
+
} else if (/not connected|cannot send|cannot establish/i.test(message) && hasP2pSignal) {
|
|
29499
|
+
code = "p2p_not_connected";
|
|
29500
|
+
reason = "daemon_mesh_p2p_not_connected";
|
|
29501
|
+
} else if (hasP2pSignal && hasFailureSignal) {
|
|
29502
|
+
code = "p2p_unavailable";
|
|
29503
|
+
reason = "daemon_mesh_p2p_transport_unavailable";
|
|
29504
|
+
}
|
|
29505
|
+
if (!code) {
|
|
29506
|
+
return {
|
|
29507
|
+
code: "mesh_logic_or_provider_failure",
|
|
29508
|
+
reason: "mesh_logic_or_provider_failure",
|
|
29509
|
+
transport: "unknown",
|
|
29510
|
+
recoverable: false,
|
|
29511
|
+
retryRecommended: false,
|
|
29512
|
+
nextAction: NON_P2P_NEXT_ACTION,
|
|
29513
|
+
noFallbackReason: NO_FALLBACK_REASON
|
|
29514
|
+
};
|
|
29515
|
+
}
|
|
29516
|
+
return {
|
|
29517
|
+
code,
|
|
29518
|
+
reason,
|
|
29519
|
+
transport: "p2p",
|
|
29520
|
+
recoverable: true,
|
|
29521
|
+
retryRecommended: true,
|
|
29522
|
+
nextAction: P2P_NEXT_ACTION,
|
|
29523
|
+
noFallbackReason: NO_FALLBACK_REASON
|
|
29524
|
+
};
|
|
29525
|
+
}
|
|
29526
|
+
function isP2pRelayTransportFailure(error48) {
|
|
29527
|
+
return classifyP2pRelayFailure(error48).recoverable === true;
|
|
29528
|
+
}
|
|
29529
|
+
function buildP2pRelayFailurePayload(error48, context = {}) {
|
|
29530
|
+
const classification = classifyP2pRelayFailure(error48, context);
|
|
29531
|
+
return {
|
|
29532
|
+
success: false,
|
|
29533
|
+
...classification,
|
|
29534
|
+
error: messageFromError(error48),
|
|
29535
|
+
...context.command ? { command: context.command } : {},
|
|
29536
|
+
...context.targetDaemonId ? { targetDaemonId: context.targetDaemonId } : {}
|
|
29537
|
+
};
|
|
29538
|
+
}
|
|
29539
|
+
var P2pRelayFailureError = class extends Error {
|
|
29540
|
+
code;
|
|
29541
|
+
reason;
|
|
29542
|
+
transport;
|
|
29543
|
+
recoverable;
|
|
29544
|
+
retryRecommended;
|
|
29545
|
+
nextAction;
|
|
29546
|
+
noFallbackReason;
|
|
29547
|
+
command;
|
|
29548
|
+
targetDaemonId;
|
|
29549
|
+
constructor(message, context = {}) {
|
|
29550
|
+
super(message);
|
|
29551
|
+
this.name = "P2pRelayFailureError";
|
|
29552
|
+
const payload = buildP2pRelayFailurePayload(message, context);
|
|
29553
|
+
this.code = payload.code;
|
|
29554
|
+
this.reason = payload.reason;
|
|
29555
|
+
this.transport = payload.transport;
|
|
29556
|
+
this.recoverable = payload.recoverable;
|
|
29557
|
+
this.retryRecommended = payload.retryRecommended;
|
|
29558
|
+
this.nextAction = payload.nextAction;
|
|
29559
|
+
this.noFallbackReason = payload.noFallbackReason;
|
|
29560
|
+
this.command = context.command;
|
|
29561
|
+
this.targetDaemonId = context.targetDaemonId;
|
|
29562
|
+
}
|
|
29563
|
+
};
|
|
29564
|
+
var import_fs6 = require("fs");
|
|
29040
29565
|
var import_path5 = require("path");
|
|
29041
29566
|
init_config();
|
|
29042
29567
|
var DEFAULT_STATE = {
|
|
@@ -29087,11 +29612,11 @@ ${lastSnapshot}`;
|
|
|
29087
29612
|
}
|
|
29088
29613
|
function loadState() {
|
|
29089
29614
|
const statePath = getStatePath();
|
|
29090
|
-
if (!(0,
|
|
29615
|
+
if (!(0, import_fs6.existsSync)(statePath)) {
|
|
29091
29616
|
return { ...DEFAULT_STATE };
|
|
29092
29617
|
}
|
|
29093
29618
|
try {
|
|
29094
|
-
const raw = (0,
|
|
29619
|
+
const raw = (0, import_fs6.readFileSync)(statePath, "utf-8");
|
|
29095
29620
|
return normalizeState(JSON.parse(raw));
|
|
29096
29621
|
} catch {
|
|
29097
29622
|
return { ...DEFAULT_STATE };
|
|
@@ -29100,15 +29625,15 @@ ${lastSnapshot}`;
|
|
|
29100
29625
|
function saveState(state) {
|
|
29101
29626
|
const statePath = getStatePath();
|
|
29102
29627
|
const normalized = normalizeState(state);
|
|
29103
|
-
(0,
|
|
29628
|
+
(0, import_fs6.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
29104
29629
|
}
|
|
29105
29630
|
function resetState() {
|
|
29106
29631
|
saveState({ ...DEFAULT_STATE });
|
|
29107
29632
|
}
|
|
29108
|
-
var
|
|
29109
|
-
var
|
|
29633
|
+
var import_child_process2 = require("child_process");
|
|
29634
|
+
var import_fs7 = require("fs");
|
|
29110
29635
|
var import_os22 = require("os");
|
|
29111
|
-
var
|
|
29636
|
+
var path10 = __toESM2(require("path"));
|
|
29112
29637
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
29113
29638
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
29114
29639
|
function registerIDEDefinition(def) {
|
|
@@ -29127,13 +29652,13 @@ ${lastSnapshot}`;
|
|
|
29127
29652
|
function findCliCommand(command) {
|
|
29128
29653
|
const trimmed = String(command || "").trim();
|
|
29129
29654
|
if (!trimmed) return null;
|
|
29130
|
-
if (
|
|
29131
|
-
const candidate = trimmed.startsWith("~") ?
|
|
29132
|
-
const resolved =
|
|
29133
|
-
return (0,
|
|
29655
|
+
if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
29656
|
+
const candidate = trimmed.startsWith("~") ? path10.join((0, import_os22.homedir)(), trimmed.slice(1)) : trimmed;
|
|
29657
|
+
const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
|
|
29658
|
+
return (0, import_fs7.existsSync)(resolved) ? resolved : null;
|
|
29134
29659
|
}
|
|
29135
29660
|
try {
|
|
29136
|
-
const result = (0,
|
|
29661
|
+
const result = (0, import_child_process2.execSync)(
|
|
29137
29662
|
(0, import_os22.platform)() === "win32" ? `where ${trimmed}` : `which ${trimmed}`,
|
|
29138
29663
|
{ encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }
|
|
29139
29664
|
).trim();
|
|
@@ -29144,7 +29669,7 @@ ${lastSnapshot}`;
|
|
|
29144
29669
|
}
|
|
29145
29670
|
function getIdeVersion(cliCommand) {
|
|
29146
29671
|
try {
|
|
29147
|
-
const result = (0,
|
|
29672
|
+
const result = (0, import_child_process2.execSync)(`"${cliCommand}" --version`, {
|
|
29148
29673
|
encoding: "utf-8",
|
|
29149
29674
|
timeout: 1e4,
|
|
29150
29675
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -29157,13 +29682,13 @@ ${lastSnapshot}`;
|
|
|
29157
29682
|
function checkPathExists(paths) {
|
|
29158
29683
|
const home = (0, import_os22.homedir)();
|
|
29159
29684
|
for (const p of paths) {
|
|
29160
|
-
const normalized = p.startsWith("~") ?
|
|
29685
|
+
const normalized = p.startsWith("~") ? path10.join(home, p.slice(1)) : p;
|
|
29161
29686
|
if (normalized.includes("*")) {
|
|
29162
29687
|
const username = home.split(/[\\/]/).pop() || "";
|
|
29163
29688
|
const resolved = normalized.replace("*", username);
|
|
29164
|
-
if ((0,
|
|
29689
|
+
if ((0, import_fs7.existsSync)(resolved)) return resolved;
|
|
29165
29690
|
} else {
|
|
29166
|
-
if ((0,
|
|
29691
|
+
if ((0, import_fs7.existsSync)(normalized)) return normalized;
|
|
29167
29692
|
}
|
|
29168
29693
|
}
|
|
29169
29694
|
return null;
|
|
@@ -29177,7 +29702,7 @@ ${lastSnapshot}`;
|
|
|
29177
29702
|
let resolvedCli = cliPath;
|
|
29178
29703
|
if (!resolvedCli && appPath && os222 === "darwin") {
|
|
29179
29704
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
29180
|
-
if ((0,
|
|
29705
|
+
if ((0, import_fs7.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
29181
29706
|
}
|
|
29182
29707
|
if (!resolvedCli && appPath && os222 === "win32") {
|
|
29183
29708
|
const { dirname: dirname9 } = await import("path");
|
|
@@ -29190,7 +29715,7 @@ ${lastSnapshot}`;
|
|
|
29190
29715
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
29191
29716
|
];
|
|
29192
29717
|
for (const c of candidates) {
|
|
29193
|
-
if ((0,
|
|
29718
|
+
if ((0, import_fs7.existsSync)(c)) {
|
|
29194
29719
|
resolvedCli = c;
|
|
29195
29720
|
break;
|
|
29196
29721
|
}
|
|
@@ -29211,133 +29736,7 @@ ${lastSnapshot}`;
|
|
|
29211
29736
|
}
|
|
29212
29737
|
return results;
|
|
29213
29738
|
}
|
|
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
|
-
}
|
|
29739
|
+
init_cli_detector();
|
|
29341
29740
|
var os42 = __toESM2(require("os"));
|
|
29342
29741
|
var import_child_process3 = require("child_process");
|
|
29343
29742
|
function parseDarwinAvailableBytes(totalMem) {
|
|
@@ -38361,6 +38760,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
38361
38760
|
var import_child_process6 = require("child_process");
|
|
38362
38761
|
var import_chalk = __toESM2((init_source(), __toCommonJS(source_exports)));
|
|
38363
38762
|
init_provider_cli_adapter();
|
|
38763
|
+
init_cli_detector();
|
|
38364
38764
|
init_config();
|
|
38365
38765
|
var os12 = __toESM2(require("os"));
|
|
38366
38766
|
var path16 = __toESM2(require("path"));
|
|
@@ -43914,6 +44314,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
43914
44314
|
return getProviderLoader().getAvailableIdeTypes();
|
|
43915
44315
|
}
|
|
43916
44316
|
init_config();
|
|
44317
|
+
init_cli_detector();
|
|
43917
44318
|
init_logger();
|
|
43918
44319
|
var fs8 = __toESM2(require("fs"));
|
|
43919
44320
|
var path21 = __toESM2(require("path"));
|
|
@@ -45046,6 +45447,209 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
45046
45447
|
}
|
|
45047
45448
|
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
45048
45449
|
}
|
|
45450
|
+
var REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
|
|
45451
|
+
var REFINE_VALIDATION_TIMEOUT_MS = 12e4;
|
|
45452
|
+
var REFINE_VALIDATION_OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
45453
|
+
var REFINE_VALIDATION_SUMMARY_CHARS = 2e3;
|
|
45454
|
+
var REFINE_VALIDATION_MAX_COMMANDS = 4;
|
|
45455
|
+
function truncateValidationOutput(value) {
|
|
45456
|
+
const text = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
45457
|
+
if (text.length <= REFINE_VALIDATION_SUMMARY_CHARS) return text;
|
|
45458
|
+
return `${text.slice(0, REFINE_VALIDATION_SUMMARY_CHARS)}
|
|
45459
|
+
[truncated ${text.length - REFINE_VALIDATION_SUMMARY_CHARS} chars]`;
|
|
45460
|
+
}
|
|
45461
|
+
function readPackageScripts(workspace) {
|
|
45462
|
+
try {
|
|
45463
|
+
const packageJsonPath = (0, import_path6.join)(workspace, "package.json");
|
|
45464
|
+
const parsed = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
|
|
45465
|
+
return parsed?.scripts && typeof parsed.scripts === "object" && !Array.isArray(parsed.scripts) ? parsed.scripts : {};
|
|
45466
|
+
} catch {
|
|
45467
|
+
return {};
|
|
45468
|
+
}
|
|
45469
|
+
}
|
|
45470
|
+
function tokenizeValidationCommand(command) {
|
|
45471
|
+
const trimmed = command.trim();
|
|
45472
|
+
if (!trimmed) return null;
|
|
45473
|
+
if (/[;&|<>`$\\\n\r'\"]/.test(trimmed)) return null;
|
|
45474
|
+
const tokens = trimmed.split(/\s+/).filter(Boolean);
|
|
45475
|
+
if (!tokens.length) return null;
|
|
45476
|
+
if (tokens.some((token) => !/^[A-Za-z0-9_@./:=+-]+$/.test(token))) return null;
|
|
45477
|
+
return tokens;
|
|
45478
|
+
}
|
|
45479
|
+
function scriptMatchesValidationCategory(scriptName, category) {
|
|
45480
|
+
return scriptName === category || scriptName.startsWith(`${category}:`);
|
|
45481
|
+
}
|
|
45482
|
+
function parsePackageManagerValidationCommand(rawCommand, category, scripts, source) {
|
|
45483
|
+
const tokens = tokenizeValidationCommand(rawCommand);
|
|
45484
|
+
if (!tokens) {
|
|
45485
|
+
return { rejected: { command: rawCommand, category, source, reason: "unsafe command string is not allowlisted" } };
|
|
45486
|
+
}
|
|
45487
|
+
const [binary, second, third, ...rest] = tokens;
|
|
45488
|
+
let scriptName = "";
|
|
45489
|
+
let command = binary;
|
|
45490
|
+
let args = [];
|
|
45491
|
+
if ((binary === "npm" || binary === "pnpm" || binary === "bun") && second === "run" && third) {
|
|
45492
|
+
scriptName = third;
|
|
45493
|
+
args = ["run", scriptName, ...rest];
|
|
45494
|
+
} else if (binary === "npm" && second === "test" && !third) {
|
|
45495
|
+
scriptName = "test";
|
|
45496
|
+
args = ["test"];
|
|
45497
|
+
} else if (binary === "yarn" && second === "run" && third) {
|
|
45498
|
+
scriptName = third;
|
|
45499
|
+
args = ["run", scriptName, ...rest];
|
|
45500
|
+
} else if (binary === "yarn" && second && !third) {
|
|
45501
|
+
scriptName = second;
|
|
45502
|
+
args = [scriptName];
|
|
45503
|
+
} else {
|
|
45504
|
+
return { rejected: { command: rawCommand, category, source, reason: "command is not a supported package-manager script invocation" } };
|
|
45505
|
+
}
|
|
45506
|
+
if (!scriptName || !Object.prototype.hasOwnProperty.call(scripts, scriptName)) {
|
|
45507
|
+
return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script is not declared in package.json" } };
|
|
45508
|
+
}
|
|
45509
|
+
if (!scriptMatchesValidationCategory(scriptName, category)) {
|
|
45510
|
+
return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script name is outside the validation category allowlist" } };
|
|
45511
|
+
}
|
|
45512
|
+
return {
|
|
45513
|
+
command: {
|
|
45514
|
+
command,
|
|
45515
|
+
args,
|
|
45516
|
+
displayCommand: [command, ...args].join(" "),
|
|
45517
|
+
category,
|
|
45518
|
+
source
|
|
45519
|
+
}
|
|
45520
|
+
};
|
|
45521
|
+
}
|
|
45522
|
+
function collectProjectContextValidationCandidates(mesh) {
|
|
45523
|
+
const commands = mesh?.projectContext?.commands;
|
|
45524
|
+
if (!commands || typeof commands !== "object" || Array.isArray(commands)) return [];
|
|
45525
|
+
const candidates = [];
|
|
45526
|
+
for (const category of REFINE_VALIDATION_CATEGORIES) {
|
|
45527
|
+
const entries = Array.isArray(commands[category]) ? commands[category] : [];
|
|
45528
|
+
for (const entry of entries) {
|
|
45529
|
+
if (typeof entry?.command !== "string") continue;
|
|
45530
|
+
candidates.push({
|
|
45531
|
+
command: entry.command,
|
|
45532
|
+
category,
|
|
45533
|
+
source: typeof entry.sourcePath === "string" ? entry.sourcePath : "projectContext.commands",
|
|
45534
|
+
confidence: typeof entry.confidence === "string" ? entry.confidence : void 0
|
|
45535
|
+
});
|
|
45536
|
+
}
|
|
45537
|
+
}
|
|
45538
|
+
return candidates.sort((a, b) => {
|
|
45539
|
+
const rank = (value) => value === "high" ? 0 : value === "medium" ? 1 : 2;
|
|
45540
|
+
return rank(a.confidence) - rank(b.confidence);
|
|
45541
|
+
});
|
|
45542
|
+
}
|
|
45543
|
+
function collectPolicyValidationCandidates(mesh) {
|
|
45544
|
+
const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
|
|
45545
|
+
const configured = Array.isArray(policy.validationCommands) ? policy.validationCommands : Array.isArray(policy.validationGate?.commands) ? policy.validationGate.commands : [];
|
|
45546
|
+
return configured.map((entry) => typeof entry === "string" ? { command: entry, category: "", source: "mesh.policy.validationCommands" } : entry).filter((entry) => entry && typeof entry.command === "string").map((entry) => {
|
|
45547
|
+
const commandText = entry.command.trim();
|
|
45548
|
+
const category = REFINE_VALIDATION_CATEGORIES.find((cat) => commandText.includes(` ${cat}`)) ?? "";
|
|
45549
|
+
return { command: commandText, category, source: "mesh.policy.validationCommands" };
|
|
45550
|
+
}).filter((entry) => !!entry.category);
|
|
45551
|
+
}
|
|
45552
|
+
function selectMeshRefineValidationCommands(mesh, workspace) {
|
|
45553
|
+
const scripts = readPackageScripts(workspace);
|
|
45554
|
+
const rejectedCommands = [];
|
|
45555
|
+
const selected = [];
|
|
45556
|
+
const seen = /* @__PURE__ */ new Set();
|
|
45557
|
+
const candidates = [
|
|
45558
|
+
...collectPolicyValidationCandidates(mesh),
|
|
45559
|
+
...collectProjectContextValidationCandidates(mesh)
|
|
45560
|
+
];
|
|
45561
|
+
for (const candidate of candidates) {
|
|
45562
|
+
const parsed = parsePackageManagerValidationCommand(candidate.command, candidate.category, scripts, candidate.source);
|
|
45563
|
+
if (parsed.rejected) {
|
|
45564
|
+
rejectedCommands.push(parsed.rejected);
|
|
45565
|
+
continue;
|
|
45566
|
+
}
|
|
45567
|
+
if (!parsed.command || seen.has(parsed.command.displayCommand)) continue;
|
|
45568
|
+
selected.push(parsed.command);
|
|
45569
|
+
seen.add(parsed.command.displayCommand);
|
|
45570
|
+
if (selected.length >= REFINE_VALIDATION_MAX_COMMANDS) break;
|
|
45571
|
+
}
|
|
45572
|
+
if (!selected.length && candidates.length === 0) {
|
|
45573
|
+
for (const category of REFINE_VALIDATION_CATEGORIES) {
|
|
45574
|
+
if (!Object.prototype.hasOwnProperty.call(scripts, category)) continue;
|
|
45575
|
+
const fallback = parsePackageManagerValidationCommand(`npm run ${category}`, category, scripts, "package.json:scripts");
|
|
45576
|
+
if (fallback.command && !seen.has(fallback.command.displayCommand)) {
|
|
45577
|
+
selected.push(fallback.command);
|
|
45578
|
+
seen.add(fallback.command.displayCommand);
|
|
45579
|
+
} else if (fallback.rejected) {
|
|
45580
|
+
rejectedCommands.push(fallback.rejected);
|
|
45581
|
+
}
|
|
45582
|
+
if (selected.length >= 2) break;
|
|
45583
|
+
}
|
|
45584
|
+
}
|
|
45585
|
+
return {
|
|
45586
|
+
commands: selected,
|
|
45587
|
+
rejectedCommands,
|
|
45588
|
+
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"
|
|
45589
|
+
};
|
|
45590
|
+
}
|
|
45591
|
+
async function runMeshRefineValidationGate(mesh, workspace) {
|
|
45592
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
45593
|
+
const { promisify: promisify3 } = await import("util");
|
|
45594
|
+
const execFileAsync3 = promisify3(execFile3);
|
|
45595
|
+
const selection = selectMeshRefineValidationCommands(mesh, workspace);
|
|
45596
|
+
const summary = {
|
|
45597
|
+
status: "skipped",
|
|
45598
|
+
required: true,
|
|
45599
|
+
commandsRun: [],
|
|
45600
|
+
rejectedCommands: selection.rejectedCommands,
|
|
45601
|
+
skippedReason: void 0,
|
|
45602
|
+
timeoutMs: REFINE_VALIDATION_TIMEOUT_MS,
|
|
45603
|
+
outputLimitBytes: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES
|
|
45604
|
+
};
|
|
45605
|
+
if (!selection.commands.length) {
|
|
45606
|
+
summary.skippedReason = "validation_unavailable: no allowlisted projectContext, mesh policy, or package.json build/test/typecheck/lint command was available";
|
|
45607
|
+
return summary;
|
|
45608
|
+
}
|
|
45609
|
+
for (const candidate of selection.commands) {
|
|
45610
|
+
const startedAt = Date.now();
|
|
45611
|
+
try {
|
|
45612
|
+
const result = await execFileAsync3(candidate.command, candidate.args, {
|
|
45613
|
+
cwd: workspace,
|
|
45614
|
+
encoding: "utf8",
|
|
45615
|
+
timeout: REFINE_VALIDATION_TIMEOUT_MS,
|
|
45616
|
+
maxBuffer: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES,
|
|
45617
|
+
env: { ...process.env, CI: process.env.CI || "1" }
|
|
45618
|
+
});
|
|
45619
|
+
summary.commandsRun.push({
|
|
45620
|
+
command: candidate.command,
|
|
45621
|
+
args: candidate.args,
|
|
45622
|
+
displayCommand: candidate.displayCommand,
|
|
45623
|
+
category: candidate.category,
|
|
45624
|
+
source: candidate.source,
|
|
45625
|
+
passed: true,
|
|
45626
|
+
exitCode: 0,
|
|
45627
|
+
durationMs: Date.now() - startedAt,
|
|
45628
|
+
stdout: truncateValidationOutput(result.stdout),
|
|
45629
|
+
stderr: truncateValidationOutput(result.stderr)
|
|
45630
|
+
});
|
|
45631
|
+
} catch (error48) {
|
|
45632
|
+
summary.commandsRun.push({
|
|
45633
|
+
command: candidate.command,
|
|
45634
|
+
args: candidate.args,
|
|
45635
|
+
displayCommand: candidate.displayCommand,
|
|
45636
|
+
category: candidate.category,
|
|
45637
|
+
source: candidate.source,
|
|
45638
|
+
passed: false,
|
|
45639
|
+
exitCode: typeof error48?.code === "number" ? error48.code : null,
|
|
45640
|
+
signal: typeof error48?.signal === "string" ? error48.signal : null,
|
|
45641
|
+
timedOut: error48?.killed === true || /timed out/i.test(String(error48?.message || "")),
|
|
45642
|
+
durationMs: Date.now() - startedAt,
|
|
45643
|
+
stdout: truncateValidationOutput(error48?.stdout),
|
|
45644
|
+
stderr: truncateValidationOutput(error48?.stderr || error48?.message)
|
|
45645
|
+
});
|
|
45646
|
+
summary.status = "failed";
|
|
45647
|
+
return summary;
|
|
45648
|
+
}
|
|
45649
|
+
}
|
|
45650
|
+
summary.status = "passed";
|
|
45651
|
+
return summary;
|
|
45652
|
+
}
|
|
45049
45653
|
function loadYamlModule() {
|
|
45050
45654
|
return yaml;
|
|
45051
45655
|
}
|
|
@@ -45329,20 +45933,98 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
45329
45933
|
recoveryHint: "Inspect the worktree branch and mesh metadata before retrying cleanup."
|
|
45330
45934
|
};
|
|
45331
45935
|
}
|
|
45936
|
+
const forceFallbackConvergence = await this.getWorktreeForceCleanupConvergence({
|
|
45937
|
+
repoRoot,
|
|
45938
|
+
workspace,
|
|
45939
|
+
node: args.node
|
|
45940
|
+
});
|
|
45332
45941
|
try {
|
|
45333
|
-
const result = await removeWorktree2(repoRoot, workspace, {
|
|
45334
|
-
|
|
45942
|
+
const result = await removeWorktree2(repoRoot, workspace, {
|
|
45943
|
+
requireClean: true,
|
|
45944
|
+
allowSubmoduleForceFallback: forceFallbackConvergence.allow
|
|
45945
|
+
});
|
|
45946
|
+
return {
|
|
45947
|
+
success: true,
|
|
45948
|
+
removedPath: result.removedPath,
|
|
45949
|
+
repoRoot,
|
|
45950
|
+
...result.fallback ? {
|
|
45951
|
+
fallback: result.fallback,
|
|
45952
|
+
forced: result.forced,
|
|
45953
|
+
reason: result.reason,
|
|
45954
|
+
convergence: forceFallbackConvergence
|
|
45955
|
+
} : {}
|
|
45956
|
+
};
|
|
45335
45957
|
} catch (e) {
|
|
45336
45958
|
const message = String(e?.message || e || "worktree cleanup failed");
|
|
45337
45959
|
const dirty = message.includes("dirty worktree") || message.includes("local changes");
|
|
45960
|
+
const submoduleForceBlocked = /working trees containing submodules cannot be moved or removed/i.test(message) && !forceFallbackConvergence.allow;
|
|
45338
45961
|
return {
|
|
45339
45962
|
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."
|
|
45963
|
+
code: dirty ? "mesh_worktree_cleanup_dirty" : submoduleForceBlocked ? "mesh_worktree_cleanup_force_fallback_blocked" : "mesh_worktree_cleanup_failed",
|
|
45964
|
+
error: submoduleForceBlocked ? `${message}; refusing --force fallback because convergence could not be verified: ${forceFallbackConvergence.error || "unknown convergence state"}` : message,
|
|
45965
|
+
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.",
|
|
45966
|
+
...submoduleForceBlocked ? { convergence: forceFallbackConvergence } : {}
|
|
45343
45967
|
};
|
|
45344
45968
|
}
|
|
45345
45969
|
}
|
|
45970
|
+
async getWorktreeForceCleanupConvergence(args) {
|
|
45971
|
+
const metadataStatus = typeof args.node?.branchConvergence?.status === "string" ? args.node.branchConvergence.status : "";
|
|
45972
|
+
if (metadataStatus === "merged_to_main" || metadataStatus === "cleanup_candidate") {
|
|
45973
|
+
return { allow: true, status: metadataStatus, source: "node_branch_convergence" };
|
|
45974
|
+
}
|
|
45975
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
45976
|
+
const { promisify: promisify3 } = await import("util");
|
|
45977
|
+
const execFileAsync3 = promisify3(execFile3);
|
|
45978
|
+
const runGit2 = async (gitArgs, cwd) => {
|
|
45979
|
+
const { stdout } = await execFileAsync3("git", gitArgs, {
|
|
45980
|
+
cwd,
|
|
45981
|
+
encoding: "utf8",
|
|
45982
|
+
timeout: 3e4,
|
|
45983
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
45984
|
+
windowsHide: true
|
|
45985
|
+
});
|
|
45986
|
+
return String(stdout || "").trim();
|
|
45987
|
+
};
|
|
45988
|
+
let head = "";
|
|
45989
|
+
try {
|
|
45990
|
+
head = await runGit2(["rev-parse", "HEAD"], args.workspace);
|
|
45991
|
+
} catch (e) {
|
|
45992
|
+
return { allow: false, error: `could not resolve worktree HEAD: ${e?.message || e}` };
|
|
45993
|
+
}
|
|
45994
|
+
if (!head) return { allow: false, error: "worktree HEAD is empty" };
|
|
45995
|
+
const candidateRefs = [];
|
|
45996
|
+
try {
|
|
45997
|
+
const defaultBranch = await runGit2(["branch", "--show-current"], args.repoRoot);
|
|
45998
|
+
if (defaultBranch) {
|
|
45999
|
+
candidateRefs.push(defaultBranch, `origin/${defaultBranch}`);
|
|
46000
|
+
}
|
|
46001
|
+
} catch {
|
|
46002
|
+
}
|
|
46003
|
+
candidateRefs.push("origin/main", "origin/master", "main", "master");
|
|
46004
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46005
|
+
const checkedRefs = [];
|
|
46006
|
+
for (const ref of candidateRefs) {
|
|
46007
|
+
if (!ref || seen.has(ref)) continue;
|
|
46008
|
+
seen.add(ref);
|
|
46009
|
+
let commit = "";
|
|
46010
|
+
try {
|
|
46011
|
+
commit = await runGit2(["rev-parse", "--verify", `${ref}^{commit}`], args.repoRoot);
|
|
46012
|
+
} catch {
|
|
46013
|
+
continue;
|
|
46014
|
+
}
|
|
46015
|
+
checkedRefs.push(ref);
|
|
46016
|
+
try {
|
|
46017
|
+
await runGit2(["merge-base", "--is-ancestor", head, commit], args.repoRoot);
|
|
46018
|
+
return { allow: true, status: "merged_to_default_ref", source: "git_merge_base", ref };
|
|
46019
|
+
} catch {
|
|
46020
|
+
}
|
|
46021
|
+
}
|
|
46022
|
+
return {
|
|
46023
|
+
allow: false,
|
|
46024
|
+
status: metadataStatus || void 0,
|
|
46025
|
+
error: checkedRefs.length ? `worktree HEAD is not contained in checked refs: ${checkedRefs.join(", ")}` : "no default/main refs were available for convergence verification"
|
|
46026
|
+
};
|
|
46027
|
+
}
|
|
45346
46028
|
isCompletedHostedSession(record2) {
|
|
45347
46029
|
return record2?.lifecycle === "stopped" || record2?.lifecycle === "failed" || record2?.lifecycle === "interrupted";
|
|
45348
46030
|
}
|
|
@@ -46302,10 +46984,61 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
46302
46984
|
if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
|
|
46303
46985
|
const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
|
|
46304
46986
|
const baseBranch = baseBranchStdout.trim();
|
|
46987
|
+
const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace);
|
|
46988
|
+
if (validationSummary.status === "failed") {
|
|
46989
|
+
return {
|
|
46990
|
+
success: false,
|
|
46991
|
+
code: "validation_failed",
|
|
46992
|
+
convergenceStatus: "blocked_review",
|
|
46993
|
+
error: "Refinery validation gate failed; merge/refine was not attempted.",
|
|
46994
|
+
branch,
|
|
46995
|
+
into: baseBranch,
|
|
46996
|
+
validationSummary,
|
|
46997
|
+
finalBranchConvergenceState: {
|
|
46998
|
+
branch,
|
|
46999
|
+
baseBranch,
|
|
47000
|
+
merged: false,
|
|
47001
|
+
removed: false,
|
|
47002
|
+
validation: "failed",
|
|
47003
|
+
status: "blocked_review"
|
|
47004
|
+
}
|
|
47005
|
+
};
|
|
47006
|
+
}
|
|
47007
|
+
if (validationSummary.status === "skipped") {
|
|
47008
|
+
return {
|
|
47009
|
+
success: false,
|
|
47010
|
+
code: "validation_unavailable",
|
|
47011
|
+
convergenceStatus: "blocked_review",
|
|
47012
|
+
error: "Refinery validation gate is required but no allowlisted validation command was available; merge/refine was not attempted.",
|
|
47013
|
+
branch,
|
|
47014
|
+
into: baseBranch,
|
|
47015
|
+
validationSummary,
|
|
47016
|
+
finalBranchConvergenceState: {
|
|
47017
|
+
branch,
|
|
47018
|
+
baseBranch,
|
|
47019
|
+
merged: false,
|
|
47020
|
+
removed: false,
|
|
47021
|
+
validation: "unavailable",
|
|
47022
|
+
status: "blocked_review"
|
|
47023
|
+
}
|
|
47024
|
+
};
|
|
47025
|
+
}
|
|
46305
47026
|
try {
|
|
46306
47027
|
await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
|
|
46307
47028
|
} catch (e) {
|
|
46308
|
-
return {
|
|
47029
|
+
return {
|
|
47030
|
+
success: false,
|
|
47031
|
+
error: `Merge failed (conflicts?): ${e.message}`,
|
|
47032
|
+
validationSummary,
|
|
47033
|
+
finalBranchConvergenceState: {
|
|
47034
|
+
branch,
|
|
47035
|
+
baseBranch,
|
|
47036
|
+
merged: false,
|
|
47037
|
+
removed: false,
|
|
47038
|
+
validation: "passed",
|
|
47039
|
+
status: "not_mergeable"
|
|
47040
|
+
}
|
|
47041
|
+
};
|
|
46309
47042
|
}
|
|
46310
47043
|
const removeResult = await this.execute("remove_mesh_node", {
|
|
46311
47044
|
meshId,
|
|
@@ -46318,11 +47051,27 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
46318
47051
|
appendLedgerEntry2(meshId, {
|
|
46319
47052
|
kind: "node_removed",
|
|
46320
47053
|
nodeId,
|
|
46321
|
-
payload: { refined: true, mergedBranch: branch, into: baseBranch }
|
|
47054
|
+
payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary }
|
|
46322
47055
|
});
|
|
46323
47056
|
} catch {
|
|
46324
47057
|
}
|
|
46325
|
-
return {
|
|
47058
|
+
return {
|
|
47059
|
+
success: true,
|
|
47060
|
+
merged: true,
|
|
47061
|
+
branch,
|
|
47062
|
+
into: baseBranch,
|
|
47063
|
+
removeResult,
|
|
47064
|
+
validationSummary,
|
|
47065
|
+
finalBranchConvergenceState: {
|
|
47066
|
+
branch: baseBranch,
|
|
47067
|
+
mergedBranch: branch,
|
|
47068
|
+
baseBranch,
|
|
47069
|
+
merged: true,
|
|
47070
|
+
removed: removeResult?.success !== false,
|
|
47071
|
+
validation: "passed",
|
|
47072
|
+
status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
|
|
47073
|
+
}
|
|
47074
|
+
};
|
|
46326
47075
|
} catch (e) {
|
|
46327
47076
|
return { success: false, error: e.message };
|
|
46328
47077
|
}
|
|
@@ -46377,7 +47126,10 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
|
|
|
46377
47126
|
sessionCleanupMode,
|
|
46378
47127
|
workspace: typeof node?.workspace === "string" ? node.workspace : void 0,
|
|
46379
47128
|
daemonId: typeof node?.daemonId === "string" ? node.daemonId : void 0,
|
|
46380
|
-
worktreeBranch: typeof node?.worktreeBranch === "string" ? node.worktreeBranch : void 0
|
|
47129
|
+
worktreeBranch: typeof node?.worktreeBranch === "string" ? node.worktreeBranch : void 0,
|
|
47130
|
+
worktreeCleanupFallback: typeof worktreeCleanup?.fallback === "string" ? worktreeCleanup.fallback : void 0,
|
|
47131
|
+
forced: worktreeCleanup?.forced === true ? true : void 0,
|
|
47132
|
+
forceFallbackReason: typeof worktreeCleanup?.reason === "string" ? worktreeCleanup.reason : void 0
|
|
46381
47133
|
}
|
|
46382
47134
|
});
|
|
46383
47135
|
} catch {
|
|
@@ -54460,6 +55212,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
54460
55212
|
return false;
|
|
54461
55213
|
}
|
|
54462
55214
|
}
|
|
55215
|
+
init_cli_detector();
|
|
54463
55216
|
var SessionRegistry = class {
|
|
54464
55217
|
bySessionId = /* @__PURE__ */ new Map();
|
|
54465
55218
|
byManagerKey = /* @__PURE__ */ new Map();
|