@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.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 ? "
|
|
398
|
-
const commitShort = readInjected(true ? "
|
|
399
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
400
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
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 (
|
|
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 = {}) {
|
|
@@ -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
|
|
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() :
|
|
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,
|
|
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
|
|
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() :
|
|
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
|
|
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:
|
|
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
|
-
|
|
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()
|
|
40955
|
+
if (this.isMeshWorkerSession()) {
|
|
40795
40956
|
const existingTaskId = typeof enrichedEvent.taskId === "string" && enrichedEvent.taskId.trim() ? enrichedEvent.taskId : void 0;
|
|
40796
40957
|
if (!existingTaskId) {
|
|
40797
|
-
|
|
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
|
};
|