@adhdev/daemon-standalone 1.0.56-rc.4 → 1.0.56-rc.5
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 +131 -80
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/vendor/mcp-server/index.js +45 -10
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -36620,10 +36620,10 @@ var require_dist3 = __commonJS({
|
|
|
36620
36620
|
}
|
|
36621
36621
|
function getDaemonBuildInfo() {
|
|
36622
36622
|
if (cached2) return cached2;
|
|
36623
|
-
const commit = readInjected(true ? "
|
|
36624
|
-
const commitShort = readInjected(true ? "
|
|
36625
|
-
const version2 = readInjected(true ? "1.0.56-rc.
|
|
36626
|
-
const builtAt = readInjected(true ? "2026-08-
|
|
36623
|
+
const commit = readInjected(true ? "d41089a0d560d75e670a90d3c4e9955bf955bbbc" : void 0) ?? "unknown";
|
|
36624
|
+
const commitShort = readInjected(true ? "d41089a0" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
36625
|
+
const version2 = readInjected(true ? "1.0.56-rc.5" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
36626
|
+
const builtAt = readInjected(true ? "2026-08-19T05:42:19.473Z" : void 0);
|
|
36627
36627
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
36628
36628
|
return cached2;
|
|
36629
36629
|
}
|
|
@@ -42852,8 +42852,9 @@ ${error48.message || ""}`;
|
|
|
42852
42852
|
CANONICAL_MESH_TOOL_NAMES = [
|
|
42853
42853
|
"mesh_status",
|
|
42854
42854
|
"mesh_list_nodes",
|
|
42855
|
-
|
|
42855
|
+
// GRAPH-ORCHESTRATION Phase F — batch before task, mirroring ALL_MESH_TOOLS.
|
|
42856
42856
|
"mesh_enqueue_batch",
|
|
42857
|
+
"mesh_enqueue_task",
|
|
42857
42858
|
"mesh_view_queue",
|
|
42858
42859
|
// GRAPH-ORCHESTRATION Phase E — the coordinator gate + graph view surface.
|
|
42859
42860
|
"mesh_graph_view",
|
|
@@ -52427,62 +52428,6 @@ ${blocks.join("\n\n")}`;
|
|
|
52427
52428
|
MAX_CLONE_CHAIN = 16;
|
|
52428
52429
|
}
|
|
52429
52430
|
});
|
|
52430
|
-
function loadDatabaseCtor() {
|
|
52431
|
-
if (DatabaseCtor) return DatabaseCtor;
|
|
52432
|
-
DatabaseCtor = loadBetterSqlite3();
|
|
52433
|
-
return DatabaseCtor;
|
|
52434
|
-
}
|
|
52435
|
-
function safeMeshId(meshId) {
|
|
52436
|
-
return meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
52437
|
-
}
|
|
52438
|
-
function legacyQueuePath(meshId) {
|
|
52439
|
-
return (0, import_path6.join)(getLedgerDir2(), `${safeMeshId(meshId)}.queue.json`);
|
|
52440
|
-
}
|
|
52441
|
-
function cleanupStrayRootRuntimeDb(canonicalPath2) {
|
|
52442
|
-
try {
|
|
52443
|
-
const strayPath = (0, import_path6.join)(getConfigDir2(), "mesh-runtime.db");
|
|
52444
|
-
if (strayPath === canonicalPath2) return;
|
|
52445
|
-
if (!(0, import_fs6.existsSync)(strayPath)) return;
|
|
52446
|
-
if ((0, import_fs6.statSync)(strayPath).size !== 0) return;
|
|
52447
|
-
(0, import_fs6.unlinkSync)(strayPath);
|
|
52448
|
-
if (!loggedStrayCleanup) {
|
|
52449
|
-
loggedStrayCleanup = true;
|
|
52450
|
-
LOG2.info("MeshRuntimeStore", `Removed stray 0-byte root mesh-runtime.db at ${strayPath}`);
|
|
52451
|
-
}
|
|
52452
|
-
} catch (err) {
|
|
52453
|
-
if (!loggedStrayCleanup) {
|
|
52454
|
-
loggedStrayCleanup = true;
|
|
52455
|
-
LOG2.warn("MeshRuntimeStore", `Stray root mesh-runtime.db cleanup failed (ignored): ${err?.message || err}`);
|
|
52456
|
-
}
|
|
52457
|
-
}
|
|
52458
|
-
}
|
|
52459
|
-
function meshRuntimeStorePath() {
|
|
52460
|
-
const dir = getLedgerDir2();
|
|
52461
|
-
const nextPath = (0, import_path6.join)(dir, "mesh-runtime.db");
|
|
52462
|
-
cleanupStrayRootRuntimeDb(nextPath);
|
|
52463
|
-
if ((0, import_fs6.existsSync)(nextPath)) return nextPath;
|
|
52464
|
-
const legacyPath = (0, import_path6.join)(dir, "beads.db");
|
|
52465
|
-
if (!(0, import_fs6.existsSync)(legacyPath)) return nextPath;
|
|
52466
|
-
try {
|
|
52467
|
-
(0, import_fs6.renameSync)(legacyPath, nextPath);
|
|
52468
|
-
for (const suffix of ["-wal", "-shm"]) {
|
|
52469
|
-
const legacyCompanion = `${legacyPath}${suffix}`;
|
|
52470
|
-
if ((0, import_fs6.existsSync)(legacyCompanion)) {
|
|
52471
|
-
(0, import_fs6.renameSync)(legacyCompanion, `${nextPath}${suffix}`);
|
|
52472
|
-
}
|
|
52473
|
-
}
|
|
52474
|
-
} catch (err) {
|
|
52475
|
-
if (!loggedMigrationFailure) {
|
|
52476
|
-
loggedMigrationFailure = true;
|
|
52477
|
-
LOG2.warn(
|
|
52478
|
-
"MeshRuntimeStore",
|
|
52479
|
-
`Legacy beads.db\u2192mesh-runtime.db migration failed; using existing DB in-place to avoid data loss: ${err?.message || err}`
|
|
52480
|
-
);
|
|
52481
|
-
}
|
|
52482
|
-
return (0, import_fs6.existsSync)(nextPath) ? nextPath : legacyPath;
|
|
52483
|
-
}
|
|
52484
|
-
return nextPath;
|
|
52485
|
-
}
|
|
52486
52431
|
function meshTurnAttemptFromRow(r) {
|
|
52487
52432
|
return {
|
|
52488
52433
|
attemptId: r.attempt_id,
|
|
@@ -52540,15 +52485,82 @@ ${blocks.join("\n\n")}`;
|
|
|
52540
52485
|
return { ledger: 0, toolCalls: 0, terminalQueue: 0, sessionDelivery: 0 };
|
|
52541
52486
|
}
|
|
52542
52487
|
}
|
|
52488
|
+
var MESH_EVENT_LEDGER_RETENTION_MS;
|
|
52489
|
+
var MESH_TOOL_CALL_LOG_RETENTION_MS;
|
|
52490
|
+
var MESH_TERMINAL_QUEUE_RETENTION_MS;
|
|
52491
|
+
var init_mesh_runtime_store_turn_rows = __esm2({
|
|
52492
|
+
"src/mesh/mesh-runtime-store-turn-rows.ts"() {
|
|
52493
|
+
"use strict";
|
|
52494
|
+
init_logger();
|
|
52495
|
+
init_mesh_retention_config();
|
|
52496
|
+
init_mesh_runtime_store();
|
|
52497
|
+
MESH_EVENT_LEDGER_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
52498
|
+
MESH_TOOL_CALL_LOG_RETENTION_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
52499
|
+
MESH_TERMINAL_QUEUE_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
52500
|
+
}
|
|
52501
|
+
});
|
|
52502
|
+
function loadDatabaseCtor() {
|
|
52503
|
+
if (DatabaseCtor) return DatabaseCtor;
|
|
52504
|
+
DatabaseCtor = loadBetterSqlite3();
|
|
52505
|
+
return DatabaseCtor;
|
|
52506
|
+
}
|
|
52507
|
+
function safeMeshId(meshId) {
|
|
52508
|
+
return meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
52509
|
+
}
|
|
52510
|
+
function legacyQueuePath(meshId) {
|
|
52511
|
+
return (0, import_path6.join)(getLedgerDir2(), `${safeMeshId(meshId)}.queue.json`);
|
|
52512
|
+
}
|
|
52513
|
+
function cleanupStrayRootRuntimeDb(canonicalPath2) {
|
|
52514
|
+
try {
|
|
52515
|
+
const strayPath = (0, import_path6.join)(getConfigDir2(), "mesh-runtime.db");
|
|
52516
|
+
if (strayPath === canonicalPath2) return;
|
|
52517
|
+
if (!(0, import_fs6.existsSync)(strayPath)) return;
|
|
52518
|
+
if ((0, import_fs6.statSync)(strayPath).size !== 0) return;
|
|
52519
|
+
(0, import_fs6.unlinkSync)(strayPath);
|
|
52520
|
+
if (!loggedStrayCleanup) {
|
|
52521
|
+
loggedStrayCleanup = true;
|
|
52522
|
+
LOG2.info("MeshRuntimeStore", `Removed stray 0-byte root mesh-runtime.db at ${strayPath}`);
|
|
52523
|
+
}
|
|
52524
|
+
} catch (err) {
|
|
52525
|
+
if (!loggedStrayCleanup) {
|
|
52526
|
+
loggedStrayCleanup = true;
|
|
52527
|
+
LOG2.warn("MeshRuntimeStore", `Stray root mesh-runtime.db cleanup failed (ignored): ${err?.message || err}`);
|
|
52528
|
+
}
|
|
52529
|
+
}
|
|
52530
|
+
}
|
|
52531
|
+
function meshRuntimeStorePath() {
|
|
52532
|
+
const dir = getLedgerDir2();
|
|
52533
|
+
const nextPath = (0, import_path6.join)(dir, "mesh-runtime.db");
|
|
52534
|
+
cleanupStrayRootRuntimeDb(nextPath);
|
|
52535
|
+
if ((0, import_fs6.existsSync)(nextPath)) return nextPath;
|
|
52536
|
+
const legacyPath = (0, import_path6.join)(dir, "beads.db");
|
|
52537
|
+
if (!(0, import_fs6.existsSync)(legacyPath)) return nextPath;
|
|
52538
|
+
try {
|
|
52539
|
+
(0, import_fs6.renameSync)(legacyPath, nextPath);
|
|
52540
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
52541
|
+
const legacyCompanion = `${legacyPath}${suffix}`;
|
|
52542
|
+
if ((0, import_fs6.existsSync)(legacyCompanion)) {
|
|
52543
|
+
(0, import_fs6.renameSync)(legacyCompanion, `${nextPath}${suffix}`);
|
|
52544
|
+
}
|
|
52545
|
+
}
|
|
52546
|
+
} catch (err) {
|
|
52547
|
+
if (!loggedMigrationFailure) {
|
|
52548
|
+
loggedMigrationFailure = true;
|
|
52549
|
+
LOG2.warn(
|
|
52550
|
+
"MeshRuntimeStore",
|
|
52551
|
+
`Legacy beads.db\u2192mesh-runtime.db migration failed; using existing DB in-place to avoid data loss: ${err?.message || err}`
|
|
52552
|
+
);
|
|
52553
|
+
}
|
|
52554
|
+
return (0, import_fs6.existsSync)(nextPath) ? nextPath : legacyPath;
|
|
52555
|
+
}
|
|
52556
|
+
return nextPath;
|
|
52557
|
+
}
|
|
52543
52558
|
var import_fs6;
|
|
52544
52559
|
var import_path6;
|
|
52545
52560
|
var DatabaseCtor;
|
|
52546
52561
|
var loggedMigrationFailure;
|
|
52547
52562
|
var loggedStrayCleanup;
|
|
52548
52563
|
var MeshRuntimeStore;
|
|
52549
|
-
var MESH_EVENT_LEDGER_RETENTION_MS;
|
|
52550
|
-
var MESH_TOOL_CALL_LOG_RETENTION_MS;
|
|
52551
|
-
var MESH_TERMINAL_QUEUE_RETENTION_MS;
|
|
52552
52564
|
var init_mesh_runtime_store = __esm2({
|
|
52553
52565
|
"src/mesh/mesh-runtime-store.ts"() {
|
|
52554
52566
|
"use strict";
|
|
@@ -52558,13 +52570,14 @@ ${blocks.join("\n\n")}`;
|
|
|
52558
52570
|
init_load_better_sqlite3();
|
|
52559
52571
|
init_config();
|
|
52560
52572
|
init_mesh_ledger();
|
|
52561
|
-
init_mesh_retention_config();
|
|
52562
52573
|
init_mesh_work_queue();
|
|
52563
52574
|
init_mesh_graph_schema();
|
|
52564
52575
|
init_mesh_graph_store();
|
|
52565
52576
|
init_slot_model_enforcement();
|
|
52566
52577
|
init_mesh_daemon_slot_axis();
|
|
52567
52578
|
init_dist();
|
|
52579
|
+
init_mesh_runtime_store_turn_rows();
|
|
52580
|
+
init_mesh_runtime_store_turn_rows();
|
|
52568
52581
|
loggedMigrationFailure = false;
|
|
52569
52582
|
loggedStrayCleanup = false;
|
|
52570
52583
|
MeshRuntimeStore = class _MeshRuntimeStore {
|
|
@@ -52760,6 +52773,7 @@ ${blocks.join("\n\n")}`;
|
|
|
52760
52773
|
mesh_id TEXT NOT NULL,
|
|
52761
52774
|
tool TEXT NOT NULL,
|
|
52762
52775
|
session_id TEXT,
|
|
52776
|
+
caller_role TEXT,
|
|
52763
52777
|
called_at INTEGER NOT NULL
|
|
52764
52778
|
);
|
|
52765
52779
|
|
|
@@ -53089,6 +53103,10 @@ ${blocks.join("\n\n")}`;
|
|
|
53089
53103
|
ON mesh_event_ledger(mesh_id, task_id, timestamp)
|
|
53090
53104
|
WHERE task_id IS NOT NULL
|
|
53091
53105
|
`);
|
|
53106
|
+
const toolCallCols = this.tableColumns("mesh_tool_call_log");
|
|
53107
|
+
if (!toolCallCols.has("caller_role")) {
|
|
53108
|
+
this.db.exec(`ALTER TABLE mesh_tool_call_log ADD COLUMN caller_role TEXT`);
|
|
53109
|
+
}
|
|
53092
53110
|
} catch (err) {
|
|
53093
53111
|
if (!loggedMigrationFailure) {
|
|
53094
53112
|
loggedMigrationFailure = true;
|
|
@@ -54022,16 +54040,23 @@ ${blocks.join("\n\n")}`;
|
|
|
54022
54040
|
* Returns a rate-limit advisory string when the call rate is too high, null otherwise.
|
|
54023
54041
|
* windowMs: sliding window size in ms (default 10s)
|
|
54024
54042
|
* maxCalls: max allowed calls within the window (default 5)
|
|
54043
|
+
*
|
|
54044
|
+
* `callerRole` is a diagnostic, not an auth boundary: it reflects whether
|
|
54045
|
+
* ADHDEV_COORDINATOR_SESSION_ID was present in this process's env at call
|
|
54046
|
+
* time, and a process can set that env var on itself. It exists to answer
|
|
54047
|
+
* "was this call made by a coordinator-launched process or not" for the
|
|
54048
|
+
* mesh-tool-call-caller-instrumentation investigation, not to gate access —
|
|
54049
|
+
* do not wire it into any block/allow decision.
|
|
54025
54050
|
*/
|
|
54026
54051
|
recordMeshToolCall(opts) {
|
|
54027
|
-
const { meshId, tool, sessionId = null } = opts;
|
|
54052
|
+
const { meshId, tool, sessionId = null, callerRole = null } = opts;
|
|
54028
54053
|
const windowMs = opts.windowMs ?? 1e4;
|
|
54029
54054
|
const maxCalls = opts.maxCalls ?? 5;
|
|
54030
54055
|
const now = Date.now();
|
|
54031
54056
|
const windowStart = now - windowMs;
|
|
54032
54057
|
this.db.prepare(
|
|
54033
|
-
"INSERT INTO mesh_tool_call_log (mesh_id, tool, session_id, called_at) VALUES (?, ?, ?, ?)"
|
|
54034
|
-
).run(meshId, tool, sessionId, now);
|
|
54058
|
+
"INSERT INTO mesh_tool_call_log (mesh_id, tool, session_id, caller_role, called_at) VALUES (?, ?, ?, ?, ?)"
|
|
54059
|
+
).run(meshId, tool, sessionId, callerRole, now);
|
|
54035
54060
|
const row = this.db.prepare(
|
|
54036
54061
|
"SELECT COUNT(*) as cnt FROM mesh_tool_call_log WHERE mesh_id = ? AND tool = ? AND called_at >= ?"
|
|
54037
54062
|
).get(meshId, tool, windowStart);
|
|
@@ -54057,6 +54082,18 @@ ${blocks.join("\n\n")}`;
|
|
|
54057
54082
|
pruneToolCallLog(olderThanMs) {
|
|
54058
54083
|
return this.db.prepare("DELETE FROM mesh_tool_call_log WHERE called_at < ?").run(Date.now() - olderThanMs).changes;
|
|
54059
54084
|
}
|
|
54085
|
+
/**
|
|
54086
|
+
* Read back recent mesh_tool_call_log rows for one mesh, most recent first.
|
|
54087
|
+
* Diagnostic reader for the MESH-TOOL-CALL-CALLER-INSTRUMENTATION 1단계
|
|
54088
|
+
* investigation (was session_id/caller_role actually getting recorded, and
|
|
54089
|
+
* does the coordinator/unknown split hold up) — not on any hot path.
|
|
54090
|
+
*/
|
|
54091
|
+
getRecentToolCalls(meshId, limit = 100) {
|
|
54092
|
+
const rows = this.db.prepare(
|
|
54093
|
+
"SELECT tool, session_id, caller_role, called_at FROM mesh_tool_call_log WHERE mesh_id = ? ORDER BY called_at DESC LIMIT ?"
|
|
54094
|
+
).all(meshId, limit);
|
|
54095
|
+
return rows.map((r) => ({ tool: r.tool, sessionId: r.session_id, callerRole: r.caller_role, calledAt: r.called_at }));
|
|
54096
|
+
}
|
|
54060
54097
|
/**
|
|
54061
54098
|
* Retention prune for mesh_event_ledger (SoT 1-11 (b)). The ledger is append-only
|
|
54062
54099
|
* with NO lifecycle GC of its own, so lifecycle events accumulate without bound
|
|
@@ -55199,9 +55236,6 @@ ${blocks.join("\n\n")}`;
|
|
|
55199
55236
|
return res.changes > 0;
|
|
55200
55237
|
}
|
|
55201
55238
|
};
|
|
55202
|
-
MESH_EVENT_LEDGER_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
55203
|
-
MESH_TOOL_CALL_LOG_RETENTION_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
55204
|
-
MESH_TERMINAL_QUEUE_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
55205
55239
|
}
|
|
55206
55240
|
});
|
|
55207
55241
|
var mesh_ledger_exports = {};
|
|
@@ -56755,7 +56789,7 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
56755
56789
|
const lines = [
|
|
56756
56790
|
"## Task difficulty",
|
|
56757
56791
|
"",
|
|
56758
|
-
"Pass `difficulty` on `mesh_enqueue_task` (`easy` / `medium` / `difficult` / `freeform`)
|
|
56792
|
+
"Pass `difficulty` on every worker entry in `mesh_enqueue_batch`, or on `mesh_enqueue_task` for the single-task fallback. The values (`easy` / `medium` / `difficult` / `freeform`) describe how hard the work is. It is a ROUTING HINT: it is matched against each node's capability slots, so a task goes to a slot configured for that difficulty.",
|
|
56759
56793
|
"",
|
|
56760
56794
|
'**The slot decides the model and thinking level \u2014 not the difficulty.** `difficulty: "difficult"` does not mean "use opus"; it means "route to a slot that handles difficult work", and that slot\'s own model/thinking is what launches. So classify honestly by how hard the task is, and change what a difficulty RUNS ON by editing the node\'s slots (`mesh_node_slots_set`), never by picking a different difficulty. Passing an explicit `model`/`thinkingLevel` still overrides everything for one task.'
|
|
56761
56795
|
];
|
|
@@ -56839,8 +56873,8 @@ ${rules.join("\n")}`;
|
|
|
56839
56873
|
return `## Rules
|
|
56840
56874
|
|
|
56841
56875
|
- **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. See also: **Never use local sub-agents** below.${destructiveGitRule}
|
|
56842
|
-
- **Never use local sub-agents.** Do NOT spawn your runtime's own sub-agents (e.g. Claude Code's Task/Explore/Agent tools, or any equivalent in-process agent-spawning tool) to read code, investigate, run RCA, or implement. Such sub-agents execute on the coordinator's machine, outside the mesh \u2014 they escape mesh parallelism, the ledger/audit trail, node capability profiles, and worktree isolation, and leave no \`mesh_task_history\` record. ALL code reading, analysis, RCA, and implementation must be delegated
|
|
56843
|
-
- **Front-load task
|
|
56876
|
+
- **Never use local sub-agents.** Do NOT spawn your runtime's own sub-agents (e.g. Claude Code's Task/Explore/Agent tools, or any equivalent in-process agent-spawning tool) to read code, investigate, run RCA, or implement. Such sub-agents execute on the coordinator's machine, outside the mesh \u2014 they escape mesh parallelism, the ledger/audit trail, node capability profiles, and worktree isolation, and leave no \`mesh_task_history\` record. ALL code reading, analysis, RCA, and implementation must be delegated through \`mesh_enqueue_batch\` for a currently known multi-step graph, \`mesh_enqueue_task\` for one ready task, or \`mesh_send_task\` for a same-session continuation (use \`task_mode: "live_debug_readonly"\` for read-only investigation), or cross-verified via \`mesh_magi_review\` for read-only fan-out. The coordinator's own actions are limited to \`mesh_*\` tool orchestration and synthesizing results.
|
|
56877
|
+
- **Front-load immutable task instructions.** Include everything the agent needs (files, problem, expected fix) in \`mesh_enqueue_batch\` / \`mesh_enqueue_task\` / \`mesh_send_task\`. Put predecessor-produced data in explicit \`inputs_from\` bindings and coordinator decisions in gates; never copy untrusted worker output into a new instruction by hand when a binding can preserve provenance. 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\`.
|
|
56844
56878
|
- **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 a fresh session only when: (a) branch/worktree isolation is required, (b) the existing session had a dispatch failure or provider mismatch, (c) the transcript/runtime is contaminated or interrupted, (d) the user explicitly asks for a different provider/session, or (e) **the delta is a genuinely NEW subject rather than a continuation** \u2014 a new topic appended to an existing session can be dropped or re-run as the previous task, so give it its own task even when a session sits idle. Continuation of the same issue in an already-idle session is allowed and preferred \u2014 this rule blocks concurrent unrelated work interleaved into a live (still-generating) session, not sequential same-issue follow-ups. The test is subject continuity, not timing: carrying an investigation forward into its own fix is the SAME subject and belongs in that session (Workflow 3f), while an unrelated bug is a new subject even if the same session just went idle.
|
|
56845
56879
|
- **Nodes are separate machines with separate checkouts \u2014 not interchangeable execution slots.** Each node is a different physical computer with its own clone of the repo. Work done on another node must be committed, pushed, and pulled back before this machine sees it, and since RELEASE/DEPLOY runs on the coordinator's own machine, sending a code change elsewhere buys a round trip out and another one back. So **default to this coordinator's own machine for code changes** \u2014 its local node (base or a worktree cloned from it). Routing to a DIFFERENT machine is the exception and needs a reason, of which there are exactly two: (a) **platform-specific verification** that cannot be done here \u2014 win32 PATH/registry, a clean install/uninstall on that OS, that machine's package-manager state; or (b) **parallelizing read-only investigation** across machines. "That node is idle" is not a reason. If you catch yourself dispatching a fix to another machine without (a) or (b), route it here instead.
|
|
56846
56880
|
- **Don't split investigation from the fix.** When a task will plainly end in a code change, dispatch it as \`code_change\` from the start \u2014 the in-session handoff and split criteria live in Workflow 3f. Split only when the fix genuinely belongs on another machine for reason (a) above; redoing an investigator's context in a fresh session (worse, on another machine) is pure loss.
|
|
@@ -56904,8 +56938,8 @@ When you compose the task message you dispatch to a node, include this requireme
|
|
|
56904
56938
|
|------|---------|
|
|
56905
56939
|
| \`mesh_status\` | Nodes' health, git state, sessions, branch convergence |
|
|
56906
56940
|
| \`mesh_list_nodes\` | List nodes with workspace paths |
|
|
56907
|
-
| \`
|
|
56908
|
-
| \`
|
|
56941
|
+
| \`mesh_enqueue_batch\` | **DEFAULT enqueue surface** for a plan with two or more known graph steps. Atomically enqueues a dependency-wired task set; \`depends_on\` may name batch-local \`ref\`s (forward refs OK). Carries the full graph surface: \`inputs_from\`, \`run_if\`, \`gates\` + \`gated_by\`, \`workspaces\` + \`workspace_ref\` |
|
|
56942
|
+
| \`mesh_enqueue_task\` | SINGLE-TASK FALLBACK \u2014 one ready task with no declarable downstream step; idle nodes auto-claim |
|
|
56909
56943
|
| \`mesh_view_queue\` | Queue status \u2014 pending/assigned/completed/failed/cancelled |
|
|
56910
56944
|
| \`mesh_graph_view\` | Inspect orchestration graphs \u2014 node states, gates awaiting you, workspace sagas, why something is blocked |
|
|
56911
56945
|
| \`mesh_graph_gate_claim\` | Take the lease on a gate awaiting a coordinator; returns the fencing token + generation a release needs |
|
|
@@ -56962,6 +56996,8 @@ When you compose the task message you dispatch to a node, include this requireme
|
|
|
56962
56996
|
| \`mesh_coordinator_prompt_append_set\` | Write/clear that APPEND (append-only; base prompt is not replaceable) |`;
|
|
56963
56997
|
TOOL_EXPOSURE_PREFLIGHT_SECTION = `## Tool Exposure Preflight
|
|
56964
56998
|
|
|
56999
|
+
Before searching for an enqueue tool, classify the whole currently known work frontier. For every new delegation search, include \`mesh_enqueue_batch\` by exact name; never search for or load only \`mesh_enqueue_task\`. Load \`mesh_enqueue_task\` only as the single-task fallback after the batch eligibility check below fails.
|
|
57000
|
+
|
|
56965
57001
|
Before doing any coordinator work, confirm that the actual callable tool list includes \`mesh_status\` and the other \`mesh_*\` tools from the table above. If this Repo Mesh coordinator prompt is present but the callable \`mesh_*\` tools are missing, the MCP server/tool manifest is stale or not injected yet. Do not substitute terminal/file/git tools, do not inspect or edit the repository directly, and do not continue as a non-mesh local coding agent. Stop immediately and tell the user to run \`/reload-mcp\` or start a fresh coordinator session so ADHDev can reconnect \`adhdev-mesh\`.`;
|
|
56966
57002
|
QUOTA_SECTION = `## Provider Quota
|
|
56967
57003
|
|
|
@@ -56972,9 +57008,15 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
56972
57008
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
56973
57009
|
|
|
56974
57010
|
1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available. Check \`mesh_task_history\` to understand what has already been done in this mesh \u2014 previous delegations, completions, and failures.
|
|
56975
|
-
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist. If \`mesh_task_history\` shows a recent failure for a task, decide whether to retry or reassign. **For multi-task work, create a mission first**: call \`mesh_mission_upsert\` with a title and goal, then attach every enqueued task with \`mission_id\`. Express "B after A" ordering with \`depends_on\`
|
|
57011
|
+
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist. If \`mesh_task_history\` shows a recent failure for a task, decide whether to retry or reassign. **For multi-task work, create a mission first**: call \`mesh_mission_upsert\` with a title and goal, then attach every enqueued task with \`mission_id\`. Express "B after A" ordering with \`depends_on\` instead of waiting and polling \u2014 the system claims dependents automatically when their dependencies complete. When the mission's outcome is decided, update its status (\`completed\`/\`abandoned\`) via \`mesh_mission_upsert\`. If the prompt already shows an **Active Mission**, continue it from its current task state \u2014 do not re-enqueue tasks that already exist.
|
|
56976
57012
|
3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
|
|
56977
|
-
a. **
|
|
57013
|
+
a. **Batch-first rule:** submit one \`mesh_enqueue_batch\` whenever the currently known plan contains two or more graph steps. A graph may include worker tasks, selected predecessor outputs via \`inputs_from\`, declarative \`run_if\` branches, delayed \`workspace_ref\` preparation, and coordinator gates for approval, Refinery, CI waiting, publish, or deployment. Submit the whole materializable plan once; do not wait and enqueue each known step separately.
|
|
57014
|
+
|
|
57015
|
+
Use \`mesh_enqueue_task\` only when exactly one new worker task is currently known and there is no known downstream step to declare, or when continuing an already-running session via \`mesh_send_task\` is the correct same-subject handoff. If later work is genuinely unknown, enqueue the one ready task and start a new batch when the next frontier becomes known.
|
|
57016
|
+
|
|
57017
|
+
Do not invent speculative downstream instructions merely to form a batch. Use an \`inputs_from\` binding when the instruction is stable but needs predecessor evidence; use a coordinator gate when a human/coordinator decision or external side effect must happen first; use \`run_if\` for a structured result predicate. If none can state the future step faithfully, single-task enqueue is correct.
|
|
57018
|
+
|
|
57019
|
+
Either way, idle node agents automatically pull tasks from the queue and begin working. A batch inserts atomically (a mid-batch error such as a cycle or bad difficulty rolls the whole set back, so no half-registered chain), and each task's \`depends_on\` may name sibling tasks by their batch-local \`ref\` label, forward references included.
|
|
56978
57020
|
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. **A node is not limited to one live session for read-only work** \u2014 \`readonly\`/\`live_debug_readonly\` tasks are exempt from the one-active-per-node invariant, so the SAME node can auto-launch multiple concurrent read-only sessions with no worktree needed. Cloning a worktree costs roughly 10 seconds, so it is cheap enough to create one whenever write work needs a free node; use it for branch isolation, for parallel write tasks (one active write per node), or when a node's read-only queue is deep enough that a second node would clearly finish faster \u2014 call \`mesh_clone_node\` to create the worktree node first.
|
|
56979
57021
|
b0. **Base nodes are for environment-specific testing, not for general code changes.** Before dispatching any write task, answer ONE question: *does this task verify the physical environment of a specific machine or OS, or does it only change code?*
|
|
56980
57022
|
- **Physical-environment task \u2192 base node, targeted.** Pin it with \`required_tags\` (e.g. \`["os=win32"]\`) or \`target_node_id\`. Examples that genuinely require the real machine: verifying a win32 \`PATH\`/registry/installer layout, a clean-install or uninstall on a specific OS, Homebrew or package-manager state on one particular machine, an OS-dependent runtime behavior (path separators, process spawn, native bindings), or reproducing a bug reported only on that node. A worktree CANNOT substitute for these \u2014 the point is the machine itself.
|
|
@@ -85682,20 +85724,29 @@ ${e?.stderr || ""}`;
|
|
|
85682
85724
|
if (!fromNodeId) continue;
|
|
85683
85725
|
addEdge(fromNodeId, nodeIdByIndex[i], "requires", omitOnSkip);
|
|
85684
85726
|
}
|
|
85727
|
+
const gateRefsForNode = new Set((t.gated_by ?? []).map((r) => r.trim()).filter(Boolean));
|
|
85685
85728
|
for (const sourceRef of collectRunIfSourceRefs(t.run_if)) {
|
|
85686
85729
|
const fromNodeId = nodeIdByRef.get(sourceRef);
|
|
85687
85730
|
if (!fromNodeId || fromNodeId === nodeIdByIndex[i]) continue;
|
|
85731
|
+
if (gateNodeIdByRef.has(sourceRef)) {
|
|
85732
|
+
gateRefsForNode.add(sourceRef);
|
|
85733
|
+
continue;
|
|
85734
|
+
}
|
|
85688
85735
|
if (edges.some((e) => e.fromNodeId === fromNodeId && e.toNodeId === nodeIdByIndex[i])) continue;
|
|
85689
85736
|
addEdge(fromNodeId, nodeIdByIndex[i], "conditional", omitOnSkip);
|
|
85690
85737
|
}
|
|
85691
85738
|
for (const sourceRef of collectInputSourceRefs(t.inputs_from)) {
|
|
85692
85739
|
const fromNodeId = nodeIdByRef.get(sourceRef);
|
|
85693
85740
|
if (!fromNodeId || fromNodeId === nodeIdByIndex[i]) continue;
|
|
85741
|
+
if (gateNodeIdByRef.has(sourceRef)) {
|
|
85742
|
+
gateRefsForNode.add(sourceRef);
|
|
85743
|
+
continue;
|
|
85744
|
+
}
|
|
85694
85745
|
if (edges.some((e) => e.fromNodeId === fromNodeId && e.toNodeId === nodeIdByIndex[i] && e.kind === "requires")) continue;
|
|
85695
85746
|
addEdge(fromNodeId, nodeIdByIndex[i], "requires", omitOnSkip);
|
|
85696
85747
|
}
|
|
85697
|
-
for (const gateRef of
|
|
85698
|
-
const fromNodeId = gateNodeIdByRef.get(gateRef
|
|
85748
|
+
for (const gateRef of gateRefsForNode) {
|
|
85749
|
+
const fromNodeId = gateNodeIdByRef.get(gateRef);
|
|
85699
85750
|
if (!fromNodeId) continue;
|
|
85700
85751
|
addEdge(fromNodeId, nodeIdByIndex[i], "gate", false);
|
|
85701
85752
|
}
|