@adhdev/daemon-core 0.9.82-rc.293 → 0.9.82-rc.295
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 +227 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +227 -20
- package/dist/index.mjs.map +1 -1
- package/dist/providers/spec/cli-adapter.d.ts +23 -0
- package/dist/providers/types/interactive-prompt.d.ts +36 -0
- package/package.json +2 -2
- package/src/config/chat-history.ts +255 -10
- package/src/mesh/coordinator-prompt.ts +1 -0
- package/src/providers/cli-provider-instance.ts +36 -14
- package/src/providers/spec/cli-adapter.ts +61 -0
- package/src/providers/types/interactive-prompt.ts +37 -8
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 ? "
|
|
279
|
-
const commitShort = readInjected(true ? "
|
|
280
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
281
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
278
|
+
const commit = readInjected(true ? "dc26917ced80beb84689897738b6edb82208c146" : void 0) ?? "unknown";
|
|
279
|
+
const commitShort = readInjected(true ? "dc26917c" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
280
|
+
const version = readInjected(true ? "0.9.82-rc.295" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
281
|
+
const builtAt = readInjected(true ? "2026-06-16T13:44:28.663Z" : 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\`.
|
|
@@ -15643,10 +15644,12 @@ function detectClaudeTuiMultiSelect(screenText) {
|
|
|
15643
15644
|
if (/Space to (?:select|toggle)|toggle selection|select multiple|select all that apply/i.test(screenText)) {
|
|
15644
15645
|
return true;
|
|
15645
15646
|
}
|
|
15646
|
-
const optionCheckbox =
|
|
15647
|
+
const optionCheckbox = `(?:\\[[ xX]\\]|[\u2610\u2612\u25FB\u25FC])`;
|
|
15648
|
+
const beforeNumber = new RegExp(`^\\s*(?:[\u276F\u203A>]\\s*)?${optionCheckbox}\\s*\\d+\\.\\s+\\S`);
|
|
15649
|
+
const afterNumber = new RegExp(`^\\s*(?:[\u276F\u203A>]\\s*)?\\d+\\.\\s*${optionCheckbox}\\s+\\S`);
|
|
15647
15650
|
for (const line of screenText.split(/\r?\n/)) {
|
|
15648
15651
|
if (line.includes("\u2714 Submit")) continue;
|
|
15649
|
-
if (
|
|
15652
|
+
if (beforeNumber.test(line) || afterNumber.test(line)) return true;
|
|
15650
15653
|
}
|
|
15651
15654
|
return false;
|
|
15652
15655
|
}
|
|
@@ -15786,6 +15789,16 @@ function parseClaudeInteractiveTuiQuestion(page, index) {
|
|
|
15786
15789
|
...allowFreeform ? { allowFreeform: true } : {}
|
|
15787
15790
|
};
|
|
15788
15791
|
}
|
|
15792
|
+
function readFocusedClaudeTuiQuestion(screenText) {
|
|
15793
|
+
if (!screenText.includes("Enter to select")) return null;
|
|
15794
|
+
const parsed = parseClaudeInteractiveTuiQuestion({ screenText }, 0);
|
|
15795
|
+
if (!parsed) return null;
|
|
15796
|
+
return {
|
|
15797
|
+
question: parsed.question,
|
|
15798
|
+
...parsed.header ? { header: parsed.header } : {},
|
|
15799
|
+
multiSelect: parsed.multiSelect
|
|
15800
|
+
};
|
|
15801
|
+
}
|
|
15789
15802
|
function detectClaudeAskUserQuestionPromptFromTuiPages(pages, options) {
|
|
15790
15803
|
if (pages.length === 0) return null;
|
|
15791
15804
|
const headers = claudeTuiQuestionHeaders(pages[0].screenText);
|
|
@@ -21912,22 +21925,160 @@ function isBoundedTailRequest(limit, offset, excludeRecentCount) {
|
|
|
21912
21925
|
if (!Number.isFinite(numericOffset) || !Number.isFinite(numericExclude)) return false;
|
|
21913
21926
|
return true;
|
|
21914
21927
|
}
|
|
21928
|
+
var REVERSE_TAIL_SMALL_FILE_BYTES = 64 * 1024;
|
|
21929
|
+
var REVERSE_TAIL_CHUNK_BYTES = 64 * 1024;
|
|
21930
|
+
var TAIL_LINES_RETAINED = BOUNDED_TAIL_MAX_LIMIT + 2 * BOUNDED_TAIL_SLACK;
|
|
21931
|
+
var INCREMENTAL_TAIL_CACHE_MAX_ENTRIES = 64;
|
|
21932
|
+
var incrementalTailCache = /* @__PURE__ */ new Map();
|
|
21933
|
+
function evictIncrementalTailCache() {
|
|
21934
|
+
while (incrementalTailCache.size > INCREMENTAL_TAIL_CACHE_MAX_ENTRIES) {
|
|
21935
|
+
const oldest = incrementalTailCache.keys().next().value;
|
|
21936
|
+
if (oldest === void 0) break;
|
|
21937
|
+
incrementalTailCache.delete(oldest);
|
|
21938
|
+
}
|
|
21939
|
+
}
|
|
21940
|
+
function splitBufferLines(buf) {
|
|
21941
|
+
const lines = [];
|
|
21942
|
+
let lineEnd = buf.length;
|
|
21943
|
+
let firstNewline = -1;
|
|
21944
|
+
for (let i = buf.length - 1; i >= 0; i--) {
|
|
21945
|
+
if (buf[i] !== 10) continue;
|
|
21946
|
+
if (i + 1 < lineEnd) {
|
|
21947
|
+
lines.push(buf.toString("utf-8", i + 1, lineEnd));
|
|
21948
|
+
}
|
|
21949
|
+
lineEnd = i;
|
|
21950
|
+
firstNewline = i;
|
|
21951
|
+
}
|
|
21952
|
+
lines.reverse();
|
|
21953
|
+
const head = firstNewline >= 0 ? buf.subarray(0, firstNewline) : buf;
|
|
21954
|
+
return { head, lines };
|
|
21955
|
+
}
|
|
21956
|
+
function readReverseTailLines(filePath, needed) {
|
|
21957
|
+
const fd = fs5.openSync(filePath, "r");
|
|
21958
|
+
try {
|
|
21959
|
+
const stat2 = fs5.fstatSync(fd);
|
|
21960
|
+
const size = stat2.size;
|
|
21961
|
+
let position = size;
|
|
21962
|
+
let carry = Buffer.alloc(0);
|
|
21963
|
+
const collected = [];
|
|
21964
|
+
while (position > 0 && collected.length < needed) {
|
|
21965
|
+
const chunkSize = Math.min(REVERSE_TAIL_CHUNK_BYTES, position);
|
|
21966
|
+
position -= chunkSize;
|
|
21967
|
+
const chunk = Buffer.alloc(chunkSize);
|
|
21968
|
+
fs5.readSync(fd, chunk, 0, chunkSize, position);
|
|
21969
|
+
const combined = carry.length ? Buffer.concat([chunk, carry]) : chunk;
|
|
21970
|
+
const { head, lines } = splitBufferLines(combined);
|
|
21971
|
+
carry = head;
|
|
21972
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
21973
|
+
collected.push(lines[i]);
|
|
21974
|
+
}
|
|
21975
|
+
}
|
|
21976
|
+
const reachedStart = position <= 0;
|
|
21977
|
+
if (reachedStart && carry.length) {
|
|
21978
|
+
collected.push(carry.toString("utf-8"));
|
|
21979
|
+
}
|
|
21980
|
+
collected.reverse();
|
|
21981
|
+
return { lines: collected, coversWholeFile: reachedStart, size, mtimeMs: stat2.mtimeMs };
|
|
21982
|
+
} finally {
|
|
21983
|
+
fs5.closeSync(fd);
|
|
21984
|
+
}
|
|
21985
|
+
}
|
|
21986
|
+
function readFileTailLines(filePath, needed) {
|
|
21987
|
+
let stat2;
|
|
21988
|
+
try {
|
|
21989
|
+
stat2 = fs5.statSync(filePath);
|
|
21990
|
+
} catch {
|
|
21991
|
+
return { lines: [], coversWholeFile: true };
|
|
21992
|
+
}
|
|
21993
|
+
const size = stat2.size;
|
|
21994
|
+
const mtimeMs = stat2.mtimeMs;
|
|
21995
|
+
if (size === 0) {
|
|
21996
|
+
incrementalTailCache.delete(filePath);
|
|
21997
|
+
return { lines: [], coversWholeFile: true };
|
|
21998
|
+
}
|
|
21999
|
+
const cached2 = incrementalTailCache.get(filePath);
|
|
22000
|
+
if (cached2) {
|
|
22001
|
+
if (cached2.size === size && cached2.mtimeMs === mtimeMs) {
|
|
22002
|
+
incrementalTailCache.delete(filePath);
|
|
22003
|
+
incrementalTailCache.set(filePath, cached2);
|
|
22004
|
+
if (cached2.coversWholeFile || cached2.lines.length >= needed) {
|
|
22005
|
+
return { lines: cached2.lines, coversWholeFile: cached2.coversWholeFile };
|
|
22006
|
+
}
|
|
22007
|
+
} else if (size > cached2.size) {
|
|
22008
|
+
const incremental = tryIncrementalTailGrowth(filePath, cached2, size, mtimeMs, needed);
|
|
22009
|
+
if (incremental) return { lines: incremental.lines, coversWholeFile: incremental.coversWholeFile };
|
|
22010
|
+
}
|
|
22011
|
+
incrementalTailCache.delete(filePath);
|
|
22012
|
+
}
|
|
22013
|
+
if (size <= REVERSE_TAIL_SMALL_FILE_BYTES) {
|
|
22014
|
+
let content;
|
|
22015
|
+
try {
|
|
22016
|
+
content = fs5.readFileSync(filePath, "utf-8");
|
|
22017
|
+
} catch {
|
|
22018
|
+
return { lines: [], coversWholeFile: true };
|
|
22019
|
+
}
|
|
22020
|
+
const lines = content.split("\n");
|
|
22021
|
+
if (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
22022
|
+
storeIncrementalTailCache(filePath, size, mtimeMs, lines, true);
|
|
22023
|
+
return { lines, coversWholeFile: true };
|
|
22024
|
+
}
|
|
22025
|
+
let result;
|
|
22026
|
+
try {
|
|
22027
|
+
result = readReverseTailLines(filePath, needed);
|
|
22028
|
+
} catch {
|
|
22029
|
+
return { lines: [], coversWholeFile: true };
|
|
22030
|
+
}
|
|
22031
|
+
storeIncrementalTailCache(filePath, result.size, result.mtimeMs, result.lines, result.coversWholeFile);
|
|
22032
|
+
return { lines: result.lines, coversWholeFile: result.coversWholeFile };
|
|
22033
|
+
}
|
|
22034
|
+
function tryIncrementalTailGrowth(filePath, cached2, size, mtimeMs, needed) {
|
|
22035
|
+
const fd = fs5.openSync(filePath, "r");
|
|
22036
|
+
try {
|
|
22037
|
+
if (cached2.size > 0) {
|
|
22038
|
+
const boundary = Buffer.alloc(1);
|
|
22039
|
+
fs5.readSync(fd, boundary, 0, 1, cached2.size - 1);
|
|
22040
|
+
if (boundary[0] !== 10) return null;
|
|
22041
|
+
}
|
|
22042
|
+
const appendedLength = size - cached2.size;
|
|
22043
|
+
const appended = Buffer.alloc(appendedLength);
|
|
22044
|
+
fs5.readSync(fd, appended, 0, appendedLength, cached2.size);
|
|
22045
|
+
const newLines = appended.toString("utf-8").split("\n");
|
|
22046
|
+
if (newLines.length && newLines[newLines.length - 1] === "") newLines.pop();
|
|
22047
|
+
const merged = cached2.lines.concat(newLines);
|
|
22048
|
+
const trimmed = merged.length > TAIL_LINES_RETAINED ? merged.slice(merged.length - TAIL_LINES_RETAINED) : merged;
|
|
22049
|
+
const coversWholeFile = cached2.coversWholeFile && trimmed.length === merged.length;
|
|
22050
|
+
storeIncrementalTailCache(filePath, size, mtimeMs, trimmed, coversWholeFile);
|
|
22051
|
+
if (coversWholeFile || trimmed.length >= needed) {
|
|
22052
|
+
return { lines: trimmed, coversWholeFile };
|
|
22053
|
+
}
|
|
22054
|
+
return { lines: trimmed, coversWholeFile };
|
|
22055
|
+
} catch {
|
|
22056
|
+
return null;
|
|
22057
|
+
} finally {
|
|
22058
|
+
fs5.closeSync(fd);
|
|
22059
|
+
}
|
|
22060
|
+
}
|
|
22061
|
+
function storeIncrementalTailCache(filePath, size, mtimeMs, lines, coversWholeFile) {
|
|
22062
|
+
const retained = lines.length > TAIL_LINES_RETAINED ? lines.slice(lines.length - TAIL_LINES_RETAINED) : lines;
|
|
22063
|
+
const covers = coversWholeFile && retained.length === lines.length;
|
|
22064
|
+
incrementalTailCache.delete(filePath);
|
|
22065
|
+
incrementalTailCache.set(filePath, { size, mtimeMs, lines: retained, coversWholeFile: covers });
|
|
22066
|
+
evictIncrementalTailCache();
|
|
22067
|
+
}
|
|
21915
22068
|
function readBoundedTailRecords(agentType, dir, files, needed) {
|
|
21916
22069
|
const collected = [];
|
|
21917
22070
|
const seen = /* @__PURE__ */ new Set();
|
|
21918
22071
|
let readAllFiles = true;
|
|
21919
22072
|
for (let f = 0; f < files.length; f++) {
|
|
21920
22073
|
const filePath = path12.join(dir, files[f]);
|
|
21921
|
-
|
|
21922
|
-
|
|
21923
|
-
|
|
21924
|
-
} catch {
|
|
21925
|
-
continue;
|
|
21926
|
-
}
|
|
21927
|
-
const lines = content.trim().split("\n").filter(Boolean);
|
|
22074
|
+
const remaining = Math.max(0, needed - collected.length);
|
|
22075
|
+
const perFileNeeded = Math.min(needed, remaining + BOUNDED_TAIL_SLACK);
|
|
22076
|
+
const { lines, coversWholeFile } = readFileTailLines(filePath, perFileNeeded);
|
|
21928
22077
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
22078
|
+
const line = lines[i];
|
|
22079
|
+
if (!line) continue;
|
|
21929
22080
|
try {
|
|
21930
|
-
const parsed = JSON.parse(
|
|
22081
|
+
const parsed = JSON.parse(line);
|
|
21931
22082
|
const sanitizedMessage = sanitizeHistoryMessage(agentType, parsed);
|
|
21932
22083
|
if (!sanitizedMessage) continue;
|
|
21933
22084
|
const hash = buildHistoryMessageHash(agentType, sanitizedMessage);
|
|
@@ -21937,6 +22088,10 @@ function readBoundedTailRecords(agentType, dir, files, needed) {
|
|
|
21937
22088
|
} catch {
|
|
21938
22089
|
}
|
|
21939
22090
|
}
|
|
22091
|
+
if (!coversWholeFile) {
|
|
22092
|
+
readAllFiles = false;
|
|
22093
|
+
break;
|
|
22094
|
+
}
|
|
21940
22095
|
if (collected.length >= needed && f < files.length - 1) {
|
|
21941
22096
|
readAllFiles = false;
|
|
21942
22097
|
break;
|
|
@@ -31893,12 +32048,14 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
31893
32048
|
}
|
|
31894
32049
|
this.maybeClearResolvedClaudeTuiPrompt();
|
|
31895
32050
|
this.maybeCaptureClaudeTuiPrompt();
|
|
32051
|
+
this.maybeUpgradeClaudeTuiMultiSelect();
|
|
31896
32052
|
this.statusCallback?.();
|
|
31897
32053
|
return;
|
|
31898
32054
|
case "pty_data":
|
|
31899
32055
|
this.detectInteractivePromptFromPtyChunk(ev.chunk);
|
|
31900
32056
|
this.maybeClearResolvedClaudeTuiPrompt();
|
|
31901
32057
|
this.maybeCaptureClaudeTuiPrompt();
|
|
32058
|
+
this.maybeUpgradeClaudeTuiMultiSelect();
|
|
31902
32059
|
try {
|
|
31903
32060
|
this.ptyDataCallback?.(ev.chunk);
|
|
31904
32061
|
} catch {
|
|
@@ -32047,6 +32204,53 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
32047
32204
|
this.claudeTuiPromptCaptureInFlight = false;
|
|
32048
32205
|
});
|
|
32049
32206
|
}
|
|
32207
|
+
/**
|
|
32208
|
+
* The TUI prompt is captured on the FIRST frame that renders the
|
|
32209
|
+
* "Enter to select" footer. At that instant the option rows' checkbox
|
|
32210
|
+
* column may not have drawn yet, so `detectClaudeTuiMultiSelect` returns
|
|
32211
|
+
* false and the prompt is frozen as single-select — the dashboard then
|
|
32212
|
+
* renders radio buttons even though the picker is multi-select.
|
|
32213
|
+
*
|
|
32214
|
+
* While the same TUI prompt is still on screen, re-check the live snapshot:
|
|
32215
|
+
* if checkbox glyphs have since appeared, promote any single-select
|
|
32216
|
+
* question to multi-select and re-emit status. Promotion is one-way
|
|
32217
|
+
* (false→true only) — once a question is known multi-select we never demote
|
|
32218
|
+
* it, since the glyph column can scroll out of view on later frames.
|
|
32219
|
+
*
|
|
32220
|
+
* For MULTI-question prompts the per-page Tab capture is the actual source
|
|
32221
|
+
* of the bug: pages 2..N are snapshotted ~120ms after the Tab keypress,
|
|
32222
|
+
* before their option-row glyph column has redrawn, so those questions
|
|
32223
|
+
* freeze as single-select while page 1 (already settled) is correct. We
|
|
32224
|
+
* cannot upgrade blindly — the live snapshot shows only ONE focused page —
|
|
32225
|
+
* but we CAN read that page's question text/header and upgrade the matching
|
|
32226
|
+
* question. As the user navigates the picker (or it settles), each page is
|
|
32227
|
+
* eventually re-read and repaired.
|
|
32228
|
+
*/
|
|
32229
|
+
maybeUpgradeClaudeTuiMultiSelect() {
|
|
32230
|
+
if (this.cliType !== "claude-cli" || this.interactivePromptTransport !== "tui" || !this.activeInteractivePrompt) return;
|
|
32231
|
+
const questions = this.activeInteractivePrompt.questions;
|
|
32232
|
+
if (questions.every((q) => q.multiSelect)) return;
|
|
32233
|
+
let screenText = "";
|
|
32234
|
+
try {
|
|
32235
|
+
screenText = this.driver.snapshot();
|
|
32236
|
+
} catch {
|
|
32237
|
+
return;
|
|
32238
|
+
}
|
|
32239
|
+
if (!screenText.includes("Enter to select")) return;
|
|
32240
|
+
if (questions.length === 1) {
|
|
32241
|
+
if (questions[0].multiSelect) return;
|
|
32242
|
+
if (!detectClaudeTuiMultiSelect(screenText)) return;
|
|
32243
|
+
questions[0].multiSelect = true;
|
|
32244
|
+
this.statusCallback?.();
|
|
32245
|
+
return;
|
|
32246
|
+
}
|
|
32247
|
+
const focused = readFocusedClaudeTuiQuestion(screenText);
|
|
32248
|
+
if (!focused || !focused.multiSelect) return;
|
|
32249
|
+
const match = questions.find((q) => focused.header && q.header && q.header === focused.header || q.question === focused.question);
|
|
32250
|
+
if (!match || match.multiSelect) return;
|
|
32251
|
+
match.multiSelect = true;
|
|
32252
|
+
this.statusCallback?.();
|
|
32253
|
+
}
|
|
32050
32254
|
readClaudeTuiHeaders(screenText) {
|
|
32051
32255
|
const navLine = screenText.split(/\r?\n/).find((line) => line.includes("\u2714 Submit") && /[☐☒]/.test(line));
|
|
32052
32256
|
if (!navLine) return [];
|
|
@@ -32196,6 +32400,7 @@ function normalizeProviderSessionId(provider, providerSessionId) {
|
|
|
32196
32400
|
}
|
|
32197
32401
|
|
|
32198
32402
|
// src/providers/cli-provider-instance.ts
|
|
32403
|
+
var STATUS_HYDRATION_TAIL_LIMIT = 200;
|
|
32199
32404
|
function isIdleStatus(value) {
|
|
32200
32405
|
const status = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
32201
32406
|
return !status || status === "idle" || status === "ready";
|
|
@@ -33858,12 +34063,14 @@ ${effect.notification.body || ""}`.trim();
|
|
|
33858
34063
|
const newestMessageAt = parsedMessages.reduce((newest, message) => Math.max(newest, getMessageTime(message)), 0);
|
|
33859
34064
|
return newestMessageAt === 0;
|
|
33860
34065
|
}
|
|
33861
|
-
syncCanonicalSavedHistoryIfNeeded() {
|
|
34066
|
+
syncCanonicalSavedHistoryIfNeeded(options = {}) {
|
|
33862
34067
|
if (!this.providerSessionId) return false;
|
|
33863
34068
|
const canonicalHistory = this.provider.nativeHistory;
|
|
33864
34069
|
if (!canonicalHistory) return false;
|
|
34070
|
+
const limit = options.full ? Number.MAX_SAFE_INTEGER : STATUS_HYDRATION_TAIL_LIMIT;
|
|
34071
|
+
const windowTag = options.full ? "full" : `tail:${STATUS_HYDRATION_TAIL_LIMIT}`;
|
|
33865
34072
|
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
33866
|
-
const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
|
|
34073
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, windowTag].join("\0");
|
|
33867
34074
|
const now = Date.now();
|
|
33868
34075
|
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
33869
34076
|
return true;
|
|
@@ -33875,7 +34082,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
33875
34082
|
historySessionId: this.providerSessionId,
|
|
33876
34083
|
workspace: this.workingDir,
|
|
33877
34084
|
offset: 0,
|
|
33878
|
-
limit
|
|
34085
|
+
limit,
|
|
33879
34086
|
historyBehavior: this.provider.historyBehavior,
|
|
33880
34087
|
scripts: this.provider.scripts
|
|
33881
34088
|
});
|
|
@@ -33891,7 +34098,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
33891
34098
|
return true;
|
|
33892
34099
|
}
|
|
33893
34100
|
try {
|
|
33894
|
-
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
|
|
34101
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror", windowTag].join("\0");
|
|
33895
34102
|
const now = Date.now();
|
|
33896
34103
|
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
33897
34104
|
return true;
|
|
@@ -33901,7 +34108,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
33901
34108
|
if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
|
|
33902
34109
|
return false;
|
|
33903
34110
|
}
|
|
33904
|
-
const restoredHistory = readChatHistory(this.type, 0,
|
|
34111
|
+
const restoredHistory = readChatHistory(this.type, 0, limit, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
33905
34112
|
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
33906
34113
|
role: message.role,
|
|
33907
34114
|
content: message.content,
|
|
@@ -33916,7 +34123,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
33916
34123
|
}
|
|
33917
34124
|
restorePersistedHistoryFromCurrentSession() {
|
|
33918
34125
|
if (!this.providerSessionId) return;
|
|
33919
|
-
this.syncCanonicalSavedHistoryIfNeeded();
|
|
34126
|
+
this.syncCanonicalSavedHistoryIfNeeded({ full: true });
|
|
33920
34127
|
const restoredHistory = isNativeSourceCanonicalHistory(this.provider.nativeHistory) ? readProviderChatHistory(this.type, {
|
|
33921
34128
|
canonicalHistory: this.provider.nativeHistory,
|
|
33922
34129
|
historySessionId: this.providerSessionId,
|