@adhdev/daemon-core 0.9.82-rc.292 → 0.9.82-rc.293
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +227 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +229 -43
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-missions.d.ts +25 -1
- package/dist/mesh/mesh-runtime-store.d.ts +15 -0
- package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
- package/package.json +2 -2
- package/src/commands/router.ts +15 -3
- package/src/git/git-status.ts +46 -11
- package/src/mesh/coordinator-prompt.ts +2 -2
- package/src/mesh/mesh-events-coordinator.ts +51 -6
- package/src/mesh/mesh-missions.ts +41 -3
- package/src/mesh/mesh-reconcile-loop.ts +55 -0
- package/src/mesh/mesh-runtime-store.ts +30 -0
- package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
- package/src/providers/cli-provider-instance.ts +21 -16
- package/src/providers/extension-provider-instance.ts +5 -1
- package/src/providers/ide-provider-instance.ts +6 -1
package/dist/index.js
CHANGED
|
@@ -275,10 +275,10 @@ function readInjected(value) {
|
|
|
275
275
|
}
|
|
276
276
|
function getDaemonBuildInfo() {
|
|
277
277
|
if (cached) return cached;
|
|
278
|
-
const commit = readInjected(true ? "
|
|
279
|
-
const commitShort = readInjected(true ? "
|
|
280
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
281
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
278
|
+
const commit = readInjected(true ? "88f97abcc85d83fe5d5313b229d32a7d76b1208a" : void 0) ?? "unknown";
|
|
279
|
+
const commitShort = readInjected(true ? "88f97abc" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
280
|
+
const version = readInjected(true ? "0.9.82-rc.293" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
281
|
+
const builtAt = readInjected(true ? "2026-06-16T11:13:51.625Z" : void 0);
|
|
282
282
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
283
283
|
return cached;
|
|
284
284
|
}
|
|
@@ -349,6 +349,15 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
349
349
|
);
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
|
+
function isNonRuntimeRootFile(file) {
|
|
353
|
+
const base = file.slice(file.lastIndexOf("/") + 1);
|
|
354
|
+
if (/^\.(?:verify|marker|converge|ff-verify|patch-equiv|live-verify)\b/i.test(base)) return true;
|
|
355
|
+
if (/(?:^|\/)docs\//i.test(file)) return true;
|
|
356
|
+
if (/^(?:README|CHANGELOG|LICENSE|NOTICE|AUTHORS|CONTRIBUTING|CODEOWNERS)(?:\.[A-Za-z0-9]+)?$/i.test(base)) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
352
361
|
async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
|
|
353
362
|
try {
|
|
354
363
|
const diff = await runGit(repoPath, ["diff", "--name-only", `${buildCommit}..HEAD`], options);
|
|
@@ -357,18 +366,18 @@ async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
|
|
|
357
366
|
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
358
367
|
}
|
|
359
368
|
const pkgs = /* @__PURE__ */ new Set();
|
|
360
|
-
let
|
|
369
|
+
let sawRuntimeAmbiguousNonPackage = false;
|
|
361
370
|
for (const file of files) {
|
|
362
371
|
const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
|
|
363
372
|
if (!match) {
|
|
364
|
-
|
|
373
|
+
if (!isNonRuntimeRootFile(file)) sawRuntimeAmbiguousNonPackage = true;
|
|
365
374
|
continue;
|
|
366
375
|
}
|
|
367
376
|
pkgs.add(match[1]);
|
|
368
377
|
}
|
|
369
378
|
const affectedPackages = [...pkgs].sort();
|
|
370
|
-
const
|
|
371
|
-
return { isDaemonAffecting: !
|
|
379
|
+
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) => WEB_ONLY_PACKAGES.has(p) && !DAEMON_RUNTIME_PACKAGES.has(p));
|
|
380
|
+
return { isDaemonAffecting: !allBenign, affectedPackages };
|
|
372
381
|
} catch {
|
|
373
382
|
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
374
383
|
}
|
|
@@ -395,7 +404,8 @@ async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
|
395
404
|
options
|
|
396
405
|
);
|
|
397
406
|
const scopeLabel = scope === "root" ? "workspace" : scope;
|
|
398
|
-
const
|
|
407
|
+
const benignDetail = affectedPackages.length > 0 ? `only web packages changed (${affectedPackages.join(", ")})` : "only non-runtime files changed (markers/docs)";
|
|
408
|
+
const warning = isDaemonAffecting ? `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} HEAD ${head.slice(0, 7)}. Merged code is NOT live until the daemon is rebuilt/redeployed and restarted \u2014 a local dist rebuild alone does not update a cloud daemon.` : `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} HEAD ${head.slice(0, 7)}, but ${benignDetail}. Daemon restart NOT required \u2014 redeploy the web app to reflect the change.`;
|
|
399
409
|
return {
|
|
400
410
|
buildCommit: build.commit,
|
|
401
411
|
buildCommitShort: build.commitShort,
|
|
@@ -1997,7 +2007,7 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
1997
2007
|
- **Reuse idle sessions.** For follow-up, retry, commit/push, or cleanup on the same issue, send only the delta to the existing idle session. Start fresh only for independent work, provider mismatch, transcript contamination, or required worktree isolation.
|
|
1998
2008
|
- **Respect explicit provider requests.** Map: Hermes \u2192 \`hermes-cli\`, Claude/Claude Code \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`, Antigravity \u2192 \`antigravity-cli\`. Never substitute the coordinator's own runtime.
|
|
1999
2009
|
- **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
|
|
2000
|
-
- **Limit parallelism.** Start with 1\u20132 tasks; scale only on success. Never duplicate a session because \`mesh_read_chat\` shows no final message while tool/terminal activity is ongoing.
|
|
2010
|
+
- **Limit parallelism.** Start with 1\u20132 tasks; scale only on success. Never duplicate a session because \`mesh_read_chat\` shows no final message while tool/terminal activity is ongoing. This caps *concurrent* load \u2014 it does not mean serialize independent work: when a new, independent request arrives and there is headroom under \`maxParallelTasks\`, dispatch it right away rather than waiting for an in-flight task or a user nudge (read-only diagnosis especially, since it has no merge cost).
|
|
2001
2011
|
- **Check history first.** Call \`mesh_task_history\` at session start to avoid duplicate work and inform recovery. On failure, read task history before retrying.
|
|
2002
2012
|
- **Converge branches.** After worktree tasks: refine/fast-forward, or classify as \`pushed_feature_branch_needs_merge\` / \`blocked_review\` / \`cleanup_candidate\` / \`not_mergeable\`. Clean up with \`mesh_remove_node\`.
|
|
2003
2013
|
- **Refinery is config-driven.** \`mesh_refine_node\` must run validation from \`.adhdev/refine.{json,yaml,yml}\` or \`repo-mesh.refine.*\`. Heuristics are scaffolding only.
|
|
@@ -2051,7 +2061,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
2051
2061
|
c. **Targeted Tasks**: Use \`mesh_send_task\` only when you need to bypass the queue and force a specific node to execute a task immediately.
|
|
2052
2062
|
d. For the first dispatch of a new task, provide a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
|
|
2053
2063
|
e. For a continuation of the same issue in an existing session, send a concise **delta instruction**: current verified state, the exact failed/blocked step, the newly approved action, and final reporting requirements. Do not resend the full original task or open a new chat solely to continue the same work; that wastes coordinator and worker context.
|
|
2054
|
-
4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly. Do **not** repeatedly call \`mesh_status\` or \`mesh_view_queue\` just to wait for assigned/generating work. After dispatching a direct or queued task, send one progress update with the task/session handle, then stop. Wait for \`pendingCoordinatorEvents\` or another completion/approval/status signal, an explicit user status request, or a real timeout/stall signal before reading status/chat/queue again. Use at most one compact \`mesh_read_chat\` check after a terminal signal. Handle approvals via \`mesh_approve\`.
|
|
2064
|
+
4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly. Do **not** repeatedly call \`mesh_status\` or \`mesh_view_queue\` just to wait for assigned/generating work. After dispatching a direct or queued task, send one progress update with the task/session handle, then stop. Wait for \`pendingCoordinatorEvents\` or another completion/approval/status signal, an explicit user status request, or a real timeout/stall signal before reading status/chat/queue again. Use at most one compact \`mesh_read_chat\` check after a terminal signal. Handle approvals via \`mesh_approve\`. **Proactively parallelize new work.** When the user reports a new bug or asks for new work, start it immediately if it is independent of in-flight tasks and there is headroom under \`maxParallelTasks\` \u2014 do not wait for a current task to finish or for the user to prompt you to parallelize. Read-only diagnosis (\`live_debug_readonly\`) has no isolation or merge cost, so dispatch it in parallel right away. The no-polling / concurrency-limit rules constrain *re-checking or duplicating already-dispatched work*; they are **not** a reason to defer starting a new, independent task.
|
|
2055
2065
|
5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
|
|
2056
2066
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
2057
2067
|
7. **Converge branches** \u2014 Before marking any task complete, classify every touched node/branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. Use \`mesh_status\` branchConvergenceSummary. For obvious clean branch catch-up (ahead 0, behind > 0, upstream fresh, no dirty/stash/submodule issues), use \`mesh_fast_forward_node\` dry-run first and execute only when explicitly safe/approved; this avoids consuming an agent session. Use \`mesh_refine_node\` for clean worktree branches when safe. Before/refine merging root commits that contain submodule gitlink changes, require each submodule commit to be reachable from the configured submodule remote main branch, not merely present on a feature ref or local checkout. If \`mesh_refine_node\` returns \`submodule_reachability_failed\` or publish-required evidence, keep the public convergence bucket as \`blocked_review\`; unless \`allowAutoPublishSubmoduleMainCommits\` is explicitly enabled and Refinery reports successful non-force publish plus post-publish verification, ask the user for explicit approval to push/publish the unreachable submodule commit(s) to submodule main, then rerun \`mesh_refine_node\`. Do not merge the root branch until the submodule commit(s) are reachable from submodule origin/main. A task that remains on a non-main branch is not fully complete unless the final report names the follow-up state and next step.
|
|
@@ -4395,6 +4405,34 @@ var init_mesh_runtime_store = __esm({
|
|
|
4395
4405
|
).get(meshId);
|
|
4396
4406
|
return row?.cnt ?? 0;
|
|
4397
4407
|
}
|
|
4408
|
+
/**
|
|
4409
|
+
* Mark specific pending-event rows drained by id (ack). Used by the
|
|
4410
|
+
* unresolved-delegate durable-forward outbox: an event is peeked (not drained)
|
|
4411
|
+
* while its push to the coordinator is unconfirmed, then marked drained ONLY
|
|
4412
|
+
* after the push is acked. A failed push leaves the row undrained so the next
|
|
4413
|
+
* reconcile tick retries it. Returns the number of rows newly marked drained.
|
|
4414
|
+
*/
|
|
4415
|
+
markPendingEventsDrainedById(ids) {
|
|
4416
|
+
const idList = ids.filter((id) => typeof id === "string" && id.length > 0);
|
|
4417
|
+
if (idList.length === 0) return 0;
|
|
4418
|
+
const now = Date.now();
|
|
4419
|
+
return this.db.prepare(
|
|
4420
|
+
`UPDATE mesh_pending_events SET drained = 1, drained_at = ? WHERE drained = 0 AND id IN (${idList.map(() => "?").join(",")})`
|
|
4421
|
+
).run(now, ...idList).changes;
|
|
4422
|
+
}
|
|
4423
|
+
/**
|
|
4424
|
+
* Hard-delete pending-event rows by id (including the dedup fingerprint history).
|
|
4425
|
+
* Used to expire an unresolved-delegate outbox entry that has exhausted its retry
|
|
4426
|
+
* budget — fully removing it frees the fingerprint so a genuinely new completion
|
|
4427
|
+
* for the same task could be re-queued later. Returns the number of rows deleted.
|
|
4428
|
+
*/
|
|
4429
|
+
deletePendingEventsById(ids) {
|
|
4430
|
+
const idList = ids.filter((id) => typeof id === "string" && id.length > 0);
|
|
4431
|
+
if (idList.length === 0) return 0;
|
|
4432
|
+
return this.db.prepare(
|
|
4433
|
+
`DELETE FROM mesh_pending_events WHERE id IN (${idList.map(() => "?").join(",")})`
|
|
4434
|
+
).run(...idList).changes;
|
|
4435
|
+
}
|
|
4398
4436
|
};
|
|
4399
4437
|
}
|
|
4400
4438
|
});
|
|
@@ -4402,6 +4440,7 @@ var init_mesh_runtime_store = __esm({
|
|
|
4402
4440
|
// src/mesh/mesh-missions.ts
|
|
4403
4441
|
var mesh_missions_exports = {};
|
|
4404
4442
|
__export(mesh_missions_exports, {
|
|
4443
|
+
GOAL_PREVIEW_MAX: () => GOAL_PREVIEW_MAX,
|
|
4405
4444
|
MESH_MISSION_STATUSES: () => MESH_MISSION_STATUSES,
|
|
4406
4445
|
buildMissionPromptSection: () => buildMissionPromptSection,
|
|
4407
4446
|
getActiveMeshMissionSummaries: () => getActiveMeshMissionSummaries,
|
|
@@ -4473,12 +4512,23 @@ function summarizeMeshMission(meshId, mission) {
|
|
|
4473
4512
|
function getActiveMeshMissionSummaries(meshId) {
|
|
4474
4513
|
return getMeshMissions(meshId, ["active"]).map((mission) => summarizeMeshMission(meshId, mission));
|
|
4475
4514
|
}
|
|
4515
|
+
function slimMissionSummary(summary) {
|
|
4516
|
+
const goal = typeof summary.goal === "string" ? summary.goal : "";
|
|
4517
|
+
const goalTruncated = goal.length > GOAL_PREVIEW_MAX;
|
|
4518
|
+
const { goal: _omitGoal, ...rest } = summary;
|
|
4519
|
+
return {
|
|
4520
|
+
...rest,
|
|
4521
|
+
goalPreview: goalTruncated ? goal.slice(0, GOAL_PREVIEW_MAX) : goal,
|
|
4522
|
+
goalTruncated
|
|
4523
|
+
};
|
|
4524
|
+
}
|
|
4476
4525
|
function getMeshStatusMissionSummaries(meshId, options) {
|
|
4477
4526
|
const historyLimit = Math.max(0, options?.historyLimit ?? 10);
|
|
4478
4527
|
const all = getMeshMissions(meshId);
|
|
4479
4528
|
const live = all.filter((m) => m.status === "active" || m.status === "paused");
|
|
4480
4529
|
const history = all.filter((m) => m.status === "completed" || m.status === "abandoned").sort((a, b) => (b.updatedAt || "").localeCompare(a.updatedAt || "")).slice(0, historyLimit);
|
|
4481
|
-
|
|
4530
|
+
const full = [...live, ...history].map((mission) => summarizeMeshMission(meshId, mission));
|
|
4531
|
+
return options?.verbose ? full : full.map(slimMissionSummary);
|
|
4482
4532
|
}
|
|
4483
4533
|
function buildMissionPromptSection(meshId) {
|
|
4484
4534
|
const summaries = getActiveMeshMissionSummaries(meshId);
|
|
@@ -4498,7 +4548,7 @@ function buildMissionPromptSection(meshId) {
|
|
|
4498
4548
|
);
|
|
4499
4549
|
return lines.join("\n");
|
|
4500
4550
|
}
|
|
4501
|
-
var import_crypto6, MESH_MISSION_STATUSES;
|
|
4551
|
+
var import_crypto6, MESH_MISSION_STATUSES, GOAL_PREVIEW_MAX;
|
|
4502
4552
|
var init_mesh_missions = __esm({
|
|
4503
4553
|
"src/mesh/mesh-missions.ts"() {
|
|
4504
4554
|
"use strict";
|
|
@@ -4506,6 +4556,7 @@ var init_mesh_missions = __esm({
|
|
|
4506
4556
|
init_mesh_runtime_store();
|
|
4507
4557
|
init_mesh_work_queue();
|
|
4508
4558
|
MESH_MISSION_STATUSES = ["active", "paused", "completed", "abandoned"];
|
|
4559
|
+
GOAL_PREVIEW_MAX = 120;
|
|
4509
4560
|
}
|
|
4510
4561
|
});
|
|
4511
4562
|
|
|
@@ -7604,6 +7655,111 @@ var init_mesh_routing = __esm({
|
|
|
7604
7655
|
}
|
|
7605
7656
|
});
|
|
7606
7657
|
|
|
7658
|
+
// src/mesh/mesh-unresolved-forward-outbox.ts
|
|
7659
|
+
function getStore() {
|
|
7660
|
+
try {
|
|
7661
|
+
return MeshRuntimeStore.getInstance();
|
|
7662
|
+
} catch {
|
|
7663
|
+
return void 0;
|
|
7664
|
+
}
|
|
7665
|
+
}
|
|
7666
|
+
function enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, forwardPayload) {
|
|
7667
|
+
const target = readNonEmptyString2(coordinatorDaemonId);
|
|
7668
|
+
const event = readNonEmptyString2(eventName);
|
|
7669
|
+
if (!target || !event) return false;
|
|
7670
|
+
const store = getStore();
|
|
7671
|
+
if (!store) return false;
|
|
7672
|
+
const queuedAt = Date.now();
|
|
7673
|
+
const fingerprintSource = {
|
|
7674
|
+
event,
|
|
7675
|
+
meshId: UNRESOLVED_FORWARD_OUTBOX_MESH_ID,
|
|
7676
|
+
nodeLabel: readNonEmptyString2(forwardPayload.nodeId) || readNonEmptyString2(forwardPayload.workspace) || "unresolved-delegate",
|
|
7677
|
+
nodeId: readNonEmptyString2(forwardPayload.nodeId) || void 0,
|
|
7678
|
+
workspace: readNonEmptyString2(forwardPayload.workspace) || void 0,
|
|
7679
|
+
metadataEvent: forwardPayload,
|
|
7680
|
+
queuedAt,
|
|
7681
|
+
targetCoordinatorDaemonId: target
|
|
7682
|
+
};
|
|
7683
|
+
const fingerprint = `${target}::${buildPendingEventFingerprint(fingerprintSource)}`;
|
|
7684
|
+
try {
|
|
7685
|
+
const inserted = store.insertPendingEvent({
|
|
7686
|
+
id: (0, import_crypto9.randomUUID)(),
|
|
7687
|
+
meshId: UNRESOLVED_FORWARD_OUTBOX_MESH_ID,
|
|
7688
|
+
coordinatorDaemonId: target,
|
|
7689
|
+
event,
|
|
7690
|
+
// Store the flat forward payload + the queue timestamp so the retry tick can
|
|
7691
|
+
// rebuild the push args and apply age-based expiry without a schema change.
|
|
7692
|
+
payload: { forwardPayload, coordinatorDaemonId: target, queuedAt },
|
|
7693
|
+
fingerprint,
|
|
7694
|
+
queuedAt
|
|
7695
|
+
});
|
|
7696
|
+
if (inserted) {
|
|
7697
|
+
LOG.info("MeshEvents", `Durably queued unresolved-delegate ${event} for coordinator ${target} (outbox)`);
|
|
7698
|
+
}
|
|
7699
|
+
return true;
|
|
7700
|
+
} catch (e) {
|
|
7701
|
+
LOG.warn("MeshEvents", `Failed to persist unresolved-delegate forward to outbox: ${e?.message || e}`);
|
|
7702
|
+
return false;
|
|
7703
|
+
}
|
|
7704
|
+
}
|
|
7705
|
+
function peekUnresolvedDelegateForwards() {
|
|
7706
|
+
const store = getStore();
|
|
7707
|
+
if (!store) return [];
|
|
7708
|
+
let rows;
|
|
7709
|
+
try {
|
|
7710
|
+
rows = store.peekPendingEvents(UNRESOLVED_FORWARD_OUTBOX_MESH_ID);
|
|
7711
|
+
} catch {
|
|
7712
|
+
return [];
|
|
7713
|
+
}
|
|
7714
|
+
const out = [];
|
|
7715
|
+
for (const row of rows) {
|
|
7716
|
+
const stored = row.payload && typeof row.payload === "object" ? row.payload : {};
|
|
7717
|
+
const coordinatorDaemonId = readNonEmptyString2(stored.coordinatorDaemonId);
|
|
7718
|
+
const forwardPayload = stored.forwardPayload && typeof stored.forwardPayload === "object" ? stored.forwardPayload : void 0;
|
|
7719
|
+
if (!coordinatorDaemonId || !forwardPayload) continue;
|
|
7720
|
+
const queuedAt = typeof stored.queuedAt === "number" ? stored.queuedAt : 0;
|
|
7721
|
+
out.push({ id: row.id, coordinatorDaemonId, payload: forwardPayload, queuedAt });
|
|
7722
|
+
}
|
|
7723
|
+
return out;
|
|
7724
|
+
}
|
|
7725
|
+
function ackUnresolvedDelegateForward(id) {
|
|
7726
|
+
const store = getStore();
|
|
7727
|
+
if (!store) return;
|
|
7728
|
+
try {
|
|
7729
|
+
store.markPendingEventsDrainedById([id]);
|
|
7730
|
+
} catch {
|
|
7731
|
+
}
|
|
7732
|
+
}
|
|
7733
|
+
function expireStaleUnresolvedDelegateForwards(nowMs = Date.now()) {
|
|
7734
|
+
const entries = peekUnresolvedDelegateForwards();
|
|
7735
|
+
const staleIds = entries.filter((e) => e.queuedAt > 0 && nowMs - e.queuedAt >= UNRESOLVED_FORWARD_MAX_AGE_MS).map((e) => e.id);
|
|
7736
|
+
if (staleIds.length === 0) return 0;
|
|
7737
|
+
const store = getStore();
|
|
7738
|
+
if (!store) return 0;
|
|
7739
|
+
try {
|
|
7740
|
+
const removed = store.deletePendingEventsById(staleIds);
|
|
7741
|
+
if (removed > 0) {
|
|
7742
|
+
LOG.warn("MeshEvents", `Expired ${removed} unresolved-delegate forward(s) after ${Math.round(UNRESOLVED_FORWARD_MAX_AGE_MS / 6e4)}m of failed retries \u2014 coordinator unreachable, completion dropped`);
|
|
7743
|
+
}
|
|
7744
|
+
return removed;
|
|
7745
|
+
} catch {
|
|
7746
|
+
return 0;
|
|
7747
|
+
}
|
|
7748
|
+
}
|
|
7749
|
+
var import_crypto9, UNRESOLVED_FORWARD_OUTBOX_MESH_ID, UNRESOLVED_FORWARD_MAX_AGE_MS;
|
|
7750
|
+
var init_mesh_unresolved_forward_outbox = __esm({
|
|
7751
|
+
"src/mesh/mesh-unresolved-forward-outbox.ts"() {
|
|
7752
|
+
"use strict";
|
|
7753
|
+
import_crypto9 = require("crypto");
|
|
7754
|
+
init_logger();
|
|
7755
|
+
init_mesh_runtime_store();
|
|
7756
|
+
init_mesh_events_pending();
|
|
7757
|
+
init_mesh_events_utils();
|
|
7758
|
+
UNRESOLVED_FORWARD_OUTBOX_MESH_ID = "__unresolved_forward_outbox__";
|
|
7759
|
+
UNRESOLVED_FORWARD_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
7760
|
+
}
|
|
7761
|
+
});
|
|
7762
|
+
|
|
7607
7763
|
// src/mesh/mesh-events-coordinator.ts
|
|
7608
7764
|
function resolveCoordinatorDrainDaemonIds(components) {
|
|
7609
7765
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -8738,12 +8894,25 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
|
|
|
8738
8894
|
nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId) || void 0,
|
|
8739
8895
|
workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
|
|
8740
8896
|
};
|
|
8741
|
-
|
|
8742
|
-
|
|
8897
|
+
const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
|
|
8898
|
+
Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
|
|
8899
|
+
if (result && result.success === false) {
|
|
8900
|
+
LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
|
|
8901
|
+
return;
|
|
8902
|
+
}
|
|
8903
|
+
if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
|
|
8904
|
+
}).catch((e) => {
|
|
8905
|
+
LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued for retry`);
|
|
8743
8906
|
});
|
|
8744
|
-
LOG.info("MeshEvents", `
|
|
8907
|
+
LOG.info("MeshEvents", `Durably forwarded ${eventName} for unresolved-mesh worker at ${routing.workspace || "(no workspace)"} to coordinator daemon ${coordinatorDaemonId}`);
|
|
8745
8908
|
return true;
|
|
8746
8909
|
}
|
|
8910
|
+
function ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload) {
|
|
8911
|
+
const match = peekUnresolvedDelegateForwards().find(
|
|
8912
|
+
(entry) => entry.coordinatorDaemonId === coordinatorDaemonId && readNonEmptyString2(entry.payload.event) === eventName && readNonEmptyString2(entry.payload.targetSessionId || entry.payload.sessionId || entry.payload.instanceId) === readNonEmptyString2(payload.targetSessionId || payload.sessionId || payload.instanceId) && readNonEmptyString2(entry.payload.workspace) === readNonEmptyString2(payload.workspace)
|
|
8913
|
+
);
|
|
8914
|
+
if (match) ackUnresolvedDelegateForward(match.id);
|
|
8915
|
+
}
|
|
8747
8916
|
function setupMeshEventForwarding(components) {
|
|
8748
8917
|
components.instanceManager.onEvent((event) => {
|
|
8749
8918
|
if (event.event === "agent:ready" || event.event === "agent:generating_completed") {
|
|
@@ -8825,6 +8994,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
8825
8994
|
init_mesh_runtime_store();
|
|
8826
8995
|
init_mesh_events_pending();
|
|
8827
8996
|
init_mesh_routing();
|
|
8997
|
+
init_mesh_unresolved_forward_outbox();
|
|
8828
8998
|
init_repo_mesh_types();
|
|
8829
8999
|
init_dist();
|
|
8830
9000
|
init_mesh_events_stale();
|
|
@@ -8940,6 +9110,13 @@ async function runMeshReconcileTick(components) {
|
|
|
8940
9110
|
return void 0;
|
|
8941
9111
|
}
|
|
8942
9112
|
})();
|
|
9113
|
+
if (dispatchMeshCommand) {
|
|
9114
|
+
try {
|
|
9115
|
+
await retryUnresolvedDelegateForwards(components);
|
|
9116
|
+
} catch (e) {
|
|
9117
|
+
LOG.warn("MeshReconcile", `Unresolved-delegate forward retry failed: ${e?.message || e}`);
|
|
9118
|
+
}
|
|
9119
|
+
}
|
|
8943
9120
|
if (dispatchMeshCommand) {
|
|
8944
9121
|
for (const mesh of listMeshes()) {
|
|
8945
9122
|
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
@@ -8993,6 +9170,28 @@ async function runMeshReconcileTick(components) {
|
|
|
8993
9170
|
}
|
|
8994
9171
|
}
|
|
8995
9172
|
}
|
|
9173
|
+
async function retryUnresolvedDelegateForwards(components) {
|
|
9174
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
9175
|
+
if (!dispatchMeshCommand) return;
|
|
9176
|
+
expireStaleUnresolvedDelegateForwards();
|
|
9177
|
+
const entries = peekUnresolvedDelegateForwards();
|
|
9178
|
+
if (entries.length === 0) return;
|
|
9179
|
+
for (const entry of entries) {
|
|
9180
|
+
let result;
|
|
9181
|
+
try {
|
|
9182
|
+
result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
|
|
9183
|
+
} catch (e) {
|
|
9184
|
+
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
|
|
9185
|
+
continue;
|
|
9186
|
+
}
|
|
9187
|
+
if (result && result.success === false) {
|
|
9188
|
+
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
|
|
9189
|
+
continue;
|
|
9190
|
+
}
|
|
9191
|
+
ackUnresolvedDelegateForward(entry.id);
|
|
9192
|
+
LOG.info("MeshReconcile", `Retried+delivered unresolved-delegate ${readNonEmptyString2(entry.payload.event)} to coordinator ${entry.coordinatorDaemonId}`);
|
|
9193
|
+
}
|
|
9194
|
+
}
|
|
8996
9195
|
async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDaemonIds) {
|
|
8997
9196
|
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
8998
9197
|
if (!dispatchMeshCommand) return;
|
|
@@ -9069,6 +9268,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
9069
9268
|
init_mesh_events_pending();
|
|
9070
9269
|
init_mesh_runtime_store();
|
|
9071
9270
|
init_mesh_events_coordinator();
|
|
9271
|
+
init_mesh_unresolved_forward_outbox();
|
|
9072
9272
|
init_mesh_events_utils();
|
|
9073
9273
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
9074
9274
|
}
|
|
@@ -22340,7 +22540,7 @@ var ExtensionProviderInstance = class {
|
|
|
22340
22540
|
this.runtimeMessages = [];
|
|
22341
22541
|
}
|
|
22342
22542
|
updateSettings(newSettings) {
|
|
22343
|
-
this.settings = { ...newSettings };
|
|
22543
|
+
this.settings = { ...this.settings, ...newSettings };
|
|
22344
22544
|
this.monitor.updateConfig({
|
|
22345
22545
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
22346
22546
|
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
@@ -23007,7 +23207,7 @@ var IdeProviderInstance = class {
|
|
|
23007
23207
|
this.extensions.clear();
|
|
23008
23208
|
}
|
|
23009
23209
|
updateSettings(newSettings) {
|
|
23010
|
-
this.settings = { ...newSettings };
|
|
23210
|
+
this.settings = { ...this.settings, ...newSettings };
|
|
23011
23211
|
this.monitor.updateConfig({
|
|
23012
23212
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
23013
23213
|
longGeneratingAlert: this.settings.longGeneratingAlert !== false,
|
|
@@ -32555,22 +32755,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
32555
32755
|
};
|
|
32556
32756
|
}
|
|
32557
32757
|
updateSettings(newSettings) {
|
|
32558
|
-
|
|
32559
|
-
for (const key of [
|
|
32560
|
-
"meshNodeFor",
|
|
32561
|
-
"meshNodeId",
|
|
32562
|
-
"meshActiveTaskId",
|
|
32563
|
-
"meshCoordinatorFor",
|
|
32564
|
-
"meshCoordinatorDaemonId",
|
|
32565
|
-
"meshCoordinatorNodeId",
|
|
32566
|
-
"spawnedSessionVisibility",
|
|
32567
|
-
"launchedByCoordinator"
|
|
32568
|
-
]) {
|
|
32569
|
-
if (this.settings[key] !== void 0 && newSettings[key] === void 0) {
|
|
32570
|
-
runtimeMeshSettings[key] = this.settings[key];
|
|
32571
|
-
}
|
|
32572
|
-
}
|
|
32573
|
-
this.settings = { ...newSettings, ...runtimeMeshSettings };
|
|
32758
|
+
this.settings = { ...this.settings, ...newSettings };
|
|
32574
32759
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
32575
32760
|
this.monitor.updateConfig({
|
|
32576
32761
|
approvalAlert: this.settings.approvalAlert !== false,
|
|
@@ -46628,9 +46813,9 @@ ${hintLines.join("\n")}` : "",
|
|
|
46628
46813
|
});
|
|
46629
46814
|
let node;
|
|
46630
46815
|
if (meshRecord.inline) {
|
|
46631
|
-
const { randomUUID:
|
|
46816
|
+
const { randomUUID: randomUUID15 } = await import("crypto");
|
|
46632
46817
|
node = {
|
|
46633
|
-
id: `node_${
|
|
46818
|
+
id: `node_${randomUUID15().replace(/-/g, "")}`,
|
|
46634
46819
|
workspace: result.worktreePath,
|
|
46635
46820
|
repoRoot: result.worktreePath,
|
|
46636
46821
|
daemonId: sourceNode.daemonId,
|
|
@@ -47404,10 +47589,11 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47404
47589
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
47405
47590
|
const meshHost = resolveMeshHostStatus(mesh);
|
|
47406
47591
|
const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
|
|
47592
|
+
const verboseMissions = args?.verbose === true || args?.compact === false;
|
|
47407
47593
|
const peekScope = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : this.deps.statusInstanceId || void 0;
|
|
47408
47594
|
const pendingCoordinatorEventCount = getPendingMeshCoordinatorEvents(meshId, peekScope).length;
|
|
47409
47595
|
const hadAggregateCache = this.aggregateMeshStatusCache.has(meshId);
|
|
47410
|
-
if (!refreshRequested && pendingCoordinatorEventCount === 0) {
|
|
47596
|
+
if (!refreshRequested && !verboseMissions && pendingCoordinatorEventCount === 0) {
|
|
47411
47597
|
const cachedStatus = this.getCachedAggregateMeshStatus(meshId, mesh, { requireDirectPeerTruth: args?.requireDirectPeerTruth === true });
|
|
47412
47598
|
if (cachedStatus) {
|
|
47413
47599
|
logRepoMeshStatusDebug("return_cached", {
|
|
@@ -47710,7 +47896,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47710
47896
|
liveSessionRecords: liveMeshSessions
|
|
47711
47897
|
});
|
|
47712
47898
|
const { getMeshStatusMissionSummaries: getMeshStatusMissionSummaries2 } = await Promise.resolve().then(() => (init_mesh_missions(), mesh_missions_exports));
|
|
47713
|
-
const missions = getMeshStatusMissionSummaries2(meshId);
|
|
47899
|
+
const missions = getMeshStatusMissionSummaries2(meshId, { verbose: verboseMissions });
|
|
47714
47900
|
const statusResult = {
|
|
47715
47901
|
success: true,
|
|
47716
47902
|
meshId: mesh.id,
|
|
@@ -47764,7 +47950,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47764
47950
|
}))
|
|
47765
47951
|
};
|
|
47766
47952
|
const { pendingCoordinatorEvents: _pendingCoordinatorEvents, unroutableDeliveries: _unroutableDeliveries, ...cacheableStatusResult } = statusResult;
|
|
47767
|
-
const rememberedStatus = this.rememberAggregateMeshStatus(meshId, cacheableStatusResult, refreshReason);
|
|
47953
|
+
const rememberedStatus = verboseMissions ? cacheableStatusResult : this.rememberAggregateMeshStatus(meshId, cacheableStatusResult, refreshReason);
|
|
47768
47954
|
const returnedStatus = {
|
|
47769
47955
|
...rememberedStatus,
|
|
47770
47956
|
...pendingCoordinatorEvents.length > 0 ? { pendingCoordinatorEvents } : {},
|
|
@@ -55318,7 +55504,7 @@ var SessionHostPtyTransportFactory = class {
|
|
|
55318
55504
|
};
|
|
55319
55505
|
|
|
55320
55506
|
// src/cli-adapters/raw-terminal-io.ts
|
|
55321
|
-
var
|
|
55507
|
+
var import_crypto10 = require("crypto");
|
|
55322
55508
|
var import_session_host_core10 = require("@adhdev/session-host-core");
|
|
55323
55509
|
var BASE_KEY_SEQUENCES = {
|
|
55324
55510
|
enter: "\r",
|
|
@@ -55416,7 +55602,7 @@ var RawTerminalAttachment = class _RawTerminalAttachment {
|
|
|
55416
55602
|
const sessionId = String(options.sessionId || "").trim();
|
|
55417
55603
|
if (!sessionId) throw new Error("sessionId is required");
|
|
55418
55604
|
const mode = options.mode || "read";
|
|
55419
|
-
const clientId = options.clientId || `raw-terminal-${process.pid}-${(0,
|
|
55605
|
+
const clientId = options.clientId || `raw-terminal-${process.pid}-${(0, import_crypto10.randomUUID)().slice(0, 8)}`;
|
|
55420
55606
|
const client = options.client || new import_session_host_core10.SessionHostClient({ endpoint: options.endpoint });
|
|
55421
55607
|
await client.connect();
|
|
55422
55608
|
const attachResponse = await client.request({
|