@adhdev/daemon-standalone 1.0.43 → 1.0.44-rc.1

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