@adhdev/daemon-standalone 1.0.56-rc.5 → 1.0.56-rc.6
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 +104 -20
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/vendor/mcp-server/index.js +41 -4
- 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 ? "d143fc7369d10b184b4cad79ce3a4240bc811faf" : void 0) ?? "unknown";
|
|
36624
|
+
const commitShort = readInjected(true ? "d143fc73" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
36625
|
+
const version2 = readInjected(true ? "1.0.56-rc.6" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
36626
|
+
const builtAt = readInjected(true ? "2026-08-19T09:46:30.077Z" : void 0);
|
|
36627
36627
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
36628
36628
|
return cached2;
|
|
36629
36629
|
}
|
|
@@ -56873,11 +56873,12 @@ ${rules.join("\n")}`;
|
|
|
56873
56873
|
return `## Rules
|
|
56874
56874
|
|
|
56875
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}
|
|
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\`
|
|
56877
|
-
- **Front-load immutable task instructions.** Include everything the agent needs (files, problem, expected fix) in \`mesh_enqueue_batch\`
|
|
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\` (the default \u2014 see Workflow 3.a), falling back to \`mesh_enqueue_task\` only for a terminal single step, to \`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 whichever dispatch surface Workflow 3.a selects (\`mesh_enqueue_batch\` by default; \`mesh_enqueue_task\` / \`mesh_send_task\` in their narrower cases). 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\`.
|
|
56878
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.
|
|
56879
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.
|
|
56880
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.
|
|
56881
|
+
- **Batch is the default enqueue surface.** Apply Workflow 3.a: before every enqueue, ask whether you will read this task's result and then dispatch more work. If yes, that successor is declarable \u2014 submit the whole plan as one \`mesh_enqueue_batch\` with \`inputs_from\` / \`run_if\` / \`gated_by\`, rather than enqueueing a step, waiting, and enqueueing the next by hand. \`mesh_enqueue_task\` is the fallback for a genuinely terminal single step, and it takes an \`orchestration_decision\` stating which \`single_reason\` applies.
|
|
56881
56882
|
- **Base nodes are reserved for environment-specific testing.** Apply Workflow 3.b0: only work that verifies a machine's physical environment runs on a base node (pinned with \`required_tags\`/\`target_node_id\`); every ordinary \`code_change\` gets its own cloned worktree. Node availability is not branch isolation.
|
|
56882
56883
|
- **Worktree affinity.** Apply Workflow 3.b1: route a branch's follow-ups back to its own worktree node (\`required_tags: ["worktree=<branch>"]\` or \`target_node_id\`, taken from the \`mesh_clone_node\` result or a live \`mesh_status\`); only \`convergence\` (merge/push) runs base-side.
|
|
56883
56884
|
- **Classify task difficulty honestly.** Judge each task's real difficulty (\`easy\`/\`medium\`/\`difficult\`/\`freeform\`) per the Task difficulty section above \u2014 it is a routing hint, and the matched slot's own model/thinking is what launches. Never bend difficulty to chase a model; retune slots instead (\`mesh_node_slots_set\`).
|
|
@@ -56943,7 +56944,7 @@ When you compose the task message you dispatch to a node, include this requireme
|
|
|
56943
56944
|
| \`mesh_view_queue\` | Queue status \u2014 pending/assigned/completed/failed/cancelled |
|
|
56944
56945
|
| \`mesh_graph_view\` | Inspect orchestration graphs \u2014 node states, gates awaiting you, workspace sagas, why something is blocked |
|
|
56945
56946
|
| \`mesh_graph_gate_claim\` | Take the lease on a gate awaiting a coordinator; returns the fencing token + generation a release needs |
|
|
56946
|
-
| \`mesh_graph_gate_release\` | Pass a gate you hold \u2014 the ONLY way through one (no timeout ever passes a gate) |
|
|
56947
|
+
| \`mesh_graph_gate_release\` | Pass a gate you hold \u2014 the ONLY way through one (no timeout ever passes a gate). **A gate and its dependents are one unit**: a gate earns its keep only when some task names it in \`gated_by\`, because releasing it is what dispatches that task. A gate nothing depends on opens nothing and is pure claim/release overhead \u2014 declare the follower in the same batch, or skip the gate |
|
|
56947
56948
|
| \`mesh_queue_cancel\` | Cancel a queue task (audit history kept) |
|
|
56948
56949
|
| \`mesh_queue_requeue\` | Return a task to pending for retry |
|
|
56949
56950
|
| \`mesh_send_task\` | Push a task straight to a specific node/session |
|
|
@@ -57008,13 +57009,22 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
57008
57009
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
57009
57010
|
|
|
57010
57011
|
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.
|
|
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
|
|
57012
|
+
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 submit the plan as one \`mesh_enqueue_batch\` carrying that \`mission_id\` (a top-level \`mission_id\` applies to every entry). 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.
|
|
57012
57013
|
3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
|
|
57013
|
-
a. **Batch-first rule
|
|
57014
|
+
a. **Batch-first rule.** Before enqueueing anything, answer ONE question: *when this task reports back, will I read its result and then dispatch more work \u2014 or does the result go to the user with nothing behind it?*
|
|
57015
|
+
- **You will act on the result \u2192 \`mesh_enqueue_batch\`.** If you already intend to read the output and dispatch a next step, that next step is a step you can declare. Declare it: bind the evidence with \`inputs_from\`, branch on it with \`run_if\`, or put your own decision behind a coordinator gate and point the follower at it with \`gated_by\`. "I need to see the result first" is HOW a graph edge is expressed, not a reason to skip the graph \u2014 that is exactly what \`inputs_from\` and gates are for. An investigation you plan to act on is, by this test, a declarable two-step plan.
|
|
57016
|
+
- **The result goes to the user and nothing follows \u2192 \`mesh_enqueue_task\`.** One task, no successor you intend to dispatch yourself. Same-subject continuation of an already-running session is \`mesh_send_task\`, not a new enqueue either way.
|
|
57017
|
+
- Submit the whole materializable plan in ONE batch. A batch may mix worker tasks, \`inputs_from\` bindings, \`run_if\` branches, delayed \`workspace_ref\` preparation, and coordinator gates for approval, Refinery, CI waiting, publish, or deployment. Do not enqueue one known step, wait for it, and then enqueue the next known step by hand.
|
|
57018
|
+
- **A mesh with idle nodes or a short plan does not remove this requirement.** "It is only two steps" and "I will just enqueue the next one when this finishes" are the two ways the graph gets skipped; neither is a reason. Two declarable steps is precisely the case the batch surface exists for.
|
|
57019
|
+
- **"The only thing I am sure of right now is this one task" is not evidence of a single.** That feeling is about your confidence, not about how many steps are settled; two steps are routinely settled at once while it still feels that way. Count the steps you would actually dispatch. If that count is two or more, it is a batch no matter how the plan feels.
|
|
57020
|
+
- **"I cannot choose the next step until I see this result" states that the next step EXISTS.** What the result decides is *which branch you take*, not *whether* there is a follow-up \u2014 and a branch that turns on a predecessor's output is what \`run_if\` selects, what \`inputs_from\` feeds, and what a coordinator gate holds until you decide. Needing to look at evidence before choosing is the ordinary case for a graph edge, not an exception to it.
|
|
57021
|
+
- **A gate or a batch is not overhead when something follows it.** The extra call buys the dispatch of everything behind it, so it costs one call and saves a whole round-trip through you. The only genuinely wasteful gate is one nothing depends on \u2014 a gate no task names in \`gated_by\` opens nothing when released, which the release response tells you about; that case is answered by declaring the follower, not by abandoning the batch.
|
|
57014
57022
|
|
|
57015
|
-
|
|
57023
|
+
When you do use \`mesh_enqueue_task\`, pass \`orchestration_decision\` recording why a single was right (\`single_reason\`: \`only_one_step_known\` / \`future_step_not_specifiable\` / \`same_session_continuation\` / \`legacy_client\` / \`operator_override\`). Omitting it is recorded as \`decision_missing\`.
|
|
57016
57024
|
|
|
57017
|
-
Do not invent speculative downstream instructions merely to form a batch.
|
|
57025
|
+
Do not invent speculative downstream instructions merely to form a batch \u2014 a step you would not actually dispatch does not belong in the graph. But check the three declaration surfaces before concluding a step is unstatable: \`inputs_from\` when the instruction is stable and only needs predecessor evidence, a coordinator gate when a human/coordinator decision or external side effect must come first, \`run_if\` when the branch turns on a structured result predicate. Only when none of the three can state the future step faithfully is single-task enqueue correct.
|
|
57026
|
+
|
|
57027
|
+
**The line between the two failures.** The rebuttals above are aimed at declining to declare a step you already intend to dispatch; this guard is aimed at fabricating one you do not. They never both apply to the same step: the test is whether the step exists in your plan, not whether its details are settled. A step you intend to run but whose exact branch depends on evidence is KNOWN and belongs in the batch \u2014 that dependency is what the three surfaces express. A step you would have to make up to fill the batch is UNKNOWN and belongs nowhere. When you genuinely cannot tell which one you are looking at, enqueue the single and record \`future_step_not_specifiable\`; that is the honest answer and it is measured.
|
|
57018
57028
|
|
|
57019
57029
|
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.
|
|
57020
57030
|
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.
|
|
@@ -60537,9 +60547,11 @@ ${rendered}`, "utf-8");
|
|
|
60537
60547
|
const materializedNodeIds = advanceReleasedGateDownstream(store, gate, node, nowIso);
|
|
60538
60548
|
const freshNodes = graphStore.listNodes(gate.graphId);
|
|
60539
60549
|
const graph = graphStore.getGraph(gate.graphId);
|
|
60550
|
+
let graphCompleted = false;
|
|
60540
60551
|
if (graph && freshNodes.every(isTerminalEquivalent)) {
|
|
60541
60552
|
graphStore.updateGraphStatus(gate.graphId, "completed", nowIso, true);
|
|
60542
60553
|
insertGateOutbox(graphStore, gate.meshId, gate.graphId, "graph_completed", { graphId: gate.graphId }, nowIso);
|
|
60554
|
+
graphCompleted = true;
|
|
60543
60555
|
} else if (graph?.status === "waiting_gate") {
|
|
60544
60556
|
const stillWaiting = graphStore.listGatesByGraph(gate.graphId).some((g) => g.gateId !== gate.gateId && (g.state === "awaiting_coordinator" || g.state === "claimed"));
|
|
60545
60557
|
if (!stillWaiting) graphStore.updateGraphStatus(gate.graphId, "active", nowIso);
|
|
@@ -60563,7 +60575,16 @@ ${rendered}`, "utf-8");
|
|
|
60563
60575
|
gateId: gate.gateId
|
|
60564
60576
|
}, nowIso);
|
|
60565
60577
|
}
|
|
60566
|
-
return {
|
|
60578
|
+
return {
|
|
60579
|
+
released: true,
|
|
60580
|
+
duplicate: false,
|
|
60581
|
+
gate: graphStore.getGate(gate.gateId),
|
|
60582
|
+
materializedNodeIds,
|
|
60583
|
+
// Read from the edge set this release already walked — a gate with an empty
|
|
60584
|
+
// directDownstream is terminal, and terminal gates materialize nothing by design.
|
|
60585
|
+
downstreamNodeCount: directDownstream.size,
|
|
60586
|
+
graphCompleted
|
|
60587
|
+
};
|
|
60567
60588
|
});
|
|
60568
60589
|
try {
|
|
60569
60590
|
drainMeshGraphOutbox(input.meshId);
|
|
@@ -60824,6 +60845,18 @@ ${rendered}`, "utf-8");
|
|
|
60824
60845
|
...p.replayed ? { replayed: true } : {}
|
|
60825
60846
|
});
|
|
60826
60847
|
}
|
|
60848
|
+
function recordSingleEnqueueDecision(meshId, p) {
|
|
60849
|
+
safeAppend(meshId, "single_enqueue_decision", {
|
|
60850
|
+
taskId: p.taskId,
|
|
60851
|
+
enqueueSurface: "single",
|
|
60852
|
+
...p.missionId ? { missionId: p.missionId } : {},
|
|
60853
|
+
...p.coordinatorSessionId ? { coordinatorSessionId: p.coordinatorSessionId } : {},
|
|
60854
|
+
orchestrationDecision: p.decision,
|
|
60855
|
+
...p.decisionMissing ? { decisionMissing: true } : {},
|
|
60856
|
+
...p.declaredEligibleSingle ? { declaredEligibleSingle: true } : {},
|
|
60857
|
+
...p.batchCapabilityAvailable ? { batchCapabilityAvailable: p.batchCapabilityAvailable } : {}
|
|
60858
|
+
}, p.taskId);
|
|
60859
|
+
}
|
|
60827
60860
|
function recordGraphEnqueueValidationFailed(meshId, p) {
|
|
60828
60861
|
safeAppend(meshId, "graph_enqueue_validation_failed", {
|
|
60829
60862
|
code: p.code,
|
|
@@ -60881,6 +60914,7 @@ ${rendered}`, "utf-8");
|
|
|
60881
60914
|
}
|
|
60882
60915
|
var MESH_VALID_SINGLE_REASONS;
|
|
60883
60916
|
var MESH_SUPERSEDED_SINGLE_REASONS;
|
|
60917
|
+
var MESH_DECLARED_ELIGIBLE_SINGLE_HINT;
|
|
60884
60918
|
var init_mesh_graph_provenance = __esm2({
|
|
60885
60919
|
"src/mesh/mesh-graph-provenance.ts"() {
|
|
60886
60920
|
"use strict";
|
|
@@ -60898,6 +60932,7 @@ ${rendered}`, "utf-8");
|
|
|
60898
60932
|
"workspace_unresolved",
|
|
60899
60933
|
"coordinator_action_between"
|
|
60900
60934
|
];
|
|
60935
|
+
MESH_DECLARED_ELIGIBLE_SINGLE_HINT = "You declared known_graph_steps >= 2 but used the single-task surface. Submit the known steps as one mesh_enqueue_batch \u2014 its input bindings, conditions and coordinator gates declare the ones that need predecessor evidence, a condition, or a coordinator action \u2014 instead of enqueueing them one at a time.";
|
|
60901
60936
|
}
|
|
60902
60937
|
});
|
|
60903
60938
|
function turnProjectionActiveWorkStatus(meshId, taskId) {
|
|
@@ -61748,8 +61783,28 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61748
61783
|
}
|
|
61749
61784
|
};
|
|
61750
61785
|
}
|
|
61751
|
-
function
|
|
61752
|
-
|
|
61786
|
+
function liveLocalProviderEnablementForRouting(loader2, isLocalNode) {
|
|
61787
|
+
if (!loader2) return null;
|
|
61788
|
+
const verdicts = /* @__PURE__ */ new Map();
|
|
61789
|
+
return {
|
|
61790
|
+
isMachineProviderEnabled: (providerType) => loader2.isMachineProviderEnabled(providerType),
|
|
61791
|
+
isMachineQuotaEnabled: (providerType) => loader2.isMachineQuotaEnabled ? loader2.isMachineQuotaEnabled(providerType) : true,
|
|
61792
|
+
isLocalNode(node) {
|
|
61793
|
+
let verdict = verdicts.get(node);
|
|
61794
|
+
if (verdict === void 0) {
|
|
61795
|
+
verdict = !!node && isLocalNode(node) === true;
|
|
61796
|
+
verdicts.set(node, verdict);
|
|
61797
|
+
}
|
|
61798
|
+
return verdict;
|
|
61799
|
+
}
|
|
61800
|
+
};
|
|
61801
|
+
}
|
|
61802
|
+
function quotaFactsContextForLiveRouting(mesh, isLocalNode, providerLoader) {
|
|
61803
|
+
return {
|
|
61804
|
+
nodes: mesh?.nodes,
|
|
61805
|
+
liveLocalQuota: liveLocalQuotaForRouting(isLocalNode),
|
|
61806
|
+
providerEnablement: liveLocalProviderEnablementForRouting(providerLoader, isLocalNode)
|
|
61807
|
+
};
|
|
61753
61808
|
}
|
|
61754
61809
|
function directQuotaEntryFor(node, providerType) {
|
|
61755
61810
|
const facts = node?.nodeFacts;
|
|
@@ -61806,6 +61861,28 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61806
61861
|
const ageText = Number.isFinite(ageMs2) ? `${Math.round(ageMs2 / 6e4)}m` : "unparseable";
|
|
61807
61862
|
LOG2.info("MeshQuota", `QUOTA GATE: provider '${providerType}' on node ${nodeId} fails open \u2014 snapshot age ${ageText} exceeds the ${Math.round(staleAfterMs / 6e4)}m freshness threshold`);
|
|
61808
61863
|
}
|
|
61864
|
+
function classifyAbsentQuotaReason(node, providerType, context) {
|
|
61865
|
+
const enablement = context?.providerEnablement;
|
|
61866
|
+
if (!enablement) return "unclassified_remote";
|
|
61867
|
+
const sourceNode = cloneSourceNodeFor(node, context);
|
|
61868
|
+
if (!enablement.isLocalNode(node) && !(sourceNode !== void 0 && enablement.isLocalNode(sourceNode))) {
|
|
61869
|
+
return "unclassified_remote";
|
|
61870
|
+
}
|
|
61871
|
+
if (!enablement.isMachineProviderEnabled(providerType)) return "provider_disabled";
|
|
61872
|
+
if (!enablement.isMachineQuotaEnabled(providerType)) return "probe_disabled";
|
|
61873
|
+
return "not_measured";
|
|
61874
|
+
}
|
|
61875
|
+
function logAbsentQuotaFailOpen(node, providerType, policy, now, context) {
|
|
61876
|
+
const staleAfterMs = resolveQuotaRoutingPolicy(policy).staleAfterMs;
|
|
61877
|
+
const nodeId = typeof node?.nodeId === "string" && node.nodeId ? node.nodeId : typeof node?.id === "string" && node.id ? node.id : "unknown";
|
|
61878
|
+
const key2 = `${nodeId} ${providerType}`;
|
|
61879
|
+
const last = absentFailOpenLoggedAt.get(key2);
|
|
61880
|
+
if (last !== void 0 && now - last < staleAfterMs) return;
|
|
61881
|
+
absentFailOpenLoggedAt.set(key2, now);
|
|
61882
|
+
const reason = classifyAbsentQuotaReason(node, providerType, context);
|
|
61883
|
+
const reasonText = reason === "probe_disabled" ? "quota probing is disabled for this provider on this machine (quotaEnabled: false \u2014 an intended opt-out, not a fault)" : reason === "provider_disabled" ? "this provider is not enabled on this machine" : reason === "not_measured" ? "no snapshot has been measured yet" : "this daemon cannot read that node's machineProviders config (remote node, or its own daemon has not injected one) \u2014 cannot tell not-yet-measured from an opt-out; check the owning node's config directly";
|
|
61884
|
+
LOG2.info("MeshQuota", `QUOTA GATE: provider '${providerType}' on node ${nodeId} fails open \u2014 no quota entry (${reason}: ${reasonText})`);
|
|
61885
|
+
}
|
|
61809
61886
|
function isSessionResetImminent(session, facts, quota, imminentMs, now) {
|
|
61810
61887
|
const resetsAt = Number(session?.resetsAt);
|
|
61811
61888
|
if (!Number.isFinite(resetsAt) || resetsAt <= 0) return false;
|
|
@@ -61827,7 +61904,10 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61827
61904
|
}
|
|
61828
61905
|
function evaluateProviderQuotaGate(node, providerType, policy, now = Date.now(), context) {
|
|
61829
61906
|
const entry = quotaEntryFor(node, providerType, context, now);
|
|
61830
|
-
if (!entry)
|
|
61907
|
+
if (!entry) {
|
|
61908
|
+
logAbsentQuotaFailOpen(node, providerType, policy, now, context);
|
|
61909
|
+
return null;
|
|
61910
|
+
}
|
|
61831
61911
|
const { facts, quota } = entry;
|
|
61832
61912
|
let sessionTrustworthy = true;
|
|
61833
61913
|
let weeklyTrustworthy = true;
|
|
@@ -61989,6 +62069,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
61989
62069
|
var PROVIDER_QUOTA_EXHAUSTED_SKIP_REASON;
|
|
61990
62070
|
var ALL_PROVIDERS_QUOTA_GATED_SKIP_REASON;
|
|
61991
62071
|
var staleFailOpenLoggedAt;
|
|
62072
|
+
var absentFailOpenLoggedAt;
|
|
61992
62073
|
var DEFAULT_WEEKLY_WINDOW_MINUTES;
|
|
61993
62074
|
var DEFAULT_SESSION_WINDOW_MINUTES;
|
|
61994
62075
|
var lastQuotaRankingByNode;
|
|
@@ -62004,6 +62085,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
62004
62085
|
PROVIDER_QUOTA_EXHAUSTED_SKIP_REASON = "provider_quota_exhausted";
|
|
62005
62086
|
ALL_PROVIDERS_QUOTA_GATED_SKIP_REASON = "all_providers_quota_gated";
|
|
62006
62087
|
staleFailOpenLoggedAt = /* @__PURE__ */ new Map();
|
|
62088
|
+
absentFailOpenLoggedAt = /* @__PURE__ */ new Map();
|
|
62007
62089
|
DEFAULT_WEEKLY_WINDOW_MINUTES = 7 * 24 * 60;
|
|
62008
62090
|
DEFAULT_SESSION_WINDOW_MINUTES = 5 * 60;
|
|
62009
62091
|
lastQuotaRankingByNode = /* @__PURE__ */ new Map();
|
|
@@ -66540,7 +66622,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
66540
66622
|
LOG2.info("MeshQueue", `Deferring queue claim for node ${nodeId} (${sessionId}): an auto fast-forward is mutating its workspace \u2014 task left pending, claim re-fires next tick`);
|
|
66541
66623
|
return false;
|
|
66542
66624
|
}
|
|
66543
|
-
const quotaClaimBlock = evaluateProviderQuotaGate(node, providerType, mesh?.policy?.quotaRouting ?? null, Date.now(), quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode));
|
|
66625
|
+
const quotaClaimBlock = evaluateProviderQuotaGate(node, providerType, mesh?.policy?.quotaRouting ?? null, Date.now(), quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode, components.providerLoader));
|
|
66544
66626
|
if (quotaClaimTrace) quotaClaimTrace.evaluated += 1;
|
|
66545
66627
|
if (quotaClaimBlock) {
|
|
66546
66628
|
const observation = { nodeId, sessionId, providerType, block: quotaClaimBlock };
|
|
@@ -67278,7 +67360,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
67278
67360
|
// pass it through for the 'fitness' strategy's task→slot ranking. The
|
|
67279
67361
|
// mesh's quotaRouting thresholds ride along so the fitness score can
|
|
67280
67362
|
// include the quota-headroom spread bonus (fail-open when unset).
|
|
67281
|
-
{ bumpCursor: true, task: { difficulty: task.difficulty, requiredTags: task.requiredTags }, quotaRouting: mesh?.policy?.quotaRouting ?? null, quotaFactsContext: quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode) }
|
|
67363
|
+
{ bumpCursor: true, task: { difficulty: task.difficulty, requiredTags: task.requiredTags }, quotaRouting: mesh?.policy?.quotaRouting ?? null, quotaFactsContext: quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode, components.providerLoader) }
|
|
67282
67364
|
).map((c) => c.node);
|
|
67283
67365
|
const skippedCandidates = [];
|
|
67284
67366
|
const SKIPPED_CANDIDATES_MAX = 5;
|
|
@@ -67337,7 +67419,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
67337
67419
|
}
|
|
67338
67420
|
autoLaunchInProgress.add(launchKey);
|
|
67339
67421
|
try {
|
|
67340
|
-
const resolved = await resolveUsableProvider(components, nodeId, node, meshId, task.requiredTags, { difficulty: task.difficulty, requiredTags: task.requiredTags }, mesh?.policy?.quotaRouting ?? null, quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode), task.id);
|
|
67422
|
+
const resolved = await resolveUsableProvider(components, nodeId, node, meshId, task.requiredTags, { difficulty: task.difficulty, requiredTags: task.requiredTags }, mesh?.policy?.quotaRouting ?? null, quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode, components.providerLoader), task.id);
|
|
67341
67423
|
if (!resolved.providerType) {
|
|
67342
67424
|
markSkip(nodeId, resolved.reason || "provider_unusable");
|
|
67343
67425
|
continue;
|
|
@@ -67478,7 +67560,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
67478
67560
|
task: { difficulty: task.difficulty, requiredTags: task.requiredTags },
|
|
67479
67561
|
resolved,
|
|
67480
67562
|
quotaRouting: mesh?.policy?.quotaRouting ?? null,
|
|
67481
|
-
quotaFactsContext: quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode),
|
|
67563
|
+
quotaFactsContext: quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode, components.providerLoader),
|
|
67482
67564
|
skippedCandidates,
|
|
67483
67565
|
requiredTagsResult: {
|
|
67484
67566
|
required: requiredTags,
|
|
@@ -71531,7 +71613,7 @@ ${cleanBody}`;
|
|
|
71531
71613
|
// daemon's live quota cache, not the git_status-stamped
|
|
71532
71614
|
// nodeFacts copy (mesh-quota-routing). Remote nodes keep
|
|
71533
71615
|
// reading their reported nodeFacts.
|
|
71534
|
-
quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode)
|
|
71616
|
+
quotaFactsContextForLiveRouting(mesh, isLocalAutoLaunchNode, components.providerLoader)
|
|
71535
71617
|
) : { action: "block" };
|
|
71536
71618
|
const relaunchProviderType = relaunch.action === "block" ? null : relaunch.providerType;
|
|
71537
71619
|
if (node) {
|
|
@@ -82437,6 +82519,7 @@ ${e?.stderr || ""}`;
|
|
|
82437
82519
|
MAX_SIZE_ROTATION_GENERATIONS: () => MAX_SIZE_ROTATION_GENERATIONS,
|
|
82438
82520
|
MESH_CONVERGE_FAST_FORWARD_TAG: () => MESH_CONVERGE_FAST_FORWARD_TAG,
|
|
82439
82521
|
MESH_CONVERGE_REFINE_TAG: () => MESH_CONVERGE_REFINE_TAG,
|
|
82522
|
+
MESH_DECLARED_ELIGIBLE_SINGLE_HINT: () => MESH_DECLARED_ELIGIBLE_SINGLE_HINT,
|
|
82440
82523
|
MESH_GATE_DEFAULT_LEASE_SECONDS: () => MESH_GATE_DEFAULT_LEASE_SECONDS,
|
|
82441
82524
|
MESH_GATE_NAMED_OUTCOMES: () => MESH_GATE_NAMED_OUTCOMES,
|
|
82442
82525
|
MESH_GATE_RELEASE_PATCH_KEYS: () => MESH_GATE_RELEASE_PATCH_KEYS,
|
|
@@ -82835,6 +82918,7 @@ ${e?.stderr || ""}`;
|
|
|
82835
82918
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
82836
82919
|
recordMissingSessionAttempt: () => recordMissingSessionAttempt2,
|
|
82837
82920
|
recordSessionUsage: () => recordSessionUsage,
|
|
82921
|
+
recordSingleEnqueueDecision: () => recordSingleEnqueueDecision,
|
|
82838
82922
|
recoverExpiredWorkspaceSagas: () => recoverExpiredWorkspaceSagas,
|
|
82839
82923
|
registerExtensionProviders: () => registerExtensionProviders,
|
|
82840
82924
|
registerMeshCoordinator: () => registerMeshCoordinator,
|