@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/cli-adapter-types.d.ts +2 -1
- package/dist/cli-adapters/cli-state-engine.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +3 -1
- package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/dist/git/git-worktree.d.ts +49 -1
- package/dist/git/index.d.ts +1 -1
- package/dist/index.js +382 -207
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +379 -204
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +10 -0
- package/package.json +2 -2
- package/src/cli-adapter-types.d.ts +2 -1
- package/src/cli-adapter-types.ts +2 -2
- package/src/cli-adapters/cli-state-engine.ts +15 -0
- package/src/cli-adapters/provider-cli-adapter.ts +32 -11
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +6 -0
- package/src/commands/cli-manager.ts +16 -2
- package/src/commands/med-family/mesh-crud.ts +9 -0
- package/src/git/git-worktree.ts +185 -3
- package/src/git/index.ts +1 -0
- package/src/mesh/mesh-event-forwarding.ts +13 -2
- package/src/mesh/mesh-queue-assignment.ts +12 -0
- package/src/mesh/mesh-reconcile-loop.ts +4 -0
- package/src/mesh/mesh-runtime-store.ts +20 -2
- package/src/mesh/mesh-work-queue.ts +23 -0
- package/src/providers/cli-provider-instance.ts +52 -8
package/dist/index.js
CHANGED
|
@@ -399,10 +399,10 @@ function readInjected(value) {
|
|
|
399
399
|
}
|
|
400
400
|
function getDaemonBuildInfo() {
|
|
401
401
|
if (cached) return cached;
|
|
402
|
-
const commit = readInjected(true ? "
|
|
403
|
-
const commitShort = readInjected(true ? "
|
|
404
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
405
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
402
|
+
const commit = readInjected(true ? "93b00efeec1fccd6550c1faf5fa838106caef4bb" : void 0) ?? "unknown";
|
|
403
|
+
const commitShort = readInjected(true ? "93b00efe" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
404
|
+
const version = readInjected(true ? "0.9.82-rc.402" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
405
|
+
const builtAt = readInjected(true ? "2026-06-27T16:41:05.513Z" : void 0);
|
|
406
406
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
407
407
|
return cached;
|
|
408
408
|
}
|
|
@@ -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 ((0, import_node_fs2.existsSync)(targetDir)) {
|
|
1448
1529
|
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
1449
1530
|
}
|
|
1450
1531
|
await (0, import_promises3.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 (
|
|
1453
|
-
args.push(
|
|
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 = {}) {
|
|
@@ -4403,6 +4491,176 @@ var init_mesh_ledger = __esm({
|
|
|
4403
4491
|
}
|
|
4404
4492
|
});
|
|
4405
4493
|
|
|
4494
|
+
// src/mesh/mesh-delivery-policy.ts
|
|
4495
|
+
function resolveDeliveryDecision(sessionStatus, opts) {
|
|
4496
|
+
const status = (sessionStatus || "").trim().toLowerCase();
|
|
4497
|
+
if (!status) {
|
|
4498
|
+
return {
|
|
4499
|
+
decision: "rejected",
|
|
4500
|
+
reason: "unknown_session_status",
|
|
4501
|
+
message: "Session status is unknown. Delivery rejected (fail-closed). Use mesh_launch_session to start a fresh session."
|
|
4502
|
+
};
|
|
4503
|
+
}
|
|
4504
|
+
if (IMMEDIATE_DELIVERY_STATUSES.has(status)) {
|
|
4505
|
+
return {
|
|
4506
|
+
decision: "immediate",
|
|
4507
|
+
reason: `session_${status}`,
|
|
4508
|
+
message: `Session is ${status} \u2014 delivery allowed immediately.`
|
|
4509
|
+
};
|
|
4510
|
+
}
|
|
4511
|
+
if (BUSY_DELIVERY_STATUSES.has(status)) {
|
|
4512
|
+
if (opts?.allowBusyInjection) {
|
|
4513
|
+
return {
|
|
4514
|
+
decision: "immediate",
|
|
4515
|
+
reason: `session_${status}_busy_injection_allowed`,
|
|
4516
|
+
message: `Session is ${status} but provider supports busy injection. Delivered immediately.`
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
if (status === "waiting_approval" && opts?.kind === "approval") {
|
|
4520
|
+
return {
|
|
4521
|
+
decision: "immediate",
|
|
4522
|
+
reason: "session_waiting_approval_approval_message",
|
|
4523
|
+
message: "Session is waiting for approval \u2014 approval message delivered immediately."
|
|
4524
|
+
};
|
|
4525
|
+
}
|
|
4526
|
+
return {
|
|
4527
|
+
decision: "queued",
|
|
4528
|
+
reason: `session_${status}_busy`,
|
|
4529
|
+
message: `Session is ${status}. Task queued for delivery when session becomes idle. Do not inject directly into a busy session.`
|
|
4530
|
+
};
|
|
4531
|
+
}
|
|
4532
|
+
if (TERMINAL_DELIVERY_STATUSES.has(status)) {
|
|
4533
|
+
return {
|
|
4534
|
+
decision: "rejected",
|
|
4535
|
+
reason: `session_${status}_terminal`,
|
|
4536
|
+
message: `Session is ${status} (terminal). Delivery rejected. Launch a new session before dispatching tasks.`
|
|
4537
|
+
};
|
|
4538
|
+
}
|
|
4539
|
+
return {
|
|
4540
|
+
decision: "rejected",
|
|
4541
|
+
reason: "unrecognized_session_status",
|
|
4542
|
+
message: `Session status '${sessionStatus}' is not recognized. Delivery rejected (fail-closed). Inspect session state before retrying.`
|
|
4543
|
+
};
|
|
4544
|
+
}
|
|
4545
|
+
function createSessionDelivery(opts) {
|
|
4546
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4547
|
+
const id = (0, import_crypto5.randomUUID)();
|
|
4548
|
+
const record = {
|
|
4549
|
+
id,
|
|
4550
|
+
meshId: opts.meshId,
|
|
4551
|
+
nodeId: opts.nodeId,
|
|
4552
|
+
sessionId: opts.sessionId,
|
|
4553
|
+
providerType: opts.providerType,
|
|
4554
|
+
taskId: opts.taskId,
|
|
4555
|
+
kind: opts.kind,
|
|
4556
|
+
priority: opts.priority ?? 0,
|
|
4557
|
+
message: opts.message,
|
|
4558
|
+
status: opts.status,
|
|
4559
|
+
deliverAfter: opts.deliverAfter,
|
|
4560
|
+
expiresAt: opts.expiresAt,
|
|
4561
|
+
attemptCount: 0,
|
|
4562
|
+
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
4563
|
+
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
4564
|
+
createdAt: now,
|
|
4565
|
+
updatedAt: now
|
|
4566
|
+
};
|
|
4567
|
+
MeshRuntimeStore.getInstance().insertSessionDelivery({
|
|
4568
|
+
id,
|
|
4569
|
+
meshId: opts.meshId,
|
|
4570
|
+
nodeId: opts.nodeId,
|
|
4571
|
+
sessionId: opts.sessionId,
|
|
4572
|
+
providerType: opts.providerType,
|
|
4573
|
+
taskId: opts.taskId,
|
|
4574
|
+
kind: opts.kind,
|
|
4575
|
+
priority: opts.priority ?? 0,
|
|
4576
|
+
message: opts.message,
|
|
4577
|
+
status: opts.status,
|
|
4578
|
+
deliverAfter: opts.deliverAfter,
|
|
4579
|
+
expiresAt: opts.expiresAt,
|
|
4580
|
+
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
4581
|
+
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
4582
|
+
createdAt: now,
|
|
4583
|
+
updatedAt: now
|
|
4584
|
+
});
|
|
4585
|
+
return record;
|
|
4586
|
+
}
|
|
4587
|
+
function updateSessionDeliveryStatus(id, status, opts) {
|
|
4588
|
+
try {
|
|
4589
|
+
MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(id, status, opts);
|
|
4590
|
+
} catch {
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
function getActiveSessionDeliveries(meshId, sessionId) {
|
|
4594
|
+
try {
|
|
4595
|
+
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
4596
|
+
} catch {
|
|
4597
|
+
return [];
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4600
|
+
function recordCompletionConflict(opts) {
|
|
4601
|
+
try {
|
|
4602
|
+
MeshRuntimeStore.getInstance().recordCompletionConflict({
|
|
4603
|
+
id: (0, import_crypto5.randomUUID)(),
|
|
4604
|
+
meshId: opts.meshId,
|
|
4605
|
+
fingerprint: opts.fingerprint,
|
|
4606
|
+
conflictingTaskId: opts.conflictingTaskId,
|
|
4607
|
+
conflictingSessionId: opts.conflictingSessionId,
|
|
4608
|
+
originalTaskId: opts.originalTaskId,
|
|
4609
|
+
originalSessionId: opts.originalSessionId,
|
|
4610
|
+
event: opts.event,
|
|
4611
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4612
|
+
});
|
|
4613
|
+
} catch {
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
function getRecentCompletionConflicts(meshId, limitMs) {
|
|
4617
|
+
try {
|
|
4618
|
+
return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
|
|
4619
|
+
} catch {
|
|
4620
|
+
return [];
|
|
4621
|
+
}
|
|
4622
|
+
}
|
|
4623
|
+
function markSessionDeliveriesTerminal(meshId, sessionId, terminalStatus) {
|
|
4624
|
+
try {
|
|
4625
|
+
const active = MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
4626
|
+
for (const delivery of active) {
|
|
4627
|
+
MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(delivery.id, terminalStatus);
|
|
4628
|
+
}
|
|
4629
|
+
} catch {
|
|
4630
|
+
}
|
|
4631
|
+
}
|
|
4632
|
+
var import_crypto5, IMMEDIATE_DELIVERY_STATUSES, BUSY_DELIVERY_STATUSES, TERMINAL_DELIVERY_STATUSES;
|
|
4633
|
+
var init_mesh_delivery_policy = __esm({
|
|
4634
|
+
"src/mesh/mesh-delivery-policy.ts"() {
|
|
4635
|
+
"use strict";
|
|
4636
|
+
import_crypto5 = require("crypto");
|
|
4637
|
+
init_mesh_runtime_store();
|
|
4638
|
+
IMMEDIATE_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4639
|
+
"idle",
|
|
4640
|
+
"waiting_input",
|
|
4641
|
+
"ready"
|
|
4642
|
+
]);
|
|
4643
|
+
BUSY_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4644
|
+
"generating",
|
|
4645
|
+
"running",
|
|
4646
|
+
"streaming",
|
|
4647
|
+
"busy",
|
|
4648
|
+
"starting",
|
|
4649
|
+
"initializing",
|
|
4650
|
+
"waiting_approval"
|
|
4651
|
+
]);
|
|
4652
|
+
TERMINAL_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4653
|
+
"stopped",
|
|
4654
|
+
"failed",
|
|
4655
|
+
"terminated",
|
|
4656
|
+
"exited",
|
|
4657
|
+
"closed",
|
|
4658
|
+
"deleted",
|
|
4659
|
+
"error"
|
|
4660
|
+
]);
|
|
4661
|
+
}
|
|
4662
|
+
});
|
|
4663
|
+
|
|
4406
4664
|
// src/mesh/mesh-work-queue.ts
|
|
4407
4665
|
var mesh_work_queue_exports = {};
|
|
4408
4666
|
__export(mesh_work_queue_exports, {
|
|
@@ -4764,7 +5022,7 @@ function enqueueTask(meshId, message, opts) {
|
|
|
4764
5022
|
if (!modeValidation.valid) {
|
|
4765
5023
|
throw new Error(`live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`);
|
|
4766
5024
|
}
|
|
4767
|
-
const id = typeof opts?.id === "string" && opts.id.trim() ? opts.id.trim() : (0,
|
|
5025
|
+
const id = typeof opts?.id === "string" && opts.id.trim() ? opts.id.trim() : (0, import_crypto6.randomUUID)();
|
|
4768
5026
|
const dependsOn = normalizeDependsOn(opts?.dependsOn);
|
|
4769
5027
|
return withQueueLock(meshId, () => {
|
|
4770
5028
|
if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
|
|
@@ -4825,6 +5083,18 @@ function recordDirectDispatchTask(meshId, message, opts) {
|
|
|
4825
5083
|
updatedAt: now
|
|
4826
5084
|
};
|
|
4827
5085
|
MeshRuntimeStore.getInstance().insertQueueEntry(entry);
|
|
5086
|
+
try {
|
|
5087
|
+
createSessionDelivery({
|
|
5088
|
+
meshId,
|
|
5089
|
+
...opts.assignedNodeId ? { nodeId: opts.assignedNodeId } : {},
|
|
5090
|
+
...opts.assignedSessionId ? { sessionId: opts.assignedSessionId } : {},
|
|
5091
|
+
taskId,
|
|
5092
|
+
kind: "task",
|
|
5093
|
+
message,
|
|
5094
|
+
status: "delivered"
|
|
5095
|
+
});
|
|
5096
|
+
} catch {
|
|
5097
|
+
}
|
|
4828
5098
|
return entry;
|
|
4829
5099
|
});
|
|
4830
5100
|
}
|
|
@@ -5098,17 +5368,18 @@ function recordMeshToolCall(opts) {
|
|
|
5098
5368
|
return { rateLimitExceeded: false, callsInWindow: 0, advisory: null };
|
|
5099
5369
|
}
|
|
5100
5370
|
}
|
|
5101
|
-
var
|
|
5371
|
+
var import_crypto6, ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS, MAX_STRANDED_RECLAIMS;
|
|
5102
5372
|
var init_mesh_work_queue = __esm({
|
|
5103
5373
|
"src/mesh/mesh-work-queue.ts"() {
|
|
5104
5374
|
"use strict";
|
|
5105
|
-
|
|
5375
|
+
import_crypto6 = require("crypto");
|
|
5106
5376
|
init_mesh_host_ownership();
|
|
5107
5377
|
init_repo_mesh_types();
|
|
5108
5378
|
init_mesh_runtime_store();
|
|
5109
5379
|
init_mesh_config();
|
|
5110
5380
|
init_logger();
|
|
5111
5381
|
init_mesh_ledger();
|
|
5382
|
+
init_mesh_delivery_policy();
|
|
5112
5383
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
5113
5384
|
HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
|
|
5114
5385
|
MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
|
|
@@ -5654,11 +5925,14 @@ var init_mesh_runtime_store = __esm({
|
|
|
5654
5925
|
}
|
|
5655
5926
|
/** A node may only execute one write task at a time (worktree isolation). */
|
|
5656
5927
|
hasActiveNodeAssignment(meshId, nodeId) {
|
|
5928
|
+
const nodeIdForms = expandDaemonIdForms(nodeId);
|
|
5929
|
+
if (nodeIdForms.length === 0) return false;
|
|
5930
|
+
const placeholders = nodeIdForms.map(() => "?").join(", ");
|
|
5657
5931
|
const row = this.db.prepare(`
|
|
5658
5932
|
SELECT 1 FROM mesh_queue
|
|
5659
|
-
WHERE mesh_id = ? AND status = 'assigned' AND assigned_node_id
|
|
5933
|
+
WHERE mesh_id = ? AND status = 'assigned' AND assigned_node_id IN (${placeholders})
|
|
5660
5934
|
LIMIT 1
|
|
5661
|
-
`).get(meshId,
|
|
5935
|
+
`).get(meshId, ...nodeIdForms);
|
|
5662
5936
|
return row !== void 0;
|
|
5663
5937
|
}
|
|
5664
5938
|
/**
|
|
@@ -6759,7 +7033,7 @@ function upsertMeshMission(meshId, input) {
|
|
|
6759
7033
|
if (input.status !== void 0 && !MESH_MISSION_STATUSES.includes(input.status)) {
|
|
6760
7034
|
throw new Error(`invalid_mission_status: '${input.status}' (valid: ${MESH_MISSION_STATUSES.join(", ")})`);
|
|
6761
7035
|
}
|
|
6762
|
-
const id = typeof input.id === "string" && input.id.trim() ? input.id.trim() : (0,
|
|
7036
|
+
const id = typeof input.id === "string" && input.id.trim() ? input.id.trim() : (0, import_crypto7.randomUUID)();
|
|
6763
7037
|
const store = MeshRuntimeStore.getInstance();
|
|
6764
7038
|
const existing = store.getMission(meshId, id);
|
|
6765
7039
|
const record = {
|
|
@@ -6875,11 +7149,11 @@ function buildMissionPromptSection(meshId) {
|
|
|
6875
7149
|
);
|
|
6876
7150
|
return lines.join("\n");
|
|
6877
7151
|
}
|
|
6878
|
-
var
|
|
7152
|
+
var import_crypto7, MESH_MISSION_STATUSES, GOAL_PREVIEW_MAX, COMPACT_STATUS_GOAL_PREVIEW_MAX;
|
|
6879
7153
|
var init_mesh_missions = __esm({
|
|
6880
7154
|
"src/mesh/mesh-missions.ts"() {
|
|
6881
7155
|
"use strict";
|
|
6882
|
-
|
|
7156
|
+
import_crypto7 = require("crypto");
|
|
6883
7157
|
init_mesh_runtime_store();
|
|
6884
7158
|
init_mesh_work_queue();
|
|
6885
7159
|
init_mesh_task_stats();
|
|
@@ -9946,7 +10220,7 @@ function queuePendingMeshCoordinatorEvent(event) {
|
|
|
9946
10220
|
let sqliteOk = false;
|
|
9947
10221
|
try {
|
|
9948
10222
|
MeshRuntimeStore.getInstance().insertPendingEvent({
|
|
9949
|
-
id: (0,
|
|
10223
|
+
id: (0, import_crypto8.randomUUID)(),
|
|
9950
10224
|
meshId: event.meshId,
|
|
9951
10225
|
coordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
9952
10226
|
event: event.event,
|
|
@@ -10134,13 +10408,13 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
10134
10408
|
}
|
|
10135
10409
|
}
|
|
10136
10410
|
}
|
|
10137
|
-
var import_fs10, import_path9,
|
|
10411
|
+
var import_fs10, import_path9, import_crypto8, REFINE_TERMINAL_EVENTS, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
10138
10412
|
var init_mesh_events_pending = __esm({
|
|
10139
10413
|
"src/mesh/mesh-events-pending.ts"() {
|
|
10140
10414
|
"use strict";
|
|
10141
10415
|
import_fs10 = require("fs");
|
|
10142
10416
|
import_path9 = require("path");
|
|
10143
|
-
|
|
10417
|
+
import_crypto8 = require("crypto");
|
|
10144
10418
|
init_logger();
|
|
10145
10419
|
init_mesh_ledger();
|
|
10146
10420
|
init_mesh_runtime_store();
|
|
@@ -10153,176 +10427,6 @@ var init_mesh_events_pending = __esm({
|
|
|
10153
10427
|
}
|
|
10154
10428
|
});
|
|
10155
10429
|
|
|
10156
|
-
// src/mesh/mesh-delivery-policy.ts
|
|
10157
|
-
function resolveDeliveryDecision(sessionStatus, opts) {
|
|
10158
|
-
const status = (sessionStatus || "").trim().toLowerCase();
|
|
10159
|
-
if (!status) {
|
|
10160
|
-
return {
|
|
10161
|
-
decision: "rejected",
|
|
10162
|
-
reason: "unknown_session_status",
|
|
10163
|
-
message: "Session status is unknown. Delivery rejected (fail-closed). Use mesh_launch_session to start a fresh session."
|
|
10164
|
-
};
|
|
10165
|
-
}
|
|
10166
|
-
if (IMMEDIATE_DELIVERY_STATUSES.has(status)) {
|
|
10167
|
-
return {
|
|
10168
|
-
decision: "immediate",
|
|
10169
|
-
reason: `session_${status}`,
|
|
10170
|
-
message: `Session is ${status} \u2014 delivery allowed immediately.`
|
|
10171
|
-
};
|
|
10172
|
-
}
|
|
10173
|
-
if (BUSY_DELIVERY_STATUSES.has(status)) {
|
|
10174
|
-
if (opts?.allowBusyInjection) {
|
|
10175
|
-
return {
|
|
10176
|
-
decision: "immediate",
|
|
10177
|
-
reason: `session_${status}_busy_injection_allowed`,
|
|
10178
|
-
message: `Session is ${status} but provider supports busy injection. Delivered immediately.`
|
|
10179
|
-
};
|
|
10180
|
-
}
|
|
10181
|
-
if (status === "waiting_approval" && opts?.kind === "approval") {
|
|
10182
|
-
return {
|
|
10183
|
-
decision: "immediate",
|
|
10184
|
-
reason: "session_waiting_approval_approval_message",
|
|
10185
|
-
message: "Session is waiting for approval \u2014 approval message delivered immediately."
|
|
10186
|
-
};
|
|
10187
|
-
}
|
|
10188
|
-
return {
|
|
10189
|
-
decision: "queued",
|
|
10190
|
-
reason: `session_${status}_busy`,
|
|
10191
|
-
message: `Session is ${status}. Task queued for delivery when session becomes idle. Do not inject directly into a busy session.`
|
|
10192
|
-
};
|
|
10193
|
-
}
|
|
10194
|
-
if (TERMINAL_DELIVERY_STATUSES.has(status)) {
|
|
10195
|
-
return {
|
|
10196
|
-
decision: "rejected",
|
|
10197
|
-
reason: `session_${status}_terminal`,
|
|
10198
|
-
message: `Session is ${status} (terminal). Delivery rejected. Launch a new session before dispatching tasks.`
|
|
10199
|
-
};
|
|
10200
|
-
}
|
|
10201
|
-
return {
|
|
10202
|
-
decision: "rejected",
|
|
10203
|
-
reason: "unrecognized_session_status",
|
|
10204
|
-
message: `Session status '${sessionStatus}' is not recognized. Delivery rejected (fail-closed). Inspect session state before retrying.`
|
|
10205
|
-
};
|
|
10206
|
-
}
|
|
10207
|
-
function createSessionDelivery(opts) {
|
|
10208
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10209
|
-
const id = (0, import_crypto8.randomUUID)();
|
|
10210
|
-
const record = {
|
|
10211
|
-
id,
|
|
10212
|
-
meshId: opts.meshId,
|
|
10213
|
-
nodeId: opts.nodeId,
|
|
10214
|
-
sessionId: opts.sessionId,
|
|
10215
|
-
providerType: opts.providerType,
|
|
10216
|
-
taskId: opts.taskId,
|
|
10217
|
-
kind: opts.kind,
|
|
10218
|
-
priority: opts.priority ?? 0,
|
|
10219
|
-
message: opts.message,
|
|
10220
|
-
status: opts.status,
|
|
10221
|
-
deliverAfter: opts.deliverAfter,
|
|
10222
|
-
expiresAt: opts.expiresAt,
|
|
10223
|
-
attemptCount: 0,
|
|
10224
|
-
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
10225
|
-
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
10226
|
-
createdAt: now,
|
|
10227
|
-
updatedAt: now
|
|
10228
|
-
};
|
|
10229
|
-
MeshRuntimeStore.getInstance().insertSessionDelivery({
|
|
10230
|
-
id,
|
|
10231
|
-
meshId: opts.meshId,
|
|
10232
|
-
nodeId: opts.nodeId,
|
|
10233
|
-
sessionId: opts.sessionId,
|
|
10234
|
-
providerType: opts.providerType,
|
|
10235
|
-
taskId: opts.taskId,
|
|
10236
|
-
kind: opts.kind,
|
|
10237
|
-
priority: opts.priority ?? 0,
|
|
10238
|
-
message: opts.message,
|
|
10239
|
-
status: opts.status,
|
|
10240
|
-
deliverAfter: opts.deliverAfter,
|
|
10241
|
-
expiresAt: opts.expiresAt,
|
|
10242
|
-
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
10243
|
-
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
10244
|
-
createdAt: now,
|
|
10245
|
-
updatedAt: now
|
|
10246
|
-
});
|
|
10247
|
-
return record;
|
|
10248
|
-
}
|
|
10249
|
-
function updateSessionDeliveryStatus(id, status, opts) {
|
|
10250
|
-
try {
|
|
10251
|
-
MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(id, status, opts);
|
|
10252
|
-
} catch {
|
|
10253
|
-
}
|
|
10254
|
-
}
|
|
10255
|
-
function getActiveSessionDeliveries(meshId, sessionId) {
|
|
10256
|
-
try {
|
|
10257
|
-
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
10258
|
-
} catch {
|
|
10259
|
-
return [];
|
|
10260
|
-
}
|
|
10261
|
-
}
|
|
10262
|
-
function recordCompletionConflict(opts) {
|
|
10263
|
-
try {
|
|
10264
|
-
MeshRuntimeStore.getInstance().recordCompletionConflict({
|
|
10265
|
-
id: (0, import_crypto8.randomUUID)(),
|
|
10266
|
-
meshId: opts.meshId,
|
|
10267
|
-
fingerprint: opts.fingerprint,
|
|
10268
|
-
conflictingTaskId: opts.conflictingTaskId,
|
|
10269
|
-
conflictingSessionId: opts.conflictingSessionId,
|
|
10270
|
-
originalTaskId: opts.originalTaskId,
|
|
10271
|
-
originalSessionId: opts.originalSessionId,
|
|
10272
|
-
event: opts.event,
|
|
10273
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10274
|
-
});
|
|
10275
|
-
} catch {
|
|
10276
|
-
}
|
|
10277
|
-
}
|
|
10278
|
-
function getRecentCompletionConflicts(meshId, limitMs) {
|
|
10279
|
-
try {
|
|
10280
|
-
return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
|
|
10281
|
-
} catch {
|
|
10282
|
-
return [];
|
|
10283
|
-
}
|
|
10284
|
-
}
|
|
10285
|
-
function markSessionDeliveriesTerminal(meshId, sessionId, terminalStatus) {
|
|
10286
|
-
try {
|
|
10287
|
-
const active = MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
10288
|
-
for (const delivery of active) {
|
|
10289
|
-
MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(delivery.id, terminalStatus);
|
|
10290
|
-
}
|
|
10291
|
-
} catch {
|
|
10292
|
-
}
|
|
10293
|
-
}
|
|
10294
|
-
var import_crypto8, IMMEDIATE_DELIVERY_STATUSES, BUSY_DELIVERY_STATUSES, TERMINAL_DELIVERY_STATUSES;
|
|
10295
|
-
var init_mesh_delivery_policy = __esm({
|
|
10296
|
-
"src/mesh/mesh-delivery-policy.ts"() {
|
|
10297
|
-
"use strict";
|
|
10298
|
-
import_crypto8 = require("crypto");
|
|
10299
|
-
init_mesh_runtime_store();
|
|
10300
|
-
IMMEDIATE_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
10301
|
-
"idle",
|
|
10302
|
-
"waiting_input",
|
|
10303
|
-
"ready"
|
|
10304
|
-
]);
|
|
10305
|
-
BUSY_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
10306
|
-
"generating",
|
|
10307
|
-
"running",
|
|
10308
|
-
"streaming",
|
|
10309
|
-
"busy",
|
|
10310
|
-
"starting",
|
|
10311
|
-
"initializing",
|
|
10312
|
-
"waiting_approval"
|
|
10313
|
-
]);
|
|
10314
|
-
TERMINAL_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
10315
|
-
"stopped",
|
|
10316
|
-
"failed",
|
|
10317
|
-
"terminated",
|
|
10318
|
-
"exited",
|
|
10319
|
-
"closed",
|
|
10320
|
-
"deleted",
|
|
10321
|
-
"error"
|
|
10322
|
-
]);
|
|
10323
|
-
}
|
|
10324
|
-
});
|
|
10325
|
-
|
|
10326
10430
|
// src/mesh/mesh-events-stale.ts
|
|
10327
10431
|
function findRecentTerminalLedgerEvidence(args) {
|
|
10328
10432
|
if (!args.sessionId && !args.nodeId) return null;
|
|
@@ -11874,7 +11978,14 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
11874
11978
|
targetSessionId: sessionId,
|
|
11875
11979
|
cliType: providerType,
|
|
11876
11980
|
action: "send_chat",
|
|
11877
|
-
message: task.message
|
|
11981
|
+
message: task.message,
|
|
11982
|
+
meshContext: {
|
|
11983
|
+
meshId,
|
|
11984
|
+
nodeId,
|
|
11985
|
+
taskId: task.id,
|
|
11986
|
+
...readNonEmptyString2(loadConfig().machineId) ? { coordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {},
|
|
11987
|
+
...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { coordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {}
|
|
11988
|
+
}
|
|
11878
11989
|
}),
|
|
11879
11990
|
{
|
|
11880
11991
|
meshId,
|
|
@@ -19544,6 +19655,15 @@ var init_cli_state_engine = __esm({
|
|
|
19544
19655
|
currentStatus = "starting";
|
|
19545
19656
|
isWaitingForResponse = false;
|
|
19546
19657
|
currentTurnScope = null;
|
|
19658
|
+
// ARCH-REFACTOR R1 (per-turn task identity): the mesh taskId bound to the most
|
|
19659
|
+
// recently STARTED turn. Unlike currentTurnScope (nulled the moment the turn
|
|
19660
|
+
// settles, before the completion event is even built), this persists past
|
|
19661
|
+
// completion and is only overwritten when the NEXT turn starts. That window is
|
|
19662
|
+
// exactly what the completion path needs: when a turn settles to idle, this still
|
|
19663
|
+
// holds THAT turn's taskId (the next task's turn cannot have started yet — it is
|
|
19664
|
+
// queued in pendingOutbound and only flushed asynchronously after idle), so the
|
|
19665
|
+
// completion event carries the correct id instead of the racy session scalar.
|
|
19666
|
+
currentTurnTaskId = null;
|
|
19547
19667
|
activeModal = null;
|
|
19548
19668
|
// ── Approval ─────────────────────────────────────
|
|
19549
19669
|
lastApprovalResolvedAt = 0;
|
|
@@ -19653,6 +19773,7 @@ var init_cli_state_engine = __esm({
|
|
|
19653
19773
|
this.finishRetryCount = 0;
|
|
19654
19774
|
this.clearIdleFinishCandidate("send_message");
|
|
19655
19775
|
this.currentTurnScope = turnScope;
|
|
19776
|
+
this.currentTurnTaskId = typeof turnScope.taskId === "string" && turnScope.taskId.trim() ? turnScope.taskId : null;
|
|
19656
19777
|
this.responseEpoch += 1;
|
|
19657
19778
|
}
|
|
19658
19779
|
/** Called when PTY exits */
|
|
@@ -21605,15 +21726,18 @@ ${lastSnapshot}`;
|
|
|
21605
21726
|
}
|
|
21606
21727
|
async sendMessage(text, options = {}) {
|
|
21607
21728
|
if (options.force === true) {
|
|
21608
|
-
await this.forceSendMessage(text);
|
|
21729
|
+
await this.forceSendMessage(text, options.meshTaskId);
|
|
21609
21730
|
return;
|
|
21610
21731
|
}
|
|
21611
|
-
await this.sendMessageNow(text, true);
|
|
21732
|
+
await this.sendMessageNow(text, true, options.meshTaskId);
|
|
21612
21733
|
}
|
|
21613
|
-
async forceSendMessage(text) {
|
|
21734
|
+
async forceSendMessage(text, meshTaskId) {
|
|
21614
21735
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
21615
21736
|
const content = String(text || "");
|
|
21616
21737
|
if (!content.trim()) return;
|
|
21738
|
+
if (typeof meshTaskId === "string" && meshTaskId.trim()) {
|
|
21739
|
+
this.engine.currentTurnTaskId = meshTaskId;
|
|
21740
|
+
}
|
|
21617
21741
|
if (this.engine.currentStatus === "waiting_approval" || this.engine.hasActionableApproval()) {
|
|
21618
21742
|
LOG.info("CLI", `[${this.cliType}] force-send held \u2014 session parked on approval modal (status=${this.engine.currentStatus})`);
|
|
21619
21743
|
return;
|
|
@@ -21626,7 +21750,7 @@ ${lastSnapshot}`;
|
|
|
21626
21750
|
async waitForForceSubmitSettle() {
|
|
21627
21751
|
await new Promise((resolve24) => setTimeout(resolve24, FORCE_SUBMIT_SETTLE_MS));
|
|
21628
21752
|
}
|
|
21629
|
-
enqueuePendingOutboundMessage(text, reason) {
|
|
21753
|
+
enqueuePendingOutboundMessage(text, reason, meshTaskId) {
|
|
21630
21754
|
const content = String(text || "");
|
|
21631
21755
|
const duplicate = this.pendingOutboundQueue.some((message2) => message2.content === content);
|
|
21632
21756
|
if (duplicate) {
|
|
@@ -21638,7 +21762,8 @@ ${lastSnapshot}`;
|
|
|
21638
21762
|
role: "user",
|
|
21639
21763
|
content,
|
|
21640
21764
|
queuedAt,
|
|
21641
|
-
source: "sendMessage"
|
|
21765
|
+
source: "sendMessage",
|
|
21766
|
+
...typeof meshTaskId === "string" && meshTaskId.trim() ? { meshTaskId } : {}
|
|
21642
21767
|
};
|
|
21643
21768
|
this.pendingOutboundQueue.push(message);
|
|
21644
21769
|
LOG.info("CLI", `[${this.cliType}] queued outbound message while busy (${reason}); queue=${this.pendingOutboundQueue.length}`);
|
|
@@ -21681,7 +21806,7 @@ ${lastSnapshot}`;
|
|
|
21681
21806
|
if (this.engine.currentStatus !== "idle" || this.engine.isWaitingForResponse || this.engine.hasActionableApproval()) break;
|
|
21682
21807
|
const next = this.pendingOutboundQueue[0];
|
|
21683
21808
|
try {
|
|
21684
|
-
await this.sendMessageNow(next.content, false);
|
|
21809
|
+
await this.sendMessageNow(next.content, false, next.meshTaskId);
|
|
21685
21810
|
this.pendingOutboundQueue.shift();
|
|
21686
21811
|
this.onStatusChange?.();
|
|
21687
21812
|
} catch (error) {
|
|
@@ -21694,7 +21819,7 @@ ${lastSnapshot}`;
|
|
|
21694
21819
|
this.pendingOutboundFlushInFlight = false;
|
|
21695
21820
|
}
|
|
21696
21821
|
}
|
|
21697
|
-
async sendMessageNow(text, allowQueue) {
|
|
21822
|
+
async sendMessageNow(text, allowQueue, meshTaskId) {
|
|
21698
21823
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
21699
21824
|
const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
|
|
21700
21825
|
const allowInterventionPrompt = allowInputDuringGeneration && this.engine.isWaitingForResponse && !this.engine.hasActionableApproval();
|
|
@@ -21714,7 +21839,7 @@ ${lastSnapshot}`;
|
|
|
21714
21839
|
})() : null;
|
|
21715
21840
|
const queueReason = this.shouldQueuePendingOutboundMessage(parsedStatusBeforeSend);
|
|
21716
21841
|
if (allowQueue && queueReason) {
|
|
21717
|
-
this.enqueuePendingOutboundMessage(text, queueReason);
|
|
21842
|
+
this.enqueuePendingOutboundMessage(text, queueReason, meshTaskId);
|
|
21718
21843
|
return;
|
|
21719
21844
|
}
|
|
21720
21845
|
if (!allowInterventionPrompt) {
|
|
@@ -21731,7 +21856,7 @@ ${lastSnapshot}`;
|
|
|
21731
21856
|
}
|
|
21732
21857
|
if (!this.ready) {
|
|
21733
21858
|
if (allowQueue) {
|
|
21734
|
-
this.enqueuePendingOutboundMessage(text, "not_ready_pending_prompt");
|
|
21859
|
+
this.enqueuePendingOutboundMessage(text, "not_ready_pending_prompt", meshTaskId);
|
|
21735
21860
|
return;
|
|
21736
21861
|
}
|
|
21737
21862
|
throw new Error(`${this.cliName} not ready (status: ${this.engine.currentStatus})`);
|
|
@@ -21745,7 +21870,7 @@ ${lastSnapshot}`;
|
|
|
21745
21870
|
const terminalLooksIdle = this.engine.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.engine.isWaitingForResponse && !this.engine.currentTurnScope && !this.engine.hasActionableApproval() && !parsedHasActionableModal;
|
|
21746
21871
|
if (!terminalLooksIdle) {
|
|
21747
21872
|
if (allowQueue) {
|
|
21748
|
-
this.enqueuePendingOutboundMessage(text, `parsed_status_${parsedSessionStatus}
|
|
21873
|
+
this.enqueuePendingOutboundMessage(text, `parsed_status_${parsedSessionStatus}`, meshTaskId);
|
|
21749
21874
|
return;
|
|
21750
21875
|
}
|
|
21751
21876
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
@@ -21755,7 +21880,7 @@ ${lastSnapshot}`;
|
|
|
21755
21880
|
const snap = this.getSnapshot();
|
|
21756
21881
|
if (!this.engine.clearStaleIdleResponseGuard("send_message_guard", snap) && !this.engine.clearParsedIdleResponseGuard("send_message_parsed_idle_guard", parsedStatusBeforeSend, snap)) {
|
|
21757
21882
|
if (allowQueue) {
|
|
21758
|
-
this.enqueuePendingOutboundMessage(text, "waiting_for_response");
|
|
21883
|
+
this.enqueuePendingOutboundMessage(text, "waiting_for_response", meshTaskId);
|
|
21759
21884
|
return;
|
|
21760
21885
|
}
|
|
21761
21886
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
@@ -21766,7 +21891,11 @@ ${lastSnapshot}`;
|
|
|
21766
21891
|
prompt: text,
|
|
21767
21892
|
startedAt: Date.now(),
|
|
21768
21893
|
bufferStart: this.accumulatedBuffer.length,
|
|
21769
|
-
rawBufferStart: this.accumulatedRawBuffer.length
|
|
21894
|
+
rawBufferStart: this.accumulatedRawBuffer.length,
|
|
21895
|
+
// ARCH-REFACTOR R1: bind this turn to its mesh task. engine.onTurnStarted
|
|
21896
|
+
// copies this into currentTurnTaskId so the turn's completion event carries
|
|
21897
|
+
// the right id even if a later task overwrites the session scalar meanwhile.
|
|
21898
|
+
...typeof meshTaskId === "string" && meshTaskId.trim() ? { taskId: meshTaskId } : {}
|
|
21770
21899
|
};
|
|
21771
21900
|
LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${turnScope.bufferStart} raw=${turnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
|
|
21772
21901
|
if (this.submitRetryTimer) {
|
|
@@ -22116,6 +22245,13 @@ ${lastSnapshot}`;
|
|
|
22116
22245
|
set currentTurnScope(v) {
|
|
22117
22246
|
this.engine.currentTurnScope = v;
|
|
22118
22247
|
}
|
|
22248
|
+
// ARCH-REFACTOR R1: the mesh taskId bound to the most recently started turn,
|
|
22249
|
+
// surviving past turn settle until the next turn starts. The provider instance
|
|
22250
|
+
// reads this when stamping completion events so they carry the completing turn's
|
|
22251
|
+
// task rather than the racy last-write-wins session scalar.
|
|
22252
|
+
get currentTurnTaskId() {
|
|
22253
|
+
return this.engine.currentTurnTaskId;
|
|
22254
|
+
}
|
|
22119
22255
|
get responseEpoch() {
|
|
22120
22256
|
return this.engine.responseEpoch;
|
|
22121
22257
|
}
|
|
@@ -40705,11 +40841,28 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
40705
40841
|
isMeshWorkerSession() {
|
|
40706
40842
|
return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
|
|
40707
40843
|
}
|
|
40844
|
+
/**
|
|
40845
|
+
* ARCH-REFACTOR R1: the taskId to attribute the CURRENTLY-completing turn to.
|
|
40846
|
+
* Prefers the per-turn binding (engine.currentTurnTaskId, set when the turn was
|
|
40847
|
+
* submitted and surviving until the next turn starts) over the last-write-wins
|
|
40848
|
+
* session scalar (settings.meshActiveTaskId). The scalar is retained only as a
|
|
40849
|
+
* backward-compat alias for the "current/last assignment" and is the source of the
|
|
40850
|
+
* NOTIF-MISDELIVER / TASK-MSG-MISROUTE race: a second task attaching before this
|
|
40851
|
+
* turn completes overwrites it. Returns undefined for a non-task ad-hoc turn.
|
|
40852
|
+
*/
|
|
40853
|
+
completingTurnTaskId() {
|
|
40854
|
+
const turnTaskId = this.adapter?.currentTurnTaskId;
|
|
40855
|
+
if (typeof turnTaskId === "string" && turnTaskId.trim()) return turnTaskId;
|
|
40856
|
+
const scalar = this.settings.meshActiveTaskId;
|
|
40857
|
+
return typeof scalar === "string" && scalar.trim() ? scalar : void 0;
|
|
40858
|
+
}
|
|
40708
40859
|
// EVTTRACE correlation context for this session's completion lifecycle. taskId is
|
|
40709
40860
|
// the primary grep anchor; instanceId is the session fallback.
|
|
40710
40861
|
meshTraceCtx(event = "agent:generating_completed") {
|
|
40711
40862
|
return {
|
|
40712
|
-
|
|
40863
|
+
// ARCH-REFACTOR R1: trace the per-turn taskId (falling back to the scalar) so
|
|
40864
|
+
// EvtTrace anchors on the same id the completion event actually carries.
|
|
40865
|
+
taskId: this.completingTurnTaskId(),
|
|
40713
40866
|
sessionId: this.instanceId,
|
|
40714
40867
|
nodeId: this.settings.meshNodeId,
|
|
40715
40868
|
meshId: this.settings.meshNodeFor,
|
|
@@ -40768,6 +40921,8 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
40768
40921
|
chatTitle: pending.chatTitle,
|
|
40769
40922
|
duration: pending.duration,
|
|
40770
40923
|
timestamp: pending.timestamp,
|
|
40924
|
+
// ARCH-REFACTOR R1: attribute to the turn captured at idle-transition.
|
|
40925
|
+
...pending.taskId ? { taskId: pending.taskId } : {},
|
|
40771
40926
|
// When finalization is forced past the timeout on a `parsed_status:` block
|
|
40772
40927
|
// (the parser never confirmed a final assistant turn) we previously rode an
|
|
40773
40928
|
// empty `finalSummary` unconditionally. That empty value propagates to the
|
|
@@ -40793,6 +40948,8 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
40793
40948
|
chatTitle: pending.chatTitle,
|
|
40794
40949
|
duration: pending.duration,
|
|
40795
40950
|
timestamp: pending.timestamp,
|
|
40951
|
+
// ARCH-REFACTOR R1: attribute to the turn captured at idle-transition.
|
|
40952
|
+
...pending.taskId ? { taskId: pending.taskId } : {},
|
|
40796
40953
|
finalSummary: this.completionFinalSummary(this.adapter?.getScriptParsedStatus()?.messages)
|
|
40797
40954
|
});
|
|
40798
40955
|
this.completedDebouncePending = null;
|
|
@@ -41069,7 +41226,11 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
41069
41226
|
duration,
|
|
41070
41227
|
timestamp: now,
|
|
41071
41228
|
firstObservedAt: now,
|
|
41072
|
-
previousStatus: this.lastStatus
|
|
41229
|
+
previousStatus: this.lastStatus,
|
|
41230
|
+
// ARCH-REFACTOR R1: snapshot the completing turn's taskId NOW (sync),
|
|
41231
|
+
// before any follow-up task's flush can start a new turn and move
|
|
41232
|
+
// engine.currentTurnTaskId.
|
|
41233
|
+
...this.completingTurnTaskId() ? { taskId: this.completingTurnTaskId() } : {}
|
|
41073
41234
|
};
|
|
41074
41235
|
const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
|
|
41075
41236
|
const meshWorkerSession = this.isMeshWorkerSession();
|
|
@@ -41172,10 +41333,11 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
41172
41333
|
workspace: typeof event.workspace === "string" && event.workspace.trim() ? event.workspace : this.workingDir,
|
|
41173
41334
|
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
41174
41335
|
};
|
|
41175
|
-
if (this.isMeshWorkerSession()
|
|
41336
|
+
if (this.isMeshWorkerSession()) {
|
|
41176
41337
|
const existingTaskId = typeof enrichedEvent.taskId === "string" && enrichedEvent.taskId.trim() ? enrichedEvent.taskId : void 0;
|
|
41177
41338
|
if (!existingTaskId) {
|
|
41178
|
-
|
|
41339
|
+
const resolved = this.completingTurnTaskId();
|
|
41340
|
+
if (resolved) enrichedEvent.taskId = resolved;
|
|
41179
41341
|
}
|
|
41180
41342
|
}
|
|
41181
41343
|
if (this.context?.emitProviderEvent) {
|
|
@@ -44055,11 +44217,15 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
44055
44217
|
}
|
|
44056
44218
|
const message = input.textFallback;
|
|
44057
44219
|
if (!message) throw new Error("message required for send_chat");
|
|
44220
|
+
const meshTaskId = meshContext && typeof meshContext === "object" && typeof meshContext.taskId === "string" && meshContext.taskId.trim() ? meshContext.taskId : void 0;
|
|
44058
44221
|
const forceSend = args?.force === true || args?.forceSend === true;
|
|
44059
44222
|
if (forceSend && typeof adapter.forceSendMessage === "function") {
|
|
44060
|
-
await adapter.forceSendMessage(message);
|
|
44223
|
+
if (meshTaskId) await adapter.forceSendMessage(message, meshTaskId);
|
|
44224
|
+
else await adapter.forceSendMessage(message);
|
|
44061
44225
|
} else if (forceSend) {
|
|
44062
|
-
await adapter.sendMessage(message, { force: true });
|
|
44226
|
+
await adapter.sendMessage(message, meshTaskId ? { force: true, meshTaskId } : { force: true });
|
|
44227
|
+
} else if (meshTaskId) {
|
|
44228
|
+
await adapter.sendMessage(message, { meshTaskId });
|
|
44063
44229
|
} else {
|
|
44064
44230
|
await adapter.sendMessage(message);
|
|
44065
44231
|
}
|
|
@@ -48587,6 +48753,11 @@ var meshCrudHandlers = {
|
|
|
48587
48753
|
baseBranch,
|
|
48588
48754
|
meshName: mesh.name
|
|
48589
48755
|
});
|
|
48756
|
+
if (result.baseSync?.warning) {
|
|
48757
|
+
console.warn(`[mesh] clone_mesh_node base sync (${result.baseSync.action}): ${result.baseSync.warning}`);
|
|
48758
|
+
} else if (result.baseSync && result.baseSync.action !== "up_to_date") {
|
|
48759
|
+
console.log(`[mesh] clone_mesh_node base sync: ${result.baseSync.action} (startRef=${result.baseSync.startRef})`);
|
|
48760
|
+
}
|
|
48590
48761
|
let node;
|
|
48591
48762
|
if (meshRecord.inline) {
|
|
48592
48763
|
const { randomUUID: randomUUID15 } = await import("crypto");
|
|
@@ -48777,6 +48948,8 @@ var meshCrudHandlers = {
|
|
|
48777
48948
|
node,
|
|
48778
48949
|
worktreePath: result.worktreePath,
|
|
48779
48950
|
branch: result.branch,
|
|
48951
|
+
...result.baseSync ? { baseSync: result.baseSync } : {},
|
|
48952
|
+
...result.baseSync?.warning ? { baseStaleWarning: result.baseSync.warning } : {},
|
|
48780
48953
|
worktreeBootstrap: runningBootstrapState,
|
|
48781
48954
|
worktreeSetup: {
|
|
48782
48955
|
status: "running",
|
|
@@ -48792,6 +48965,8 @@ var meshCrudHandlers = {
|
|
|
48792
48965
|
node,
|
|
48793
48966
|
worktreePath: result.worktreePath,
|
|
48794
48967
|
branch: result.branch,
|
|
48968
|
+
...result.baseSync ? { baseSync: result.baseSync } : {},
|
|
48969
|
+
...result.baseSync?.warning ? { baseStaleWarning: result.baseSync.warning } : {},
|
|
48795
48970
|
submodulesInitialized,
|
|
48796
48971
|
worktreeBootstrap: bootstrapState
|
|
48797
48972
|
};
|