@adhdev/daemon-core 0.9.82-rc.400 → 0.9.82-rc.402

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.mjs CHANGED
@@ -394,10 +394,10 @@ function readInjected(value) {
394
394
  }
395
395
  function getDaemonBuildInfo() {
396
396
  if (cached) return cached;
397
- const commit = readInjected(true ? "2350563490670c1c560cc5cf6f863a9e61ef3f89" : void 0) ?? "unknown";
398
- const commitShort = readInjected(true ? "23505634" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
399
- const version = readInjected(true ? "0.9.82-rc.400" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
400
- const builtAt = readInjected(true ? "2026-06-27T13:15:45.410Z" : void 0);
397
+ const commit = readInjected(true ? "93b00efeec1fccd6550c1faf5fa838106caef4bb" : void 0) ?? "unknown";
398
+ const commitShort = readInjected(true ? "93b00efe" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
399
+ const version = readInjected(true ? "0.9.82-rc.402" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
400
+ const builtAt = readInjected(true ? "2026-06-27T16:41:05.513Z" : void 0);
401
401
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
402
402
  return cached;
403
403
  }
@@ -1441,16 +1441,103 @@ function resolveWorktreePath(repoRoot, meshName, branch) {
1441
1441
  const parentDir = path4.dirname(repoRoot);
1442
1442
  return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
1443
1443
  }
1444
+ async function tryGit(cwd, args) {
1445
+ try {
1446
+ const { stdout, stderr } = await execFileAsync2("git", args, {
1447
+ cwd,
1448
+ encoding: "utf8",
1449
+ timeout: GIT_TIMEOUT_MS,
1450
+ maxBuffer: GIT_MAX_BUFFER,
1451
+ windowsHide: true
1452
+ });
1453
+ return { ok: true, stdout: (stdout || "").trim(), stderr: (stderr || "").trim() };
1454
+ } catch (error) {
1455
+ return {
1456
+ ok: false,
1457
+ stdout: typeof error?.stdout === "string" ? error.stdout.trim() : "",
1458
+ stderr: typeof error?.stderr === "string" ? error.stderr.trim() : error?.message || ""
1459
+ };
1460
+ }
1461
+ }
1462
+ async function resolveWorktreeBaseStartPoint(repoRoot, baseBranch, remote) {
1463
+ const fetchResult = await tryGit(repoRoot, ["fetch", remote, baseBranch]);
1464
+ const fetched = fetchResult.ok;
1465
+ const localRev = await tryGit(repoRoot, ["rev-parse", "--verify", "--quiet", `refs/heads/${baseBranch}`]);
1466
+ const remoteRev = await tryGit(repoRoot, ["rev-parse", "--verify", "--quiet", `refs/remotes/${remote}/${baseBranch}`]);
1467
+ const localSha = localRev.ok && localRev.stdout ? localRev.stdout : void 0;
1468
+ const remoteSha = remoteRev.ok && remoteRev.stdout ? remoteRev.stdout : void 0;
1469
+ const remoteRef = `${remote}/${baseBranch}`;
1470
+ const base = {
1471
+ branch: baseBranch,
1472
+ remote,
1473
+ startRef: baseBranch,
1474
+ fetched,
1475
+ localSha,
1476
+ remoteSha,
1477
+ behindBy: 0,
1478
+ aheadBy: 0,
1479
+ action: "up_to_date"
1480
+ };
1481
+ const fetchWarn = fetched ? "" : ` (warning: git fetch ${remote} ${baseBranch} failed: ${fetchResult.stderr || "unknown error"})`;
1482
+ if (!remoteSha) {
1483
+ return {
1484
+ ...base,
1485
+ action: "no_remote_ref_used_local",
1486
+ ...fetched ? {} : { warning: `Could not fetch ${remoteRef}${fetchWarn}; worktree branched from local ${baseBranch}.` }
1487
+ };
1488
+ }
1489
+ if (!localSha) {
1490
+ return {
1491
+ ...base,
1492
+ startRef: remoteRef,
1493
+ action: "no_local_ref_used_remote"
1494
+ };
1495
+ }
1496
+ if (localSha === remoteSha) {
1497
+ return base;
1498
+ }
1499
+ const localIsAncestor = (await tryGit(repoRoot, ["merge-base", "--is-ancestor", localSha, remoteSha])).ok;
1500
+ const remoteIsAncestor = (await tryGit(repoRoot, ["merge-base", "--is-ancestor", remoteSha, localSha])).ok;
1501
+ const behindBy = Number((await tryGit(repoRoot, ["rev-list", "--count", `${localSha}..${remoteSha}`])).stdout) || 0;
1502
+ const aheadBy = Number((await tryGit(repoRoot, ["rev-list", "--count", `${remoteSha}..${localSha}`])).stdout) || 0;
1503
+ if (localIsAncestor && !remoteIsAncestor) {
1504
+ return {
1505
+ ...base,
1506
+ startRef: remoteRef,
1507
+ behindBy,
1508
+ aheadBy,
1509
+ action: "local_behind_used_remote",
1510
+ warning: `Base node local ${baseBranch} was behind ${remoteRef} by ${behindBy} commit(s); worktree branched from ${remoteRef} (${remoteSha.slice(0, 8)}) instead of stale local ${localSha.slice(0, 8)}.${fetchWarn}`
1511
+ };
1512
+ }
1513
+ if (remoteIsAncestor) {
1514
+ return { ...base, behindBy, aheadBy, action: "local_ahead_used_local" };
1515
+ }
1516
+ return {
1517
+ ...base,
1518
+ behindBy,
1519
+ aheadBy,
1520
+ action: "diverged_used_local",
1521
+ warning: `Base node local ${baseBranch} (${localSha.slice(0, 8)}) has DIVERGED from ${remoteRef} (${remoteSha.slice(0, 8)}): behind ${behindBy}, ahead ${aheadBy}. Worktree branched from local; a rebase onto ${remoteRef} will be required before its push can fast-forward.${fetchWarn}`
1522
+ };
1523
+ }
1444
1524
  async function createWorktree(opts) {
1445
1525
  const { repoRoot, branch, baseBranch, meshName } = opts;
1526
+ const remote = (opts.remote || "origin").trim() || "origin";
1446
1527
  const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
1447
1528
  if (existsSync2(targetDir)) {
1448
1529
  throw new Error(`Worktree target directory already exists: ${targetDir}`);
1449
1530
  }
1450
1531
  await mkdir(path4.dirname(targetDir), { recursive: true });
1532
+ let baseSync;
1533
+ let startRef = baseBranch;
1534
+ if (baseBranch && opts.syncBaseFromRemote !== false) {
1535
+ baseSync = await resolveWorktreeBaseStartPoint(repoRoot, baseBranch, remote);
1536
+ startRef = baseSync.startRef;
1537
+ }
1451
1538
  const args = ["worktree", "add", targetDir, "-b", branch];
1452
- if (baseBranch) {
1453
- args.push(baseBranch);
1539
+ if (startRef) {
1540
+ args.push(startRef);
1454
1541
  }
1455
1542
  try {
1456
1543
  await execFileAsync2("git", args, {
@@ -1473,7 +1560,8 @@ async function createWorktree(opts) {
1473
1560
  return {
1474
1561
  success: true,
1475
1562
  worktreePath: targetDir,
1476
- branch
1563
+ branch,
1564
+ ...baseSync ? { baseSync } : {}
1477
1565
  };
1478
1566
  }
1479
1567
  async function removeWorktree(repoRoot, worktreePath, opts = {}) {
@@ -4396,6 +4484,176 @@ var init_mesh_ledger = __esm({
4396
4484
  }
4397
4485
  });
4398
4486
 
4487
+ // src/mesh/mesh-delivery-policy.ts
4488
+ import { randomUUID as randomUUID5 } from "crypto";
4489
+ function resolveDeliveryDecision(sessionStatus, opts) {
4490
+ const status = (sessionStatus || "").trim().toLowerCase();
4491
+ if (!status) {
4492
+ return {
4493
+ decision: "rejected",
4494
+ reason: "unknown_session_status",
4495
+ message: "Session status is unknown. Delivery rejected (fail-closed). Use mesh_launch_session to start a fresh session."
4496
+ };
4497
+ }
4498
+ if (IMMEDIATE_DELIVERY_STATUSES.has(status)) {
4499
+ return {
4500
+ decision: "immediate",
4501
+ reason: `session_${status}`,
4502
+ message: `Session is ${status} \u2014 delivery allowed immediately.`
4503
+ };
4504
+ }
4505
+ if (BUSY_DELIVERY_STATUSES.has(status)) {
4506
+ if (opts?.allowBusyInjection) {
4507
+ return {
4508
+ decision: "immediate",
4509
+ reason: `session_${status}_busy_injection_allowed`,
4510
+ message: `Session is ${status} but provider supports busy injection. Delivered immediately.`
4511
+ };
4512
+ }
4513
+ if (status === "waiting_approval" && opts?.kind === "approval") {
4514
+ return {
4515
+ decision: "immediate",
4516
+ reason: "session_waiting_approval_approval_message",
4517
+ message: "Session is waiting for approval \u2014 approval message delivered immediately."
4518
+ };
4519
+ }
4520
+ return {
4521
+ decision: "queued",
4522
+ reason: `session_${status}_busy`,
4523
+ message: `Session is ${status}. Task queued for delivery when session becomes idle. Do not inject directly into a busy session.`
4524
+ };
4525
+ }
4526
+ if (TERMINAL_DELIVERY_STATUSES.has(status)) {
4527
+ return {
4528
+ decision: "rejected",
4529
+ reason: `session_${status}_terminal`,
4530
+ message: `Session is ${status} (terminal). Delivery rejected. Launch a new session before dispatching tasks.`
4531
+ };
4532
+ }
4533
+ return {
4534
+ decision: "rejected",
4535
+ reason: "unrecognized_session_status",
4536
+ message: `Session status '${sessionStatus}' is not recognized. Delivery rejected (fail-closed). Inspect session state before retrying.`
4537
+ };
4538
+ }
4539
+ function createSessionDelivery(opts) {
4540
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4541
+ const id = randomUUID5();
4542
+ const record = {
4543
+ id,
4544
+ meshId: opts.meshId,
4545
+ nodeId: opts.nodeId,
4546
+ sessionId: opts.sessionId,
4547
+ providerType: opts.providerType,
4548
+ taskId: opts.taskId,
4549
+ kind: opts.kind,
4550
+ priority: opts.priority ?? 0,
4551
+ message: opts.message,
4552
+ status: opts.status,
4553
+ deliverAfter: opts.deliverAfter,
4554
+ expiresAt: opts.expiresAt,
4555
+ attemptCount: 0,
4556
+ sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
4557
+ sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
4558
+ createdAt: now,
4559
+ updatedAt: now
4560
+ };
4561
+ MeshRuntimeStore.getInstance().insertSessionDelivery({
4562
+ id,
4563
+ meshId: opts.meshId,
4564
+ nodeId: opts.nodeId,
4565
+ sessionId: opts.sessionId,
4566
+ providerType: opts.providerType,
4567
+ taskId: opts.taskId,
4568
+ kind: opts.kind,
4569
+ priority: opts.priority ?? 0,
4570
+ message: opts.message,
4571
+ status: opts.status,
4572
+ deliverAfter: opts.deliverAfter,
4573
+ expiresAt: opts.expiresAt,
4574
+ sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
4575
+ sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
4576
+ createdAt: now,
4577
+ updatedAt: now
4578
+ });
4579
+ return record;
4580
+ }
4581
+ function updateSessionDeliveryStatus(id, status, opts) {
4582
+ try {
4583
+ MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(id, status, opts);
4584
+ } catch {
4585
+ }
4586
+ }
4587
+ function getActiveSessionDeliveries(meshId, sessionId) {
4588
+ try {
4589
+ return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
4590
+ } catch {
4591
+ return [];
4592
+ }
4593
+ }
4594
+ function recordCompletionConflict(opts) {
4595
+ try {
4596
+ MeshRuntimeStore.getInstance().recordCompletionConflict({
4597
+ id: randomUUID5(),
4598
+ meshId: opts.meshId,
4599
+ fingerprint: opts.fingerprint,
4600
+ conflictingTaskId: opts.conflictingTaskId,
4601
+ conflictingSessionId: opts.conflictingSessionId,
4602
+ originalTaskId: opts.originalTaskId,
4603
+ originalSessionId: opts.originalSessionId,
4604
+ event: opts.event,
4605
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
4606
+ });
4607
+ } catch {
4608
+ }
4609
+ }
4610
+ function getRecentCompletionConflicts(meshId, limitMs) {
4611
+ try {
4612
+ return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
4613
+ } catch {
4614
+ return [];
4615
+ }
4616
+ }
4617
+ function markSessionDeliveriesTerminal(meshId, sessionId, terminalStatus) {
4618
+ try {
4619
+ const active = MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
4620
+ for (const delivery of active) {
4621
+ MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(delivery.id, terminalStatus);
4622
+ }
4623
+ } catch {
4624
+ }
4625
+ }
4626
+ var IMMEDIATE_DELIVERY_STATUSES, BUSY_DELIVERY_STATUSES, TERMINAL_DELIVERY_STATUSES;
4627
+ var init_mesh_delivery_policy = __esm({
4628
+ "src/mesh/mesh-delivery-policy.ts"() {
4629
+ "use strict";
4630
+ init_mesh_runtime_store();
4631
+ IMMEDIATE_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
4632
+ "idle",
4633
+ "waiting_input",
4634
+ "ready"
4635
+ ]);
4636
+ BUSY_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
4637
+ "generating",
4638
+ "running",
4639
+ "streaming",
4640
+ "busy",
4641
+ "starting",
4642
+ "initializing",
4643
+ "waiting_approval"
4644
+ ]);
4645
+ TERMINAL_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
4646
+ "stopped",
4647
+ "failed",
4648
+ "terminated",
4649
+ "exited",
4650
+ "closed",
4651
+ "deleted",
4652
+ "error"
4653
+ ]);
4654
+ }
4655
+ });
4656
+
4399
4657
  // src/mesh/mesh-work-queue.ts
4400
4658
  var mesh_work_queue_exports = {};
4401
4659
  __export(mesh_work_queue_exports, {
@@ -4435,7 +4693,7 @@ __export(mesh_work_queue_exports, {
4435
4693
  updateTaskStatus: () => updateTaskStatus,
4436
4694
  validateMeshTaskModeRequest: () => validateMeshTaskModeRequest
4437
4695
  });
4438
- import { randomUUID as randomUUID5 } from "crypto";
4696
+ import { randomUUID as randomUUID6 } from "crypto";
4439
4697
  function hasNegationBefore(text, matchIndex) {
4440
4698
  const before = text.slice(0, matchIndex);
4441
4699
  const clauseStart = Math.max(
@@ -4758,7 +5016,7 @@ function enqueueTask(meshId, message, opts) {
4758
5016
  if (!modeValidation.valid) {
4759
5017
  throw new Error(`live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`);
4760
5018
  }
4761
- const id = typeof opts?.id === "string" && opts.id.trim() ? opts.id.trim() : randomUUID5();
5019
+ const id = typeof opts?.id === "string" && opts.id.trim() ? opts.id.trim() : randomUUID6();
4762
5020
  const dependsOn = normalizeDependsOn(opts?.dependsOn);
4763
5021
  return withQueueLock(meshId, () => {
4764
5022
  if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
@@ -4819,6 +5077,18 @@ function recordDirectDispatchTask(meshId, message, opts) {
4819
5077
  updatedAt: now
4820
5078
  };
4821
5079
  MeshRuntimeStore.getInstance().insertQueueEntry(entry);
5080
+ try {
5081
+ createSessionDelivery({
5082
+ meshId,
5083
+ ...opts.assignedNodeId ? { nodeId: opts.assignedNodeId } : {},
5084
+ ...opts.assignedSessionId ? { sessionId: opts.assignedSessionId } : {},
5085
+ taskId,
5086
+ kind: "task",
5087
+ message,
5088
+ status: "delivered"
5089
+ });
5090
+ } catch {
5091
+ }
4822
5092
  return entry;
4823
5093
  });
4824
5094
  }
@@ -5102,6 +5372,7 @@ var init_mesh_work_queue = __esm({
5102
5372
  init_mesh_config();
5103
5373
  init_logger();
5104
5374
  init_mesh_ledger();
5375
+ init_mesh_delivery_policy();
5105
5376
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
5106
5377
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
5107
5378
  MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
@@ -5647,11 +5918,14 @@ var init_mesh_runtime_store = __esm({
5647
5918
  }
5648
5919
  /** A node may only execute one write task at a time (worktree isolation). */
5649
5920
  hasActiveNodeAssignment(meshId, nodeId) {
5921
+ const nodeIdForms = expandDaemonIdForms(nodeId);
5922
+ if (nodeIdForms.length === 0) return false;
5923
+ const placeholders = nodeIdForms.map(() => "?").join(", ");
5650
5924
  const row = this.db.prepare(`
5651
5925
  SELECT 1 FROM mesh_queue
5652
- WHERE mesh_id = ? AND status = 'assigned' AND assigned_node_id = ?
5926
+ WHERE mesh_id = ? AND status = 'assigned' AND assigned_node_id IN (${placeholders})
5653
5927
  LIMIT 1
5654
- `).get(meshId, nodeId);
5928
+ `).get(meshId, ...nodeIdForms);
5655
5929
  return row !== void 0;
5656
5930
  }
5657
5931
  /**
@@ -6743,7 +7017,7 @@ __export(mesh_missions_exports, {
6743
7017
  summarizeMissionTasks: () => summarizeMissionTasks,
6744
7018
  upsertMeshMission: () => upsertMeshMission
6745
7019
  });
6746
- import { randomUUID as randomUUID6 } from "crypto";
7020
+ import { randomUUID as randomUUID7 } from "crypto";
6747
7021
  function normalizeMissionStatus(value) {
6748
7022
  return MESH_MISSION_STATUSES.includes(value) ? value : "active";
6749
7023
  }
@@ -6753,7 +7027,7 @@ function upsertMeshMission(meshId, input) {
6753
7027
  if (input.status !== void 0 && !MESH_MISSION_STATUSES.includes(input.status)) {
6754
7028
  throw new Error(`invalid_mission_status: '${input.status}' (valid: ${MESH_MISSION_STATUSES.join(", ")})`);
6755
7029
  }
6756
- const id = typeof input.id === "string" && input.id.trim() ? input.id.trim() : randomUUID6();
7030
+ const id = typeof input.id === "string" && input.id.trim() ? input.id.trim() : randomUUID7();
6757
7031
  const store = MeshRuntimeStore.getInstance();
6758
7032
  const existing = store.getMission(meshId, id);
6759
7033
  const record = {
@@ -9738,7 +10012,7 @@ var init_mesh_events_utils = __esm({
9738
10012
  // src/mesh/mesh-events-pending.ts
9739
10013
  import { appendFileSync as appendFileSync2, existsSync as existsSync14, readFileSync as readFileSync11, renameSync as renameSync4, statSync as statSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
9740
10014
  import { join as join15 } from "path";
9741
- import { randomUUID as randomUUID7 } from "crypto";
10015
+ import { randomUUID as randomUUID8 } from "crypto";
9742
10016
  function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
9743
10017
  return expandDaemonIdForms(coordinatorDaemonId);
9744
10018
  }
@@ -9942,7 +10216,7 @@ function queuePendingMeshCoordinatorEvent(event) {
9942
10216
  let sqliteOk = false;
9943
10217
  try {
9944
10218
  MeshRuntimeStore.getInstance().insertPendingEvent({
9945
- id: randomUUID7(),
10219
+ id: randomUUID8(),
9946
10220
  meshId: event.meshId,
9947
10221
  coordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
9948
10222
  event: event.event,
@@ -10146,176 +10420,6 @@ var init_mesh_events_pending = __esm({
10146
10420
  }
10147
10421
  });
10148
10422
 
10149
- // src/mesh/mesh-delivery-policy.ts
10150
- import { randomUUID as randomUUID8 } from "crypto";
10151
- function resolveDeliveryDecision(sessionStatus, opts) {
10152
- const status = (sessionStatus || "").trim().toLowerCase();
10153
- if (!status) {
10154
- return {
10155
- decision: "rejected",
10156
- reason: "unknown_session_status",
10157
- message: "Session status is unknown. Delivery rejected (fail-closed). Use mesh_launch_session to start a fresh session."
10158
- };
10159
- }
10160
- if (IMMEDIATE_DELIVERY_STATUSES.has(status)) {
10161
- return {
10162
- decision: "immediate",
10163
- reason: `session_${status}`,
10164
- message: `Session is ${status} \u2014 delivery allowed immediately.`
10165
- };
10166
- }
10167
- if (BUSY_DELIVERY_STATUSES.has(status)) {
10168
- if (opts?.allowBusyInjection) {
10169
- return {
10170
- decision: "immediate",
10171
- reason: `session_${status}_busy_injection_allowed`,
10172
- message: `Session is ${status} but provider supports busy injection. Delivered immediately.`
10173
- };
10174
- }
10175
- if (status === "waiting_approval" && opts?.kind === "approval") {
10176
- return {
10177
- decision: "immediate",
10178
- reason: "session_waiting_approval_approval_message",
10179
- message: "Session is waiting for approval \u2014 approval message delivered immediately."
10180
- };
10181
- }
10182
- return {
10183
- decision: "queued",
10184
- reason: `session_${status}_busy`,
10185
- message: `Session is ${status}. Task queued for delivery when session becomes idle. Do not inject directly into a busy session.`
10186
- };
10187
- }
10188
- if (TERMINAL_DELIVERY_STATUSES.has(status)) {
10189
- return {
10190
- decision: "rejected",
10191
- reason: `session_${status}_terminal`,
10192
- message: `Session is ${status} (terminal). Delivery rejected. Launch a new session before dispatching tasks.`
10193
- };
10194
- }
10195
- return {
10196
- decision: "rejected",
10197
- reason: "unrecognized_session_status",
10198
- message: `Session status '${sessionStatus}' is not recognized. Delivery rejected (fail-closed). Inspect session state before retrying.`
10199
- };
10200
- }
10201
- function createSessionDelivery(opts) {
10202
- const now = (/* @__PURE__ */ new Date()).toISOString();
10203
- const id = randomUUID8();
10204
- const record = {
10205
- id,
10206
- meshId: opts.meshId,
10207
- nodeId: opts.nodeId,
10208
- sessionId: opts.sessionId,
10209
- providerType: opts.providerType,
10210
- taskId: opts.taskId,
10211
- kind: opts.kind,
10212
- priority: opts.priority ?? 0,
10213
- message: opts.message,
10214
- status: opts.status,
10215
- deliverAfter: opts.deliverAfter,
10216
- expiresAt: opts.expiresAt,
10217
- attemptCount: 0,
10218
- sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
10219
- sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
10220
- createdAt: now,
10221
- updatedAt: now
10222
- };
10223
- MeshRuntimeStore.getInstance().insertSessionDelivery({
10224
- id,
10225
- meshId: opts.meshId,
10226
- nodeId: opts.nodeId,
10227
- sessionId: opts.sessionId,
10228
- providerType: opts.providerType,
10229
- taskId: opts.taskId,
10230
- kind: opts.kind,
10231
- priority: opts.priority ?? 0,
10232
- message: opts.message,
10233
- status: opts.status,
10234
- deliverAfter: opts.deliverAfter,
10235
- expiresAt: opts.expiresAt,
10236
- sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
10237
- sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
10238
- createdAt: now,
10239
- updatedAt: now
10240
- });
10241
- return record;
10242
- }
10243
- function updateSessionDeliveryStatus(id, status, opts) {
10244
- try {
10245
- MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(id, status, opts);
10246
- } catch {
10247
- }
10248
- }
10249
- function getActiveSessionDeliveries(meshId, sessionId) {
10250
- try {
10251
- return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
10252
- } catch {
10253
- return [];
10254
- }
10255
- }
10256
- function recordCompletionConflict(opts) {
10257
- try {
10258
- MeshRuntimeStore.getInstance().recordCompletionConflict({
10259
- id: randomUUID8(),
10260
- meshId: opts.meshId,
10261
- fingerprint: opts.fingerprint,
10262
- conflictingTaskId: opts.conflictingTaskId,
10263
- conflictingSessionId: opts.conflictingSessionId,
10264
- originalTaskId: opts.originalTaskId,
10265
- originalSessionId: opts.originalSessionId,
10266
- event: opts.event,
10267
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
10268
- });
10269
- } catch {
10270
- }
10271
- }
10272
- function getRecentCompletionConflicts(meshId, limitMs) {
10273
- try {
10274
- return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
10275
- } catch {
10276
- return [];
10277
- }
10278
- }
10279
- function markSessionDeliveriesTerminal(meshId, sessionId, terminalStatus) {
10280
- try {
10281
- const active = MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
10282
- for (const delivery of active) {
10283
- MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(delivery.id, terminalStatus);
10284
- }
10285
- } catch {
10286
- }
10287
- }
10288
- var IMMEDIATE_DELIVERY_STATUSES, BUSY_DELIVERY_STATUSES, TERMINAL_DELIVERY_STATUSES;
10289
- var init_mesh_delivery_policy = __esm({
10290
- "src/mesh/mesh-delivery-policy.ts"() {
10291
- "use strict";
10292
- init_mesh_runtime_store();
10293
- IMMEDIATE_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
10294
- "idle",
10295
- "waiting_input",
10296
- "ready"
10297
- ]);
10298
- BUSY_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
10299
- "generating",
10300
- "running",
10301
- "streaming",
10302
- "busy",
10303
- "starting",
10304
- "initializing",
10305
- "waiting_approval"
10306
- ]);
10307
- TERMINAL_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
10308
- "stopped",
10309
- "failed",
10310
- "terminated",
10311
- "exited",
10312
- "closed",
10313
- "deleted",
10314
- "error"
10315
- ]);
10316
- }
10317
- });
10318
-
10319
10423
  // src/mesh/mesh-events-stale.ts
10320
10424
  function findRecentTerminalLedgerEvidence(args) {
10321
10425
  if (!args.sessionId && !args.nodeId) return null;
@@ -11870,7 +11974,14 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
11870
11974
  targetSessionId: sessionId,
11871
11975
  cliType: providerType,
11872
11976
  action: "send_chat",
11873
- message: task.message
11977
+ message: task.message,
11978
+ meshContext: {
11979
+ meshId,
11980
+ nodeId,
11981
+ taskId: task.id,
11982
+ ...readNonEmptyString2(loadConfig().machineId) ? { coordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {},
11983
+ ...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { coordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {}
11984
+ }
11874
11985
  }),
11875
11986
  {
11876
11987
  meshId,
@@ -19538,6 +19649,15 @@ var init_cli_state_engine = __esm({
19538
19649
  currentStatus = "starting";
19539
19650
  isWaitingForResponse = false;
19540
19651
  currentTurnScope = null;
19652
+ // ARCH-REFACTOR R1 (per-turn task identity): the mesh taskId bound to the most
19653
+ // recently STARTED turn. Unlike currentTurnScope (nulled the moment the turn
19654
+ // settles, before the completion event is even built), this persists past
19655
+ // completion and is only overwritten when the NEXT turn starts. That window is
19656
+ // exactly what the completion path needs: when a turn settles to idle, this still
19657
+ // holds THAT turn's taskId (the next task's turn cannot have started yet — it is
19658
+ // queued in pendingOutbound and only flushed asynchronously after idle), so the
19659
+ // completion event carries the correct id instead of the racy session scalar.
19660
+ currentTurnTaskId = null;
19541
19661
  activeModal = null;
19542
19662
  // ── Approval ─────────────────────────────────────
19543
19663
  lastApprovalResolvedAt = 0;
@@ -19647,6 +19767,7 @@ var init_cli_state_engine = __esm({
19647
19767
  this.finishRetryCount = 0;
19648
19768
  this.clearIdleFinishCandidate("send_message");
19649
19769
  this.currentTurnScope = turnScope;
19770
+ this.currentTurnTaskId = typeof turnScope.taskId === "string" && turnScope.taskId.trim() ? turnScope.taskId : null;
19650
19771
  this.responseEpoch += 1;
19651
19772
  }
19652
19773
  /** Called when PTY exits */
@@ -21598,15 +21719,18 @@ ${lastSnapshot}`;
21598
21719
  }
21599
21720
  async sendMessage(text, options = {}) {
21600
21721
  if (options.force === true) {
21601
- await this.forceSendMessage(text);
21722
+ await this.forceSendMessage(text, options.meshTaskId);
21602
21723
  return;
21603
21724
  }
21604
- await this.sendMessageNow(text, true);
21725
+ await this.sendMessageNow(text, true, options.meshTaskId);
21605
21726
  }
21606
- async forceSendMessage(text) {
21727
+ async forceSendMessage(text, meshTaskId) {
21607
21728
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
21608
21729
  const content = String(text || "");
21609
21730
  if (!content.trim()) return;
21731
+ if (typeof meshTaskId === "string" && meshTaskId.trim()) {
21732
+ this.engine.currentTurnTaskId = meshTaskId;
21733
+ }
21610
21734
  if (this.engine.currentStatus === "waiting_approval" || this.engine.hasActionableApproval()) {
21611
21735
  LOG.info("CLI", `[${this.cliType}] force-send held \u2014 session parked on approval modal (status=${this.engine.currentStatus})`);
21612
21736
  return;
@@ -21619,7 +21743,7 @@ ${lastSnapshot}`;
21619
21743
  async waitForForceSubmitSettle() {
21620
21744
  await new Promise((resolve24) => setTimeout(resolve24, FORCE_SUBMIT_SETTLE_MS));
21621
21745
  }
21622
- enqueuePendingOutboundMessage(text, reason) {
21746
+ enqueuePendingOutboundMessage(text, reason, meshTaskId) {
21623
21747
  const content = String(text || "");
21624
21748
  const duplicate = this.pendingOutboundQueue.some((message2) => message2.content === content);
21625
21749
  if (duplicate) {
@@ -21631,7 +21755,8 @@ ${lastSnapshot}`;
21631
21755
  role: "user",
21632
21756
  content,
21633
21757
  queuedAt,
21634
- source: "sendMessage"
21758
+ source: "sendMessage",
21759
+ ...typeof meshTaskId === "string" && meshTaskId.trim() ? { meshTaskId } : {}
21635
21760
  };
21636
21761
  this.pendingOutboundQueue.push(message);
21637
21762
  LOG.info("CLI", `[${this.cliType}] queued outbound message while busy (${reason}); queue=${this.pendingOutboundQueue.length}`);
@@ -21674,7 +21799,7 @@ ${lastSnapshot}`;
21674
21799
  if (this.engine.currentStatus !== "idle" || this.engine.isWaitingForResponse || this.engine.hasActionableApproval()) break;
21675
21800
  const next = this.pendingOutboundQueue[0];
21676
21801
  try {
21677
- await this.sendMessageNow(next.content, false);
21802
+ await this.sendMessageNow(next.content, false, next.meshTaskId);
21678
21803
  this.pendingOutboundQueue.shift();
21679
21804
  this.onStatusChange?.();
21680
21805
  } catch (error) {
@@ -21687,7 +21812,7 @@ ${lastSnapshot}`;
21687
21812
  this.pendingOutboundFlushInFlight = false;
21688
21813
  }
21689
21814
  }
21690
- async sendMessageNow(text, allowQueue) {
21815
+ async sendMessageNow(text, allowQueue, meshTaskId) {
21691
21816
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
21692
21817
  const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
21693
21818
  const allowInterventionPrompt = allowInputDuringGeneration && this.engine.isWaitingForResponse && !this.engine.hasActionableApproval();
@@ -21707,7 +21832,7 @@ ${lastSnapshot}`;
21707
21832
  })() : null;
21708
21833
  const queueReason = this.shouldQueuePendingOutboundMessage(parsedStatusBeforeSend);
21709
21834
  if (allowQueue && queueReason) {
21710
- this.enqueuePendingOutboundMessage(text, queueReason);
21835
+ this.enqueuePendingOutboundMessage(text, queueReason, meshTaskId);
21711
21836
  return;
21712
21837
  }
21713
21838
  if (!allowInterventionPrompt) {
@@ -21724,7 +21849,7 @@ ${lastSnapshot}`;
21724
21849
  }
21725
21850
  if (!this.ready) {
21726
21851
  if (allowQueue) {
21727
- this.enqueuePendingOutboundMessage(text, "not_ready_pending_prompt");
21852
+ this.enqueuePendingOutboundMessage(text, "not_ready_pending_prompt", meshTaskId);
21728
21853
  return;
21729
21854
  }
21730
21855
  throw new Error(`${this.cliName} not ready (status: ${this.engine.currentStatus})`);
@@ -21738,7 +21863,7 @@ ${lastSnapshot}`;
21738
21863
  const terminalLooksIdle = this.engine.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.engine.isWaitingForResponse && !this.engine.currentTurnScope && !this.engine.hasActionableApproval() && !parsedHasActionableModal;
21739
21864
  if (!terminalLooksIdle) {
21740
21865
  if (allowQueue) {
21741
- this.enqueuePendingOutboundMessage(text, `parsed_status_${parsedSessionStatus}`);
21866
+ this.enqueuePendingOutboundMessage(text, `parsed_status_${parsedSessionStatus}`, meshTaskId);
21742
21867
  return;
21743
21868
  }
21744
21869
  throw new Error(`${this.cliName} is still processing the previous prompt`);
@@ -21748,7 +21873,7 @@ ${lastSnapshot}`;
21748
21873
  const snap = this.getSnapshot();
21749
21874
  if (!this.engine.clearStaleIdleResponseGuard("send_message_guard", snap) && !this.engine.clearParsedIdleResponseGuard("send_message_parsed_idle_guard", parsedStatusBeforeSend, snap)) {
21750
21875
  if (allowQueue) {
21751
- this.enqueuePendingOutboundMessage(text, "waiting_for_response");
21876
+ this.enqueuePendingOutboundMessage(text, "waiting_for_response", meshTaskId);
21752
21877
  return;
21753
21878
  }
21754
21879
  throw new Error(`${this.cliName} is still processing the previous prompt`);
@@ -21759,7 +21884,11 @@ ${lastSnapshot}`;
21759
21884
  prompt: text,
21760
21885
  startedAt: Date.now(),
21761
21886
  bufferStart: this.accumulatedBuffer.length,
21762
- rawBufferStart: this.accumulatedRawBuffer.length
21887
+ rawBufferStart: this.accumulatedRawBuffer.length,
21888
+ // ARCH-REFACTOR R1: bind this turn to its mesh task. engine.onTurnStarted
21889
+ // copies this into currentTurnTaskId so the turn's completion event carries
21890
+ // the right id even if a later task overwrites the session scalar meanwhile.
21891
+ ...typeof meshTaskId === "string" && meshTaskId.trim() ? { taskId: meshTaskId } : {}
21763
21892
  };
21764
21893
  LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${turnScope.bufferStart} raw=${turnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
21765
21894
  if (this.submitRetryTimer) {
@@ -22109,6 +22238,13 @@ ${lastSnapshot}`;
22109
22238
  set currentTurnScope(v) {
22110
22239
  this.engine.currentTurnScope = v;
22111
22240
  }
22241
+ // ARCH-REFACTOR R1: the mesh taskId bound to the most recently started turn,
22242
+ // surviving past turn settle until the next turn starts. The provider instance
22243
+ // reads this when stamping completion events so they carry the completing turn's
22244
+ // task rather than the racy last-write-wins session scalar.
22245
+ get currentTurnTaskId() {
22246
+ return this.engine.currentTurnTaskId;
22247
+ }
22112
22248
  get responseEpoch() {
22113
22249
  return this.engine.responseEpoch;
22114
22250
  }
@@ -40324,11 +40460,28 @@ var CliProviderInstance = class _CliProviderInstance {
40324
40460
  isMeshWorkerSession() {
40325
40461
  return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
40326
40462
  }
40463
+ /**
40464
+ * ARCH-REFACTOR R1: the taskId to attribute the CURRENTLY-completing turn to.
40465
+ * Prefers the per-turn binding (engine.currentTurnTaskId, set when the turn was
40466
+ * submitted and surviving until the next turn starts) over the last-write-wins
40467
+ * session scalar (settings.meshActiveTaskId). The scalar is retained only as a
40468
+ * backward-compat alias for the "current/last assignment" and is the source of the
40469
+ * NOTIF-MISDELIVER / TASK-MSG-MISROUTE race: a second task attaching before this
40470
+ * turn completes overwrites it. Returns undefined for a non-task ad-hoc turn.
40471
+ */
40472
+ completingTurnTaskId() {
40473
+ const turnTaskId = this.adapter?.currentTurnTaskId;
40474
+ if (typeof turnTaskId === "string" && turnTaskId.trim()) return turnTaskId;
40475
+ const scalar = this.settings.meshActiveTaskId;
40476
+ return typeof scalar === "string" && scalar.trim() ? scalar : void 0;
40477
+ }
40327
40478
  // EVTTRACE correlation context for this session's completion lifecycle. taskId is
40328
40479
  // the primary grep anchor; instanceId is the session fallback.
40329
40480
  meshTraceCtx(event = "agent:generating_completed") {
40330
40481
  return {
40331
- taskId: this.settings.meshActiveTaskId,
40482
+ // ARCH-REFACTOR R1: trace the per-turn taskId (falling back to the scalar) so
40483
+ // EvtTrace anchors on the same id the completion event actually carries.
40484
+ taskId: this.completingTurnTaskId(),
40332
40485
  sessionId: this.instanceId,
40333
40486
  nodeId: this.settings.meshNodeId,
40334
40487
  meshId: this.settings.meshNodeFor,
@@ -40387,6 +40540,8 @@ var CliProviderInstance = class _CliProviderInstance {
40387
40540
  chatTitle: pending.chatTitle,
40388
40541
  duration: pending.duration,
40389
40542
  timestamp: pending.timestamp,
40543
+ // ARCH-REFACTOR R1: attribute to the turn captured at idle-transition.
40544
+ ...pending.taskId ? { taskId: pending.taskId } : {},
40390
40545
  // When finalization is forced past the timeout on a `parsed_status:` block
40391
40546
  // (the parser never confirmed a final assistant turn) we previously rode an
40392
40547
  // empty `finalSummary` unconditionally. That empty value propagates to the
@@ -40412,6 +40567,8 @@ var CliProviderInstance = class _CliProviderInstance {
40412
40567
  chatTitle: pending.chatTitle,
40413
40568
  duration: pending.duration,
40414
40569
  timestamp: pending.timestamp,
40570
+ // ARCH-REFACTOR R1: attribute to the turn captured at idle-transition.
40571
+ ...pending.taskId ? { taskId: pending.taskId } : {},
40415
40572
  finalSummary: this.completionFinalSummary(this.adapter?.getScriptParsedStatus()?.messages)
40416
40573
  });
40417
40574
  this.completedDebouncePending = null;
@@ -40688,7 +40845,11 @@ var CliProviderInstance = class _CliProviderInstance {
40688
40845
  duration,
40689
40846
  timestamp: now,
40690
40847
  firstObservedAt: now,
40691
- previousStatus: this.lastStatus
40848
+ previousStatus: this.lastStatus,
40849
+ // ARCH-REFACTOR R1: snapshot the completing turn's taskId NOW (sync),
40850
+ // before any follow-up task's flush can start a new turn and move
40851
+ // engine.currentTurnTaskId.
40852
+ ...this.completingTurnTaskId() ? { taskId: this.completingTurnTaskId() } : {}
40692
40853
  };
40693
40854
  const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
40694
40855
  const meshWorkerSession = this.isMeshWorkerSession();
@@ -40791,10 +40952,11 @@ var CliProviderInstance = class _CliProviderInstance {
40791
40952
  workspace: typeof event.workspace === "string" && event.workspace.trim() ? event.workspace : this.workingDir,
40792
40953
  providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
40793
40954
  };
40794
- if (this.isMeshWorkerSession() && this.settings.meshActiveTaskId) {
40955
+ if (this.isMeshWorkerSession()) {
40795
40956
  const existingTaskId = typeof enrichedEvent.taskId === "string" && enrichedEvent.taskId.trim() ? enrichedEvent.taskId : void 0;
40796
40957
  if (!existingTaskId) {
40797
- enrichedEvent.taskId = this.settings.meshActiveTaskId;
40958
+ const resolved = this.completingTurnTaskId();
40959
+ if (resolved) enrichedEvent.taskId = resolved;
40798
40960
  }
40799
40961
  }
40800
40962
  if (this.context?.emitProviderEvent) {
@@ -43679,11 +43841,15 @@ Run 'adhdev doctor' for detailed diagnostics.`
43679
43841
  }
43680
43842
  const message = input.textFallback;
43681
43843
  if (!message) throw new Error("message required for send_chat");
43844
+ const meshTaskId = meshContext && typeof meshContext === "object" && typeof meshContext.taskId === "string" && meshContext.taskId.trim() ? meshContext.taskId : void 0;
43682
43845
  const forceSend = args?.force === true || args?.forceSend === true;
43683
43846
  if (forceSend && typeof adapter.forceSendMessage === "function") {
43684
- await adapter.forceSendMessage(message);
43847
+ if (meshTaskId) await adapter.forceSendMessage(message, meshTaskId);
43848
+ else await adapter.forceSendMessage(message);
43685
43849
  } else if (forceSend) {
43686
- await adapter.sendMessage(message, { force: true });
43850
+ await adapter.sendMessage(message, meshTaskId ? { force: true, meshTaskId } : { force: true });
43851
+ } else if (meshTaskId) {
43852
+ await adapter.sendMessage(message, { meshTaskId });
43687
43853
  } else {
43688
43854
  await adapter.sendMessage(message);
43689
43855
  }
@@ -48211,6 +48377,11 @@ var meshCrudHandlers = {
48211
48377
  baseBranch,
48212
48378
  meshName: mesh.name
48213
48379
  });
48380
+ if (result.baseSync?.warning) {
48381
+ console.warn(`[mesh] clone_mesh_node base sync (${result.baseSync.action}): ${result.baseSync.warning}`);
48382
+ } else if (result.baseSync && result.baseSync.action !== "up_to_date") {
48383
+ console.log(`[mesh] clone_mesh_node base sync: ${result.baseSync.action} (startRef=${result.baseSync.startRef})`);
48384
+ }
48214
48385
  let node;
48215
48386
  if (meshRecord.inline) {
48216
48387
  const { randomUUID: randomUUID15 } = await import("crypto");
@@ -48401,6 +48572,8 @@ var meshCrudHandlers = {
48401
48572
  node,
48402
48573
  worktreePath: result.worktreePath,
48403
48574
  branch: result.branch,
48575
+ ...result.baseSync ? { baseSync: result.baseSync } : {},
48576
+ ...result.baseSync?.warning ? { baseStaleWarning: result.baseSync.warning } : {},
48404
48577
  worktreeBootstrap: runningBootstrapState,
48405
48578
  worktreeSetup: {
48406
48579
  status: "running",
@@ -48416,6 +48589,8 @@ var meshCrudHandlers = {
48416
48589
  node,
48417
48590
  worktreePath: result.worktreePath,
48418
48591
  branch: result.branch,
48592
+ ...result.baseSync ? { baseSync: result.baseSync } : {},
48593
+ ...result.baseSync?.warning ? { baseStaleWarning: result.baseSync.warning } : {},
48419
48594
  submodulesInitialized,
48420
48595
  worktreeBootstrap: bootstrapState
48421
48596
  };