@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
|
@@ -46,6 +46,10 @@ export declare function createDefaultWindowsAtomicHooks(options: {
|
|
|
46
46
|
cwd: string;
|
|
47
47
|
env: NodeJS.ProcessEnv;
|
|
48
48
|
log: (message: string) => void;
|
|
49
|
+
/** Loopback IPC port to probe for health/version. Defaults to the daemon's local IPC port. */
|
|
50
|
+
healthPort?: number;
|
|
51
|
+
/** How long to poll for the replacement daemon to report the target version. */
|
|
52
|
+
healthTimeoutMs?: number;
|
|
49
53
|
}): WindowsAtomicUpgradeHooks;
|
|
50
54
|
export declare function boundedCleanupInactivePrefixes(layout: WindowsInstallerLayout, activePrefix: string, log: (message: string) => void): void;
|
|
51
55
|
export declare function cleanupInactivePrefixesWithGuard(options: {
|
package/dist/index.js
CHANGED
|
@@ -442,10 +442,10 @@ function readInjected(value) {
|
|
|
442
442
|
}
|
|
443
443
|
function getDaemonBuildInfo() {
|
|
444
444
|
if (cached) return cached;
|
|
445
|
-
const commit = readInjected(true ? "
|
|
446
|
-
const commitShort = readInjected(true ? "
|
|
447
|
-
const version = readInjected(true ? "1.0.18-rc.
|
|
448
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
445
|
+
const commit = readInjected(true ? "3a1a0d16c0dd7ce3df15591fbe30b7e8638ab876" : void 0) ?? "unknown";
|
|
446
|
+
const commitShort = readInjected(true ? "3a1a0d16" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
447
|
+
const version = readInjected(true ? "1.0.18-rc.9" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
448
|
+
const builtAt = readInjected(true ? "2026-07-22T05:27:14.328Z" : void 0);
|
|
449
449
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
450
450
|
return cached;
|
|
451
451
|
}
|
|
@@ -9869,40 +9869,113 @@ function isDurableCategory(category) {
|
|
|
9869
9869
|
if (!category) return true;
|
|
9870
9870
|
return !(category in OPERATING_NOTE_CATEGORY_TTL_DAYS);
|
|
9871
9871
|
}
|
|
9872
|
-
function
|
|
9872
|
+
function deriveSubjectKey(note) {
|
|
9873
|
+
const explicit = typeof note.subjectKey === "string" ? note.subjectKey.trim().toLowerCase() : "";
|
|
9874
|
+
if (explicit) return explicit;
|
|
9875
|
+
const text = typeof note.text === "string" ? note.text.trimStart() : "";
|
|
9876
|
+
const m = /^\[([^\]]{1,80})\]/.exec(text);
|
|
9877
|
+
const tag = m ? m[1].trim().toLowerCase() : "";
|
|
9878
|
+
return tag || void 0;
|
|
9879
|
+
}
|
|
9880
|
+
function foldSameClassNotes(ranked) {
|
|
9881
|
+
const out = [];
|
|
9882
|
+
const survivorByKey = /* @__PURE__ */ new Map();
|
|
9883
|
+
for (const note of ranked) {
|
|
9884
|
+
const subject = deriveSubjectKey(note);
|
|
9885
|
+
const foldable = !note.pinned && !!note.category && !!subject;
|
|
9886
|
+
if (foldable) {
|
|
9887
|
+
const key2 = `${note.category}\0${subject}`;
|
|
9888
|
+
const existing = survivorByKey.get(key2);
|
|
9889
|
+
if (existing !== void 0) {
|
|
9890
|
+
const survivor = out[existing];
|
|
9891
|
+
survivor.subsumedCount += 1;
|
|
9892
|
+
if (typeof note.noteId === "string" && note.noteId) survivor.subsumedIds.push(note.noteId);
|
|
9893
|
+
continue;
|
|
9894
|
+
}
|
|
9895
|
+
survivorByKey.set(key2, out.length);
|
|
9896
|
+
}
|
|
9897
|
+
out.push({ note, subsumedIds: [], subsumedCount: 0 });
|
|
9898
|
+
}
|
|
9899
|
+
return out;
|
|
9900
|
+
}
|
|
9901
|
+
function renderedNoteBytes(folded) {
|
|
9902
|
+
return byteLength2(renderOperatingNoteLine(folded));
|
|
9903
|
+
}
|
|
9904
|
+
function selectOperatingNotesForPrompt(notes, now, cap = OPERATING_NOTES_PROMPT_CAP, byteBudget = OPERATING_NOTE_INJECTION_BYTE_BUDGET) {
|
|
9873
9905
|
const valid = Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
|
|
9874
|
-
|
|
9906
|
+
let kept = valid.map((note, index) => ({ note, index })).filter(({ note }) => note.pinned || !isNoteExpired(note, now));
|
|
9907
|
+
const supersededAtIndex = /* @__PURE__ */ new Map();
|
|
9908
|
+
for (const { note, index } of kept) {
|
|
9909
|
+
const target = typeof note.supersedes === "string" ? note.supersedes.trim().toLowerCase() : "";
|
|
9910
|
+
if (!target) continue;
|
|
9911
|
+
const prev = supersededAtIndex.get(target);
|
|
9912
|
+
if (prev === void 0 || index > prev) supersededAtIndex.set(target, index);
|
|
9913
|
+
}
|
|
9914
|
+
if (supersededAtIndex.size > 0) {
|
|
9915
|
+
kept = kept.filter(({ note, index }) => {
|
|
9916
|
+
if (note.pinned) return true;
|
|
9917
|
+
const byId = typeof note.noteId === "string" ? note.noteId.trim().toLowerCase() : "";
|
|
9918
|
+
const bySubject = deriveSubjectKey(note);
|
|
9919
|
+
const supIdx = Math.max(
|
|
9920
|
+
byId ? supersededAtIndex.get(byId) ?? -1 : -1,
|
|
9921
|
+
bySubject ? supersededAtIndex.get(bySubject) ?? -1 : -1
|
|
9922
|
+
);
|
|
9923
|
+
return !(supIdx > index);
|
|
9924
|
+
});
|
|
9925
|
+
}
|
|
9875
9926
|
const rank = (n) => n.pinned ? 0 : isDurableCategory(n.category) ? 1 : 2;
|
|
9876
9927
|
kept.sort((a, b) => {
|
|
9877
9928
|
const r = rank(a.note) - rank(b.note);
|
|
9878
9929
|
if (r !== 0) return r;
|
|
9879
9930
|
return b.index - a.index;
|
|
9880
9931
|
});
|
|
9881
|
-
const
|
|
9882
|
-
const shown =
|
|
9932
|
+
const folded = foldSameClassNotes(kept.map((k) => k.note));
|
|
9933
|
+
const shown = [];
|
|
9934
|
+
let usedBytes = 0;
|
|
9935
|
+
let usedCount = 0;
|
|
9936
|
+
for (const entry of folded) {
|
|
9937
|
+
if (entry.note.pinned) {
|
|
9938
|
+
shown.push(entry);
|
|
9939
|
+
usedBytes += renderedNoteBytes(entry);
|
|
9940
|
+
usedCount += 1;
|
|
9941
|
+
continue;
|
|
9942
|
+
}
|
|
9943
|
+
if (usedCount >= cap) break;
|
|
9944
|
+
const bytes = renderedNoteBytes(entry);
|
|
9945
|
+
if (usedCount > 0 && usedBytes + bytes > byteBudget) break;
|
|
9946
|
+
shown.push(entry);
|
|
9947
|
+
usedBytes += bytes;
|
|
9948
|
+
usedCount += 1;
|
|
9949
|
+
}
|
|
9950
|
+
const omittedCount = Math.max(0, folded.length - shown.length);
|
|
9883
9951
|
return { shown, omittedCount };
|
|
9884
9952
|
}
|
|
9885
|
-
function
|
|
9886
|
-
const
|
|
9887
|
-
if (!hasAny) return "";
|
|
9953
|
+
function renderOperatingNoteLine(folded) {
|
|
9954
|
+
const n = folded.note;
|
|
9888
9955
|
const categoryLabel = {
|
|
9889
9956
|
provider_quirk: "provider quirk",
|
|
9890
9957
|
pattern_to_avoid: "pattern to avoid",
|
|
9891
9958
|
recovery_lesson: "recovery lesson"
|
|
9892
9959
|
};
|
|
9960
|
+
const pin = n.pinned ? "\u{1F4CC} " : "";
|
|
9961
|
+
const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
|
|
9962
|
+
const fold = folded.subsumedCount > 0 ? ` _(+${folded.subsumedCount} earlier same-subject note${folded.subsumedCount === 1 ? "" : "s"} folded${folded.subsumedIds.length ? `: ${folded.subsumedIds.join(", ")}` : ""})_` : "";
|
|
9963
|
+
return `- ${pin}${cat}${truncateNote(n.text.trim())}${fold}`;
|
|
9964
|
+
}
|
|
9965
|
+
function buildOperatingNotesSection(notes, now = Date.now()) {
|
|
9966
|
+
const hasAny = Array.isArray(notes) ? notes.some((n) => n && typeof n.text === "string" && n.text.trim()) : false;
|
|
9967
|
+
if (!hasAny) return "";
|
|
9893
9968
|
const { shown, omittedCount } = selectOperatingNotesForPrompt(notes ?? [], now);
|
|
9894
9969
|
if (shown.length === 0) return "";
|
|
9895
9970
|
const lines = ["## Operating Notes", ""];
|
|
9896
9971
|
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.");
|
|
9897
9972
|
lines.push("");
|
|
9898
|
-
for (const
|
|
9899
|
-
|
|
9900
|
-
const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
|
|
9901
|
-
lines.push(`- ${pin}${cat}${truncateNote(n.text.trim())}`);
|
|
9973
|
+
for (const entry of shown) {
|
|
9974
|
+
lines.push(renderOperatingNoteLine(entry));
|
|
9902
9975
|
}
|
|
9903
9976
|
if (omittedCount > 0) {
|
|
9904
9977
|
lines.push("");
|
|
9905
|
-
lines.push(`_${omittedCount} lower-priority note${omittedCount === 1 ? "" : "s"} omitted (kept in ledger; expired
|
|
9978
|
+
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\`)._`);
|
|
9906
9979
|
}
|
|
9907
9980
|
return lines.join("\n");
|
|
9908
9981
|
}
|
|
@@ -10026,7 +10099,7 @@ When you compose the task message you dispatch to a node, include these requirem
|
|
|
10026
10099
|
- **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.
|
|
10027
10100
|
- **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.`;
|
|
10028
10101
|
}
|
|
10029
|
-
var fs4, os3, path9, PROMPT_SOFT_CAP_BYTES, OPERATING_NOTES_PROMPT_CAP, OPERATING_NOTE_MAX_CHARS, TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION, ONBOARDING_SECTION;
|
|
10102
|
+
var fs4, os3, path9, 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;
|
|
10030
10103
|
var init_coordinator_prompt = __esm({
|
|
10031
10104
|
"src/mesh/coordinator-prompt.ts"() {
|
|
10032
10105
|
"use strict";
|
|
@@ -10041,6 +10114,7 @@ var init_coordinator_prompt = __esm({
|
|
|
10041
10114
|
PROMPT_SOFT_CAP_BYTES = 60 * 1024;
|
|
10042
10115
|
OPERATING_NOTES_PROMPT_CAP = 20;
|
|
10043
10116
|
OPERATING_NOTE_MAX_CHARS = 300;
|
|
10117
|
+
OPERATING_NOTE_INJECTION_BYTE_BUDGET = 6 * 1024;
|
|
10044
10118
|
TOOLS_SECTION = `## Available Tools
|
|
10045
10119
|
|
|
10046
10120
|
| Tool | Purpose |
|
|
@@ -11810,9 +11884,13 @@ function normalizeOperatingNote(value) {
|
|
|
11810
11884
|
...typeof value.createdAt === "string" ? { createdAt: value.createdAt } : {},
|
|
11811
11885
|
...typeof value.sourceCoordinator === "string" ? { sourceCoordinator: value.sourceCoordinator } : {},
|
|
11812
11886
|
// Operating-notes lifecycle: a repo-declared note may pin itself or set an
|
|
11813
|
-
// explicit expiry, same as a runtime-recorded one.
|
|
11887
|
+
// explicit expiry, same as a runtime-recorded one. Phase 2 (b)/(c): it may
|
|
11888
|
+
// also declare supersedes/subjectKey to retire an earlier note or group
|
|
11889
|
+
// same-subject notes for folding.
|
|
11814
11890
|
...value.pinned === true ? { pinned: true } : {},
|
|
11815
|
-
...typeof value.expiresAt === "string" ? { expiresAt: value.expiresAt } : {}
|
|
11891
|
+
...typeof value.expiresAt === "string" ? { expiresAt: value.expiresAt } : {},
|
|
11892
|
+
...typeof value.supersedes === "string" ? { supersedes: value.supersedes } : {},
|
|
11893
|
+
...typeof value.subjectKey === "string" ? { subjectKey: value.subjectKey } : {}
|
|
11816
11894
|
};
|
|
11817
11895
|
}
|
|
11818
11896
|
function normalizeRepoMeshDeclarativeConfig(parsed) {
|
|
@@ -16561,6 +16639,33 @@ function isTargetNodeTransientlyUnresolved(mesh, task) {
|
|
|
16561
16639
|
}
|
|
16562
16640
|
return isWithinCloneBootstrapGrace(targetNodeId);
|
|
16563
16641
|
}
|
|
16642
|
+
function resolveDeadTargetVerdict(components, meshId, mesh, task) {
|
|
16643
|
+
const NOT_DEAD = { dead: false, nodeDead: false, reason: "" };
|
|
16644
|
+
const targetSessionId = readNonEmptyString(task.targetSessionId);
|
|
16645
|
+
const targetNodeId = readNonEmptyString(task.targetNodeId);
|
|
16646
|
+
if (!targetSessionId && !targetNodeId) return NOT_DEAD;
|
|
16647
|
+
const lastUpdateMs = Date.parse(task.updatedAt || task.createdAt || "");
|
|
16648
|
+
if (Number.isFinite(lastUpdateMs) && Date.now() - lastUpdateMs < DEAD_TARGET_GRACE_MS) return NOT_DEAD;
|
|
16649
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
16650
|
+
if (targetNodeId) {
|
|
16651
|
+
const nodePresent = nodes.some((n) => meshNodeIdMatches(n, targetNodeId));
|
|
16652
|
+
if (!nodePresent) {
|
|
16653
|
+
if (isTargetNodeTransientlyUnresolved(mesh, task)) return NOT_DEAD;
|
|
16654
|
+
return { dead: true, nodeDead: true, reason: "dead_target_node_absent" };
|
|
16655
|
+
}
|
|
16656
|
+
}
|
|
16657
|
+
if (targetSessionId) {
|
|
16658
|
+
const node = targetNodeId ? nodes.find((n) => meshNodeIdMatches(n, targetNodeId)) : void 0;
|
|
16659
|
+
const nodeIsLocal = node ? isLocalAutoLaunchNode(node) : true;
|
|
16660
|
+
if (nodeIsLocal) {
|
|
16661
|
+
const verdict = resolveSessionBusyVerdict(components, targetSessionId);
|
|
16662
|
+
if (verdict === "UNKNOWN") {
|
|
16663
|
+
return { dead: true, nodeDead: false, reason: "dead_target_session_absent" };
|
|
16664
|
+
}
|
|
16665
|
+
}
|
|
16666
|
+
}
|
|
16667
|
+
return NOT_DEAD;
|
|
16668
|
+
}
|
|
16564
16669
|
function retractActionableSkipIfPreviouslyNotified(meshId, taskId) {
|
|
16565
16670
|
const dedupKey = `${meshId}:${taskId}`;
|
|
16566
16671
|
if (!lastActionableSkipNotified.delete(dedupKey)) return;
|
|
@@ -17078,6 +17183,21 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
17078
17183
|
continue;
|
|
17079
17184
|
}
|
|
17080
17185
|
if (task.targetSessionId) {
|
|
17186
|
+
const deadTarget = resolveDeadTargetVerdict(components, meshId, mesh, task);
|
|
17187
|
+
if (deadTarget.dead) {
|
|
17188
|
+
const requeued = requeueTask(meshId, task.id, {
|
|
17189
|
+
reason: deadTarget.reason,
|
|
17190
|
+
clearTargetSession: true,
|
|
17191
|
+
// Keep the node pin if only the SESSION died on a still-live node; clear it
|
|
17192
|
+
// when the NODE itself is absent (nothing to pin to).
|
|
17193
|
+
clearTargetNode: deadTarget.nodeDead
|
|
17194
|
+
});
|
|
17195
|
+
if (requeued) {
|
|
17196
|
+
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}).`);
|
|
17197
|
+
}
|
|
17198
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_dead_requeued" });
|
|
17199
|
+
continue;
|
|
17200
|
+
}
|
|
17081
17201
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "target_session_constraint" });
|
|
17082
17202
|
continue;
|
|
17083
17203
|
}
|
|
@@ -17649,7 +17769,7 @@ function runIdleMaintenanceThenAssignQueue(components, args) {
|
|
|
17649
17769
|
});
|
|
17650
17770
|
});
|
|
17651
17771
|
}
|
|
17652
|
-
var import_fs13, 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;
|
|
17772
|
+
var import_fs13, 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;
|
|
17653
17773
|
var init_mesh_queue_assignment = __esm({
|
|
17654
17774
|
"src/mesh/mesh-queue-assignment.ts"() {
|
|
17655
17775
|
"use strict";
|
|
@@ -17711,6 +17831,7 @@ var init_mesh_queue_assignment = __esm({
|
|
|
17711
17831
|
];
|
|
17712
17832
|
TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON = "target_node_bootstrap_pending";
|
|
17713
17833
|
lastActionableSkipNotified = /* @__PURE__ */ new Map();
|
|
17834
|
+
DEAD_TARGET_GRACE_MS = 6e4;
|
|
17714
17835
|
}
|
|
17715
17836
|
});
|
|
17716
17837
|
|
|
@@ -43317,6 +43438,40 @@ async function stopOwnedProcessesForPrefixes(options) {
|
|
|
43317
43438
|
var POINTER_NAME = ".adhdev-current";
|
|
43318
43439
|
var STABLE_FILES = [POINTER_NAME, "adhdev.cmd", "adhdev.ps1", "adhdev"];
|
|
43319
43440
|
var DEFAULT_HEALTH_PORT = 19222;
|
|
43441
|
+
function fetchLocalJson(port, pathname) {
|
|
43442
|
+
return new Promise((resolve27) => {
|
|
43443
|
+
const req = http2.get(`http://127.0.0.1:${port}${pathname}`, { timeout: 1500 }, (res) => {
|
|
43444
|
+
let body = "";
|
|
43445
|
+
res.setEncoding("utf8");
|
|
43446
|
+
res.on("data", (chunk) => {
|
|
43447
|
+
body += chunk;
|
|
43448
|
+
});
|
|
43449
|
+
res.on("end", () => resolve27({ ok: res.statusCode === 200, body }));
|
|
43450
|
+
});
|
|
43451
|
+
req.on("timeout", () => req.destroy());
|
|
43452
|
+
req.on("error", () => resolve27({ ok: false, body: "" }));
|
|
43453
|
+
});
|
|
43454
|
+
}
|
|
43455
|
+
async function fetchLocalHealth(port) {
|
|
43456
|
+
const { ok, body } = await fetchLocalJson(port, "/health");
|
|
43457
|
+
if (!ok) return { ok: false };
|
|
43458
|
+
try {
|
|
43459
|
+
const pid = Number(JSON.parse(body)?.pid);
|
|
43460
|
+
return { ok: true, pid: Number.isFinite(pid) ? pid : void 0 };
|
|
43461
|
+
} catch {
|
|
43462
|
+
return { ok: false };
|
|
43463
|
+
}
|
|
43464
|
+
}
|
|
43465
|
+
async function fetchLocalStatusVersion(port) {
|
|
43466
|
+
const { ok, body } = await fetchLocalJson(port, "/api/v1/status");
|
|
43467
|
+
if (!ok) return void 0;
|
|
43468
|
+
try {
|
|
43469
|
+
const version = JSON.parse(body)?.status?.version;
|
|
43470
|
+
return typeof version === "string" ? version : void 0;
|
|
43471
|
+
} catch {
|
|
43472
|
+
return void 0;
|
|
43473
|
+
}
|
|
43474
|
+
}
|
|
43320
43475
|
var ADHDEV_OWNED_MARKERS = [
|
|
43321
43476
|
"session-host-daemon",
|
|
43322
43477
|
"node_modules/adhdev",
|
|
@@ -43594,6 +43749,8 @@ async function performWindowsAtomicUpgrade(options) {
|
|
|
43594
43749
|
}
|
|
43595
43750
|
}
|
|
43596
43751
|
function createDefaultWindowsAtomicHooks(options) {
|
|
43752
|
+
const healthPort = options.healthPort ?? DEFAULT_HEALTH_PORT;
|
|
43753
|
+
const healthTimeoutMs = options.healthTimeoutMs ?? 3e4;
|
|
43597
43754
|
return {
|
|
43598
43755
|
install: (stagedPrefix, portableNode) => {
|
|
43599
43756
|
const env = {
|
|
@@ -43604,7 +43761,7 @@ function createDefaultWindowsAtomicHooks(options) {
|
|
|
43604
43761
|
};
|
|
43605
43762
|
const pathKey = Object.keys(env).find((key2) => key2.toLowerCase() === "path") || "Path";
|
|
43606
43763
|
env[pathKey] = `${path20.dirname(portableNode)};${env[pathKey] || ""}`;
|
|
43607
|
-
(0, import_child_process6.execFileSync)(portableNode, [
|
|
43764
|
+
const installOutput = String((0, import_child_process6.execFileSync)(portableNode, [
|
|
43608
43765
|
options.npmCliPath,
|
|
43609
43766
|
"install",
|
|
43610
43767
|
"-g",
|
|
@@ -43619,7 +43776,8 @@ function createDefaultWindowsAtomicHooks(options) {
|
|
|
43619
43776
|
maxBuffer: 20 * 1024 * 1024,
|
|
43620
43777
|
windowsHide: true,
|
|
43621
43778
|
env
|
|
43622
|
-
});
|
|
43779
|
+
}));
|
|
43780
|
+
if (installOutput.trim()) options.log(installOutput.trim());
|
|
43623
43781
|
},
|
|
43624
43782
|
restart: (portableNode, stagedCliEntry) => {
|
|
43625
43783
|
const restartArgv = options.restartArgv.map((arg, index) => index === 0 ? stagedCliEntry : arg);
|
|
@@ -43646,28 +43804,12 @@ function createDefaultWindowsAtomicHooks(options) {
|
|
|
43646
43804
|
child.unref();
|
|
43647
43805
|
},
|
|
43648
43806
|
waitForHealth: async (pid, targetVersion) => {
|
|
43649
|
-
const deadline = Date.now() +
|
|
43807
|
+
const deadline = Date.now() + healthTimeoutMs;
|
|
43650
43808
|
while (Date.now() < deadline) {
|
|
43651
|
-
const
|
|
43652
|
-
|
|
43653
|
-
|
|
43654
|
-
|
|
43655
|
-
res.on("data", (chunk) => {
|
|
43656
|
-
body += chunk;
|
|
43657
|
-
});
|
|
43658
|
-
res.on("end", () => {
|
|
43659
|
-
let responsePid;
|
|
43660
|
-
try {
|
|
43661
|
-
responsePid = Number(JSON.parse(body)?.pid);
|
|
43662
|
-
} catch {
|
|
43663
|
-
}
|
|
43664
|
-
resolve27({ ok: res.statusCode === 200, pid: responsePid, body });
|
|
43665
|
-
});
|
|
43666
|
-
});
|
|
43667
|
-
req.on("timeout", () => req.destroy());
|
|
43668
|
-
req.on("error", () => resolve27({ ok: false }));
|
|
43669
|
-
});
|
|
43670
|
-
if (result.ok && result.pid === pid && result.body?.includes(targetVersion)) return true;
|
|
43809
|
+
const liveness = await fetchLocalHealth(healthPort);
|
|
43810
|
+
const alive = liveness.ok && liveness.pid === pid;
|
|
43811
|
+
const version = alive ? await fetchLocalStatusVersion(healthPort) : void 0;
|
|
43812
|
+
if (alive && version === targetVersion) return true;
|
|
43671
43813
|
await new Promise((resolve27) => setTimeout(resolve27, 500));
|
|
43672
43814
|
}
|
|
43673
43815
|
return false;
|
|
@@ -44096,22 +44238,31 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
44096
44238
|
`Cannot upgrade: owned processes still running under current prefix: ${preStop.survivors.map((s2) => s2.pid).join(", ")}`
|
|
44097
44239
|
);
|
|
44098
44240
|
}
|
|
44099
|
-
|
|
44100
|
-
|
|
44101
|
-
|
|
44102
|
-
targetVersion: payload.targetVersion,
|
|
44103
|
-
portableNode,
|
|
44104
|
-
excludePids: upgradePids,
|
|
44105
|
-
hooks: createDefaultWindowsAtomicHooks({
|
|
44241
|
+
try {
|
|
44242
|
+
await performWindowsAtomicUpgrade({
|
|
44243
|
+
layout: windowsInstallerLayout,
|
|
44106
44244
|
packageName: payload.packageName,
|
|
44107
44245
|
targetVersion: payload.targetVersion,
|
|
44108
|
-
|
|
44109
|
-
|
|
44110
|
-
|
|
44111
|
-
|
|
44112
|
-
|
|
44113
|
-
|
|
44114
|
-
|
|
44246
|
+
portableNode,
|
|
44247
|
+
excludePids: upgradePids,
|
|
44248
|
+
hooks: createDefaultWindowsAtomicHooks({
|
|
44249
|
+
packageName: payload.packageName,
|
|
44250
|
+
targetVersion: payload.targetVersion,
|
|
44251
|
+
npmCliPath,
|
|
44252
|
+
restartArgv,
|
|
44253
|
+
cwd: payload.cwd || process.cwd(),
|
|
44254
|
+
env: Object.fromEntries(Object.entries(process.env).filter(([key2]) => key2 !== UPGRADE_HELPER_ENV)),
|
|
44255
|
+
log: appendUpgradeLog
|
|
44256
|
+
})
|
|
44257
|
+
});
|
|
44258
|
+
} catch (error) {
|
|
44259
|
+
emitUpgradeFailureNotice([
|
|
44260
|
+
`adhdev ${payload.packageName}@${payload.targetVersion} upgrade failed and was rolled back: ${error?.message || String(error)}`,
|
|
44261
|
+
`Previous version preserved (active prefix: ${windowsInstallerLayout.activePrefix}).`,
|
|
44262
|
+
"See daemon-upgrade.log for the full install/health trace. The next daemon start will retry."
|
|
44263
|
+
]);
|
|
44264
|
+
throw error;
|
|
44265
|
+
}
|
|
44115
44266
|
try {
|
|
44116
44267
|
fs15.unlinkSync(getUpgradeFailureNoticePath());
|
|
44117
44268
|
} catch {
|
|
@@ -49024,6 +49175,16 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
49024
49175
|
generatingDebounceTimer = null;
|
|
49025
49176
|
generatingDebouncePending = null;
|
|
49026
49177
|
lastApprovalEventFingerprint = "";
|
|
49178
|
+
// INTERACTIVE-PROMPT-PUSH: edge-trigger key for the AskUserQuestion / waiting_choice
|
|
49179
|
+
// notification. An AskUserQuestion prompt is surfaced only as a display-only
|
|
49180
|
+
// `waiting_choice` overlay in getState(); the raw adapter status stays idle/generating,
|
|
49181
|
+
// so detectStatusTransition()'s status-keyed arms never fire and no push-worthy
|
|
49182
|
+
// agent:* event is emitted — the owner misses the "ACTION REQUIRED" prompt when the
|
|
49183
|
+
// app is backgrounded. We emit one agent:waiting_approval on ENTRY into the prompt
|
|
49184
|
+
// state (reusing the existing server push path, no cloud change) and dedupe on this
|
|
49185
|
+
// key so repeated status ticks with the same prompt do not re-fire. '' means no
|
|
49186
|
+
// prompt is currently active (cleared when the prompt is answered/gone).
|
|
49187
|
+
lastInteractivePromptEventKey = "";
|
|
49027
49188
|
autoApproveBusy = false;
|
|
49028
49189
|
autoApproveBusyTimer = null;
|
|
49029
49190
|
lastAutoApprovalSignature = "";
|
|
@@ -51394,6 +51555,25 @@ ${buttons.join("\n")}`;
|
|
|
51394
51555
|
}
|
|
51395
51556
|
this.lastStatus = newStatus;
|
|
51396
51557
|
}
|
|
51558
|
+
const interactivePrompt = adapterStatus.activeInteractivePrompt ?? null;
|
|
51559
|
+
if (interactivePrompt && newStatus !== "waiting_approval") {
|
|
51560
|
+
const firstQuestion = interactivePrompt.questions?.[0];
|
|
51561
|
+
const promptKey = `${interactivePrompt.promptId}::${firstQuestion?.question ?? ""}`;
|
|
51562
|
+
if (promptKey !== this.lastInteractivePromptEventKey) {
|
|
51563
|
+
this.lastInteractivePromptEventKey = promptKey;
|
|
51564
|
+
const modalMessage = firstQuestion ? firstQuestion.header ? `${firstQuestion.header}: ${firstQuestion.question}` : firstQuestion.question : void 0;
|
|
51565
|
+
const modalButtons = firstQuestion?.options?.map((option) => option.label);
|
|
51566
|
+
this.pushEvent({
|
|
51567
|
+
event: "agent:waiting_approval",
|
|
51568
|
+
chatTitle,
|
|
51569
|
+
timestamp: now,
|
|
51570
|
+
modalMessage,
|
|
51571
|
+
modalButtons
|
|
51572
|
+
});
|
|
51573
|
+
}
|
|
51574
|
+
} else if (!interactivePrompt && this.lastInteractivePromptEventKey) {
|
|
51575
|
+
this.lastInteractivePromptEventKey = "";
|
|
51576
|
+
}
|
|
51397
51577
|
const firstTurnStartedAt = typeof this.adapter?.currentTurnStartedAt === "number" ? this.adapter.currentTurnStartedAt : 0;
|
|
51398
51578
|
const collapsedAt = this.startupGraceCollapseAt;
|
|
51399
51579
|
const turnStartedWithinCollapseWindow = collapsedAt !== null && firstTurnStartedAt > 0 && firstTurnStartedAt >= collapsedAt && firstTurnStartedAt - collapsedAt < STARTUP_GRACE_IDLE_COLLAPSE_WINDOW_MS;
|
|
@@ -60880,7 +61060,7 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
60880
61060
|
const buildOperatingNotesBestEffort = async (id) => {
|
|
60881
61061
|
try {
|
|
60882
61062
|
const { readOperatingNotes: readOperatingNotes2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
60883
|
-
const noteEntries = readOperatingNotes2(id, { tail:
|
|
61063
|
+
const noteEntries = readOperatingNotes2(id, { tail: 100 });
|
|
60884
61064
|
const notes = noteEntries.map((e) => {
|
|
60885
61065
|
const p = e.payload || {};
|
|
60886
61066
|
const text = typeof p.text === "string" ? p.text.trim() : "";
|
|
@@ -60895,7 +61075,13 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
60895
61075
|
// injection-side selection can honor them. Legacy notes lack
|
|
60896
61076
|
// these → pinned defaults false, expiry governed by category TTL.
|
|
60897
61077
|
pinned: p.pinned === true,
|
|
60898
|
-
...typeof p.expiresAt === "string" ? { expiresAt: p.expiresAt } : {}
|
|
61078
|
+
...typeof p.expiresAt === "string" ? { expiresAt: p.expiresAt } : {},
|
|
61079
|
+
// Phase 2 (b)/(c): thread the ledger id + supersedes/subjectKey
|
|
61080
|
+
// so version-supersede targeting and same-class folding work.
|
|
61081
|
+
// Legacy notes lack them → no supersede, fold by leading [tag].
|
|
61082
|
+
noteId: e.id,
|
|
61083
|
+
...typeof p.supersedes === "string" ? { supersedes: p.supersedes } : {},
|
|
61084
|
+
...typeof p.subjectKey === "string" ? { subjectKey: p.subjectKey } : {}
|
|
60899
61085
|
};
|
|
60900
61086
|
}).filter((n) => n !== null);
|
|
60901
61087
|
return notes.length ? notes : void 0;
|