@adhdev/daemon-core 0.9.82-rc.293 → 0.9.82-rc.294

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 CHANGED
@@ -275,10 +275,10 @@ function readInjected(value) {
275
275
  }
276
276
  function getDaemonBuildInfo() {
277
277
  if (cached) return cached;
278
- const commit = readInjected(true ? "88f97abcc85d83fe5d5313b229d32a7d76b1208a" : void 0) ?? "unknown";
279
- const commitShort = readInjected(true ? "88f97abc" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
280
- const version = readInjected(true ? "0.9.82-rc.293" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
281
- const builtAt = readInjected(true ? "2026-06-16T11:13:51.625Z" : void 0);
278
+ const commit = readInjected(true ? "6ee0e52b0b7347870577ebe598054d87127078fe" : void 0) ?? "unknown";
279
+ const commitShort = readInjected(true ? "6ee0e52b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
280
+ const version = readInjected(true ? "0.9.82-rc.294" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
281
+ const builtAt = readInjected(true ? "2026-06-16T12:15:42.290Z" : void 0);
282
282
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
283
283
  return cached;
284
284
  }
@@ -2009,6 +2009,7 @@ function buildRulesSection(coordinatorCliType) {
2009
2009
  - **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
2010
2010
  - **Limit parallelism.** Start with 1\u20132 tasks; scale only on success. Never duplicate a session because \`mesh_read_chat\` shows no final message while tool/terminal activity is ongoing. This caps *concurrent* load \u2014 it does not mean serialize independent work: when a new, independent request arrives and there is headroom under \`maxParallelTasks\`, dispatch it right away rather than waiting for an in-flight task or a user nudge (read-only diagnosis especially, since it has no merge cost).
2011
2011
  - **Check history first.** Call \`mesh_task_history\` at session start to avoid duplicate work and inform recovery. On failure, read task history before retrying.
2012
+ - **Sequence shared-base-moving merges.** Parallel dispatch is encouraged, but merging one worktree can advance another in-flight worktree's base \u2014 especially the oss submodule pointer \u2014 turning a clean fast-forward into a diverged rebase (patch-equivalence correctly blocks this). Before merging an in-flight worktree while siblings are also in flight, land in an intentional order, re-clone long-running worktrees from the advanced base, or expect to manually rebase + ff-only the laggards; merging an independent fix mid-flight can strand siblings into a rebase.
2012
2013
  - **Converge branches.** After worktree tasks: refine/fast-forward, or classify as \`pushed_feature_branch_needs_merge\` / \`blocked_review\` / \`cleanup_candidate\` / \`not_mergeable\`. Clean up with \`mesh_remove_node\`.
2013
2014
  - **Refinery is config-driven.** \`mesh_refine_node\` must run validation from \`.adhdev/refine.{json,yaml,yml}\` or \`repo-mesh.refine.*\`. Heuristics are scaffolding only.
2014
2015
  - **Submodule reachability = publish-needed.** \`submodule_reachability_failed\` \u2192 classify as \`blocked_review\`, request user approval to push to submodule main, then rerun \`mesh_refine_node\`.
@@ -21912,22 +21913,160 @@ function isBoundedTailRequest(limit, offset, excludeRecentCount) {
21912
21913
  if (!Number.isFinite(numericOffset) || !Number.isFinite(numericExclude)) return false;
21913
21914
  return true;
21914
21915
  }
21916
+ var REVERSE_TAIL_SMALL_FILE_BYTES = 64 * 1024;
21917
+ var REVERSE_TAIL_CHUNK_BYTES = 64 * 1024;
21918
+ var TAIL_LINES_RETAINED = BOUNDED_TAIL_MAX_LIMIT + 2 * BOUNDED_TAIL_SLACK;
21919
+ var INCREMENTAL_TAIL_CACHE_MAX_ENTRIES = 64;
21920
+ var incrementalTailCache = /* @__PURE__ */ new Map();
21921
+ function evictIncrementalTailCache() {
21922
+ while (incrementalTailCache.size > INCREMENTAL_TAIL_CACHE_MAX_ENTRIES) {
21923
+ const oldest = incrementalTailCache.keys().next().value;
21924
+ if (oldest === void 0) break;
21925
+ incrementalTailCache.delete(oldest);
21926
+ }
21927
+ }
21928
+ function splitBufferLines(buf) {
21929
+ const lines = [];
21930
+ let lineEnd = buf.length;
21931
+ let firstNewline = -1;
21932
+ for (let i = buf.length - 1; i >= 0; i--) {
21933
+ if (buf[i] !== 10) continue;
21934
+ if (i + 1 < lineEnd) {
21935
+ lines.push(buf.toString("utf-8", i + 1, lineEnd));
21936
+ }
21937
+ lineEnd = i;
21938
+ firstNewline = i;
21939
+ }
21940
+ lines.reverse();
21941
+ const head = firstNewline >= 0 ? buf.subarray(0, firstNewline) : buf;
21942
+ return { head, lines };
21943
+ }
21944
+ function readReverseTailLines(filePath, needed) {
21945
+ const fd = fs5.openSync(filePath, "r");
21946
+ try {
21947
+ const stat2 = fs5.fstatSync(fd);
21948
+ const size = stat2.size;
21949
+ let position = size;
21950
+ let carry = Buffer.alloc(0);
21951
+ const collected = [];
21952
+ while (position > 0 && collected.length < needed) {
21953
+ const chunkSize = Math.min(REVERSE_TAIL_CHUNK_BYTES, position);
21954
+ position -= chunkSize;
21955
+ const chunk = Buffer.alloc(chunkSize);
21956
+ fs5.readSync(fd, chunk, 0, chunkSize, position);
21957
+ const combined = carry.length ? Buffer.concat([chunk, carry]) : chunk;
21958
+ const { head, lines } = splitBufferLines(combined);
21959
+ carry = head;
21960
+ for (let i = lines.length - 1; i >= 0; i--) {
21961
+ collected.push(lines[i]);
21962
+ }
21963
+ }
21964
+ const reachedStart = position <= 0;
21965
+ if (reachedStart && carry.length) {
21966
+ collected.push(carry.toString("utf-8"));
21967
+ }
21968
+ collected.reverse();
21969
+ return { lines: collected, coversWholeFile: reachedStart, size, mtimeMs: stat2.mtimeMs };
21970
+ } finally {
21971
+ fs5.closeSync(fd);
21972
+ }
21973
+ }
21974
+ function readFileTailLines(filePath, needed) {
21975
+ let stat2;
21976
+ try {
21977
+ stat2 = fs5.statSync(filePath);
21978
+ } catch {
21979
+ return { lines: [], coversWholeFile: true };
21980
+ }
21981
+ const size = stat2.size;
21982
+ const mtimeMs = stat2.mtimeMs;
21983
+ if (size === 0) {
21984
+ incrementalTailCache.delete(filePath);
21985
+ return { lines: [], coversWholeFile: true };
21986
+ }
21987
+ const cached2 = incrementalTailCache.get(filePath);
21988
+ if (cached2) {
21989
+ if (cached2.size === size && cached2.mtimeMs === mtimeMs) {
21990
+ incrementalTailCache.delete(filePath);
21991
+ incrementalTailCache.set(filePath, cached2);
21992
+ if (cached2.coversWholeFile || cached2.lines.length >= needed) {
21993
+ return { lines: cached2.lines, coversWholeFile: cached2.coversWholeFile };
21994
+ }
21995
+ } else if (size > cached2.size) {
21996
+ const incremental = tryIncrementalTailGrowth(filePath, cached2, size, mtimeMs, needed);
21997
+ if (incremental) return { lines: incremental.lines, coversWholeFile: incremental.coversWholeFile };
21998
+ }
21999
+ incrementalTailCache.delete(filePath);
22000
+ }
22001
+ if (size <= REVERSE_TAIL_SMALL_FILE_BYTES) {
22002
+ let content;
22003
+ try {
22004
+ content = fs5.readFileSync(filePath, "utf-8");
22005
+ } catch {
22006
+ return { lines: [], coversWholeFile: true };
22007
+ }
22008
+ const lines = content.split("\n");
22009
+ if (lines.length && lines[lines.length - 1] === "") lines.pop();
22010
+ storeIncrementalTailCache(filePath, size, mtimeMs, lines, true);
22011
+ return { lines, coversWholeFile: true };
22012
+ }
22013
+ let result;
22014
+ try {
22015
+ result = readReverseTailLines(filePath, needed);
22016
+ } catch {
22017
+ return { lines: [], coversWholeFile: true };
22018
+ }
22019
+ storeIncrementalTailCache(filePath, result.size, result.mtimeMs, result.lines, result.coversWholeFile);
22020
+ return { lines: result.lines, coversWholeFile: result.coversWholeFile };
22021
+ }
22022
+ function tryIncrementalTailGrowth(filePath, cached2, size, mtimeMs, needed) {
22023
+ const fd = fs5.openSync(filePath, "r");
22024
+ try {
22025
+ if (cached2.size > 0) {
22026
+ const boundary = Buffer.alloc(1);
22027
+ fs5.readSync(fd, boundary, 0, 1, cached2.size - 1);
22028
+ if (boundary[0] !== 10) return null;
22029
+ }
22030
+ const appendedLength = size - cached2.size;
22031
+ const appended = Buffer.alloc(appendedLength);
22032
+ fs5.readSync(fd, appended, 0, appendedLength, cached2.size);
22033
+ const newLines = appended.toString("utf-8").split("\n");
22034
+ if (newLines.length && newLines[newLines.length - 1] === "") newLines.pop();
22035
+ const merged = cached2.lines.concat(newLines);
22036
+ const trimmed = merged.length > TAIL_LINES_RETAINED ? merged.slice(merged.length - TAIL_LINES_RETAINED) : merged;
22037
+ const coversWholeFile = cached2.coversWholeFile && trimmed.length === merged.length;
22038
+ storeIncrementalTailCache(filePath, size, mtimeMs, trimmed, coversWholeFile);
22039
+ if (coversWholeFile || trimmed.length >= needed) {
22040
+ return { lines: trimmed, coversWholeFile };
22041
+ }
22042
+ return { lines: trimmed, coversWholeFile };
22043
+ } catch {
22044
+ return null;
22045
+ } finally {
22046
+ fs5.closeSync(fd);
22047
+ }
22048
+ }
22049
+ function storeIncrementalTailCache(filePath, size, mtimeMs, lines, coversWholeFile) {
22050
+ const retained = lines.length > TAIL_LINES_RETAINED ? lines.slice(lines.length - TAIL_LINES_RETAINED) : lines;
22051
+ const covers = coversWholeFile && retained.length === lines.length;
22052
+ incrementalTailCache.delete(filePath);
22053
+ incrementalTailCache.set(filePath, { size, mtimeMs, lines: retained, coversWholeFile: covers });
22054
+ evictIncrementalTailCache();
22055
+ }
21915
22056
  function readBoundedTailRecords(agentType, dir, files, needed) {
21916
22057
  const collected = [];
21917
22058
  const seen = /* @__PURE__ */ new Set();
21918
22059
  let readAllFiles = true;
21919
22060
  for (let f = 0; f < files.length; f++) {
21920
22061
  const filePath = path12.join(dir, files[f]);
21921
- let content;
21922
- try {
21923
- content = fs5.readFileSync(filePath, "utf-8");
21924
- } catch {
21925
- continue;
21926
- }
21927
- const lines = content.trim().split("\n").filter(Boolean);
22062
+ const remaining = Math.max(0, needed - collected.length);
22063
+ const perFileNeeded = Math.min(needed, remaining + BOUNDED_TAIL_SLACK);
22064
+ const { lines, coversWholeFile } = readFileTailLines(filePath, perFileNeeded);
21928
22065
  for (let i = lines.length - 1; i >= 0; i--) {
22066
+ const line = lines[i];
22067
+ if (!line) continue;
21929
22068
  try {
21930
- const parsed = JSON.parse(lines[i]);
22069
+ const parsed = JSON.parse(line);
21931
22070
  const sanitizedMessage = sanitizeHistoryMessage(agentType, parsed);
21932
22071
  if (!sanitizedMessage) continue;
21933
22072
  const hash = buildHistoryMessageHash(agentType, sanitizedMessage);
@@ -21937,6 +22076,10 @@ function readBoundedTailRecords(agentType, dir, files, needed) {
21937
22076
  } catch {
21938
22077
  }
21939
22078
  }
22079
+ if (!coversWholeFile) {
22080
+ readAllFiles = false;
22081
+ break;
22082
+ }
21940
22083
  if (collected.length >= needed && f < files.length - 1) {
21941
22084
  readAllFiles = false;
21942
22085
  break;
@@ -31893,12 +32036,14 @@ var SpecCliAdapter = class _SpecCliAdapter {
31893
32036
  }
31894
32037
  this.maybeClearResolvedClaudeTuiPrompt();
31895
32038
  this.maybeCaptureClaudeTuiPrompt();
32039
+ this.maybeUpgradeClaudeTuiMultiSelect();
31896
32040
  this.statusCallback?.();
31897
32041
  return;
31898
32042
  case "pty_data":
31899
32043
  this.detectInteractivePromptFromPtyChunk(ev.chunk);
31900
32044
  this.maybeClearResolvedClaudeTuiPrompt();
31901
32045
  this.maybeCaptureClaudeTuiPrompt();
32046
+ this.maybeUpgradeClaudeTuiMultiSelect();
31902
32047
  try {
31903
32048
  this.ptyDataCallback?.(ev.chunk);
31904
32049
  } catch {
@@ -32047,6 +32192,35 @@ var SpecCliAdapter = class _SpecCliAdapter {
32047
32192
  this.claudeTuiPromptCaptureInFlight = false;
32048
32193
  });
32049
32194
  }
32195
+ /**
32196
+ * The TUI prompt is captured on the FIRST frame that renders the
32197
+ * "Enter to select" footer. At that instant the option rows' checkbox
32198
+ * column may not have drawn yet, so `detectClaudeTuiMultiSelect` returns
32199
+ * false and the prompt is frozen as single-select — the dashboard then
32200
+ * renders radio buttons even though the picker is multi-select.
32201
+ *
32202
+ * While the same TUI prompt is still on screen, re-check the live snapshot:
32203
+ * if checkbox glyphs have since appeared, promote any single-select
32204
+ * question to multi-select and re-emit status. Promotion is one-way
32205
+ * (false→true only) — once a question is known multi-select we never demote
32206
+ * it, since the glyph column can scroll out of view on later frames.
32207
+ */
32208
+ maybeUpgradeClaudeTuiMultiSelect() {
32209
+ if (this.cliType !== "claude-cli" || this.interactivePromptTransport !== "tui" || !this.activeInteractivePrompt) return;
32210
+ const questions = this.activeInteractivePrompt.questions;
32211
+ if (questions.length !== 1) return;
32212
+ if (questions[0].multiSelect) return;
32213
+ let screenText = "";
32214
+ try {
32215
+ screenText = this.driver.snapshot();
32216
+ } catch {
32217
+ return;
32218
+ }
32219
+ if (!screenText.includes("Enter to select")) return;
32220
+ if (!detectClaudeTuiMultiSelect(screenText)) return;
32221
+ questions[0].multiSelect = true;
32222
+ this.statusCallback?.();
32223
+ }
32050
32224
  readClaudeTuiHeaders(screenText) {
32051
32225
  const navLine = screenText.split(/\r?\n/).find((line) => line.includes("\u2714 Submit") && /[☐☒]/.test(line));
32052
32226
  if (!navLine) return [];
@@ -32196,6 +32370,7 @@ function normalizeProviderSessionId(provider, providerSessionId) {
32196
32370
  }
32197
32371
 
32198
32372
  // src/providers/cli-provider-instance.ts
32373
+ var STATUS_HYDRATION_TAIL_LIMIT = 200;
32199
32374
  function isIdleStatus(value) {
32200
32375
  const status = typeof value === "string" ? value.trim().toLowerCase() : "";
32201
32376
  return !status || status === "idle" || status === "ready";
@@ -33858,12 +34033,14 @@ ${effect.notification.body || ""}`.trim();
33858
34033
  const newestMessageAt = parsedMessages.reduce((newest, message) => Math.max(newest, getMessageTime(message)), 0);
33859
34034
  return newestMessageAt === 0;
33860
34035
  }
33861
- syncCanonicalSavedHistoryIfNeeded() {
34036
+ syncCanonicalSavedHistoryIfNeeded(options = {}) {
33862
34037
  if (!this.providerSessionId) return false;
33863
34038
  const canonicalHistory = this.provider.nativeHistory;
33864
34039
  if (!canonicalHistory) return false;
34040
+ const limit = options.full ? Number.MAX_SAFE_INTEGER : STATUS_HYDRATION_TAIL_LIMIT;
34041
+ const windowTag = options.full ? "full" : `tail:${STATUS_HYDRATION_TAIL_LIMIT}`;
33865
34042
  if (isNativeSourceCanonicalHistory(canonicalHistory)) {
33866
- const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
34043
+ const cacheKey = [this.type, this.providerSessionId, this.workingDir, windowTag].join("\0");
33867
34044
  const now = Date.now();
33868
34045
  if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
33869
34046
  return true;
@@ -33875,7 +34052,7 @@ ${effect.notification.body || ""}`.trim();
33875
34052
  historySessionId: this.providerSessionId,
33876
34053
  workspace: this.workingDir,
33877
34054
  offset: 0,
33878
- limit: Number.MAX_SAFE_INTEGER,
34055
+ limit,
33879
34056
  historyBehavior: this.provider.historyBehavior,
33880
34057
  scripts: this.provider.scripts
33881
34058
  });
@@ -33891,7 +34068,7 @@ ${effect.notification.body || ""}`.trim();
33891
34068
  return true;
33892
34069
  }
33893
34070
  try {
33894
- const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
34071
+ const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror", windowTag].join("\0");
33895
34072
  const now = Date.now();
33896
34073
  if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
33897
34074
  return true;
@@ -33901,7 +34078,7 @@ ${effect.notification.body || ""}`.trim();
33901
34078
  if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
33902
34079
  return false;
33903
34080
  }
33904
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
34081
+ const restoredHistory = readChatHistory(this.type, 0, limit, this.providerSessionId, 0, this.provider.historyBehavior);
33905
34082
  this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
33906
34083
  role: message.role,
33907
34084
  content: message.content,
@@ -33916,7 +34093,7 @@ ${effect.notification.body || ""}`.trim();
33916
34093
  }
33917
34094
  restorePersistedHistoryFromCurrentSession() {
33918
34095
  if (!this.providerSessionId) return;
33919
- this.syncCanonicalSavedHistoryIfNeeded();
34096
+ this.syncCanonicalSavedHistoryIfNeeded({ full: true });
33920
34097
  const restoredHistory = isNativeSourceCanonicalHistory(this.provider.nativeHistory) ? readProviderChatHistory(this.type, {
33921
34098
  canonicalHistory: this.provider.nativeHistory,
33922
34099
  historySessionId: this.providerSessionId,