@adhdev/daemon-standalone 0.9.82-rc.396 → 0.9.82-rc.398
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 +129 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30108,10 +30108,10 @@ var require_dist3 = __commonJS({
|
|
|
30108
30108
|
}
|
|
30109
30109
|
function getDaemonBuildInfo() {
|
|
30110
30110
|
if (cached2) return cached2;
|
|
30111
|
-
const commit = readInjected(true ? "
|
|
30112
|
-
const commitShort = readInjected(true ? "
|
|
30113
|
-
const version2 = readInjected(true ? "0.9.82-rc.
|
|
30114
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
30111
|
+
const commit = readInjected(true ? "a572a9e7fe0e92e33a309d89e35299ad42aa407d" : void 0) ?? "unknown";
|
|
30112
|
+
const commitShort = readInjected(true ? "a572a9e7" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
30113
|
+
const version2 = readInjected(true ? "0.9.82-rc.398" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30114
|
+
const builtAt = readInjected(true ? "2026-06-27T09:05:37.974Z" : void 0);
|
|
30115
30115
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
30116
30116
|
return cached2;
|
|
30117
30117
|
}
|
|
@@ -34977,6 +34977,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
34977
34977
|
init_load_better_sqlite3();
|
|
34978
34978
|
init_mesh_ledger();
|
|
34979
34979
|
init_mesh_work_queue();
|
|
34980
|
+
init_dist();
|
|
34980
34981
|
loggedMigrationFailure = false;
|
|
34981
34982
|
MeshRuntimeStore = class _MeshRuntimeStore {
|
|
34982
34983
|
static instance;
|
|
@@ -35509,6 +35510,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35509
35510
|
if (providerType && typeof providerMaxParallel === "number" && Number.isFinite(providerMaxParallel) && providerMaxParallel >= 0 && this.activeProviderAssignmentCount(meshId, nodeId, providerType) >= providerMaxParallel) {
|
|
35510
35511
|
return null;
|
|
35511
35512
|
}
|
|
35513
|
+
const nodeIdForms = expandDaemonIdForms(nodeId);
|
|
35514
|
+
const nodePinnedPlaceholders = nodeIdForms.map(() => "?").join(", ");
|
|
35512
35515
|
const rows = [
|
|
35513
35516
|
...this.db.prepare(`
|
|
35514
35517
|
SELECT payload FROM mesh_queue
|
|
@@ -35517,9 +35520,9 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35517
35520
|
`).all(meshId, sessionId),
|
|
35518
35521
|
...this.db.prepare(`
|
|
35519
35522
|
SELECT payload FROM mesh_queue
|
|
35520
|
-
WHERE mesh_id = ? AND status = 'pending' AND target_node_id
|
|
35523
|
+
WHERE mesh_id = ? AND status = 'pending' AND target_node_id IN (${nodePinnedPlaceholders}) AND target_session_id IS NULL
|
|
35521
35524
|
ORDER BY created_at ASC
|
|
35522
|
-
`).all(meshId,
|
|
35525
|
+
`).all(meshId, ...nodeIdForms),
|
|
35523
35526
|
...this.db.prepare(`
|
|
35524
35527
|
SELECT payload FROM mesh_queue
|
|
35525
35528
|
WHERE mesh_id = ? AND status = 'pending' AND target_node_id IS NULL AND target_session_id IS NULL
|
|
@@ -35549,7 +35552,9 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35549
35552
|
const convergenceAllows = (candidate) => candidate.taskMode !== "convergence" || !nodeIsWorktree;
|
|
35550
35553
|
const targetMatches = (candidate) => {
|
|
35551
35554
|
if (candidate.targetSessionId && candidate.targetSessionId !== sessionId) return false;
|
|
35552
|
-
if (candidate.targetNodeId && candidate.targetNodeId
|
|
35555
|
+
if (candidate.targetNodeId && !daemonIdsEquivalent(candidate.targetNodeId, nodeId) && !meshNodeIdMatches({ id: candidate.targetNodeId }, nodeId)) {
|
|
35556
|
+
return false;
|
|
35557
|
+
}
|
|
35553
35558
|
return true;
|
|
35554
35559
|
};
|
|
35555
35560
|
const entry = candidates.find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags) && dependenciesSatisfied(candidate) && convergenceAllows(candidate) && targetMatches(candidate) && nodeConflictAllows(candidate));
|
|
@@ -40570,7 +40575,7 @@ Next step: ${nextStep}`;
|
|
|
40570
40575
|
}
|
|
40571
40576
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
40572
40577
|
const mesh = getMeshWithCache(components, meshId);
|
|
40573
|
-
const node = mesh?.nodes.find((n) =>
|
|
40578
|
+
const node = mesh?.nodes.find((n) => meshNodeIdMatches(n, nodeId));
|
|
40574
40579
|
const gateNode = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
40575
40580
|
if (gateNode?.worktreeBootstrap?.status === "running") {
|
|
40576
40581
|
LOG2.info("MeshQueue", `Gating queue claim for worktree node ${nodeId} (${sessionId}): worktree bootstrap still running \u2014 task left pending; claim re-fires once bootstrap reaches a terminal state (guards against dispatching into a half-built worktree \u2192 empty session)`);
|
|
@@ -41179,7 +41184,7 @@ Next step: ${nextStep}`;
|
|
|
41179
41184
|
const providerType = state.type || readNonEmptyString2(settings.providerType);
|
|
41180
41185
|
if (providerType) {
|
|
41181
41186
|
localIdleSessionsChecked += 1;
|
|
41182
|
-
localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) =>
|
|
41187
|
+
localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) => meshNodeIdMatches(n, nodeId)) });
|
|
41183
41188
|
} else {
|
|
41184
41189
|
skippedSessions.push({
|
|
41185
41190
|
nodeId,
|
|
@@ -44474,6 +44479,18 @@ ${cleanBody}`;
|
|
|
44474
44479
|
completedTaskForLedger = markSessionTerminal(sessionId, "failed");
|
|
44475
44480
|
}
|
|
44476
44481
|
} else if (args.event === "worktree_bootstrap_complete" || args.event === "worktree_bootstrap_failed") {
|
|
44482
|
+
const bootstrapNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
44483
|
+
if (bootstrapNodeId) {
|
|
44484
|
+
try {
|
|
44485
|
+
components.router?.markWorktreeBootstrapTerminalState?.(
|
|
44486
|
+
args.meshId,
|
|
44487
|
+
bootstrapNodeId,
|
|
44488
|
+
args.event === "worktree_bootstrap_failed" ? "failed" : "complete"
|
|
44489
|
+
);
|
|
44490
|
+
} catch (e) {
|
|
44491
|
+
LOG2.warn("MeshQueue", `Failed to stamp terminal bootstrap state for ${bootstrapNodeId} (mesh ${args.meshId}): ${e?.message || e}`);
|
|
44492
|
+
}
|
|
44493
|
+
}
|
|
44477
44494
|
setImmediate(() => {
|
|
44478
44495
|
triggerMeshQueue(components, args.meshId).catch((e) => {
|
|
44479
44496
|
LOG2.warn("MeshQueue", `Queue re-fire after ${args.event} failed (mesh ${args.meshId}): ${e?.message || e}`);
|
|
@@ -49400,6 +49417,16 @@ ${cont}` : cont;
|
|
|
49400
49417
|
providerSessionId = null;
|
|
49401
49418
|
responseTimeout = null;
|
|
49402
49419
|
ready = false;
|
|
49420
|
+
// WIN32-READY-HOLD: the ready barrier can release on screen/spec-FSM grace
|
|
49421
|
+
// before win32 ConPTY's input layer is live. The first split write (text, then a
|
|
49422
|
+
// separate trailing CR via waitForEchoAndSubmit) then has its submit CR swallowed,
|
|
49423
|
+
// and every CR-only retry re-sends a bare CR the input layer keeps dropping — the
|
|
49424
|
+
// first message is typed-but-never-submitted and lost. Routing only the FIRST turn
|
|
49425
|
+
// through the atomic content+sendKey single write (submitImmediatePrompt) keeps the
|
|
49426
|
+
// Enter in the same PTY write unit as the text, the invariant win32 ConPTY needs to
|
|
49427
|
+
// recognize a submit, so the swallow is bypassed. Subsequent turns (input layer now
|
|
49428
|
+
// proven live) keep the normal echo-gated path. Flips true on first committed turn.
|
|
49429
|
+
firstTurnSent = false;
|
|
49403
49430
|
startupBuffer = "";
|
|
49404
49431
|
startupParseGate = false;
|
|
49405
49432
|
startupSettleTimer = null;
|
|
@@ -49686,6 +49713,7 @@ ${lastSnapshot}`;
|
|
|
49686
49713
|
this.resetTerminalScreen(import_session_host_core5.DEFAULT_SESSION_HOST_ROWS, import_session_host_core5.DEFAULT_SESSION_HOST_COLS);
|
|
49687
49714
|
this.pendingTerminalQueryTail = "";
|
|
49688
49715
|
this.ready = false;
|
|
49716
|
+
this.firstTurnSent = false;
|
|
49689
49717
|
await this.ptyProcess.ready;
|
|
49690
49718
|
this.engine.onSpawnReady();
|
|
49691
49719
|
this.scheduleStartupSettleCheck();
|
|
@@ -50150,6 +50178,7 @@ ${lastSnapshot}`;
|
|
|
50150
50178
|
commitSendUserTurn(state) {
|
|
50151
50179
|
if (state.didCommitUserTurn) return;
|
|
50152
50180
|
state.didCommitUserTurn = true;
|
|
50181
|
+
this.firstTurnSent = true;
|
|
50153
50182
|
}
|
|
50154
50183
|
armResponseTimeout() {
|
|
50155
50184
|
if (this.responseTimeout) clearTimeout(this.responseTimeout);
|
|
@@ -50172,12 +50201,30 @@ ${lastSnapshot}`;
|
|
|
50172
50201
|
LOG2.warn("CLI", `[${this.cliType}] ${mode} write failed: ${error48?.message || error48}`);
|
|
50173
50202
|
});
|
|
50174
50203
|
}
|
|
50204
|
+
// WIN32-READY-HOLD: choose the retry write for a stuck prompt. When the FIRST turn
|
|
50205
|
+
// is stuck on win32 — the premature-ready swallow window — the prompt text itself
|
|
50206
|
+
// may have been partially eaten by a not-yet-live ConPTY input layer, so re-sending
|
|
50207
|
+
// a bare CR keeps hitting nothing. Re-type the whole `text + sendKey` atomically
|
|
50208
|
+
// once so the input layer (now live) receives a self-contained, submit-coupled
|
|
50209
|
+
// write. All other cases keep the cheap bare-CR retry (the prompt is fully echoed
|
|
50210
|
+
// and only the Enter is missing).
|
|
50211
|
+
writeStuckRetry(state, mode) {
|
|
50212
|
+
const retypeFirstTurn = process.platform === "win32" && state.isFirstTurn;
|
|
50213
|
+
if (retypeFirstTurn) {
|
|
50214
|
+
LOG2.info("CLI", `[${this.cliType}] ${mode}: re-typing full prompt atomically (win32 first-turn swallow recovery)`);
|
|
50215
|
+
void this.writeToPty(state.text + this.sendKey).catch((error48) => {
|
|
50216
|
+
LOG2.warn("CLI", `[${this.cliType}] ${mode} re-type write failed: ${error48?.message || error48}`);
|
|
50217
|
+
});
|
|
50218
|
+
return;
|
|
50219
|
+
}
|
|
50220
|
+
this.writeSubmitKeyForRetry(mode);
|
|
50221
|
+
}
|
|
50175
50222
|
retrySubmitIfStuck(state, attempt) {
|
|
50176
50223
|
this.submitRetryTimer = null;
|
|
50177
50224
|
if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
|
|
50178
50225
|
this.engine.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
50179
50226
|
LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
50180
|
-
this.
|
|
50227
|
+
this.writeStuckRetry(state, "submit_retry");
|
|
50181
50228
|
if (attempt >= 3) {
|
|
50182
50229
|
this.engine.submitRetryUsed = true;
|
|
50183
50230
|
return;
|
|
@@ -50189,7 +50236,7 @@ ${lastSnapshot}`;
|
|
|
50189
50236
|
if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
|
|
50190
50237
|
this.engine.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
50191
50238
|
LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
|
|
50192
|
-
this.
|
|
50239
|
+
this.writeStuckRetry(state, "immediate_retry");
|
|
50193
50240
|
this.engine.submitRetryUsed = true;
|
|
50194
50241
|
}
|
|
50195
50242
|
submitSendKey(state, completion) {
|
|
@@ -50442,7 +50489,9 @@ ${lastSnapshot}`;
|
|
|
50442
50489
|
submitDelayMs,
|
|
50443
50490
|
maxEchoWaitMs,
|
|
50444
50491
|
retryDelayMs,
|
|
50445
|
-
didCommitUserTurn: false
|
|
50492
|
+
didCommitUserTurn: false,
|
|
50493
|
+
// Capture BEFORE the send commits — commitSendUserTurn flips firstTurnSent.
|
|
50494
|
+
isFirstTurn: !this.firstTurnSent
|
|
50446
50495
|
};
|
|
50447
50496
|
this.engine.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
50448
50497
|
await new Promise((resolve24, reject) => {
|
|
@@ -50460,7 +50509,8 @@ ${lastSnapshot}`;
|
|
|
50460
50509
|
reject(error48);
|
|
50461
50510
|
}
|
|
50462
50511
|
};
|
|
50463
|
-
|
|
50512
|
+
const useAtomicFirstTurn = this.submitStrategy === "immediate" || process.platform === "win32" && sendState.isFirstTurn;
|
|
50513
|
+
if (useAtomicFirstTurn) {
|
|
50464
50514
|
this.submitImmediatePrompt(sendState, completion);
|
|
50465
50515
|
return;
|
|
50466
50516
|
}
|
|
@@ -82554,6 +82604,64 @@ ${mergeTreeErr?.stderr || ""}`;
|
|
|
82554
82604
|
this.invalidateAggregateMeshStatus(meshId);
|
|
82555
82605
|
return true;
|
|
82556
82606
|
}
|
|
82607
|
+
/**
|
|
82608
|
+
* WORKTREE-BOOTSTRAP-COORD-STATE: mark a worktree node's bootstrap as reaching a
|
|
82609
|
+
* terminal state (complete / failed) in THIS daemon's mesh view.
|
|
82610
|
+
*
|
|
82611
|
+
* Root cause this fixes: clone_mesh_node forwards the clone+bootstrap to the
|
|
82612
|
+
* source node's daemon (the worktree's machine). persistWorktreeSetupState
|
|
82613
|
+
* therefore flips worktreeBootstrap.status to 'complete' on the WORKER daemon's
|
|
82614
|
+
* mesh object — never on the coordinator's. The coordinator only ever holds the
|
|
82615
|
+
* 'running' state it stamped from the forwarded clone reply. The claim path's
|
|
82616
|
+
* bootstrap gate (mesh-event-forwarding agent:ready / mesh-queue-assignment)
|
|
82617
|
+
* reads the coordinator's mesh via getMeshWithCache, sees status==='running'
|
|
82618
|
+
* forever, and DEFERS every claim — so the worktree_bootstrap_complete re-fire
|
|
82619
|
+
* (triggerMeshQueue) loops against a gate that never opens: claim never lands,
|
|
82620
|
+
* the idle session is re-registered each tick, and auto-launch keeps spawning
|
|
82621
|
+
* fresh sessions (runaway worktree-session multiplication).
|
|
82622
|
+
*
|
|
82623
|
+
* Called from the worktree_bootstrap_complete/_failed event handler BEFORE the
|
|
82624
|
+
* queue re-fire so the gate sees the terminal state and the deferred claim can
|
|
82625
|
+
* finally land. Updates the inline cache (clone worktree nodes are inline-only)
|
|
82626
|
+
* and, when the node also exists in local config, persists there too; both paths
|
|
82627
|
+
* invalidate the aggregate status cache. Best-effort and idempotent.
|
|
82628
|
+
*/
|
|
82629
|
+
markWorktreeBootstrapTerminalState(meshId, nodeId, status) {
|
|
82630
|
+
if (!meshId || !nodeId) return;
|
|
82631
|
+
const stamp = (mesh) => {
|
|
82632
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
82633
|
+
const node = mesh.nodes.find((entry) => meshNodeIdMatches(entry, nodeId));
|
|
82634
|
+
if (!node) return false;
|
|
82635
|
+
const prev = node.worktreeBootstrap && typeof node.worktreeBootstrap === "object" ? node.worktreeBootstrap : {};
|
|
82636
|
+
if (prev.status === status) return false;
|
|
82637
|
+
node.worktreeBootstrap = {
|
|
82638
|
+
...prev,
|
|
82639
|
+
status,
|
|
82640
|
+
completedAt: prev.completedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
82641
|
+
};
|
|
82642
|
+
return true;
|
|
82643
|
+
};
|
|
82644
|
+
let changed = false;
|
|
82645
|
+
try {
|
|
82646
|
+
const cached3 = this.getCachedInlineMesh(meshId);
|
|
82647
|
+
if (cached3 && stamp(cached3)) {
|
|
82648
|
+
cached3.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
82649
|
+
this.inlineMeshCache.set(meshId, cached3);
|
|
82650
|
+
changed = true;
|
|
82651
|
+
}
|
|
82652
|
+
} catch {
|
|
82653
|
+
}
|
|
82654
|
+
if (changed) this.invalidateAggregateMeshStatus(meshId);
|
|
82655
|
+
void Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports)).then(({ getMesh: getMesh2, updateNode: updateNode2 }) => {
|
|
82656
|
+
const local = getMesh2(meshId);
|
|
82657
|
+
if (local && stamp(local)) {
|
|
82658
|
+
const node = local.nodes.find((entry) => meshNodeIdMatches(entry, nodeId));
|
|
82659
|
+
if (node) updateNode2(meshId, node.id, { worktreeBootstrap: node.worktreeBootstrap });
|
|
82660
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
82661
|
+
}
|
|
82662
|
+
}).catch(() => {
|
|
82663
|
+
});
|
|
82664
|
+
}
|
|
82557
82665
|
tombstoneRemovedInlineMeshNode(meshId, nodeId) {
|
|
82558
82666
|
if (!nodeId) return;
|
|
82559
82667
|
let set2 = this.removedInlineMeshNodeIds.get(meshId);
|
|
@@ -83937,7 +84045,14 @@ ${hintLines.join("\n")}` : "",
|
|
|
83937
84045
|
nodeId,
|
|
83938
84046
|
sessionCleanupMode: refineSessionCleanupMode,
|
|
83939
84047
|
...refineSessionIds && refineSessionIds.length > 0 ? { sessionIds: refineSessionIds } : {},
|
|
83940
|
-
inlineMesh: args?.inlineMesh
|
|
84048
|
+
inlineMesh: args?.inlineMesh,
|
|
84049
|
+
// REFINE-CLEANUP: refine reaches cleanup only AFTER a verified merge
|
|
84050
|
+
// convergence, so any residual worktree dirtiness here is incidental
|
|
84051
|
+
// (e.g. a bootstrap lockfile rewrite) — never unmerged work. `force`
|
|
84052
|
+
// sets requireClean=false so a plain-dirty worktree no longer aborts
|
|
84053
|
+
// removal with merged_cleanup_failed. Branch-ref deletion still keys off
|
|
84054
|
+
// mergeConvergence (NOT the force flag), so no merged work can be lost.
|
|
84055
|
+
force: true
|
|
83941
84056
|
});
|
|
83942
84057
|
recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
|
|
83943
84058
|
removed: removeResult?.removed,
|