@adhdev/daemon-standalone 1.0.43 → 1.0.44-rc.1
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 +1365 -1157
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/public/assets/index-ExETXxNL.js +121 -0
- package/public/assets/index-zRNkTYHz.css +1 -0
- package/public/index.html +2 -2
- package/vendor/mcp-server/index.js +0 -0
- package/vendor/mcp-server/index.js.map +1 -1
- package/vendor/session-host-daemon/index.js +0 -0
- package/vendor/session-host-daemon/index.mjs +0 -0
- package/public/assets/index-CM5X3KcB.js +0 -121
- package/public/assets/index-DcvJsnpp.css +0 -1
package/dist/index.js
CHANGED
|
@@ -31423,9 +31423,9 @@ var require_streamx = __commonJS({
|
|
|
31423
31423
|
}
|
|
31424
31424
|
});
|
|
31425
31425
|
|
|
31426
|
-
//
|
|
31426
|
+
// ../../node_modules/tar-stream/node_modules/b4a/index.js
|
|
31427
31427
|
var require_b4a2 = __commonJS({
|
|
31428
|
-
"
|
|
31428
|
+
"../../node_modules/tar-stream/node_modules/b4a/index.js"(exports2, module2) {
|
|
31429
31429
|
"use strict";
|
|
31430
31430
|
function isBuffer(value) {
|
|
31431
31431
|
return Buffer.isBuffer(value) || value instanceof Uint8Array;
|
|
@@ -31581,9 +31581,9 @@ var require_b4a2 = __commonJS({
|
|
|
31581
31581
|
}
|
|
31582
31582
|
});
|
|
31583
31583
|
|
|
31584
|
-
//
|
|
31584
|
+
// ../../node_modules/tar-stream/headers.js
|
|
31585
31585
|
var require_headers = __commonJS({
|
|
31586
|
-
"
|
|
31586
|
+
"../../node_modules/tar-stream/headers.js"(exports2) {
|
|
31587
31587
|
"use strict";
|
|
31588
31588
|
var b4a = require_b4a2();
|
|
31589
31589
|
var ZEROS = "0000000000000000000";
|
|
@@ -31844,9 +31844,9 @@ var require_headers = __commonJS({
|
|
|
31844
31844
|
}
|
|
31845
31845
|
});
|
|
31846
31846
|
|
|
31847
|
-
//
|
|
31847
|
+
// ../../node_modules/tar-stream/extract.js
|
|
31848
31848
|
var require_extract = __commonJS({
|
|
31849
|
-
"
|
|
31849
|
+
"../../node_modules/tar-stream/extract.js"(exports2, module2) {
|
|
31850
31850
|
"use strict";
|
|
31851
31851
|
var { Writable, Readable, getStreamError } = require_streamx();
|
|
31852
31852
|
var FIFO = require_fast_fifo();
|
|
@@ -32189,9 +32189,9 @@ var require_extract = __commonJS({
|
|
|
32189
32189
|
}
|
|
32190
32190
|
});
|
|
32191
32191
|
|
|
32192
|
-
//
|
|
32192
|
+
// ../../node_modules/tar-stream/constants.js
|
|
32193
32193
|
var require_constants = __commonJS({
|
|
32194
|
-
"
|
|
32194
|
+
"../../node_modules/tar-stream/constants.js"(exports2, module2) {
|
|
32195
32195
|
"use strict";
|
|
32196
32196
|
var constants = {
|
|
32197
32197
|
// just for envs without fs
|
|
@@ -32210,9 +32210,9 @@ var require_constants = __commonJS({
|
|
|
32210
32210
|
}
|
|
32211
32211
|
});
|
|
32212
32212
|
|
|
32213
|
-
//
|
|
32213
|
+
// ../../node_modules/tar-stream/pack.js
|
|
32214
32214
|
var require_pack = __commonJS({
|
|
32215
|
-
"
|
|
32215
|
+
"../../node_modules/tar-stream/pack.js"(exports2, module2) {
|
|
32216
32216
|
"use strict";
|
|
32217
32217
|
var { Readable, Writable, getStreamError } = require_streamx();
|
|
32218
32218
|
var b4a = require_b4a2();
|
|
@@ -32445,9 +32445,9 @@ var require_pack = __commonJS({
|
|
|
32445
32445
|
}
|
|
32446
32446
|
});
|
|
32447
32447
|
|
|
32448
|
-
//
|
|
32448
|
+
// ../../node_modules/tar-stream/index.js
|
|
32449
32449
|
var require_tar_stream = __commonJS({
|
|
32450
|
-
"
|
|
32450
|
+
"../../node_modules/tar-stream/index.js"(exports2) {
|
|
32451
32451
|
"use strict";
|
|
32452
32452
|
exports2.extract = require_extract();
|
|
32453
32453
|
exports2.pack = require_pack();
|
|
@@ -32690,9 +32690,9 @@ var require_pump = __commonJS({
|
|
|
32690
32690
|
}
|
|
32691
32691
|
});
|
|
32692
32692
|
|
|
32693
|
-
//
|
|
32693
|
+
// ../../node_modules/tar-fs/index.js
|
|
32694
32694
|
var require_tar_fs = __commonJS({
|
|
32695
|
-
"
|
|
32695
|
+
"../../node_modules/tar-fs/index.js"(exports2) {
|
|
32696
32696
|
"use strict";
|
|
32697
32697
|
var tar = require_tar_stream();
|
|
32698
32698
|
var pump = require_pump();
|
|
@@ -36556,10 +36556,10 @@ var require_dist3 = __commonJS({
|
|
|
36556
36556
|
}
|
|
36557
36557
|
function getDaemonBuildInfo() {
|
|
36558
36558
|
if (cached2) return cached2;
|
|
36559
|
-
const commit = readInjected(true ? "
|
|
36560
|
-
const commitShort = readInjected(true ? "
|
|
36561
|
-
const version2 = readInjected(true ? "1.0.
|
|
36562
|
-
const builtAt = readInjected(true ? "2026-08-
|
|
36559
|
+
const commit = readInjected(true ? "c44c9ecb04316113166fd0c06a0a3584f072be76" : void 0) ?? "unknown";
|
|
36560
|
+
const commitShort = readInjected(true ? "c44c9ecb" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
36561
|
+
const version2 = readInjected(true ? "1.0.44-rc.1" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
36562
|
+
const builtAt = readInjected(true ? "2026-08-11T06:22:26.388Z" : void 0);
|
|
36563
36563
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
36564
36564
|
return cached2;
|
|
36565
36565
|
}
|
|
@@ -37817,7 +37817,7 @@ var require_dist3 = __commonJS({
|
|
|
37817
37817
|
}
|
|
37818
37818
|
});
|
|
37819
37819
|
function resolveBuildTrack(env2 = process.env) {
|
|
37820
|
-
const injected = true ? "" : void 0;
|
|
37820
|
+
const injected = true ? "preview" : void 0;
|
|
37821
37821
|
const stamped = typeof injected === "string" ? injected.trim() : "";
|
|
37822
37822
|
const raw = (stamped || (env2[BUILD_CHANNEL_ENV_VAR] ?? "").trim()).toLowerCase();
|
|
37823
37823
|
return raw === "preview" || raw === "next" ? "preview" : "stable";
|
|
@@ -38723,7 +38723,7 @@ child.on('exit', () => process.exit(0));
|
|
|
38723
38723
|
return typeof value === "boolean" ? value : fallback;
|
|
38724
38724
|
}
|
|
38725
38725
|
function resolveQuotaShowAccountEmail(parsed) {
|
|
38726
|
-
const fallback = DEFAULT_CONFIG.quotaShowAccountEmail ??
|
|
38726
|
+
const fallback = DEFAULT_CONFIG.quotaShowAccountEmail ?? false;
|
|
38727
38727
|
if (parsed.quotaShowAccountEmailSetByUser === true) {
|
|
38728
38728
|
return asBoolean(parsed.quotaShowAccountEmail, fallback);
|
|
38729
38729
|
}
|
|
@@ -38948,7 +38948,7 @@ child.on('exit', () => process.exit(0));
|
|
|
38948
38948
|
// preview API instead of silently pinning stable.
|
|
38949
38949
|
serverUrl: IDENTITY.serverUrl,
|
|
38950
38950
|
allowServerApiProxy: false,
|
|
38951
|
-
quotaShowAccountEmail:
|
|
38951
|
+
quotaShowAccountEmail: false,
|
|
38952
38952
|
selectedIde: null,
|
|
38953
38953
|
configuredIdes: [],
|
|
38954
38954
|
installedExtensions: [],
|
|
@@ -40271,7 +40271,7 @@ child.on('exit', () => process.exit(0));
|
|
|
40271
40271
|
return Array.from(new Set(merged));
|
|
40272
40272
|
}
|
|
40273
40273
|
function npmGlobalPrefix() {
|
|
40274
|
-
if (cachedNpmPrefix !== void 0) return cachedNpmPrefix
|
|
40274
|
+
if (cachedNpmPrefix !== void 0) return cachedNpmPrefix;
|
|
40275
40275
|
try {
|
|
40276
40276
|
const prefix = (0, import_child_process.execSync)("npm config get prefix", {
|
|
40277
40277
|
encoding: "utf-8",
|
|
@@ -40279,11 +40279,10 @@ child.on('exit', () => process.exit(0));
|
|
|
40279
40279
|
windowsHide: true,
|
|
40280
40280
|
stdio: ["ignore", "pipe", "ignore"]
|
|
40281
40281
|
}).trim();
|
|
40282
|
-
|
|
40282
|
+
if (prefix && prefix !== "undefined") cachedNpmPrefix = prefix;
|
|
40283
40283
|
} catch {
|
|
40284
|
-
cachedNpmPrefix = null;
|
|
40285
40284
|
}
|
|
40286
|
-
return cachedNpmPrefix
|
|
40285
|
+
return cachedNpmPrefix;
|
|
40287
40286
|
}
|
|
40288
40287
|
function windowsExtraBinDirs() {
|
|
40289
40288
|
const dirs = [];
|
|
@@ -40658,7 +40657,6 @@ child.on('exit', () => process.exit(0));
|
|
|
40658
40657
|
MESH_SEND_KEYS_MAX_ITEMS = 64;
|
|
40659
40658
|
MESH_SEND_KEYS_MAX_TEXT_BYTES = 4096;
|
|
40660
40659
|
buildCliSpawnEnv = import_session_host_core3.sanitizeSpawnEnv;
|
|
40661
|
-
cachedNpmPrefix = void 0;
|
|
40662
40660
|
}
|
|
40663
40661
|
});
|
|
40664
40662
|
function parseVersion(raw) {
|
|
@@ -41692,6 +41690,7 @@ ${error48.message || ""}`;
|
|
|
41692
41690
|
DEFAULT_DIFFICULTY_BRAINS: () => DEFAULT_DIFFICULTY_BRAINS,
|
|
41693
41691
|
MAGI_RAW_ANSWER_CAP: () => MAGI_RAW_ANSWER_CAP,
|
|
41694
41692
|
MESH_TASK_DIFFICULTIES: () => MESH_TASK_DIFFICULTIES,
|
|
41693
|
+
QUOTA_SUPPORTED_PROVIDERS: () => QUOTA_SUPPORTED_PROVIDERS,
|
|
41695
41694
|
STATUS_PROBE_ARG_KEY: () => STATUS_PROBE_ARG_KEY,
|
|
41696
41695
|
UNKNOWN_CLI_SLOT_RECIPE: () => UNKNOWN_CLI_SLOT_RECIPE,
|
|
41697
41696
|
argsCarryStatusProbeMarker: () => argsCarryStatusProbeMarker,
|
|
@@ -41733,6 +41732,7 @@ ${error48.message || ""}`;
|
|
|
41733
41732
|
sessionIdsEquivalent: () => sessionIdsEquivalent,
|
|
41734
41733
|
stripStatusProbeMarker: () => stripStatusProbeMarker,
|
|
41735
41734
|
summarizeGitShape: () => summarizeGitShape,
|
|
41735
|
+
supportsQuota: () => supportsQuota,
|
|
41736
41736
|
withStatusProbeMarker: () => withStatusProbeMarker
|
|
41737
41737
|
});
|
|
41738
41738
|
function readRecord(value) {
|
|
@@ -41980,6 +41980,9 @@ ${error48.message || ""}`;
|
|
|
41980
41980
|
if (!Number.isFinite(reportedAt) || reportedAt <= 0) return void 0;
|
|
41981
41981
|
return { ...record2, schemaVersion, reportedAt };
|
|
41982
41982
|
}
|
|
41983
|
+
function supportsQuota(providerType) {
|
|
41984
|
+
return !!providerType && QUOTA_SUPPORTED_PROVIDERS.includes(providerType);
|
|
41985
|
+
}
|
|
41983
41986
|
function formatQuotaAccount(quota) {
|
|
41984
41987
|
const meta3 = quota?.metadata;
|
|
41985
41988
|
const email3 = typeof meta3?.accountEmail === "string" ? meta3.accountEmail.trim() : "";
|
|
@@ -42270,6 +42273,7 @@ ${error48.message || ""}`;
|
|
|
42270
42273
|
const { [STATUS_PROBE_ARG_KEY]: _drop, ...rest } = args;
|
|
42271
42274
|
return rest;
|
|
42272
42275
|
}
|
|
42276
|
+
var QUOTA_SUPPORTED_PROVIDERS;
|
|
42273
42277
|
var DAEMON_ID_PREFIXES;
|
|
42274
42278
|
var MAGI_RAW_ANSWER_CAP;
|
|
42275
42279
|
var MESH_TASK_DIFFICULTIES;
|
|
@@ -42282,6 +42286,12 @@ ${error48.message || ""}`;
|
|
|
42282
42286
|
var init_dist = __esm2({
|
|
42283
42287
|
"../mesh-shared/dist/index.mjs"() {
|
|
42284
42288
|
"use strict";
|
|
42289
|
+
QUOTA_SUPPORTED_PROVIDERS = [
|
|
42290
|
+
"claude-cli",
|
|
42291
|
+
"codex-cli",
|
|
42292
|
+
"kimi",
|
|
42293
|
+
"opencode"
|
|
42294
|
+
];
|
|
42285
42295
|
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
42286
42296
|
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
42287
42297
|
MESH_TASK_DIFFICULTIES = ["easy", "medium", "difficult", "freeform"];
|
|
@@ -59943,6 +59953,332 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
59943
59953
|
PROVIDER_QUOTA_WEEKLY_LOW_SKIP_REASON = "provider_quota_weekly_low";
|
|
59944
59954
|
}
|
|
59945
59955
|
});
|
|
59956
|
+
function isAnthropicProvider(providerType) {
|
|
59957
|
+
const p = typeof providerType === "string" ? providerType.trim().toLowerCase() : "";
|
|
59958
|
+
return p.length > 0 && ANTHROPIC_PROVIDER_TYPES.has(p);
|
|
59959
|
+
}
|
|
59960
|
+
function isAnthropicModel(model) {
|
|
59961
|
+
const m = typeof model === "string" ? model.trim().toLowerCase() : "";
|
|
59962
|
+
if (!m) return false;
|
|
59963
|
+
if (m.startsWith("claude") || m.startsWith("anthropic")) return true;
|
|
59964
|
+
return /^(opus|sonnet|haiku)(\b|[-_])/.test(m);
|
|
59965
|
+
}
|
|
59966
|
+
function isModelCompatibleWithProvider(model, providerType) {
|
|
59967
|
+
if (!isAnthropicModel(model)) return true;
|
|
59968
|
+
if (isAnthropicProvider(providerType)) return true;
|
|
59969
|
+
return false;
|
|
59970
|
+
}
|
|
59971
|
+
var ANTHROPIC_PROVIDER_TYPES;
|
|
59972
|
+
var init_model_provider_compat = __esm2({
|
|
59973
|
+
"src/mesh/model-provider-compat.ts"() {
|
|
59974
|
+
"use strict";
|
|
59975
|
+
ANTHROPIC_PROVIDER_TYPES = /* @__PURE__ */ new Set([
|
|
59976
|
+
"claude-cli"
|
|
59977
|
+
]);
|
|
59978
|
+
}
|
|
59979
|
+
});
|
|
59980
|
+
function encodeDuplicateMeshDispatchCode(holderSessionId) {
|
|
59981
|
+
const holder = typeof holderSessionId === "string" ? holderSessionId.trim() : "";
|
|
59982
|
+
return holder ? `${DUPLICATE_MESH_DISPATCH_CODE}:${holder}` : DUPLICATE_MESH_DISPATCH_CODE;
|
|
59983
|
+
}
|
|
59984
|
+
function classifyDuplicateMeshDispatch(err) {
|
|
59985
|
+
if (!err || typeof err !== "object") return null;
|
|
59986
|
+
const e = err;
|
|
59987
|
+
if (e.code === DUPLICATE_MESH_DISPATCH_CODE) {
|
|
59988
|
+
const holder = typeof e.holderSessionId === "string" ? e.holderSessionId.trim() : "";
|
|
59989
|
+
return holder ? { holderSessionId: holder } : {};
|
|
59990
|
+
}
|
|
59991
|
+
for (const raw of [e.meshCode, e.code]) {
|
|
59992
|
+
if (typeof raw !== "string") continue;
|
|
59993
|
+
if (raw !== DUPLICATE_MESH_DISPATCH_CODE && !raw.startsWith(`${DUPLICATE_MESH_DISPATCH_CODE}:`)) continue;
|
|
59994
|
+
const holder = raw.slice(DUPLICATE_MESH_DISPATCH_CODE.length + 1).trim();
|
|
59995
|
+
return holder ? { holderSessionId: holder } : {};
|
|
59996
|
+
}
|
|
59997
|
+
return null;
|
|
59998
|
+
}
|
|
59999
|
+
var DUPLICATE_MESH_DISPATCH_CODE;
|
|
60000
|
+
var DuplicateMeshDispatchError;
|
|
60001
|
+
var init_mesh_duplicate_dispatch = __esm2({
|
|
60002
|
+
"src/mesh/mesh-duplicate-dispatch.ts"() {
|
|
60003
|
+
"use strict";
|
|
60004
|
+
DUPLICATE_MESH_DISPATCH_CODE = "DUPLICATE_MESH_DISPATCH";
|
|
60005
|
+
DuplicateMeshDispatchError = class extends Error {
|
|
60006
|
+
code = DUPLICATE_MESH_DISPATCH_CODE;
|
|
60007
|
+
holderSessionId;
|
|
60008
|
+
constructor(message, info = {}) {
|
|
60009
|
+
super(message);
|
|
60010
|
+
this.name = "DuplicateMeshDispatchError";
|
|
60011
|
+
this.holderSessionId = info.holderSessionId;
|
|
60012
|
+
}
|
|
60013
|
+
};
|
|
60014
|
+
}
|
|
60015
|
+
});
|
|
60016
|
+
function acquireAutoFastForwardLease(workspace) {
|
|
60017
|
+
const key2 = normalizeMeshWorkspaceForCompare(workspace);
|
|
60018
|
+
if (!key2) return false;
|
|
60019
|
+
if (autoFastForwardWorkspaceLease.has(key2)) return false;
|
|
60020
|
+
autoFastForwardWorkspaceLease.add(key2);
|
|
60021
|
+
return true;
|
|
60022
|
+
}
|
|
60023
|
+
function releaseAutoFastForwardLease(workspace) {
|
|
60024
|
+
const key2 = normalizeMeshWorkspaceForCompare(workspace);
|
|
60025
|
+
if (key2) autoFastForwardWorkspaceLease.delete(key2);
|
|
60026
|
+
}
|
|
60027
|
+
function isWorkspaceAutoFastForwardInFlight(workspace) {
|
|
60028
|
+
const key2 = normalizeMeshWorkspaceForCompare(workspace || "");
|
|
60029
|
+
return !!key2 && autoFastForwardWorkspaceLease.has(key2);
|
|
60030
|
+
}
|
|
60031
|
+
function __resetIdleAutoFastForwardForTests() {
|
|
60032
|
+
idleAutoFastForwardLastAttempt.clear();
|
|
60033
|
+
continuousAutoFastForwardLastScan.clear();
|
|
60034
|
+
autoFastForwardWorkspaceLease.clear();
|
|
60035
|
+
}
|
|
60036
|
+
function isDirtyNode(node) {
|
|
60037
|
+
return node?.health === "dirty" || node?.git?.dirty === true;
|
|
60038
|
+
}
|
|
60039
|
+
function resolveAutoFastForwardPolicy(mesh) {
|
|
60040
|
+
const record2 = mesh?.policy?.autoFastForward && typeof mesh.policy.autoFastForward === "object" && !Array.isArray(mesh.policy.autoFastForward) ? mesh.policy.autoFastForward : {};
|
|
60041
|
+
const maxBehind = Number(record2.maxBehind);
|
|
60042
|
+
return {
|
|
60043
|
+
enabled: record2.enabled !== false,
|
|
60044
|
+
...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
|
|
60045
|
+
requireCleanSubmodules: record2.requireCleanSubmodules !== false,
|
|
60046
|
+
// Strict opt-in: absent/false → self-only (historical behavior). Only an
|
|
60047
|
+
// explicit `true` extends auto ff to remote owning-daemon nodes.
|
|
60048
|
+
remoteNodes: record2.remoteNodes === true,
|
|
60049
|
+
// Absent/anything-but-continuous → 'idle' (historical idle-edge-only detection).
|
|
60050
|
+
mode: record2.mode === "continuous" ? "continuous" : "idle"
|
|
60051
|
+
};
|
|
60052
|
+
}
|
|
60053
|
+
function dryRunSatisfiesAutoFastForwardPolicy(dryRun, policy) {
|
|
60054
|
+
if (!dryRun || dryRun.code !== "fast_forward_available" || dryRun.allowed !== true) return false;
|
|
60055
|
+
const behind = Number(dryRun.current?.behind);
|
|
60056
|
+
if (!Number.isFinite(behind) || behind <= 0) return false;
|
|
60057
|
+
if (policy.maxBehind !== void 0 && behind > policy.maxBehind) return false;
|
|
60058
|
+
if (policy.requireCleanSubmodules) {
|
|
60059
|
+
const submodules = Array.isArray(dryRun.current?.submodules) ? dryRun.current.submodules : [];
|
|
60060
|
+
if (submodules.some((submodule) => submodule?.dirty || submodule?.outOfSync || submodule?.error)) return false;
|
|
60061
|
+
}
|
|
60062
|
+
return true;
|
|
60063
|
+
}
|
|
60064
|
+
function readNodeSubmoduleIgnorePaths(node) {
|
|
60065
|
+
return Array.isArray(node?.policy?.submoduleIgnorePaths) ? node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
60066
|
+
}
|
|
60067
|
+
function nodeIsAutoFastForwardEligible(components, meshId, nodeId, node, currentSessionId) {
|
|
60068
|
+
if (!node) return false;
|
|
60069
|
+
if (node.status === "disabled" || node.status === "removed") return false;
|
|
60070
|
+
if (node.readOnly === true || node.policy?.readOnly === true) return false;
|
|
60071
|
+
if (isWorktreeBootstrapStaleRunning(node)) return false;
|
|
60072
|
+
if (node.worktreeBootstrap?.status === "running") return false;
|
|
60073
|
+
if (nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId)) return false;
|
|
60074
|
+
return true;
|
|
60075
|
+
}
|
|
60076
|
+
function remoteNodeIsConnected(components, node) {
|
|
60077
|
+
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
60078
|
+
if (!daemonId) return false;
|
|
60079
|
+
const getPeerStatus = components.getMeshPeerConnectionStatus;
|
|
60080
|
+
if (getPeerStatus) {
|
|
60081
|
+
const snapshot = getPeerStatus(daemonId);
|
|
60082
|
+
return !!snapshot && String(snapshot.state) === "connected";
|
|
60083
|
+
}
|
|
60084
|
+
return readNonEmptyString(node?.connection?.state).toLowerCase() === "connected";
|
|
60085
|
+
}
|
|
60086
|
+
async function delegateRemoteAutoFastForward(components, args) {
|
|
60087
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
60088
|
+
if (!dispatchMeshCommand) return;
|
|
60089
|
+
if (!acquireAutoFastForwardLease(args.workspace)) return;
|
|
60090
|
+
const submoduleIgnorePaths = readNodeSubmoduleIgnorePaths(args.node);
|
|
60091
|
+
const mesh = getMeshWithCache(components, args.meshId);
|
|
60092
|
+
const baseArgs = {
|
|
60093
|
+
meshId: args.meshId,
|
|
60094
|
+
nodeId: args.nodeId,
|
|
60095
|
+
workspace: args.workspace,
|
|
60096
|
+
inlineMesh: mesh,
|
|
60097
|
+
...submoduleIgnorePaths ? { submoduleIgnorePaths } : {},
|
|
60098
|
+
trigger: args.trigger,
|
|
60099
|
+
// Preserve the pre-fix self-only semantics for submodules: the local idle path
|
|
60100
|
+
// never updated submodules (updateSubmodules:false), so the remote path matches.
|
|
60101
|
+
updateSubmodules: false
|
|
60102
|
+
};
|
|
60103
|
+
try {
|
|
60104
|
+
const remoteDry = await dispatchMeshCommand(args.daemonId, "fast_forward_mesh_node", {
|
|
60105
|
+
...baseArgs,
|
|
60106
|
+
execute: false,
|
|
60107
|
+
dryRun: true
|
|
60108
|
+
});
|
|
60109
|
+
if (!dryRunSatisfiesAutoFastForwardPolicy(remoteDry, args.policy)) return;
|
|
60110
|
+
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId)) return;
|
|
60111
|
+
const executed = await dispatchMeshCommand(args.daemonId, "fast_forward_mesh_node", {
|
|
60112
|
+
...baseArgs,
|
|
60113
|
+
execute: true,
|
|
60114
|
+
dryRun: false
|
|
60115
|
+
});
|
|
60116
|
+
if (executed?.executed === true) {
|
|
60117
|
+
LOG2.info("MeshFastForward", `Remote auto fast-forward executed for node ${args.nodeId} (daemon ${String(args.daemonId).slice(0, 12)}, trigger ${args.trigger})`);
|
|
60118
|
+
}
|
|
60119
|
+
} catch (e) {
|
|
60120
|
+
LOG2.warn("MeshFastForward", `Remote auto fast-forward delegation failed for ${args.nodeId}: ${e?.message || e}`);
|
|
60121
|
+
} finally {
|
|
60122
|
+
releaseAutoFastForwardLease(args.workspace);
|
|
60123
|
+
}
|
|
60124
|
+
}
|
|
60125
|
+
async function executeLocalAutoFastForward(args) {
|
|
60126
|
+
if (!acquireAutoFastForwardLease(args.workspace)) return;
|
|
60127
|
+
const submoduleIgnorePaths = readNodeSubmoduleIgnorePaths(args.node);
|
|
60128
|
+
try {
|
|
60129
|
+
const dryRun = await fastForwardMeshNode({
|
|
60130
|
+
meshId: args.meshId,
|
|
60131
|
+
nodeId: args.nodeId,
|
|
60132
|
+
workspace: args.workspace,
|
|
60133
|
+
execute: false,
|
|
60134
|
+
dryRun: true,
|
|
60135
|
+
updateSubmodules: false,
|
|
60136
|
+
submoduleIgnorePaths,
|
|
60137
|
+
trigger: args.trigger
|
|
60138
|
+
});
|
|
60139
|
+
if (!dryRunSatisfiesAutoFastForwardPolicy(dryRun, args.policy)) return;
|
|
60140
|
+
await fastForwardMeshNode({
|
|
60141
|
+
meshId: args.meshId,
|
|
60142
|
+
nodeId: args.nodeId,
|
|
60143
|
+
workspace: args.workspace,
|
|
60144
|
+
execute: true,
|
|
60145
|
+
dryRun: false,
|
|
60146
|
+
updateSubmodules: false,
|
|
60147
|
+
submoduleIgnorePaths,
|
|
60148
|
+
trigger: args.trigger
|
|
60149
|
+
});
|
|
60150
|
+
} catch (e) {
|
|
60151
|
+
LOG2.warn("MeshFastForward", `Idle auto fast-forward check failed for ${args.nodeId}: ${e?.message || e}`);
|
|
60152
|
+
} finally {
|
|
60153
|
+
releaseAutoFastForwardLease(args.workspace);
|
|
60154
|
+
}
|
|
60155
|
+
}
|
|
60156
|
+
async function maybeAutoFastForwardIdleNode(components, args) {
|
|
60157
|
+
const mesh = getMeshWithCache(components, args.meshId);
|
|
60158
|
+
const node = mesh?.nodes?.find((candidate) => meshNodeIdMatches(candidate, args.nodeId));
|
|
60159
|
+
const workspace = readNonEmptyString(node?.workspace);
|
|
60160
|
+
if (!workspace) return;
|
|
60161
|
+
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
60162
|
+
if (!policy.enabled) return;
|
|
60163
|
+
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
|
|
60164
|
+
const throttleKey = `${args.meshId}:${args.nodeId}`;
|
|
60165
|
+
const now = Date.now();
|
|
60166
|
+
const lastAttempt = idleAutoFastForwardLastAttempt.get(throttleKey) || 0;
|
|
60167
|
+
if (now - lastAttempt < IDLE_AUTO_FAST_FORWARD_THROTTLE_MS) return;
|
|
60168
|
+
idleAutoFastForwardLastAttempt.set(throttleKey, now);
|
|
60169
|
+
if (isLocalAutoLaunchNode(node)) {
|
|
60170
|
+
if (!(0, import_fs14.existsSync)(workspace)) return;
|
|
60171
|
+
await executeLocalAutoFastForward({ meshId: args.meshId, nodeId: args.nodeId, node, workspace, policy, trigger: "idle_auto" });
|
|
60172
|
+
return;
|
|
60173
|
+
}
|
|
60174
|
+
if (!policy.remoteNodes) return;
|
|
60175
|
+
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
60176
|
+
if (!daemonId || !components.dispatchMeshCommand) return;
|
|
60177
|
+
if (!remoteNodeIsConnected(components, node)) return;
|
|
60178
|
+
await delegateRemoteAutoFastForward(components, { meshId: args.meshId, nodeId: args.nodeId, node, daemonId, workspace, policy, trigger: "idle_auto" });
|
|
60179
|
+
}
|
|
60180
|
+
async function runContinuousAutoFastForwardScan(components, mesh) {
|
|
60181
|
+
if (!components.dispatchMeshCommand) return;
|
|
60182
|
+
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
60183
|
+
if (!policy.enabled || !policy.remoteNodes || policy.mode !== "continuous") return;
|
|
60184
|
+
const meshId = readNonEmptyString(mesh?.id);
|
|
60185
|
+
if (!meshId) return;
|
|
60186
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60187
|
+
const now = Date.now();
|
|
60188
|
+
for (const node of nodes) {
|
|
60189
|
+
const nodeId = normalizeMeshNodeId(node);
|
|
60190
|
+
if (!nodeId) continue;
|
|
60191
|
+
if (node?.isLocalWorktree === true) continue;
|
|
60192
|
+
if (isLocalAutoLaunchNode(node)) continue;
|
|
60193
|
+
const workspace = readNonEmptyString(node?.workspace);
|
|
60194
|
+
if (!workspace) continue;
|
|
60195
|
+
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
60196
|
+
if (!daemonId) continue;
|
|
60197
|
+
if (!nodeIsAutoFastForwardEligible(components, meshId, nodeId, node)) continue;
|
|
60198
|
+
if (!remoteNodeIsConnected(components, node)) continue;
|
|
60199
|
+
const cooldownKey = `${meshId}:${nodeId}`;
|
|
60200
|
+
const lastScan = continuousAutoFastForwardLastScan.get(cooldownKey) || 0;
|
|
60201
|
+
if (now - lastScan < CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS) continue;
|
|
60202
|
+
continuousAutoFastForwardLastScan.set(cooldownKey, now);
|
|
60203
|
+
await delegateRemoteAutoFastForward(components, { meshId, nodeId, node, daemonId, workspace, policy, trigger: "reconcile_auto" });
|
|
60204
|
+
}
|
|
60205
|
+
}
|
|
60206
|
+
async function runPendingCoordinatorCatchupScan(components, mesh) {
|
|
60207
|
+
const meshId = readNonEmptyString(mesh?.id);
|
|
60208
|
+
if (!meshId) return;
|
|
60209
|
+
const localIds = expandDaemonIdForms([
|
|
60210
|
+
readNonEmptyString(components.statusInstanceId),
|
|
60211
|
+
readNonEmptyString(loadConfig2().machineId)
|
|
60212
|
+
]);
|
|
60213
|
+
let markers = [];
|
|
60214
|
+
try {
|
|
60215
|
+
markers = drainPendingMeshCoordinatorEvents(
|
|
60216
|
+
meshId,
|
|
60217
|
+
localIds.length > 0 ? localIds : void 0,
|
|
60218
|
+
{ onlyEvents: /* @__PURE__ */ new Set(["coordinator_catchup"]) }
|
|
60219
|
+
);
|
|
60220
|
+
} catch (e) {
|
|
60221
|
+
LOG2.warn("MeshReconcile", `Coordinator-catchup drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
60222
|
+
return;
|
|
60223
|
+
}
|
|
60224
|
+
if (markers.length === 0) return;
|
|
60225
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60226
|
+
for (const marker of markers) {
|
|
60227
|
+
const meta3 = marker.metadataEvent || {};
|
|
60228
|
+
const nodeId = readNonEmptyString(marker.nodeId) || readNonEmptyString(meta3.nodeId);
|
|
60229
|
+
const workspace = readNonEmptyString(marker.workspace) || readNonEmptyString(meta3.workspace);
|
|
60230
|
+
const baseBranch = readNonEmptyString(meta3.baseBranch);
|
|
60231
|
+
if (!workspace) continue;
|
|
60232
|
+
if (nodeId && nodeHasActiveMeshWork(components, meshId, nodeId)) {
|
|
60233
|
+
try {
|
|
60234
|
+
queuePendingMeshCoordinatorEvent(marker);
|
|
60235
|
+
} catch {
|
|
60236
|
+
}
|
|
60237
|
+
continue;
|
|
60238
|
+
}
|
|
60239
|
+
try {
|
|
60240
|
+
const ff = await fastForwardMeshNode({
|
|
60241
|
+
meshId,
|
|
60242
|
+
...nodeId ? { nodeId } : {},
|
|
60243
|
+
workspace,
|
|
60244
|
+
...baseBranch ? { branch: baseBranch } : {},
|
|
60245
|
+
mode: "merge",
|
|
60246
|
+
execute: true,
|
|
60247
|
+
trigger: "refine_post_push_catchup",
|
|
60248
|
+
allowAutoPublishSubmoduleMainCommits: mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true
|
|
60249
|
+
});
|
|
60250
|
+
LOG2.info("MeshReconcile", `Coordinator catch-up ff for ${meshId}/${nodeId || workspace}: ${ff.code} (executed=${ff.executed})`);
|
|
60251
|
+
} catch (e) {
|
|
60252
|
+
LOG2.warn("MeshReconcile", `Coordinator catch-up ff failed for ${meshId}/${nodeId || workspace}: ${e?.message || e}`);
|
|
60253
|
+
}
|
|
60254
|
+
}
|
|
60255
|
+
}
|
|
60256
|
+
var import_fs14;
|
|
60257
|
+
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS;
|
|
60258
|
+
var idleAutoFastForwardLastAttempt;
|
|
60259
|
+
var CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS;
|
|
60260
|
+
var continuousAutoFastForwardLastScan;
|
|
60261
|
+
var autoFastForwardWorkspaceLease;
|
|
60262
|
+
var init_mesh_auto_fast_forward = __esm2({
|
|
60263
|
+
"src/mesh/mesh-auto-fast-forward.ts"() {
|
|
60264
|
+
"use strict";
|
|
60265
|
+
import_fs14 = require("fs");
|
|
60266
|
+
init_logger();
|
|
60267
|
+
init_config();
|
|
60268
|
+
init_mesh_fast_forward();
|
|
60269
|
+
init_dist();
|
|
60270
|
+
init_mesh_events_utils();
|
|
60271
|
+
init_mesh_node_identity();
|
|
60272
|
+
init_mesh_events_pending();
|
|
60273
|
+
init_worktree_bootstrap_config();
|
|
60274
|
+
init_mesh_queue_assignment();
|
|
60275
|
+
IDLE_AUTO_FAST_FORWARD_THROTTLE_MS = 30 * 60 * 1e3;
|
|
60276
|
+
idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
|
|
60277
|
+
CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS = 45 * 1e3;
|
|
60278
|
+
continuousAutoFastForwardLastScan = /* @__PURE__ */ new Map();
|
|
60279
|
+
autoFastForwardWorkspaceLease = /* @__PURE__ */ new Set();
|
|
60280
|
+
}
|
|
60281
|
+
});
|
|
59946
60282
|
function normalizeNodeIdKey(nodeId) {
|
|
59947
60283
|
return normalizeMeshNodeId({ id: nodeId ?? void 0 }) ?? "";
|
|
59948
60284
|
}
|
|
@@ -59978,88 +60314,384 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
59978
60314
|
MAX_TRACKED_CLONED_NODES = 512;
|
|
59979
60315
|
}
|
|
59980
60316
|
});
|
|
59981
|
-
function
|
|
59982
|
-
|
|
59983
|
-
return
|
|
60317
|
+
function isActionableSkipReason(reason) {
|
|
60318
|
+
if (!reason) return false;
|
|
60319
|
+
return ACTIONABLE_SKIP_REASON_PREFIXES.some((prefix) => reason === prefix || reason.startsWith(prefix));
|
|
59984
60320
|
}
|
|
59985
|
-
function
|
|
59986
|
-
const
|
|
59987
|
-
if (!
|
|
59988
|
-
|
|
59989
|
-
|
|
60321
|
+
function isTargetNodeTransientlyUnresolved(mesh, task) {
|
|
60322
|
+
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
60323
|
+
if (!targetNodeId) return false;
|
|
60324
|
+
const node = Array.isArray(mesh?.nodes) ? mesh.nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
60325
|
+
if (node && node.worktreeBootstrap?.status === "running" && !isWorktreeBootstrapStaleRunning(node)) {
|
|
60326
|
+
return true;
|
|
60327
|
+
}
|
|
60328
|
+
return isWithinCloneBootstrapGrace(targetNodeId);
|
|
59990
60329
|
}
|
|
59991
|
-
function
|
|
59992
|
-
|
|
59993
|
-
|
|
59994
|
-
return false;
|
|
60330
|
+
function targetPinAgeMs(task, nowMs = Date.now()) {
|
|
60331
|
+
const anchorMs = Date.parse(task.requeuedAt || task.createdAt || "");
|
|
60332
|
+
return Number.isFinite(anchorMs) ? nowMs - anchorMs : null;
|
|
59995
60333
|
}
|
|
59996
|
-
|
|
59997
|
-
|
|
59998
|
-
|
|
60334
|
+
function resolveDeadTargetVerdict(components, meshId, mesh, task) {
|
|
60335
|
+
const NOT_DEAD = { dead: false, nodeDead: false, reason: "" };
|
|
60336
|
+
const targetSessionId = readNonEmptyString(task.targetSessionId);
|
|
60337
|
+
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
60338
|
+
if (!targetSessionId && !targetNodeId) return NOT_DEAD;
|
|
60339
|
+
const lastUpdateMs = Date.parse(task.updatedAt || task.createdAt || "");
|
|
60340
|
+
if (Number.isFinite(lastUpdateMs) && Date.now() - lastUpdateMs < DEAD_TARGET_GRACE_MS) return NOT_DEAD;
|
|
60341
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60342
|
+
if (targetNodeId) {
|
|
60343
|
+
const nodePresent = nodes.some((n) => meshNodeIdMatches(n, targetNodeId));
|
|
60344
|
+
if (!nodePresent) {
|
|
60345
|
+
if (isTargetNodeTransientlyUnresolved(mesh, task)) return NOT_DEAD;
|
|
60346
|
+
return { dead: true, nodeDead: true, reason: "dead_target_node_absent" };
|
|
60347
|
+
}
|
|
60348
|
+
}
|
|
60349
|
+
if (targetSessionId) {
|
|
60350
|
+
const node = targetNodeId ? nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
60351
|
+
const nodeIsLocal = node ? isLocalAutoLaunchNode(node) : true;
|
|
60352
|
+
if (nodeIsLocal) {
|
|
60353
|
+
const verdict = resolveSessionBusyVerdict(components, targetSessionId);
|
|
60354
|
+
if (verdict === "UNKNOWN") {
|
|
60355
|
+
return { dead: true, nodeDead: false, reason: "dead_target_session_absent" };
|
|
60356
|
+
}
|
|
60357
|
+
}
|
|
60358
|
+
}
|
|
60359
|
+
return NOT_DEAD;
|
|
60360
|
+
}
|
|
60361
|
+
function retractActionableSkipIfPreviouslyNotified(meshId, taskId) {
|
|
60362
|
+
const dedupKey = `${meshId}:${taskId}`;
|
|
60363
|
+
if (!lastActionableSkipNotified.delete(dedupKey)) return;
|
|
60364
|
+
try {
|
|
60365
|
+
const coordinatorDaemonId = readNonEmptyString(loadConfig2().machineId) || void 0;
|
|
60366
|
+
const removed = retractPendingDispatchBlockedEvent(meshId, taskId, coordinatorDaemonId);
|
|
60367
|
+
if (removed > 0) {
|
|
60368
|
+
LOG2.info("MeshQueue", `Retracted ${removed} stale dispatch-blocked event(s) for task ${taskId} (mesh ${meshId}) \u2014 its blocker resolved`);
|
|
60369
|
+
}
|
|
60370
|
+
} catch (e) {
|
|
60371
|
+
LOG2.warn("MeshQueue", `Failed to retract stale dispatch-blocked event for task ${taskId} (mesh ${meshId}): ${e?.message || e}`);
|
|
60372
|
+
}
|
|
60373
|
+
}
|
|
60374
|
+
function actionableSkipGuidance(reason) {
|
|
60375
|
+
if (reason === "target_node_id_unmatched") return {
|
|
60376
|
+
summary: "it is pinned to a target node id that matches no node in the mesh (the node may have been removed, or its id form does not resolve)",
|
|
60377
|
+
nextAction: "Verify the target node still exists with mesh_status, then re-enqueue without the node pin or with a valid node id (or re-clone the node)."
|
|
60378
|
+
};
|
|
60379
|
+
if (reason === "no_node_satisfies_required_tags") return {
|
|
60380
|
+
summary: "no node in the mesh can satisfy the task's required capability tags",
|
|
60381
|
+
nextAction: "Relax the task's requiredTags, or add/launch a node whose provider produces the required capabilities."
|
|
60382
|
+
};
|
|
60383
|
+
if (reason === "mesh_convergence_target_is_worktree") return {
|
|
60384
|
+
summary: "it is a convergence task (base-only: merge \u2192 push \u2192 cleanup) but every candidate node is a worktree clone",
|
|
60385
|
+
nextAction: "Dispatch the convergence task to the base node, or run the deterministic fast-forward path (mesh_fast_forward_node / mesh_refine_node) instead."
|
|
60386
|
+
};
|
|
60387
|
+
if (reason.startsWith("remote_auto_launch")) return {
|
|
60388
|
+
summary: "the target node is on a remote daemon this coordinator cannot auto-launch a session on (no dispatch transport, or no coordinator daemon id to stamp)",
|
|
60389
|
+
nextAction: "Launch a session on that node yourself with mesh_launch_session, or ensure the remote daemon is connected over P2P."
|
|
60390
|
+
};
|
|
60391
|
+
if (reason.startsWith("provider") || reason === "missing_provider_priority") return {
|
|
60392
|
+
summary: "the node has no usable provider for this task (provider priority missing/unusable, or the provider loader is unavailable)",
|
|
60393
|
+
nextAction: "Check the node's providerPriority policy and that the required CLI/ACP provider is installed and enabled on that machine."
|
|
60394
|
+
};
|
|
60395
|
+
if (reason === "dirty_workspace") return {
|
|
60396
|
+
summary: "the node's workspace is dirty, so auto-launch is blocked to avoid clobbering uncommitted changes",
|
|
60397
|
+
nextAction: "Clean or commit the node's working tree (or fast-forward it); the task will then auto-assign."
|
|
60398
|
+
};
|
|
60399
|
+
if (reason === "target_session_pin_expired") return {
|
|
60400
|
+
summary: "it was pinned to a specific session (a follow-up/delta for work already in flight) that never claimed it within the pin TTL, so the pin was cleared and the message will NOT reach the session it was addressed to",
|
|
60401
|
+
nextAction: "Assume the addressed session never received this delta and is still acting on its previous instructions. Re-send it to that session once it is idle (or re-target it), and re-check the work it produced in the meantime."
|
|
60402
|
+
};
|
|
60403
|
+
if (reason === SLOT_MODEL_ABSENT_SKIP_REASON) return {
|
|
60404
|
+
summary: "no capability slot on the node declares the model this task resolved to (its difficulty\u2192brain preset picked a model the node was never configured to run)",
|
|
60405
|
+
nextAction: "Re-enqueue with a difficulty/model the node's slots declare, target a node that declares this model, or add a slot for it. The task is NOT run on a substitute model \u2014 an undeclared model is never launched."
|
|
60406
|
+
};
|
|
60407
|
+
return {
|
|
60408
|
+
summary: `it cannot be dispatched (${reason})`,
|
|
60409
|
+
nextAction: "Inspect the node/mesh state with mesh_status and resolve the blocker, or re-enqueue the task."
|
|
60410
|
+
};
|
|
60411
|
+
}
|
|
60412
|
+
function notifyCoordinatorOfActionableSkip(meshId, taskId, reason, nodeId) {
|
|
60413
|
+
if (!isActionableSkipReason(reason)) return;
|
|
60414
|
+
if (reason === "target_node_id_unmatched" && isWithinCloneBootstrapGrace(readNonEmptyString(nodeId))) return;
|
|
60415
|
+
const dedupKey = `${meshId}:${taskId}`;
|
|
60416
|
+
if (lastActionableSkipNotified.get(dedupKey) === reason) return;
|
|
60417
|
+
lastActionableSkipNotified.set(dedupKey, reason);
|
|
60418
|
+
if (lastActionableSkipNotified.size > AUTO_LAUNCH_LEDGER_DEDUP_MAX) {
|
|
60419
|
+
const oldest = lastActionableSkipNotified.keys().next().value;
|
|
60420
|
+
if (oldest !== void 0) lastActionableSkipNotified.delete(oldest);
|
|
60421
|
+
}
|
|
60422
|
+
let task;
|
|
60423
|
+
try {
|
|
60424
|
+
task = getQueue(meshId).find((t) => t.id === taskId);
|
|
60425
|
+
} catch {
|
|
60426
|
+
}
|
|
60427
|
+
const targetCoordinatorDaemonId = readNonEmptyString(loadConfig2().machineId);
|
|
60428
|
+
const targetCoordinatorSessionId = readNonEmptyString(task?.sourceCoordinatorSessionId);
|
|
60429
|
+
const nodeLabel = readNonEmptyString(nodeId) || readNonEmptyString(task?.targetNodeId);
|
|
60430
|
+
const { summary, nextAction } = actionableSkipGuidance(reason);
|
|
60431
|
+
const coordinatorMessage = `[System] A queued mesh task${nodeLabel ? ` for node ${nodeLabel}` : ""} is not being dispatched because ${summary}. ${nextAction} This is an actionable blocker \u2014 it will NOT clear on its own; the task stays pending until you resolve it.`;
|
|
60432
|
+
try {
|
|
60433
|
+
queuePendingMeshCoordinatorEvent({
|
|
60434
|
+
event: "mesh:dispatch_blocked",
|
|
60435
|
+
meshId,
|
|
60436
|
+
nodeLabel: nodeLabel || meshId,
|
|
60437
|
+
...nodeLabel ? { nodeId: nodeLabel } : {},
|
|
60438
|
+
metadataEvent: {
|
|
60439
|
+
source: "mesh_queue_dispatch_skip",
|
|
60440
|
+
taskId,
|
|
60441
|
+
reason,
|
|
60442
|
+
...nodeLabel ? { nodeId: nodeLabel } : {},
|
|
60443
|
+
coordinatorMessage
|
|
60444
|
+
},
|
|
60445
|
+
coordinatorMessage,
|
|
60446
|
+
queuedAt: Date.now(),
|
|
60447
|
+
...targetCoordinatorDaemonId ? { targetCoordinatorDaemonId } : {},
|
|
60448
|
+
...targetCoordinatorSessionId ? { targetCoordinatorSessionId } : {}
|
|
60449
|
+
});
|
|
60450
|
+
} catch (e) {
|
|
60451
|
+
LOG2.warn("MeshQueue", `Failed to surface actionable dispatch-skip (${reason}) for task ${taskId}: ${e?.message || e}`);
|
|
60452
|
+
}
|
|
60453
|
+
}
|
|
60454
|
+
var ACTIONABLE_SKIP_REASON_PREFIXES;
|
|
60455
|
+
var TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON;
|
|
60456
|
+
var lastActionableSkipNotified;
|
|
60457
|
+
var DEAD_TARGET_GRACE_MS;
|
|
60458
|
+
var TARGET_SESSION_PIN_TTL_MS;
|
|
60459
|
+
var init_mesh_skip_notify = __esm2({
|
|
60460
|
+
"src/mesh/mesh-skip-notify.ts"() {
|
|
59999
60461
|
"use strict";
|
|
60000
|
-
|
|
60001
|
-
|
|
60002
|
-
|
|
60462
|
+
init_logger();
|
|
60463
|
+
init_mesh_work_queue();
|
|
60464
|
+
init_dist();
|
|
60465
|
+
init_mesh_events_utils();
|
|
60466
|
+
init_mesh_events_pending();
|
|
60467
|
+
init_worktree_bootstrap_config();
|
|
60468
|
+
init_mesh_clone_grace();
|
|
60469
|
+
init_config();
|
|
60470
|
+
init_slot_model_enforcement();
|
|
60471
|
+
init_mesh_queue_assignment();
|
|
60472
|
+
ACTIONABLE_SKIP_REASON_PREFIXES = [
|
|
60473
|
+
"target_node_id_unmatched",
|
|
60474
|
+
"no_node_satisfies_required_tags",
|
|
60475
|
+
"mesh_convergence_target_is_worktree",
|
|
60476
|
+
"remote_auto_launch_unsupported",
|
|
60477
|
+
"remote_auto_launch_no_coordinator_daemon_id",
|
|
60478
|
+
"missing_provider_priority",
|
|
60479
|
+
"provider_loader_unavailable",
|
|
60480
|
+
"provider_priority_unusable",
|
|
60481
|
+
"provider_unusable",
|
|
60482
|
+
"dirty_workspace",
|
|
60483
|
+
// TARGET-PIN-TTL EXPIRY: the task was pinned to a specific session (a delta —
|
|
60484
|
+
// a correction addressed to work already in flight) and that session never
|
|
60485
|
+
// claimed it within the TTL, so the pin was cleared. Unlike the transient
|
|
60486
|
+
// skips, this does NOT self-resolve into the intended outcome: the delta is
|
|
60487
|
+
// now claimable by ANY compatible session, i.e. it will not reach the session
|
|
60488
|
+
// it was written for. Previously this only bumped a metrics counter and wrote
|
|
60489
|
+
// a log, so the coordinator kept waiting for a delivery that could no longer
|
|
60490
|
+
// happen — measured live as 74min of silence while a worker continued on a
|
|
60491
|
+
// premise the delta was meant to correct. The coordinator must know its
|
|
60492
|
+
// addressed message lost its address.
|
|
60493
|
+
"target_session_pin_expired",
|
|
60494
|
+
// SLOT MODEL GUARD (absent): no slot on the node declares the task's model.
|
|
60495
|
+
// Permanent — no amount of waiting produces a slot, so the coordinator must
|
|
60496
|
+
// re-drive (adjust difficulty, target another node, ask the owner). Its
|
|
60497
|
+
// busy counterpart SLOT_MODEL_BUSY_SKIP_REASON is deliberately NOT listed:
|
|
60498
|
+
// that one clears on its own when the slot goes idle.
|
|
60499
|
+
SLOT_MODEL_ABSENT_SKIP_REASON
|
|
60500
|
+
// QUOTA GATE: 'provider_quota_session_low' / 'provider_quota_weekly_low' are
|
|
60501
|
+
// deliberately NOT listed either — an exhausted quota window RESETS, so the
|
|
60502
|
+
// block self-resolves exactly like the slot-busy case; the task waits in the
|
|
60503
|
+
// queue and the coordinator is not paged (mesh-quota-routing.ts).
|
|
60504
|
+
];
|
|
60505
|
+
TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON = "target_node_bootstrap_pending";
|
|
60506
|
+
lastActionableSkipNotified = /* @__PURE__ */ new Map();
|
|
60507
|
+
DEAD_TARGET_GRACE_MS = 6e4;
|
|
60508
|
+
TARGET_SESSION_PIN_TTL_MS = 15 * 6e4;
|
|
60003
60509
|
}
|
|
60004
60510
|
});
|
|
60005
|
-
function
|
|
60006
|
-
|
|
60007
|
-
return holder ? `${DUPLICATE_MESH_DISPATCH_CODE}:${holder}` : DUPLICATE_MESH_DISPATCH_CODE;
|
|
60511
|
+
function activeWriteAssignedCount(meshId) {
|
|
60512
|
+
return getQueue(meshId, { status: ["assigned"] }).filter((task) => !isTaskReadonly(task)).length;
|
|
60008
60513
|
}
|
|
60009
|
-
function
|
|
60010
|
-
|
|
60011
|
-
|
|
60012
|
-
|
|
60013
|
-
|
|
60014
|
-
|
|
60514
|
+
function activeReadonlyAssignedCount(meshId) {
|
|
60515
|
+
return getQueue(meshId, { status: ["assigned"] }).filter(isTaskReadonly).length;
|
|
60516
|
+
}
|
|
60517
|
+
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
60518
|
+
return getQueue(meshId, { status: ["assigned"] }).some((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId));
|
|
60519
|
+
}
|
|
60520
|
+
function nodeActiveLoad(meshId, nodeId) {
|
|
60521
|
+
return MeshRuntimeStore.getInstance().nodeActiveAssignmentCount(meshId, nodeId);
|
|
60522
|
+
}
|
|
60523
|
+
function meshHasExplicitSlots(mesh) {
|
|
60524
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60525
|
+
return nodes.some((n) => normalizeNodeCapabilitySlots(n?.policy?.slots).length > 0);
|
|
60526
|
+
}
|
|
60527
|
+
function resolveSchedulingStrategy(mesh) {
|
|
60528
|
+
const raw = mesh?.policy?.schedulingStrategy;
|
|
60529
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
60530
|
+
return normalizeMeshSchedulingStrategy(raw);
|
|
60015
60531
|
}
|
|
60016
|
-
|
|
60017
|
-
|
|
60018
|
-
|
|
60019
|
-
|
|
60020
|
-
|
|
60532
|
+
return meshHasExplicitSlots(mesh) ? "fitness" : normalizeMeshSchedulingStrategy(void 0);
|
|
60533
|
+
}
|
|
60534
|
+
function buildSchedulingPool(localCandidates, remoteCandidates) {
|
|
60535
|
+
const pool = [...localCandidates, ...remoteCandidates].map((c) => ({
|
|
60536
|
+
...c,
|
|
60537
|
+
nodeId: normalizeMeshNodeId(c.node) ?? c.nodeId
|
|
60538
|
+
}));
|
|
60539
|
+
const uniqueNodes = [...new Set(pool.map((c) => c.nodeId))].map((nodeId, index) => ({
|
|
60540
|
+
nodeId,
|
|
60541
|
+
node: pool.find((c) => meshNodeIdMatches({ id: c.nodeId }, nodeId))?.node,
|
|
60542
|
+
index
|
|
60543
|
+
}));
|
|
60544
|
+
return { pool, uniqueNodes };
|
|
60545
|
+
}
|
|
60546
|
+
function scoreSlotForTask(slot, task, quotaBonus = 0) {
|
|
60547
|
+
let score = 1;
|
|
60548
|
+
const diff = isMeshTaskDifficulty(task.difficulty) ? task.difficulty : void 0;
|
|
60549
|
+
if (diff) {
|
|
60550
|
+
if (slot.difficulty?.length) {
|
|
60551
|
+
score += slot.difficulty.includes(diff) ? 100 : 0;
|
|
60552
|
+
} else {
|
|
60553
|
+
score += 20;
|
|
60554
|
+
}
|
|
60021
60555
|
}
|
|
60022
|
-
|
|
60556
|
+
const req = task.requiredTags?.filter((t) => !!t) ?? [];
|
|
60557
|
+
if (req.length) {
|
|
60558
|
+
const cap = new Set(slot.capability ?? []);
|
|
60559
|
+
const covered = req.every((t) => cap.has(t));
|
|
60560
|
+
score += covered ? 30 : 0;
|
|
60561
|
+
}
|
|
60562
|
+
score += quotaBonus;
|
|
60563
|
+
return score;
|
|
60023
60564
|
}
|
|
60024
|
-
|
|
60025
|
-
|
|
60026
|
-
|
|
60027
|
-
|
|
60028
|
-
|
|
60029
|
-
|
|
60030
|
-
|
|
60031
|
-
|
|
60032
|
-
|
|
60033
|
-
|
|
60034
|
-
|
|
60035
|
-
|
|
60036
|
-
|
|
60565
|
+
function orderSlotsForProviderSelection(slots, meshId, nodeId, node, task, quotaBonusByProvider) {
|
|
60566
|
+
return [...slots].sort((a, b) => {
|
|
60567
|
+
const capDelta = Number(slotHasCapacity(meshId, nodeId, node, b)) - Number(slotHasCapacity(meshId, nodeId, node, a));
|
|
60568
|
+
if (capDelta !== 0) return capDelta;
|
|
60569
|
+
return scoreSlotForTask(b, task, quotaBonusByProvider?.[b.provider] ?? 0) - scoreSlotForTask(a, task, quotaBonusByProvider?.[a.provider] ?? 0);
|
|
60570
|
+
});
|
|
60571
|
+
}
|
|
60572
|
+
function bestSlotForTask(node, task, meshId, quotaBonusByProvider) {
|
|
60573
|
+
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
60574
|
+
if (!slots.length) return null;
|
|
60575
|
+
let best = null;
|
|
60576
|
+
for (const slot of slots) {
|
|
60577
|
+
const score = scoreSlotForTask(slot, task, quotaBonusByProvider?.[slot.provider] ?? 0);
|
|
60578
|
+
if (!best || score > best.score) best = { slot, score };
|
|
60579
|
+
}
|
|
60580
|
+
return best;
|
|
60581
|
+
}
|
|
60582
|
+
function nodeFitnessForTask(node, task, meshId, quotaBonusByProvider) {
|
|
60583
|
+
return bestSlotForTask(node, task, meshId, quotaBonusByProvider)?.score ?? 0;
|
|
60584
|
+
}
|
|
60585
|
+
function slotCoversTaskDifficulty(slot, difficulty) {
|
|
60586
|
+
if (!slot) return false;
|
|
60587
|
+
if (!isMeshTaskDifficulty(difficulty)) return false;
|
|
60588
|
+
if (!slot.difficulty?.length) return true;
|
|
60589
|
+
return slot.difficulty.includes(difficulty);
|
|
60590
|
+
}
|
|
60591
|
+
function resolveLaunchAxis(taskValue, taskSource, slotValue, slotCoversDifficulty) {
|
|
60592
|
+
const stamped = typeof taskValue === "string" && taskValue.trim() ? taskValue.trim() : void 0;
|
|
60593
|
+
if (!stamped) return slotValue;
|
|
60594
|
+
if (taskSource !== "preset") return stamped;
|
|
60595
|
+
return slotCoversDifficulty && slotValue ? slotValue : stamped;
|
|
60596
|
+
}
|
|
60597
|
+
function orderEligibleNodes(meshId, strategy, nodes, opts) {
|
|
60598
|
+
if (strategy === "first_eligible" || nodes.length <= 1) {
|
|
60599
|
+
return nodes;
|
|
60600
|
+
}
|
|
60601
|
+
if (strategy === "fitness" && opts?.task) {
|
|
60602
|
+
const task = opts.task;
|
|
60603
|
+
const bonusCache = /* @__PURE__ */ new Map();
|
|
60604
|
+
const bonusFor = (c) => {
|
|
60605
|
+
let bonus = bonusCache.get(c.nodeId);
|
|
60606
|
+
if (!bonus) {
|
|
60607
|
+
bonus = quotaSpreadBonusByProvider(c.node, opts.quotaRouting);
|
|
60608
|
+
bonusCache.set(c.nodeId, bonus);
|
|
60037
60609
|
}
|
|
60610
|
+
return bonus;
|
|
60038
60611
|
};
|
|
60612
|
+
return [...nodes].sort((a, b) => {
|
|
60613
|
+
const fitDelta = nodeFitnessForTask(b.node, task, meshId, bonusFor(b)) - nodeFitnessForTask(a.node, task, meshId, bonusFor(a));
|
|
60614
|
+
if (fitDelta !== 0) return fitDelta;
|
|
60615
|
+
const prioDelta = resolveNodeSchedulingPriority(b.node?.policy) - resolveNodeSchedulingPriority(a.node?.policy);
|
|
60616
|
+
if (prioDelta !== 0) return prioDelta;
|
|
60617
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
60618
|
+
if (loadDelta !== 0) return loadDelta;
|
|
60619
|
+
return a.index - b.index;
|
|
60620
|
+
});
|
|
60039
60621
|
}
|
|
60040
|
-
|
|
60041
|
-
|
|
60042
|
-
|
|
60622
|
+
const priorityOf = (n) => resolveNodeSchedulingPriority(n.node?.policy);
|
|
60623
|
+
let rotation = 0;
|
|
60624
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
60625
|
+
const cursor = opts?.bumpCursor ? MeshRuntimeStore.getInstance().bumpSchedulerCursor(meshId) : MeshRuntimeStore.getInstance().getSchedulerCursor(meshId);
|
|
60626
|
+
rotation = (cursor % nodes.length + nodes.length) % nodes.length;
|
|
60627
|
+
}
|
|
60628
|
+
const rotationRank = (index) => (index - rotation + nodes.length) % nodes.length;
|
|
60629
|
+
return [...nodes].sort((a, b) => {
|
|
60630
|
+
const prioDelta = priorityOf(b) - priorityOf(a);
|
|
60631
|
+
if (prioDelta !== 0) return prioDelta;
|
|
60632
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
60633
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
60634
|
+
if (loadDelta !== 0) return loadDelta;
|
|
60635
|
+
}
|
|
60636
|
+
return rotationRank(a.index) - rotationRank(b.index);
|
|
60637
|
+
});
|
|
60043
60638
|
}
|
|
60044
|
-
function
|
|
60045
|
-
|
|
60046
|
-
if (!key2) return false;
|
|
60047
|
-
if (autoFastForwardWorkspaceLease.has(key2)) return false;
|
|
60048
|
-
autoFastForwardWorkspaceLease.add(key2);
|
|
60049
|
-
return true;
|
|
60639
|
+
function activeProviderAssignedCount(meshId, nodeId, providerType) {
|
|
60640
|
+
return getQueue(meshId, { status: ["assigned"] }).filter((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId) && task.assignedProviderType === providerType).length;
|
|
60050
60641
|
}
|
|
60051
|
-
function
|
|
60052
|
-
|
|
60053
|
-
|
|
60642
|
+
function activeSlotAssignedCount(meshId, nodeId, providerType, slot) {
|
|
60643
|
+
return getQueue(meshId, { status: ["assigned"] }).filter((task) => {
|
|
60644
|
+
if (!daemonIdsEquivalent(task.assignedNodeId, nodeId)) return false;
|
|
60645
|
+
if (task.assignedProviderType !== providerType) return false;
|
|
60646
|
+
const assignedModel = task.assignedModel;
|
|
60647
|
+
if (typeof assignedModel !== "string" || !assignedModel.trim()) return true;
|
|
60648
|
+
return isModelAllowedBySlot(assignedModel, slot);
|
|
60649
|
+
}).length;
|
|
60054
60650
|
}
|
|
60055
|
-
function
|
|
60056
|
-
const
|
|
60057
|
-
return
|
|
60651
|
+
function slotCapacityRemaining(meshId, nodeId, node, slot) {
|
|
60652
|
+
const providerType = typeof slot.provider === "string" ? slot.provider.trim() : "";
|
|
60653
|
+
if (!providerType) return { available: false };
|
|
60654
|
+
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
60655
|
+
const slotCap = resolveSlotMaxParallel(slots, providerType, slot.model, isModelAllowedBySlot);
|
|
60656
|
+
if (slotCap !== void 0 && activeSlotAssignedCount(meshId, nodeId, providerType, slot) >= slotCap) {
|
|
60657
|
+
return { available: false, slotCap };
|
|
60658
|
+
}
|
|
60659
|
+
const providerCap = resolveProviderMaxParallel(slots, providerType);
|
|
60660
|
+
if (providerCap !== void 0 && activeProviderAssignedCount(meshId, nodeId, providerType) >= providerCap) {
|
|
60661
|
+
return { available: false, slotCap, providerCap };
|
|
60662
|
+
}
|
|
60663
|
+
return { available: true, slotCap, providerCap };
|
|
60058
60664
|
}
|
|
60059
|
-
function
|
|
60060
|
-
|
|
60061
|
-
|
|
60062
|
-
|
|
60665
|
+
function slotHasCapacity(meshId, nodeId, node, slot) {
|
|
60666
|
+
return slotCapacityRemaining(meshId, nodeId, node, slot).available;
|
|
60667
|
+
}
|
|
60668
|
+
function sessionHasActiveAssignment(meshId, sessionId) {
|
|
60669
|
+
if (getQueue(meshId, { status: ["assigned"] }).some((task) => sessionIdsEquivalent(task.assignedSessionId, sessionId))) {
|
|
60670
|
+
return true;
|
|
60671
|
+
}
|
|
60672
|
+
try {
|
|
60673
|
+
if (getActiveDirectDispatches(meshId).some((d) => sessionIdsEquivalent(d.sessionId, sessionId))) return true;
|
|
60674
|
+
if (hasUnterminalDirectDispatchLedgerEntry(meshId, sessionId)) return true;
|
|
60675
|
+
} catch {
|
|
60676
|
+
}
|
|
60677
|
+
return false;
|
|
60678
|
+
}
|
|
60679
|
+
var init_mesh_scheduling_fitness = __esm2({
|
|
60680
|
+
"src/mesh/mesh-scheduling-fitness.ts"() {
|
|
60681
|
+
"use strict";
|
|
60682
|
+
init_mesh_work_queue();
|
|
60683
|
+
init_mesh_runtime_store();
|
|
60684
|
+
init_mesh_work_queue();
|
|
60685
|
+
init_repo_mesh_types();
|
|
60686
|
+
init_dist();
|
|
60687
|
+
init_mesh_node_slots();
|
|
60688
|
+
init_mesh_quota_routing();
|
|
60689
|
+
init_mesh_events_stale();
|
|
60690
|
+
init_slot_model_enforcement();
|
|
60691
|
+
}
|
|
60692
|
+
});
|
|
60693
|
+
function localCoordinatorDaemonId() {
|
|
60694
|
+
return canonicalDaemonId(readNonEmptyString(loadConfig2().machineId));
|
|
60063
60695
|
}
|
|
60064
60696
|
function loadRepoConfigForNode(node) {
|
|
60065
60697
|
const workspace = typeof node?.workspace === "string" && node.workspace.trim() ? node.workspace.trim() : "";
|
|
@@ -60604,143 +61236,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60604
61236
|
}
|
|
60605
61237
|
return out;
|
|
60606
61238
|
}
|
|
60607
|
-
function isActionableSkipReason(reason) {
|
|
60608
|
-
if (!reason) return false;
|
|
60609
|
-
return ACTIONABLE_SKIP_REASON_PREFIXES.some((prefix) => reason === prefix || reason.startsWith(prefix));
|
|
60610
|
-
}
|
|
60611
|
-
function isTargetNodeTransientlyUnresolved(mesh, task) {
|
|
60612
|
-
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
60613
|
-
if (!targetNodeId) return false;
|
|
60614
|
-
const node = Array.isArray(mesh?.nodes) ? mesh.nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
60615
|
-
if (node && node.worktreeBootstrap?.status === "running" && !isWorktreeBootstrapStaleRunning(node)) {
|
|
60616
|
-
return true;
|
|
60617
|
-
}
|
|
60618
|
-
return isWithinCloneBootstrapGrace(targetNodeId);
|
|
60619
|
-
}
|
|
60620
|
-
function targetPinAgeMs(task, nowMs = Date.now()) {
|
|
60621
|
-
const anchorMs = Date.parse(task.requeuedAt || task.createdAt || "");
|
|
60622
|
-
return Number.isFinite(anchorMs) ? nowMs - anchorMs : null;
|
|
60623
|
-
}
|
|
60624
|
-
function resolveDeadTargetVerdict(components, meshId, mesh, task) {
|
|
60625
|
-
const NOT_DEAD = { dead: false, nodeDead: false, reason: "" };
|
|
60626
|
-
const targetSessionId = readNonEmptyString(task.targetSessionId);
|
|
60627
|
-
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
60628
|
-
if (!targetSessionId && !targetNodeId) return NOT_DEAD;
|
|
60629
|
-
const lastUpdateMs = Date.parse(task.updatedAt || task.createdAt || "");
|
|
60630
|
-
if (Number.isFinite(lastUpdateMs) && Date.now() - lastUpdateMs < DEAD_TARGET_GRACE_MS) return NOT_DEAD;
|
|
60631
|
-
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60632
|
-
if (targetNodeId) {
|
|
60633
|
-
const nodePresent = nodes.some((n) => meshNodeIdMatches(n, targetNodeId));
|
|
60634
|
-
if (!nodePresent) {
|
|
60635
|
-
if (isTargetNodeTransientlyUnresolved(mesh, task)) return NOT_DEAD;
|
|
60636
|
-
return { dead: true, nodeDead: true, reason: "dead_target_node_absent" };
|
|
60637
|
-
}
|
|
60638
|
-
}
|
|
60639
|
-
if (targetSessionId) {
|
|
60640
|
-
const node = targetNodeId ? nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
60641
|
-
const nodeIsLocal = node ? isLocalAutoLaunchNode(node) : true;
|
|
60642
|
-
if (nodeIsLocal) {
|
|
60643
|
-
const verdict = resolveSessionBusyVerdict(components, targetSessionId);
|
|
60644
|
-
if (verdict === "UNKNOWN") {
|
|
60645
|
-
return { dead: true, nodeDead: false, reason: "dead_target_session_absent" };
|
|
60646
|
-
}
|
|
60647
|
-
}
|
|
60648
|
-
}
|
|
60649
|
-
return NOT_DEAD;
|
|
60650
|
-
}
|
|
60651
|
-
function retractActionableSkipIfPreviouslyNotified(meshId, taskId) {
|
|
60652
|
-
const dedupKey = `${meshId}:${taskId}`;
|
|
60653
|
-
if (!lastActionableSkipNotified.delete(dedupKey)) return;
|
|
60654
|
-
try {
|
|
60655
|
-
const coordinatorDaemonId = readNonEmptyString(loadConfig2().machineId) || void 0;
|
|
60656
|
-
const removed = retractPendingDispatchBlockedEvent(meshId, taskId, coordinatorDaemonId);
|
|
60657
|
-
if (removed > 0) {
|
|
60658
|
-
LOG2.info("MeshQueue", `Retracted ${removed} stale dispatch-blocked event(s) for task ${taskId} (mesh ${meshId}) \u2014 its blocker resolved`);
|
|
60659
|
-
}
|
|
60660
|
-
} catch (e) {
|
|
60661
|
-
LOG2.warn("MeshQueue", `Failed to retract stale dispatch-blocked event for task ${taskId} (mesh ${meshId}): ${e?.message || e}`);
|
|
60662
|
-
}
|
|
60663
|
-
}
|
|
60664
|
-
function actionableSkipGuidance(reason) {
|
|
60665
|
-
if (reason === "target_node_id_unmatched") return {
|
|
60666
|
-
summary: "it is pinned to a target node id that matches no node in the mesh (the node may have been removed, or its id form does not resolve)",
|
|
60667
|
-
nextAction: "Verify the target node still exists with mesh_status, then re-enqueue without the node pin or with a valid node id (or re-clone the node)."
|
|
60668
|
-
};
|
|
60669
|
-
if (reason === "no_node_satisfies_required_tags") return {
|
|
60670
|
-
summary: "no node in the mesh can satisfy the task's required capability tags",
|
|
60671
|
-
nextAction: "Relax the task's requiredTags, or add/launch a node whose provider produces the required capabilities."
|
|
60672
|
-
};
|
|
60673
|
-
if (reason === "mesh_convergence_target_is_worktree") return {
|
|
60674
|
-
summary: "it is a convergence task (base-only: merge \u2192 push \u2192 cleanup) but every candidate node is a worktree clone",
|
|
60675
|
-
nextAction: "Dispatch the convergence task to the base node, or run the deterministic fast-forward path (mesh_fast_forward_node / mesh_refine_node) instead."
|
|
60676
|
-
};
|
|
60677
|
-
if (reason.startsWith("remote_auto_launch")) return {
|
|
60678
|
-
summary: "the target node is on a remote daemon this coordinator cannot auto-launch a session on (no dispatch transport, or no coordinator daemon id to stamp)",
|
|
60679
|
-
nextAction: "Launch a session on that node yourself with mesh_launch_session, or ensure the remote daemon is connected over P2P."
|
|
60680
|
-
};
|
|
60681
|
-
if (reason.startsWith("provider") || reason === "missing_provider_priority") return {
|
|
60682
|
-
summary: "the node has no usable provider for this task (provider priority missing/unusable, or the provider loader is unavailable)",
|
|
60683
|
-
nextAction: "Check the node's providerPriority policy and that the required CLI/ACP provider is installed and enabled on that machine."
|
|
60684
|
-
};
|
|
60685
|
-
if (reason === "dirty_workspace") return {
|
|
60686
|
-
summary: "the node's workspace is dirty, so auto-launch is blocked to avoid clobbering uncommitted changes",
|
|
60687
|
-
nextAction: "Clean or commit the node's working tree (or fast-forward it); the task will then auto-assign."
|
|
60688
|
-
};
|
|
60689
|
-
if (reason === "target_session_pin_expired") return {
|
|
60690
|
-
summary: "it was pinned to a specific session (a follow-up/delta for work already in flight) that never claimed it within the pin TTL, so the pin was cleared and the message will NOT reach the session it was addressed to",
|
|
60691
|
-
nextAction: "Assume the addressed session never received this delta and is still acting on its previous instructions. Re-send it to that session once it is idle (or re-target it), and re-check the work it produced in the meantime."
|
|
60692
|
-
};
|
|
60693
|
-
if (reason === SLOT_MODEL_ABSENT_SKIP_REASON) return {
|
|
60694
|
-
summary: "no capability slot on the node declares the model this task resolved to (its difficulty\u2192brain preset picked a model the node was never configured to run)",
|
|
60695
|
-
nextAction: "Re-enqueue with a difficulty/model the node's slots declare, target a node that declares this model, or add a slot for it. The task is NOT run on a substitute model \u2014 an undeclared model is never launched."
|
|
60696
|
-
};
|
|
60697
|
-
return {
|
|
60698
|
-
summary: `it cannot be dispatched (${reason})`,
|
|
60699
|
-
nextAction: "Inspect the node/mesh state with mesh_status and resolve the blocker, or re-enqueue the task."
|
|
60700
|
-
};
|
|
60701
|
-
}
|
|
60702
|
-
function notifyCoordinatorOfActionableSkip(meshId, taskId, reason, nodeId) {
|
|
60703
|
-
if (!isActionableSkipReason(reason)) return;
|
|
60704
|
-
if (reason === "target_node_id_unmatched" && isWithinCloneBootstrapGrace(readNonEmptyString(nodeId))) return;
|
|
60705
|
-
const dedupKey = `${meshId}:${taskId}`;
|
|
60706
|
-
if (lastActionableSkipNotified.get(dedupKey) === reason) return;
|
|
60707
|
-
lastActionableSkipNotified.set(dedupKey, reason);
|
|
60708
|
-
if (lastActionableSkipNotified.size > AUTO_LAUNCH_LEDGER_DEDUP_MAX) {
|
|
60709
|
-
const oldest = lastActionableSkipNotified.keys().next().value;
|
|
60710
|
-
if (oldest !== void 0) lastActionableSkipNotified.delete(oldest);
|
|
60711
|
-
}
|
|
60712
|
-
let task;
|
|
60713
|
-
try {
|
|
60714
|
-
task = getQueue(meshId).find((t) => t.id === taskId);
|
|
60715
|
-
} catch {
|
|
60716
|
-
}
|
|
60717
|
-
const targetCoordinatorDaemonId = readNonEmptyString(loadConfig2().machineId);
|
|
60718
|
-
const targetCoordinatorSessionId = readNonEmptyString(task?.sourceCoordinatorSessionId);
|
|
60719
|
-
const nodeLabel = readNonEmptyString(nodeId) || readNonEmptyString(task?.targetNodeId);
|
|
60720
|
-
const { summary, nextAction } = actionableSkipGuidance(reason);
|
|
60721
|
-
const coordinatorMessage = `[System] A queued mesh task${nodeLabel ? ` for node ${nodeLabel}` : ""} is not being dispatched because ${summary}. ${nextAction} This is an actionable blocker \u2014 it will NOT clear on its own; the task stays pending until you resolve it.`;
|
|
60722
|
-
try {
|
|
60723
|
-
queuePendingMeshCoordinatorEvent({
|
|
60724
|
-
event: "mesh:dispatch_blocked",
|
|
60725
|
-
meshId,
|
|
60726
|
-
nodeLabel: nodeLabel || meshId,
|
|
60727
|
-
...nodeLabel ? { nodeId: nodeLabel } : {},
|
|
60728
|
-
metadataEvent: {
|
|
60729
|
-
source: "mesh_queue_dispatch_skip",
|
|
60730
|
-
taskId,
|
|
60731
|
-
reason,
|
|
60732
|
-
...nodeLabel ? { nodeId: nodeLabel } : {},
|
|
60733
|
-
coordinatorMessage
|
|
60734
|
-
},
|
|
60735
|
-
coordinatorMessage,
|
|
60736
|
-
queuedAt: Date.now(),
|
|
60737
|
-
...targetCoordinatorDaemonId ? { targetCoordinatorDaemonId } : {},
|
|
60738
|
-
...targetCoordinatorSessionId ? { targetCoordinatorSessionId } : {}
|
|
60739
|
-
});
|
|
60740
|
-
} catch (e) {
|
|
60741
|
-
LOG2.warn("MeshQueue", `Failed to surface actionable dispatch-skip (${reason}) for task ${taskId}: ${e?.message || e}`);
|
|
60742
|
-
}
|
|
60743
|
-
}
|
|
60744
61239
|
function sweepExpiredCooldowns() {
|
|
60745
61240
|
const now = Date.now();
|
|
60746
61241
|
for (const [key2, until] of autoLaunchCooldownUntil) {
|
|
@@ -60760,28 +61255,11 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60760
61255
|
function isTerminalSessionStatus(status) {
|
|
60761
61256
|
return ["stopped", "failed", "terminated", "exited", "closed"].includes(status);
|
|
60762
61257
|
}
|
|
60763
|
-
function
|
|
61258
|
+
function isIdleSessionState2(state) {
|
|
60764
61259
|
const status = readNonEmptyString(state?.status).toLowerCase();
|
|
60765
61260
|
if (isTerminalSessionStatus(status)) return false;
|
|
60766
61261
|
return status === "idle" || state?.activeChat?.status === "waiting_input";
|
|
60767
61262
|
}
|
|
60768
|
-
function isDirtyNode(node) {
|
|
60769
|
-
return node?.health === "dirty" || node?.git?.dirty === true;
|
|
60770
|
-
}
|
|
60771
|
-
function resolveAutoFastForwardPolicy(mesh) {
|
|
60772
|
-
const record2 = mesh?.policy?.autoFastForward && typeof mesh.policy.autoFastForward === "object" && !Array.isArray(mesh.policy.autoFastForward) ? mesh.policy.autoFastForward : {};
|
|
60773
|
-
const maxBehind = Number(record2.maxBehind);
|
|
60774
|
-
return {
|
|
60775
|
-
enabled: record2.enabled !== false,
|
|
60776
|
-
...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
|
|
60777
|
-
requireCleanSubmodules: record2.requireCleanSubmodules !== false,
|
|
60778
|
-
// Strict opt-in: absent/false → self-only (historical behavior). Only an
|
|
60779
|
-
// explicit `true` extends auto ff to remote owning-daemon nodes.
|
|
60780
|
-
remoteNodes: record2.remoteNodes === true,
|
|
60781
|
-
// Absent/anything-but-continuous → 'idle' (historical idle-edge-only detection).
|
|
60782
|
-
mode: record2.mode === "continuous" ? "continuous" : "idle"
|
|
60783
|
-
};
|
|
60784
|
-
}
|
|
60785
61263
|
function sessionStateLooksActive(state) {
|
|
60786
61264
|
const status = readNonEmptyString(state?.status).toLowerCase();
|
|
60787
61265
|
const chatStatus = readNonEmptyString(state?.activeChat?.status).toLowerCase();
|
|
@@ -60797,7 +61275,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60797
61275
|
const instNodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
60798
61276
|
if (!daemonIdsEquivalent(instNodeId, nodeId)) return false;
|
|
60799
61277
|
const sessionId = readNonEmptyString(state.instanceId);
|
|
60800
|
-
if (currentSessionId && sessionIdsEquivalent(sessionId, currentSessionId) &&
|
|
61278
|
+
if (currentSessionId && sessionIdsEquivalent(sessionId, currentSessionId) && isIdleSessionState2(state)) return false;
|
|
60801
61279
|
return sessionStateLooksActive(state);
|
|
60802
61280
|
});
|
|
60803
61281
|
}
|
|
@@ -60832,174 +61310,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60832
61310
|
if (!coordinatorDaemonId) return { mode: "skip", reason: "remote_auto_launch_no_coordinator_daemon_id" };
|
|
60833
61311
|
return { mode: "remote", daemonId, coordinatorDaemonId };
|
|
60834
61312
|
}
|
|
60835
|
-
function activeWriteAssignedCount(meshId) {
|
|
60836
|
-
return getQueue(meshId, { status: ["assigned"] }).filter((task) => !isTaskReadonly(task)).length;
|
|
60837
|
-
}
|
|
60838
|
-
function activeReadonlyAssignedCount(meshId) {
|
|
60839
|
-
return getQueue(meshId, { status: ["assigned"] }).filter(isTaskReadonly).length;
|
|
60840
|
-
}
|
|
60841
|
-
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
60842
|
-
return getQueue(meshId, { status: ["assigned"] }).some((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId));
|
|
60843
|
-
}
|
|
60844
|
-
function nodeActiveLoad(meshId, nodeId) {
|
|
60845
|
-
return MeshRuntimeStore.getInstance().nodeActiveAssignmentCount(meshId, nodeId);
|
|
60846
|
-
}
|
|
60847
|
-
function meshHasExplicitSlots(mesh) {
|
|
60848
|
-
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60849
|
-
return nodes.some((n) => normalizeNodeCapabilitySlots(n?.policy?.slots).length > 0);
|
|
60850
|
-
}
|
|
60851
|
-
function resolveSchedulingStrategy(mesh) {
|
|
60852
|
-
const raw = mesh?.policy?.schedulingStrategy;
|
|
60853
|
-
if (typeof raw === "string" && raw.trim()) {
|
|
60854
|
-
return normalizeMeshSchedulingStrategy(raw);
|
|
60855
|
-
}
|
|
60856
|
-
return meshHasExplicitSlots(mesh) ? "fitness" : normalizeMeshSchedulingStrategy(void 0);
|
|
60857
|
-
}
|
|
60858
|
-
function buildSchedulingPool(localCandidates, remoteCandidates) {
|
|
60859
|
-
const pool = [...localCandidates, ...remoteCandidates].map((c) => ({
|
|
60860
|
-
...c,
|
|
60861
|
-
nodeId: normalizeMeshNodeId(c.node) ?? c.nodeId
|
|
60862
|
-
}));
|
|
60863
|
-
const uniqueNodes = [...new Set(pool.map((c) => c.nodeId))].map((nodeId, index) => ({
|
|
60864
|
-
nodeId,
|
|
60865
|
-
node: pool.find((c) => meshNodeIdMatches({ id: c.nodeId }, nodeId))?.node,
|
|
60866
|
-
index
|
|
60867
|
-
}));
|
|
60868
|
-
return { pool, uniqueNodes };
|
|
60869
|
-
}
|
|
60870
|
-
function scoreSlotForTask(slot, task, quotaBonus = 0) {
|
|
60871
|
-
let score = 1;
|
|
60872
|
-
const diff = isMeshTaskDifficulty(task.difficulty) ? task.difficulty : void 0;
|
|
60873
|
-
if (diff) {
|
|
60874
|
-
if (slot.difficulty?.length) {
|
|
60875
|
-
score += slot.difficulty.includes(diff) ? 100 : 0;
|
|
60876
|
-
} else {
|
|
60877
|
-
score += 20;
|
|
60878
|
-
}
|
|
60879
|
-
}
|
|
60880
|
-
const req = task.requiredTags?.filter((t) => !!t) ?? [];
|
|
60881
|
-
if (req.length) {
|
|
60882
|
-
const cap = new Set(slot.capability ?? []);
|
|
60883
|
-
const covered = req.every((t) => cap.has(t));
|
|
60884
|
-
score += covered ? 30 : 0;
|
|
60885
|
-
}
|
|
60886
|
-
score += quotaBonus;
|
|
60887
|
-
return score;
|
|
60888
|
-
}
|
|
60889
|
-
function orderSlotsForProviderSelection(slots, meshId, nodeId, node, task, quotaBonusByProvider) {
|
|
60890
|
-
return [...slots].sort((a, b) => {
|
|
60891
|
-
const capDelta = Number(slotHasCapacity(meshId, nodeId, node, b)) - Number(slotHasCapacity(meshId, nodeId, node, a));
|
|
60892
|
-
if (capDelta !== 0) return capDelta;
|
|
60893
|
-
return scoreSlotForTask(b, task, quotaBonusByProvider?.[b.provider] ?? 0) - scoreSlotForTask(a, task, quotaBonusByProvider?.[a.provider] ?? 0);
|
|
60894
|
-
});
|
|
60895
|
-
}
|
|
60896
|
-
function bestSlotForTask(node, task, meshId, quotaBonusByProvider) {
|
|
60897
|
-
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
60898
|
-
if (!slots.length) return null;
|
|
60899
|
-
let best = null;
|
|
60900
|
-
for (const slot of slots) {
|
|
60901
|
-
const score = scoreSlotForTask(slot, task, quotaBonusByProvider?.[slot.provider] ?? 0);
|
|
60902
|
-
if (!best || score > best.score) best = { slot, score };
|
|
60903
|
-
}
|
|
60904
|
-
return best;
|
|
60905
|
-
}
|
|
60906
|
-
function nodeFitnessForTask(node, task, meshId, quotaBonusByProvider) {
|
|
60907
|
-
return bestSlotForTask(node, task, meshId, quotaBonusByProvider)?.score ?? 0;
|
|
60908
|
-
}
|
|
60909
|
-
function slotCoversTaskDifficulty(slot, difficulty) {
|
|
60910
|
-
if (!slot) return false;
|
|
60911
|
-
if (!isMeshTaskDifficulty(difficulty)) return false;
|
|
60912
|
-
if (!slot.difficulty?.length) return true;
|
|
60913
|
-
return slot.difficulty.includes(difficulty);
|
|
60914
|
-
}
|
|
60915
|
-
function resolveLaunchAxis(taskValue, taskSource, slotValue, slotCoversDifficulty) {
|
|
60916
|
-
const stamped = typeof taskValue === "string" && taskValue.trim() ? taskValue.trim() : void 0;
|
|
60917
|
-
if (!stamped) return slotValue;
|
|
60918
|
-
if (taskSource !== "preset") return stamped;
|
|
60919
|
-
return slotCoversDifficulty && slotValue ? slotValue : stamped;
|
|
60920
|
-
}
|
|
60921
|
-
function orderEligibleNodes(meshId, strategy, nodes, opts) {
|
|
60922
|
-
if (strategy === "first_eligible" || nodes.length <= 1) {
|
|
60923
|
-
return nodes;
|
|
60924
|
-
}
|
|
60925
|
-
if (strategy === "fitness" && opts?.task) {
|
|
60926
|
-
const task = opts.task;
|
|
60927
|
-
const bonusCache = /* @__PURE__ */ new Map();
|
|
60928
|
-
const bonusFor = (c) => {
|
|
60929
|
-
let bonus = bonusCache.get(c.nodeId);
|
|
60930
|
-
if (!bonus) {
|
|
60931
|
-
bonus = quotaSpreadBonusByProvider(c.node, opts.quotaRouting);
|
|
60932
|
-
bonusCache.set(c.nodeId, bonus);
|
|
60933
|
-
}
|
|
60934
|
-
return bonus;
|
|
60935
|
-
};
|
|
60936
|
-
return [...nodes].sort((a, b) => {
|
|
60937
|
-
const fitDelta = nodeFitnessForTask(b.node, task, meshId, bonusFor(b)) - nodeFitnessForTask(a.node, task, meshId, bonusFor(a));
|
|
60938
|
-
if (fitDelta !== 0) return fitDelta;
|
|
60939
|
-
const prioDelta = resolveNodeSchedulingPriority(b.node?.policy) - resolveNodeSchedulingPriority(a.node?.policy);
|
|
60940
|
-
if (prioDelta !== 0) return prioDelta;
|
|
60941
|
-
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
60942
|
-
if (loadDelta !== 0) return loadDelta;
|
|
60943
|
-
return a.index - b.index;
|
|
60944
|
-
});
|
|
60945
|
-
}
|
|
60946
|
-
const priorityOf = (n) => resolveNodeSchedulingPriority(n.node?.policy);
|
|
60947
|
-
let rotation = 0;
|
|
60948
|
-
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
60949
|
-
const cursor = opts?.bumpCursor ? MeshRuntimeStore.getInstance().bumpSchedulerCursor(meshId) : MeshRuntimeStore.getInstance().getSchedulerCursor(meshId);
|
|
60950
|
-
rotation = (cursor % nodes.length + nodes.length) % nodes.length;
|
|
60951
|
-
}
|
|
60952
|
-
const rotationRank = (index) => (index - rotation + nodes.length) % nodes.length;
|
|
60953
|
-
return [...nodes].sort((a, b) => {
|
|
60954
|
-
const prioDelta = priorityOf(b) - priorityOf(a);
|
|
60955
|
-
if (prioDelta !== 0) return prioDelta;
|
|
60956
|
-
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
60957
|
-
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
60958
|
-
if (loadDelta !== 0) return loadDelta;
|
|
60959
|
-
}
|
|
60960
|
-
return rotationRank(a.index) - rotationRank(b.index);
|
|
60961
|
-
});
|
|
60962
|
-
}
|
|
60963
|
-
function activeProviderAssignedCount(meshId, nodeId, providerType) {
|
|
60964
|
-
return getQueue(meshId, { status: ["assigned"] }).filter((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId) && task.assignedProviderType === providerType).length;
|
|
60965
|
-
}
|
|
60966
|
-
function activeSlotAssignedCount(meshId, nodeId, providerType, slot) {
|
|
60967
|
-
return getQueue(meshId, { status: ["assigned"] }).filter((task) => {
|
|
60968
|
-
if (!daemonIdsEquivalent(task.assignedNodeId, nodeId)) return false;
|
|
60969
|
-
if (task.assignedProviderType !== providerType) return false;
|
|
60970
|
-
const assignedModel = task.assignedModel;
|
|
60971
|
-
if (typeof assignedModel !== "string" || !assignedModel.trim()) return true;
|
|
60972
|
-
return isModelAllowedBySlot(assignedModel, slot);
|
|
60973
|
-
}).length;
|
|
60974
|
-
}
|
|
60975
|
-
function slotCapacityRemaining(meshId, nodeId, node, slot) {
|
|
60976
|
-
const providerType = typeof slot.provider === "string" ? slot.provider.trim() : "";
|
|
60977
|
-
if (!providerType) return { available: false };
|
|
60978
|
-
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
60979
|
-
const slotCap = resolveSlotMaxParallel(slots, providerType, slot.model, isModelAllowedBySlot);
|
|
60980
|
-
if (slotCap !== void 0 && activeSlotAssignedCount(meshId, nodeId, providerType, slot) >= slotCap) {
|
|
60981
|
-
return { available: false, slotCap };
|
|
60982
|
-
}
|
|
60983
|
-
const providerCap = resolveProviderMaxParallel(slots, providerType);
|
|
60984
|
-
if (providerCap !== void 0 && activeProviderAssignedCount(meshId, nodeId, providerType) >= providerCap) {
|
|
60985
|
-
return { available: false, slotCap, providerCap };
|
|
60986
|
-
}
|
|
60987
|
-
return { available: true, slotCap, providerCap };
|
|
60988
|
-
}
|
|
60989
|
-
function slotHasCapacity(meshId, nodeId, node, slot) {
|
|
60990
|
-
return slotCapacityRemaining(meshId, nodeId, node, slot).available;
|
|
60991
|
-
}
|
|
60992
|
-
function sessionHasActiveAssignment(meshId, sessionId) {
|
|
60993
|
-
if (getQueue(meshId, { status: ["assigned"] }).some((task) => sessionIdsEquivalent(task.assignedSessionId, sessionId))) {
|
|
60994
|
-
return true;
|
|
60995
|
-
}
|
|
60996
|
-
try {
|
|
60997
|
-
if (getActiveDirectDispatches(meshId).some((d) => sessionIdsEquivalent(d.sessionId, sessionId))) return true;
|
|
60998
|
-
if (hasUnterminalDirectDispatchLedgerEntry(meshId, sessionId)) return true;
|
|
60999
|
-
} catch {
|
|
61000
|
-
}
|
|
61001
|
-
return false;
|
|
61002
|
-
}
|
|
61003
61313
|
function isSessionActivelyGenerating(components, sessionId) {
|
|
61004
61314
|
if (!sessionId) return false;
|
|
61005
61315
|
const state = components.instanceManager?.getInstance?.(sessionId)?.getState?.();
|
|
@@ -61594,7 +61904,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61594
61904
|
if (instMeshId !== meshId) continue;
|
|
61595
61905
|
const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
61596
61906
|
if (!nodeId) continue;
|
|
61597
|
-
if (!
|
|
61907
|
+
if (!isIdleSessionState2(state)) {
|
|
61598
61908
|
const status = readNonEmptyString(state.status).toLowerCase();
|
|
61599
61909
|
skippedSessions.push({
|
|
61600
61910
|
nodeId,
|
|
@@ -61701,209 +62011,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61701
62011
|
...pendingAfter > 0 && newlyAssignedTasks.length === 0 && localIdleSessionsChecked === 0 && remoteIdleSessionsChecked === 0 && !autoLaunchPending ? { noIdleMeshSessionAvailable: true } : {}
|
|
61702
62012
|
};
|
|
61703
62013
|
}
|
|
61704
|
-
function dryRunSatisfiesAutoFastForwardPolicy(dryRun, policy) {
|
|
61705
|
-
if (!dryRun || dryRun.code !== "fast_forward_available" || dryRun.allowed !== true) return false;
|
|
61706
|
-
const behind = Number(dryRun.current?.behind);
|
|
61707
|
-
if (!Number.isFinite(behind) || behind <= 0) return false;
|
|
61708
|
-
if (policy.maxBehind !== void 0 && behind > policy.maxBehind) return false;
|
|
61709
|
-
if (policy.requireCleanSubmodules) {
|
|
61710
|
-
const submodules = Array.isArray(dryRun.current?.submodules) ? dryRun.current.submodules : [];
|
|
61711
|
-
if (submodules.some((submodule) => submodule?.dirty || submodule?.outOfSync || submodule?.error)) return false;
|
|
61712
|
-
}
|
|
61713
|
-
return true;
|
|
61714
|
-
}
|
|
61715
|
-
function readNodeSubmoduleIgnorePaths(node) {
|
|
61716
|
-
return Array.isArray(node?.policy?.submoduleIgnorePaths) ? node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
61717
|
-
}
|
|
61718
|
-
function nodeIsAutoFastForwardEligible(components, meshId, nodeId, node, currentSessionId) {
|
|
61719
|
-
if (!node) return false;
|
|
61720
|
-
if (node.status === "disabled" || node.status === "removed") return false;
|
|
61721
|
-
if (node.readOnly === true || node.policy?.readOnly === true) return false;
|
|
61722
|
-
if (isWorktreeBootstrapStaleRunning(node)) return false;
|
|
61723
|
-
if (node.worktreeBootstrap?.status === "running") return false;
|
|
61724
|
-
if (nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId)) return false;
|
|
61725
|
-
return true;
|
|
61726
|
-
}
|
|
61727
|
-
function remoteNodeIsConnected(components, node) {
|
|
61728
|
-
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
61729
|
-
if (!daemonId) return false;
|
|
61730
|
-
const getPeerStatus = components.getMeshPeerConnectionStatus;
|
|
61731
|
-
if (getPeerStatus) {
|
|
61732
|
-
const snapshot = getPeerStatus(daemonId);
|
|
61733
|
-
return !!snapshot && String(snapshot.state) === "connected";
|
|
61734
|
-
}
|
|
61735
|
-
return readNonEmptyString(node?.connection?.state).toLowerCase() === "connected";
|
|
61736
|
-
}
|
|
61737
|
-
async function delegateRemoteAutoFastForward(components, args) {
|
|
61738
|
-
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
61739
|
-
if (!dispatchMeshCommand) return;
|
|
61740
|
-
if (!acquireAutoFastForwardLease(args.workspace)) return;
|
|
61741
|
-
const submoduleIgnorePaths = readNodeSubmoduleIgnorePaths(args.node);
|
|
61742
|
-
const mesh = getMeshWithCache(components, args.meshId);
|
|
61743
|
-
const baseArgs = {
|
|
61744
|
-
meshId: args.meshId,
|
|
61745
|
-
nodeId: args.nodeId,
|
|
61746
|
-
workspace: args.workspace,
|
|
61747
|
-
inlineMesh: mesh,
|
|
61748
|
-
...submoduleIgnorePaths ? { submoduleIgnorePaths } : {},
|
|
61749
|
-
trigger: args.trigger,
|
|
61750
|
-
// Preserve the pre-fix self-only semantics for submodules: the local idle path
|
|
61751
|
-
// never updated submodules (updateSubmodules:false), so the remote path matches.
|
|
61752
|
-
updateSubmodules: false
|
|
61753
|
-
};
|
|
61754
|
-
try {
|
|
61755
|
-
const remoteDry = await dispatchMeshCommand(args.daemonId, "fast_forward_mesh_node", {
|
|
61756
|
-
...baseArgs,
|
|
61757
|
-
execute: false,
|
|
61758
|
-
dryRun: true
|
|
61759
|
-
});
|
|
61760
|
-
if (!dryRunSatisfiesAutoFastForwardPolicy(remoteDry, args.policy)) return;
|
|
61761
|
-
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId)) return;
|
|
61762
|
-
const executed = await dispatchMeshCommand(args.daemonId, "fast_forward_mesh_node", {
|
|
61763
|
-
...baseArgs,
|
|
61764
|
-
execute: true,
|
|
61765
|
-
dryRun: false
|
|
61766
|
-
});
|
|
61767
|
-
if (executed?.executed === true) {
|
|
61768
|
-
LOG2.info("MeshFastForward", `Remote auto fast-forward executed for node ${args.nodeId} (daemon ${String(args.daemonId).slice(0, 12)}, trigger ${args.trigger})`);
|
|
61769
|
-
}
|
|
61770
|
-
} catch (e) {
|
|
61771
|
-
LOG2.warn("MeshFastForward", `Remote auto fast-forward delegation failed for ${args.nodeId}: ${e?.message || e}`);
|
|
61772
|
-
} finally {
|
|
61773
|
-
releaseAutoFastForwardLease(args.workspace);
|
|
61774
|
-
}
|
|
61775
|
-
}
|
|
61776
|
-
async function executeLocalAutoFastForward(args) {
|
|
61777
|
-
if (!acquireAutoFastForwardLease(args.workspace)) return;
|
|
61778
|
-
const submoduleIgnorePaths = readNodeSubmoduleIgnorePaths(args.node);
|
|
61779
|
-
try {
|
|
61780
|
-
const dryRun = await fastForwardMeshNode({
|
|
61781
|
-
meshId: args.meshId,
|
|
61782
|
-
nodeId: args.nodeId,
|
|
61783
|
-
workspace: args.workspace,
|
|
61784
|
-
execute: false,
|
|
61785
|
-
dryRun: true,
|
|
61786
|
-
updateSubmodules: false,
|
|
61787
|
-
submoduleIgnorePaths,
|
|
61788
|
-
trigger: args.trigger
|
|
61789
|
-
});
|
|
61790
|
-
if (!dryRunSatisfiesAutoFastForwardPolicy(dryRun, args.policy)) return;
|
|
61791
|
-
await fastForwardMeshNode({
|
|
61792
|
-
meshId: args.meshId,
|
|
61793
|
-
nodeId: args.nodeId,
|
|
61794
|
-
workspace: args.workspace,
|
|
61795
|
-
execute: true,
|
|
61796
|
-
dryRun: false,
|
|
61797
|
-
updateSubmodules: false,
|
|
61798
|
-
submoduleIgnorePaths,
|
|
61799
|
-
trigger: args.trigger
|
|
61800
|
-
});
|
|
61801
|
-
} catch (e) {
|
|
61802
|
-
LOG2.warn("MeshFastForward", `Idle auto fast-forward check failed for ${args.nodeId}: ${e?.message || e}`);
|
|
61803
|
-
} finally {
|
|
61804
|
-
releaseAutoFastForwardLease(args.workspace);
|
|
61805
|
-
}
|
|
61806
|
-
}
|
|
61807
|
-
async function maybeAutoFastForwardIdleNode(components, args) {
|
|
61808
|
-
const mesh = getMeshWithCache(components, args.meshId);
|
|
61809
|
-
const node = mesh?.nodes?.find((candidate) => meshNodeIdMatches(candidate, args.nodeId));
|
|
61810
|
-
const workspace = readNonEmptyString(node?.workspace);
|
|
61811
|
-
if (!workspace) return;
|
|
61812
|
-
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
61813
|
-
if (!policy.enabled) return;
|
|
61814
|
-
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
|
|
61815
|
-
const throttleKey = `${args.meshId}:${args.nodeId}`;
|
|
61816
|
-
const now = Date.now();
|
|
61817
|
-
const lastAttempt = idleAutoFastForwardLastAttempt.get(throttleKey) || 0;
|
|
61818
|
-
if (now - lastAttempt < IDLE_AUTO_FAST_FORWARD_THROTTLE_MS) return;
|
|
61819
|
-
idleAutoFastForwardLastAttempt.set(throttleKey, now);
|
|
61820
|
-
if (isLocalAutoLaunchNode(node)) {
|
|
61821
|
-
if (!(0, import_fs14.existsSync)(workspace)) return;
|
|
61822
|
-
await executeLocalAutoFastForward({ meshId: args.meshId, nodeId: args.nodeId, node, workspace, policy, trigger: "idle_auto" });
|
|
61823
|
-
return;
|
|
61824
|
-
}
|
|
61825
|
-
if (!policy.remoteNodes) return;
|
|
61826
|
-
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
61827
|
-
if (!daemonId || !components.dispatchMeshCommand) return;
|
|
61828
|
-
if (!remoteNodeIsConnected(components, node)) return;
|
|
61829
|
-
await delegateRemoteAutoFastForward(components, { meshId: args.meshId, nodeId: args.nodeId, node, daemonId, workspace, policy, trigger: "idle_auto" });
|
|
61830
|
-
}
|
|
61831
|
-
async function runContinuousAutoFastForwardScan(components, mesh) {
|
|
61832
|
-
if (!components.dispatchMeshCommand) return;
|
|
61833
|
-
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
61834
|
-
if (!policy.enabled || !policy.remoteNodes || policy.mode !== "continuous") return;
|
|
61835
|
-
const meshId = readNonEmptyString(mesh?.id);
|
|
61836
|
-
if (!meshId) return;
|
|
61837
|
-
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
61838
|
-
const now = Date.now();
|
|
61839
|
-
for (const node of nodes) {
|
|
61840
|
-
const nodeId = normalizeMeshNodeId(node);
|
|
61841
|
-
if (!nodeId) continue;
|
|
61842
|
-
if (node?.isLocalWorktree === true) continue;
|
|
61843
|
-
if (isLocalAutoLaunchNode(node)) continue;
|
|
61844
|
-
const workspace = readNonEmptyString(node?.workspace);
|
|
61845
|
-
if (!workspace) continue;
|
|
61846
|
-
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
61847
|
-
if (!daemonId) continue;
|
|
61848
|
-
if (!nodeIsAutoFastForwardEligible(components, meshId, nodeId, node)) continue;
|
|
61849
|
-
if (!remoteNodeIsConnected(components, node)) continue;
|
|
61850
|
-
const cooldownKey = `${meshId}:${nodeId}`;
|
|
61851
|
-
const lastScan = continuousAutoFastForwardLastScan.get(cooldownKey) || 0;
|
|
61852
|
-
if (now - lastScan < CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS) continue;
|
|
61853
|
-
continuousAutoFastForwardLastScan.set(cooldownKey, now);
|
|
61854
|
-
await delegateRemoteAutoFastForward(components, { meshId, nodeId, node, daemonId, workspace, policy, trigger: "reconcile_auto" });
|
|
61855
|
-
}
|
|
61856
|
-
}
|
|
61857
|
-
async function runPendingCoordinatorCatchupScan(components, mesh) {
|
|
61858
|
-
const meshId = readNonEmptyString(mesh?.id);
|
|
61859
|
-
if (!meshId) return;
|
|
61860
|
-
const localIds = expandDaemonIdForms([
|
|
61861
|
-
readNonEmptyString(components.statusInstanceId),
|
|
61862
|
-
readNonEmptyString(loadConfig2().machineId)
|
|
61863
|
-
]);
|
|
61864
|
-
let markers = [];
|
|
61865
|
-
try {
|
|
61866
|
-
markers = drainPendingMeshCoordinatorEvents(
|
|
61867
|
-
meshId,
|
|
61868
|
-
localIds.length > 0 ? localIds : void 0,
|
|
61869
|
-
{ onlyEvents: /* @__PURE__ */ new Set(["coordinator_catchup"]) }
|
|
61870
|
-
);
|
|
61871
|
-
} catch (e) {
|
|
61872
|
-
LOG2.warn("MeshReconcile", `Coordinator-catchup drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
61873
|
-
return;
|
|
61874
|
-
}
|
|
61875
|
-
if (markers.length === 0) return;
|
|
61876
|
-
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
61877
|
-
for (const marker of markers) {
|
|
61878
|
-
const meta3 = marker.metadataEvent || {};
|
|
61879
|
-
const nodeId = readNonEmptyString(marker.nodeId) || readNonEmptyString(meta3.nodeId);
|
|
61880
|
-
const workspace = readNonEmptyString(marker.workspace) || readNonEmptyString(meta3.workspace);
|
|
61881
|
-
const baseBranch = readNonEmptyString(meta3.baseBranch);
|
|
61882
|
-
if (!workspace) continue;
|
|
61883
|
-
if (nodeId && nodeHasActiveMeshWork(components, meshId, nodeId)) {
|
|
61884
|
-
try {
|
|
61885
|
-
queuePendingMeshCoordinatorEvent(marker);
|
|
61886
|
-
} catch {
|
|
61887
|
-
}
|
|
61888
|
-
continue;
|
|
61889
|
-
}
|
|
61890
|
-
try {
|
|
61891
|
-
const ff = await fastForwardMeshNode({
|
|
61892
|
-
meshId,
|
|
61893
|
-
...nodeId ? { nodeId } : {},
|
|
61894
|
-
workspace,
|
|
61895
|
-
...baseBranch ? { branch: baseBranch } : {},
|
|
61896
|
-
mode: "merge",
|
|
61897
|
-
execute: true,
|
|
61898
|
-
trigger: "refine_post_push_catchup",
|
|
61899
|
-
allowAutoPublishSubmoduleMainCommits: mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true
|
|
61900
|
-
});
|
|
61901
|
-
LOG2.info("MeshReconcile", `Coordinator catch-up ff for ${meshId}/${nodeId || workspace}: ${ff.code} (executed=${ff.executed})`);
|
|
61902
|
-
} catch (e) {
|
|
61903
|
-
LOG2.warn("MeshReconcile", `Coordinator catch-up ff failed for ${meshId}/${nodeId || workspace}: ${e?.message || e}`);
|
|
61904
|
-
}
|
|
61905
|
-
}
|
|
61906
|
-
}
|
|
61907
62014
|
function runIdleMaintenanceThenAssignQueue(components, args) {
|
|
61908
62015
|
setImmediate(() => {
|
|
61909
62016
|
maybeAutoFastForwardIdleNode(components, args).finally(() => {
|
|
@@ -61915,12 +62022,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61915
62022
|
});
|
|
61916
62023
|
});
|
|
61917
62024
|
}
|
|
61918
|
-
var import_fs14;
|
|
61919
|
-
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS;
|
|
61920
|
-
var idleAutoFastForwardLastAttempt;
|
|
61921
|
-
var CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS;
|
|
61922
|
-
var continuousAutoFastForwardLastScan;
|
|
61923
|
-
var autoFastForwardWorkspaceLease;
|
|
61924
62025
|
var BOOTSTRAP_TERMINAL_STATUSES;
|
|
61925
62026
|
var DISPATCH_CONFIRM_TIMEOUT_MS;
|
|
61926
62027
|
var DISPATCH_CONNECT_TIMEOUT_MS;
|
|
@@ -61936,15 +62037,9 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61936
62037
|
var autoLaunchAwaitClaimBackoff;
|
|
61937
62038
|
var lastAutoLaunchLedgerKey;
|
|
61938
62039
|
var AUTO_LAUNCH_LEDGER_DEDUP_MAX;
|
|
61939
|
-
var ACTIONABLE_SKIP_REASON_PREFIXES;
|
|
61940
|
-
var TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON;
|
|
61941
|
-
var lastActionableSkipNotified;
|
|
61942
|
-
var DEAD_TARGET_GRACE_MS;
|
|
61943
|
-
var TARGET_SESSION_PIN_TTL_MS;
|
|
61944
62040
|
var init_mesh_queue_assignment = __esm2({
|
|
61945
62041
|
"src/mesh/mesh-queue-assignment.ts"() {
|
|
61946
62042
|
"use strict";
|
|
61947
|
-
import_fs14 = require("fs");
|
|
61948
62043
|
init_runtime_defaults();
|
|
61949
62044
|
init_config();
|
|
61950
62045
|
init_mesh_config();
|
|
@@ -61953,7 +62048,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61953
62048
|
init_mesh_ledger();
|
|
61954
62049
|
init_mesh_work_queue();
|
|
61955
62050
|
init_transcript_evidence();
|
|
61956
|
-
init_mesh_fast_forward();
|
|
61957
62051
|
init_mesh_delivery_policy();
|
|
61958
62052
|
init_mesh_runtime_store();
|
|
61959
62053
|
init_mesh_event_trace();
|
|
@@ -61966,19 +62060,18 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61966
62060
|
init_mesh_events_stale();
|
|
61967
62061
|
init_mesh_events_utils();
|
|
61968
62062
|
init_mesh_node_identity();
|
|
61969
|
-
init_mesh_events_pending();
|
|
61970
62063
|
init_worktree_bootstrap_config();
|
|
61971
|
-
init_mesh_clone_grace();
|
|
61972
62064
|
init_mesh_task_inflight();
|
|
61973
62065
|
init_model_provider_compat();
|
|
61974
62066
|
init_slot_model_enforcement();
|
|
61975
62067
|
init_mesh_turn_ledger();
|
|
61976
62068
|
init_mesh_duplicate_dispatch();
|
|
61977
|
-
|
|
61978
|
-
|
|
61979
|
-
|
|
61980
|
-
|
|
61981
|
-
|
|
62069
|
+
init_mesh_auto_fast_forward();
|
|
62070
|
+
init_mesh_skip_notify();
|
|
62071
|
+
init_mesh_scheduling_fitness();
|
|
62072
|
+
init_mesh_auto_fast_forward();
|
|
62073
|
+
init_mesh_skip_notify();
|
|
62074
|
+
init_mesh_scheduling_fitness();
|
|
61982
62075
|
BOOTSTRAP_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["complete", "failed"]);
|
|
61983
62076
|
DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
|
|
61984
62077
|
DISPATCH_CONNECT_TIMEOUT_MS = MESH_CONNECT_TIMEOUT_MS2;
|
|
@@ -61994,43 +62087,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61994
62087
|
autoLaunchAwaitClaimBackoff = /* @__PURE__ */ new Map();
|
|
61995
62088
|
lastAutoLaunchLedgerKey = /* @__PURE__ */ new Map();
|
|
61996
62089
|
AUTO_LAUNCH_LEDGER_DEDUP_MAX = 2e3;
|
|
61997
|
-
ACTIONABLE_SKIP_REASON_PREFIXES = [
|
|
61998
|
-
"target_node_id_unmatched",
|
|
61999
|
-
"no_node_satisfies_required_tags",
|
|
62000
|
-
"mesh_convergence_target_is_worktree",
|
|
62001
|
-
"remote_auto_launch_unsupported",
|
|
62002
|
-
"remote_auto_launch_no_coordinator_daemon_id",
|
|
62003
|
-
"missing_provider_priority",
|
|
62004
|
-
"provider_loader_unavailable",
|
|
62005
|
-
"provider_priority_unusable",
|
|
62006
|
-
"provider_unusable",
|
|
62007
|
-
"dirty_workspace",
|
|
62008
|
-
// TARGET-PIN-TTL EXPIRY: the task was pinned to a specific session (a delta —
|
|
62009
|
-
// a correction addressed to work already in flight) and that session never
|
|
62010
|
-
// claimed it within the TTL, so the pin was cleared. Unlike the transient
|
|
62011
|
-
// skips, this does NOT self-resolve into the intended outcome: the delta is
|
|
62012
|
-
// now claimable by ANY compatible session, i.e. it will not reach the session
|
|
62013
|
-
// it was written for. Previously this only bumped a metrics counter and wrote
|
|
62014
|
-
// a log, so the coordinator kept waiting for a delivery that could no longer
|
|
62015
|
-
// happen — measured live as 74min of silence while a worker continued on a
|
|
62016
|
-
// premise the delta was meant to correct. The coordinator must know its
|
|
62017
|
-
// addressed message lost its address.
|
|
62018
|
-
"target_session_pin_expired",
|
|
62019
|
-
// SLOT MODEL GUARD (absent): no slot on the node declares the task's model.
|
|
62020
|
-
// Permanent — no amount of waiting produces a slot, so the coordinator must
|
|
62021
|
-
// re-drive (adjust difficulty, target another node, ask the owner). Its
|
|
62022
|
-
// busy counterpart SLOT_MODEL_BUSY_SKIP_REASON is deliberately NOT listed:
|
|
62023
|
-
// that one clears on its own when the slot goes idle.
|
|
62024
|
-
SLOT_MODEL_ABSENT_SKIP_REASON
|
|
62025
|
-
// QUOTA GATE: 'provider_quota_session_low' / 'provider_quota_weekly_low' are
|
|
62026
|
-
// deliberately NOT listed either — an exhausted quota window RESETS, so the
|
|
62027
|
-
// block self-resolves exactly like the slot-busy case; the task waits in the
|
|
62028
|
-
// queue and the coordinator is not paged (mesh-quota-routing.ts).
|
|
62029
|
-
];
|
|
62030
|
-
TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON = "target_node_bootstrap_pending";
|
|
62031
|
-
lastActionableSkipNotified = /* @__PURE__ */ new Map();
|
|
62032
|
-
DEAD_TARGET_GRACE_MS = 6e4;
|
|
62033
|
-
TARGET_SESSION_PIN_TTL_MS = 15 * 6e4;
|
|
62034
62090
|
}
|
|
62035
62091
|
});
|
|
62036
62092
|
function readSettings(state) {
|
|
@@ -62504,6 +62560,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
62504
62560
|
return cachedBinding;
|
|
62505
62561
|
}
|
|
62506
62562
|
const errors = [];
|
|
62563
|
+
let allModuleNotFound = true;
|
|
62507
62564
|
for (const ref of getBindingCandidates()) {
|
|
62508
62565
|
try {
|
|
62509
62566
|
const mod = require(ref);
|
|
@@ -62515,15 +62572,19 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
62515
62572
|
errors.push(`${ref}: module not found`);
|
|
62516
62573
|
continue;
|
|
62517
62574
|
}
|
|
62575
|
+
allModuleNotFound = false;
|
|
62518
62576
|
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
62519
62577
|
errors.push(`${ref}: ${message}`);
|
|
62520
62578
|
}
|
|
62521
62579
|
}
|
|
62522
|
-
|
|
62523
|
-
cachedBindingError = new Error(
|
|
62580
|
+
const buildError = () => new Error(
|
|
62524
62581
|
`ghostty-vt binding unavailable for runtime ${runtimeTriplet()} (${errors.join("; ") || "no candidates tried"})`
|
|
62525
62582
|
);
|
|
62526
|
-
|
|
62583
|
+
if (allModuleNotFound) {
|
|
62584
|
+
cachedBinding = null;
|
|
62585
|
+
cachedBindingError = buildError();
|
|
62586
|
+
}
|
|
62587
|
+
throw buildError();
|
|
62527
62588
|
}
|
|
62528
62589
|
var DEFAULT_BINDING_CANDIDATES;
|
|
62529
62590
|
var cachedBinding;
|
|
@@ -69936,20 +69997,31 @@ ${cleanBody}`;
|
|
|
69936
69997
|
});
|
|
69937
69998
|
var pty_transport_exports = {};
|
|
69938
69999
|
__export2(pty_transport_exports, {
|
|
69939
|
-
NodePtyTransportFactory: () => NodePtyTransportFactory
|
|
70000
|
+
NodePtyTransportFactory: () => NodePtyTransportFactory,
|
|
70001
|
+
__setNodePtyLoaderForTests: () => __setNodePtyLoaderForTests
|
|
69940
70002
|
});
|
|
70003
|
+
function isModuleNotFoundError2(error48) {
|
|
70004
|
+
return error48 instanceof Error && "code" in error48 && error48.code === "MODULE_NOT_FOUND";
|
|
70005
|
+
}
|
|
69941
70006
|
function loadNodePty() {
|
|
69942
70007
|
if (cachedPty !== void 0) return cachedPty;
|
|
69943
70008
|
try {
|
|
69944
|
-
cachedPty =
|
|
70009
|
+
cachedPty = requireNodePty();
|
|
69945
70010
|
(0, import_session_host_core3.ensureNodePtySpawnHelperPermissions)();
|
|
69946
|
-
} catch {
|
|
69947
|
-
|
|
70011
|
+
} catch (error48) {
|
|
70012
|
+
if (isModuleNotFoundError2(error48)) {
|
|
70013
|
+
cachedPty = null;
|
|
70014
|
+
}
|
|
69948
70015
|
}
|
|
69949
|
-
return cachedPty;
|
|
70016
|
+
return cachedPty ?? null;
|
|
70017
|
+
}
|
|
70018
|
+
function __setNodePtyLoaderForTests(loader2) {
|
|
70019
|
+
cachedPty = void 0;
|
|
70020
|
+
requireNodePty = loader2 ?? (() => require("node-pty"));
|
|
69950
70021
|
}
|
|
69951
70022
|
var os12;
|
|
69952
70023
|
var cachedPty;
|
|
70024
|
+
var requireNodePty;
|
|
69953
70025
|
var NodePtyRuntimeTransport;
|
|
69954
70026
|
var NodePtyTransportFactory;
|
|
69955
70027
|
var init_pty_transport = __esm2({
|
|
@@ -69958,6 +70030,7 @@ ${cleanBody}`;
|
|
|
69958
70030
|
os12 = __toESM2(require("os"));
|
|
69959
70031
|
init_spawn_env();
|
|
69960
70032
|
init_resolve_executable();
|
|
70033
|
+
requireNodePty = () => require("node-pty");
|
|
69961
70034
|
NodePtyRuntimeTransport = class {
|
|
69962
70035
|
constructor(handle) {
|
|
69963
70036
|
this.handle = handle;
|
|
@@ -70012,6 +70085,100 @@ ${cleanBody}`;
|
|
|
70012
70085
|
};
|
|
70013
70086
|
}
|
|
70014
70087
|
});
|
|
70088
|
+
function resolveTerminationSignal(termination) {
|
|
70089
|
+
if (typeof termination.signal === "number" && termination.signal > 0) return termination.signal;
|
|
70090
|
+
const code = termination.exitCode;
|
|
70091
|
+
if (typeof code === "number" && code > 128 && code <= 159) return code - 128;
|
|
70092
|
+
return null;
|
|
70093
|
+
}
|
|
70094
|
+
function terminationSignalName(signal) {
|
|
70095
|
+
return signal !== null ? SIGNAL_NAMES[signal] : void 0;
|
|
70096
|
+
}
|
|
70097
|
+
function classifyMeshTerminationStop(termination) {
|
|
70098
|
+
const signal = resolveTerminationSignal(termination);
|
|
70099
|
+
const signalName = terminationSignalName(signal);
|
|
70100
|
+
if (termination.requestedStop) {
|
|
70101
|
+
return { reason: "host_requested_stop", intentional: true, signal, signalName };
|
|
70102
|
+
}
|
|
70103
|
+
if (signal !== null) return { reason: "external_signal", intentional: false, signal, signalName };
|
|
70104
|
+
if (termination.exitCode === null) return { reason: "unknown_termination", intentional: false, signal, signalName };
|
|
70105
|
+
if (termination.exitCode === 0) return { reason: "self_exit", intentional: false, signal, signalName };
|
|
70106
|
+
return { reason: "unexpected_exit", intentional: false, signal, signalName };
|
|
70107
|
+
}
|
|
70108
|
+
function buildMeshTerminationStopPayload(input) {
|
|
70109
|
+
const { termination } = input;
|
|
70110
|
+
const classified = classifyMeshTerminationStop(termination);
|
|
70111
|
+
const terminatedAtIso = Number.isFinite(termination.terminatedAt) ? new Date(termination.terminatedAt).toISOString() : void 0;
|
|
70112
|
+
const lastOutputAtIso = typeof termination.lastOutputAt === "number" && Number.isFinite(termination.lastOutputAt) ? new Date(termination.lastOutputAt).toISOString() : void 0;
|
|
70113
|
+
const silentForMs = typeof termination.lastOutputAt === "number" && Number.isFinite(termination.lastOutputAt) && Number.isFinite(termination.terminatedAt) && termination.terminatedAt >= termination.lastOutputAt ? termination.terminatedAt - termination.lastOutputAt : void 0;
|
|
70114
|
+
return {
|
|
70115
|
+
intentional: classified.intentional,
|
|
70116
|
+
reason: classified.reason,
|
|
70117
|
+
// `source` marks who wrote the row, mirroring the operator-cleanup path's
|
|
70118
|
+
// convention so a reader can tell the two writers apart.
|
|
70119
|
+
source: "session_host_tombstone",
|
|
70120
|
+
observedVia: "session_exit",
|
|
70121
|
+
exitCode: termination.exitCode,
|
|
70122
|
+
signal: classified.signal,
|
|
70123
|
+
...classified.signalName ? { signalName: classified.signalName } : {},
|
|
70124
|
+
// session-host's own classification, kept verbatim alongside ours so the
|
|
70125
|
+
// ledger never silently disagrees with the tombstone on disk.
|
|
70126
|
+
terminationReason: termination.reason,
|
|
70127
|
+
lifecycle: termination.lifecycle,
|
|
70128
|
+
...termination.previousLifecycle ? { previousLifecycle: termination.previousLifecycle } : {},
|
|
70129
|
+
...termination.requestedStop ? { requestedStop: termination.requestedStop } : {},
|
|
70130
|
+
...typeof termination.osPid === "number" ? { osPid: termination.osPid } : {},
|
|
70131
|
+
...terminatedAtIso ? { terminatedAt: terminatedAtIso } : {},
|
|
70132
|
+
...lastOutputAtIso ? { lastOutputAt: lastOutputAtIso } : {},
|
|
70133
|
+
...silentForMs !== void 0 ? { silentForMs } : {},
|
|
70134
|
+
...input.isCoordinator ? { coordinatorSession: true } : {},
|
|
70135
|
+
...input.workspace ? { workspace: input.workspace } : {}
|
|
70136
|
+
};
|
|
70137
|
+
}
|
|
70138
|
+
function resolveMeshTerminationBinding(settings) {
|
|
70139
|
+
if (!settings || typeof settings !== "object") return null;
|
|
70140
|
+
const read = (value) => typeof value === "string" ? value.trim() : "";
|
|
70141
|
+
const workerMeshId = read(settings.meshNodeFor);
|
|
70142
|
+
if (workerMeshId) {
|
|
70143
|
+
const nodeId = read(settings.meshNodeId);
|
|
70144
|
+
return { meshId: workerMeshId, ...nodeId ? { nodeId } : {}, isCoordinator: false };
|
|
70145
|
+
}
|
|
70146
|
+
const coordinatorMeshId = read(settings.meshCoordinatorFor);
|
|
70147
|
+
if (coordinatorMeshId) return { meshId: coordinatorMeshId, isCoordinator: true };
|
|
70148
|
+
return null;
|
|
70149
|
+
}
|
|
70150
|
+
async function recordMeshSessionTerminationStop(input) {
|
|
70151
|
+
if (!input.meshId || !input.sessionId) return;
|
|
70152
|
+
try {
|
|
70153
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
70154
|
+
appendLedgerEntry2(input.meshId, {
|
|
70155
|
+
kind: "session_stopped",
|
|
70156
|
+
...input.nodeId ? { nodeId: input.nodeId } : {},
|
|
70157
|
+
sessionId: input.sessionId,
|
|
70158
|
+
...input.providerType ? { providerType: input.providerType } : {},
|
|
70159
|
+
payload: buildMeshTerminationStopPayload(input)
|
|
70160
|
+
});
|
|
70161
|
+
} catch (e) {
|
|
70162
|
+
LOG2.warn("MeshTermination", `Failed to record termination stop for ${input.sessionId}: ${e?.message || e}`);
|
|
70163
|
+
}
|
|
70164
|
+
}
|
|
70165
|
+
var SIGNAL_NAMES;
|
|
70166
|
+
var init_mesh_termination_bridge = __esm2({
|
|
70167
|
+
"src/mesh/mesh-termination-bridge.ts"() {
|
|
70168
|
+
"use strict";
|
|
70169
|
+
init_logger();
|
|
70170
|
+
SIGNAL_NAMES = {
|
|
70171
|
+
1: "SIGHUP",
|
|
70172
|
+
2: "SIGINT",
|
|
70173
|
+
3: "SIGQUIT",
|
|
70174
|
+
6: "SIGABRT",
|
|
70175
|
+
9: "SIGKILL",
|
|
70176
|
+
11: "SIGSEGV",
|
|
70177
|
+
13: "SIGPIPE",
|
|
70178
|
+
15: "SIGTERM"
|
|
70179
|
+
};
|
|
70180
|
+
}
|
|
70181
|
+
});
|
|
70015
70182
|
function chunkPreservingSurrogates(text, size) {
|
|
70016
70183
|
const chunks = [];
|
|
70017
70184
|
let offset = 0;
|
|
@@ -74444,6 +74611,7 @@ ${cont}` : cont;
|
|
|
74444
74611
|
init_terminal_screen();
|
|
74445
74612
|
import_session_host_core8 = require_dist();
|
|
74446
74613
|
init_pty_transport();
|
|
74614
|
+
init_mesh_termination_bridge();
|
|
74447
74615
|
init_pty_write_chunking();
|
|
74448
74616
|
init_provider_cli_shared();
|
|
74449
74617
|
init_cli_script_runner();
|
|
@@ -74457,9 +74625,10 @@ ${cont}` : cont;
|
|
|
74457
74625
|
missingBackgroundSourceWarned = /* @__PURE__ */ new Set();
|
|
74458
74626
|
FORCE_SUBMIT_SETTLE_MS = 150;
|
|
74459
74627
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
74460
|
-
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
74628
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory(), owningSessionId) {
|
|
74461
74629
|
this.extraArgs = extraArgs;
|
|
74462
74630
|
this.extraEnv = extraEnv;
|
|
74631
|
+
this.owningSessionId = owningSessionId;
|
|
74463
74632
|
this.runner = new CliScriptRunner(provider.type);
|
|
74464
74633
|
this.provider = provider;
|
|
74465
74634
|
this.transportFactory = transportFactory;
|
|
@@ -74909,8 +75078,9 @@ ${lastSnapshot}`;
|
|
|
74909
75078
|
}
|
|
74910
75079
|
}
|
|
74911
75080
|
});
|
|
74912
|
-
this.ptyProcess.onExit(({ exitCode, signal }) => {
|
|
75081
|
+
this.ptyProcess.onExit(({ exitCode, signal, termination }) => {
|
|
74913
75082
|
LOG2.info("CLI", `[${this.cliType}] Exit code ${exitCode === null || exitCode === void 0 ? "unknown" : exitCode}${signal ? ` (signal ${signal})` : ""}`);
|
|
75083
|
+
this.recordMeshTerminationIfBound(termination);
|
|
74914
75084
|
this.flushPendingOutputParse();
|
|
74915
75085
|
this.ptyProcess = null;
|
|
74916
75086
|
this.engine.onPtyExit();
|
|
@@ -74938,6 +75108,38 @@ ${lastSnapshot}`;
|
|
|
74938
75108
|
this.scheduleStartupSettleCheck();
|
|
74939
75109
|
this.onStatusChange?.();
|
|
74940
75110
|
}
|
|
75111
|
+
/**
|
|
75112
|
+
* TOMBSTONE-LEDGER-BRIDGE: write a mesh `session_stopped` ledger entry for a
|
|
75113
|
+
* terminated mesh session.
|
|
75114
|
+
*
|
|
75115
|
+
* This is the daemon's existing observation point for a dying CLI child — the
|
|
75116
|
+
* session host already emits `session_exit` carrying its termination
|
|
75117
|
+
* classification, so no watcher or polling loop is added. Previously the
|
|
75118
|
+
* classification was discarded here, which is why an externally-killed mesh
|
|
75119
|
+
* session (e.g. a SIGTERM from outside the mesh) left the ledger with no entry
|
|
75120
|
+
* at all and its death read as an unexplained gap in the record.
|
|
75121
|
+
*
|
|
75122
|
+
* Silent no-op for a non-mesh session or a transport that reports no
|
|
75123
|
+
* termination (raw node-pty), and never throws into the exit path.
|
|
75124
|
+
*/
|
|
75125
|
+
recordMeshTerminationIfBound(termination) {
|
|
75126
|
+
if (!termination || !this.owningSessionId) return;
|
|
75127
|
+
try {
|
|
75128
|
+
const binding = resolveMeshTerminationBinding(this.runtimeSettings);
|
|
75129
|
+
if (!binding) return;
|
|
75130
|
+
void recordMeshSessionTerminationStop({
|
|
75131
|
+
meshId: binding.meshId,
|
|
75132
|
+
sessionId: this.owningSessionId,
|
|
75133
|
+
nodeId: binding.nodeId,
|
|
75134
|
+
providerType: this.cliType,
|
|
75135
|
+
workspace: this.workingDir,
|
|
75136
|
+
isCoordinator: binding.isCoordinator,
|
|
75137
|
+
termination
|
|
75138
|
+
});
|
|
75139
|
+
} catch (e) {
|
|
75140
|
+
LOG2.warn("CLI", `[${this.cliType}] mesh termination ledger bridge failed: ${e?.message || e}`);
|
|
75141
|
+
}
|
|
75142
|
+
}
|
|
74941
75143
|
// ─── Output Handling ────────────────────────────
|
|
74942
75144
|
handleOutput(rawData) {
|
|
74943
75145
|
this.terminalScreen.write(rawData);
|
|
@@ -84198,10 +84400,50 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84198
84400
|
init_contracts2();
|
|
84199
84401
|
init_chat_history();
|
|
84200
84402
|
init_state_store();
|
|
84201
|
-
init_coordinator_registry();
|
|
84202
|
-
init_mesh_turn_presentation();
|
|
84203
84403
|
init_logger();
|
|
84204
84404
|
init_debug_trace();
|
|
84405
|
+
init_chat_message_normalization();
|
|
84406
|
+
init_contracts2();
|
|
84407
|
+
init_coordinator_registry();
|
|
84408
|
+
init_logger();
|
|
84409
|
+
init_chat_message_normalization();
|
|
84410
|
+
function normalizeReadChatTailLimit(args) {
|
|
84411
|
+
const value = Number(args?.tailLimit || 0);
|
|
84412
|
+
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
84413
|
+
}
|
|
84414
|
+
function normalizeReadChatMessages(payload) {
|
|
84415
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
84416
|
+
return normalizeChatMessages(messages);
|
|
84417
|
+
}
|
|
84418
|
+
function maybeHideCoordinatorPromptMessage(h, providerType, sessionId, messages) {
|
|
84419
|
+
if (!Array.isArray(messages) || messages.length === 0) return messages;
|
|
84420
|
+
if (!sessionId) return messages;
|
|
84421
|
+
const loader2 = h.ctx?.providerLoader;
|
|
84422
|
+
if (!loader2) return messages;
|
|
84423
|
+
let showSetting = void 0;
|
|
84424
|
+
try {
|
|
84425
|
+
showSetting = loader2.getSettingValue?.(providerType, "showCoordinatorSystemPrompt");
|
|
84426
|
+
} catch {
|
|
84427
|
+
}
|
|
84428
|
+
if (showSetting === true) return messages;
|
|
84429
|
+
const coord = getCoordinatorForSession(sessionId);
|
|
84430
|
+
if (!coord) return messages;
|
|
84431
|
+
const promptBody = typeof coord.systemPrompt === "string" ? coord.systemPrompt : "";
|
|
84432
|
+
const MARKER = "adhdev-mesh-coordinator-prompt";
|
|
84433
|
+
const filtered = messages.filter((m) => {
|
|
84434
|
+
const role = String(m?.role || "").toLowerCase();
|
|
84435
|
+
if (role !== "user" && role !== "system") return true;
|
|
84436
|
+
const content = flattenContent(m?.content);
|
|
84437
|
+
if (!content) return true;
|
|
84438
|
+
if (content.includes(MARKER)) return false;
|
|
84439
|
+
if (promptBody && content.includes(promptBody.slice(0, Math.min(400, promptBody.length)))) return false;
|
|
84440
|
+
return true;
|
|
84441
|
+
});
|
|
84442
|
+
if (filtered.length !== messages.length) {
|
|
84443
|
+
LOG2.debug("ChatFilter", `[${providerType}] hid ${messages.length - filtered.length} coordinator-prompt message(s) from ${sessionId}`);
|
|
84444
|
+
}
|
|
84445
|
+
return filtered;
|
|
84446
|
+
}
|
|
84205
84447
|
var INITIAL_CHAT_SOURCE_STATE = Object.freeze({
|
|
84206
84448
|
name: "Booting",
|
|
84207
84449
|
nativeSequencePeak: void 0,
|
|
@@ -84522,58 +84764,443 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84522
84764
|
lockState: result.lockState
|
|
84523
84765
|
};
|
|
84524
84766
|
}
|
|
84525
|
-
};
|
|
84526
|
-
function appendTransition(existing, next) {
|
|
84527
|
-
const last = existing[existing.length - 1];
|
|
84528
|
-
if (last && last.fromState === next.fromState && last.toState === next.toState && last.event === next.event && last.cause === next.cause) {
|
|
84529
|
-
return existing;
|
|
84767
|
+
};
|
|
84768
|
+
function appendTransition(existing, next) {
|
|
84769
|
+
const last = existing[existing.length - 1];
|
|
84770
|
+
if (last && last.fromState === next.fromState && last.toState === next.toState && last.event === next.event && last.cause === next.cause) {
|
|
84771
|
+
return existing;
|
|
84772
|
+
}
|
|
84773
|
+
const trimmed = existing.length >= TRANSITION_HISTORY_LIMIT ? existing.slice(existing.length - TRANSITION_HISTORY_LIMIT + 1) : [...existing];
|
|
84774
|
+
trimmed.push(next);
|
|
84775
|
+
return trimmed;
|
|
84776
|
+
}
|
|
84777
|
+
function buildV1NativePresentObservation(args) {
|
|
84778
|
+
const identities = [];
|
|
84779
|
+
let synthesisedSequence = 0;
|
|
84780
|
+
for (const message of args.messages) {
|
|
84781
|
+
const providerUnitKey = pickFirstString(
|
|
84782
|
+
message.providerUnitKey,
|
|
84783
|
+
message.bubbleId,
|
|
84784
|
+
message.id
|
|
84785
|
+
) ?? synthesiseV1UnitKey(args.providerType, args.sessionId, synthesisedSequence, message);
|
|
84786
|
+
const sequence = pickFiniteNumber(message.receivedAt, message.timestamp, message.index) ?? synthesisedSequence;
|
|
84787
|
+
identities.push({ providerUnitKey, sequence });
|
|
84788
|
+
synthesisedSequence += 1;
|
|
84789
|
+
}
|
|
84790
|
+
return {
|
|
84791
|
+
kind: "native_present",
|
|
84792
|
+
contractVersion: CHAT_CONTRACT_VERSION_V1,
|
|
84793
|
+
messages: identities,
|
|
84794
|
+
coverage: args.coverage,
|
|
84795
|
+
safeMapping: args.safeMapping
|
|
84796
|
+
};
|
|
84797
|
+
}
|
|
84798
|
+
function pickFirstString(...candidates) {
|
|
84799
|
+
for (const c of candidates) {
|
|
84800
|
+
if (typeof c === "string" && c.length > 0) return c;
|
|
84801
|
+
}
|
|
84802
|
+
return void 0;
|
|
84803
|
+
}
|
|
84804
|
+
function pickFiniteNumber(...candidates) {
|
|
84805
|
+
for (const c of candidates) {
|
|
84806
|
+
if (typeof c === "number" && Number.isFinite(c)) return c;
|
|
84807
|
+
}
|
|
84808
|
+
return void 0;
|
|
84809
|
+
}
|
|
84810
|
+
function synthesiseV1UnitKey(providerType, sessionId, positionalSeq, message) {
|
|
84811
|
+
const role = typeof message.role === "string" ? message.role : "";
|
|
84812
|
+
const ts2 = pickFiniteNumber(message.receivedAt, message.timestamp);
|
|
84813
|
+
return `v1:${providerType}:${sessionId}:${ts2 ?? ""}:${positionalSeq}:${role}`;
|
|
84814
|
+
}
|
|
84815
|
+
var CHAT_SOURCE_REGISTRY = new ChatSourceRegistry();
|
|
84816
|
+
init_chat_history();
|
|
84817
|
+
var CLI_NATIVE_TRANSCRIPT_PROVIDERS = /* @__PURE__ */ new Set(["codex-cli", "claude-cli", "hermes-cli", "antigravity-cli"]);
|
|
84818
|
+
var warnedLegacyNativeAllowlistHits = /* @__PURE__ */ new Set();
|
|
84819
|
+
function warnLegacyNativeAllowlistHit(providerType) {
|
|
84820
|
+
if (warnedLegacyNativeAllowlistHits.has(providerType)) return;
|
|
84821
|
+
warnedLegacyNativeAllowlistHits.add(providerType);
|
|
84822
|
+
console.warn(
|
|
84823
|
+
`[chat-commands] supportsCliNativeTranscript fell back to the hardcoded CLI_NATIVE_TRANSCRIPT_PROVIDERS set for "${providerType}". The provider module was unavailable or did not declare canonicalHistory. Set canonicalHistory.contractVersion in the provider.json to remove this dependency.`
|
|
84824
|
+
);
|
|
84825
|
+
}
|
|
84826
|
+
function supportsCliNativeTranscript(providerType, provider) {
|
|
84827
|
+
if (provider?.category === "cli" && isNativeSourceCanonicalHistory(provider?.nativeHistory)) {
|
|
84828
|
+
return true;
|
|
84829
|
+
}
|
|
84830
|
+
if (CLI_NATIVE_TRANSCRIPT_PROVIDERS.has(providerType)) {
|
|
84831
|
+
warnLegacyNativeAllowlistHit(providerType);
|
|
84832
|
+
return true;
|
|
84833
|
+
}
|
|
84834
|
+
return false;
|
|
84835
|
+
}
|
|
84836
|
+
function getMessageNewestReceivedAt(messages) {
|
|
84837
|
+
let newest = 0;
|
|
84838
|
+
for (const message of messages) {
|
|
84839
|
+
const receivedAt = Number(message?.receivedAt ?? message?.timestamp ?? 0);
|
|
84840
|
+
if (Number.isFinite(receivedAt) && receivedAt > newest) newest = receivedAt;
|
|
84841
|
+
}
|
|
84842
|
+
return newest;
|
|
84843
|
+
}
|
|
84844
|
+
function buildCliMessageSourceProvenance(args) {
|
|
84845
|
+
const sourceMtimeMs = Number(args.sourceMtimeMs || 0);
|
|
84846
|
+
const sourceMtimeAgeMs = sourceMtimeMs > 0 ? Math.max(0, Date.now() - sourceMtimeMs) : void 0;
|
|
84847
|
+
const nativeMessages = args.nativeMessages || [];
|
|
84848
|
+
const ptyMessages = args.ptyMessages || [];
|
|
84849
|
+
const returnedMessages = args.returnedMessages || [];
|
|
84850
|
+
const identityStatus = args.selected === "native-history" ? "safe" : args.fallbackReason === "native_history_not_safely_mapped" ? "ambiguous_session_identity" : args.fallbackReason?.startsWith("native_history_unavailable") ? "transcript_unmapped" : void 0;
|
|
84851
|
+
return {
|
|
84852
|
+
selected: args.selected,
|
|
84853
|
+
provider: args.provider,
|
|
84854
|
+
providerType: args.provider,
|
|
84855
|
+
...identityStatus ? { identityStatus } : {},
|
|
84856
|
+
...args.nativeHandle ? { nativeHandle: args.nativeHandle } : {},
|
|
84857
|
+
...args.nativeHandle ? { nativeSessionId: args.nativeHandle } : {},
|
|
84858
|
+
...args.sessionWorkspace ? { sessionWorkspace: args.sessionWorkspace } : {},
|
|
84859
|
+
...args.intendedWorkspace ? { intendedWorkspace: args.intendedWorkspace } : {},
|
|
84860
|
+
...args.transcriptWorkspace ? { transcriptWorkspace: args.transcriptWorkspace } : {},
|
|
84861
|
+
...args.fallbackReason ? { fallbackReason: args.fallbackReason } : {},
|
|
84862
|
+
...args.nativeSource ? { nativeSource: args.nativeSource } : {},
|
|
84863
|
+
...args.sourcePath ? { sourcePath: args.sourcePath } : {},
|
|
84864
|
+
...args.nativeHistoryCoverage ? { nativeHistoryCoverage: args.nativeHistoryCoverage } : {},
|
|
84865
|
+
...args.partialReason ? { partialReason: args.partialReason } : {},
|
|
84866
|
+
...args.unavailableReason ? { unavailableReason: args.unavailableReason } : {},
|
|
84867
|
+
ptyStatusApprovalOnly: args.ptyStatusApprovalOnly === true,
|
|
84868
|
+
staleness: {
|
|
84869
|
+
sourceMtimeMs: sourceMtimeMs || void 0,
|
|
84870
|
+
sourceMtimeAgeMs,
|
|
84871
|
+
nativeNewestMessageAt: getMessageNewestReceivedAt(nativeMessages),
|
|
84872
|
+
ptyNewestMessageAt: getMessageNewestReceivedAt(ptyMessages),
|
|
84873
|
+
freshEnough: args.freshEnough === true
|
|
84874
|
+
},
|
|
84875
|
+
coverage: {
|
|
84876
|
+
nativeMessageCount: nativeMessages.length,
|
|
84877
|
+
ptyMessageCount: ptyMessages.length,
|
|
84878
|
+
returnedMessageCount: returnedMessages.length,
|
|
84879
|
+
safeMapping: args.safeMapping === true,
|
|
84880
|
+
// true when PTY message bodies are suppressed and must not be treated as
|
|
84881
|
+
// chat content. PTY may still contribute status/approval/screen evidence.
|
|
84882
|
+
ptyMessagesSuppressed: args.selected === "native-history" || args.ptyStatusApprovalOnly === true
|
|
84883
|
+
}
|
|
84884
|
+
};
|
|
84885
|
+
}
|
|
84886
|
+
function causeToLegacyFallbackReason(cause, selected, extraDetail) {
|
|
84887
|
+
if (selected === "native-history") return void 0;
|
|
84888
|
+
switch (cause) {
|
|
84889
|
+
case "initial":
|
|
84890
|
+
return "native_history_not_checked";
|
|
84891
|
+
case "native_progressed":
|
|
84892
|
+
return "native_history_not_selected";
|
|
84893
|
+
case "native_regressed_shrunk":
|
|
84894
|
+
return "native_history_empty";
|
|
84895
|
+
case "native_regressed_unsafe_mapping":
|
|
84896
|
+
return "native_history_not_safely_mapped";
|
|
84897
|
+
case "native_regressed_coverage_partial":
|
|
84898
|
+
return "native_history_partial";
|
|
84899
|
+
case "native_regressed_coverage_unavailable":
|
|
84900
|
+
return "native_history_unavailable";
|
|
84901
|
+
case "native_unavailable_read_error":
|
|
84902
|
+
return extraDetail?.unavailableReason ? `native_history_unavailable:${extraDetail.unavailableReason}` : "native_history_unavailable";
|
|
84903
|
+
case "native_unavailable_provider_unsupported":
|
|
84904
|
+
return "provider_native_transcript_not_supported";
|
|
84905
|
+
case "native_unavailable_empty":
|
|
84906
|
+
return "native_history_empty";
|
|
84907
|
+
case "native_unavailable_not_native_source":
|
|
84908
|
+
return extraDetail?.nativeSource ? `native_history_source_${extraDetail.nativeSource}` : "native_history_unavailable";
|
|
84909
|
+
}
|
|
84910
|
+
}
|
|
84911
|
+
function decideCliReadChatSource(args) {
|
|
84912
|
+
const supportsNative = supportsCliNativeTranscript(args.providerType, args.provider);
|
|
84913
|
+
const observation = buildObservationForCli(args, supportsNative);
|
|
84914
|
+
const sessionKey = chatSourceSessionKey(args.providerType, args.sessionId);
|
|
84915
|
+
const priorSnapshot = CHAT_SOURCE_REGISTRY.snapshotRecord(sessionKey);
|
|
84916
|
+
const priorState = priorSnapshot?.state ?? CHAT_SOURCE_REGISTRY.getState(sessionKey);
|
|
84917
|
+
const eligibleForStickyHold = args.trustedExactNativeIdentity === true && (priorState.name === "NativeLocked" || priorState.name === "Recovering");
|
|
84918
|
+
let decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
84919
|
+
const heldNativeMessages = observation.kind === "native_present" ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult) : [];
|
|
84920
|
+
const mayHoldNativeSlice = heldNativeMessages.length > 0 && args.safeMapping === true;
|
|
84921
|
+
if (eligibleForStickyHold && decision.selected === "pty-parser" && mayHoldNativeSlice) {
|
|
84922
|
+
CHAT_SOURCE_REGISTRY.restoreRecord(sessionKey, priorSnapshot);
|
|
84923
|
+
const messageSource2 = buildCliMessageSourceProvenance({
|
|
84924
|
+
selected: "native-history",
|
|
84925
|
+
provider: args.providerType,
|
|
84926
|
+
nativeHandle: typeof args.nativeHistoryResult?.providerSessionId === "string" ? args.nativeHistoryResult.providerSessionId : void 0,
|
|
84927
|
+
sessionWorkspace: args.sessionWorkspace,
|
|
84928
|
+
intendedWorkspace: args.intendedWorkspace,
|
|
84929
|
+
transcriptWorkspace: void 0,
|
|
84930
|
+
fallbackReason: "native_history_transient_gap_held",
|
|
84931
|
+
nativeSource: "provider-native",
|
|
84932
|
+
sourcePath: typeof args.nativeHistoryResult?.sourcePath === "string" ? args.nativeHistoryResult.sourcePath : void 0,
|
|
84933
|
+
sourceMtimeMs: typeof args.nativeHistoryResult?.sourceMtimeMs === "number" ? args.nativeHistoryResult.sourceMtimeMs : void 0,
|
|
84934
|
+
nativeHistoryCoverage: void 0,
|
|
84935
|
+
partialReason: void 0,
|
|
84936
|
+
unavailableReason: observation.kind === "native_unavailable" ? observation.reason : void 0,
|
|
84937
|
+
nativeMessages: heldNativeMessages,
|
|
84938
|
+
ptyMessages: args.ptyMessages,
|
|
84939
|
+
returnedMessages: heldNativeMessages,
|
|
84940
|
+
safeMapping: args.safeMapping,
|
|
84941
|
+
freshEnough: true,
|
|
84942
|
+
ptyStatusApprovalOnly: true
|
|
84943
|
+
});
|
|
84944
|
+
return {
|
|
84945
|
+
decision: {
|
|
84946
|
+
selected: "native-history",
|
|
84947
|
+
nextState: priorState,
|
|
84948
|
+
transition: {
|
|
84949
|
+
fromState: priorState.name,
|
|
84950
|
+
toState: priorState.name,
|
|
84951
|
+
event: "NoOp",
|
|
84952
|
+
cause: decision.transition.cause,
|
|
84953
|
+
at: Date.now()
|
|
84954
|
+
},
|
|
84955
|
+
lockState: { locked: priorState.name === "NativeLocked" }
|
|
84956
|
+
},
|
|
84957
|
+
messageSource: messageSource2,
|
|
84958
|
+
nativeMessages: heldNativeMessages,
|
|
84959
|
+
nativeSelected: true
|
|
84960
|
+
};
|
|
84961
|
+
}
|
|
84962
|
+
if (decision.selected === "pty-parser" && args.trustedExactNativeIdentity === true && args.safeMapping && args.ptyMessages.length === 0 && observation.kind === "native_present" && observation.coverage !== "partial" && observation.messages.length > 0) {
|
|
84963
|
+
CHAT_SOURCE_REGISTRY.clear(sessionKey);
|
|
84964
|
+
decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
84965
|
+
}
|
|
84966
|
+
const nativeMessages = observation.kind === "native_present" ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult) : [];
|
|
84967
|
+
const nativeSource = typeof args.nativeHistoryResult?.source === "string" ? args.nativeHistoryResult.source : void 0;
|
|
84968
|
+
const sourcePath = typeof args.nativeHistoryResult?.sourcePath === "string" ? args.nativeHistoryResult.sourcePath : void 0;
|
|
84969
|
+
const sourceMtimeMs = typeof args.nativeHistoryResult?.sourceMtimeMs === "number" ? args.nativeHistoryResult.sourceMtimeMs : void 0;
|
|
84970
|
+
const coverageHint = typeof args.nativeHistoryResult?.nativeHistoryCoverage === "string" ? args.nativeHistoryResult.nativeHistoryCoverage : void 0;
|
|
84971
|
+
const partialReason = typeof args.nativeHistoryResult?.partialReason === "string" ? args.nativeHistoryResult.partialReason : void 0;
|
|
84972
|
+
const unavailableReason = typeof args.nativeHistoryResult?.unavailableReason === "string" ? args.nativeHistoryResult.unavailableReason : args.nativeHistoryError ? `error:${args.nativeHistoryError?.message || String(args.nativeHistoryError)}` : void 0;
|
|
84973
|
+
const nativeHandle = typeof args.nativeHistoryResult?.providerSessionId === "string" ? args.nativeHistoryResult.providerSessionId : void 0;
|
|
84974
|
+
const transcriptWorkspace = typeof args.nativeHistoryResult?.workspace === "string" ? args.nativeHistoryResult.workspace : nativeMessages.map((m) => typeof m?.workspace === "string" ? m.workspace.trim() : "").find(Boolean);
|
|
84975
|
+
const fallbackReason = causeToLegacyFallbackReason(decision.transition.cause, decision.selected, {
|
|
84976
|
+
unavailableReason,
|
|
84977
|
+
nativeSource: nativeSource && nativeSource !== "provider-native" ? nativeSource : void 0
|
|
84978
|
+
});
|
|
84979
|
+
const ptyStatusApprovalOnly = decision.selected === "native-history" ? true : args.ptyStatusApprovalOnly;
|
|
84980
|
+
const messageSource = buildCliMessageSourceProvenance({
|
|
84981
|
+
selected: decision.selected,
|
|
84982
|
+
provider: args.providerType,
|
|
84983
|
+
nativeHandle,
|
|
84984
|
+
sessionWorkspace: args.sessionWorkspace,
|
|
84985
|
+
intendedWorkspace: args.intendedWorkspace,
|
|
84986
|
+
transcriptWorkspace,
|
|
84987
|
+
fallbackReason,
|
|
84988
|
+
nativeSource,
|
|
84989
|
+
sourcePath,
|
|
84990
|
+
sourceMtimeMs,
|
|
84991
|
+
nativeHistoryCoverage: coverageHint,
|
|
84992
|
+
partialReason,
|
|
84993
|
+
unavailableReason,
|
|
84994
|
+
nativeMessages,
|
|
84995
|
+
ptyMessages: args.ptyMessages,
|
|
84996
|
+
returnedMessages: decision.selected === "native-history" ? nativeMessages : args.ptyMessages,
|
|
84997
|
+
safeMapping: args.safeMapping,
|
|
84998
|
+
// freshEnough is a v1 concept the machine does not model directly.
|
|
84999
|
+
// We surface lockState.locked here so v1 consumers reading
|
|
85000
|
+
// staleness.freshEnough still get a meaningful boolean.
|
|
85001
|
+
freshEnough: decision.lockState.locked,
|
|
85002
|
+
ptyStatusApprovalOnly
|
|
85003
|
+
});
|
|
85004
|
+
return {
|
|
85005
|
+
decision,
|
|
85006
|
+
messageSource,
|
|
85007
|
+
nativeMessages,
|
|
85008
|
+
nativeSelected: decision.selected === "native-history"
|
|
85009
|
+
};
|
|
85010
|
+
}
|
|
85011
|
+
function buildObservationForCli(args, supportsNative) {
|
|
85012
|
+
if (!supportsNative) {
|
|
85013
|
+
return { kind: "native_unavailable", reason: "provider_not_supported" };
|
|
85014
|
+
}
|
|
85015
|
+
if (args.nativeHistoryError) {
|
|
85016
|
+
return { kind: "native_unavailable", reason: "read_error" };
|
|
85017
|
+
}
|
|
85018
|
+
const result = args.nativeHistoryResult;
|
|
85019
|
+
if (!result || typeof result !== "object") {
|
|
85020
|
+
return { kind: "native_unavailable", reason: "read_error" };
|
|
85021
|
+
}
|
|
85022
|
+
const source = typeof result.source === "string" ? result.source : "";
|
|
85023
|
+
if (source && source !== "provider-native") {
|
|
85024
|
+
return { kind: "native_unavailable", reason: source === "native-unavailable" ? "empty" : "not_native_source" };
|
|
85025
|
+
}
|
|
85026
|
+
const messages = Array.isArray(result.messages) ? result.messages : [];
|
|
85027
|
+
if (messages.length === 0) {
|
|
85028
|
+
return { kind: "native_unavailable", reason: "empty" };
|
|
85029
|
+
}
|
|
85030
|
+
const coverage = typeof result.nativeHistoryCoverage === "string" ? result.nativeHistoryCoverage : "tail";
|
|
85031
|
+
if (coverage === "unavailable") {
|
|
85032
|
+
return { kind: "native_unavailable", reason: "coverage_unavailable" };
|
|
85033
|
+
}
|
|
85034
|
+
return buildV1NativePresentObservation({
|
|
85035
|
+
providerType: args.providerType,
|
|
85036
|
+
sessionId: args.sessionId,
|
|
85037
|
+
messages,
|
|
85038
|
+
coverage: coverage === "full" || coverage === "tail" || coverage === "current-turn" || coverage === "partial" ? coverage : "tail",
|
|
85039
|
+
safeMapping: args.safeMapping
|
|
85040
|
+
});
|
|
85041
|
+
}
|
|
85042
|
+
function extractNativeMessagesFromResult(providerType, result) {
|
|
85043
|
+
if (!result || !Array.isArray(result.messages)) return [];
|
|
85044
|
+
return normalizeNativeHistoryMessages(
|
|
85045
|
+
providerType,
|
|
85046
|
+
result.messages,
|
|
85047
|
+
typeof result.providerSessionId === "string" ? result.providerSessionId : void 0
|
|
85048
|
+
);
|
|
85049
|
+
}
|
|
85050
|
+
init_mesh_turn_presentation();
|
|
85051
|
+
init_chat_message_normalization();
|
|
85052
|
+
function shouldPreserveReadChatPayloadField(key2) {
|
|
85053
|
+
return key2 === "messageSource" || key2 === "transcriptProvenance";
|
|
85054
|
+
}
|
|
85055
|
+
function updateMessageSourceReturnedCount(value, returnedMessageCount) {
|
|
85056
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
85057
|
+
const record2 = value;
|
|
85058
|
+
const coverage = record2.coverage && typeof record2.coverage === "object" && !Array.isArray(record2.coverage) ? record2.coverage : void 0;
|
|
85059
|
+
if (!coverage) return value;
|
|
85060
|
+
return {
|
|
85061
|
+
...record2,
|
|
85062
|
+
coverage: {
|
|
85063
|
+
...coverage,
|
|
85064
|
+
returnedMessageCount
|
|
85065
|
+
}
|
|
85066
|
+
};
|
|
85067
|
+
}
|
|
85068
|
+
function buildFullTail(messages, tailLimit) {
|
|
85069
|
+
const totalMessages = messages.length;
|
|
85070
|
+
const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
|
|
85071
|
+
return {
|
|
85072
|
+
messages: tailMessages,
|
|
85073
|
+
totalMessages
|
|
85074
|
+
};
|
|
85075
|
+
}
|
|
85076
|
+
function hasNonEmptyModalButtons(activeModal) {
|
|
85077
|
+
if (!activeModal || typeof activeModal !== "object") return false;
|
|
85078
|
+
const buttons = activeModal.buttons;
|
|
85079
|
+
return Array.isArray(buttons) && buttons.some((button) => typeof button === "string" && button.trim().length > 0);
|
|
85080
|
+
}
|
|
85081
|
+
function normalizeReadChatCommandStatus(status, activeModal) {
|
|
85082
|
+
const raw = typeof status === "string" ? status.trim() : "";
|
|
85083
|
+
if (!raw) {
|
|
85084
|
+
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "idle";
|
|
85085
|
+
}
|
|
85086
|
+
switch (raw) {
|
|
85087
|
+
case "starting":
|
|
85088
|
+
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "starting";
|
|
85089
|
+
case "stopped":
|
|
85090
|
+
case "disconnected":
|
|
85091
|
+
case "not_monitored":
|
|
85092
|
+
return "error";
|
|
85093
|
+
case "waiting_approval":
|
|
85094
|
+
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "generating";
|
|
85095
|
+
default:
|
|
85096
|
+
return raw;
|
|
85097
|
+
}
|
|
85098
|
+
}
|
|
85099
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
85100
|
+
if (status !== "idle") return messages;
|
|
85101
|
+
return messages.map((message) => {
|
|
85102
|
+
const meta3 = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
85103
|
+
const hasStreamingMeta = meta3?.streaming === true;
|
|
85104
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
85105
|
+
return {
|
|
85106
|
+
...message,
|
|
85107
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
85108
|
+
...hasStreamingMeta ? { meta: { ...meta3, streaming: false } } : {}
|
|
85109
|
+
};
|
|
85110
|
+
});
|
|
85111
|
+
}
|
|
85112
|
+
function collapseAdjacentDuplicateChatMessages(messages) {
|
|
85113
|
+
if (!Array.isArray(messages) || messages.length <= 1) return messages;
|
|
85114
|
+
const result = [];
|
|
85115
|
+
let prevRoleKind = "";
|
|
85116
|
+
let prevStripped = "";
|
|
85117
|
+
for (const message of messages) {
|
|
85118
|
+
const role = typeof message.role === "string" ? message.role : "";
|
|
85119
|
+
const kind = typeof message.kind === "string" ? message.kind : "standard";
|
|
85120
|
+
const content = typeof message.content === "string" ? message.content : Array.isArray(message.content) ? message.content.map((p) => typeof p?.text === "string" ? p.text : "").join("") : "";
|
|
85121
|
+
const strippedContent = content.replace(/\s+/g, "");
|
|
85122
|
+
if (!strippedContent || role === "system") {
|
|
85123
|
+
result.push(message);
|
|
85124
|
+
prevRoleKind = "";
|
|
85125
|
+
prevStripped = "";
|
|
85126
|
+
continue;
|
|
85127
|
+
}
|
|
85128
|
+
const roleKind = `${role}:${kind}`;
|
|
85129
|
+
const sameStripped = strippedContent === prevStripped && roleKind === prevRoleKind;
|
|
85130
|
+
if (result.length > 0 && sameStripped) {
|
|
85131
|
+
result[result.length - 1] = message;
|
|
85132
|
+
prevRoleKind = roleKind;
|
|
85133
|
+
prevStripped = strippedContent;
|
|
85134
|
+
continue;
|
|
85135
|
+
}
|
|
85136
|
+
result.push(message);
|
|
85137
|
+
prevRoleKind = roleKind;
|
|
85138
|
+
prevStripped = strippedContent;
|
|
85139
|
+
}
|
|
85140
|
+
return result;
|
|
85141
|
+
}
|
|
85142
|
+
function buildReadChatCommandResult(payload, args, h) {
|
|
85143
|
+
let validatedPayload;
|
|
85144
|
+
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
85145
|
+
const presentationSessionIdHint = typeof args?.targetSessionId === "string" && args.targetSessionId.trim() ? args.targetSessionId.trim() : typeof args?.sessionId === "string" && args.sessionId.trim() ? args.sessionId.trim() : typeof h?.currentSession?.sessionId === "string" ? String(h.currentSession.sessionId) : "";
|
|
85146
|
+
const providerHint = typeof args?.cliType === "string" ? args.cliType : typeof args?.providerType === "string" ? args.providerType : typeof args?.agentType === "string" ? args.agentType : "";
|
|
85147
|
+
const legacyStatus = normalizeReadChatCommandStatus(payload?.status, payload?.activeModal);
|
|
85148
|
+
const turnPresentation = resolveSessionTurnPresentation({
|
|
85149
|
+
sessionId: presentationSessionIdHint || void 0,
|
|
85150
|
+
legacyStatus,
|
|
85151
|
+
providerType: providerHint || void 0,
|
|
85152
|
+
surface: "read_chat"
|
|
85153
|
+
});
|
|
85154
|
+
let effectiveStatus = legacyStatus;
|
|
85155
|
+
if (turnPresentation.authority === "turn_reducer") {
|
|
85156
|
+
effectiveStatus = turnPresentation.status;
|
|
85157
|
+
if (effectiveStatus === "waiting_approval" && !hasNonEmptyModalButtons(payload?.activeModal)) {
|
|
85158
|
+
effectiveStatus = "generating";
|
|
85159
|
+
}
|
|
85160
|
+
}
|
|
85161
|
+
try {
|
|
85162
|
+
validatedPayload = validateReadChatResultPayload({
|
|
85163
|
+
...payload,
|
|
85164
|
+
status: effectiveStatus
|
|
85165
|
+
}, "read_chat command result");
|
|
85166
|
+
} catch (error48) {
|
|
85167
|
+
return { success: false, error: error48?.message || String(error48) };
|
|
84530
85168
|
}
|
|
84531
|
-
const
|
|
84532
|
-
|
|
84533
|
-
|
|
84534
|
-
|
|
84535
|
-
|
|
84536
|
-
const
|
|
84537
|
-
|
|
84538
|
-
|
|
84539
|
-
|
|
84540
|
-
|
|
84541
|
-
|
|
84542
|
-
|
|
84543
|
-
|
|
84544
|
-
const sequence = pickFiniteNumber(message.receivedAt, message.timestamp, message.index) ?? synthesisedSequence;
|
|
84545
|
-
identities.push({ providerUnitKey, sequence });
|
|
84546
|
-
synthesisedSequence += 1;
|
|
85169
|
+
const messages = normalizeReadChatMessages(validatedPayload);
|
|
85170
|
+
const sessionIdHint = typeof args?.targetSessionId === "string" ? args.targetSessionId : typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
85171
|
+
const filteredMessages = h ? maybeHideCoordinatorPromptMessage(h, providerHint, sessionIdHint, messages) : messages;
|
|
85172
|
+
const includeActivity = args?.includeActivity === true || args?.includeActivity === "true";
|
|
85173
|
+
const visibleMessages = includeActivity ? filteredMessages.filter((m) => isUserFacingChatMessage(m) || isActivityChatMessage(m)) : filterUserFacingChatMessages(filteredMessages);
|
|
85174
|
+
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
85175
|
+
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
85176
|
+
const preservedPayloadFields = Object.fromEntries(Object.entries(payload).filter(([key2]) => shouldPreserveReadChatPayloadField(key2)));
|
|
85177
|
+
if (preservedPayloadFields.messageSource) {
|
|
85178
|
+
preservedPayloadFields.messageSource = updateMessageSourceReturnedCount(preservedPayloadFields.messageSource, sync.messages.length);
|
|
85179
|
+
}
|
|
85180
|
+
if (preservedPayloadFields.transcriptProvenance) {
|
|
85181
|
+
preservedPayloadFields.transcriptProvenance = updateMessageSourceReturnedCount(preservedPayloadFields.transcriptProvenance, sync.messages.length);
|
|
84547
85182
|
}
|
|
85183
|
+
const returnedDebugReadChat = debugReadChat ? {
|
|
85184
|
+
...debugReadChat,
|
|
85185
|
+
fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
|
|
85186
|
+
visibleMsgCount: visibleMessages.length,
|
|
85187
|
+
hiddenMsgCount,
|
|
85188
|
+
returnedMsgCount: sync.messages.length
|
|
85189
|
+
} : void 0;
|
|
84548
85190
|
return {
|
|
84549
|
-
|
|
84550
|
-
|
|
84551
|
-
|
|
84552
|
-
|
|
84553
|
-
|
|
85191
|
+
success: true,
|
|
85192
|
+
...validatedPayload,
|
|
85193
|
+
...preservedPayloadFields,
|
|
85194
|
+
messages: sync.messages,
|
|
85195
|
+
totalMessages: sync.totalMessages,
|
|
85196
|
+
// Stage 6: the authoritative turn presentation rides the read_chat
|
|
85197
|
+
// payload for mesh-owned sessions (identity + stage + evidence
|
|
85198
|
+
// timestamps; the `status` field above already reflects it).
|
|
85199
|
+
...turnPresentation.authority === "turn_reducer" ? { turn: turnPresentation } : {},
|
|
85200
|
+
...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
|
|
84554
85201
|
};
|
|
84555
85202
|
}
|
|
84556
|
-
function pickFirstString(...candidates) {
|
|
84557
|
-
for (const c of candidates) {
|
|
84558
|
-
if (typeof c === "string" && c.length > 0) return c;
|
|
84559
|
-
}
|
|
84560
|
-
return void 0;
|
|
84561
|
-
}
|
|
84562
|
-
function pickFiniteNumber(...candidates) {
|
|
84563
|
-
for (const c of candidates) {
|
|
84564
|
-
if (typeof c === "number" && Number.isFinite(c)) return c;
|
|
84565
|
-
}
|
|
84566
|
-
return void 0;
|
|
84567
|
-
}
|
|
84568
|
-
function synthesiseV1UnitKey(providerType, sessionId, positionalSeq, message) {
|
|
84569
|
-
const role = typeof message.role === "string" ? message.role : "";
|
|
84570
|
-
const ts2 = pickFiniteNumber(message.receivedAt, message.timestamp);
|
|
84571
|
-
return `v1:${providerType}:${sessionId}:${ts2 ?? ""}:${positionalSeq}:${role}`;
|
|
84572
|
-
}
|
|
84573
|
-
var CHAT_SOURCE_REGISTRY = new ChatSourceRegistry();
|
|
84574
|
-
init_chat_message_normalization();
|
|
84575
85203
|
var HOT_TAIL_MIN_LIMIT = 60;
|
|
84576
|
-
var CLI_NATIVE_TRANSCRIPT_PROVIDERS = /* @__PURE__ */ new Set(["codex-cli", "claude-cli", "hermes-cli", "antigravity-cli"]);
|
|
84577
85204
|
var lastBoundProviderSessionIdByMeshSession = /* @__PURE__ */ new Map();
|
|
84578
85205
|
var persistedProviderSessionPinsHydrated = false;
|
|
84579
85206
|
function hydratePersistedProviderSessionPinsOnce() {
|
|
@@ -84609,14 +85236,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84609
85236
|
const pinned = lastBoundProviderSessionIdByMeshSession.get(key2);
|
|
84610
85237
|
return pinned && pinned.trim() ? pinned.trim() : void 0;
|
|
84611
85238
|
}
|
|
84612
|
-
var warnedLegacyNativeAllowlistHits = /* @__PURE__ */ new Set();
|
|
84613
|
-
function warnLegacyNativeAllowlistHit(providerType) {
|
|
84614
|
-
if (warnedLegacyNativeAllowlistHits.has(providerType)) return;
|
|
84615
|
-
warnedLegacyNativeAllowlistHits.add(providerType);
|
|
84616
|
-
console.warn(
|
|
84617
|
-
`[chat-commands] supportsCliNativeTranscript fell back to the hardcoded CLI_NATIVE_TRANSCRIPT_PROVIDERS set for "${providerType}". The provider module was unavailable or did not declare canonicalHistory. Set canonicalHistory.contractVersion in the provider.json to remove this dependency.`
|
|
84618
|
-
);
|
|
84619
|
-
}
|
|
84620
85239
|
function getExplicitHistorySessionId(args) {
|
|
84621
85240
|
const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
|
|
84622
85241
|
if (explicit) return explicit;
|
|
@@ -84695,22 +85314,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84695
85314
|
payload: options.payload
|
|
84696
85315
|
});
|
|
84697
85316
|
}
|
|
84698
|
-
function normalizeReadChatTailLimit(args) {
|
|
84699
|
-
const value = Number(args?.tailLimit || 0);
|
|
84700
|
-
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
84701
|
-
}
|
|
84702
|
-
function normalizeReadChatMessages(payload) {
|
|
84703
|
-
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
84704
|
-
return normalizeChatMessages(messages);
|
|
84705
|
-
}
|
|
84706
|
-
function getMessageNewestReceivedAt(messages) {
|
|
84707
|
-
let newest = 0;
|
|
84708
|
-
for (const message of messages) {
|
|
84709
|
-
const receivedAt = Number(message?.receivedAt ?? message?.timestamp ?? 0);
|
|
84710
|
-
if (Number.isFinite(receivedAt) && receivedAt > newest) newest = receivedAt;
|
|
84711
|
-
}
|
|
84712
|
-
return newest;
|
|
84713
|
-
}
|
|
84714
85317
|
function readHistorySessionIdFromMessages(messages) {
|
|
84715
85318
|
for (const message of messages) {
|
|
84716
85319
|
const historySessionId = typeof message?.historySessionId === "string" ? message.historySessionId.trim() : "";
|
|
@@ -84731,35 +85334,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84731
85334
|
}
|
|
84732
85335
|
return true;
|
|
84733
85336
|
}
|
|
84734
|
-
function maybeHideCoordinatorPromptMessage(h, providerType, sessionId, messages) {
|
|
84735
|
-
if (!Array.isArray(messages) || messages.length === 0) return messages;
|
|
84736
|
-
if (!sessionId) return messages;
|
|
84737
|
-
const loader2 = h.ctx?.providerLoader;
|
|
84738
|
-
if (!loader2) return messages;
|
|
84739
|
-
let showSetting = void 0;
|
|
84740
|
-
try {
|
|
84741
|
-
showSetting = loader2.getSettingValue?.(providerType, "showCoordinatorSystemPrompt");
|
|
84742
|
-
} catch {
|
|
84743
|
-
}
|
|
84744
|
-
if (showSetting === true) return messages;
|
|
84745
|
-
const coord = getCoordinatorForSession(sessionId);
|
|
84746
|
-
if (!coord) return messages;
|
|
84747
|
-
const promptBody = typeof coord.systemPrompt === "string" ? coord.systemPrompt : "";
|
|
84748
|
-
const MARKER = "adhdev-mesh-coordinator-prompt";
|
|
84749
|
-
const filtered = messages.filter((m) => {
|
|
84750
|
-
const role = String(m?.role || "").toLowerCase();
|
|
84751
|
-
if (role !== "user" && role !== "system") return true;
|
|
84752
|
-
const content = flattenContent(m?.content);
|
|
84753
|
-
if (!content) return true;
|
|
84754
|
-
if (content.includes(MARKER)) return false;
|
|
84755
|
-
if (promptBody && content.includes(promptBody.slice(0, Math.min(400, promptBody.length)))) return false;
|
|
84756
|
-
return true;
|
|
84757
|
-
});
|
|
84758
|
-
if (filtered.length !== messages.length) {
|
|
84759
|
-
LOG2.debug("ChatFilter", `[${providerType}] hid ${messages.length - filtered.length} coordinator-prompt message(s) from ${sessionId}`);
|
|
84760
|
-
}
|
|
84761
|
-
return filtered;
|
|
84762
|
-
}
|
|
84763
85337
|
function normalizeAndFilterNativeHistory(h, providerType, args, messages, nativeSessionId) {
|
|
84764
85338
|
const normalized = normalizeNativeHistoryMessages(providerType, messages, nativeSessionId);
|
|
84765
85339
|
const sessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -84833,212 +85407,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84833
85407
|
};
|
|
84834
85408
|
});
|
|
84835
85409
|
}
|
|
84836
|
-
function buildCliMessageSourceProvenance(args) {
|
|
84837
|
-
const sourceMtimeMs = Number(args.sourceMtimeMs || 0);
|
|
84838
|
-
const sourceMtimeAgeMs = sourceMtimeMs > 0 ? Math.max(0, Date.now() - sourceMtimeMs) : void 0;
|
|
84839
|
-
const nativeMessages = args.nativeMessages || [];
|
|
84840
|
-
const ptyMessages = args.ptyMessages || [];
|
|
84841
|
-
const returnedMessages = args.returnedMessages || [];
|
|
84842
|
-
const identityStatus = args.selected === "native-history" ? "safe" : args.fallbackReason === "native_history_not_safely_mapped" ? "ambiguous_session_identity" : args.fallbackReason?.startsWith("native_history_unavailable") ? "transcript_unmapped" : void 0;
|
|
84843
|
-
return {
|
|
84844
|
-
selected: args.selected,
|
|
84845
|
-
provider: args.provider,
|
|
84846
|
-
providerType: args.provider,
|
|
84847
|
-
...identityStatus ? { identityStatus } : {},
|
|
84848
|
-
...args.nativeHandle ? { nativeHandle: args.nativeHandle } : {},
|
|
84849
|
-
...args.nativeHandle ? { nativeSessionId: args.nativeHandle } : {},
|
|
84850
|
-
...args.sessionWorkspace ? { sessionWorkspace: args.sessionWorkspace } : {},
|
|
84851
|
-
...args.intendedWorkspace ? { intendedWorkspace: args.intendedWorkspace } : {},
|
|
84852
|
-
...args.transcriptWorkspace ? { transcriptWorkspace: args.transcriptWorkspace } : {},
|
|
84853
|
-
...args.fallbackReason ? { fallbackReason: args.fallbackReason } : {},
|
|
84854
|
-
...args.nativeSource ? { nativeSource: args.nativeSource } : {},
|
|
84855
|
-
...args.sourcePath ? { sourcePath: args.sourcePath } : {},
|
|
84856
|
-
...args.nativeHistoryCoverage ? { nativeHistoryCoverage: args.nativeHistoryCoverage } : {},
|
|
84857
|
-
...args.partialReason ? { partialReason: args.partialReason } : {},
|
|
84858
|
-
...args.unavailableReason ? { unavailableReason: args.unavailableReason } : {},
|
|
84859
|
-
ptyStatusApprovalOnly: args.ptyStatusApprovalOnly === true,
|
|
84860
|
-
staleness: {
|
|
84861
|
-
sourceMtimeMs: sourceMtimeMs || void 0,
|
|
84862
|
-
sourceMtimeAgeMs,
|
|
84863
|
-
nativeNewestMessageAt: getMessageNewestReceivedAt(nativeMessages),
|
|
84864
|
-
ptyNewestMessageAt: getMessageNewestReceivedAt(ptyMessages),
|
|
84865
|
-
freshEnough: args.freshEnough === true
|
|
84866
|
-
},
|
|
84867
|
-
coverage: {
|
|
84868
|
-
nativeMessageCount: nativeMessages.length,
|
|
84869
|
-
ptyMessageCount: ptyMessages.length,
|
|
84870
|
-
returnedMessageCount: returnedMessages.length,
|
|
84871
|
-
safeMapping: args.safeMapping === true,
|
|
84872
|
-
// true when PTY message bodies are suppressed and must not be treated as
|
|
84873
|
-
// chat content. PTY may still contribute status/approval/screen evidence.
|
|
84874
|
-
ptyMessagesSuppressed: args.selected === "native-history" || args.ptyStatusApprovalOnly === true
|
|
84875
|
-
}
|
|
84876
|
-
};
|
|
84877
|
-
}
|
|
84878
|
-
function causeToLegacyFallbackReason(cause, selected, extraDetail) {
|
|
84879
|
-
if (selected === "native-history") return void 0;
|
|
84880
|
-
switch (cause) {
|
|
84881
|
-
case "initial":
|
|
84882
|
-
return "native_history_not_checked";
|
|
84883
|
-
case "native_progressed":
|
|
84884
|
-
return "native_history_not_selected";
|
|
84885
|
-
case "native_regressed_shrunk":
|
|
84886
|
-
return "native_history_empty";
|
|
84887
|
-
case "native_regressed_unsafe_mapping":
|
|
84888
|
-
return "native_history_not_safely_mapped";
|
|
84889
|
-
case "native_regressed_coverage_partial":
|
|
84890
|
-
return "native_history_partial";
|
|
84891
|
-
case "native_regressed_coverage_unavailable":
|
|
84892
|
-
return "native_history_unavailable";
|
|
84893
|
-
case "native_unavailable_read_error":
|
|
84894
|
-
return extraDetail?.unavailableReason ? `native_history_unavailable:${extraDetail.unavailableReason}` : "native_history_unavailable";
|
|
84895
|
-
case "native_unavailable_provider_unsupported":
|
|
84896
|
-
return "provider_native_transcript_not_supported";
|
|
84897
|
-
case "native_unavailable_empty":
|
|
84898
|
-
return "native_history_empty";
|
|
84899
|
-
case "native_unavailable_not_native_source":
|
|
84900
|
-
return extraDetail?.nativeSource ? `native_history_source_${extraDetail.nativeSource}` : "native_history_unavailable";
|
|
84901
|
-
}
|
|
84902
|
-
}
|
|
84903
|
-
function decideCliReadChatSource(args) {
|
|
84904
|
-
const supportsNative = supportsCliNativeTranscript(args.providerType, args.provider);
|
|
84905
|
-
const observation = buildObservationForCli(args, supportsNative);
|
|
84906
|
-
const sessionKey = chatSourceSessionKey(args.providerType, args.sessionId);
|
|
84907
|
-
const priorSnapshot = CHAT_SOURCE_REGISTRY.snapshotRecord(sessionKey);
|
|
84908
|
-
const priorState = priorSnapshot?.state ?? CHAT_SOURCE_REGISTRY.getState(sessionKey);
|
|
84909
|
-
const eligibleForStickyHold = args.trustedExactNativeIdentity === true && (priorState.name === "NativeLocked" || priorState.name === "Recovering");
|
|
84910
|
-
let decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
84911
|
-
const heldNativeMessages = observation.kind === "native_present" ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult) : [];
|
|
84912
|
-
const mayHoldNativeSlice = heldNativeMessages.length > 0 && args.safeMapping === true;
|
|
84913
|
-
if (eligibleForStickyHold && decision.selected === "pty-parser" && mayHoldNativeSlice) {
|
|
84914
|
-
CHAT_SOURCE_REGISTRY.restoreRecord(sessionKey, priorSnapshot);
|
|
84915
|
-
const messageSource2 = buildCliMessageSourceProvenance({
|
|
84916
|
-
selected: "native-history",
|
|
84917
|
-
provider: args.providerType,
|
|
84918
|
-
nativeHandle: typeof args.nativeHistoryResult?.providerSessionId === "string" ? args.nativeHistoryResult.providerSessionId : void 0,
|
|
84919
|
-
sessionWorkspace: args.sessionWorkspace,
|
|
84920
|
-
intendedWorkspace: args.intendedWorkspace,
|
|
84921
|
-
transcriptWorkspace: void 0,
|
|
84922
|
-
fallbackReason: "native_history_transient_gap_held",
|
|
84923
|
-
nativeSource: "provider-native",
|
|
84924
|
-
sourcePath: typeof args.nativeHistoryResult?.sourcePath === "string" ? args.nativeHistoryResult.sourcePath : void 0,
|
|
84925
|
-
sourceMtimeMs: typeof args.nativeHistoryResult?.sourceMtimeMs === "number" ? args.nativeHistoryResult.sourceMtimeMs : void 0,
|
|
84926
|
-
nativeHistoryCoverage: void 0,
|
|
84927
|
-
partialReason: void 0,
|
|
84928
|
-
unavailableReason: observation.kind === "native_unavailable" ? observation.reason : void 0,
|
|
84929
|
-
nativeMessages: heldNativeMessages,
|
|
84930
|
-
ptyMessages: args.ptyMessages,
|
|
84931
|
-
returnedMessages: heldNativeMessages,
|
|
84932
|
-
safeMapping: args.safeMapping,
|
|
84933
|
-
freshEnough: true,
|
|
84934
|
-
ptyStatusApprovalOnly: true
|
|
84935
|
-
});
|
|
84936
|
-
return {
|
|
84937
|
-
decision: {
|
|
84938
|
-
selected: "native-history",
|
|
84939
|
-
nextState: priorState,
|
|
84940
|
-
transition: {
|
|
84941
|
-
fromState: priorState.name,
|
|
84942
|
-
toState: priorState.name,
|
|
84943
|
-
event: "NoOp",
|
|
84944
|
-
cause: decision.transition.cause,
|
|
84945
|
-
at: Date.now()
|
|
84946
|
-
},
|
|
84947
|
-
lockState: { locked: priorState.name === "NativeLocked" }
|
|
84948
|
-
},
|
|
84949
|
-
messageSource: messageSource2,
|
|
84950
|
-
nativeMessages: heldNativeMessages,
|
|
84951
|
-
nativeSelected: true
|
|
84952
|
-
};
|
|
84953
|
-
}
|
|
84954
|
-
if (decision.selected === "pty-parser" && args.trustedExactNativeIdentity === true && args.safeMapping && args.ptyMessages.length === 0 && observation.kind === "native_present" && observation.coverage !== "partial" && observation.messages.length > 0) {
|
|
84955
|
-
CHAT_SOURCE_REGISTRY.clear(sessionKey);
|
|
84956
|
-
decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
84957
|
-
}
|
|
84958
|
-
const nativeMessages = observation.kind === "native_present" ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult) : [];
|
|
84959
|
-
const nativeSource = typeof args.nativeHistoryResult?.source === "string" ? args.nativeHistoryResult.source : void 0;
|
|
84960
|
-
const sourcePath = typeof args.nativeHistoryResult?.sourcePath === "string" ? args.nativeHistoryResult.sourcePath : void 0;
|
|
84961
|
-
const sourceMtimeMs = typeof args.nativeHistoryResult?.sourceMtimeMs === "number" ? args.nativeHistoryResult.sourceMtimeMs : void 0;
|
|
84962
|
-
const coverageHint = typeof args.nativeHistoryResult?.nativeHistoryCoverage === "string" ? args.nativeHistoryResult.nativeHistoryCoverage : void 0;
|
|
84963
|
-
const partialReason = typeof args.nativeHistoryResult?.partialReason === "string" ? args.nativeHistoryResult.partialReason : void 0;
|
|
84964
|
-
const unavailableReason = typeof args.nativeHistoryResult?.unavailableReason === "string" ? args.nativeHistoryResult.unavailableReason : args.nativeHistoryError ? `error:${args.nativeHistoryError?.message || String(args.nativeHistoryError)}` : void 0;
|
|
84965
|
-
const nativeHandle = typeof args.nativeHistoryResult?.providerSessionId === "string" ? args.nativeHistoryResult.providerSessionId : void 0;
|
|
84966
|
-
const transcriptWorkspace = typeof args.nativeHistoryResult?.workspace === "string" ? args.nativeHistoryResult.workspace : nativeMessages.map((m) => typeof m?.workspace === "string" ? m.workspace.trim() : "").find(Boolean);
|
|
84967
|
-
const fallbackReason = causeToLegacyFallbackReason(decision.transition.cause, decision.selected, {
|
|
84968
|
-
unavailableReason,
|
|
84969
|
-
nativeSource: nativeSource && nativeSource !== "provider-native" ? nativeSource : void 0
|
|
84970
|
-
});
|
|
84971
|
-
const ptyStatusApprovalOnly = decision.selected === "native-history" ? true : args.ptyStatusApprovalOnly;
|
|
84972
|
-
const messageSource = buildCliMessageSourceProvenance({
|
|
84973
|
-
selected: decision.selected,
|
|
84974
|
-
provider: args.providerType,
|
|
84975
|
-
nativeHandle,
|
|
84976
|
-
sessionWorkspace: args.sessionWorkspace,
|
|
84977
|
-
intendedWorkspace: args.intendedWorkspace,
|
|
84978
|
-
transcriptWorkspace,
|
|
84979
|
-
fallbackReason,
|
|
84980
|
-
nativeSource,
|
|
84981
|
-
sourcePath,
|
|
84982
|
-
sourceMtimeMs,
|
|
84983
|
-
nativeHistoryCoverage: coverageHint,
|
|
84984
|
-
partialReason,
|
|
84985
|
-
unavailableReason,
|
|
84986
|
-
nativeMessages,
|
|
84987
|
-
ptyMessages: args.ptyMessages,
|
|
84988
|
-
returnedMessages: decision.selected === "native-history" ? nativeMessages : args.ptyMessages,
|
|
84989
|
-
safeMapping: args.safeMapping,
|
|
84990
|
-
// freshEnough is a v1 concept the machine does not model directly.
|
|
84991
|
-
// We surface lockState.locked here so v1 consumers reading
|
|
84992
|
-
// staleness.freshEnough still get a meaningful boolean.
|
|
84993
|
-
freshEnough: decision.lockState.locked,
|
|
84994
|
-
ptyStatusApprovalOnly
|
|
84995
|
-
});
|
|
84996
|
-
return {
|
|
84997
|
-
decision,
|
|
84998
|
-
messageSource,
|
|
84999
|
-
nativeMessages,
|
|
85000
|
-
nativeSelected: decision.selected === "native-history"
|
|
85001
|
-
};
|
|
85002
|
-
}
|
|
85003
|
-
function buildObservationForCli(args, supportsNative) {
|
|
85004
|
-
if (!supportsNative) {
|
|
85005
|
-
return { kind: "native_unavailable", reason: "provider_not_supported" };
|
|
85006
|
-
}
|
|
85007
|
-
if (args.nativeHistoryError) {
|
|
85008
|
-
return { kind: "native_unavailable", reason: "read_error" };
|
|
85009
|
-
}
|
|
85010
|
-
const result = args.nativeHistoryResult;
|
|
85011
|
-
if (!result || typeof result !== "object") {
|
|
85012
|
-
return { kind: "native_unavailable", reason: "read_error" };
|
|
85013
|
-
}
|
|
85014
|
-
const source = typeof result.source === "string" ? result.source : "";
|
|
85015
|
-
if (source && source !== "provider-native") {
|
|
85016
|
-
return { kind: "native_unavailable", reason: source === "native-unavailable" ? "empty" : "not_native_source" };
|
|
85017
|
-
}
|
|
85018
|
-
const messages = Array.isArray(result.messages) ? result.messages : [];
|
|
85019
|
-
if (messages.length === 0) {
|
|
85020
|
-
return { kind: "native_unavailable", reason: "empty" };
|
|
85021
|
-
}
|
|
85022
|
-
const coverage = typeof result.nativeHistoryCoverage === "string" ? result.nativeHistoryCoverage : "tail";
|
|
85023
|
-
if (coverage === "unavailable") {
|
|
85024
|
-
return { kind: "native_unavailable", reason: "coverage_unavailable" };
|
|
85025
|
-
}
|
|
85026
|
-
return buildV1NativePresentObservation({
|
|
85027
|
-
providerType: args.providerType,
|
|
85028
|
-
sessionId: args.sessionId,
|
|
85029
|
-
messages,
|
|
85030
|
-
coverage: coverage === "full" || coverage === "tail" || coverage === "current-turn" || coverage === "partial" ? coverage : "tail",
|
|
85031
|
-
safeMapping: args.safeMapping
|
|
85032
|
-
});
|
|
85033
|
-
}
|
|
85034
|
-
function extractNativeMessagesFromResult(providerType, result) {
|
|
85035
|
-
if (!result || !Array.isArray(result.messages)) return [];
|
|
85036
|
-
return normalizeNativeHistoryMessages(
|
|
85037
|
-
providerType,
|
|
85038
|
-
result.messages,
|
|
85039
|
-
typeof result.providerSessionId === "string" ? result.providerSessionId : void 0
|
|
85040
|
-
);
|
|
85041
|
-
}
|
|
85042
85410
|
function applyUnsafeNativeDaemonFallback(args) {
|
|
85043
85411
|
if (args.adapter.cliType !== "codex-cli") {
|
|
85044
85412
|
return;
|
|
@@ -85210,16 +85578,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85210
85578
|
const start = Math.max(0, end - args.limit);
|
|
85211
85579
|
return { messages: ptyMessages.slice(start, end), hasMore: start > 0 };
|
|
85212
85580
|
}
|
|
85213
|
-
function supportsCliNativeTranscript(providerType, provider) {
|
|
85214
|
-
if (provider?.category === "cli" && isNativeSourceCanonicalHistory(provider?.nativeHistory)) {
|
|
85215
|
-
return true;
|
|
85216
|
-
}
|
|
85217
|
-
if (CLI_NATIVE_TRANSCRIPT_PROVIDERS.has(providerType)) {
|
|
85218
|
-
warnLegacyNativeAllowlistHit(providerType);
|
|
85219
|
-
return true;
|
|
85220
|
-
}
|
|
85221
|
-
return false;
|
|
85222
|
-
}
|
|
85223
85581
|
function getComparableVisibleText(message) {
|
|
85224
85582
|
if (!message) return "";
|
|
85225
85583
|
const role = String(message.role || "").trim().toLowerCase();
|
|
@@ -85352,22 +85710,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85352
85710
|
});
|
|
85353
85711
|
return { ...history, lookup: "workspace" };
|
|
85354
85712
|
}
|
|
85355
|
-
function shouldPreserveReadChatPayloadField(key2) {
|
|
85356
|
-
return key2 === "messageSource" || key2 === "transcriptProvenance";
|
|
85357
|
-
}
|
|
85358
|
-
function updateMessageSourceReturnedCount(value, returnedMessageCount) {
|
|
85359
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
85360
|
-
const record2 = value;
|
|
85361
|
-
const coverage = record2.coverage && typeof record2.coverage === "object" && !Array.isArray(record2.coverage) ? record2.coverage : void 0;
|
|
85362
|
-
if (!coverage) return value;
|
|
85363
|
-
return {
|
|
85364
|
-
...record2,
|
|
85365
|
-
coverage: {
|
|
85366
|
-
...coverage,
|
|
85367
|
-
returnedMessageCount
|
|
85368
|
-
}
|
|
85369
|
-
};
|
|
85370
|
-
}
|
|
85371
85713
|
function deriveHistoryDedupKey(message) {
|
|
85372
85714
|
const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
|
|
85373
85715
|
if (unitKey) return `read_chat:${unitKey}`;
|
|
@@ -85391,37 +85733,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85391
85733
|
historyDedupKey: deriveHistoryDedupKey(message)
|
|
85392
85734
|
}));
|
|
85393
85735
|
}
|
|
85394
|
-
function buildFullTail(messages, tailLimit) {
|
|
85395
|
-
const totalMessages = messages.length;
|
|
85396
|
-
const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
|
|
85397
|
-
return {
|
|
85398
|
-
messages: tailMessages,
|
|
85399
|
-
totalMessages
|
|
85400
|
-
};
|
|
85401
|
-
}
|
|
85402
|
-
function hasNonEmptyModalButtons(activeModal) {
|
|
85403
|
-
if (!activeModal || typeof activeModal !== "object") return false;
|
|
85404
|
-
const buttons = activeModal.buttons;
|
|
85405
|
-
return Array.isArray(buttons) && buttons.some((button) => typeof button === "string" && button.trim().length > 0);
|
|
85406
|
-
}
|
|
85407
|
-
function normalizeReadChatCommandStatus(status, activeModal) {
|
|
85408
|
-
const raw = typeof status === "string" ? status.trim() : "";
|
|
85409
|
-
if (!raw) {
|
|
85410
|
-
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "idle";
|
|
85411
|
-
}
|
|
85412
|
-
switch (raw) {
|
|
85413
|
-
case "starting":
|
|
85414
|
-
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "starting";
|
|
85415
|
-
case "stopped":
|
|
85416
|
-
case "disconnected":
|
|
85417
|
-
case "not_monitored":
|
|
85418
|
-
return "error";
|
|
85419
|
-
case "waiting_approval":
|
|
85420
|
-
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "generating";
|
|
85421
|
-
default:
|
|
85422
|
-
return raw;
|
|
85423
|
-
}
|
|
85424
|
-
}
|
|
85425
85736
|
function isGeneratingLikeStatus(status) {
|
|
85426
85737
|
return status === "generating" || status === "streaming" || status === "no_progress" || status === "long_generating" || status === "starting";
|
|
85427
85738
|
}
|
|
@@ -85461,110 +85772,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85461
85772
|
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
85462
85773
|
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
85463
85774
|
}
|
|
85464
|
-
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
85465
|
-
if (status !== "idle") return messages;
|
|
85466
|
-
return messages.map((message) => {
|
|
85467
|
-
const meta3 = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
85468
|
-
const hasStreamingMeta = meta3?.streaming === true;
|
|
85469
|
-
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
85470
|
-
return {
|
|
85471
|
-
...message,
|
|
85472
|
-
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
85473
|
-
...hasStreamingMeta ? { meta: { ...meta3, streaming: false } } : {}
|
|
85474
|
-
};
|
|
85475
|
-
});
|
|
85476
|
-
}
|
|
85477
|
-
function collapseAdjacentDuplicateChatMessages(messages) {
|
|
85478
|
-
if (!Array.isArray(messages) || messages.length <= 1) return messages;
|
|
85479
|
-
const result = [];
|
|
85480
|
-
let prevRoleKind = "";
|
|
85481
|
-
let prevStripped = "";
|
|
85482
|
-
for (const message of messages) {
|
|
85483
|
-
const role = typeof message.role === "string" ? message.role : "";
|
|
85484
|
-
const kind = typeof message.kind === "string" ? message.kind : "standard";
|
|
85485
|
-
const content = typeof message.content === "string" ? message.content : Array.isArray(message.content) ? message.content.map((p) => typeof p?.text === "string" ? p.text : "").join("") : "";
|
|
85486
|
-
const strippedContent = content.replace(/\s+/g, "");
|
|
85487
|
-
if (!strippedContent || role === "system") {
|
|
85488
|
-
result.push(message);
|
|
85489
|
-
prevRoleKind = "";
|
|
85490
|
-
prevStripped = "";
|
|
85491
|
-
continue;
|
|
85492
|
-
}
|
|
85493
|
-
const roleKind = `${role}:${kind}`;
|
|
85494
|
-
const sameStripped = strippedContent === prevStripped && roleKind === prevRoleKind;
|
|
85495
|
-
if (result.length > 0 && sameStripped) {
|
|
85496
|
-
result[result.length - 1] = message;
|
|
85497
|
-
prevRoleKind = roleKind;
|
|
85498
|
-
prevStripped = strippedContent;
|
|
85499
|
-
continue;
|
|
85500
|
-
}
|
|
85501
|
-
result.push(message);
|
|
85502
|
-
prevRoleKind = roleKind;
|
|
85503
|
-
prevStripped = strippedContent;
|
|
85504
|
-
}
|
|
85505
|
-
return result;
|
|
85506
|
-
}
|
|
85507
|
-
function buildReadChatCommandResult(payload, args, h) {
|
|
85508
|
-
let validatedPayload;
|
|
85509
|
-
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
85510
|
-
const presentationSessionIdHint = typeof args?.targetSessionId === "string" && args.targetSessionId.trim() ? args.targetSessionId.trim() : typeof args?.sessionId === "string" && args.sessionId.trim() ? args.sessionId.trim() : typeof h?.currentSession?.sessionId === "string" ? String(h.currentSession.sessionId) : "";
|
|
85511
|
-
const providerHint = typeof args?.cliType === "string" ? args.cliType : typeof args?.providerType === "string" ? args.providerType : typeof args?.agentType === "string" ? args.agentType : "";
|
|
85512
|
-
const legacyStatus = normalizeReadChatCommandStatus(payload?.status, payload?.activeModal);
|
|
85513
|
-
const turnPresentation = resolveSessionTurnPresentation({
|
|
85514
|
-
sessionId: presentationSessionIdHint || void 0,
|
|
85515
|
-
legacyStatus,
|
|
85516
|
-
providerType: providerHint || void 0,
|
|
85517
|
-
surface: "read_chat"
|
|
85518
|
-
});
|
|
85519
|
-
let effectiveStatus = legacyStatus;
|
|
85520
|
-
if (turnPresentation.authority === "turn_reducer") {
|
|
85521
|
-
effectiveStatus = turnPresentation.status;
|
|
85522
|
-
if (effectiveStatus === "waiting_approval" && !hasNonEmptyModalButtons(payload?.activeModal)) {
|
|
85523
|
-
effectiveStatus = "generating";
|
|
85524
|
-
}
|
|
85525
|
-
}
|
|
85526
|
-
try {
|
|
85527
|
-
validatedPayload = validateReadChatResultPayload({
|
|
85528
|
-
...payload,
|
|
85529
|
-
status: effectiveStatus
|
|
85530
|
-
}, "read_chat command result");
|
|
85531
|
-
} catch (error48) {
|
|
85532
|
-
return { success: false, error: error48?.message || String(error48) };
|
|
85533
|
-
}
|
|
85534
|
-
const messages = normalizeReadChatMessages(validatedPayload);
|
|
85535
|
-
const sessionIdHint = typeof args?.targetSessionId === "string" ? args.targetSessionId : typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
85536
|
-
const filteredMessages = h ? maybeHideCoordinatorPromptMessage(h, providerHint, sessionIdHint, messages) : messages;
|
|
85537
|
-
const includeActivity = args?.includeActivity === true || args?.includeActivity === "true";
|
|
85538
|
-
const visibleMessages = includeActivity ? filteredMessages.filter((m) => isUserFacingChatMessage(m) || isActivityChatMessage(m)) : filterUserFacingChatMessages(filteredMessages);
|
|
85539
|
-
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
85540
|
-
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
85541
|
-
const preservedPayloadFields = Object.fromEntries(Object.entries(payload).filter(([key2]) => shouldPreserveReadChatPayloadField(key2)));
|
|
85542
|
-
if (preservedPayloadFields.messageSource) {
|
|
85543
|
-
preservedPayloadFields.messageSource = updateMessageSourceReturnedCount(preservedPayloadFields.messageSource, sync.messages.length);
|
|
85544
|
-
}
|
|
85545
|
-
if (preservedPayloadFields.transcriptProvenance) {
|
|
85546
|
-
preservedPayloadFields.transcriptProvenance = updateMessageSourceReturnedCount(preservedPayloadFields.transcriptProvenance, sync.messages.length);
|
|
85547
|
-
}
|
|
85548
|
-
const returnedDebugReadChat = debugReadChat ? {
|
|
85549
|
-
...debugReadChat,
|
|
85550
|
-
fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
|
|
85551
|
-
visibleMsgCount: visibleMessages.length,
|
|
85552
|
-
hiddenMsgCount,
|
|
85553
|
-
returnedMsgCount: sync.messages.length
|
|
85554
|
-
} : void 0;
|
|
85555
|
-
return {
|
|
85556
|
-
success: true,
|
|
85557
|
-
...validatedPayload,
|
|
85558
|
-
...preservedPayloadFields,
|
|
85559
|
-
messages: sync.messages,
|
|
85560
|
-
totalMessages: sync.totalMessages,
|
|
85561
|
-
// Stage 6: the authoritative turn presentation rides the read_chat
|
|
85562
|
-
// payload for mesh-owned sessions (identity + stage + evidence
|
|
85563
|
-
// timestamps; the `status` field above already reflects it).
|
|
85564
|
-
...turnPresentation.authority === "turn_reducer" ? { turn: turnPresentation } : {},
|
|
85565
|
-
...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
|
|
85566
|
-
};
|
|
85567
|
-
}
|
|
85568
85775
|
function toNonNegativeNumber(value) {
|
|
85569
85776
|
const numeric = Number(value ?? 0);
|
|
85570
85777
|
return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
|
|
@@ -95473,7 +95680,7 @@ ${marker}`,
|
|
|
95473
95680
|
LOG2.warn("spec-route", `[${provider.type}] spec invalid, falling back to ProviderCliAdapter: ${err.message}`);
|
|
95474
95681
|
}
|
|
95475
95682
|
}
|
|
95476
|
-
return new ProviderCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFactory);
|
|
95683
|
+
return new ProviderCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFactory, sessionId);
|
|
95477
95684
|
}
|
|
95478
95685
|
init_chat_history();
|
|
95479
95686
|
init_logger();
|
|
@@ -102801,7 +103008,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
102801
103008
|
const { shouldDeferDispatchForBootstrap: shouldDeferDispatchForBootstrap2 } = await Promise.resolve().then(() => (init_worktree_bootstrap_config(), worktree_bootstrap_config_exports));
|
|
102802
103009
|
if (shouldDeferDispatchForBootstrap2(nodeObj)) {
|
|
102803
103010
|
const dispatchSessionState = dispatchSessionId ? ctx.deps.instanceManager?.getInstance?.(dispatchSessionId)?.getState?.() : void 0;
|
|
102804
|
-
const sessionConfirmedReady = !!dispatchSessionState &&
|
|
103011
|
+
const sessionConfirmedReady = !!dispatchSessionState && isIdleSessionState2(dispatchSessionState);
|
|
102805
103012
|
if (!sessionConfirmedReady) {
|
|
102806
103013
|
return {
|
|
102807
103014
|
success: false,
|
|
@@ -124411,8 +124618,9 @@ data: ${JSON.stringify(msg.data)}
|
|
|
124411
124618
|
if (event.type === "session_exit") {
|
|
124412
124619
|
const exitCode = typeof event.exitCode === "number" ? event.exitCode : null;
|
|
124413
124620
|
const signal = typeof event.signal === "number" ? event.signal : null;
|
|
124621
|
+
const termination = event.termination;
|
|
124414
124622
|
for (const callback of this.exitCallbacks) {
|
|
124415
|
-
callback({ exitCode, signal });
|
|
124623
|
+
callback({ exitCode, signal, termination });
|
|
124416
124624
|
}
|
|
124417
124625
|
void this.closeClient(false);
|
|
124418
124626
|
}
|