@adhdev/daemon-core 1.0.18-rc.7 → 1.0.18-rc.9
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/commands/windows-atomic-upgrade.d.ts +4 -0
- package/dist/index.js +245 -59
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +245 -59
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +57 -13
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/package.json +3 -3
- package/src/commands/high-family/mesh-coordinator-launch.ts +12 -2
- package/src/commands/upgrade-helper.ts +28 -14
- package/src/commands/windows-atomic-upgrade.ts +61 -18
- package/src/config/mesh-json-config.ts +5 -1
- package/src/mesh/coordinator-prompt.ts +206 -31
- package/src/mesh/mesh-queue-assignment.ts +126 -1
- package/src/providers/cli-provider-instance.ts +51 -0
package/dist/index.mjs
CHANGED
|
@@ -437,10 +437,10 @@ function readInjected(value) {
|
|
|
437
437
|
}
|
|
438
438
|
function getDaemonBuildInfo() {
|
|
439
439
|
if (cached) return cached;
|
|
440
|
-
const commit = readInjected(true ? "
|
|
441
|
-
const commitShort = readInjected(true ? "
|
|
442
|
-
const version = readInjected(true ? "1.0.18-rc.
|
|
443
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
440
|
+
const commit = readInjected(true ? "3a1a0d16c0dd7ce3df15591fbe30b7e8638ab876" : void 0) ?? "unknown";
|
|
441
|
+
const commitShort = readInjected(true ? "3a1a0d16" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
442
|
+
const version = readInjected(true ? "1.0.18-rc.9" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
443
|
+
const builtAt = readInjected(true ? "2026-07-22T05:27:14.328Z" : void 0);
|
|
444
444
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
445
445
|
return cached;
|
|
446
446
|
}
|
|
@@ -9865,40 +9865,113 @@ function isDurableCategory(category) {
|
|
|
9865
9865
|
if (!category) return true;
|
|
9866
9866
|
return !(category in OPERATING_NOTE_CATEGORY_TTL_DAYS);
|
|
9867
9867
|
}
|
|
9868
|
-
function
|
|
9868
|
+
function deriveSubjectKey(note) {
|
|
9869
|
+
const explicit = typeof note.subjectKey === "string" ? note.subjectKey.trim().toLowerCase() : "";
|
|
9870
|
+
if (explicit) return explicit;
|
|
9871
|
+
const text = typeof note.text === "string" ? note.text.trimStart() : "";
|
|
9872
|
+
const m = /^\[([^\]]{1,80})\]/.exec(text);
|
|
9873
|
+
const tag = m ? m[1].trim().toLowerCase() : "";
|
|
9874
|
+
return tag || void 0;
|
|
9875
|
+
}
|
|
9876
|
+
function foldSameClassNotes(ranked) {
|
|
9877
|
+
const out = [];
|
|
9878
|
+
const survivorByKey = /* @__PURE__ */ new Map();
|
|
9879
|
+
for (const note of ranked) {
|
|
9880
|
+
const subject = deriveSubjectKey(note);
|
|
9881
|
+
const foldable = !note.pinned && !!note.category && !!subject;
|
|
9882
|
+
if (foldable) {
|
|
9883
|
+
const key2 = `${note.category}\0${subject}`;
|
|
9884
|
+
const existing = survivorByKey.get(key2);
|
|
9885
|
+
if (existing !== void 0) {
|
|
9886
|
+
const survivor = out[existing];
|
|
9887
|
+
survivor.subsumedCount += 1;
|
|
9888
|
+
if (typeof note.noteId === "string" && note.noteId) survivor.subsumedIds.push(note.noteId);
|
|
9889
|
+
continue;
|
|
9890
|
+
}
|
|
9891
|
+
survivorByKey.set(key2, out.length);
|
|
9892
|
+
}
|
|
9893
|
+
out.push({ note, subsumedIds: [], subsumedCount: 0 });
|
|
9894
|
+
}
|
|
9895
|
+
return out;
|
|
9896
|
+
}
|
|
9897
|
+
function renderedNoteBytes(folded) {
|
|
9898
|
+
return byteLength2(renderOperatingNoteLine(folded));
|
|
9899
|
+
}
|
|
9900
|
+
function selectOperatingNotesForPrompt(notes, now, cap = OPERATING_NOTES_PROMPT_CAP, byteBudget = OPERATING_NOTE_INJECTION_BYTE_BUDGET) {
|
|
9869
9901
|
const valid = Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
|
|
9870
|
-
|
|
9902
|
+
let kept = valid.map((note, index) => ({ note, index })).filter(({ note }) => note.pinned || !isNoteExpired(note, now));
|
|
9903
|
+
const supersededAtIndex = /* @__PURE__ */ new Map();
|
|
9904
|
+
for (const { note, index } of kept) {
|
|
9905
|
+
const target = typeof note.supersedes === "string" ? note.supersedes.trim().toLowerCase() : "";
|
|
9906
|
+
if (!target) continue;
|
|
9907
|
+
const prev = supersededAtIndex.get(target);
|
|
9908
|
+
if (prev === void 0 || index > prev) supersededAtIndex.set(target, index);
|
|
9909
|
+
}
|
|
9910
|
+
if (supersededAtIndex.size > 0) {
|
|
9911
|
+
kept = kept.filter(({ note, index }) => {
|
|
9912
|
+
if (note.pinned) return true;
|
|
9913
|
+
const byId = typeof note.noteId === "string" ? note.noteId.trim().toLowerCase() : "";
|
|
9914
|
+
const bySubject = deriveSubjectKey(note);
|
|
9915
|
+
const supIdx = Math.max(
|
|
9916
|
+
byId ? supersededAtIndex.get(byId) ?? -1 : -1,
|
|
9917
|
+
bySubject ? supersededAtIndex.get(bySubject) ?? -1 : -1
|
|
9918
|
+
);
|
|
9919
|
+
return !(supIdx > index);
|
|
9920
|
+
});
|
|
9921
|
+
}
|
|
9871
9922
|
const rank = (n) => n.pinned ? 0 : isDurableCategory(n.category) ? 1 : 2;
|
|
9872
9923
|
kept.sort((a, b) => {
|
|
9873
9924
|
const r = rank(a.note) - rank(b.note);
|
|
9874
9925
|
if (r !== 0) return r;
|
|
9875
9926
|
return b.index - a.index;
|
|
9876
9927
|
});
|
|
9877
|
-
const
|
|
9878
|
-
const shown =
|
|
9928
|
+
const folded = foldSameClassNotes(kept.map((k) => k.note));
|
|
9929
|
+
const shown = [];
|
|
9930
|
+
let usedBytes = 0;
|
|
9931
|
+
let usedCount = 0;
|
|
9932
|
+
for (const entry of folded) {
|
|
9933
|
+
if (entry.note.pinned) {
|
|
9934
|
+
shown.push(entry);
|
|
9935
|
+
usedBytes += renderedNoteBytes(entry);
|
|
9936
|
+
usedCount += 1;
|
|
9937
|
+
continue;
|
|
9938
|
+
}
|
|
9939
|
+
if (usedCount >= cap) break;
|
|
9940
|
+
const bytes = renderedNoteBytes(entry);
|
|
9941
|
+
if (usedCount > 0 && usedBytes + bytes > byteBudget) break;
|
|
9942
|
+
shown.push(entry);
|
|
9943
|
+
usedBytes += bytes;
|
|
9944
|
+
usedCount += 1;
|
|
9945
|
+
}
|
|
9946
|
+
const omittedCount = Math.max(0, folded.length - shown.length);
|
|
9879
9947
|
return { shown, omittedCount };
|
|
9880
9948
|
}
|
|
9881
|
-
function
|
|
9882
|
-
const
|
|
9883
|
-
if (!hasAny) return "";
|
|
9949
|
+
function renderOperatingNoteLine(folded) {
|
|
9950
|
+
const n = folded.note;
|
|
9884
9951
|
const categoryLabel = {
|
|
9885
9952
|
provider_quirk: "provider quirk",
|
|
9886
9953
|
pattern_to_avoid: "pattern to avoid",
|
|
9887
9954
|
recovery_lesson: "recovery lesson"
|
|
9888
9955
|
};
|
|
9956
|
+
const pin = n.pinned ? "\u{1F4CC} " : "";
|
|
9957
|
+
const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
|
|
9958
|
+
const fold = folded.subsumedCount > 0 ? ` _(+${folded.subsumedCount} earlier same-subject note${folded.subsumedCount === 1 ? "" : "s"} folded${folded.subsumedIds.length ? `: ${folded.subsumedIds.join(", ")}` : ""})_` : "";
|
|
9959
|
+
return `- ${pin}${cat}${truncateNote(n.text.trim())}${fold}`;
|
|
9960
|
+
}
|
|
9961
|
+
function buildOperatingNotesSection(notes, now = Date.now()) {
|
|
9962
|
+
const hasAny = Array.isArray(notes) ? notes.some((n) => n && typeof n.text === "string" && n.text.trim()) : false;
|
|
9963
|
+
if (!hasAny) return "";
|
|
9889
9964
|
const { shown, omittedCount } = selectOperatingNotesForPrompt(notes ?? [], now);
|
|
9890
9965
|
if (shown.length === 0) return "";
|
|
9891
9966
|
const lines = ["## Operating Notes", ""];
|
|
9892
9967
|
lines.push("Lessons earlier coordinators on this mesh recorded via `mesh_record_note`. Treat them as accumulated operating knowledge \u2014 apply them. When you learn a durable lesson (a provider quirk, a pattern to avoid, a recovery lesson), record it with `mesh_record_note` so future coordinators inherit it.");
|
|
9893
9968
|
lines.push("");
|
|
9894
|
-
for (const
|
|
9895
|
-
|
|
9896
|
-
const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
|
|
9897
|
-
lines.push(`- ${pin}${cat}${truncateNote(n.text.trim())}`);
|
|
9969
|
+
for (const entry of shown) {
|
|
9970
|
+
lines.push(renderOperatingNoteLine(entry));
|
|
9898
9971
|
}
|
|
9899
9972
|
if (omittedCount > 0) {
|
|
9900
9973
|
lines.push("");
|
|
9901
|
-
lines.push(`_${omittedCount} lower-priority note${omittedCount === 1 ? "" : "s"} omitted (kept in ledger; expired
|
|
9974
|
+
lines.push(`_${omittedCount} lower-priority note${omittedCount === 1 ? "" : "s"} omitted to fit the injection cap/byte-budget (kept in ledger; expired, superseded, and same-subject-folded notes are also hidden from this list but retained for audit; prune with \`mesh_forget_note\`)._`);
|
|
9902
9975
|
}
|
|
9903
9976
|
return lines.join("\n");
|
|
9904
9977
|
}
|
|
@@ -10022,7 +10095,7 @@ When you compose the task message you dispatch to a node, include these requirem
|
|
|
10022
10095
|
- **Scoped test runs.** For a validation or code-change task, instruct the worker to run only the tests covering the changed files (\`vitest run <path>\` or \`-t <name>\`), not the whole suite. Run the full suite only when the task is explicitly a full-suite gate \u2014 a broad daemon-core run is minutes of wall-clock and the biggest source of worker slowness.
|
|
10023
10096
|
- **Branch convergence state.** For a worktree task, require the completion report to classify the touched branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. A task that ends on a non-main branch is not complete unless the report names that state and the next step.`;
|
|
10024
10097
|
}
|
|
10025
|
-
var PROMPT_SOFT_CAP_BYTES, OPERATING_NOTES_PROMPT_CAP, OPERATING_NOTE_MAX_CHARS, TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION, ONBOARDING_SECTION;
|
|
10098
|
+
var PROMPT_SOFT_CAP_BYTES, OPERATING_NOTES_PROMPT_CAP, OPERATING_NOTE_MAX_CHARS, OPERATING_NOTE_INJECTION_BYTE_BUDGET, TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION, ONBOARDING_SECTION;
|
|
10026
10099
|
var init_coordinator_prompt = __esm({
|
|
10027
10100
|
"src/mesh/coordinator-prompt.ts"() {
|
|
10028
10101
|
"use strict";
|
|
@@ -10034,6 +10107,7 @@ var init_coordinator_prompt = __esm({
|
|
|
10034
10107
|
PROMPT_SOFT_CAP_BYTES = 60 * 1024;
|
|
10035
10108
|
OPERATING_NOTES_PROMPT_CAP = 20;
|
|
10036
10109
|
OPERATING_NOTE_MAX_CHARS = 300;
|
|
10110
|
+
OPERATING_NOTE_INJECTION_BYTE_BUDGET = 6 * 1024;
|
|
10037
10111
|
TOOLS_SECTION = `## Available Tools
|
|
10038
10112
|
|
|
10039
10113
|
| Tool | Purpose |
|
|
@@ -11806,9 +11880,13 @@ function normalizeOperatingNote(value) {
|
|
|
11806
11880
|
...typeof value.createdAt === "string" ? { createdAt: value.createdAt } : {},
|
|
11807
11881
|
...typeof value.sourceCoordinator === "string" ? { sourceCoordinator: value.sourceCoordinator } : {},
|
|
11808
11882
|
// Operating-notes lifecycle: a repo-declared note may pin itself or set an
|
|
11809
|
-
// explicit expiry, same as a runtime-recorded one.
|
|
11883
|
+
// explicit expiry, same as a runtime-recorded one. Phase 2 (b)/(c): it may
|
|
11884
|
+
// also declare supersedes/subjectKey to retire an earlier note or group
|
|
11885
|
+
// same-subject notes for folding.
|
|
11810
11886
|
...value.pinned === true ? { pinned: true } : {},
|
|
11811
|
-
...typeof value.expiresAt === "string" ? { expiresAt: value.expiresAt } : {}
|
|
11887
|
+
...typeof value.expiresAt === "string" ? { expiresAt: value.expiresAt } : {},
|
|
11888
|
+
...typeof value.supersedes === "string" ? { supersedes: value.supersedes } : {},
|
|
11889
|
+
...typeof value.subjectKey === "string" ? { subjectKey: value.subjectKey } : {}
|
|
11812
11890
|
};
|
|
11813
11891
|
}
|
|
11814
11892
|
function normalizeRepoMeshDeclarativeConfig(parsed) {
|
|
@@ -16564,6 +16642,33 @@ function isTargetNodeTransientlyUnresolved(mesh, task) {
|
|
|
16564
16642
|
}
|
|
16565
16643
|
return isWithinCloneBootstrapGrace(targetNodeId);
|
|
16566
16644
|
}
|
|
16645
|
+
function resolveDeadTargetVerdict(components, meshId, mesh, task) {
|
|
16646
|
+
const NOT_DEAD = { dead: false, nodeDead: false, reason: "" };
|
|
16647
|
+
const targetSessionId = readNonEmptyString(task.targetSessionId);
|
|
16648
|
+
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
16649
|
+
if (!targetSessionId && !targetNodeId) return NOT_DEAD;
|
|
16650
|
+
const lastUpdateMs = Date.parse(task.updatedAt || task.createdAt || "");
|
|
16651
|
+
if (Number.isFinite(lastUpdateMs) && Date.now() - lastUpdateMs < DEAD_TARGET_GRACE_MS) return NOT_DEAD;
|
|
16652
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
16653
|
+
if (targetNodeId) {
|
|
16654
|
+
const nodePresent = nodes.some((n) => meshNodeIdMatches(n, targetNodeId));
|
|
16655
|
+
if (!nodePresent) {
|
|
16656
|
+
if (isTargetNodeTransientlyUnresolved(mesh, task)) return NOT_DEAD;
|
|
16657
|
+
return { dead: true, nodeDead: true, reason: "dead_target_node_absent" };
|
|
16658
|
+
}
|
|
16659
|
+
}
|
|
16660
|
+
if (targetSessionId) {
|
|
16661
|
+
const node = targetNodeId ? nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
16662
|
+
const nodeIsLocal = node ? isLocalAutoLaunchNode(node) : true;
|
|
16663
|
+
if (nodeIsLocal) {
|
|
16664
|
+
const verdict = resolveSessionBusyVerdict(components, targetSessionId);
|
|
16665
|
+
if (verdict === "UNKNOWN") {
|
|
16666
|
+
return { dead: true, nodeDead: false, reason: "dead_target_session_absent" };
|
|
16667
|
+
}
|
|
16668
|
+
}
|
|
16669
|
+
}
|
|
16670
|
+
return NOT_DEAD;
|
|
16671
|
+
}
|
|
16567
16672
|
function retractActionableSkipIfPreviouslyNotified(meshId, taskId) {
|
|
16568
16673
|
const dedupKey = `${meshId}:${taskId}`;
|
|
16569
16674
|
if (!lastActionableSkipNotified.delete(dedupKey)) return;
|
|
@@ -17081,6 +17186,21 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
17081
17186
|
continue;
|
|
17082
17187
|
}
|
|
17083
17188
|
if (task.targetSessionId) {
|
|
17189
|
+
const deadTarget = resolveDeadTargetVerdict(components, meshId, mesh, task);
|
|
17190
|
+
if (deadTarget.dead) {
|
|
17191
|
+
const requeued = requeueTask(meshId, task.id, {
|
|
17192
|
+
reason: deadTarget.reason,
|
|
17193
|
+
clearTargetSession: true,
|
|
17194
|
+
// Keep the node pin if only the SESSION died on a still-live node; clear it
|
|
17195
|
+
// when the NODE itself is absent (nothing to pin to).
|
|
17196
|
+
clearTargetNode: deadTarget.nodeDead
|
|
17197
|
+
});
|
|
17198
|
+
if (requeued) {
|
|
17199
|
+
LOG.warn("MeshQueue", `DEAD-TARGET-SELFHEAL: task ${task.id} (mesh ${meshId}) was pinned to a dead target (${deadTarget.reason}); requeued${deadTarget.nodeDead ? " and unpinned node" : ""} (requeueCount=${requeued.requeueCount ?? "?"}, status=${requeued.status}).`);
|
|
17200
|
+
}
|
|
17201
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_dead_requeued" });
|
|
17202
|
+
continue;
|
|
17203
|
+
}
|
|
17084
17204
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_constraint" });
|
|
17085
17205
|
continue;
|
|
17086
17206
|
}
|
|
@@ -17652,7 +17772,7 @@ function runIdleMaintenanceThenAssignQueue(components, args) {
|
|
|
17652
17772
|
});
|
|
17653
17773
|
});
|
|
17654
17774
|
}
|
|
17655
|
-
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS, continuousAutoFastForwardLastScan, autoFastForwardWorkspaceLease, BOOTSTRAP_TERMINAL_STATUSES, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, LOCAL_LAUNCH_READY_TIMEOUT_MS, LOCAL_LAUNCH_READY_POLL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, AUTO_LAUNCH_AWAIT_CLAIM_BACKOFF_CAP_CYCLES, AUTO_LAUNCH_REMOTE_IDLE_TTL_MS, autoLaunchAwaitClaimBackoff, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, ACTIONABLE_SKIP_REASON_PREFIXES, TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON, lastActionableSkipNotified;
|
|
17775
|
+
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, CONTINUOUS_AUTO_FAST_FORWARD_SCAN_COOLDOWN_MS, continuousAutoFastForwardLastScan, autoFastForwardWorkspaceLease, BOOTSTRAP_TERMINAL_STATUSES, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, LOCAL_LAUNCH_READY_TIMEOUT_MS, LOCAL_LAUNCH_READY_POLL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, AUTO_LAUNCH_AWAIT_CLAIM_BACKOFF_CAP_CYCLES, AUTO_LAUNCH_REMOTE_IDLE_TTL_MS, autoLaunchAwaitClaimBackoff, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, ACTIONABLE_SKIP_REASON_PREFIXES, TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON, lastActionableSkipNotified, DEAD_TARGET_GRACE_MS;
|
|
17656
17776
|
var init_mesh_queue_assignment = __esm({
|
|
17657
17777
|
"src/mesh/mesh-queue-assignment.ts"() {
|
|
17658
17778
|
"use strict";
|
|
@@ -17713,6 +17833,7 @@ var init_mesh_queue_assignment = __esm({
|
|
|
17713
17833
|
];
|
|
17714
17834
|
TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON = "target_node_bootstrap_pending";
|
|
17715
17835
|
lastActionableSkipNotified = /* @__PURE__ */ new Map();
|
|
17836
|
+
DEAD_TARGET_GRACE_MS = 6e4;
|
|
17716
17837
|
}
|
|
17717
17838
|
});
|
|
17718
17839
|
|
|
@@ -42890,6 +43011,40 @@ async function stopOwnedProcessesForPrefixes(options) {
|
|
|
42890
43011
|
var POINTER_NAME = ".adhdev-current";
|
|
42891
43012
|
var STABLE_FILES = [POINTER_NAME, "adhdev.cmd", "adhdev.ps1", "adhdev"];
|
|
42892
43013
|
var DEFAULT_HEALTH_PORT = 19222;
|
|
43014
|
+
function fetchLocalJson(port, pathname) {
|
|
43015
|
+
return new Promise((resolve27) => {
|
|
43016
|
+
const req = http2.get(`http://127.0.0.1:${port}${pathname}`, { timeout: 1500 }, (res) => {
|
|
43017
|
+
let body = "";
|
|
43018
|
+
res.setEncoding("utf8");
|
|
43019
|
+
res.on("data", (chunk) => {
|
|
43020
|
+
body += chunk;
|
|
43021
|
+
});
|
|
43022
|
+
res.on("end", () => resolve27({ ok: res.statusCode === 200, body }));
|
|
43023
|
+
});
|
|
43024
|
+
req.on("timeout", () => req.destroy());
|
|
43025
|
+
req.on("error", () => resolve27({ ok: false, body: "" }));
|
|
43026
|
+
});
|
|
43027
|
+
}
|
|
43028
|
+
async function fetchLocalHealth(port) {
|
|
43029
|
+
const { ok, body } = await fetchLocalJson(port, "/health");
|
|
43030
|
+
if (!ok) return { ok: false };
|
|
43031
|
+
try {
|
|
43032
|
+
const pid = Number(JSON.parse(body)?.pid);
|
|
43033
|
+
return { ok: true, pid: Number.isFinite(pid) ? pid : void 0 };
|
|
43034
|
+
} catch {
|
|
43035
|
+
return { ok: false };
|
|
43036
|
+
}
|
|
43037
|
+
}
|
|
43038
|
+
async function fetchLocalStatusVersion(port) {
|
|
43039
|
+
const { ok, body } = await fetchLocalJson(port, "/api/v1/status");
|
|
43040
|
+
if (!ok) return void 0;
|
|
43041
|
+
try {
|
|
43042
|
+
const version = JSON.parse(body)?.status?.version;
|
|
43043
|
+
return typeof version === "string" ? version : void 0;
|
|
43044
|
+
} catch {
|
|
43045
|
+
return void 0;
|
|
43046
|
+
}
|
|
43047
|
+
}
|
|
42893
43048
|
var ADHDEV_OWNED_MARKERS = [
|
|
42894
43049
|
"session-host-daemon",
|
|
42895
43050
|
"node_modules/adhdev",
|
|
@@ -43167,6 +43322,8 @@ async function performWindowsAtomicUpgrade(options) {
|
|
|
43167
43322
|
}
|
|
43168
43323
|
}
|
|
43169
43324
|
function createDefaultWindowsAtomicHooks(options) {
|
|
43325
|
+
const healthPort = options.healthPort ?? DEFAULT_HEALTH_PORT;
|
|
43326
|
+
const healthTimeoutMs = options.healthTimeoutMs ?? 3e4;
|
|
43170
43327
|
return {
|
|
43171
43328
|
install: (stagedPrefix, portableNode) => {
|
|
43172
43329
|
const env = {
|
|
@@ -43177,7 +43334,7 @@ function createDefaultWindowsAtomicHooks(options) {
|
|
|
43177
43334
|
};
|
|
43178
43335
|
const pathKey = Object.keys(env).find((key2) => key2.toLowerCase() === "path") || "Path";
|
|
43179
43336
|
env[pathKey] = `${path20.dirname(portableNode)};${env[pathKey] || ""}`;
|
|
43180
|
-
execFileSync4(portableNode, [
|
|
43337
|
+
const installOutput = String(execFileSync4(portableNode, [
|
|
43181
43338
|
options.npmCliPath,
|
|
43182
43339
|
"install",
|
|
43183
43340
|
"-g",
|
|
@@ -43192,7 +43349,8 @@ function createDefaultWindowsAtomicHooks(options) {
|
|
|
43192
43349
|
maxBuffer: 20 * 1024 * 1024,
|
|
43193
43350
|
windowsHide: true,
|
|
43194
43351
|
env
|
|
43195
|
-
});
|
|
43352
|
+
}));
|
|
43353
|
+
if (installOutput.trim()) options.log(installOutput.trim());
|
|
43196
43354
|
},
|
|
43197
43355
|
restart: (portableNode, stagedCliEntry) => {
|
|
43198
43356
|
const restartArgv = options.restartArgv.map((arg, index) => index === 0 ? stagedCliEntry : arg);
|
|
@@ -43219,28 +43377,12 @@ function createDefaultWindowsAtomicHooks(options) {
|
|
|
43219
43377
|
child.unref();
|
|
43220
43378
|
},
|
|
43221
43379
|
waitForHealth: async (pid, targetVersion) => {
|
|
43222
|
-
const deadline = Date.now() +
|
|
43380
|
+
const deadline = Date.now() + healthTimeoutMs;
|
|
43223
43381
|
while (Date.now() < deadline) {
|
|
43224
|
-
const
|
|
43225
|
-
|
|
43226
|
-
|
|
43227
|
-
|
|
43228
|
-
res.on("data", (chunk) => {
|
|
43229
|
-
body += chunk;
|
|
43230
|
-
});
|
|
43231
|
-
res.on("end", () => {
|
|
43232
|
-
let responsePid;
|
|
43233
|
-
try {
|
|
43234
|
-
responsePid = Number(JSON.parse(body)?.pid);
|
|
43235
|
-
} catch {
|
|
43236
|
-
}
|
|
43237
|
-
resolve27({ ok: res.statusCode === 200, pid: responsePid, body });
|
|
43238
|
-
});
|
|
43239
|
-
});
|
|
43240
|
-
req.on("timeout", () => req.destroy());
|
|
43241
|
-
req.on("error", () => resolve27({ ok: false }));
|
|
43242
|
-
});
|
|
43243
|
-
if (result.ok && result.pid === pid && result.body?.includes(targetVersion)) return true;
|
|
43382
|
+
const liveness = await fetchLocalHealth(healthPort);
|
|
43383
|
+
const alive = liveness.ok && liveness.pid === pid;
|
|
43384
|
+
const version = alive ? await fetchLocalStatusVersion(healthPort) : void 0;
|
|
43385
|
+
if (alive && version === targetVersion) return true;
|
|
43244
43386
|
await new Promise((resolve27) => setTimeout(resolve27, 500));
|
|
43245
43387
|
}
|
|
43246
43388
|
return false;
|
|
@@ -43669,22 +43811,31 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
43669
43811
|
`Cannot upgrade: owned processes still running under current prefix: ${preStop.survivors.map((s2) => s2.pid).join(", ")}`
|
|
43670
43812
|
);
|
|
43671
43813
|
}
|
|
43672
|
-
|
|
43673
|
-
|
|
43674
|
-
|
|
43675
|
-
targetVersion: payload.targetVersion,
|
|
43676
|
-
portableNode,
|
|
43677
|
-
excludePids: upgradePids,
|
|
43678
|
-
hooks: createDefaultWindowsAtomicHooks({
|
|
43814
|
+
try {
|
|
43815
|
+
await performWindowsAtomicUpgrade({
|
|
43816
|
+
layout: windowsInstallerLayout,
|
|
43679
43817
|
packageName: payload.packageName,
|
|
43680
43818
|
targetVersion: payload.targetVersion,
|
|
43681
|
-
|
|
43682
|
-
|
|
43683
|
-
|
|
43684
|
-
|
|
43685
|
-
|
|
43686
|
-
|
|
43687
|
-
|
|
43819
|
+
portableNode,
|
|
43820
|
+
excludePids: upgradePids,
|
|
43821
|
+
hooks: createDefaultWindowsAtomicHooks({
|
|
43822
|
+
packageName: payload.packageName,
|
|
43823
|
+
targetVersion: payload.targetVersion,
|
|
43824
|
+
npmCliPath,
|
|
43825
|
+
restartArgv,
|
|
43826
|
+
cwd: payload.cwd || process.cwd(),
|
|
43827
|
+
env: Object.fromEntries(Object.entries(process.env).filter(([key2]) => key2 !== UPGRADE_HELPER_ENV)),
|
|
43828
|
+
log: appendUpgradeLog
|
|
43829
|
+
})
|
|
43830
|
+
});
|
|
43831
|
+
} catch (error) {
|
|
43832
|
+
emitUpgradeFailureNotice([
|
|
43833
|
+
`adhdev ${payload.packageName}@${payload.targetVersion} upgrade failed and was rolled back: ${error?.message || String(error)}`,
|
|
43834
|
+
`Previous version preserved (active prefix: ${windowsInstallerLayout.activePrefix}).`,
|
|
43835
|
+
"See daemon-upgrade.log for the full install/health trace. The next daemon start will retry."
|
|
43836
|
+
]);
|
|
43837
|
+
throw error;
|
|
43838
|
+
}
|
|
43688
43839
|
try {
|
|
43689
43840
|
fs15.unlinkSync(getUpgradeFailureNoticePath());
|
|
43690
43841
|
} catch {
|
|
@@ -48597,6 +48748,16 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
48597
48748
|
generatingDebounceTimer = null;
|
|
48598
48749
|
generatingDebouncePending = null;
|
|
48599
48750
|
lastApprovalEventFingerprint = "";
|
|
48751
|
+
// INTERACTIVE-PROMPT-PUSH: edge-trigger key for the AskUserQuestion / waiting_choice
|
|
48752
|
+
// notification. An AskUserQuestion prompt is surfaced only as a display-only
|
|
48753
|
+
// `waiting_choice` overlay in getState(); the raw adapter status stays idle/generating,
|
|
48754
|
+
// so detectStatusTransition()'s status-keyed arms never fire and no push-worthy
|
|
48755
|
+
// agent:* event is emitted — the owner misses the "ACTION REQUIRED" prompt when the
|
|
48756
|
+
// app is backgrounded. We emit one agent:waiting_approval on ENTRY into the prompt
|
|
48757
|
+
// state (reusing the existing server push path, no cloud change) and dedupe on this
|
|
48758
|
+
// key so repeated status ticks with the same prompt do not re-fire. '' means no
|
|
48759
|
+
// prompt is currently active (cleared when the prompt is answered/gone).
|
|
48760
|
+
lastInteractivePromptEventKey = "";
|
|
48600
48761
|
autoApproveBusy = false;
|
|
48601
48762
|
autoApproveBusyTimer = null;
|
|
48602
48763
|
lastAutoApprovalSignature = "";
|
|
@@ -50967,6 +51128,25 @@ ${buttons.join("\n")}`;
|
|
|
50967
51128
|
}
|
|
50968
51129
|
this.lastStatus = newStatus;
|
|
50969
51130
|
}
|
|
51131
|
+
const interactivePrompt = adapterStatus.activeInteractivePrompt ?? null;
|
|
51132
|
+
if (interactivePrompt && newStatus !== "waiting_approval") {
|
|
51133
|
+
const firstQuestion = interactivePrompt.questions?.[0];
|
|
51134
|
+
const promptKey = `${interactivePrompt.promptId}::${firstQuestion?.question ?? ""}`;
|
|
51135
|
+
if (promptKey !== this.lastInteractivePromptEventKey) {
|
|
51136
|
+
this.lastInteractivePromptEventKey = promptKey;
|
|
51137
|
+
const modalMessage = firstQuestion ? firstQuestion.header ? `${firstQuestion.header}: ${firstQuestion.question}` : firstQuestion.question : void 0;
|
|
51138
|
+
const modalButtons = firstQuestion?.options?.map((option) => option.label);
|
|
51139
|
+
this.pushEvent({
|
|
51140
|
+
event: "agent:waiting_approval",
|
|
51141
|
+
chatTitle,
|
|
51142
|
+
timestamp: now,
|
|
51143
|
+
modalMessage,
|
|
51144
|
+
modalButtons
|
|
51145
|
+
});
|
|
51146
|
+
}
|
|
51147
|
+
} else if (!interactivePrompt && this.lastInteractivePromptEventKey) {
|
|
51148
|
+
this.lastInteractivePromptEventKey = "";
|
|
51149
|
+
}
|
|
50970
51150
|
const firstTurnStartedAt = typeof this.adapter?.currentTurnStartedAt === "number" ? this.adapter.currentTurnStartedAt : 0;
|
|
50971
51151
|
const collapsedAt = this.startupGraceCollapseAt;
|
|
50972
51152
|
const turnStartedWithinCollapseWindow = collapsedAt !== null && firstTurnStartedAt > 0 && firstTurnStartedAt >= collapsedAt && firstTurnStartedAt - collapsedAt < STARTUP_GRACE_IDLE_COLLAPSE_WINDOW_MS;
|
|
@@ -60458,7 +60638,7 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
60458
60638
|
const buildOperatingNotesBestEffort = async (id) => {
|
|
60459
60639
|
try {
|
|
60460
60640
|
const { readOperatingNotes: readOperatingNotes2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
60461
|
-
const noteEntries = readOperatingNotes2(id, { tail:
|
|
60641
|
+
const noteEntries = readOperatingNotes2(id, { tail: 100 });
|
|
60462
60642
|
const notes = noteEntries.map((e) => {
|
|
60463
60643
|
const p = e.payload || {};
|
|
60464
60644
|
const text = typeof p.text === "string" ? p.text.trim() : "";
|
|
@@ -60473,7 +60653,13 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
60473
60653
|
// injection-side selection can honor them. Legacy notes lack
|
|
60474
60654
|
// these → pinned defaults false, expiry governed by category TTL.
|
|
60475
60655
|
pinned: p.pinned === true,
|
|
60476
|
-
...typeof p.expiresAt === "string" ? { expiresAt: p.expiresAt } : {}
|
|
60656
|
+
...typeof p.expiresAt === "string" ? { expiresAt: p.expiresAt } : {},
|
|
60657
|
+
// Phase 2 (b)/(c): thread the ledger id + supersedes/subjectKey
|
|
60658
|
+
// so version-supersede targeting and same-class folding work.
|
|
60659
|
+
// Legacy notes lack them → no supersede, fold by leading [tag].
|
|
60660
|
+
noteId: e.id,
|
|
60661
|
+
...typeof p.supersedes === "string" ? { supersedes: p.supersedes } : {},
|
|
60662
|
+
...typeof p.subjectKey === "string" ? { subjectKey: p.subjectKey } : {}
|
|
60477
60663
|
};
|
|
60478
60664
|
}).filter((n) => n !== null);
|
|
60479
60665
|
return notes.length ? notes : void 0;
|