@adhdev/daemon-core 0.9.82-rc.481 → 0.9.82-rc.483
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/config/mesh-config.d.ts +10 -28
- package/dist/index.d.ts +2 -2
- package/dist/index.js +337 -249
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +337 -244
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/contracts.d.ts +35 -9
- package/dist/mesh/mesh-reconcile-loop.d.ts +4 -0
- package/dist/mesh/mesh-runtime-store.d.ts +47 -2
- package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +4 -0
- package/dist/repo-mesh-types.d.ts +8 -14
- package/dist/types.d.ts +15 -6
- package/package.json +3 -3
- package/src/commands/chat-commands-read.ts +81 -60
- package/src/commands/low-family/coordinator-prompt.ts +53 -0
- package/src/commands/med-family/mesh-crud.ts +19 -62
- package/src/config/mesh-config.ts +21 -140
- package/src/index.ts +1 -2
- package/src/mesh/contracts.ts +59 -18
- package/src/mesh/coordinator-prompt.ts +22 -6
- package/src/mesh/mesh-event-forwarding.ts +38 -102
- package/src/mesh/mesh-events-pending.ts +20 -0
- package/src/mesh/mesh-reconcile-loop.ts +157 -2
- package/src/mesh/mesh-runtime-store.ts +118 -3
- package/src/mesh/mesh-unresolved-forward-outbox.ts +30 -0
- package/src/repo-mesh-types.ts +8 -14
- package/src/types.ts +21 -6
package/dist/index.mjs
CHANGED
|
@@ -183,7 +183,7 @@ var init_repo_mesh_types = __esm({
|
|
|
183
183
|
"checkpoint_then_continue"
|
|
184
184
|
]);
|
|
185
185
|
MESH_MAX_PARALLEL_TASKS_MIN = 1;
|
|
186
|
-
MESH_MAX_PARALLEL_TASKS_MAX =
|
|
186
|
+
MESH_MAX_PARALLEL_TASKS_MAX = 64;
|
|
187
187
|
DEFAULT_MESH_READONLY_MULTIPLIER = 2;
|
|
188
188
|
}
|
|
189
189
|
});
|
|
@@ -404,10 +404,10 @@ function readInjected(value) {
|
|
|
404
404
|
}
|
|
405
405
|
function getDaemonBuildInfo() {
|
|
406
406
|
if (cached) return cached;
|
|
407
|
-
const commit = readInjected(true ? "
|
|
408
|
-
const commitShort = readInjected(true ? "
|
|
409
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
410
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
407
|
+
const commit = readInjected(true ? "0862a3f10fa9de60a46591c0894a7209534db2e2" : void 0) ?? "unknown";
|
|
408
|
+
const commitShort = readInjected(true ? "0862a3f1" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
409
|
+
const version = readInjected(true ? "0.9.82-rc.483" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
410
|
+
const builtAt = readInjected(true ? "2026-07-08T04:27:00.139Z" : void 0);
|
|
411
411
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
412
412
|
return cached;
|
|
413
413
|
}
|
|
@@ -2813,8 +2813,6 @@ var init_dist = __esm({
|
|
|
2813
2813
|
"mesh_review_inbox",
|
|
2814
2814
|
"mesh_magi_review",
|
|
2815
2815
|
"mesh_magi_collect",
|
|
2816
|
-
"mesh_magi_panel_set",
|
|
2817
|
-
"mesh_magi_panel_list",
|
|
2818
2816
|
"mesh_magi_kind_panel_set",
|
|
2819
2817
|
"mesh_magi_kind_panel_list"
|
|
2820
2818
|
];
|
|
@@ -2914,24 +2912,19 @@ __export(mesh_config_exports, {
|
|
|
2914
2912
|
createMeshHostPairingToken: () => createMeshHostPairingToken,
|
|
2915
2913
|
deleteMesh: () => deleteMesh,
|
|
2916
2914
|
getMagiKindPanel: () => getMagiKindPanel,
|
|
2917
|
-
getMagiPanel: () => getMagiPanel,
|
|
2918
2915
|
getMesh: () => getMesh,
|
|
2919
2916
|
getMeshByRepo: () => getMeshByRepo,
|
|
2920
2917
|
listMagiKindPanels: () => listMagiKindPanels,
|
|
2921
|
-
listMagiPanels: () => listMagiPanels,
|
|
2922
2918
|
listMeshes: () => listMeshes,
|
|
2923
2919
|
markMeshHostPairingJoined: () => markMeshHostPairingJoined,
|
|
2924
|
-
normalizeMagiPanel: () => normalizeMagiPanel,
|
|
2925
2920
|
normalizeMagiSlots: () => normalizeMagiSlots,
|
|
2926
2921
|
normalizeRepoIdentity: () => normalizeRepoIdentity,
|
|
2927
2922
|
removeMagiKindPanel: () => removeMagiKindPanel,
|
|
2928
|
-
removeMagiPanel: () => removeMagiPanel,
|
|
2929
2923
|
removeNode: () => removeNode,
|
|
2930
2924
|
setMagiKindPanel: () => setMagiKindPanel,
|
|
2931
2925
|
tokenIdForManualPairing: () => tokenIdForManualPairing,
|
|
2932
2926
|
updateMesh: () => updateMesh,
|
|
2933
|
-
updateNode: () => updateNode
|
|
2934
|
-
upsertMagiPanel: () => upsertMagiPanel
|
|
2927
|
+
updateNode: () => updateNode
|
|
2935
2928
|
});
|
|
2936
2929
|
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
2937
2930
|
import { join as join5 } from "path";
|
|
@@ -3313,6 +3306,11 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
3313
3306
|
node.reportedDaemonBuildVersion = opts.reportedDaemonBuildVersion.trim();
|
|
3314
3307
|
}
|
|
3315
3308
|
if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
|
|
3309
|
+
if (Object.prototype.hasOwnProperty.call(opts, "capabilities")) {
|
|
3310
|
+
const tags = normalizeCapabilityTags(opts.capabilities);
|
|
3311
|
+
if (tags && tags.length) node.capabilities = tags;
|
|
3312
|
+
else delete node.capabilities;
|
|
3313
|
+
}
|
|
3316
3314
|
if (opts.worktreeBootstrap) node.worktreeBootstrap = opts.worktreeBootstrap;
|
|
3317
3315
|
if (Object.prototype.hasOwnProperty.call(opts, "systemPrompt")) {
|
|
3318
3316
|
if (opts.systemPrompt && opts.systemPrompt.trim()) {
|
|
@@ -3330,99 +3328,6 @@ function normalizeReplicaCount(value) {
|
|
|
3330
3328
|
const n = Math.floor(value);
|
|
3331
3329
|
return n >= 1 ? n : void 0;
|
|
3332
3330
|
}
|
|
3333
|
-
function normalizeMagiPanelDefaultKind(raw) {
|
|
3334
|
-
if (raw == null) return void 0;
|
|
3335
|
-
const s2 = typeof raw === "string" ? raw.trim().toLowerCase() : "";
|
|
3336
|
-
if (s2 === "claim_audit" || s2 === "rca" || s2 === "design") return s2;
|
|
3337
|
-
if (s2 === "freeform") {
|
|
3338
|
-
console.warn(
|
|
3339
|
-
"[magi] panel defaultKind='freeform' rejected \u2014 freeform contributes no structured claims to cross-verification; dropping (use claim_audit / rca / design, or omit)."
|
|
3340
|
-
);
|
|
3341
|
-
return void 0;
|
|
3342
|
-
}
|
|
3343
|
-
return void 0;
|
|
3344
|
-
}
|
|
3345
|
-
function normalizeMagiPanel(config) {
|
|
3346
|
-
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
3347
|
-
throw new Error("invalid_magi_panel: config must be an object");
|
|
3348
|
-
}
|
|
3349
|
-
const raw = config;
|
|
3350
|
-
const rawMembers = raw.members;
|
|
3351
|
-
if (!Array.isArray(rawMembers) || rawMembers.length === 0) {
|
|
3352
|
-
throw new Error("invalid_magi_panel: members must be a non-empty array");
|
|
3353
|
-
}
|
|
3354
|
-
if (rawMembers.length > MAX_MAGI_PANEL_MEMBERS) {
|
|
3355
|
-
throw new Error(`invalid_magi_panel: too many members (max ${MAX_MAGI_PANEL_MEMBERS})`);
|
|
3356
|
-
}
|
|
3357
|
-
const members = rawMembers.map((entry, idx) => {
|
|
3358
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
3359
|
-
throw new Error(`invalid_magi_panel: member[${idx}] must be an object`);
|
|
3360
|
-
}
|
|
3361
|
-
const m = entry;
|
|
3362
|
-
const provider = typeof m.provider === "string" ? m.provider.trim() : "";
|
|
3363
|
-
if (!provider) {
|
|
3364
|
-
throw new Error(`invalid_magi_panel: member[${idx}].provider is required`);
|
|
3365
|
-
}
|
|
3366
|
-
const nodeId = typeof m.nodeId === "string" && m.nodeId.trim() ? m.nodeId.trim() : void 0;
|
|
3367
|
-
const model = typeof m.model === "string" && m.model.trim() ? m.model.trim() : void 0;
|
|
3368
|
-
const capabilityTags = normalizeCapabilityTags(m.capabilityTags);
|
|
3369
|
-
const n = normalizeReplicaCount(m.n);
|
|
3370
|
-
return {
|
|
3371
|
-
provider,
|
|
3372
|
-
...nodeId ? { nodeId } : {},
|
|
3373
|
-
...model ? { model } : {},
|
|
3374
|
-
...capabilityTags ? { capabilityTags } : {},
|
|
3375
|
-
...n !== void 0 ? { n } : {}
|
|
3376
|
-
};
|
|
3377
|
-
});
|
|
3378
|
-
const description = typeof raw.description === "string" && raw.description.trim() ? raw.description.trim().slice(0, 200) : void 0;
|
|
3379
|
-
const defaultN = normalizeReplicaCount(raw.defaultN);
|
|
3380
|
-
const defaultKind = normalizeMagiPanelDefaultKind(raw.defaultKind);
|
|
3381
|
-
return {
|
|
3382
|
-
...description ? { description } : {},
|
|
3383
|
-
members,
|
|
3384
|
-
...defaultN !== void 0 ? { defaultN } : {},
|
|
3385
|
-
...defaultKind !== void 0 ? { defaultKind } : {},
|
|
3386
|
-
// dedupExempt is always meaningful for a MAGI panel (intentional same-prompt
|
|
3387
|
-
// fan-out). Persist it true unless the caller explicitly disables it.
|
|
3388
|
-
dedupExempt: raw.dedupExempt === false ? false : true
|
|
3389
|
-
};
|
|
3390
|
-
}
|
|
3391
|
-
function normalizePanelName(name) {
|
|
3392
|
-
const trimmed = typeof name === "string" ? name.trim() : "";
|
|
3393
|
-
if (!trimmed) throw new Error("invalid_magi_panel: panel name is required");
|
|
3394
|
-
return trimmed.slice(0, 100);
|
|
3395
|
-
}
|
|
3396
|
-
function listMagiPanels() {
|
|
3397
|
-
return loadMeshConfig().magiPanels ?? {};
|
|
3398
|
-
}
|
|
3399
|
-
function getMagiPanel(name) {
|
|
3400
|
-
const key2 = typeof name === "string" ? name.trim() : "";
|
|
3401
|
-
if (!key2) return void 0;
|
|
3402
|
-
return loadMeshConfig().magiPanels?.[key2];
|
|
3403
|
-
}
|
|
3404
|
-
function upsertMagiPanel(name, config, opts = {}) {
|
|
3405
|
-
const key2 = normalizePanelName(name);
|
|
3406
|
-
const panel = normalizeMagiPanel(config);
|
|
3407
|
-
const stored = loadMeshConfig();
|
|
3408
|
-
const panels = stored.magiPanels ?? {};
|
|
3409
|
-
if (panels[key2] && opts.overwrite !== true) {
|
|
3410
|
-
throw new Error(`magi_panel_exists: panel '${key2}' already exists \u2014 pass overwrite=true to replace it`);
|
|
3411
|
-
}
|
|
3412
|
-
panels[key2] = panel;
|
|
3413
|
-
stored.magiPanels = panels;
|
|
3414
|
-
saveMeshConfig(stored);
|
|
3415
|
-
return panel;
|
|
3416
|
-
}
|
|
3417
|
-
function removeMagiPanel(name) {
|
|
3418
|
-
const key2 = typeof name === "string" ? name.trim() : "";
|
|
3419
|
-
if (!key2) return false;
|
|
3420
|
-
const stored = loadMeshConfig();
|
|
3421
|
-
if (!stored.magiPanels || !stored.magiPanels[key2]) return false;
|
|
3422
|
-
delete stored.magiPanels[key2];
|
|
3423
|
-
saveMeshConfig(stored);
|
|
3424
|
-
return true;
|
|
3425
|
-
}
|
|
3426
3331
|
function normalizeMagiTaskKindKey(raw) {
|
|
3427
3332
|
const s2 = typeof raw === "string" ? raw.trim().toLowerCase() : "";
|
|
3428
3333
|
if (!MAGI_KIND_PANEL_KINDS.includes(s2)) {
|
|
@@ -3494,7 +3399,7 @@ function removeMagiKindPanel(kind) {
|
|
|
3494
3399
|
saveMeshConfig(stored);
|
|
3495
3400
|
return true;
|
|
3496
3401
|
}
|
|
3497
|
-
var mergeMeshPolicy,
|
|
3402
|
+
var mergeMeshPolicy, MAGI_KIND_PANEL_KINDS, MAX_MAGI_KIND_SLOTS;
|
|
3498
3403
|
var init_mesh_config = __esm({
|
|
3499
3404
|
"src/config/mesh-config.ts"() {
|
|
3500
3405
|
"use strict";
|
|
@@ -3503,7 +3408,6 @@ var init_mesh_config = __esm({
|
|
|
3503
3408
|
init_repo_mesh_types();
|
|
3504
3409
|
init_mesh_host_ownership();
|
|
3505
3410
|
mergeMeshPolicy = mergeAndNormalizePolicy;
|
|
3506
|
-
MAX_MAGI_PANEL_MEMBERS = 24;
|
|
3507
3411
|
MAGI_KIND_PANEL_KINDS = ["claim_audit", "rca", "design", "freeform"];
|
|
3508
3412
|
MAX_MAGI_KIND_SLOTS = 24;
|
|
3509
3413
|
}
|
|
@@ -3699,6 +3603,21 @@ function buildNodeConfigSection(mesh) {
|
|
|
3699
3603
|
}).filter(Boolean) : [];
|
|
3700
3604
|
const providerRolesSuffix = providerRoles.length ? ` | caps: ${providerRoles.join(", ")}` : "";
|
|
3701
3605
|
lines.push(`- ${explicitLabel} nodeId: \`${n.id}\` | workspace: \`${n.workspace}\`${n.daemonId ? ` | daemon: \`${n.daemonId}\`` : ""}${providerPriority}${providerRolesSuffix}${suffix}`);
|
|
3606
|
+
const routingTags = [];
|
|
3607
|
+
const custom = Array.isArray(n.capabilities) ? n.capabilities : [];
|
|
3608
|
+
for (const t of custom) {
|
|
3609
|
+
const s2 = typeof t === "string" ? t.trim() : "";
|
|
3610
|
+
if (s2) routingTags.push(s2);
|
|
3611
|
+
}
|
|
3612
|
+
const tagOs = (n.userOverrides?.platform || n.reportedPlatform || "").toString().trim();
|
|
3613
|
+
const tagArch = (n.userOverrides?.arch || n.reportedArch || "").toString().trim();
|
|
3614
|
+
if (tagOs) routingTags.push(`os=${tagOs}`);
|
|
3615
|
+
if (tagArch) routingTags.push(`arch=${tagArch}`);
|
|
3616
|
+
const wtBranch = typeof n.worktreeBranch === "string" ? n.worktreeBranch.trim() : "";
|
|
3617
|
+
if (n.isLocalWorktree && wtBranch) routingTags.push(`worktree=${wtBranch}`);
|
|
3618
|
+
if (routingTags.length) {
|
|
3619
|
+
lines.push(` \u{1F3F7}\uFE0F routing tags: ${routingTags.map((t) => `\`${t}\``).join(", ")}`);
|
|
3620
|
+
}
|
|
3702
3621
|
const nodePrompt = typeof n.systemPrompt === "string" ? n.systemPrompt.trim() : "";
|
|
3703
3622
|
if (nodePrompt) {
|
|
3704
3623
|
lines.push(` \u{1F4CC} Node instruction: ${indentFollowing(nodePrompt, " ")}`);
|
|
@@ -3800,6 +3719,7 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
3800
3719
|
- **Route, don't implement.** Delegate all code reading, analysis, and execution to node agents. Never read source files or run commands in the coordinator \u2014 keep context lean.
|
|
3801
3720
|
- **Front-load task messages.** Include everything the agent needs (files, problem, expected fix) in \`mesh_enqueue_task\` / \`mesh_send_task\`. Append a structured result request at the end: ask the worker to conclude with a JSON block containing \`status\`, \`changedFiles\`, \`gitStatus\`, \`validationResults\`, \`errors\`, \`nextAction\`. The daemon parses this automatically; you can read it from \`mesh_task_history\`.
|
|
3802
3721
|
- **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.
|
|
3722
|
+
- **Worktree affinity.** A worktree is a durable per-branch workspace; keep all of a branch's code_change/fix/review work on its worktree node by targeting \`required_tags: ["worktree=<branch>"]\` or \`target_node_id\`. Get the id/branch from the \`mesh_clone_node\` result or a live \`mesh_status\` \u2014 the Configured Nodes snapshot won't list a worktree cloned after launch. Untargeted same-branch follow-ups drift to the base node. Only \`convergence\` (merge/push) runs on the base, never pinned to the worktree.
|
|
3803
3723
|
- **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.
|
|
3804
3724
|
- **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
|
|
3805
3725
|
- **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).
|
|
@@ -3874,9 +3794,7 @@ var init_coordinator_prompt = __esm({
|
|
|
3874
3794
|
| \`mesh_write_mesh_json_config\` | Gated write of \`.adhdev/mesh.json\` (repo coordinator-prompt config) from the mesh entry \u2014 dry-run/overwrite like mesh_init |
|
|
3875
3795
|
| \`mesh_magi_review\` | Cross-verify a read-only investigation across a standing panel of independent mesh agents (different machines/providers) instead of a single worker |
|
|
3876
3796
|
| \`mesh_magi_collect\` | Collect + synthesize a previously dispatched MAGI fan-out by its consensus group id (async companion to mesh_magi_review wait:false) |
|
|
3877
|
-
| \`
|
|
3878
|
-
| \`mesh_magi_panel_list\` | List configured MAGI panels and resolve each member's availability against the current mesh (read-only) |
|
|
3879
|
-
| \`mesh_magi_kind_panel_set\` | Bind a task_kind \u2192 MAGI kind-panel slots (machine-local, wholesale replacement \u2014 approve current-vs-new first) |
|
|
3797
|
+
| \`mesh_magi_kind_panel_set\` | Bind a task_kind \u2192 MAGI kind-panel slots (the SOLE MAGI panel-resolution surface; machine-local, wholesale replacement \u2014 approve current-vs-new first) |
|
|
3880
3798
|
| \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only) |`;
|
|
3881
3799
|
TOOL_EXPOSURE_PREFLIGHT_SECTION = `## Tool Exposure Preflight
|
|
3882
3800
|
|
|
@@ -3888,6 +3806,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
3888
3806
|
3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
|
|
3889
3807
|
a. **General Tasks**: Enqueue tasks using \`mesh_enqueue_task\`. Idle node agents will automatically pull tasks from the queue and begin working.
|
|
3890
3808
|
b. **Node Preparation**: Reuse an existing idle session on the correct node/provider before launching a new chat/session. Call \`mesh_launch_session\` only when no suitable session exists, when the user explicitly asks for a fresh provider/session, or when branch/worktree isolation requires it. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
3809
|
+
b1. **Keep a branch's work on its worktree (worktree affinity).** A worktree node is a durable per-branch workspace, not a one-task throwaway \u2014 implement, review, and fix for the same branch all belong on the SAME worktree, and it lives until its work is converged (merged/pushed) and it is cleaned up. So once you clone a worktree for a branch, route every subsequent \`code_change\`/\`validation\`/fix task for that branch back to that same node: pass \`required_tags: ["worktree=<branch>"]\` or \`target_node_id: <that worktree node's id>\`. **Where to get the node id / tag:** the \`mesh_clone_node\` result returns the new node's \`id\` and \`worktreeBranch\` directly \u2014 use them immediately. The Configured Nodes list in this prompt is a launch-time snapshot and will NOT list a worktree you cloned after this session started, so do not rely on it for freshly-cloned worktrees; take the id/branch from the \`mesh_clone_node\` result, or call \`mesh_status\` to re-list the live nodes (each worktree there advertises its \`worktree=<branch>\` tag). Do NOT leave same-branch follow-ups untargeted \u2014 an untargeted task is claimed by whichever node polls first (usually the base machine node), which strands the work off the branch's worktree. The ONE exception is a \`convergence\` task (merge/push): that is base-only and must NOT be pinned to the worktree.
|
|
3891
3810
|
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.
|
|
3892
3811
|
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.
|
|
3893
3812
|
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.
|
|
@@ -3916,7 +3835,7 @@ When the user asks to **set up / configure / onboard** this repo for Repo Mesh (
|
|
|
3916
3835
|
|
|
3917
3836
|
**Save scopes \u2014 label every draft with its scope before asking for approval:**
|
|
3918
3837
|
- **repo-file (commit target)** \u2014 \`.adhdev/refine.json\`, \`.adhdev/worktree_bootstrap.json\`, \`.adhdev/change-impact.json\`, \`.adhdev/mesh.json\`. These are committed to the repository and shared with every machine/contributor.
|
|
3919
|
-
- **machine-local** \u2014 MAGI kind\u2192panel bindings
|
|
3838
|
+
- **machine-local** \u2014 MAGI kind\u2192panel bindings, node providerPriority (\`~/.adhdev/meshes.json\`). These stay on this machine and are NOT committed.
|
|
3920
3839
|
|
|
3921
3840
|
**Guided sequence:**
|
|
3922
3841
|
1. **Scan (dry-run)** \u2014 Call \`mesh_init\` (write=false, the default). It returns per-domain suggested configs for refine / worktree_bootstrap / change-impact, a recommended providerPriority, AND \`currentConfig\` \u2014 the currently-saved config per domain (repo files + machine-local \`magiKindPanels\`). Nothing is written.
|
|
@@ -3924,8 +3843,7 @@ When the user asks to **set up / configure / onboard** this repo for Repo Mesh (
|
|
|
3924
3843
|
3. **Approve \u2192 gated write** \u2014 Only after the user approves, call the matching gated-write tool:
|
|
3925
3844
|
- repo \`.adhdev/*\` config files \u2192 \`mesh_init\` with \`write=true\` (and \`overwrite=true\` ONLY for domains the user approved replacing).
|
|
3926
3845
|
- \`.adhdev/mesh.json\` (coordinator prompt / operating notes) \u2192 \`mesh_write_mesh_json_config\` (write=true, overwrite only if approved).
|
|
3927
|
-
- machine-local MAGI kind\u2192panel slots \u2192 \`mesh_magi_kind_panel_set\` (write=true). NOTE: a kind binding is a **wholesale replacement** of that kind's slot list \u2014 present the current-vs-new slots first.
|
|
3928
|
-
- machine-local named MAGI panels \u2192 \`mesh_magi_panel_set\`. providerPriority \u2192 apply via node policy update.
|
|
3846
|
+
- machine-local MAGI kind\u2192panel slots \u2192 \`mesh_magi_kind_panel_set\` (write=true). NOTE: a kind binding is a **wholesale replacement** of that kind's slot list \u2014 present the current-vs-new slots first. providerPriority \u2192 apply via node policy update.
|
|
3929
3847
|
|
|
3930
3848
|
**init vs reinit:**
|
|
3931
3849
|
- **\`mesh_init\`** \u2014 for a fresh, never-onboarded repo. Existing config files are kept (existing-wins) unless the user explicitly approves overwrite. Use for first-time setup.
|
|
@@ -4338,9 +4256,11 @@ function shouldDeliverPendingEventToCoordinator(event, drainer) {
|
|
|
4338
4256
|
if (!event.intendedFor) return false;
|
|
4339
4257
|
return coordinatorIdentityEquals(event.intendedFor, drainer);
|
|
4340
4258
|
}
|
|
4259
|
+
function isTerminalTaskEvent(eventName) {
|
|
4260
|
+
return TERMINAL_TASK_EVENTS.has(eventName);
|
|
4261
|
+
}
|
|
4341
4262
|
function defaultScopeForEvent(eventName) {
|
|
4342
|
-
if (
|
|
4343
|
-
if (TERMINAL_TASK_EVENTS.has(eventName)) return "unicast";
|
|
4263
|
+
if (TERMINAL_TASK_EVENTS.has(eventName) || COORDINATOR_ALERT_EVENTS.has(eventName)) return "unicast";
|
|
4344
4264
|
return "broadcast";
|
|
4345
4265
|
}
|
|
4346
4266
|
function coordinatorIdentityFromEmitFields(fields) {
|
|
@@ -4355,7 +4275,11 @@ function buildPendingEventEmitStamp(opts) {
|
|
|
4355
4275
|
let scope = opts.scope ?? defaultScopeForEvent(opts.eventName);
|
|
4356
4276
|
let intendedFor = opts.intendedFor;
|
|
4357
4277
|
if (scope === "unicast" && !intendedFor) {
|
|
4358
|
-
|
|
4278
|
+
if (isTerminalTaskEvent(opts.eventName)) {
|
|
4279
|
+
intendedFor = opts.dispatchedBy;
|
|
4280
|
+
} else {
|
|
4281
|
+
scope = "broadcast";
|
|
4282
|
+
}
|
|
4359
4283
|
}
|
|
4360
4284
|
if (scope !== "unicast") intendedFor = void 0;
|
|
4361
4285
|
return {
|
|
@@ -4366,7 +4290,7 @@ function buildPendingEventEmitStamp(opts) {
|
|
|
4366
4290
|
...intendedFor ? { intendedFor } : {}
|
|
4367
4291
|
};
|
|
4368
4292
|
}
|
|
4369
|
-
var MESH_PROTOCOL_VERSION_V1, MESH_PROTOCOL_VERSION_V2, SUPPORTED_MESH_PROTOCOL_VERSIONS, MESH_EVENT_SCOPES, MeshContractViolationError, TERMINAL_TASK_EVENTS,
|
|
4293
|
+
var MESH_PROTOCOL_VERSION_V1, MESH_PROTOCOL_VERSION_V2, SUPPORTED_MESH_PROTOCOL_VERSIONS, MESH_EVENT_SCOPES, MeshContractViolationError, TERMINAL_TASK_EVENTS, COORDINATOR_ALERT_EVENTS;
|
|
4370
4294
|
var init_contracts = __esm({
|
|
4371
4295
|
"src/mesh/contracts.ts"() {
|
|
4372
4296
|
"use strict";
|
|
@@ -4395,7 +4319,7 @@ var init_contracts = __esm({
|
|
|
4395
4319
|
"refine:failed",
|
|
4396
4320
|
"refine:accepted"
|
|
4397
4321
|
]);
|
|
4398
|
-
|
|
4322
|
+
COORDINATOR_ALERT_EVENTS = /* @__PURE__ */ new Set([
|
|
4399
4323
|
"mesh:dispatch_blocked"
|
|
4400
4324
|
]);
|
|
4401
4325
|
}
|
|
@@ -6349,7 +6273,22 @@ function meshRuntimeStorePath() {
|
|
|
6349
6273
|
}
|
|
6350
6274
|
return nextPath;
|
|
6351
6275
|
}
|
|
6352
|
-
|
|
6276
|
+
function pruneMeshRuntimeRetention() {
|
|
6277
|
+
try {
|
|
6278
|
+
const store = MeshRuntimeStore.getInstance();
|
|
6279
|
+
const ledger = store.pruneEventLedger(MESH_EVENT_LEDGER_RETENTION_MS);
|
|
6280
|
+
const toolCalls = store.pruneToolCallLog(MESH_TOOL_CALL_LOG_RETENTION_MS);
|
|
6281
|
+
const terminalQueue = store.pruneTerminalQueueEntries(MESH_TERMINAL_QUEUE_RETENTION_MS);
|
|
6282
|
+
if (ledger + toolCalls + terminalQueue > 0) {
|
|
6283
|
+
LOG.info("MeshRuntimeStore", `Retention prune removed ${ledger} ledger / ${toolCalls} tool-call / ${terminalQueue} terminal-queue row(s)`);
|
|
6284
|
+
}
|
|
6285
|
+
return { ledger, toolCalls, terminalQueue };
|
|
6286
|
+
} catch (e) {
|
|
6287
|
+
LOG.warn("MeshRuntimeStore", `Runtime retention prune failed: ${e?.message || e}`);
|
|
6288
|
+
return { ledger: 0, toolCalls: 0, terminalQueue: 0 };
|
|
6289
|
+
}
|
|
6290
|
+
}
|
|
6291
|
+
var DatabaseCtor, loggedMigrationFailure, loggedStrayCleanup, MeshRuntimeStore, MESH_EVENT_LEDGER_RETENTION_MS, MESH_TOOL_CALL_LOG_RETENTION_MS, MESH_TERMINAL_QUEUE_RETENTION_MS;
|
|
6353
6292
|
var init_mesh_runtime_store = __esm({
|
|
6354
6293
|
"src/mesh/mesh-runtime-store.ts"() {
|
|
6355
6294
|
"use strict";
|
|
@@ -7459,10 +7398,79 @@ var init_mesh_runtime_store = __esm({
|
|
|
7459
7398
|
}
|
|
7460
7399
|
/**
|
|
7461
7400
|
* Prune tool call log entries older than the given age in ms.
|
|
7462
|
-
*
|
|
7401
|
+
* Returns the number of rows deleted. Also used by the periodic retention
|
|
7402
|
+
* sweep (pruneMeshRuntimeRetention) — the in-write sweep in recordMeshToolCall
|
|
7403
|
+
* only fires every 200 calls and only covers the rate-limit window, so a
|
|
7404
|
+
* quiet mesh otherwise accumulates rows indefinitely.
|
|
7463
7405
|
*/
|
|
7464
7406
|
pruneToolCallLog(olderThanMs) {
|
|
7465
|
-
this.db.prepare("DELETE FROM mesh_tool_call_log WHERE called_at < ?").run(Date.now() - olderThanMs);
|
|
7407
|
+
return this.db.prepare("DELETE FROM mesh_tool_call_log WHERE called_at < ?").run(Date.now() - olderThanMs).changes;
|
|
7408
|
+
}
|
|
7409
|
+
/**
|
|
7410
|
+
* Retention prune for mesh_event_ledger (SoT 1-11 (b)). The ledger is append-only
|
|
7411
|
+
* with NO lifecycle GC of its own, so lifecycle events accumulate without bound
|
|
7412
|
+
* (the dominant mesh-runtime.db growth). Every production reader is bounded to a
|
|
7413
|
+
* recent window (readLedgerEntries tail/limit ≤ a few hundred; task-stats /
|
|
7414
|
+
* terminal-evidence scans look at recent tasks), so rows past a generous age only
|
|
7415
|
+
* cost space. Excluded from deletion — retained forever:
|
|
7416
|
+
* - coordinator_operating_note / _tombstone: runtime-accumulated lessons whose
|
|
7417
|
+
* whole point is surviving restarts; a tombstone must also outlive the notes
|
|
7418
|
+
* it retracts.
|
|
7419
|
+
* Timestamps are ISO-8601 TEXT, so the lexicographic `<` cutoff is a correct time
|
|
7420
|
+
* comparison; a malformed timestamp compares greater than any ISO date and is
|
|
7421
|
+
* conservatively retained. Returns rows deleted.
|
|
7422
|
+
*/
|
|
7423
|
+
pruneEventLedger(olderThanMs) {
|
|
7424
|
+
const cutoffIso = new Date(Date.now() - Math.max(0, olderThanMs)).toISOString();
|
|
7425
|
+
return this.db.prepare(
|
|
7426
|
+
`DELETE FROM mesh_event_ledger
|
|
7427
|
+
WHERE timestamp < ?
|
|
7428
|
+
AND kind NOT IN ('coordinator_operating_note', 'coordinator_operating_note_tombstone')`
|
|
7429
|
+
).run(cutoffIso).changes;
|
|
7430
|
+
}
|
|
7431
|
+
/**
|
|
7432
|
+
* Retention prune for TERMINAL (completed/cancelled/failed) mesh_queue rows
|
|
7433
|
+
* (SoT 1-11 (b)). Terminal rows are kept as recent history (mesh_task_history,
|
|
7434
|
+
* completion-dedup taskId lookups) but nothing ever deletes them, so the queue
|
|
7435
|
+
* table grows monotonically. Rows past the retention window serve no reader —
|
|
7436
|
+
* every dedup/attribution path operates on recent tasks — EXCEPT as a dependency
|
|
7437
|
+
* anchor: taskDependenciesSatisfied resolves dependsOn by id and treats a MISSING
|
|
7438
|
+
* row as not-completed, so deleting a completed row that a still-live
|
|
7439
|
+
* (pending/assigned) row depends on would permanently strand the dependent.
|
|
7440
|
+
* Those ids are collected first and excluded. Returns rows deleted.
|
|
7441
|
+
*/
|
|
7442
|
+
pruneTerminalQueueEntries(olderThanMs) {
|
|
7443
|
+
const cutoffIso = new Date(Date.now() - Math.max(0, olderThanMs)).toISOString();
|
|
7444
|
+
return this.transaction(() => {
|
|
7445
|
+
const liveRows = this.db.prepare(
|
|
7446
|
+
`SELECT payload FROM mesh_queue WHERE status IN ('pending', 'assigned')`
|
|
7447
|
+
).all();
|
|
7448
|
+
const protectedIds = /* @__PURE__ */ new Set();
|
|
7449
|
+
for (const row of liveRows) {
|
|
7450
|
+
try {
|
|
7451
|
+
const entry = JSON.parse(row.payload);
|
|
7452
|
+
if (Array.isArray(entry.dependsOn)) {
|
|
7453
|
+
for (const dep of entry.dependsOn) {
|
|
7454
|
+
if (typeof dep === "string" && dep) protectedIds.add(dep);
|
|
7455
|
+
}
|
|
7456
|
+
}
|
|
7457
|
+
} catch {
|
|
7458
|
+
}
|
|
7459
|
+
}
|
|
7460
|
+
const candidates = this.db.prepare(
|
|
7461
|
+
`SELECT id FROM mesh_queue
|
|
7462
|
+
WHERE status IN ('completed', 'cancelled', 'failed') AND updated_at < ?`
|
|
7463
|
+
).all(cutoffIso);
|
|
7464
|
+
const deletable = candidates.map((r) => r.id).filter((id) => !protectedIds.has(id));
|
|
7465
|
+
let removed = 0;
|
|
7466
|
+
for (let i = 0; i < deletable.length; i += 500) {
|
|
7467
|
+
const chunk = deletable.slice(i, i + 500);
|
|
7468
|
+
removed += this.db.prepare(
|
|
7469
|
+
`DELETE FROM mesh_queue WHERE id IN (${chunk.map(() => "?").join(",")})`
|
|
7470
|
+
).run(...chunk).changes;
|
|
7471
|
+
}
|
|
7472
|
+
return removed;
|
|
7473
|
+
});
|
|
7466
7474
|
}
|
|
7467
7475
|
// ── G2: Event Ledger ────────────────────────────────────────────────────
|
|
7468
7476
|
appendLedgerEntry(entry) {
|
|
@@ -7948,6 +7956,9 @@ var init_mesh_runtime_store = __esm({
|
|
|
7948
7956
|
return removed;
|
|
7949
7957
|
}
|
|
7950
7958
|
};
|
|
7959
|
+
MESH_EVENT_LEDGER_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
7960
|
+
MESH_TOOL_CALL_LOG_RETENTION_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
7961
|
+
MESH_TERMINAL_QUEUE_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
7951
7962
|
}
|
|
7952
7963
|
});
|
|
7953
7964
|
|
|
@@ -8426,6 +8437,16 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
|
|
|
8426
8437
|
continue;
|
|
8427
8438
|
}
|
|
8428
8439
|
if (validated.scope !== "unicast") {
|
|
8440
|
+
if (validated.scope === "broadcast" && isTerminalTaskEvent(validated.event)) {
|
|
8441
|
+
if (identityDeliversTo(validated.dispatchedBy, drainer)) {
|
|
8442
|
+
ctx.batchSeen.add(eventId);
|
|
8443
|
+
bump("v2Delivered");
|
|
8444
|
+
kept.push(event);
|
|
8445
|
+
} else {
|
|
8446
|
+
bump("v2RoutedAway");
|
|
8447
|
+
}
|
|
8448
|
+
continue;
|
|
8449
|
+
}
|
|
8429
8450
|
if (shouldDeliverPendingEventToCoordinator(validated, drainer)) {
|
|
8430
8451
|
ctx.batchSeen.add(eventId);
|
|
8431
8452
|
bump("v2Delivered");
|
|
@@ -16570,6 +16591,15 @@ function getStore() {
|
|
|
16570
16591
|
return void 0;
|
|
16571
16592
|
}
|
|
16572
16593
|
}
|
|
16594
|
+
function registerUnresolvedForwardRetryNudge(handler) {
|
|
16595
|
+
retryNudgeHandler = handler;
|
|
16596
|
+
}
|
|
16597
|
+
function nudgeUnresolvedForwardRetry() {
|
|
16598
|
+
try {
|
|
16599
|
+
retryNudgeHandler?.();
|
|
16600
|
+
} catch {
|
|
16601
|
+
}
|
|
16602
|
+
}
|
|
16573
16603
|
function enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, forwardPayload) {
|
|
16574
16604
|
const target = readNonEmptyString2(coordinatorDaemonId);
|
|
16575
16605
|
const event = readNonEmptyString2(eventName);
|
|
@@ -16653,7 +16683,7 @@ function expireStaleUnresolvedDelegateForwards(nowMs = Date.now()) {
|
|
|
16653
16683
|
return 0;
|
|
16654
16684
|
}
|
|
16655
16685
|
}
|
|
16656
|
-
var UNRESOLVED_FORWARD_OUTBOX_MESH_ID, UNRESOLVED_FORWARD_MAX_AGE_MS;
|
|
16686
|
+
var UNRESOLVED_FORWARD_OUTBOX_MESH_ID, UNRESOLVED_FORWARD_MAX_AGE_MS, retryNudgeHandler;
|
|
16657
16687
|
var init_mesh_unresolved_forward_outbox = __esm({
|
|
16658
16688
|
"src/mesh/mesh-unresolved-forward-outbox.ts"() {
|
|
16659
16689
|
"use strict";
|
|
@@ -19044,6 +19074,7 @@ function sweepExpiredRemoteIdleSessions() {
|
|
|
19044
19074
|
if (now - lastPendingEventsPruneAt >= PENDING_EVENTS_PRUNE_INTERVAL_MS) {
|
|
19045
19075
|
lastPendingEventsPruneAt = now;
|
|
19046
19076
|
prunePendingMeshCoordinatorEventsRetention();
|
|
19077
|
+
pruneMeshRuntimeRetention();
|
|
19047
19078
|
}
|
|
19048
19079
|
}
|
|
19049
19080
|
function isIntentionalCleanupStopMetadata(event) {
|
|
@@ -19900,25 +19931,6 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
19900
19931
|
v2Envelope: readV2EnvelopeFromWire(payload)
|
|
19901
19932
|
});
|
|
19902
19933
|
}
|
|
19903
|
-
function enqueueCoordinatorForwardPush(coordinatorDaemonId, run) {
|
|
19904
|
-
let lane = coordinatorForwardLanes.get(coordinatorDaemonId);
|
|
19905
|
-
if (!lane) {
|
|
19906
|
-
lane = { tail: Promise.resolve(), depth: 0 };
|
|
19907
|
-
coordinatorForwardLanes.set(coordinatorDaemonId, lane);
|
|
19908
|
-
}
|
|
19909
|
-
const wasIdle = lane.depth === 0;
|
|
19910
|
-
lane.depth += 1;
|
|
19911
|
-
const dec = () => {
|
|
19912
|
-
lane.depth -= 1;
|
|
19913
|
-
};
|
|
19914
|
-
if (wasIdle) {
|
|
19915
|
-
lane.tail = Promise.resolve(run()).catch(() => {
|
|
19916
|
-
}).then(dec, dec);
|
|
19917
|
-
} else {
|
|
19918
|
-
lane.tail = lane.tail.then(() => run()).catch(() => {
|
|
19919
|
-
}).then(dec, dec);
|
|
19920
|
-
}
|
|
19921
|
-
}
|
|
19922
19934
|
function forwardUnresolvedDelegateEvent(components, routing, event) {
|
|
19923
19935
|
const coordinatorDaemonId = readNonEmptyString2(routing.coordinatorDaemonId);
|
|
19924
19936
|
if (!coordinatorDaemonId) return false;
|
|
@@ -19955,28 +19967,15 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
|
|
|
19955
19967
|
nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
|
|
19956
19968
|
event: eventName
|
|
19957
19969
|
};
|
|
19958
|
-
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
return;
|
|
19966
|
-
}
|
|
19967
|
-
if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
|
|
19968
|
-
}).catch((e) => {
|
|
19969
|
-
LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued for retry`);
|
|
19970
|
-
}));
|
|
19971
|
-
LOG.info("MeshEvents", `Durably forwarded ${eventName} for unresolved-mesh worker at ${routing.workspace || "(no workspace)"} to coordinator daemon ${coordinatorDaemonId}`);
|
|
19970
|
+
if (!persisted) {
|
|
19971
|
+
traceMeshEventDrop("outbox_enqueue_failed", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId}`);
|
|
19972
|
+
return false;
|
|
19973
|
+
}
|
|
19974
|
+
traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=${readNonEmptyString2(payload.meshId) || "absent"}`);
|
|
19975
|
+
nudgeUnresolvedForwardRetry();
|
|
19976
|
+
LOG.info("MeshEvents", `Durably queued ${eventName} for unresolved-mesh worker at ${routing.workspace || "(no workspace)"} to coordinator daemon ${coordinatorDaemonId} (reconcile PHASE 0 delivers)`);
|
|
19972
19977
|
return true;
|
|
19973
19978
|
}
|
|
19974
|
-
function ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload) {
|
|
19975
|
-
const match = peekUnresolvedDelegateForwards().find(
|
|
19976
|
-
(entry) => daemonIdsEquivalent(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)
|
|
19977
|
-
);
|
|
19978
|
-
if (match) ackUnresolvedDelegateForward(match.id);
|
|
19979
|
-
}
|
|
19980
19979
|
function flushPendingForMeshIdleCoordinators(components, meshId) {
|
|
19981
19980
|
try {
|
|
19982
19981
|
const store = MeshRuntimeStore.getInstance();
|
|
@@ -20109,7 +20108,7 @@ function setupMeshEventForwarding(components) {
|
|
|
20109
20108
|
flushPendingForMeshIdleCoordinators(components, routing.meshId);
|
|
20110
20109
|
});
|
|
20111
20110
|
}
|
|
20112
|
-
var REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, lastPendingEventsPruneAt, PENDING_EVENTS_PRUNE_INTERVAL_MS, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, RECONCILED_COMPLETION_SOURCES
|
|
20111
|
+
var REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, lastPendingEventsPruneAt, PENDING_EVENTS_PRUNE_INTERVAL_MS, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, RECONCILED_COMPLETION_SOURCES;
|
|
20113
20112
|
var init_mesh_event_forwarding = __esm({
|
|
20114
20113
|
"src/mesh/mesh-event-forwarding.ts"() {
|
|
20115
20114
|
"use strict";
|
|
@@ -20146,7 +20145,6 @@ var init_mesh_event_forwarding = __esm({
|
|
|
20146
20145
|
"mcp_mesh_status_transcript_reconciliation",
|
|
20147
20146
|
"no_progress_reconciliation"
|
|
20148
20147
|
]);
|
|
20149
|
-
coordinatorForwardLanes = /* @__PURE__ */ new Map();
|
|
20150
20148
|
}
|
|
20151
20149
|
});
|
|
20152
20150
|
|
|
@@ -21125,6 +21123,65 @@ function recoverStrandedAssignedDispatches(components, meshId, store) {
|
|
|
21125
21123
|
}
|
|
21126
21124
|
}
|
|
21127
21125
|
}
|
|
21126
|
+
function reconcileZombieAssignedTasks(components, mesh, selfIds) {
|
|
21127
|
+
const meshId = mesh.id;
|
|
21128
|
+
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
21129
|
+
if (!assigned.length) return;
|
|
21130
|
+
const nowMs = Date.now();
|
|
21131
|
+
const assignedNodeIsLocal = (assignedNodeId) => {
|
|
21132
|
+
if (!assignedNodeId) return true;
|
|
21133
|
+
if (selfIds.some((id) => daemonIdsEquivalent(id, assignedNodeId))) return true;
|
|
21134
|
+
const nodes = Array.isArray(mesh.nodes) ? mesh.nodes : [];
|
|
21135
|
+
const node = nodes.find((n) => meshNodeIdMatches(n, assignedNodeId));
|
|
21136
|
+
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
21137
|
+
return !!nodeDaemonId && selfIds.some((id) => daemonIdsEquivalent(id, nodeDaemonId));
|
|
21138
|
+
};
|
|
21139
|
+
for (const row of assigned) {
|
|
21140
|
+
if (Number.isFinite(Date.parse(row.dispatchTimestamp ?? ""))) continue;
|
|
21141
|
+
const updatedMs = Date.parse(row.updatedAt ?? "");
|
|
21142
|
+
const createdMs = Date.parse(row.createdAt ?? "");
|
|
21143
|
+
const anchorMs = Number.isFinite(updatedMs) ? updatedMs : createdMs;
|
|
21144
|
+
if (!Number.isFinite(anchorMs)) continue;
|
|
21145
|
+
if (nowMs - anchorMs < ZOMBIE_ASSIGNED_MIN_AGE_MS) continue;
|
|
21146
|
+
const terminal = findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id });
|
|
21147
|
+
if (terminal) {
|
|
21148
|
+
const status = terminal.kind === "task_completed" ? "completed" : "failed";
|
|
21149
|
+
updateTaskStatus(meshId, row.id, status);
|
|
21150
|
+
LOG.warn("MeshReconcile", `Zombie assigned task ${row.id} on mesh ${meshId} had ${terminal.kind} ledger evidence \u2014 flipped to ${status}`);
|
|
21151
|
+
continue;
|
|
21152
|
+
}
|
|
21153
|
+
if (!assignedNodeIsLocal(row.assignedNodeId)) continue;
|
|
21154
|
+
if (row.assignedSessionId) {
|
|
21155
|
+
const verdict = resolveSessionBusyVerdict(components, row.assignedSessionId);
|
|
21156
|
+
if (verdict !== "UNKNOWN") continue;
|
|
21157
|
+
}
|
|
21158
|
+
const reason = row.assignedSessionId ? "assigned_zombie_session_missing" : "assigned_zombie_no_session_bound";
|
|
21159
|
+
const failed = updateTaskStatus(meshId, row.id, "failed");
|
|
21160
|
+
if (!failed) continue;
|
|
21161
|
+
try {
|
|
21162
|
+
appendLedgerEntry(meshId, {
|
|
21163
|
+
kind: "task_failed",
|
|
21164
|
+
nodeId: row.assignedNodeId,
|
|
21165
|
+
sessionId: row.assignedSessionId,
|
|
21166
|
+
payload: {
|
|
21167
|
+
taskId: row.id,
|
|
21168
|
+
reason,
|
|
21169
|
+
source: "reconcile_zombie_assigned_sweep",
|
|
21170
|
+
ageMs: nowMs - anchorMs
|
|
21171
|
+
}
|
|
21172
|
+
});
|
|
21173
|
+
} catch {
|
|
21174
|
+
}
|
|
21175
|
+
LOG.warn("MeshReconcile", `Failed zombie assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, no dispatchTimestamp, stale ${Math.round((nowMs - anchorMs) / 6e4)}m, ${reason})`);
|
|
21176
|
+
traceMeshEventDrop("assigned_zombie_failed", {
|
|
21177
|
+
taskId: row.id,
|
|
21178
|
+
sessionId: row.assignedSessionId,
|
|
21179
|
+
nodeId: row.assignedNodeId,
|
|
21180
|
+
meshId,
|
|
21181
|
+
event: "agent:generating_completed"
|
|
21182
|
+
}, `${reason} stale=${Math.round((nowMs - anchorMs) / 6e4)}m`);
|
|
21183
|
+
}
|
|
21184
|
+
}
|
|
21128
21185
|
async function runMeshReconcileTick(components) {
|
|
21129
21186
|
const localDaemonId = readNonEmptyString2(loadConfig().machineId) || void 0;
|
|
21130
21187
|
const drainDaemonIds = resolveCoordinatorDaemonIds(components);
|
|
@@ -21163,6 +21220,11 @@ async function runMeshReconcileTick(components) {
|
|
|
21163
21220
|
} catch (e) {
|
|
21164
21221
|
LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
21165
21222
|
}
|
|
21223
|
+
try {
|
|
21224
|
+
reconcileZombieAssignedTasks(components, mesh, selfIds);
|
|
21225
|
+
} catch (e) {
|
|
21226
|
+
LOG.warn("MeshReconcile", `Assigned-zombie sweep failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
21227
|
+
}
|
|
21166
21228
|
}
|
|
21167
21229
|
}
|
|
21168
21230
|
for (const mesh of listMeshes()) {
|
|
@@ -21384,6 +21446,25 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
21384
21446
|
LOG.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
21385
21447
|
}
|
|
21386
21448
|
}
|
|
21449
|
+
function scheduleUnresolvedForwardNudge(components) {
|
|
21450
|
+
if (!components.dispatchMeshCommand) return;
|
|
21451
|
+
if (unresolvedForwardNudgeTimer) return;
|
|
21452
|
+
unresolvedForwardNudgeTimer = setTimeout(() => {
|
|
21453
|
+
unresolvedForwardNudgeTimer = void 0;
|
|
21454
|
+
if (unresolvedForwardNudgeRunning) return;
|
|
21455
|
+
unresolvedForwardNudgeRunning = true;
|
|
21456
|
+
void retryUnresolvedDelegateForwards(components).catch((e) => LOG.warn("MeshReconcile", `Nudged unresolved-forward retry failed: ${e?.message || e}`)).finally(() => {
|
|
21457
|
+
unresolvedForwardNudgeRunning = false;
|
|
21458
|
+
});
|
|
21459
|
+
}, UNRESOLVED_FORWARD_NUDGE_DELAY_MS);
|
|
21460
|
+
if (typeof unresolvedForwardNudgeTimer.unref === "function") unresolvedForwardNudgeTimer.unref();
|
|
21461
|
+
}
|
|
21462
|
+
function clearUnresolvedForwardNudge() {
|
|
21463
|
+
if (unresolvedForwardNudgeTimer) {
|
|
21464
|
+
clearTimeout(unresolvedForwardNudgeTimer);
|
|
21465
|
+
unresolvedForwardNudgeTimer = void 0;
|
|
21466
|
+
}
|
|
21467
|
+
}
|
|
21387
21468
|
async function retryUnresolvedDelegateForwards(components) {
|
|
21388
21469
|
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
21389
21470
|
if (!dispatchMeshCommand) return;
|
|
@@ -21468,15 +21549,18 @@ function setupMeshReconcileLoop(components) {
|
|
|
21468
21549
|
});
|
|
21469
21550
|
}, intervalMs);
|
|
21470
21551
|
if (typeof timer.unref === "function") timer.unref();
|
|
21552
|
+
registerUnresolvedForwardRetryNudge(() => scheduleUnresolvedForwardNudge(components));
|
|
21471
21553
|
LOG.info("MeshReconcile", `Mesh reconcile loop started (interval ${intervalMs}ms)`);
|
|
21472
21554
|
return {
|
|
21473
21555
|
stop() {
|
|
21474
21556
|
clearInterval(timer);
|
|
21557
|
+
registerUnresolvedForwardRetryNudge(void 0);
|
|
21558
|
+
clearUnresolvedForwardNudge();
|
|
21475
21559
|
LOG.info("MeshReconcile", "Mesh reconcile loop stopped");
|
|
21476
21560
|
}
|
|
21477
21561
|
};
|
|
21478
21562
|
}
|
|
21479
|
-
var coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
21563
|
+
var coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
|
|
21480
21564
|
var init_mesh_reconcile_loop = __esm({
|
|
21481
21565
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
21482
21566
|
"use strict";
|
|
@@ -21508,9 +21592,12 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
21508
21592
|
DELIVERED_NO_TURN_DEADLINE_MS = 15 * 6e4;
|
|
21509
21593
|
RECLAIM_UNKNOWN_GRACE_TICKS = 3;
|
|
21510
21594
|
deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
|
|
21595
|
+
ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
|
|
21511
21596
|
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
21512
21597
|
unresolvedForwardRejectionCounts = /* @__PURE__ */ new Map();
|
|
21513
21598
|
MAX_FORWARD_REJECTIONS = 5;
|
|
21599
|
+
UNRESOLVED_FORWARD_NUDGE_DELAY_MS = 250;
|
|
21600
|
+
unresolvedForwardNudgeRunning = false;
|
|
21514
21601
|
}
|
|
21515
21602
|
});
|
|
21516
21603
|
|
|
@@ -34195,6 +34282,16 @@ function isRuntimeFallbackHistorySessionId(candidateHistorySessionId, targetSess
|
|
|
34195
34282
|
const candidate = typeof candidateHistorySessionId === "string" ? candidateHistorySessionId.trim() : "";
|
|
34196
34283
|
return candidate === target;
|
|
34197
34284
|
}
|
|
34285
|
+
function resolveNativeHistoryReadSession(args, candidateHistorySessionId) {
|
|
34286
|
+
const targetSid = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
|
|
34287
|
+
const explicitHistorySessionId = getExplicitHistorySessionId(args);
|
|
34288
|
+
const isRuntimeFallback = Boolean(
|
|
34289
|
+
targetSid && isRuntimeFallbackHistorySessionId(candidateHistorySessionId, targetSid) && (!explicitHistorySessionId || isRuntimeFallbackHistorySessionId(explicitHistorySessionId, targetSid))
|
|
34290
|
+
);
|
|
34291
|
+
const pinnedProviderSessionId = getBoundProviderSessionIdPin(args?.targetSessionId);
|
|
34292
|
+
const effectiveHistorySessionId = isRuntimeFallback ? pinnedProviderSessionId || void 0 : candidateHistorySessionId;
|
|
34293
|
+
return { isRuntimeFallback, pinnedProviderSessionId, effectiveHistorySessionId };
|
|
34294
|
+
}
|
|
34198
34295
|
function getHistorySessionId(h, args) {
|
|
34199
34296
|
const explicit = getExplicitHistorySessionId(args);
|
|
34200
34297
|
if (explicit) return explicit;
|
|
@@ -35029,13 +35126,11 @@ async function handleChatHistory(h, args) {
|
|
|
35029
35126
|
if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
|
|
35030
35127
|
}
|
|
35031
35128
|
const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
|
|
35032
|
-
const
|
|
35033
|
-
|
|
35034
|
-
|
|
35035
|
-
|
|
35036
|
-
);
|
|
35037
|
-
const pinnedProviderSessionIdForHistory = getBoundProviderSessionIdPin(args?.targetSessionId);
|
|
35038
|
-
const effectiveHistorySessionId = historySessionIdIsRuntimeFallback ? pinnedProviderSessionIdForHistory || void 0 : historySessionId;
|
|
35129
|
+
const {
|
|
35130
|
+
isRuntimeFallback: historySessionIdIsRuntimeFallback,
|
|
35131
|
+
pinnedProviderSessionId: pinnedProviderSessionIdForHistory,
|
|
35132
|
+
effectiveHistorySessionId
|
|
35133
|
+
} = resolveNativeHistoryReadSession(args, historySessionId);
|
|
35039
35134
|
const exactNativeHistoryScope = Boolean(
|
|
35040
35135
|
typeof args?.targetSessionId === "string" && args.targetSessionId.trim() || typeof args?.historySessionId === "string" && args.historySessionId.trim() && !historySessionIdIsRuntimeFallback || typeof args?.providerSessionId === "string" && args.providerSessionId.trim()
|
|
35041
35136
|
);
|
|
@@ -35196,12 +35291,10 @@ async function handleReadChat(h, args) {
|
|
|
35196
35291
|
let nativeHistory = null;
|
|
35197
35292
|
let nativeHistoryError;
|
|
35198
35293
|
if (supportsNative) {
|
|
35199
|
-
const
|
|
35200
|
-
|
|
35201
|
-
|
|
35202
|
-
|
|
35203
|
-
);
|
|
35204
|
-
const effectiveNativeReadSessionId = nativeReadSessionIdIsRuntimeFallback ? pinnedProviderSessionIdForRead || void 0 : nativeHistoryReadSessionId;
|
|
35294
|
+
const {
|
|
35295
|
+
pinnedProviderSessionId: pinnedProviderSessionIdForRead,
|
|
35296
|
+
effectiveHistorySessionId: effectiveNativeReadSessionId
|
|
35297
|
+
} = resolveNativeHistoryReadSession(args, nativeHistoryReadSessionId);
|
|
35205
35298
|
try {
|
|
35206
35299
|
nativeHistory = readCliProviderNativeHistory(agentStr, {
|
|
35207
35300
|
canonicalHistory: provider?.nativeHistory,
|
|
@@ -35478,12 +35571,11 @@ async function handleReadChat(h, args) {
|
|
|
35478
35571
|
const workspace = targetSid ? typeof registrySessionWorkspace === "string" ? registrySessionWorkspace : argsWorkspace ?? currentSessionWorkspace : typeof currentSessionWorkspace === "string" ? currentSessionWorkspace : void 0;
|
|
35479
35572
|
const intendedWorkspace = argsWorkspace;
|
|
35480
35573
|
const supportsNative = supportsCliNativeTranscript(agentStr, provider) && isNativeSourceCanonicalHistory(provider?.nativeHistory);
|
|
35481
|
-
const
|
|
35482
|
-
|
|
35483
|
-
|
|
35484
|
-
|
|
35485
|
-
);
|
|
35486
|
-
const effectiveHistorySessionIdForRead = historySessionIdIsRuntimeFallback ? pinnedProviderSessionIdForHistory || void 0 : historySessionId;
|
|
35574
|
+
const {
|
|
35575
|
+
isRuntimeFallback: historySessionIdIsRuntimeFallback,
|
|
35576
|
+
pinnedProviderSessionId: pinnedProviderSessionIdForHistory,
|
|
35577
|
+
effectiveHistorySessionId: effectiveHistorySessionIdForRead
|
|
35578
|
+
} = resolveNativeHistoryReadSession(args, historySessionId);
|
|
35487
35579
|
const history = supportsNative ? readCliProviderNativeHistory(agentStr, {
|
|
35488
35580
|
canonicalHistory: provider?.nativeHistory,
|
|
35489
35581
|
historySessionId: effectiveHistorySessionIdForRead,
|
|
@@ -39707,6 +39799,53 @@ var statusMetaHandlers = {
|
|
|
39707
39799
|
|
|
39708
39800
|
// src/commands/low-family/coordinator-prompt.ts
|
|
39709
39801
|
var coordinatorPromptHandlers = {
|
|
39802
|
+
/**
|
|
39803
|
+
* Render the coordinator system prompt for a mesh + CLI type, so the
|
|
39804
|
+
* dashboard can show the operator exactly what a coordinator session
|
|
39805
|
+
* receives by default. This resolves the mesh, applies its repo-mesh
|
|
39806
|
+
* config, and runs the SAME buildCoordinatorSystemPrompt the launch path
|
|
39807
|
+
* uses — minus the runtime-only best-effort sections (mission / recent
|
|
39808
|
+
* activity / operating notes), which are launch-scope and not part of the
|
|
39809
|
+
* static "default base" an operator is trying to preview here.
|
|
39810
|
+
*
|
|
39811
|
+
* It respects mesh-level and user-file override/append layering, so the
|
|
39812
|
+
* preview reflects the effective prompt: with no overrides configured it
|
|
39813
|
+
* shows the pure daemon default; with an override set it shows that.
|
|
39814
|
+
*/
|
|
39815
|
+
coordinator_prompt_preview: async (ctx, args) => {
|
|
39816
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
39817
|
+
const cliType = typeof args?.cliType === "string" && args.cliType.trim() ? args.cliType.trim() : "claude-cli";
|
|
39818
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
39819
|
+
try {
|
|
39820
|
+
let mesh = null;
|
|
39821
|
+
if (ctx.getMeshForCommand) {
|
|
39822
|
+
const resolved = await ctx.getMeshForCommand(meshId);
|
|
39823
|
+
mesh = resolved?.mesh ?? null;
|
|
39824
|
+
}
|
|
39825
|
+
if (!mesh) {
|
|
39826
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
39827
|
+
mesh = getMesh2(meshId);
|
|
39828
|
+
}
|
|
39829
|
+
if (!mesh) return { success: false, error: `mesh not found: ${meshId}` };
|
|
39830
|
+
let effectiveMesh = mesh;
|
|
39831
|
+
try {
|
|
39832
|
+
const { loadRepoMeshJsonConfig: loadRepoMeshJsonConfig2, applyRepoMeshConfig: applyRepoMeshConfig2 } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
|
|
39833
|
+
const workspace = typeof mesh?.workspace === "string" ? mesh.workspace : void 0;
|
|
39834
|
+
if (workspace) {
|
|
39835
|
+
const loaded = loadRepoMeshJsonConfig2(workspace);
|
|
39836
|
+
if (loaded?.sourceType !== "invalid") {
|
|
39837
|
+
effectiveMesh = applyRepoMeshConfig2(mesh, loaded?.config);
|
|
39838
|
+
}
|
|
39839
|
+
}
|
|
39840
|
+
} catch {
|
|
39841
|
+
}
|
|
39842
|
+
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
39843
|
+
const prompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType });
|
|
39844
|
+
return { success: true, prompt, cliType, meshId, bytes: Buffer.byteLength(prompt, "utf8") };
|
|
39845
|
+
} catch (error) {
|
|
39846
|
+
return { success: false, error: error?.message || String(error) };
|
|
39847
|
+
}
|
|
39848
|
+
},
|
|
39710
39849
|
list_coordinator_prompts: async (_ctx, _args) => {
|
|
39711
39850
|
const fs41 = await import("fs");
|
|
39712
39851
|
const path45 = await import("path");
|
|
@@ -54288,61 +54427,15 @@ var meshCrudHandlers = {
|
|
|
54288
54427
|
return { success: false, error: e.message };
|
|
54289
54428
|
}
|
|
54290
54429
|
},
|
|
54291
|
-
// ─── MAGI panels (machine-local config, sibling to meshes) ───────────────
|
|
54292
|
-
// Panels live in ~/.adhdev/meshes.json `magiPanels` and are pure local config
|
|
54293
|
-
// (no mesh ownership). These three handlers mirror list_meshes/create_mesh/
|
|
54294
|
-
// update_mesh: dynamic-import the already-exported mesh-config accessors and
|
|
54295
|
-
// surface normalizeMagiPanel's structured error codes (invalid_magi_panel,
|
|
54296
|
-
// magi_panel_exists) verbatim so the dashboard can render them.
|
|
54297
|
-
//
|
|
54298
|
-
// Permission: magi_panel_set / magi_panel_remove are WRITE commands. They are
|
|
54299
|
-
// intentionally NOT listed in canPeerUsePrivilegedShareCommand (daemon-cloud
|
|
54300
|
-
// data-channel-router), so a peer holding ANY share permission hits its
|
|
54301
|
-
// `default → false` branch — identical owner-only gating to create_mesh /
|
|
54302
|
-
// update_mesh / list_meshes (none of which are listed there either). A trusted
|
|
54303
|
-
// peer (no permission = the owner) passes the top `!permission → true` guard.
|
|
54304
|
-
// Mirror, don't invent: do not add a new policy tier here.
|
|
54305
|
-
//
|
|
54306
|
-
// Resolvability (coupling / stale / available) is deliberately NOT computed
|
|
54307
|
-
// here: buildMagiFanoutPlan lives in mcp-server, unreachable from daemon-core.
|
|
54308
|
-
// magi_panel_list returns the raw definitions only; the dashboard derives
|
|
54309
|
-
// member resolvability client-side (web-core MagiPanelManager, reusing the
|
|
54310
|
-
// MagiGroupRow coupling logic) against live mesh_status.
|
|
54311
|
-
magi_panel_list: async (_ctx, _args) => {
|
|
54312
|
-
try {
|
|
54313
|
-
const { listMagiPanels: listMagiPanels2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
54314
|
-
return { success: true, panels: listMagiPanels2() };
|
|
54315
|
-
} catch (e) {
|
|
54316
|
-
return { success: false, error: e.message };
|
|
54317
|
-
}
|
|
54318
|
-
},
|
|
54319
|
-
magi_panel_set: async (_ctx, args) => {
|
|
54320
|
-
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
54321
|
-
if (!name) return { success: false, error: "invalid_magi_panel: panel name is required" };
|
|
54322
|
-
try {
|
|
54323
|
-
const { upsertMagiPanel: upsertMagiPanel2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
54324
|
-
const panel = upsertMagiPanel2(name, args?.panel, { overwrite: args?.overwrite === true });
|
|
54325
|
-
return { success: true, name, panel };
|
|
54326
|
-
} catch (e) {
|
|
54327
|
-
return { success: false, error: e.message };
|
|
54328
|
-
}
|
|
54329
|
-
},
|
|
54330
|
-
magi_panel_remove: async (_ctx, args) => {
|
|
54331
|
-
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
54332
|
-
if (!name) return { success: false, error: "invalid_magi_panel: panel name is required" };
|
|
54333
|
-
try {
|
|
54334
|
-
const { removeMagiPanel: removeMagiPanel2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
54335
|
-
const removed = removeMagiPanel2(name);
|
|
54336
|
-
return { success: true, removed };
|
|
54337
|
-
} catch (e) {
|
|
54338
|
-
return { success: false, error: e.message };
|
|
54339
|
-
}
|
|
54340
|
-
},
|
|
54341
54430
|
// ─── MAGI kind → panel bindings (MAGI-KIND-PANEL, machine-local config) ───
|
|
54342
|
-
// Per-task_kind slot lists in ~/.adhdev/meshes.json `magiKindPanels
|
|
54343
|
-
//
|
|
54344
|
-
//
|
|
54345
|
-
//
|
|
54431
|
+
// Per-task_kind slot lists in ~/.adhdev/meshes.json `magiKindPanels` — the SOLE
|
|
54432
|
+
// MAGI panel-resolution surface (the former named-panel magi_panel_* handlers were
|
|
54433
|
+
// removed). Owner-only gating: intentionally NOT listed in
|
|
54434
|
+
// canPeerUsePrivilegedShareCommand (daemon-cloud data-channel-router), so a peer
|
|
54435
|
+
// holding ANY share permission hits its `default → false` branch — identical
|
|
54436
|
+
// owner-only gating to create_mesh / update_mesh / list_meshes. A trusted peer (no
|
|
54437
|
+
// permission = the owner) passes the top `!permission → true` guard. set/remove are
|
|
54438
|
+
// WRITE commands; list is read-only. normalizeMagiSlots (inside setMagiKindPanel)
|
|
54346
54439
|
// surfaces invalid_magi_kind_panel: … messages verbatim for the editor.
|
|
54347
54440
|
magi_kind_panel_list: async (_ctx, _args) => {
|
|
54348
54441
|
try {
|
|
@@ -54395,13 +54488,15 @@ var meshCrudHandlers = {
|
|
|
54395
54488
|
const daemonId = typeof args?.daemonId === "string" && args.daemonId.trim() ? args.daemonId.trim() : void 0;
|
|
54396
54489
|
const machineId = typeof args?.machineId === "string" && args.machineId.trim() ? args.machineId.trim() : void 0;
|
|
54397
54490
|
const repoRoot = typeof args?.repoRoot === "string" && args.repoRoot.trim() ? args.repoRoot.trim() : void 0;
|
|
54491
|
+
const capabilities = Array.isArray(args?.capabilities) ? args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean) : void 0;
|
|
54398
54492
|
const node = addNode2(meshId, {
|
|
54399
54493
|
workspace,
|
|
54400
54494
|
...repoRoot ? { repoRoot } : {},
|
|
54401
54495
|
...daemonId ? { daemonId } : {},
|
|
54402
54496
|
...machineId ? { machineId } : {},
|
|
54403
54497
|
...policy ? { policy } : {},
|
|
54404
|
-
...role ? { role } : {}
|
|
54498
|
+
...role ? { role } : {},
|
|
54499
|
+
...capabilities && capabilities.length ? { capabilities } : {}
|
|
54405
54500
|
});
|
|
54406
54501
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
54407
54502
|
ctx.invalidateAggregateMeshStatus(meshId);
|
|
@@ -54443,6 +54538,9 @@ var meshCrudHandlers = {
|
|
|
54443
54538
|
} else if (args?.systemPrompt === null) {
|
|
54444
54539
|
patch.systemPrompt = void 0;
|
|
54445
54540
|
}
|
|
54541
|
+
if (Array.isArray(args?.capabilities)) {
|
|
54542
|
+
patch.capabilities = args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean);
|
|
54543
|
+
}
|
|
54446
54544
|
const node = updateNode2(meshId, nodeId, patch);
|
|
54447
54545
|
if (!node) return { success: false, error: "Mesh node not found" };
|
|
54448
54546
|
ctx.invalidateAggregateMeshStatus(meshId);
|
|
@@ -69481,7 +69579,6 @@ export {
|
|
|
69481
69579
|
getLedgerSummary,
|
|
69482
69580
|
getLogLevel,
|
|
69483
69581
|
getMagiKindPanel,
|
|
69484
|
-
getMagiPanel,
|
|
69485
69582
|
getMesh,
|
|
69486
69583
|
getMeshByRepo,
|
|
69487
69584
|
getMeshMagiActivityByGroup,
|
|
@@ -69539,7 +69636,6 @@ export {
|
|
|
69539
69636
|
listCoordinatorsForWorkspace,
|
|
69540
69637
|
listHostedCliRuntimes,
|
|
69541
69638
|
listMagiKindPanels,
|
|
69542
|
-
listMagiPanels,
|
|
69543
69639
|
listMeshMissionSummaries,
|
|
69544
69640
|
listMeshMissionsForTool,
|
|
69545
69641
|
listMeshes,
|
|
@@ -69576,7 +69672,6 @@ export {
|
|
|
69576
69672
|
normalizeInputEnvelope,
|
|
69577
69673
|
normalizeInteractivePrompt,
|
|
69578
69674
|
normalizeInteractivePromptResponse,
|
|
69579
|
-
normalizeMagiPanel,
|
|
69580
69675
|
normalizeMagiSlots,
|
|
69581
69676
|
normalizeManagedStatus,
|
|
69582
69677
|
normalizeMeshCapabilityTags,
|
|
@@ -69619,7 +69714,6 @@ export {
|
|
|
69619
69714
|
registerExtensionProviders,
|
|
69620
69715
|
registerMeshCoordinator,
|
|
69621
69716
|
removeMagiKindPanel,
|
|
69622
|
-
removeMagiPanel,
|
|
69623
69717
|
removeNode,
|
|
69624
69718
|
removeWorktree,
|
|
69625
69719
|
requeueHeldMeshCoordinatorEvents,
|
|
@@ -69682,7 +69776,6 @@ export {
|
|
|
69682
69776
|
updateSessionDeliveryStatus,
|
|
69683
69777
|
updateSessionTaskStatus,
|
|
69684
69778
|
updateTaskStatus,
|
|
69685
|
-
upsertMagiPanel,
|
|
69686
69779
|
upsertMeshMission,
|
|
69687
69780
|
upsertSavedProviderSession,
|
|
69688
69781
|
validateChangeImpactConfig,
|