@adhdev/daemon-standalone 1.0.43 → 1.0.44-rc.2
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 +1495 -1131
- 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 +7 -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 ? "648305378fc7e0a1970cfe964a80ce7a68172964" : void 0) ?? "unknown";
|
|
36560
|
+
const commitShort = readInjected(true ? "64830537" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
36561
|
+
const version2 = readInjected(true ? "1.0.44-rc.2" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
36562
|
+
const builtAt = readInjected(true ? "2026-08-11T08:23:49.936Z" : 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"];
|
|
@@ -45707,14 +45717,60 @@ Next step: ${nextStep}`;
|
|
|
45707
45717
|
const reconciled = terminalJobIds.size === 0 ? events : events.filter((event) => !(event.event === "refine:accepted" && terminalJobIds.has(readRefineJobId2(event))));
|
|
45708
45718
|
return backfilled.length === 0 ? reconciled : [...reconciled, ...backfilled];
|
|
45709
45719
|
}
|
|
45720
|
+
function getPendingRetentionCounters() {
|
|
45721
|
+
return { ...pendingRetentionCounters };
|
|
45722
|
+
}
|
|
45723
|
+
function ledgerRecordExpiredUndrainedEvent(row) {
|
|
45724
|
+
try {
|
|
45725
|
+
const restored = row.payload && typeof row.payload === "object" ? row.payload : void 0;
|
|
45726
|
+
const finalSummary = restored?.metadataEvent ? readMeshCompletionSummary(restored.metadataEvent) : void 0;
|
|
45727
|
+
appendLedgerEntry(row.meshId, {
|
|
45728
|
+
kind: "event_held",
|
|
45729
|
+
...restored?.nodeId ? { nodeId: restored.nodeId } : {},
|
|
45730
|
+
payload: {
|
|
45731
|
+
event: row.event,
|
|
45732
|
+
reason: PENDING_RETENTION_EXPIRED_HOLD_REASON,
|
|
45733
|
+
recoverable: true,
|
|
45734
|
+
nodeLabel: restored?.nodeLabel ?? "",
|
|
45735
|
+
...restored?.workspace ? { workspace: restored.workspace } : {},
|
|
45736
|
+
targetCoordinatorDaemonId: restored?.targetCoordinatorDaemonId ?? null,
|
|
45737
|
+
...readNonEmptyString(restored?.eventId) ? { eventId: restored.eventId } : {},
|
|
45738
|
+
queuedAt: restored?.queuedAt ?? null,
|
|
45739
|
+
...finalSummary ? { finalSummary } : {},
|
|
45740
|
+
// Full original event so mesh_requeue_held_events can restore it
|
|
45741
|
+
// losslessly (event_held→pending), same as every other event_held feeder.
|
|
45742
|
+
...restored ? { heldEvent: restored } : {}
|
|
45743
|
+
}
|
|
45744
|
+
});
|
|
45745
|
+
} catch (e) {
|
|
45746
|
+
pendingRetentionCounters.undrainedExpiredMirrorFailed++;
|
|
45747
|
+
LOG2.warn("MeshEvents", `Failed to ledger-record retention-expired pending event ${row.event} (row ${row.id}, mesh ${row.meshId}) \u2014 it is being deleted UNRECOVERABLY: ${e?.message || e}`);
|
|
45748
|
+
}
|
|
45749
|
+
}
|
|
45710
45750
|
function prunePendingMeshCoordinatorEventsRetention() {
|
|
45711
45751
|
try {
|
|
45712
|
-
const
|
|
45752
|
+
const { drainedExpired, undrainedExpired, undrainedRows } = MeshRuntimeStore.getInstance().prunePendingEvents({
|
|
45713
45753
|
drainedOlderThanMs: PENDING_EVENTS_DRAINED_RETENTION_MS,
|
|
45714
45754
|
undrainedOlderThanMs: PENDING_EVENTS_UNDRAINED_RETENTION_MS
|
|
45715
45755
|
});
|
|
45756
|
+
pendingRetentionCounters.drainedExpired += drainedExpired;
|
|
45757
|
+
pendingRetentionCounters.undrainedExpired += undrainedExpired;
|
|
45758
|
+
if (undrainedRows.length > 0) {
|
|
45759
|
+
for (const row of undrainedRows) {
|
|
45760
|
+
ledgerRecordExpiredUndrainedEvent(row);
|
|
45761
|
+
}
|
|
45762
|
+
const meshIds = [...new Set(undrainedRows.map((r) => r.meshId))];
|
|
45763
|
+
const droppedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
45764
|
+
LOG2.warn(
|
|
45765
|
+
"MeshEvents",
|
|
45766
|
+
`Pending-event retention DROPPED ${undrainedRows.length} never-delivered event(s) at ${droppedAt} (queued >30d, still undrained) across mesh(es) ${meshIds.join(", ")} \u2014 mirrored to the ledger as event_held (reason: ${PENDING_RETENTION_EXPIRED_HOLD_REASON}); recover with mesh_requeue_held_events.`
|
|
45767
|
+
);
|
|
45768
|
+
}
|
|
45769
|
+
const removed = drainedExpired + undrainedExpired;
|
|
45716
45770
|
if (removed > 0) {
|
|
45717
45771
|
LOG2.info("MeshEvents", `Pruned ${removed} stale pending-event row(s) (drained >7d / undrained >30d)`);
|
|
45772
|
+
} else {
|
|
45773
|
+
pendingRetentionCounters.sweepsNoop++;
|
|
45718
45774
|
}
|
|
45719
45775
|
return removed;
|
|
45720
45776
|
} catch (e) {
|
|
@@ -46043,6 +46099,8 @@ Next step: ${nextStep}`;
|
|
|
46043
46099
|
var TERMINAL_COMPLETION_EVENTS;
|
|
46044
46100
|
var PENDING_EVENTS_DRAINED_RETENTION_MS;
|
|
46045
46101
|
var PENDING_EVENTS_UNDRAINED_RETENTION_MS;
|
|
46102
|
+
var PENDING_RETENTION_EXPIRED_HOLD_REASON;
|
|
46103
|
+
var pendingRetentionCounters;
|
|
46046
46104
|
var init_mesh_events_pending = __esm2({
|
|
46047
46105
|
"src/mesh/mesh-events-pending.ts"() {
|
|
46048
46106
|
"use strict";
|
|
@@ -46091,6 +46149,22 @@ Next step: ${nextStep}`;
|
|
|
46091
46149
|
TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
|
|
46092
46150
|
PENDING_EVENTS_DRAINED_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
46093
46151
|
PENDING_EVENTS_UNDRAINED_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
46152
|
+
PENDING_RETENTION_EXPIRED_HOLD_REASON = "pending_retention_expired";
|
|
46153
|
+
pendingRetentionCounters = {
|
|
46154
|
+
/** Already-drained rows deleted past the 7-day dedup-useful window. Not a drop. */
|
|
46155
|
+
drainedExpired: 0,
|
|
46156
|
+
/** Never-delivered rows deleted past the 30-day undrained window. A genuine
|
|
46157
|
+
* silent-drop risk — mirrored to event_held before deletion (see below). */
|
|
46158
|
+
undrainedExpired: 0,
|
|
46159
|
+
/** undrainedExpired rows that failed to mirror to the ledger (ledger write threw).
|
|
46160
|
+
* Non-zero here means those specific rows are NOT recoverable via
|
|
46161
|
+
* mesh_requeue_held_events — the delete still proceeds (retention must not wedge
|
|
46162
|
+
* on a ledger fault), but this count is the operator's signal of true loss. */
|
|
46163
|
+
undrainedExpiredMirrorFailed: 0,
|
|
46164
|
+
/** How many times the sweep has run and found nothing to prune (0 in both
|
|
46165
|
+
* windows). Purely diagnostic — confirms the sweep is actually firing. */
|
|
46166
|
+
sweepsNoop: 0
|
|
46167
|
+
};
|
|
46094
46168
|
}
|
|
46095
46169
|
});
|
|
46096
46170
|
var mesh_missions_exports = {};
|
|
@@ -49828,21 +49902,43 @@ Next step: ${nextStep}`;
|
|
|
49828
49902
|
* receives its backlog; only genuinely unrecoverable orphans are swept.
|
|
49829
49903
|
*
|
|
49830
49904
|
* Both windows key off `queued_at` (always present) — `drained_at` can be NULL on
|
|
49831
|
-
* legacy rows. Returns the number of rows deleted
|
|
49832
|
-
*
|
|
49905
|
+
* legacy rows. Returns the number of rows deleted, split by which window matched:
|
|
49906
|
+
* `drainedExpired` (already-delivered rows past the dedup-useful window — not a
|
|
49907
|
+
* drop, the coordinator already got these) and `undrainedExpired` (rows that were
|
|
49908
|
+
* NEVER delivered — a genuine silent drop, same shape as the retired JSONL trim's
|
|
49909
|
+
* `pending_trim_dropped`). `undrainedRows` carries the id/meshId/event/payload of
|
|
49910
|
+
* every undrained-expired row BEFORE deletion so the caller can mirror it to the
|
|
49911
|
+
* mesh ledger as `event_held` (recoverable via mesh_requeue_held_events) instead of
|
|
49912
|
+
* losing it silently — this is the observability gap the retired trim used to cover
|
|
49913
|
+
* and the SQLite-only cutover left open. Best-effort / idempotent: running it
|
|
49914
|
+
* repeatedly with nothing to prune is a cheap no-op.
|
|
49833
49915
|
*/
|
|
49834
49916
|
prunePendingEvents(opts) {
|
|
49835
49917
|
const now = Date.now();
|
|
49836
49918
|
const drainedCutoff = now - Math.max(0, opts.drainedOlderThanMs);
|
|
49837
49919
|
const undrainedCutoff = now - Math.max(0, opts.undrainedOlderThanMs);
|
|
49838
|
-
|
|
49839
|
-
|
|
49920
|
+
const undrainedSelectRows = this.db.prepare(
|
|
49921
|
+
"SELECT id, mesh_id, event, payload FROM mesh_pending_events WHERE drained = 0 AND queued_at < ?"
|
|
49922
|
+
).all(undrainedCutoff);
|
|
49923
|
+
const undrainedRows = undrainedSelectRows.map((r) => ({
|
|
49924
|
+
id: r.id,
|
|
49925
|
+
meshId: r.mesh_id,
|
|
49926
|
+
event: r.event,
|
|
49927
|
+
payload: (() => {
|
|
49928
|
+
try {
|
|
49929
|
+
return JSON.parse(r.payload);
|
|
49930
|
+
} catch {
|
|
49931
|
+
return {};
|
|
49932
|
+
}
|
|
49933
|
+
})()
|
|
49934
|
+
}));
|
|
49935
|
+
const drainedExpired = this.db.prepare(
|
|
49840
49936
|
"DELETE FROM mesh_pending_events WHERE drained = 1 AND queued_at < ?"
|
|
49841
49937
|
).run(drainedCutoff).changes;
|
|
49842
|
-
|
|
49938
|
+
const undrainedExpired = this.db.prepare(
|
|
49843
49939
|
"DELETE FROM mesh_pending_events WHERE drained = 0 AND queued_at < ?"
|
|
49844
49940
|
).run(undrainedCutoff).changes;
|
|
49845
|
-
return
|
|
49941
|
+
return { drainedExpired, undrainedExpired, undrainedRows };
|
|
49846
49942
|
}
|
|
49847
49943
|
// ── TURN-LEDGER (Stage 5): authoritative turn attempts ───────────────────
|
|
49848
49944
|
/**
|
|
@@ -59943,6 +60039,332 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
59943
60039
|
PROVIDER_QUOTA_WEEKLY_LOW_SKIP_REASON = "provider_quota_weekly_low";
|
|
59944
60040
|
}
|
|
59945
60041
|
});
|
|
60042
|
+
function isAnthropicProvider(providerType) {
|
|
60043
|
+
const p = typeof providerType === "string" ? providerType.trim().toLowerCase() : "";
|
|
60044
|
+
return p.length > 0 && ANTHROPIC_PROVIDER_TYPES.has(p);
|
|
60045
|
+
}
|
|
60046
|
+
function isAnthropicModel(model) {
|
|
60047
|
+
const m = typeof model === "string" ? model.trim().toLowerCase() : "";
|
|
60048
|
+
if (!m) return false;
|
|
60049
|
+
if (m.startsWith("claude") || m.startsWith("anthropic")) return true;
|
|
60050
|
+
return /^(opus|sonnet|haiku)(\b|[-_])/.test(m);
|
|
60051
|
+
}
|
|
60052
|
+
function isModelCompatibleWithProvider(model, providerType) {
|
|
60053
|
+
if (!isAnthropicModel(model)) return true;
|
|
60054
|
+
if (isAnthropicProvider(providerType)) return true;
|
|
60055
|
+
return false;
|
|
60056
|
+
}
|
|
60057
|
+
var ANTHROPIC_PROVIDER_TYPES;
|
|
60058
|
+
var init_model_provider_compat = __esm2({
|
|
60059
|
+
"src/mesh/model-provider-compat.ts"() {
|
|
60060
|
+
"use strict";
|
|
60061
|
+
ANTHROPIC_PROVIDER_TYPES = /* @__PURE__ */ new Set([
|
|
60062
|
+
"claude-cli"
|
|
60063
|
+
]);
|
|
60064
|
+
}
|
|
60065
|
+
});
|
|
60066
|
+
function encodeDuplicateMeshDispatchCode(holderSessionId) {
|
|
60067
|
+
const holder = typeof holderSessionId === "string" ? holderSessionId.trim() : "";
|
|
60068
|
+
return holder ? `${DUPLICATE_MESH_DISPATCH_CODE}:${holder}` : DUPLICATE_MESH_DISPATCH_CODE;
|
|
60069
|
+
}
|
|
60070
|
+
function classifyDuplicateMeshDispatch(err) {
|
|
60071
|
+
if (!err || typeof err !== "object") return null;
|
|
60072
|
+
const e = err;
|
|
60073
|
+
if (e.code === DUPLICATE_MESH_DISPATCH_CODE) {
|
|
60074
|
+
const holder = typeof e.holderSessionId === "string" ? e.holderSessionId.trim() : "";
|
|
60075
|
+
return holder ? { holderSessionId: holder } : {};
|
|
60076
|
+
}
|
|
60077
|
+
for (const raw of [e.meshCode, e.code]) {
|
|
60078
|
+
if (typeof raw !== "string") continue;
|
|
60079
|
+
if (raw !== DUPLICATE_MESH_DISPATCH_CODE && !raw.startsWith(`${DUPLICATE_MESH_DISPATCH_CODE}:`)) continue;
|
|
60080
|
+
const holder = raw.slice(DUPLICATE_MESH_DISPATCH_CODE.length + 1).trim();
|
|
60081
|
+
return holder ? { holderSessionId: holder } : {};
|
|
60082
|
+
}
|
|
60083
|
+
return null;
|
|
60084
|
+
}
|
|
60085
|
+
var DUPLICATE_MESH_DISPATCH_CODE;
|
|
60086
|
+
var DuplicateMeshDispatchError;
|
|
60087
|
+
var init_mesh_duplicate_dispatch = __esm2({
|
|
60088
|
+
"src/mesh/mesh-duplicate-dispatch.ts"() {
|
|
60089
|
+
"use strict";
|
|
60090
|
+
DUPLICATE_MESH_DISPATCH_CODE = "DUPLICATE_MESH_DISPATCH";
|
|
60091
|
+
DuplicateMeshDispatchError = class extends Error {
|
|
60092
|
+
code = DUPLICATE_MESH_DISPATCH_CODE;
|
|
60093
|
+
holderSessionId;
|
|
60094
|
+
constructor(message, info = {}) {
|
|
60095
|
+
super(message);
|
|
60096
|
+
this.name = "DuplicateMeshDispatchError";
|
|
60097
|
+
this.holderSessionId = info.holderSessionId;
|
|
60098
|
+
}
|
|
60099
|
+
};
|
|
60100
|
+
}
|
|
60101
|
+
});
|
|
60102
|
+
function acquireAutoFastForwardLease(workspace) {
|
|
60103
|
+
const key2 = normalizeMeshWorkspaceForCompare(workspace);
|
|
60104
|
+
if (!key2) return false;
|
|
60105
|
+
if (autoFastForwardWorkspaceLease.has(key2)) return false;
|
|
60106
|
+
autoFastForwardWorkspaceLease.add(key2);
|
|
60107
|
+
return true;
|
|
60108
|
+
}
|
|
60109
|
+
function releaseAutoFastForwardLease(workspace) {
|
|
60110
|
+
const key2 = normalizeMeshWorkspaceForCompare(workspace);
|
|
60111
|
+
if (key2) autoFastForwardWorkspaceLease.delete(key2);
|
|
60112
|
+
}
|
|
60113
|
+
function isWorkspaceAutoFastForwardInFlight(workspace) {
|
|
60114
|
+
const key2 = normalizeMeshWorkspaceForCompare(workspace || "");
|
|
60115
|
+
return !!key2 && autoFastForwardWorkspaceLease.has(key2);
|
|
60116
|
+
}
|
|
60117
|
+
function __resetIdleAutoFastForwardForTests() {
|
|
60118
|
+
idleAutoFastForwardLastAttempt.clear();
|
|
60119
|
+
continuousAutoFastForwardLastScan.clear();
|
|
60120
|
+
autoFastForwardWorkspaceLease.clear();
|
|
60121
|
+
}
|
|
60122
|
+
function isDirtyNode(node) {
|
|
60123
|
+
return node?.health === "dirty" || node?.git?.dirty === true;
|
|
60124
|
+
}
|
|
60125
|
+
function resolveAutoFastForwardPolicy(mesh) {
|
|
60126
|
+
const record2 = mesh?.policy?.autoFastForward && typeof mesh.policy.autoFastForward === "object" && !Array.isArray(mesh.policy.autoFastForward) ? mesh.policy.autoFastForward : {};
|
|
60127
|
+
const maxBehind = Number(record2.maxBehind);
|
|
60128
|
+
return {
|
|
60129
|
+
enabled: record2.enabled !== false,
|
|
60130
|
+
...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
|
|
60131
|
+
requireCleanSubmodules: record2.requireCleanSubmodules !== false,
|
|
60132
|
+
// Strict opt-in: absent/false → self-only (historical behavior). Only an
|
|
60133
|
+
// explicit `true` extends auto ff to remote owning-daemon nodes.
|
|
60134
|
+
remoteNodes: record2.remoteNodes === true,
|
|
60135
|
+
// Absent/anything-but-continuous → 'idle' (historical idle-edge-only detection).
|
|
60136
|
+
mode: record2.mode === "continuous" ? "continuous" : "idle"
|
|
60137
|
+
};
|
|
60138
|
+
}
|
|
60139
|
+
function dryRunSatisfiesAutoFastForwardPolicy(dryRun, policy) {
|
|
60140
|
+
if (!dryRun || dryRun.code !== "fast_forward_available" || dryRun.allowed !== true) return false;
|
|
60141
|
+
const behind = Number(dryRun.current?.behind);
|
|
60142
|
+
if (!Number.isFinite(behind) || behind <= 0) return false;
|
|
60143
|
+
if (policy.maxBehind !== void 0 && behind > policy.maxBehind) return false;
|
|
60144
|
+
if (policy.requireCleanSubmodules) {
|
|
60145
|
+
const submodules = Array.isArray(dryRun.current?.submodules) ? dryRun.current.submodules : [];
|
|
60146
|
+
if (submodules.some((submodule) => submodule?.dirty || submodule?.outOfSync || submodule?.error)) return false;
|
|
60147
|
+
}
|
|
60148
|
+
return true;
|
|
60149
|
+
}
|
|
60150
|
+
function readNodeSubmoduleIgnorePaths(node) {
|
|
60151
|
+
return Array.isArray(node?.policy?.submoduleIgnorePaths) ? node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
60152
|
+
}
|
|
60153
|
+
function nodeIsAutoFastForwardEligible(components, meshId, nodeId, node, currentSessionId) {
|
|
60154
|
+
if (!node) return false;
|
|
60155
|
+
if (node.status === "disabled" || node.status === "removed") return false;
|
|
60156
|
+
if (node.readOnly === true || node.policy?.readOnly === true) return false;
|
|
60157
|
+
if (isWorktreeBootstrapStaleRunning(node)) return false;
|
|
60158
|
+
if (node.worktreeBootstrap?.status === "running") return false;
|
|
60159
|
+
if (nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId)) return false;
|
|
60160
|
+
return true;
|
|
60161
|
+
}
|
|
60162
|
+
function remoteNodeIsConnected(components, node) {
|
|
60163
|
+
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
60164
|
+
if (!daemonId) return false;
|
|
60165
|
+
const getPeerStatus = components.getMeshPeerConnectionStatus;
|
|
60166
|
+
if (getPeerStatus) {
|
|
60167
|
+
const snapshot = getPeerStatus(daemonId);
|
|
60168
|
+
return !!snapshot && String(snapshot.state) === "connected";
|
|
60169
|
+
}
|
|
60170
|
+
return readNonEmptyString(node?.connection?.state).toLowerCase() === "connected";
|
|
60171
|
+
}
|
|
60172
|
+
async function delegateRemoteAutoFastForward(components, args) {
|
|
60173
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
60174
|
+
if (!dispatchMeshCommand) return;
|
|
60175
|
+
if (!acquireAutoFastForwardLease(args.workspace)) return;
|
|
60176
|
+
const submoduleIgnorePaths = readNodeSubmoduleIgnorePaths(args.node);
|
|
60177
|
+
const mesh = getMeshWithCache(components, args.meshId);
|
|
60178
|
+
const baseArgs = {
|
|
60179
|
+
meshId: args.meshId,
|
|
60180
|
+
nodeId: args.nodeId,
|
|
60181
|
+
workspace: args.workspace,
|
|
60182
|
+
inlineMesh: mesh,
|
|
60183
|
+
...submoduleIgnorePaths ? { submoduleIgnorePaths } : {},
|
|
60184
|
+
trigger: args.trigger,
|
|
60185
|
+
// Preserve the pre-fix self-only semantics for submodules: the local idle path
|
|
60186
|
+
// never updated submodules (updateSubmodules:false), so the remote path matches.
|
|
60187
|
+
updateSubmodules: false
|
|
60188
|
+
};
|
|
60189
|
+
try {
|
|
60190
|
+
const remoteDry = await dispatchMeshCommand(args.daemonId, "fast_forward_mesh_node", {
|
|
60191
|
+
...baseArgs,
|
|
60192
|
+
execute: false,
|
|
60193
|
+
dryRun: true
|
|
60194
|
+
});
|
|
60195
|
+
if (!dryRunSatisfiesAutoFastForwardPolicy(remoteDry, args.policy)) return;
|
|
60196
|
+
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId)) return;
|
|
60197
|
+
const executed = await dispatchMeshCommand(args.daemonId, "fast_forward_mesh_node", {
|
|
60198
|
+
...baseArgs,
|
|
60199
|
+
execute: true,
|
|
60200
|
+
dryRun: false
|
|
60201
|
+
});
|
|
60202
|
+
if (executed?.executed === true) {
|
|
60203
|
+
LOG2.info("MeshFastForward", `Remote auto fast-forward executed for node ${args.nodeId} (daemon ${String(args.daemonId).slice(0, 12)}, trigger ${args.trigger})`);
|
|
60204
|
+
}
|
|
60205
|
+
} catch (e) {
|
|
60206
|
+
LOG2.warn("MeshFastForward", `Remote auto fast-forward delegation failed for ${args.nodeId}: ${e?.message || e}`);
|
|
60207
|
+
} finally {
|
|
60208
|
+
releaseAutoFastForwardLease(args.workspace);
|
|
60209
|
+
}
|
|
60210
|
+
}
|
|
60211
|
+
async function executeLocalAutoFastForward(args) {
|
|
60212
|
+
if (!acquireAutoFastForwardLease(args.workspace)) return;
|
|
60213
|
+
const submoduleIgnorePaths = readNodeSubmoduleIgnorePaths(args.node);
|
|
60214
|
+
try {
|
|
60215
|
+
const dryRun = await fastForwardMeshNode({
|
|
60216
|
+
meshId: args.meshId,
|
|
60217
|
+
nodeId: args.nodeId,
|
|
60218
|
+
workspace: args.workspace,
|
|
60219
|
+
execute: false,
|
|
60220
|
+
dryRun: true,
|
|
60221
|
+
updateSubmodules: false,
|
|
60222
|
+
submoduleIgnorePaths,
|
|
60223
|
+
trigger: args.trigger
|
|
60224
|
+
});
|
|
60225
|
+
if (!dryRunSatisfiesAutoFastForwardPolicy(dryRun, args.policy)) return;
|
|
60226
|
+
await fastForwardMeshNode({
|
|
60227
|
+
meshId: args.meshId,
|
|
60228
|
+
nodeId: args.nodeId,
|
|
60229
|
+
workspace: args.workspace,
|
|
60230
|
+
execute: true,
|
|
60231
|
+
dryRun: false,
|
|
60232
|
+
updateSubmodules: false,
|
|
60233
|
+
submoduleIgnorePaths,
|
|
60234
|
+
trigger: args.trigger
|
|
60235
|
+
});
|
|
60236
|
+
} catch (e) {
|
|
60237
|
+
LOG2.warn("MeshFastForward", `Idle auto fast-forward check failed for ${args.nodeId}: ${e?.message || e}`);
|
|
60238
|
+
} finally {
|
|
60239
|
+
releaseAutoFastForwardLease(args.workspace);
|
|
60240
|
+
}
|
|
60241
|
+
}
|
|
60242
|
+
async function maybeAutoFastForwardIdleNode(components, args) {
|
|
60243
|
+
const mesh = getMeshWithCache(components, args.meshId);
|
|
60244
|
+
const node = mesh?.nodes?.find((candidate) => meshNodeIdMatches(candidate, args.nodeId));
|
|
60245
|
+
const workspace = readNonEmptyString(node?.workspace);
|
|
60246
|
+
if (!workspace) return;
|
|
60247
|
+
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
60248
|
+
if (!policy.enabled) return;
|
|
60249
|
+
if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
|
|
60250
|
+
const throttleKey = `${args.meshId}:${args.nodeId}`;
|
|
60251
|
+
const now = Date.now();
|
|
60252
|
+
const lastAttempt = idleAutoFastForwardLastAttempt.get(throttleKey) || 0;
|
|
60253
|
+
if (now - lastAttempt < IDLE_AUTO_FAST_FORWARD_THROTTLE_MS) return;
|
|
60254
|
+
idleAutoFastForwardLastAttempt.set(throttleKey, now);
|
|
60255
|
+
if (isLocalAutoLaunchNode(node)) {
|
|
60256
|
+
if (!(0, import_fs14.existsSync)(workspace)) return;
|
|
60257
|
+
await executeLocalAutoFastForward({ meshId: args.meshId, nodeId: args.nodeId, node, workspace, policy, trigger: "idle_auto" });
|
|
60258
|
+
return;
|
|
60259
|
+
}
|
|
60260
|
+
if (!policy.remoteNodes) return;
|
|
60261
|
+
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
60262
|
+
if (!daemonId || !components.dispatchMeshCommand) return;
|
|
60263
|
+
if (!remoteNodeIsConnected(components, node)) return;
|
|
60264
|
+
await delegateRemoteAutoFastForward(components, { meshId: args.meshId, nodeId: args.nodeId, node, daemonId, workspace, policy, trigger: "idle_auto" });
|
|
60265
|
+
}
|
|
60266
|
+
async function runContinuousAutoFastForwardScan(components, mesh) {
|
|
60267
|
+
if (!components.dispatchMeshCommand) return;
|
|
60268
|
+
const policy = resolveAutoFastForwardPolicy(mesh);
|
|
60269
|
+
if (!policy.enabled || !policy.remoteNodes || policy.mode !== "continuous") return;
|
|
60270
|
+
const meshId = readNonEmptyString(mesh?.id);
|
|
60271
|
+
if (!meshId) return;
|
|
60272
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60273
|
+
const now = Date.now();
|
|
60274
|
+
for (const node of nodes) {
|
|
60275
|
+
const nodeId = normalizeMeshNodeId(node);
|
|
60276
|
+
if (!nodeId) continue;
|
|
60277
|
+
if (node?.isLocalWorktree === true) continue;
|
|
60278
|
+
if (isLocalAutoLaunchNode(node)) continue;
|
|
60279
|
+
const workspace = readNonEmptyString(node?.workspace);
|
|
60280
|
+
if (!workspace) continue;
|
|
60281
|
+
const daemonId = readMeshNodeDaemonId(node ?? {});
|
|
60282
|
+
if (!daemonId) continue;
|
|
60283
|
+
if (!nodeIsAutoFastForwardEligible(components, meshId, nodeId, node)) continue;
|
|
60284
|
+
if (!remoteNodeIsConnected(components, node)) continue;
|
|
60285
|
+
const cooldownKey = `${meshId}:${nodeId}`;
|
|
60286
|
+
const lastScan = continuousAutoFastForwardLastScan.get(cooldownKey) || 0;
|
|
60287
|
+
if (now - lastScan < CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS) continue;
|
|
60288
|
+
continuousAutoFastForwardLastScan.set(cooldownKey, now);
|
|
60289
|
+
await delegateRemoteAutoFastForward(components, { meshId, nodeId, node, daemonId, workspace, policy, trigger: "reconcile_auto" });
|
|
60290
|
+
}
|
|
60291
|
+
}
|
|
60292
|
+
async function runPendingCoordinatorCatchupScan(components, mesh) {
|
|
60293
|
+
const meshId = readNonEmptyString(mesh?.id);
|
|
60294
|
+
if (!meshId) return;
|
|
60295
|
+
const localIds = expandDaemonIdForms([
|
|
60296
|
+
readNonEmptyString(components.statusInstanceId),
|
|
60297
|
+
readNonEmptyString(loadConfig2().machineId)
|
|
60298
|
+
]);
|
|
60299
|
+
let markers = [];
|
|
60300
|
+
try {
|
|
60301
|
+
markers = drainPendingMeshCoordinatorEvents(
|
|
60302
|
+
meshId,
|
|
60303
|
+
localIds.length > 0 ? localIds : void 0,
|
|
60304
|
+
{ onlyEvents: /* @__PURE__ */ new Set(["coordinator_catchup"]) }
|
|
60305
|
+
);
|
|
60306
|
+
} catch (e) {
|
|
60307
|
+
LOG2.warn("MeshReconcile", `Coordinator-catchup drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
60308
|
+
return;
|
|
60309
|
+
}
|
|
60310
|
+
if (markers.length === 0) return;
|
|
60311
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60312
|
+
for (const marker of markers) {
|
|
60313
|
+
const meta3 = marker.metadataEvent || {};
|
|
60314
|
+
const nodeId = readNonEmptyString(marker.nodeId) || readNonEmptyString(meta3.nodeId);
|
|
60315
|
+
const workspace = readNonEmptyString(marker.workspace) || readNonEmptyString(meta3.workspace);
|
|
60316
|
+
const baseBranch = readNonEmptyString(meta3.baseBranch);
|
|
60317
|
+
if (!workspace) continue;
|
|
60318
|
+
if (nodeId && nodeHasActiveMeshWork(components, meshId, nodeId)) {
|
|
60319
|
+
try {
|
|
60320
|
+
queuePendingMeshCoordinatorEvent(marker);
|
|
60321
|
+
} catch {
|
|
60322
|
+
}
|
|
60323
|
+
continue;
|
|
60324
|
+
}
|
|
60325
|
+
try {
|
|
60326
|
+
const ff = await fastForwardMeshNode({
|
|
60327
|
+
meshId,
|
|
60328
|
+
...nodeId ? { nodeId } : {},
|
|
60329
|
+
workspace,
|
|
60330
|
+
...baseBranch ? { branch: baseBranch } : {},
|
|
60331
|
+
mode: "merge",
|
|
60332
|
+
execute: true,
|
|
60333
|
+
trigger: "refine_post_push_catchup",
|
|
60334
|
+
allowAutoPublishSubmoduleMainCommits: mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true
|
|
60335
|
+
});
|
|
60336
|
+
LOG2.info("MeshReconcile", `Coordinator catch-up ff for ${meshId}/${nodeId || workspace}: ${ff.code} (executed=${ff.executed})`);
|
|
60337
|
+
} catch (e) {
|
|
60338
|
+
LOG2.warn("MeshReconcile", `Coordinator catch-up ff failed for ${meshId}/${nodeId || workspace}: ${e?.message || e}`);
|
|
60339
|
+
}
|
|
60340
|
+
}
|
|
60341
|
+
}
|
|
60342
|
+
var import_fs14;
|
|
60343
|
+
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS;
|
|
60344
|
+
var idleAutoFastForwardLastAttempt;
|
|
60345
|
+
var CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS;
|
|
60346
|
+
var continuousAutoFastForwardLastScan;
|
|
60347
|
+
var autoFastForwardWorkspaceLease;
|
|
60348
|
+
var init_mesh_auto_fast_forward = __esm2({
|
|
60349
|
+
"src/mesh/mesh-auto-fast-forward.ts"() {
|
|
60350
|
+
"use strict";
|
|
60351
|
+
import_fs14 = require("fs");
|
|
60352
|
+
init_logger();
|
|
60353
|
+
init_config();
|
|
60354
|
+
init_mesh_fast_forward();
|
|
60355
|
+
init_dist();
|
|
60356
|
+
init_mesh_events_utils();
|
|
60357
|
+
init_mesh_node_identity();
|
|
60358
|
+
init_mesh_events_pending();
|
|
60359
|
+
init_worktree_bootstrap_config();
|
|
60360
|
+
init_mesh_queue_assignment();
|
|
60361
|
+
IDLE_AUTO_FAST_FORWARD_THROTTLE_MS = 30 * 60 * 1e3;
|
|
60362
|
+
idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
|
|
60363
|
+
CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS = 45 * 1e3;
|
|
60364
|
+
continuousAutoFastForwardLastScan = /* @__PURE__ */ new Map();
|
|
60365
|
+
autoFastForwardWorkspaceLease = /* @__PURE__ */ new Set();
|
|
60366
|
+
}
|
|
60367
|
+
});
|
|
59946
60368
|
function normalizeNodeIdKey(nodeId) {
|
|
59947
60369
|
return normalizeMeshNodeId({ id: nodeId ?? void 0 }) ?? "";
|
|
59948
60370
|
}
|
|
@@ -59978,88 +60400,407 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
59978
60400
|
MAX_TRACKED_CLONED_NODES = 512;
|
|
59979
60401
|
}
|
|
59980
60402
|
});
|
|
59981
|
-
function
|
|
59982
|
-
|
|
59983
|
-
return
|
|
60403
|
+
function isActionableSkipReason(reason) {
|
|
60404
|
+
if (!reason) return false;
|
|
60405
|
+
return ACTIONABLE_SKIP_REASON_PREFIXES.some((prefix) => reason === prefix || reason.startsWith(prefix));
|
|
59984
60406
|
}
|
|
59985
|
-
function
|
|
59986
|
-
const
|
|
59987
|
-
if (!
|
|
59988
|
-
|
|
59989
|
-
|
|
60407
|
+
function isTargetNodeTransientlyUnresolved(mesh, task) {
|
|
60408
|
+
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
60409
|
+
if (!targetNodeId) return false;
|
|
60410
|
+
const node = Array.isArray(mesh?.nodes) ? mesh.nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
60411
|
+
if (node && node.worktreeBootstrap?.status === "running" && !isWorktreeBootstrapStaleRunning(node)) {
|
|
60412
|
+
return true;
|
|
60413
|
+
}
|
|
60414
|
+
return isWithinCloneBootstrapGrace(targetNodeId);
|
|
59990
60415
|
}
|
|
59991
|
-
function
|
|
59992
|
-
|
|
59993
|
-
|
|
59994
|
-
return false;
|
|
60416
|
+
function targetPinAgeMs(task, nowMs = Date.now()) {
|
|
60417
|
+
const anchorMs = Date.parse(task.requeuedAt || task.createdAt || "");
|
|
60418
|
+
return Number.isFinite(anchorMs) ? nowMs - anchorMs : null;
|
|
59995
60419
|
}
|
|
59996
|
-
|
|
59997
|
-
|
|
59998
|
-
|
|
60420
|
+
function resolveDeadTargetVerdict(components, meshId, mesh, task) {
|
|
60421
|
+
const NOT_DEAD = { dead: false, nodeDead: false, reason: "" };
|
|
60422
|
+
const targetSessionId = readNonEmptyString(task.targetSessionId);
|
|
60423
|
+
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
60424
|
+
if (!targetSessionId && !targetNodeId) return NOT_DEAD;
|
|
60425
|
+
const lastUpdateMs = Date.parse(task.updatedAt || task.createdAt || "");
|
|
60426
|
+
if (Number.isFinite(lastUpdateMs) && Date.now() - lastUpdateMs < DEAD_TARGET_GRACE_MS) return NOT_DEAD;
|
|
60427
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60428
|
+
if (targetNodeId) {
|
|
60429
|
+
const nodePresent = nodes.some((n) => meshNodeIdMatches(n, targetNodeId));
|
|
60430
|
+
if (!nodePresent) {
|
|
60431
|
+
if (isTargetNodeTransientlyUnresolved(mesh, task)) return NOT_DEAD;
|
|
60432
|
+
return { dead: true, nodeDead: true, reason: "dead_target_node_absent" };
|
|
60433
|
+
}
|
|
60434
|
+
}
|
|
60435
|
+
if (targetSessionId) {
|
|
60436
|
+
const node = targetNodeId ? nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
60437
|
+
const nodeIsLocal = node ? isLocalAutoLaunchNode(node) : true;
|
|
60438
|
+
if (nodeIsLocal) {
|
|
60439
|
+
const verdict = resolveSessionBusyVerdict(components, targetSessionId);
|
|
60440
|
+
if (verdict === "UNKNOWN") {
|
|
60441
|
+
return { dead: true, nodeDead: false, reason: "dead_target_session_absent" };
|
|
60442
|
+
}
|
|
60443
|
+
}
|
|
60444
|
+
}
|
|
60445
|
+
return NOT_DEAD;
|
|
60446
|
+
}
|
|
60447
|
+
function retractActionableSkipIfPreviouslyNotified(meshId, taskId) {
|
|
60448
|
+
const dedupKey = `${meshId}:${taskId}`;
|
|
60449
|
+
if (!lastActionableSkipNotified.delete(dedupKey)) return;
|
|
60450
|
+
try {
|
|
60451
|
+
const coordinatorDaemonId = readNonEmptyString(loadConfig2().machineId) || void 0;
|
|
60452
|
+
const removed = retractPendingDispatchBlockedEvent(meshId, taskId, coordinatorDaemonId);
|
|
60453
|
+
if (removed > 0) {
|
|
60454
|
+
LOG2.info("MeshQueue", `Retracted ${removed} stale dispatch-blocked event(s) for task ${taskId} (mesh ${meshId}) \u2014 its blocker resolved`);
|
|
60455
|
+
}
|
|
60456
|
+
} catch (e) {
|
|
60457
|
+
LOG2.warn("MeshQueue", `Failed to retract stale dispatch-blocked event for task ${taskId} (mesh ${meshId}): ${e?.message || e}`);
|
|
60458
|
+
}
|
|
60459
|
+
}
|
|
60460
|
+
function resolveTaskDeliveryEvidence(meshId, taskId) {
|
|
60461
|
+
try {
|
|
60462
|
+
const store = MeshRuntimeStore.getInstance();
|
|
60463
|
+
if (store.taskDeliveryConsumed(meshId, taskId)) return "consumed";
|
|
60464
|
+
if (store.taskHasConfirmedDelivery(meshId, taskId)) return "delivered";
|
|
60465
|
+
} catch {
|
|
60466
|
+
return "delivered";
|
|
60467
|
+
}
|
|
60468
|
+
return "never_dispatched";
|
|
60469
|
+
}
|
|
60470
|
+
function actionableSkipGuidance(reason, evidence) {
|
|
60471
|
+
if (reason === "target_node_id_unmatched") return {
|
|
60472
|
+
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)",
|
|
60473
|
+
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)."
|
|
60474
|
+
};
|
|
60475
|
+
if (reason === "no_node_satisfies_required_tags") return {
|
|
60476
|
+
summary: "no node in the mesh can satisfy the task's required capability tags",
|
|
60477
|
+
nextAction: "Relax the task's requiredTags, or add/launch a node whose provider produces the required capabilities."
|
|
60478
|
+
};
|
|
60479
|
+
if (reason === "mesh_convergence_target_is_worktree") return {
|
|
60480
|
+
summary: "it is a convergence task (base-only: merge \u2192 push \u2192 cleanup) but every candidate node is a worktree clone",
|
|
60481
|
+
nextAction: "Dispatch the convergence task to the base node, or run the deterministic fast-forward path (mesh_fast_forward_node / mesh_refine_node) instead."
|
|
60482
|
+
};
|
|
60483
|
+
if (reason.startsWith("remote_auto_launch")) return {
|
|
60484
|
+
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)",
|
|
60485
|
+
nextAction: "Launch a session on that node yourself with mesh_launch_session, or ensure the remote daemon is connected over P2P."
|
|
60486
|
+
};
|
|
60487
|
+
if (reason.startsWith("provider") || reason === "missing_provider_priority") return {
|
|
60488
|
+
summary: "the node has no usable provider for this task (provider priority missing/unusable, or the provider loader is unavailable)",
|
|
60489
|
+
nextAction: "Check the node's providerPriority policy and that the required CLI/ACP provider is installed and enabled on that machine."
|
|
60490
|
+
};
|
|
60491
|
+
if (reason === "dirty_workspace") return {
|
|
60492
|
+
summary: "the node's workspace is dirty, so auto-launch is blocked to avoid clobbering uncommitted changes",
|
|
60493
|
+
nextAction: "Clean or commit the node's working tree (or fast-forward it); the task will then auto-assign."
|
|
60494
|
+
};
|
|
60495
|
+
if (reason === "target_session_pin_expired") {
|
|
60496
|
+
if (evidence === "consumed") return {
|
|
60497
|
+
summary: "it was pinned to a specific session and the pin TTL expired before the queue row was claimed \u2014 but the delivery record shows this session DID receive and start acting on the message (a turn was started for it), so the queue row lagging is a bookkeeping gap, not a lost delta",
|
|
60498
|
+
nextAction: "Do NOT re-send it \u2014 the session already has this message and re-sending would run the same instruction twice. Check its current output (mesh_read_chat / mesh_read_terminal) to confirm the work is under way."
|
|
60499
|
+
};
|
|
60500
|
+
if (evidence === "delivered") return {
|
|
60501
|
+
summary: "it was pinned to a specific session and the pin TTL expired before the queue row was claimed; the message WAS handed to that session's transport, but the session never echoed a turn start, so whether it acted on it is unconfirmed",
|
|
60502
|
+
nextAction: "Verify before re-sending: check the session with mesh_read_chat / mesh_read_terminal. Re-send only if its output shows no sign of this message \u2014 it may already be acting on it, and re-sending would duplicate the instruction."
|
|
60503
|
+
};
|
|
60504
|
+
return {
|
|
60505
|
+
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; no delivery to that session was ever recorded, so the message did not reach it",
|
|
60506
|
+
nextAction: "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."
|
|
60507
|
+
};
|
|
60508
|
+
}
|
|
60509
|
+
if (reason === SLOT_MODEL_ABSENT_SKIP_REASON) return {
|
|
60510
|
+
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)",
|
|
60511
|
+
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."
|
|
60512
|
+
};
|
|
60513
|
+
return {
|
|
60514
|
+
summary: `it cannot be dispatched (${reason})`,
|
|
60515
|
+
nextAction: "Inspect the node/mesh state with mesh_status and resolve the blocker, or re-enqueue the task."
|
|
60516
|
+
};
|
|
60517
|
+
}
|
|
60518
|
+
function notifyCoordinatorOfActionableSkip(meshId, taskId, reason, nodeId) {
|
|
60519
|
+
if (!isActionableSkipReason(reason)) return;
|
|
60520
|
+
if (reason === "target_node_id_unmatched" && isWithinCloneBootstrapGrace(readNonEmptyString(nodeId))) return;
|
|
60521
|
+
const dedupKey = `${meshId}:${taskId}`;
|
|
60522
|
+
if (lastActionableSkipNotified.get(dedupKey) === reason) return;
|
|
60523
|
+
lastActionableSkipNotified.set(dedupKey, reason);
|
|
60524
|
+
if (lastActionableSkipNotified.size > AUTO_LAUNCH_LEDGER_DEDUP_MAX) {
|
|
60525
|
+
const oldest = lastActionableSkipNotified.keys().next().value;
|
|
60526
|
+
if (oldest !== void 0) lastActionableSkipNotified.delete(oldest);
|
|
60527
|
+
}
|
|
60528
|
+
let task;
|
|
60529
|
+
try {
|
|
60530
|
+
task = getQueue(meshId).find((t) => t.id === taskId);
|
|
60531
|
+
} catch {
|
|
60532
|
+
}
|
|
60533
|
+
const targetCoordinatorDaemonId = readNonEmptyString(loadConfig2().machineId);
|
|
60534
|
+
const targetCoordinatorSessionId = readNonEmptyString(task?.sourceCoordinatorSessionId);
|
|
60535
|
+
const nodeLabel = readNonEmptyString(nodeId) || readNonEmptyString(task?.targetNodeId);
|
|
60536
|
+
const evidence = reason === "target_session_pin_expired" ? resolveTaskDeliveryEvidence(meshId, taskId) : void 0;
|
|
60537
|
+
const { summary, nextAction } = actionableSkipGuidance(reason, evidence);
|
|
60538
|
+
const closing = reason === "target_session_pin_expired" ? "The stale pin has already been cleared, so the task is now claimable by any compatible session \u2014 the action above is about the session it was originally addressed to." : "This is an actionable blocker \u2014 it will NOT clear on its own; the task stays pending until you resolve it.";
|
|
60539
|
+
const coordinatorMessage = `[System] A queued mesh task${nodeLabel ? ` for node ${nodeLabel}` : ""} is not being dispatched because ${summary}. ${nextAction} ${closing}`;
|
|
60540
|
+
try {
|
|
60541
|
+
queuePendingMeshCoordinatorEvent({
|
|
60542
|
+
event: "mesh:dispatch_blocked",
|
|
60543
|
+
meshId,
|
|
60544
|
+
nodeLabel: nodeLabel || meshId,
|
|
60545
|
+
...nodeLabel ? { nodeId: nodeLabel } : {},
|
|
60546
|
+
metadataEvent: {
|
|
60547
|
+
source: "mesh_queue_dispatch_skip",
|
|
60548
|
+
taskId,
|
|
60549
|
+
reason,
|
|
60550
|
+
...nodeLabel ? { nodeId: nodeLabel } : {},
|
|
60551
|
+
coordinatorMessage
|
|
60552
|
+
},
|
|
60553
|
+
coordinatorMessage,
|
|
60554
|
+
queuedAt: Date.now(),
|
|
60555
|
+
...targetCoordinatorDaemonId ? { targetCoordinatorDaemonId } : {},
|
|
60556
|
+
...targetCoordinatorSessionId ? { targetCoordinatorSessionId } : {}
|
|
60557
|
+
});
|
|
60558
|
+
} catch (e) {
|
|
60559
|
+
LOG2.warn("MeshQueue", `Failed to surface actionable dispatch-skip (${reason}) for task ${taskId}: ${e?.message || e}`);
|
|
60560
|
+
}
|
|
60561
|
+
}
|
|
60562
|
+
var ACTIONABLE_SKIP_REASON_PREFIXES;
|
|
60563
|
+
var TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON;
|
|
60564
|
+
var lastActionableSkipNotified;
|
|
60565
|
+
var DEAD_TARGET_GRACE_MS;
|
|
60566
|
+
var TARGET_SESSION_PIN_TTL_MS;
|
|
60567
|
+
var init_mesh_skip_notify = __esm2({
|
|
60568
|
+
"src/mesh/mesh-skip-notify.ts"() {
|
|
59999
60569
|
"use strict";
|
|
60000
|
-
|
|
60001
|
-
|
|
60002
|
-
|
|
60570
|
+
init_logger();
|
|
60571
|
+
init_mesh_work_queue();
|
|
60572
|
+
init_mesh_runtime_store();
|
|
60573
|
+
init_dist();
|
|
60574
|
+
init_mesh_events_utils();
|
|
60575
|
+
init_mesh_events_pending();
|
|
60576
|
+
init_worktree_bootstrap_config();
|
|
60577
|
+
init_mesh_clone_grace();
|
|
60578
|
+
init_config();
|
|
60579
|
+
init_slot_model_enforcement();
|
|
60580
|
+
init_mesh_queue_assignment();
|
|
60581
|
+
ACTIONABLE_SKIP_REASON_PREFIXES = [
|
|
60582
|
+
"target_node_id_unmatched",
|
|
60583
|
+
"no_node_satisfies_required_tags",
|
|
60584
|
+
"mesh_convergence_target_is_worktree",
|
|
60585
|
+
"remote_auto_launch_unsupported",
|
|
60586
|
+
"remote_auto_launch_no_coordinator_daemon_id",
|
|
60587
|
+
"missing_provider_priority",
|
|
60588
|
+
"provider_loader_unavailable",
|
|
60589
|
+
"provider_priority_unusable",
|
|
60590
|
+
"provider_unusable",
|
|
60591
|
+
"dirty_workspace",
|
|
60592
|
+
// TARGET-PIN-TTL EXPIRY: the task was pinned to a specific session (a delta —
|
|
60593
|
+
// a correction addressed to work already in flight) and that session never
|
|
60594
|
+
// claimed it within the TTL, so the pin was cleared. Unlike the transient
|
|
60595
|
+
// skips, this does NOT self-resolve into the intended outcome: the delta is
|
|
60596
|
+
// now claimable by ANY compatible session, i.e. it will not reach the session
|
|
60597
|
+
// it was written for. Previously this only bumped a metrics counter and wrote
|
|
60598
|
+
// a log, so the coordinator kept waiting for a delivery that could no longer
|
|
60599
|
+
// happen — measured live as 74min of silence while a worker continued on a
|
|
60600
|
+
// premise the delta was meant to correct. The coordinator must know its
|
|
60601
|
+
// addressed message lost its address.
|
|
60602
|
+
"target_session_pin_expired",
|
|
60603
|
+
// SLOT MODEL GUARD (absent): no slot on the node declares the task's model.
|
|
60604
|
+
// Permanent — no amount of waiting produces a slot, so the coordinator must
|
|
60605
|
+
// re-drive (adjust difficulty, target another node, ask the owner). Its
|
|
60606
|
+
// busy counterpart SLOT_MODEL_BUSY_SKIP_REASON is deliberately NOT listed:
|
|
60607
|
+
// that one clears on its own when the slot goes idle.
|
|
60608
|
+
SLOT_MODEL_ABSENT_SKIP_REASON
|
|
60609
|
+
// QUOTA GATE: 'provider_quota_session_low' / 'provider_quota_weekly_low' are
|
|
60610
|
+
// deliberately NOT listed either — an exhausted quota window RESETS, so the
|
|
60611
|
+
// block self-resolves exactly like the slot-busy case; the task waits in the
|
|
60612
|
+
// queue and the coordinator is not paged (mesh-quota-routing.ts).
|
|
60613
|
+
];
|
|
60614
|
+
TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON = "target_node_bootstrap_pending";
|
|
60615
|
+
lastActionableSkipNotified = /* @__PURE__ */ new Map();
|
|
60616
|
+
DEAD_TARGET_GRACE_MS = 6e4;
|
|
60617
|
+
TARGET_SESSION_PIN_TTL_MS = 15 * 6e4;
|
|
60003
60618
|
}
|
|
60004
60619
|
});
|
|
60005
|
-
function
|
|
60006
|
-
|
|
60007
|
-
return holder ? `${DUPLICATE_MESH_DISPATCH_CODE}:${holder}` : DUPLICATE_MESH_DISPATCH_CODE;
|
|
60620
|
+
function activeWriteAssignedCount(meshId) {
|
|
60621
|
+
return getQueue(meshId, { status: ["assigned"] }).filter((task) => !isTaskReadonly(task)).length;
|
|
60008
60622
|
}
|
|
60009
|
-
function
|
|
60010
|
-
|
|
60011
|
-
|
|
60012
|
-
|
|
60013
|
-
|
|
60014
|
-
|
|
60623
|
+
function activeReadonlyAssignedCount(meshId) {
|
|
60624
|
+
return getQueue(meshId, { status: ["assigned"] }).filter(isTaskReadonly).length;
|
|
60625
|
+
}
|
|
60626
|
+
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
60627
|
+
return getQueue(meshId, { status: ["assigned"] }).some((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId));
|
|
60628
|
+
}
|
|
60629
|
+
function nodeActiveLoad(meshId, nodeId) {
|
|
60630
|
+
return MeshRuntimeStore.getInstance().nodeActiveAssignmentCount(meshId, nodeId);
|
|
60631
|
+
}
|
|
60632
|
+
function meshHasExplicitSlots(mesh) {
|
|
60633
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
60634
|
+
return nodes.some((n) => normalizeNodeCapabilitySlots(n?.policy?.slots).length > 0);
|
|
60635
|
+
}
|
|
60636
|
+
function resolveSchedulingStrategy(mesh) {
|
|
60637
|
+
const raw = mesh?.policy?.schedulingStrategy;
|
|
60638
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
60639
|
+
return normalizeMeshSchedulingStrategy(raw);
|
|
60015
60640
|
}
|
|
60016
|
-
|
|
60017
|
-
|
|
60018
|
-
|
|
60019
|
-
|
|
60020
|
-
|
|
60641
|
+
return meshHasExplicitSlots(mesh) ? "fitness" : normalizeMeshSchedulingStrategy(void 0);
|
|
60642
|
+
}
|
|
60643
|
+
function buildSchedulingPool(localCandidates, remoteCandidates) {
|
|
60644
|
+
const pool = [...localCandidates, ...remoteCandidates].map((c) => ({
|
|
60645
|
+
...c,
|
|
60646
|
+
nodeId: normalizeMeshNodeId(c.node) ?? c.nodeId
|
|
60647
|
+
}));
|
|
60648
|
+
const uniqueNodes = [...new Set(pool.map((c) => c.nodeId))].map((nodeId, index) => ({
|
|
60649
|
+
nodeId,
|
|
60650
|
+
node: pool.find((c) => meshNodeIdMatches({ id: c.nodeId }, nodeId))?.node,
|
|
60651
|
+
index
|
|
60652
|
+
}));
|
|
60653
|
+
return { pool, uniqueNodes };
|
|
60654
|
+
}
|
|
60655
|
+
function scoreSlotForTask(slot, task, quotaBonus = 0) {
|
|
60656
|
+
let score = 1;
|
|
60657
|
+
const diff = isMeshTaskDifficulty(task.difficulty) ? task.difficulty : void 0;
|
|
60658
|
+
if (diff) {
|
|
60659
|
+
if (slot.difficulty?.length) {
|
|
60660
|
+
score += slot.difficulty.includes(diff) ? 100 : 0;
|
|
60661
|
+
} else {
|
|
60662
|
+
score += 20;
|
|
60663
|
+
}
|
|
60021
60664
|
}
|
|
60022
|
-
|
|
60665
|
+
const req = task.requiredTags?.filter((t) => !!t) ?? [];
|
|
60666
|
+
if (req.length) {
|
|
60667
|
+
const cap = new Set(slot.capability ?? []);
|
|
60668
|
+
const covered = req.every((t) => cap.has(t));
|
|
60669
|
+
score += covered ? 30 : 0;
|
|
60670
|
+
}
|
|
60671
|
+
score += quotaBonus;
|
|
60672
|
+
return score;
|
|
60023
60673
|
}
|
|
60024
|
-
|
|
60025
|
-
|
|
60026
|
-
|
|
60027
|
-
|
|
60028
|
-
|
|
60029
|
-
|
|
60030
|
-
|
|
60031
|
-
|
|
60032
|
-
|
|
60033
|
-
|
|
60034
|
-
|
|
60035
|
-
|
|
60036
|
-
|
|
60674
|
+
function orderSlotsForProviderSelection(slots, meshId, nodeId, node, task, quotaBonusByProvider) {
|
|
60675
|
+
return [...slots].sort((a, b) => {
|
|
60676
|
+
const capDelta = Number(slotHasCapacity(meshId, nodeId, node, b)) - Number(slotHasCapacity(meshId, nodeId, node, a));
|
|
60677
|
+
if (capDelta !== 0) return capDelta;
|
|
60678
|
+
return scoreSlotForTask(b, task, quotaBonusByProvider?.[b.provider] ?? 0) - scoreSlotForTask(a, task, quotaBonusByProvider?.[a.provider] ?? 0);
|
|
60679
|
+
});
|
|
60680
|
+
}
|
|
60681
|
+
function bestSlotForTask(node, task, meshId, quotaBonusByProvider) {
|
|
60682
|
+
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
60683
|
+
if (!slots.length) return null;
|
|
60684
|
+
let best = null;
|
|
60685
|
+
for (const slot of slots) {
|
|
60686
|
+
const score = scoreSlotForTask(slot, task, quotaBonusByProvider?.[slot.provider] ?? 0);
|
|
60687
|
+
if (!best || score > best.score) best = { slot, score };
|
|
60688
|
+
}
|
|
60689
|
+
return best;
|
|
60690
|
+
}
|
|
60691
|
+
function nodeFitnessForTask(node, task, meshId, quotaBonusByProvider) {
|
|
60692
|
+
return bestSlotForTask(node, task, meshId, quotaBonusByProvider)?.score ?? 0;
|
|
60693
|
+
}
|
|
60694
|
+
function slotCoversTaskDifficulty(slot, difficulty) {
|
|
60695
|
+
if (!slot) return false;
|
|
60696
|
+
if (!isMeshTaskDifficulty(difficulty)) return false;
|
|
60697
|
+
if (!slot.difficulty?.length) return true;
|
|
60698
|
+
return slot.difficulty.includes(difficulty);
|
|
60699
|
+
}
|
|
60700
|
+
function resolveLaunchAxis(taskValue, taskSource, slotValue, slotCoversDifficulty) {
|
|
60701
|
+
const stamped = typeof taskValue === "string" && taskValue.trim() ? taskValue.trim() : void 0;
|
|
60702
|
+
if (!stamped) return slotValue;
|
|
60703
|
+
if (taskSource !== "preset") return stamped;
|
|
60704
|
+
return slotCoversDifficulty && slotValue ? slotValue : stamped;
|
|
60705
|
+
}
|
|
60706
|
+
function orderEligibleNodes(meshId, strategy, nodes, opts) {
|
|
60707
|
+
if (strategy === "first_eligible" || nodes.length <= 1) {
|
|
60708
|
+
return nodes;
|
|
60709
|
+
}
|
|
60710
|
+
if (strategy === "fitness" && opts?.task) {
|
|
60711
|
+
const task = opts.task;
|
|
60712
|
+
const bonusCache = /* @__PURE__ */ new Map();
|
|
60713
|
+
const bonusFor = (c) => {
|
|
60714
|
+
let bonus = bonusCache.get(c.nodeId);
|
|
60715
|
+
if (!bonus) {
|
|
60716
|
+
bonus = quotaSpreadBonusByProvider(c.node, opts.quotaRouting);
|
|
60717
|
+
bonusCache.set(c.nodeId, bonus);
|
|
60037
60718
|
}
|
|
60719
|
+
return bonus;
|
|
60038
60720
|
};
|
|
60721
|
+
return [...nodes].sort((a, b) => {
|
|
60722
|
+
const fitDelta = nodeFitnessForTask(b.node, task, meshId, bonusFor(b)) - nodeFitnessForTask(a.node, task, meshId, bonusFor(a));
|
|
60723
|
+
if (fitDelta !== 0) return fitDelta;
|
|
60724
|
+
const prioDelta = resolveNodeSchedulingPriority(b.node?.policy) - resolveNodeSchedulingPriority(a.node?.policy);
|
|
60725
|
+
if (prioDelta !== 0) return prioDelta;
|
|
60726
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
60727
|
+
if (loadDelta !== 0) return loadDelta;
|
|
60728
|
+
return a.index - b.index;
|
|
60729
|
+
});
|
|
60039
60730
|
}
|
|
60040
|
-
|
|
60041
|
-
|
|
60042
|
-
|
|
60731
|
+
const priorityOf = (n) => resolveNodeSchedulingPriority(n.node?.policy);
|
|
60732
|
+
let rotation = 0;
|
|
60733
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
60734
|
+
const cursor = opts?.bumpCursor ? MeshRuntimeStore.getInstance().bumpSchedulerCursor(meshId) : MeshRuntimeStore.getInstance().getSchedulerCursor(meshId);
|
|
60735
|
+
rotation = (cursor % nodes.length + nodes.length) % nodes.length;
|
|
60736
|
+
}
|
|
60737
|
+
const rotationRank = (index) => (index - rotation + nodes.length) % nodes.length;
|
|
60738
|
+
return [...nodes].sort((a, b) => {
|
|
60739
|
+
const prioDelta = priorityOf(b) - priorityOf(a);
|
|
60740
|
+
if (prioDelta !== 0) return prioDelta;
|
|
60741
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
60742
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
60743
|
+
if (loadDelta !== 0) return loadDelta;
|
|
60744
|
+
}
|
|
60745
|
+
return rotationRank(a.index) - rotationRank(b.index);
|
|
60746
|
+
});
|
|
60043
60747
|
}
|
|
60044
|
-
function
|
|
60045
|
-
|
|
60046
|
-
if (!key2) return false;
|
|
60047
|
-
if (autoFastForwardWorkspaceLease.has(key2)) return false;
|
|
60048
|
-
autoFastForwardWorkspaceLease.add(key2);
|
|
60049
|
-
return true;
|
|
60748
|
+
function activeProviderAssignedCount(meshId, nodeId, providerType) {
|
|
60749
|
+
return getQueue(meshId, { status: ["assigned"] }).filter((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId) && task.assignedProviderType === providerType).length;
|
|
60050
60750
|
}
|
|
60051
|
-
function
|
|
60052
|
-
|
|
60053
|
-
|
|
60751
|
+
function activeSlotAssignedCount(meshId, nodeId, providerType, slot) {
|
|
60752
|
+
return getQueue(meshId, { status: ["assigned"] }).filter((task) => {
|
|
60753
|
+
if (!daemonIdsEquivalent(task.assignedNodeId, nodeId)) return false;
|
|
60754
|
+
if (task.assignedProviderType !== providerType) return false;
|
|
60755
|
+
const assignedModel = task.assignedModel;
|
|
60756
|
+
if (typeof assignedModel !== "string" || !assignedModel.trim()) return true;
|
|
60757
|
+
return isModelAllowedBySlot(assignedModel, slot);
|
|
60758
|
+
}).length;
|
|
60054
60759
|
}
|
|
60055
|
-
function
|
|
60056
|
-
const
|
|
60057
|
-
return
|
|
60760
|
+
function slotCapacityRemaining(meshId, nodeId, node, slot) {
|
|
60761
|
+
const providerType = typeof slot.provider === "string" ? slot.provider.trim() : "";
|
|
60762
|
+
if (!providerType) return { available: false };
|
|
60763
|
+
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
60764
|
+
const slotCap = resolveSlotMaxParallel(slots, providerType, slot.model, isModelAllowedBySlot);
|
|
60765
|
+
if (slotCap !== void 0 && activeSlotAssignedCount(meshId, nodeId, providerType, slot) >= slotCap) {
|
|
60766
|
+
return { available: false, slotCap };
|
|
60767
|
+
}
|
|
60768
|
+
const providerCap = resolveProviderMaxParallel(slots, providerType);
|
|
60769
|
+
if (providerCap !== void 0 && activeProviderAssignedCount(meshId, nodeId, providerType) >= providerCap) {
|
|
60770
|
+
return { available: false, slotCap, providerCap };
|
|
60771
|
+
}
|
|
60772
|
+
return { available: true, slotCap, providerCap };
|
|
60058
60773
|
}
|
|
60059
|
-
function
|
|
60060
|
-
|
|
60061
|
-
|
|
60062
|
-
|
|
60774
|
+
function slotHasCapacity(meshId, nodeId, node, slot) {
|
|
60775
|
+
return slotCapacityRemaining(meshId, nodeId, node, slot).available;
|
|
60776
|
+
}
|
|
60777
|
+
function sessionHasActiveAssignment(meshId, sessionId) {
|
|
60778
|
+
if (getQueue(meshId, { status: ["assigned"] }).some((task) => sessionIdsEquivalent(task.assignedSessionId, sessionId))) {
|
|
60779
|
+
return true;
|
|
60780
|
+
}
|
|
60781
|
+
try {
|
|
60782
|
+
if (getActiveDirectDispatches(meshId).some((d) => sessionIdsEquivalent(d.sessionId, sessionId))) return true;
|
|
60783
|
+
if (hasUnterminalDirectDispatchLedgerEntry(meshId, sessionId)) return true;
|
|
60784
|
+
} catch {
|
|
60785
|
+
}
|
|
60786
|
+
return false;
|
|
60787
|
+
}
|
|
60788
|
+
var init_mesh_scheduling_fitness = __esm2({
|
|
60789
|
+
"src/mesh/mesh-scheduling-fitness.ts"() {
|
|
60790
|
+
"use strict";
|
|
60791
|
+
init_mesh_work_queue();
|
|
60792
|
+
init_mesh_runtime_store();
|
|
60793
|
+
init_mesh_work_queue();
|
|
60794
|
+
init_repo_mesh_types();
|
|
60795
|
+
init_dist();
|
|
60796
|
+
init_mesh_node_slots();
|
|
60797
|
+
init_mesh_quota_routing();
|
|
60798
|
+
init_mesh_events_stale();
|
|
60799
|
+
init_slot_model_enforcement();
|
|
60800
|
+
}
|
|
60801
|
+
});
|
|
60802
|
+
function localCoordinatorDaemonId() {
|
|
60803
|
+
return canonicalDaemonId(readNonEmptyString(loadConfig2().machineId));
|
|
60063
60804
|
}
|
|
60064
60805
|
function loadRepoConfigForNode(node) {
|
|
60065
60806
|
const workspace = typeof node?.workspace === "string" && node.workspace.trim() ? node.workspace.trim() : "";
|
|
@@ -60247,14 +60988,15 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60247
60988
|
if (timer) clearTimeout(timer);
|
|
60248
60989
|
const isQueued = res && typeof res === "object" && res.status === "queued";
|
|
60249
60990
|
updateSessionDeliveryStatus(delivery.id, isQueued ? "queued" : "delivered");
|
|
60250
|
-
if (
|
|
60991
|
+
if (ctx.task.attemptId) {
|
|
60251
60992
|
try {
|
|
60252
60993
|
recordTurnAck({
|
|
60253
60994
|
meshId: ctx.meshId,
|
|
60254
60995
|
taskId: ctx.task.id,
|
|
60255
|
-
kind: "delivered",
|
|
60996
|
+
kind: isQueued ? "accepted" : "delivered",
|
|
60256
60997
|
attemptId: ctx.task.attemptId,
|
|
60257
|
-
sessionId: ctx.sessionId
|
|
60998
|
+
sessionId: ctx.sessionId,
|
|
60999
|
+
...isQueued ? { evidence: { source: "transport_queued_in_adapter" } } : {}
|
|
60258
61000
|
});
|
|
60259
61001
|
} catch {
|
|
60260
61002
|
}
|
|
@@ -60295,22 +61037,52 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60295
61037
|
LOG2.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
|
|
60296
61038
|
updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
60297
61039
|
endTaskDispatchInFlight(ctx.meshId, ctx.task.id);
|
|
60298
|
-
updateTaskStatus(ctx.meshId, ctx.task.id, "pending");
|
|
60299
61040
|
try {
|
|
60300
61041
|
closeAttemptForReassignment({ meshId: ctx.meshId, taskId: ctx.task.id, reason: "dispatch_failed" });
|
|
60301
61042
|
} catch {
|
|
60302
61043
|
}
|
|
61044
|
+
const retryable = isRetryableDispatchFailure(e);
|
|
61045
|
+
if (!retryable) {
|
|
61046
|
+
failTaskAsUndeliverable(ctx, `dispatch_unrecoverable: ${e?.message || "transport reported the failure as non-recoverable"}`);
|
|
61047
|
+
} else {
|
|
61048
|
+
const requeued = requeueTask(ctx.meshId, ctx.task.id, {
|
|
61049
|
+
reason: "dispatch_failed",
|
|
61050
|
+
clearTargetSession: false
|
|
61051
|
+
});
|
|
61052
|
+
if (requeued?.status === "failed") {
|
|
61053
|
+
LOG2.error("MeshQueue", `Task ${ctx.task.id} (mesh ${ctx.meshId}) failed after repeated undeliverable dispatches to node ${ctx.nodeId}: ${requeued.cancelReason || "max_retries_exceeded"}. Dependents were unblocked.`);
|
|
61054
|
+
}
|
|
61055
|
+
}
|
|
60303
61056
|
try {
|
|
60304
61057
|
appendLedgerEntry(ctx.meshId, {
|
|
60305
61058
|
kind: "dispatch_failed",
|
|
60306
61059
|
nodeId: ctx.nodeId,
|
|
60307
61060
|
sessionId: ctx.sessionId,
|
|
60308
|
-
payload: { taskId: ctx.task.id, deliveryId: delivery.id, error: e?.message, retryable
|
|
61061
|
+
payload: { taskId: ctx.task.id, deliveryId: delivery.id, error: e?.message, retryable, transport: ctx.transport }
|
|
60309
61062
|
});
|
|
60310
61063
|
} catch {
|
|
60311
61064
|
}
|
|
60312
61065
|
});
|
|
60313
61066
|
}
|
|
61067
|
+
function failTaskAsUndeliverable(ctx, reason) {
|
|
61068
|
+
try {
|
|
61069
|
+
const failed = requeueTask(ctx.meshId, ctx.task.id, { maxRetries: 0, reason, clearTargetSession: false });
|
|
61070
|
+
if (!failed) return;
|
|
61071
|
+
} catch (err) {
|
|
61072
|
+
LOG2.warn("MeshQueue", `Failed to mark undeliverable task ${ctx.task.id} (mesh ${ctx.meshId}) terminal: ${err?.message || err}`);
|
|
61073
|
+
return;
|
|
61074
|
+
}
|
|
61075
|
+
LOG2.error("MeshQueue", `Task ${ctx.task.id} (mesh ${ctx.meshId}) is undeliverable to node ${ctx.nodeId} (session ${ctx.sessionId ?? "?"}) and will NOT be retried: ${reason}`);
|
|
61076
|
+
try {
|
|
61077
|
+
appendLedgerEntry(ctx.meshId, {
|
|
61078
|
+
kind: "task_failed",
|
|
61079
|
+
nodeId: ctx.nodeId,
|
|
61080
|
+
sessionId: ctx.sessionId,
|
|
61081
|
+
payload: { taskId: ctx.task.id, reason, undeliverable: true }
|
|
61082
|
+
});
|
|
61083
|
+
} catch {
|
|
61084
|
+
}
|
|
61085
|
+
}
|
|
60314
61086
|
function isRetryableDispatchFailure(e) {
|
|
60315
61087
|
if (e && typeof e === "object") {
|
|
60316
61088
|
if (e.retryRecommended === false) return false;
|
|
@@ -60604,143 +61376,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60604
61376
|
}
|
|
60605
61377
|
return out;
|
|
60606
61378
|
}
|
|
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
61379
|
function sweepExpiredCooldowns() {
|
|
60745
61380
|
const now = Date.now();
|
|
60746
61381
|
for (const [key2, until] of autoLaunchCooldownUntil) {
|
|
@@ -60760,28 +61395,11 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60760
61395
|
function isTerminalSessionStatus(status) {
|
|
60761
61396
|
return ["stopped", "failed", "terminated", "exited", "closed"].includes(status);
|
|
60762
61397
|
}
|
|
60763
|
-
function
|
|
61398
|
+
function isIdleSessionState2(state) {
|
|
60764
61399
|
const status = readNonEmptyString(state?.status).toLowerCase();
|
|
60765
61400
|
if (isTerminalSessionStatus(status)) return false;
|
|
60766
61401
|
return status === "idle" || state?.activeChat?.status === "waiting_input";
|
|
60767
61402
|
}
|
|
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
61403
|
function sessionStateLooksActive(state) {
|
|
60786
61404
|
const status = readNonEmptyString(state?.status).toLowerCase();
|
|
60787
61405
|
const chatStatus = readNonEmptyString(state?.activeChat?.status).toLowerCase();
|
|
@@ -60797,7 +61415,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60797
61415
|
const instNodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
60798
61416
|
if (!daemonIdsEquivalent(instNodeId, nodeId)) return false;
|
|
60799
61417
|
const sessionId = readNonEmptyString(state.instanceId);
|
|
60800
|
-
if (currentSessionId && sessionIdsEquivalent(sessionId, currentSessionId) &&
|
|
61418
|
+
if (currentSessionId && sessionIdsEquivalent(sessionId, currentSessionId) && isIdleSessionState2(state)) return false;
|
|
60801
61419
|
return sessionStateLooksActive(state);
|
|
60802
61420
|
});
|
|
60803
61421
|
}
|
|
@@ -60832,174 +61450,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
60832
61450
|
if (!coordinatorDaemonId) return { mode: "skip", reason: "remote_auto_launch_no_coordinator_daemon_id" };
|
|
60833
61451
|
return { mode: "remote", daemonId, coordinatorDaemonId };
|
|
60834
61452
|
}
|
|
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
61453
|
function isSessionActivelyGenerating(components, sessionId) {
|
|
61004
61454
|
if (!sessionId) return false;
|
|
61005
61455
|
const state = components.instanceManager?.getInstance?.(sessionId)?.getState?.();
|
|
@@ -61594,7 +62044,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61594
62044
|
if (instMeshId !== meshId) continue;
|
|
61595
62045
|
const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
61596
62046
|
if (!nodeId) continue;
|
|
61597
|
-
if (!
|
|
62047
|
+
if (!isIdleSessionState2(state)) {
|
|
61598
62048
|
const status = readNonEmptyString(state.status).toLowerCase();
|
|
61599
62049
|
skippedSessions.push({
|
|
61600
62050
|
nodeId,
|
|
@@ -61701,209 +62151,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61701
62151
|
...pendingAfter > 0 && newlyAssignedTasks.length === 0 && localIdleSessionsChecked === 0 && remoteIdleSessionsChecked === 0 && !autoLaunchPending ? { noIdleMeshSessionAvailable: true } : {}
|
|
61702
62152
|
};
|
|
61703
62153
|
}
|
|
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
62154
|
function runIdleMaintenanceThenAssignQueue(components, args) {
|
|
61908
62155
|
setImmediate(() => {
|
|
61909
62156
|
maybeAutoFastForwardIdleNode(components, args).finally(() => {
|
|
@@ -61915,12 +62162,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61915
62162
|
});
|
|
61916
62163
|
});
|
|
61917
62164
|
}
|
|
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
62165
|
var BOOTSTRAP_TERMINAL_STATUSES;
|
|
61925
62166
|
var DISPATCH_CONFIRM_TIMEOUT_MS;
|
|
61926
62167
|
var DISPATCH_CONNECT_TIMEOUT_MS;
|
|
@@ -61936,15 +62177,9 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61936
62177
|
var autoLaunchAwaitClaimBackoff;
|
|
61937
62178
|
var lastAutoLaunchLedgerKey;
|
|
61938
62179
|
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
62180
|
var init_mesh_queue_assignment = __esm2({
|
|
61945
62181
|
"src/mesh/mesh-queue-assignment.ts"() {
|
|
61946
62182
|
"use strict";
|
|
61947
|
-
import_fs14 = require("fs");
|
|
61948
62183
|
init_runtime_defaults();
|
|
61949
62184
|
init_config();
|
|
61950
62185
|
init_mesh_config();
|
|
@@ -61953,7 +62188,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61953
62188
|
init_mesh_ledger();
|
|
61954
62189
|
init_mesh_work_queue();
|
|
61955
62190
|
init_transcript_evidence();
|
|
61956
|
-
init_mesh_fast_forward();
|
|
61957
62191
|
init_mesh_delivery_policy();
|
|
61958
62192
|
init_mesh_runtime_store();
|
|
61959
62193
|
init_mesh_event_trace();
|
|
@@ -61966,19 +62200,18 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61966
62200
|
init_mesh_events_stale();
|
|
61967
62201
|
init_mesh_events_utils();
|
|
61968
62202
|
init_mesh_node_identity();
|
|
61969
|
-
init_mesh_events_pending();
|
|
61970
62203
|
init_worktree_bootstrap_config();
|
|
61971
|
-
init_mesh_clone_grace();
|
|
61972
62204
|
init_mesh_task_inflight();
|
|
61973
62205
|
init_model_provider_compat();
|
|
61974
62206
|
init_slot_model_enforcement();
|
|
61975
62207
|
init_mesh_turn_ledger();
|
|
61976
62208
|
init_mesh_duplicate_dispatch();
|
|
61977
|
-
|
|
61978
|
-
|
|
61979
|
-
|
|
61980
|
-
|
|
61981
|
-
|
|
62209
|
+
init_mesh_auto_fast_forward();
|
|
62210
|
+
init_mesh_skip_notify();
|
|
62211
|
+
init_mesh_scheduling_fitness();
|
|
62212
|
+
init_mesh_auto_fast_forward();
|
|
62213
|
+
init_mesh_skip_notify();
|
|
62214
|
+
init_mesh_scheduling_fitness();
|
|
61982
62215
|
BOOTSTRAP_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["complete", "failed"]);
|
|
61983
62216
|
DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
|
|
61984
62217
|
DISPATCH_CONNECT_TIMEOUT_MS = MESH_CONNECT_TIMEOUT_MS2;
|
|
@@ -61994,43 +62227,6 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61994
62227
|
autoLaunchAwaitClaimBackoff = /* @__PURE__ */ new Map();
|
|
61995
62228
|
lastAutoLaunchLedgerKey = /* @__PURE__ */ new Map();
|
|
61996
62229
|
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
62230
|
}
|
|
62035
62231
|
});
|
|
62036
62232
|
function readSettings(state) {
|
|
@@ -62504,6 +62700,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
62504
62700
|
return cachedBinding;
|
|
62505
62701
|
}
|
|
62506
62702
|
const errors = [];
|
|
62703
|
+
let allModuleNotFound = true;
|
|
62507
62704
|
for (const ref of getBindingCandidates()) {
|
|
62508
62705
|
try {
|
|
62509
62706
|
const mod = require(ref);
|
|
@@ -62515,15 +62712,19 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
62515
62712
|
errors.push(`${ref}: module not found`);
|
|
62516
62713
|
continue;
|
|
62517
62714
|
}
|
|
62715
|
+
allModuleNotFound = false;
|
|
62518
62716
|
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
62519
62717
|
errors.push(`${ref}: ${message}`);
|
|
62520
62718
|
}
|
|
62521
62719
|
}
|
|
62522
|
-
|
|
62523
|
-
cachedBindingError = new Error(
|
|
62720
|
+
const buildError = () => new Error(
|
|
62524
62721
|
`ghostty-vt binding unavailable for runtime ${runtimeTriplet()} (${errors.join("; ") || "no candidates tried"})`
|
|
62525
62722
|
);
|
|
62526
|
-
|
|
62723
|
+
if (allModuleNotFound) {
|
|
62724
|
+
cachedBinding = null;
|
|
62725
|
+
cachedBindingError = buildError();
|
|
62726
|
+
}
|
|
62727
|
+
throw buildError();
|
|
62527
62728
|
}
|
|
62528
62729
|
var DEFAULT_BINDING_CANDIDATES;
|
|
62529
62730
|
var cachedBinding;
|
|
@@ -68949,6 +69150,7 @@ ${cleanBody}`;
|
|
|
68949
69150
|
});
|
|
68950
69151
|
var mesh_events_exports = {};
|
|
68951
69152
|
__export2(mesh_events_exports, {
|
|
69153
|
+
PENDING_RETENTION_EXPIRED_HOLD_REASON: () => PENDING_RETENTION_EXPIRED_HOLD_REASON,
|
|
68952
69154
|
__resetIdleAutoFastForwardForTests: () => __resetIdleAutoFastForwardForTests,
|
|
68953
69155
|
__resetMeshWorkspaceCacheForTests: () => __resetMeshWorkspaceCacheForTests,
|
|
68954
69156
|
clearPendingMeshCoordinatorEvents: () => clearPendingMeshCoordinatorEvents,
|
|
@@ -68956,6 +69158,7 @@ ${cleanBody}`;
|
|
|
68956
69158
|
getMeshV2BackstopCounters: () => getMeshV2BackstopCounters,
|
|
68957
69159
|
getMeshV2DrainCounters: () => getMeshV2DrainCounters,
|
|
68958
69160
|
getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
|
|
69161
|
+
getPendingRetentionCounters: () => getPendingRetentionCounters,
|
|
68959
69162
|
handleMeshForwardEvent: () => handleMeshForwardEvent,
|
|
68960
69163
|
isMeshCoordinatorEvent: () => isMeshCoordinatorEvent,
|
|
68961
69164
|
isMeshProtocolV2EnforceEnabled: () => isMeshProtocolV2EnforceEnabled,
|
|
@@ -69936,20 +70139,31 @@ ${cleanBody}`;
|
|
|
69936
70139
|
});
|
|
69937
70140
|
var pty_transport_exports = {};
|
|
69938
70141
|
__export2(pty_transport_exports, {
|
|
69939
|
-
NodePtyTransportFactory: () => NodePtyTransportFactory
|
|
70142
|
+
NodePtyTransportFactory: () => NodePtyTransportFactory,
|
|
70143
|
+
__setNodePtyLoaderForTests: () => __setNodePtyLoaderForTests
|
|
69940
70144
|
});
|
|
70145
|
+
function isModuleNotFoundError2(error48) {
|
|
70146
|
+
return error48 instanceof Error && "code" in error48 && error48.code === "MODULE_NOT_FOUND";
|
|
70147
|
+
}
|
|
69941
70148
|
function loadNodePty() {
|
|
69942
70149
|
if (cachedPty !== void 0) return cachedPty;
|
|
69943
70150
|
try {
|
|
69944
|
-
cachedPty =
|
|
70151
|
+
cachedPty = requireNodePty();
|
|
69945
70152
|
(0, import_session_host_core3.ensureNodePtySpawnHelperPermissions)();
|
|
69946
|
-
} catch {
|
|
69947
|
-
|
|
70153
|
+
} catch (error48) {
|
|
70154
|
+
if (isModuleNotFoundError2(error48)) {
|
|
70155
|
+
cachedPty = null;
|
|
70156
|
+
}
|
|
69948
70157
|
}
|
|
69949
|
-
return cachedPty;
|
|
70158
|
+
return cachedPty ?? null;
|
|
70159
|
+
}
|
|
70160
|
+
function __setNodePtyLoaderForTests(loader2) {
|
|
70161
|
+
cachedPty = void 0;
|
|
70162
|
+
requireNodePty = loader2 ?? (() => require("node-pty"));
|
|
69950
70163
|
}
|
|
69951
70164
|
var os12;
|
|
69952
70165
|
var cachedPty;
|
|
70166
|
+
var requireNodePty;
|
|
69953
70167
|
var NodePtyRuntimeTransport;
|
|
69954
70168
|
var NodePtyTransportFactory;
|
|
69955
70169
|
var init_pty_transport = __esm2({
|
|
@@ -69958,6 +70172,7 @@ ${cleanBody}`;
|
|
|
69958
70172
|
os12 = __toESM2(require("os"));
|
|
69959
70173
|
init_spawn_env();
|
|
69960
70174
|
init_resolve_executable();
|
|
70175
|
+
requireNodePty = () => require("node-pty");
|
|
69961
70176
|
NodePtyRuntimeTransport = class {
|
|
69962
70177
|
constructor(handle) {
|
|
69963
70178
|
this.handle = handle;
|
|
@@ -70012,6 +70227,100 @@ ${cleanBody}`;
|
|
|
70012
70227
|
};
|
|
70013
70228
|
}
|
|
70014
70229
|
});
|
|
70230
|
+
function resolveTerminationSignal(termination) {
|
|
70231
|
+
if (typeof termination.signal === "number" && termination.signal > 0) return termination.signal;
|
|
70232
|
+
const code = termination.exitCode;
|
|
70233
|
+
if (typeof code === "number" && code > 128 && code <= 159) return code - 128;
|
|
70234
|
+
return null;
|
|
70235
|
+
}
|
|
70236
|
+
function terminationSignalName(signal) {
|
|
70237
|
+
return signal !== null ? SIGNAL_NAMES[signal] : void 0;
|
|
70238
|
+
}
|
|
70239
|
+
function classifyMeshTerminationStop(termination) {
|
|
70240
|
+
const signal = resolveTerminationSignal(termination);
|
|
70241
|
+
const signalName = terminationSignalName(signal);
|
|
70242
|
+
if (termination.requestedStop) {
|
|
70243
|
+
return { reason: "host_requested_stop", intentional: true, signal, signalName };
|
|
70244
|
+
}
|
|
70245
|
+
if (signal !== null) return { reason: "external_signal", intentional: false, signal, signalName };
|
|
70246
|
+
if (termination.exitCode === null) return { reason: "unknown_termination", intentional: false, signal, signalName };
|
|
70247
|
+
if (termination.exitCode === 0) return { reason: "self_exit", intentional: false, signal, signalName };
|
|
70248
|
+
return { reason: "unexpected_exit", intentional: false, signal, signalName };
|
|
70249
|
+
}
|
|
70250
|
+
function buildMeshTerminationStopPayload(input) {
|
|
70251
|
+
const { termination } = input;
|
|
70252
|
+
const classified = classifyMeshTerminationStop(termination);
|
|
70253
|
+
const terminatedAtIso = Number.isFinite(termination.terminatedAt) ? new Date(termination.terminatedAt).toISOString() : void 0;
|
|
70254
|
+
const lastOutputAtIso = typeof termination.lastOutputAt === "number" && Number.isFinite(termination.lastOutputAt) ? new Date(termination.lastOutputAt).toISOString() : void 0;
|
|
70255
|
+
const silentForMs = typeof termination.lastOutputAt === "number" && Number.isFinite(termination.lastOutputAt) && Number.isFinite(termination.terminatedAt) && termination.terminatedAt >= termination.lastOutputAt ? termination.terminatedAt - termination.lastOutputAt : void 0;
|
|
70256
|
+
return {
|
|
70257
|
+
intentional: classified.intentional,
|
|
70258
|
+
reason: classified.reason,
|
|
70259
|
+
// `source` marks who wrote the row, mirroring the operator-cleanup path's
|
|
70260
|
+
// convention so a reader can tell the two writers apart.
|
|
70261
|
+
source: "session_host_tombstone",
|
|
70262
|
+
observedVia: "session_exit",
|
|
70263
|
+
exitCode: termination.exitCode,
|
|
70264
|
+
signal: classified.signal,
|
|
70265
|
+
...classified.signalName ? { signalName: classified.signalName } : {},
|
|
70266
|
+
// session-host's own classification, kept verbatim alongside ours so the
|
|
70267
|
+
// ledger never silently disagrees with the tombstone on disk.
|
|
70268
|
+
terminationReason: termination.reason,
|
|
70269
|
+
lifecycle: termination.lifecycle,
|
|
70270
|
+
...termination.previousLifecycle ? { previousLifecycle: termination.previousLifecycle } : {},
|
|
70271
|
+
...termination.requestedStop ? { requestedStop: termination.requestedStop } : {},
|
|
70272
|
+
...typeof termination.osPid === "number" ? { osPid: termination.osPid } : {},
|
|
70273
|
+
...terminatedAtIso ? { terminatedAt: terminatedAtIso } : {},
|
|
70274
|
+
...lastOutputAtIso ? { lastOutputAt: lastOutputAtIso } : {},
|
|
70275
|
+
...silentForMs !== void 0 ? { silentForMs } : {},
|
|
70276
|
+
...input.isCoordinator ? { coordinatorSession: true } : {},
|
|
70277
|
+
...input.workspace ? { workspace: input.workspace } : {}
|
|
70278
|
+
};
|
|
70279
|
+
}
|
|
70280
|
+
function resolveMeshTerminationBinding(settings) {
|
|
70281
|
+
if (!settings || typeof settings !== "object") return null;
|
|
70282
|
+
const read = (value) => typeof value === "string" ? value.trim() : "";
|
|
70283
|
+
const workerMeshId = read(settings.meshNodeFor);
|
|
70284
|
+
if (workerMeshId) {
|
|
70285
|
+
const nodeId = read(settings.meshNodeId);
|
|
70286
|
+
return { meshId: workerMeshId, ...nodeId ? { nodeId } : {}, isCoordinator: false };
|
|
70287
|
+
}
|
|
70288
|
+
const coordinatorMeshId = read(settings.meshCoordinatorFor);
|
|
70289
|
+
if (coordinatorMeshId) return { meshId: coordinatorMeshId, isCoordinator: true };
|
|
70290
|
+
return null;
|
|
70291
|
+
}
|
|
70292
|
+
async function recordMeshSessionTerminationStop(input) {
|
|
70293
|
+
if (!input.meshId || !input.sessionId) return;
|
|
70294
|
+
try {
|
|
70295
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
70296
|
+
appendLedgerEntry2(input.meshId, {
|
|
70297
|
+
kind: "session_stopped",
|
|
70298
|
+
...input.nodeId ? { nodeId: input.nodeId } : {},
|
|
70299
|
+
sessionId: input.sessionId,
|
|
70300
|
+
...input.providerType ? { providerType: input.providerType } : {},
|
|
70301
|
+
payload: buildMeshTerminationStopPayload(input)
|
|
70302
|
+
});
|
|
70303
|
+
} catch (e) {
|
|
70304
|
+
LOG2.warn("MeshTermination", `Failed to record termination stop for ${input.sessionId}: ${e?.message || e}`);
|
|
70305
|
+
}
|
|
70306
|
+
}
|
|
70307
|
+
var SIGNAL_NAMES;
|
|
70308
|
+
var init_mesh_termination_bridge = __esm2({
|
|
70309
|
+
"src/mesh/mesh-termination-bridge.ts"() {
|
|
70310
|
+
"use strict";
|
|
70311
|
+
init_logger();
|
|
70312
|
+
SIGNAL_NAMES = {
|
|
70313
|
+
1: "SIGHUP",
|
|
70314
|
+
2: "SIGINT",
|
|
70315
|
+
3: "SIGQUIT",
|
|
70316
|
+
6: "SIGABRT",
|
|
70317
|
+
9: "SIGKILL",
|
|
70318
|
+
11: "SIGSEGV",
|
|
70319
|
+
13: "SIGPIPE",
|
|
70320
|
+
15: "SIGTERM"
|
|
70321
|
+
};
|
|
70322
|
+
}
|
|
70323
|
+
});
|
|
70015
70324
|
function chunkPreservingSurrogates(text, size) {
|
|
70016
70325
|
const chunks = [];
|
|
70017
70326
|
let offset = 0;
|
|
@@ -74444,6 +74753,7 @@ ${cont}` : cont;
|
|
|
74444
74753
|
init_terminal_screen();
|
|
74445
74754
|
import_session_host_core8 = require_dist();
|
|
74446
74755
|
init_pty_transport();
|
|
74756
|
+
init_mesh_termination_bridge();
|
|
74447
74757
|
init_pty_write_chunking();
|
|
74448
74758
|
init_provider_cli_shared();
|
|
74449
74759
|
init_cli_script_runner();
|
|
@@ -74457,9 +74767,10 @@ ${cont}` : cont;
|
|
|
74457
74767
|
missingBackgroundSourceWarned = /* @__PURE__ */ new Set();
|
|
74458
74768
|
FORCE_SUBMIT_SETTLE_MS = 150;
|
|
74459
74769
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
74460
|
-
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
74770
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory(), owningSessionId) {
|
|
74461
74771
|
this.extraArgs = extraArgs;
|
|
74462
74772
|
this.extraEnv = extraEnv;
|
|
74773
|
+
this.owningSessionId = owningSessionId;
|
|
74463
74774
|
this.runner = new CliScriptRunner(provider.type);
|
|
74464
74775
|
this.provider = provider;
|
|
74465
74776
|
this.transportFactory = transportFactory;
|
|
@@ -74909,8 +75220,9 @@ ${lastSnapshot}`;
|
|
|
74909
75220
|
}
|
|
74910
75221
|
}
|
|
74911
75222
|
});
|
|
74912
|
-
this.ptyProcess.onExit(({ exitCode, signal }) => {
|
|
75223
|
+
this.ptyProcess.onExit(({ exitCode, signal, termination }) => {
|
|
74913
75224
|
LOG2.info("CLI", `[${this.cliType}] Exit code ${exitCode === null || exitCode === void 0 ? "unknown" : exitCode}${signal ? ` (signal ${signal})` : ""}`);
|
|
75225
|
+
this.recordMeshTerminationIfBound(termination);
|
|
74914
75226
|
this.flushPendingOutputParse();
|
|
74915
75227
|
this.ptyProcess = null;
|
|
74916
75228
|
this.engine.onPtyExit();
|
|
@@ -74938,6 +75250,38 @@ ${lastSnapshot}`;
|
|
|
74938
75250
|
this.scheduleStartupSettleCheck();
|
|
74939
75251
|
this.onStatusChange?.();
|
|
74940
75252
|
}
|
|
75253
|
+
/**
|
|
75254
|
+
* TOMBSTONE-LEDGER-BRIDGE: write a mesh `session_stopped` ledger entry for a
|
|
75255
|
+
* terminated mesh session.
|
|
75256
|
+
*
|
|
75257
|
+
* This is the daemon's existing observation point for a dying CLI child — the
|
|
75258
|
+
* session host already emits `session_exit` carrying its termination
|
|
75259
|
+
* classification, so no watcher or polling loop is added. Previously the
|
|
75260
|
+
* classification was discarded here, which is why an externally-killed mesh
|
|
75261
|
+
* session (e.g. a SIGTERM from outside the mesh) left the ledger with no entry
|
|
75262
|
+
* at all and its death read as an unexplained gap in the record.
|
|
75263
|
+
*
|
|
75264
|
+
* Silent no-op for a non-mesh session or a transport that reports no
|
|
75265
|
+
* termination (raw node-pty), and never throws into the exit path.
|
|
75266
|
+
*/
|
|
75267
|
+
recordMeshTerminationIfBound(termination) {
|
|
75268
|
+
if (!termination || !this.owningSessionId) return;
|
|
75269
|
+
try {
|
|
75270
|
+
const binding = resolveMeshTerminationBinding(this.runtimeSettings);
|
|
75271
|
+
if (!binding) return;
|
|
75272
|
+
void recordMeshSessionTerminationStop({
|
|
75273
|
+
meshId: binding.meshId,
|
|
75274
|
+
sessionId: this.owningSessionId,
|
|
75275
|
+
nodeId: binding.nodeId,
|
|
75276
|
+
providerType: this.cliType,
|
|
75277
|
+
workspace: this.workingDir,
|
|
75278
|
+
isCoordinator: binding.isCoordinator,
|
|
75279
|
+
termination
|
|
75280
|
+
});
|
|
75281
|
+
} catch (e) {
|
|
75282
|
+
LOG2.warn("CLI", `[${this.cliType}] mesh termination ledger bridge failed: ${e?.message || e}`);
|
|
75283
|
+
}
|
|
75284
|
+
}
|
|
74941
75285
|
// ─── Output Handling ────────────────────────────
|
|
74942
75286
|
handleOutput(rawData) {
|
|
74943
75287
|
this.terminalScreen.write(rawData);
|
|
@@ -84198,10 +84542,50 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84198
84542
|
init_contracts2();
|
|
84199
84543
|
init_chat_history();
|
|
84200
84544
|
init_state_store();
|
|
84201
|
-
init_coordinator_registry();
|
|
84202
|
-
init_mesh_turn_presentation();
|
|
84203
84545
|
init_logger();
|
|
84204
84546
|
init_debug_trace();
|
|
84547
|
+
init_chat_message_normalization();
|
|
84548
|
+
init_contracts2();
|
|
84549
|
+
init_coordinator_registry();
|
|
84550
|
+
init_logger();
|
|
84551
|
+
init_chat_message_normalization();
|
|
84552
|
+
function normalizeReadChatTailLimit(args) {
|
|
84553
|
+
const value = Number(args?.tailLimit || 0);
|
|
84554
|
+
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
84555
|
+
}
|
|
84556
|
+
function normalizeReadChatMessages(payload) {
|
|
84557
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
84558
|
+
return normalizeChatMessages(messages);
|
|
84559
|
+
}
|
|
84560
|
+
function maybeHideCoordinatorPromptMessage(h, providerType, sessionId, messages) {
|
|
84561
|
+
if (!Array.isArray(messages) || messages.length === 0) return messages;
|
|
84562
|
+
if (!sessionId) return messages;
|
|
84563
|
+
const loader2 = h.ctx?.providerLoader;
|
|
84564
|
+
if (!loader2) return messages;
|
|
84565
|
+
let showSetting = void 0;
|
|
84566
|
+
try {
|
|
84567
|
+
showSetting = loader2.getSettingValue?.(providerType, "showCoordinatorSystemPrompt");
|
|
84568
|
+
} catch {
|
|
84569
|
+
}
|
|
84570
|
+
if (showSetting === true) return messages;
|
|
84571
|
+
const coord = getCoordinatorForSession(sessionId);
|
|
84572
|
+
if (!coord) return messages;
|
|
84573
|
+
const promptBody = typeof coord.systemPrompt === "string" ? coord.systemPrompt : "";
|
|
84574
|
+
const MARKER = "adhdev-mesh-coordinator-prompt";
|
|
84575
|
+
const filtered = messages.filter((m) => {
|
|
84576
|
+
const role = String(m?.role || "").toLowerCase();
|
|
84577
|
+
if (role !== "user" && role !== "system") return true;
|
|
84578
|
+
const content = flattenContent(m?.content);
|
|
84579
|
+
if (!content) return true;
|
|
84580
|
+
if (content.includes(MARKER)) return false;
|
|
84581
|
+
if (promptBody && content.includes(promptBody.slice(0, Math.min(400, promptBody.length)))) return false;
|
|
84582
|
+
return true;
|
|
84583
|
+
});
|
|
84584
|
+
if (filtered.length !== messages.length) {
|
|
84585
|
+
LOG2.debug("ChatFilter", `[${providerType}] hid ${messages.length - filtered.length} coordinator-prompt message(s) from ${sessionId}`);
|
|
84586
|
+
}
|
|
84587
|
+
return filtered;
|
|
84588
|
+
}
|
|
84205
84589
|
var INITIAL_CHAT_SOURCE_STATE = Object.freeze({
|
|
84206
84590
|
name: "Booting",
|
|
84207
84591
|
nativeSequencePeak: void 0,
|
|
@@ -84571,9 +84955,394 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84571
84955
|
return `v1:${providerType}:${sessionId}:${ts2 ?? ""}:${positionalSeq}:${role}`;
|
|
84572
84956
|
}
|
|
84573
84957
|
var CHAT_SOURCE_REGISTRY = new ChatSourceRegistry();
|
|
84958
|
+
init_chat_history();
|
|
84959
|
+
var CLI_NATIVE_TRANSCRIPT_PROVIDERS = /* @__PURE__ */ new Set(["codex-cli", "claude-cli", "hermes-cli", "antigravity-cli"]);
|
|
84960
|
+
var warnedLegacyNativeAllowlistHits = /* @__PURE__ */ new Set();
|
|
84961
|
+
function warnLegacyNativeAllowlistHit(providerType) {
|
|
84962
|
+
if (warnedLegacyNativeAllowlistHits.has(providerType)) return;
|
|
84963
|
+
warnedLegacyNativeAllowlistHits.add(providerType);
|
|
84964
|
+
console.warn(
|
|
84965
|
+
`[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.`
|
|
84966
|
+
);
|
|
84967
|
+
}
|
|
84968
|
+
function supportsCliNativeTranscript(providerType, provider) {
|
|
84969
|
+
if (provider?.category === "cli" && isNativeSourceCanonicalHistory(provider?.nativeHistory)) {
|
|
84970
|
+
return true;
|
|
84971
|
+
}
|
|
84972
|
+
if (CLI_NATIVE_TRANSCRIPT_PROVIDERS.has(providerType)) {
|
|
84973
|
+
warnLegacyNativeAllowlistHit(providerType);
|
|
84974
|
+
return true;
|
|
84975
|
+
}
|
|
84976
|
+
return false;
|
|
84977
|
+
}
|
|
84978
|
+
function getMessageNewestReceivedAt(messages) {
|
|
84979
|
+
let newest = 0;
|
|
84980
|
+
for (const message of messages) {
|
|
84981
|
+
const receivedAt = Number(message?.receivedAt ?? message?.timestamp ?? 0);
|
|
84982
|
+
if (Number.isFinite(receivedAt) && receivedAt > newest) newest = receivedAt;
|
|
84983
|
+
}
|
|
84984
|
+
return newest;
|
|
84985
|
+
}
|
|
84986
|
+
function buildCliMessageSourceProvenance(args) {
|
|
84987
|
+
const sourceMtimeMs = Number(args.sourceMtimeMs || 0);
|
|
84988
|
+
const sourceMtimeAgeMs = sourceMtimeMs > 0 ? Math.max(0, Date.now() - sourceMtimeMs) : void 0;
|
|
84989
|
+
const nativeMessages = args.nativeMessages || [];
|
|
84990
|
+
const ptyMessages = args.ptyMessages || [];
|
|
84991
|
+
const returnedMessages = args.returnedMessages || [];
|
|
84992
|
+
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;
|
|
84993
|
+
return {
|
|
84994
|
+
selected: args.selected,
|
|
84995
|
+
provider: args.provider,
|
|
84996
|
+
providerType: args.provider,
|
|
84997
|
+
...identityStatus ? { identityStatus } : {},
|
|
84998
|
+
...args.nativeHandle ? { nativeHandle: args.nativeHandle } : {},
|
|
84999
|
+
...args.nativeHandle ? { nativeSessionId: args.nativeHandle } : {},
|
|
85000
|
+
...args.sessionWorkspace ? { sessionWorkspace: args.sessionWorkspace } : {},
|
|
85001
|
+
...args.intendedWorkspace ? { intendedWorkspace: args.intendedWorkspace } : {},
|
|
85002
|
+
...args.transcriptWorkspace ? { transcriptWorkspace: args.transcriptWorkspace } : {},
|
|
85003
|
+
...args.fallbackReason ? { fallbackReason: args.fallbackReason } : {},
|
|
85004
|
+
...args.nativeSource ? { nativeSource: args.nativeSource } : {},
|
|
85005
|
+
...args.sourcePath ? { sourcePath: args.sourcePath } : {},
|
|
85006
|
+
...args.nativeHistoryCoverage ? { nativeHistoryCoverage: args.nativeHistoryCoverage } : {},
|
|
85007
|
+
...args.partialReason ? { partialReason: args.partialReason } : {},
|
|
85008
|
+
...args.unavailableReason ? { unavailableReason: args.unavailableReason } : {},
|
|
85009
|
+
ptyStatusApprovalOnly: args.ptyStatusApprovalOnly === true,
|
|
85010
|
+
staleness: {
|
|
85011
|
+
sourceMtimeMs: sourceMtimeMs || void 0,
|
|
85012
|
+
sourceMtimeAgeMs,
|
|
85013
|
+
nativeNewestMessageAt: getMessageNewestReceivedAt(nativeMessages),
|
|
85014
|
+
ptyNewestMessageAt: getMessageNewestReceivedAt(ptyMessages),
|
|
85015
|
+
freshEnough: args.freshEnough === true
|
|
85016
|
+
},
|
|
85017
|
+
coverage: {
|
|
85018
|
+
nativeMessageCount: nativeMessages.length,
|
|
85019
|
+
ptyMessageCount: ptyMessages.length,
|
|
85020
|
+
returnedMessageCount: returnedMessages.length,
|
|
85021
|
+
safeMapping: args.safeMapping === true,
|
|
85022
|
+
// true when PTY message bodies are suppressed and must not be treated as
|
|
85023
|
+
// chat content. PTY may still contribute status/approval/screen evidence.
|
|
85024
|
+
ptyMessagesSuppressed: args.selected === "native-history" || args.ptyStatusApprovalOnly === true
|
|
85025
|
+
}
|
|
85026
|
+
};
|
|
85027
|
+
}
|
|
85028
|
+
function causeToLegacyFallbackReason(cause, selected, extraDetail) {
|
|
85029
|
+
if (selected === "native-history") return void 0;
|
|
85030
|
+
switch (cause) {
|
|
85031
|
+
case "initial":
|
|
85032
|
+
return "native_history_not_checked";
|
|
85033
|
+
case "native_progressed":
|
|
85034
|
+
return "native_history_not_selected";
|
|
85035
|
+
case "native_regressed_shrunk":
|
|
85036
|
+
return "native_history_empty";
|
|
85037
|
+
case "native_regressed_unsafe_mapping":
|
|
85038
|
+
return "native_history_not_safely_mapped";
|
|
85039
|
+
case "native_regressed_coverage_partial":
|
|
85040
|
+
return "native_history_partial";
|
|
85041
|
+
case "native_regressed_coverage_unavailable":
|
|
85042
|
+
return "native_history_unavailable";
|
|
85043
|
+
case "native_unavailable_read_error":
|
|
85044
|
+
return extraDetail?.unavailableReason ? `native_history_unavailable:${extraDetail.unavailableReason}` : "native_history_unavailable";
|
|
85045
|
+
case "native_unavailable_provider_unsupported":
|
|
85046
|
+
return "provider_native_transcript_not_supported";
|
|
85047
|
+
case "native_unavailable_empty":
|
|
85048
|
+
return "native_history_empty";
|
|
85049
|
+
case "native_unavailable_not_native_source":
|
|
85050
|
+
return extraDetail?.nativeSource ? `native_history_source_${extraDetail.nativeSource}` : "native_history_unavailable";
|
|
85051
|
+
}
|
|
85052
|
+
}
|
|
85053
|
+
function decideCliReadChatSource(args) {
|
|
85054
|
+
const supportsNative = supportsCliNativeTranscript(args.providerType, args.provider);
|
|
85055
|
+
const observation = buildObservationForCli(args, supportsNative);
|
|
85056
|
+
const sessionKey = chatSourceSessionKey(args.providerType, args.sessionId);
|
|
85057
|
+
const priorSnapshot = CHAT_SOURCE_REGISTRY.snapshotRecord(sessionKey);
|
|
85058
|
+
const priorState = priorSnapshot?.state ?? CHAT_SOURCE_REGISTRY.getState(sessionKey);
|
|
85059
|
+
const eligibleForStickyHold = args.trustedExactNativeIdentity === true && (priorState.name === "NativeLocked" || priorState.name === "Recovering");
|
|
85060
|
+
let decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
85061
|
+
const heldNativeMessages = observation.kind === "native_present" ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult) : [];
|
|
85062
|
+
const mayHoldNativeSlice = heldNativeMessages.length > 0 && args.safeMapping === true;
|
|
85063
|
+
if (eligibleForStickyHold && decision.selected === "pty-parser" && mayHoldNativeSlice) {
|
|
85064
|
+
CHAT_SOURCE_REGISTRY.restoreRecord(sessionKey, priorSnapshot);
|
|
85065
|
+
const messageSource2 = buildCliMessageSourceProvenance({
|
|
85066
|
+
selected: "native-history",
|
|
85067
|
+
provider: args.providerType,
|
|
85068
|
+
nativeHandle: typeof args.nativeHistoryResult?.providerSessionId === "string" ? args.nativeHistoryResult.providerSessionId : void 0,
|
|
85069
|
+
sessionWorkspace: args.sessionWorkspace,
|
|
85070
|
+
intendedWorkspace: args.intendedWorkspace,
|
|
85071
|
+
transcriptWorkspace: void 0,
|
|
85072
|
+
fallbackReason: "native_history_transient_gap_held",
|
|
85073
|
+
nativeSource: "provider-native",
|
|
85074
|
+
sourcePath: typeof args.nativeHistoryResult?.sourcePath === "string" ? args.nativeHistoryResult.sourcePath : void 0,
|
|
85075
|
+
sourceMtimeMs: typeof args.nativeHistoryResult?.sourceMtimeMs === "number" ? args.nativeHistoryResult.sourceMtimeMs : void 0,
|
|
85076
|
+
nativeHistoryCoverage: void 0,
|
|
85077
|
+
partialReason: void 0,
|
|
85078
|
+
unavailableReason: observation.kind === "native_unavailable" ? observation.reason : void 0,
|
|
85079
|
+
nativeMessages: heldNativeMessages,
|
|
85080
|
+
ptyMessages: args.ptyMessages,
|
|
85081
|
+
returnedMessages: heldNativeMessages,
|
|
85082
|
+
safeMapping: args.safeMapping,
|
|
85083
|
+
freshEnough: true,
|
|
85084
|
+
ptyStatusApprovalOnly: true
|
|
85085
|
+
});
|
|
85086
|
+
return {
|
|
85087
|
+
decision: {
|
|
85088
|
+
selected: "native-history",
|
|
85089
|
+
nextState: priorState,
|
|
85090
|
+
transition: {
|
|
85091
|
+
fromState: priorState.name,
|
|
85092
|
+
toState: priorState.name,
|
|
85093
|
+
event: "NoOp",
|
|
85094
|
+
cause: decision.transition.cause,
|
|
85095
|
+
at: Date.now()
|
|
85096
|
+
},
|
|
85097
|
+
lockState: { locked: priorState.name === "NativeLocked" }
|
|
85098
|
+
},
|
|
85099
|
+
messageSource: messageSource2,
|
|
85100
|
+
nativeMessages: heldNativeMessages,
|
|
85101
|
+
nativeSelected: true
|
|
85102
|
+
};
|
|
85103
|
+
}
|
|
85104
|
+
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) {
|
|
85105
|
+
CHAT_SOURCE_REGISTRY.clear(sessionKey);
|
|
85106
|
+
decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
|
|
85107
|
+
}
|
|
85108
|
+
const nativeMessages = observation.kind === "native_present" ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult) : [];
|
|
85109
|
+
const nativeSource = typeof args.nativeHistoryResult?.source === "string" ? args.nativeHistoryResult.source : void 0;
|
|
85110
|
+
const sourcePath = typeof args.nativeHistoryResult?.sourcePath === "string" ? args.nativeHistoryResult.sourcePath : void 0;
|
|
85111
|
+
const sourceMtimeMs = typeof args.nativeHistoryResult?.sourceMtimeMs === "number" ? args.nativeHistoryResult.sourceMtimeMs : void 0;
|
|
85112
|
+
const coverageHint = typeof args.nativeHistoryResult?.nativeHistoryCoverage === "string" ? args.nativeHistoryResult.nativeHistoryCoverage : void 0;
|
|
85113
|
+
const partialReason = typeof args.nativeHistoryResult?.partialReason === "string" ? args.nativeHistoryResult.partialReason : void 0;
|
|
85114
|
+
const unavailableReason = typeof args.nativeHistoryResult?.unavailableReason === "string" ? args.nativeHistoryResult.unavailableReason : args.nativeHistoryError ? `error:${args.nativeHistoryError?.message || String(args.nativeHistoryError)}` : void 0;
|
|
85115
|
+
const nativeHandle = typeof args.nativeHistoryResult?.providerSessionId === "string" ? args.nativeHistoryResult.providerSessionId : void 0;
|
|
85116
|
+
const transcriptWorkspace = typeof args.nativeHistoryResult?.workspace === "string" ? args.nativeHistoryResult.workspace : nativeMessages.map((m) => typeof m?.workspace === "string" ? m.workspace.trim() : "").find(Boolean);
|
|
85117
|
+
const fallbackReason = causeToLegacyFallbackReason(decision.transition.cause, decision.selected, {
|
|
85118
|
+
unavailableReason,
|
|
85119
|
+
nativeSource: nativeSource && nativeSource !== "provider-native" ? nativeSource : void 0
|
|
85120
|
+
});
|
|
85121
|
+
const ptyStatusApprovalOnly = decision.selected === "native-history" ? true : args.ptyStatusApprovalOnly;
|
|
85122
|
+
const messageSource = buildCliMessageSourceProvenance({
|
|
85123
|
+
selected: decision.selected,
|
|
85124
|
+
provider: args.providerType,
|
|
85125
|
+
nativeHandle,
|
|
85126
|
+
sessionWorkspace: args.sessionWorkspace,
|
|
85127
|
+
intendedWorkspace: args.intendedWorkspace,
|
|
85128
|
+
transcriptWorkspace,
|
|
85129
|
+
fallbackReason,
|
|
85130
|
+
nativeSource,
|
|
85131
|
+
sourcePath,
|
|
85132
|
+
sourceMtimeMs,
|
|
85133
|
+
nativeHistoryCoverage: coverageHint,
|
|
85134
|
+
partialReason,
|
|
85135
|
+
unavailableReason,
|
|
85136
|
+
nativeMessages,
|
|
85137
|
+
ptyMessages: args.ptyMessages,
|
|
85138
|
+
returnedMessages: decision.selected === "native-history" ? nativeMessages : args.ptyMessages,
|
|
85139
|
+
safeMapping: args.safeMapping,
|
|
85140
|
+
// freshEnough is a v1 concept the machine does not model directly.
|
|
85141
|
+
// We surface lockState.locked here so v1 consumers reading
|
|
85142
|
+
// staleness.freshEnough still get a meaningful boolean.
|
|
85143
|
+
freshEnough: decision.lockState.locked,
|
|
85144
|
+
ptyStatusApprovalOnly
|
|
85145
|
+
});
|
|
85146
|
+
return {
|
|
85147
|
+
decision,
|
|
85148
|
+
messageSource,
|
|
85149
|
+
nativeMessages,
|
|
85150
|
+
nativeSelected: decision.selected === "native-history"
|
|
85151
|
+
};
|
|
85152
|
+
}
|
|
85153
|
+
function buildObservationForCli(args, supportsNative) {
|
|
85154
|
+
if (!supportsNative) {
|
|
85155
|
+
return { kind: "native_unavailable", reason: "provider_not_supported" };
|
|
85156
|
+
}
|
|
85157
|
+
if (args.nativeHistoryError) {
|
|
85158
|
+
return { kind: "native_unavailable", reason: "read_error" };
|
|
85159
|
+
}
|
|
85160
|
+
const result = args.nativeHistoryResult;
|
|
85161
|
+
if (!result || typeof result !== "object") {
|
|
85162
|
+
return { kind: "native_unavailable", reason: "read_error" };
|
|
85163
|
+
}
|
|
85164
|
+
const source = typeof result.source === "string" ? result.source : "";
|
|
85165
|
+
if (source && source !== "provider-native") {
|
|
85166
|
+
return { kind: "native_unavailable", reason: source === "native-unavailable" ? "empty" : "not_native_source" };
|
|
85167
|
+
}
|
|
85168
|
+
const messages = Array.isArray(result.messages) ? result.messages : [];
|
|
85169
|
+
if (messages.length === 0) {
|
|
85170
|
+
return { kind: "native_unavailable", reason: "empty" };
|
|
85171
|
+
}
|
|
85172
|
+
const coverage = typeof result.nativeHistoryCoverage === "string" ? result.nativeHistoryCoverage : "tail";
|
|
85173
|
+
if (coverage === "unavailable") {
|
|
85174
|
+
return { kind: "native_unavailable", reason: "coverage_unavailable" };
|
|
85175
|
+
}
|
|
85176
|
+
return buildV1NativePresentObservation({
|
|
85177
|
+
providerType: args.providerType,
|
|
85178
|
+
sessionId: args.sessionId,
|
|
85179
|
+
messages,
|
|
85180
|
+
coverage: coverage === "full" || coverage === "tail" || coverage === "current-turn" || coverage === "partial" ? coverage : "tail",
|
|
85181
|
+
safeMapping: args.safeMapping
|
|
85182
|
+
});
|
|
85183
|
+
}
|
|
85184
|
+
function extractNativeMessagesFromResult(providerType, result) {
|
|
85185
|
+
if (!result || !Array.isArray(result.messages)) return [];
|
|
85186
|
+
return normalizeNativeHistoryMessages(
|
|
85187
|
+
providerType,
|
|
85188
|
+
result.messages,
|
|
85189
|
+
typeof result.providerSessionId === "string" ? result.providerSessionId : void 0
|
|
85190
|
+
);
|
|
85191
|
+
}
|
|
85192
|
+
init_mesh_turn_presentation();
|
|
84574
85193
|
init_chat_message_normalization();
|
|
85194
|
+
function shouldPreserveReadChatPayloadField(key2) {
|
|
85195
|
+
return key2 === "messageSource" || key2 === "transcriptProvenance";
|
|
85196
|
+
}
|
|
85197
|
+
function updateMessageSourceReturnedCount(value, returnedMessageCount) {
|
|
85198
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
85199
|
+
const record2 = value;
|
|
85200
|
+
const coverage = record2.coverage && typeof record2.coverage === "object" && !Array.isArray(record2.coverage) ? record2.coverage : void 0;
|
|
85201
|
+
if (!coverage) return value;
|
|
85202
|
+
return {
|
|
85203
|
+
...record2,
|
|
85204
|
+
coverage: {
|
|
85205
|
+
...coverage,
|
|
85206
|
+
returnedMessageCount
|
|
85207
|
+
}
|
|
85208
|
+
};
|
|
85209
|
+
}
|
|
85210
|
+
function buildFullTail(messages, tailLimit) {
|
|
85211
|
+
const totalMessages = messages.length;
|
|
85212
|
+
const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
|
|
85213
|
+
return {
|
|
85214
|
+
messages: tailMessages,
|
|
85215
|
+
totalMessages
|
|
85216
|
+
};
|
|
85217
|
+
}
|
|
85218
|
+
function hasNonEmptyModalButtons(activeModal) {
|
|
85219
|
+
if (!activeModal || typeof activeModal !== "object") return false;
|
|
85220
|
+
const buttons = activeModal.buttons;
|
|
85221
|
+
return Array.isArray(buttons) && buttons.some((button) => typeof button === "string" && button.trim().length > 0);
|
|
85222
|
+
}
|
|
85223
|
+
function normalizeReadChatCommandStatus(status, activeModal) {
|
|
85224
|
+
const raw = typeof status === "string" ? status.trim() : "";
|
|
85225
|
+
if (!raw) {
|
|
85226
|
+
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "idle";
|
|
85227
|
+
}
|
|
85228
|
+
switch (raw) {
|
|
85229
|
+
case "starting":
|
|
85230
|
+
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "starting";
|
|
85231
|
+
case "stopped":
|
|
85232
|
+
case "disconnected":
|
|
85233
|
+
case "not_monitored":
|
|
85234
|
+
return "error";
|
|
85235
|
+
case "waiting_approval":
|
|
85236
|
+
return hasNonEmptyModalButtons(activeModal) ? "waiting_approval" : "generating";
|
|
85237
|
+
default:
|
|
85238
|
+
return raw;
|
|
85239
|
+
}
|
|
85240
|
+
}
|
|
85241
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
85242
|
+
if (status !== "idle") return messages;
|
|
85243
|
+
return messages.map((message) => {
|
|
85244
|
+
const meta3 = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
85245
|
+
const hasStreamingMeta = meta3?.streaming === true;
|
|
85246
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
85247
|
+
return {
|
|
85248
|
+
...message,
|
|
85249
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
85250
|
+
...hasStreamingMeta ? { meta: { ...meta3, streaming: false } } : {}
|
|
85251
|
+
};
|
|
85252
|
+
});
|
|
85253
|
+
}
|
|
85254
|
+
function collapseAdjacentDuplicateChatMessages(messages) {
|
|
85255
|
+
if (!Array.isArray(messages) || messages.length <= 1) return messages;
|
|
85256
|
+
const result = [];
|
|
85257
|
+
let prevRoleKind = "";
|
|
85258
|
+
let prevStripped = "";
|
|
85259
|
+
for (const message of messages) {
|
|
85260
|
+
const role = typeof message.role === "string" ? message.role : "";
|
|
85261
|
+
const kind = typeof message.kind === "string" ? message.kind : "standard";
|
|
85262
|
+
const content = typeof message.content === "string" ? message.content : Array.isArray(message.content) ? message.content.map((p) => typeof p?.text === "string" ? p.text : "").join("") : "";
|
|
85263
|
+
const strippedContent = content.replace(/\s+/g, "");
|
|
85264
|
+
if (!strippedContent || role === "system") {
|
|
85265
|
+
result.push(message);
|
|
85266
|
+
prevRoleKind = "";
|
|
85267
|
+
prevStripped = "";
|
|
85268
|
+
continue;
|
|
85269
|
+
}
|
|
85270
|
+
const roleKind = `${role}:${kind}`;
|
|
85271
|
+
const sameStripped = strippedContent === prevStripped && roleKind === prevRoleKind;
|
|
85272
|
+
if (result.length > 0 && sameStripped) {
|
|
85273
|
+
result[result.length - 1] = message;
|
|
85274
|
+
prevRoleKind = roleKind;
|
|
85275
|
+
prevStripped = strippedContent;
|
|
85276
|
+
continue;
|
|
85277
|
+
}
|
|
85278
|
+
result.push(message);
|
|
85279
|
+
prevRoleKind = roleKind;
|
|
85280
|
+
prevStripped = strippedContent;
|
|
85281
|
+
}
|
|
85282
|
+
return result;
|
|
85283
|
+
}
|
|
85284
|
+
function buildReadChatCommandResult(payload, args, h) {
|
|
85285
|
+
let validatedPayload;
|
|
85286
|
+
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
85287
|
+
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) : "";
|
|
85288
|
+
const providerHint = typeof args?.cliType === "string" ? args.cliType : typeof args?.providerType === "string" ? args.providerType : typeof args?.agentType === "string" ? args.agentType : "";
|
|
85289
|
+
const legacyStatus = normalizeReadChatCommandStatus(payload?.status, payload?.activeModal);
|
|
85290
|
+
const turnPresentation = resolveSessionTurnPresentation({
|
|
85291
|
+
sessionId: presentationSessionIdHint || void 0,
|
|
85292
|
+
legacyStatus,
|
|
85293
|
+
providerType: providerHint || void 0,
|
|
85294
|
+
surface: "read_chat"
|
|
85295
|
+
});
|
|
85296
|
+
let effectiveStatus = legacyStatus;
|
|
85297
|
+
if (turnPresentation.authority === "turn_reducer") {
|
|
85298
|
+
effectiveStatus = turnPresentation.status;
|
|
85299
|
+
if (effectiveStatus === "waiting_approval" && !hasNonEmptyModalButtons(payload?.activeModal)) {
|
|
85300
|
+
effectiveStatus = "generating";
|
|
85301
|
+
}
|
|
85302
|
+
}
|
|
85303
|
+
try {
|
|
85304
|
+
validatedPayload = validateReadChatResultPayload({
|
|
85305
|
+
...payload,
|
|
85306
|
+
status: effectiveStatus
|
|
85307
|
+
}, "read_chat command result");
|
|
85308
|
+
} catch (error48) {
|
|
85309
|
+
return { success: false, error: error48?.message || String(error48) };
|
|
85310
|
+
}
|
|
85311
|
+
const messages = normalizeReadChatMessages(validatedPayload);
|
|
85312
|
+
const sessionIdHint = typeof args?.targetSessionId === "string" ? args.targetSessionId : typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
85313
|
+
const filteredMessages = h ? maybeHideCoordinatorPromptMessage(h, providerHint, sessionIdHint, messages) : messages;
|
|
85314
|
+
const includeActivity = args?.includeActivity === true || args?.includeActivity === "true";
|
|
85315
|
+
const visibleMessages = includeActivity ? filteredMessages.filter((m) => isUserFacingChatMessage(m) || isActivityChatMessage(m)) : filterUserFacingChatMessages(filteredMessages);
|
|
85316
|
+
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
85317
|
+
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
85318
|
+
const preservedPayloadFields = Object.fromEntries(Object.entries(payload).filter(([key2]) => shouldPreserveReadChatPayloadField(key2)));
|
|
85319
|
+
if (preservedPayloadFields.messageSource) {
|
|
85320
|
+
preservedPayloadFields.messageSource = updateMessageSourceReturnedCount(preservedPayloadFields.messageSource, sync.messages.length);
|
|
85321
|
+
}
|
|
85322
|
+
if (preservedPayloadFields.transcriptProvenance) {
|
|
85323
|
+
preservedPayloadFields.transcriptProvenance = updateMessageSourceReturnedCount(preservedPayloadFields.transcriptProvenance, sync.messages.length);
|
|
85324
|
+
}
|
|
85325
|
+
const returnedDebugReadChat = debugReadChat ? {
|
|
85326
|
+
...debugReadChat,
|
|
85327
|
+
fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
|
|
85328
|
+
visibleMsgCount: visibleMessages.length,
|
|
85329
|
+
hiddenMsgCount,
|
|
85330
|
+
returnedMsgCount: sync.messages.length
|
|
85331
|
+
} : void 0;
|
|
85332
|
+
return {
|
|
85333
|
+
success: true,
|
|
85334
|
+
...validatedPayload,
|
|
85335
|
+
...preservedPayloadFields,
|
|
85336
|
+
messages: sync.messages,
|
|
85337
|
+
totalMessages: sync.totalMessages,
|
|
85338
|
+
// Stage 6: the authoritative turn presentation rides the read_chat
|
|
85339
|
+
// payload for mesh-owned sessions (identity + stage + evidence
|
|
85340
|
+
// timestamps; the `status` field above already reflects it).
|
|
85341
|
+
...turnPresentation.authority === "turn_reducer" ? { turn: turnPresentation } : {},
|
|
85342
|
+
...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
|
|
85343
|
+
};
|
|
85344
|
+
}
|
|
84575
85345
|
var HOT_TAIL_MIN_LIMIT = 60;
|
|
84576
|
-
var CLI_NATIVE_TRANSCRIPT_PROVIDERS = /* @__PURE__ */ new Set(["codex-cli", "claude-cli", "hermes-cli", "antigravity-cli"]);
|
|
84577
85346
|
var lastBoundProviderSessionIdByMeshSession = /* @__PURE__ */ new Map();
|
|
84578
85347
|
var persistedProviderSessionPinsHydrated = false;
|
|
84579
85348
|
function hydratePersistedProviderSessionPinsOnce() {
|
|
@@ -84609,14 +85378,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84609
85378
|
const pinned = lastBoundProviderSessionIdByMeshSession.get(key2);
|
|
84610
85379
|
return pinned && pinned.trim() ? pinned.trim() : void 0;
|
|
84611
85380
|
}
|
|
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
85381
|
function getExplicitHistorySessionId(args) {
|
|
84621
85382
|
const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
|
|
84622
85383
|
if (explicit) return explicit;
|
|
@@ -84695,22 +85456,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84695
85456
|
payload: options.payload
|
|
84696
85457
|
});
|
|
84697
85458
|
}
|
|
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
85459
|
function readHistorySessionIdFromMessages(messages) {
|
|
84715
85460
|
for (const message of messages) {
|
|
84716
85461
|
const historySessionId = typeof message?.historySessionId === "string" ? message.historySessionId.trim() : "";
|
|
@@ -84731,35 +85476,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84731
85476
|
}
|
|
84732
85477
|
return true;
|
|
84733
85478
|
}
|
|
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
85479
|
function normalizeAndFilterNativeHistory(h, providerType, args, messages, nativeSessionId) {
|
|
84764
85480
|
const normalized = normalizeNativeHistoryMessages(providerType, messages, nativeSessionId);
|
|
84765
85481
|
const sessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -84833,212 +85549,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
84833
85549
|
};
|
|
84834
85550
|
});
|
|
84835
85551
|
}
|
|
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
85552
|
function applyUnsafeNativeDaemonFallback(args) {
|
|
85043
85553
|
if (args.adapter.cliType !== "codex-cli") {
|
|
85044
85554
|
return;
|
|
@@ -85210,16 +85720,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85210
85720
|
const start = Math.max(0, end - args.limit);
|
|
85211
85721
|
return { messages: ptyMessages.slice(start, end), hasMore: start > 0 };
|
|
85212
85722
|
}
|
|
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
85723
|
function getComparableVisibleText(message) {
|
|
85224
85724
|
if (!message) return "";
|
|
85225
85725
|
const role = String(message.role || "").trim().toLowerCase();
|
|
@@ -85352,22 +85852,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85352
85852
|
});
|
|
85353
85853
|
return { ...history, lookup: "workspace" };
|
|
85354
85854
|
}
|
|
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
85855
|
function deriveHistoryDedupKey(message) {
|
|
85372
85856
|
const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
|
|
85373
85857
|
if (unitKey) return `read_chat:${unitKey}`;
|
|
@@ -85391,37 +85875,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85391
85875
|
historyDedupKey: deriveHistoryDedupKey(message)
|
|
85392
85876
|
}));
|
|
85393
85877
|
}
|
|
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
85878
|
function isGeneratingLikeStatus(status) {
|
|
85426
85879
|
return status === "generating" || status === "streaming" || status === "no_progress" || status === "long_generating" || status === "starting";
|
|
85427
85880
|
}
|
|
@@ -85461,110 +85914,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
85461
85914
|
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
85462
85915
|
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
85463
85916
|
}
|
|
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
85917
|
function toNonNegativeNumber(value) {
|
|
85569
85918
|
const numeric = Number(value ?? 0);
|
|
85570
85919
|
return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
|
|
@@ -95473,7 +95822,7 @@ ${marker}`,
|
|
|
95473
95822
|
LOG2.warn("spec-route", `[${provider.type}] spec invalid, falling back to ProviderCliAdapter: ${err.message}`);
|
|
95474
95823
|
}
|
|
95475
95824
|
}
|
|
95476
|
-
return new ProviderCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFactory);
|
|
95825
|
+
return new ProviderCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFactory, sessionId);
|
|
95477
95826
|
}
|
|
95478
95827
|
init_chat_history();
|
|
95479
95828
|
init_logger();
|
|
@@ -102801,7 +103150,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
102801
103150
|
const { shouldDeferDispatchForBootstrap: shouldDeferDispatchForBootstrap2 } = await Promise.resolve().then(() => (init_worktree_bootstrap_config(), worktree_bootstrap_config_exports));
|
|
102802
103151
|
if (shouldDeferDispatchForBootstrap2(nodeObj)) {
|
|
102803
103152
|
const dispatchSessionState = dispatchSessionId ? ctx.deps.instanceManager?.getInstance?.(dispatchSessionId)?.getState?.() : void 0;
|
|
102804
|
-
const sessionConfirmedReady = !!dispatchSessionState &&
|
|
103153
|
+
const sessionConfirmedReady = !!dispatchSessionState && isIdleSessionState2(dispatchSessionState);
|
|
102805
103154
|
if (!sessionConfirmedReady) {
|
|
102806
103155
|
return {
|
|
102807
103156
|
success: false,
|
|
@@ -110641,7 +110990,8 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
110641
110990
|
drain: { ...getMeshV2DrainCounters() },
|
|
110642
110991
|
backstop: { ...getMeshV2BackstopCounters() }
|
|
110643
110992
|
};
|
|
110644
|
-
|
|
110993
|
+
const pendingRetentionCounters2 = { ...getPendingRetentionCounters() };
|
|
110994
|
+
return { success: true, events, hasLiveCliCoordinator, meshProtocolV2Counters, pendingRetentionCounters: pendingRetentionCounters2, ...selfCoordinatorInboxRead ? { surfacedForSelfCoordinator: true } : {} };
|
|
110645
110995
|
},
|
|
110646
110996
|
interactive_prompt_response: async (ctx, args) => {
|
|
110647
110997
|
const sessionId = typeof args?.targetSessionId === "string" && args.targetSessionId.trim() ? args.targetSessionId.trim() : typeof args?.sessionId === "string" && args.sessionId.trim() ? args.sessionId.trim() : "";
|
|
@@ -111798,6 +112148,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
111798
112148
|
drain: { ...getMeshV2DrainCounters() },
|
|
111799
112149
|
backstop: { ...getMeshV2BackstopCounters() }
|
|
111800
112150
|
};
|
|
112151
|
+
const pendingRetentionCounters2 = { ...getPendingRetentionCounters() };
|
|
111801
112152
|
const turnPresentationCounters = getTurnPresentationMetrics();
|
|
111802
112153
|
const previewFreshness = (() => {
|
|
111803
112154
|
const localRepoRoot = nodeStatuses.map((node) => readStringValue(node?.git?.repoRoot, node?.repoRoot, node?.workspace)).find((candidate) => !!candidate && fs43.existsSync(candidate));
|
|
@@ -111889,6 +112240,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
111889
112240
|
...pendingCoordinatorEvents.length > 0 ? { pendingCoordinatorEvents } : {},
|
|
111890
112241
|
...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {},
|
|
111891
112242
|
meshProtocolV2Counters,
|
|
112243
|
+
pendingRetentionCounters: pendingRetentionCounters2,
|
|
111892
112244
|
turnPresentationCounters,
|
|
111893
112245
|
activeRefineJobs: Array.from(ctx.runningRefineJobs.values()).filter((job) => job.meshId === meshId).map((job) => ({
|
|
111894
112246
|
jobId: job.jobId,
|
|
@@ -111899,13 +112251,14 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
111899
112251
|
targetCoordinatorDaemonId: job.targetCoordinatorDaemonId
|
|
111900
112252
|
}))
|
|
111901
112253
|
};
|
|
111902
|
-
const { pendingCoordinatorEvents: _pendingCoordinatorEvents, unroutableDeliveries: _unroutableDeliveries, meshProtocolV2Counters: _meshProtocolV2Counters, turnPresentationCounters: _turnPresentationCounters, ...cacheableStatusResult } = statusResult;
|
|
112254
|
+
const { pendingCoordinatorEvents: _pendingCoordinatorEvents, unroutableDeliveries: _unroutableDeliveries, meshProtocolV2Counters: _meshProtocolV2Counters, pendingRetentionCounters: _pendingRetentionCounters, turnPresentationCounters: _turnPresentationCounters, ...cacheableStatusResult } = statusResult;
|
|
111903
112255
|
const rememberedStatus = verboseMissions ? cacheableStatusResult : ctx.rememberAggregateMeshStatus(meshId, cacheableStatusResult, refreshReason);
|
|
111904
112256
|
const returnedStatus = {
|
|
111905
112257
|
...rememberedStatus,
|
|
111906
112258
|
...pendingCoordinatorEvents.length > 0 ? { pendingCoordinatorEvents } : {},
|
|
111907
112259
|
...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {},
|
|
111908
112260
|
meshProtocolV2Counters,
|
|
112261
|
+
pendingRetentionCounters: pendingRetentionCounters2,
|
|
111909
112262
|
turnPresentationCounters
|
|
111910
112263
|
};
|
|
111911
112264
|
logRepoMeshStatusDebug("return_live", {
|
|
@@ -115770,17 +116123,27 @@ ${e?.stderr || ""}`;
|
|
|
115770
116123
|
}
|
|
115771
116124
|
async function startMeshRefineJob(self, meshId, nodeId, args) {
|
|
115772
116125
|
const key2 = buildRefineJobKey(self, meshId, nodeId);
|
|
115773
|
-
const running = self.runningRefineJobs.get(key2);
|
|
115774
|
-
if (running) return { ...running, duplicate: true };
|
|
115775
116126
|
const terminal = self.terminalRefineJobs.get(key2);
|
|
116127
|
+
const alreadyRunning = self.runningRefineJobs.get(key2);
|
|
116128
|
+
if (alreadyRunning) return { ...alreadyRunning, duplicate: true };
|
|
116129
|
+
const jobId = `refine_${createInteractionId()}`;
|
|
116130
|
+
const interactionId = createInteractionId();
|
|
116131
|
+
const placeholder = buildRefineJobHandle(self, { meshId, nodeId, jobId, interactionId, retryOfJobId: terminal?.jobId });
|
|
116132
|
+
self.runningRefineJobs.set(key2, placeholder);
|
|
115776
116133
|
const meshRecord = await self.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
115777
116134
|
const mesh = meshRecord?.mesh;
|
|
115778
116135
|
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
115779
|
-
if (!node)
|
|
115780
|
-
|
|
116136
|
+
if (!node) {
|
|
116137
|
+
self.runningRefineJobs.delete(key2);
|
|
116138
|
+
return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
116139
|
+
}
|
|
116140
|
+
if (!node.isLocalWorktree || !node.workspace) {
|
|
116141
|
+
self.runningRefineJobs.delete(key2);
|
|
116142
|
+
return { success: false, error: `Refinery requires a local worktree node` };
|
|
116143
|
+
}
|
|
115781
116144
|
const coordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : self.deps.statusInstanceId || void 0;
|
|
115782
116145
|
const coordinatorSessionId = typeof args?.coordinatorSessionId === "string" && args.coordinatorSessionId.trim() ? args.coordinatorSessionId.trim() : void 0;
|
|
115783
|
-
const handle = buildRefineJobHandle(self, { meshId, nodeId, node, retryOfJobId: terminal?.jobId, coordinatorDaemonId, coordinatorSessionId });
|
|
116146
|
+
const handle = buildRefineJobHandle(self, { meshId, nodeId, node, jobId, interactionId, retryOfJobId: terminal?.jobId, coordinatorDaemonId, coordinatorSessionId });
|
|
115784
116147
|
self.runningRefineJobs.set(key2, handle);
|
|
115785
116148
|
await appendRefineJobLedger(self, "task_dispatched", handle);
|
|
115786
116149
|
queueRefineJobEvent(self, "refine:accepted", handle);
|
|
@@ -124411,8 +124774,9 @@ data: ${JSON.stringify(msg.data)}
|
|
|
124411
124774
|
if (event.type === "session_exit") {
|
|
124412
124775
|
const exitCode = typeof event.exitCode === "number" ? event.exitCode : null;
|
|
124413
124776
|
const signal = typeof event.signal === "number" ? event.signal : null;
|
|
124777
|
+
const termination = event.termination;
|
|
124414
124778
|
for (const callback of this.exitCallbacks) {
|
|
124415
|
-
callback({ exitCode, signal });
|
|
124779
|
+
callback({ exitCode, signal, termination });
|
|
124416
124780
|
}
|
|
124417
124781
|
void this.closeClient(false);
|
|
124418
124782
|
}
|