@adhdev/daemon-core 0.9.82-rc.482 → 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 +5 -0
- package/dist/index.js +98 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +98 -7
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/contracts.d.ts +27 -4
- package/dist/repo-mesh-types.d.ts +1 -1
- package/package.json +3 -3
- package/src/commands/low-family/coordinator-prompt.ts +53 -0
- package/src/commands/med-family/mesh-crud.ts +11 -0
- package/src/config/mesh-config.ts +12 -0
- package/src/mesh/contracts.ts +42 -7
- package/src/mesh/coordinator-prompt.ts +19 -0
- package/src/mesh/mesh-events-pending.ts +20 -0
- package/src/repo-mesh-types.ts +1 -1
|
@@ -121,6 +121,11 @@ export declare function removeNode(meshId: string, nodeId: string): boolean;
|
|
|
121
121
|
export declare function updateNode(meshId: string, nodeId: string, opts: {
|
|
122
122
|
userOverrides?: Partial<RepoMeshNodeCapabilities>;
|
|
123
123
|
policy?: RepoMeshNodePolicy;
|
|
124
|
+
/** Operator-defined custom capability tags used by mesh queue matching.
|
|
125
|
+
* Passing an array replaces the node's custom tags (empty/whitespace
|
|
126
|
+
* entries dropped, deduped); an empty result clears them. Omit to leave
|
|
127
|
+
* the existing tags untouched. */
|
|
128
|
+
capabilities?: string[];
|
|
124
129
|
worktreeBootstrap?: LocalMeshNodeEntry['worktreeBootstrap'];
|
|
125
130
|
/** Per-node instruction surfaced in the coordinator prompt. Pass an
|
|
126
131
|
* empty string or undefined to clear it. */
|
package/dist/index.js
CHANGED
|
@@ -188,7 +188,7 @@ var init_repo_mesh_types = __esm({
|
|
|
188
188
|
"checkpoint_then_continue"
|
|
189
189
|
]);
|
|
190
190
|
MESH_MAX_PARALLEL_TASKS_MIN = 1;
|
|
191
|
-
MESH_MAX_PARALLEL_TASKS_MAX =
|
|
191
|
+
MESH_MAX_PARALLEL_TASKS_MAX = 64;
|
|
192
192
|
DEFAULT_MESH_READONLY_MULTIPLIER = 2;
|
|
193
193
|
}
|
|
194
194
|
});
|
|
@@ -409,10 +409,10 @@ function readInjected(value) {
|
|
|
409
409
|
}
|
|
410
410
|
function getDaemonBuildInfo() {
|
|
411
411
|
if (cached) return cached;
|
|
412
|
-
const commit = readInjected(true ? "
|
|
413
|
-
const commitShort = readInjected(true ? "
|
|
414
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
415
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
412
|
+
const commit = readInjected(true ? "0862a3f10fa9de60a46591c0894a7209534db2e2" : void 0) ?? "unknown";
|
|
413
|
+
const commitShort = readInjected(true ? "0862a3f1" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
414
|
+
const version = readInjected(true ? "0.9.82-rc.483" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
415
|
+
const builtAt = readInjected(true ? "2026-07-08T04:27:00.139Z" : void 0);
|
|
416
416
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
417
|
return cached;
|
|
418
418
|
}
|
|
@@ -3309,6 +3309,11 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
3309
3309
|
node.reportedDaemonBuildVersion = opts.reportedDaemonBuildVersion.trim();
|
|
3310
3310
|
}
|
|
3311
3311
|
if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
|
|
3312
|
+
if (Object.prototype.hasOwnProperty.call(opts, "capabilities")) {
|
|
3313
|
+
const tags = normalizeCapabilityTags(opts.capabilities);
|
|
3314
|
+
if (tags && tags.length) node.capabilities = tags;
|
|
3315
|
+
else delete node.capabilities;
|
|
3316
|
+
}
|
|
3312
3317
|
if (opts.worktreeBootstrap) node.worktreeBootstrap = opts.worktreeBootstrap;
|
|
3313
3318
|
if (Object.prototype.hasOwnProperty.call(opts, "systemPrompt")) {
|
|
3314
3319
|
if (opts.systemPrompt && opts.systemPrompt.trim()) {
|
|
@@ -3601,6 +3606,21 @@ function buildNodeConfigSection(mesh) {
|
|
|
3601
3606
|
}).filter(Boolean) : [];
|
|
3602
3607
|
const providerRolesSuffix = providerRoles.length ? ` | caps: ${providerRoles.join(", ")}` : "";
|
|
3603
3608
|
lines.push(`- ${explicitLabel} nodeId: \`${n.id}\` | workspace: \`${n.workspace}\`${n.daemonId ? ` | daemon: \`${n.daemonId}\`` : ""}${providerPriority}${providerRolesSuffix}${suffix}`);
|
|
3609
|
+
const routingTags = [];
|
|
3610
|
+
const custom = Array.isArray(n.capabilities) ? n.capabilities : [];
|
|
3611
|
+
for (const t of custom) {
|
|
3612
|
+
const s2 = typeof t === "string" ? t.trim() : "";
|
|
3613
|
+
if (s2) routingTags.push(s2);
|
|
3614
|
+
}
|
|
3615
|
+
const tagOs = (n.userOverrides?.platform || n.reportedPlatform || "").toString().trim();
|
|
3616
|
+
const tagArch = (n.userOverrides?.arch || n.reportedArch || "").toString().trim();
|
|
3617
|
+
if (tagOs) routingTags.push(`os=${tagOs}`);
|
|
3618
|
+
if (tagArch) routingTags.push(`arch=${tagArch}`);
|
|
3619
|
+
const wtBranch = typeof n.worktreeBranch === "string" ? n.worktreeBranch.trim() : "";
|
|
3620
|
+
if (n.isLocalWorktree && wtBranch) routingTags.push(`worktree=${wtBranch}`);
|
|
3621
|
+
if (routingTags.length) {
|
|
3622
|
+
lines.push(` \u{1F3F7}\uFE0F routing tags: ${routingTags.map((t) => `\`${t}\``).join(", ")}`);
|
|
3623
|
+
}
|
|
3604
3624
|
const nodePrompt = typeof n.systemPrompt === "string" ? n.systemPrompt.trim() : "";
|
|
3605
3625
|
if (nodePrompt) {
|
|
3606
3626
|
lines.push(` \u{1F4CC} Node instruction: ${indentFollowing(nodePrompt, " ")}`);
|
|
@@ -3702,6 +3722,7 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
3702
3722
|
- **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.
|
|
3703
3723
|
- **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\`.
|
|
3704
3724
|
- **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.
|
|
3725
|
+
- **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.
|
|
3705
3726
|
- **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.
|
|
3706
3727
|
- **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
|
|
3707
3728
|
- **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).
|
|
@@ -3791,6 +3812,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
3791
3812
|
3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
|
|
3792
3813
|
a. **General Tasks**: Enqueue tasks using \`mesh_enqueue_task\`. Idle node agents will automatically pull tasks from the queue and begin working.
|
|
3793
3814
|
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.
|
|
3815
|
+
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.
|
|
3794
3816
|
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.
|
|
3795
3817
|
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.
|
|
3796
3818
|
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.
|
|
@@ -4241,6 +4263,9 @@ function shouldDeliverPendingEventToCoordinator(event, drainer) {
|
|
|
4241
4263
|
if (!event.intendedFor) return false;
|
|
4242
4264
|
return coordinatorIdentityEquals(event.intendedFor, drainer);
|
|
4243
4265
|
}
|
|
4266
|
+
function isTerminalTaskEvent(eventName) {
|
|
4267
|
+
return TERMINAL_TASK_EVENTS.has(eventName);
|
|
4268
|
+
}
|
|
4244
4269
|
function defaultScopeForEvent(eventName) {
|
|
4245
4270
|
if (TERMINAL_TASK_EVENTS.has(eventName) || COORDINATOR_ALERT_EVENTS.has(eventName)) return "unicast";
|
|
4246
4271
|
return "broadcast";
|
|
@@ -4257,7 +4282,11 @@ function buildPendingEventEmitStamp(opts) {
|
|
|
4257
4282
|
let scope = opts.scope ?? defaultScopeForEvent(opts.eventName);
|
|
4258
4283
|
let intendedFor = opts.intendedFor;
|
|
4259
4284
|
if (scope === "unicast" && !intendedFor) {
|
|
4260
|
-
|
|
4285
|
+
if (isTerminalTaskEvent(opts.eventName)) {
|
|
4286
|
+
intendedFor = opts.dispatchedBy;
|
|
4287
|
+
} else {
|
|
4288
|
+
scope = "broadcast";
|
|
4289
|
+
}
|
|
4261
4290
|
}
|
|
4262
4291
|
if (scope !== "unicast") intendedFor = void 0;
|
|
4263
4292
|
return {
|
|
@@ -8412,6 +8441,16 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
|
|
|
8412
8441
|
continue;
|
|
8413
8442
|
}
|
|
8414
8443
|
if (validated.scope !== "unicast") {
|
|
8444
|
+
if (validated.scope === "broadcast" && isTerminalTaskEvent(validated.event)) {
|
|
8445
|
+
if (identityDeliversTo(validated.dispatchedBy, drainer)) {
|
|
8446
|
+
ctx.batchSeen.add(eventId);
|
|
8447
|
+
bump("v2Delivered");
|
|
8448
|
+
kept.push(event);
|
|
8449
|
+
} else {
|
|
8450
|
+
bump("v2RoutedAway");
|
|
8451
|
+
}
|
|
8452
|
+
continue;
|
|
8453
|
+
}
|
|
8415
8454
|
if (shouldDeliverPendingEventToCoordinator(validated, drainer)) {
|
|
8416
8455
|
ctx.batchSeen.add(eventId);
|
|
8417
8456
|
bump("v2Delivered");
|
|
@@ -40179,6 +40218,53 @@ var statusMetaHandlers = {
|
|
|
40179
40218
|
|
|
40180
40219
|
// src/commands/low-family/coordinator-prompt.ts
|
|
40181
40220
|
var coordinatorPromptHandlers = {
|
|
40221
|
+
/**
|
|
40222
|
+
* Render the coordinator system prompt for a mesh + CLI type, so the
|
|
40223
|
+
* dashboard can show the operator exactly what a coordinator session
|
|
40224
|
+
* receives by default. This resolves the mesh, applies its repo-mesh
|
|
40225
|
+
* config, and runs the SAME buildCoordinatorSystemPrompt the launch path
|
|
40226
|
+
* uses — minus the runtime-only best-effort sections (mission / recent
|
|
40227
|
+
* activity / operating notes), which are launch-scope and not part of the
|
|
40228
|
+
* static "default base" an operator is trying to preview here.
|
|
40229
|
+
*
|
|
40230
|
+
* It respects mesh-level and user-file override/append layering, so the
|
|
40231
|
+
* preview reflects the effective prompt: with no overrides configured it
|
|
40232
|
+
* shows the pure daemon default; with an override set it shows that.
|
|
40233
|
+
*/
|
|
40234
|
+
coordinator_prompt_preview: async (ctx, args) => {
|
|
40235
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
40236
|
+
const cliType = typeof args?.cliType === "string" && args.cliType.trim() ? args.cliType.trim() : "claude-cli";
|
|
40237
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
40238
|
+
try {
|
|
40239
|
+
let mesh = null;
|
|
40240
|
+
if (ctx.getMeshForCommand) {
|
|
40241
|
+
const resolved = await ctx.getMeshForCommand(meshId);
|
|
40242
|
+
mesh = resolved?.mesh ?? null;
|
|
40243
|
+
}
|
|
40244
|
+
if (!mesh) {
|
|
40245
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
40246
|
+
mesh = getMesh2(meshId);
|
|
40247
|
+
}
|
|
40248
|
+
if (!mesh) return { success: false, error: `mesh not found: ${meshId}` };
|
|
40249
|
+
let effectiveMesh = mesh;
|
|
40250
|
+
try {
|
|
40251
|
+
const { loadRepoMeshJsonConfig: loadRepoMeshJsonConfig2, applyRepoMeshConfig: applyRepoMeshConfig2 } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
|
|
40252
|
+
const workspace = typeof mesh?.workspace === "string" ? mesh.workspace : void 0;
|
|
40253
|
+
if (workspace) {
|
|
40254
|
+
const loaded = loadRepoMeshJsonConfig2(workspace);
|
|
40255
|
+
if (loaded?.sourceType !== "invalid") {
|
|
40256
|
+
effectiveMesh = applyRepoMeshConfig2(mesh, loaded?.config);
|
|
40257
|
+
}
|
|
40258
|
+
}
|
|
40259
|
+
} catch {
|
|
40260
|
+
}
|
|
40261
|
+
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
40262
|
+
const prompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType });
|
|
40263
|
+
return { success: true, prompt, cliType, meshId, bytes: Buffer.byteLength(prompt, "utf8") };
|
|
40264
|
+
} catch (error) {
|
|
40265
|
+
return { success: false, error: error?.message || String(error) };
|
|
40266
|
+
}
|
|
40267
|
+
},
|
|
40182
40268
|
list_coordinator_prompts: async (_ctx, _args) => {
|
|
40183
40269
|
const fs41 = await import("fs");
|
|
40184
40270
|
const path45 = await import("path");
|
|
@@ -54816,13 +54902,15 @@ var meshCrudHandlers = {
|
|
|
54816
54902
|
const daemonId = typeof args?.daemonId === "string" && args.daemonId.trim() ? args.daemonId.trim() : void 0;
|
|
54817
54903
|
const machineId = typeof args?.machineId === "string" && args.machineId.trim() ? args.machineId.trim() : void 0;
|
|
54818
54904
|
const repoRoot = typeof args?.repoRoot === "string" && args.repoRoot.trim() ? args.repoRoot.trim() : void 0;
|
|
54905
|
+
const capabilities = Array.isArray(args?.capabilities) ? args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean) : void 0;
|
|
54819
54906
|
const node = addNode2(meshId, {
|
|
54820
54907
|
workspace,
|
|
54821
54908
|
...repoRoot ? { repoRoot } : {},
|
|
54822
54909
|
...daemonId ? { daemonId } : {},
|
|
54823
54910
|
...machineId ? { machineId } : {},
|
|
54824
54911
|
...policy ? { policy } : {},
|
|
54825
|
-
...role ? { role } : {}
|
|
54912
|
+
...role ? { role } : {},
|
|
54913
|
+
...capabilities && capabilities.length ? { capabilities } : {}
|
|
54826
54914
|
});
|
|
54827
54915
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
54828
54916
|
ctx.invalidateAggregateMeshStatus(meshId);
|
|
@@ -54864,6 +54952,9 @@ var meshCrudHandlers = {
|
|
|
54864
54952
|
} else if (args?.systemPrompt === null) {
|
|
54865
54953
|
patch.systemPrompt = void 0;
|
|
54866
54954
|
}
|
|
54955
|
+
if (Array.isArray(args?.capabilities)) {
|
|
54956
|
+
patch.capabilities = args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean);
|
|
54957
|
+
}
|
|
54867
54958
|
const node = updateNode2(meshId, nodeId, patch);
|
|
54868
54959
|
if (!node) return { success: false, error: "Mesh node not found" };
|
|
54869
54960
|
ctx.invalidateAggregateMeshStatus(meshId);
|