blun-king-cli 9.1.459 → 9.1.460
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/bin/session-resume-checkpoint.cjs +1 -1
- package/bin/session-scrollback-archive.cjs +206 -0
- package/blun.mjs +78 -6
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ const crypto = require('node:crypto');
|
|
|
4
4
|
const fs = require('node:fs');
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
|
|
7
|
-
const RESUME_CHECKPOINT_SCHEMA_VERSION =
|
|
7
|
+
const RESUME_CHECKPOINT_SCHEMA_VERSION = 2;
|
|
8
8
|
const MAX_RESUME_SNAPSHOT_BYTES = 4 * 1024 * 1024;
|
|
9
9
|
const MAX_RESUME_CHECKPOINT_BYTES = MAX_RESUME_SNAPSHOT_BYTES + 256 * 1024;
|
|
10
10
|
const WIRE_SAMPLE_BYTES = 4096;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const ARCHIVE_SCHEMA_VERSION = 1;
|
|
8
|
+
const INDEX_FILE = 'index.json';
|
|
9
|
+
|
|
10
|
+
function sessionScrollbackArchiveDirectory(wirePath) {
|
|
11
|
+
return path.join(path.dirname(wirePath), 'tui-scrollback-v1');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isNonNegativeInteger(value) {
|
|
15
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function writeAtomic(filePath, value) {
|
|
19
|
+
const temporaryPath = `${filePath}.tmp-${process.pid}-${crypto.randomBytes(8).toString('hex')}`;
|
|
20
|
+
try {
|
|
21
|
+
fs.writeFileSync(temporaryPath, value, {
|
|
22
|
+
encoding: 'utf8',
|
|
23
|
+
flag: 'wx',
|
|
24
|
+
mode: 0o600,
|
|
25
|
+
});
|
|
26
|
+
fs.renameSync(temporaryPath, filePath);
|
|
27
|
+
} finally {
|
|
28
|
+
try {
|
|
29
|
+
fs.rmSync(temporaryPath, { force: true });
|
|
30
|
+
} catch {}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class SessionScrollbackArchive {
|
|
35
|
+
constructor({ directory, reset = false, reuse = false }) {
|
|
36
|
+
if (typeof directory !== 'string' || directory.length === 0) {
|
|
37
|
+
throw new TypeError('session scrollback directory is required');
|
|
38
|
+
}
|
|
39
|
+
this.directory = path.resolve(directory);
|
|
40
|
+
this.chunks = [];
|
|
41
|
+
this.loadedChunks = new Map();
|
|
42
|
+
this.lineCount = 0;
|
|
43
|
+
this.loadedExisting = false;
|
|
44
|
+
|
|
45
|
+
if (reset) {
|
|
46
|
+
this.reset();
|
|
47
|
+
} else if (reuse) {
|
|
48
|
+
this.loadExisting();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get totalLines() {
|
|
53
|
+
return this.lineCount;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get loadedChunkCount() {
|
|
57
|
+
return this.loadedChunks.size;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
append(lines) {
|
|
61
|
+
if (!Array.isArray(lines) || !lines.every((line) => typeof line === 'string')) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
if (lines.length === 0) return true;
|
|
65
|
+
|
|
66
|
+
fs.mkdirSync(this.directory, { recursive: true });
|
|
67
|
+
const file = `chunk-${String(this.chunks.length).padStart(8, '0')}-${crypto.randomBytes(6).toString('hex')}.json`;
|
|
68
|
+
const chunkPath = path.join(this.directory, file);
|
|
69
|
+
const chunk = {
|
|
70
|
+
file,
|
|
71
|
+
startLine: this.lineCount,
|
|
72
|
+
lineCount: lines.length,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
writeAtomic(chunkPath, JSON.stringify(lines));
|
|
77
|
+
const nextChunks = [...this.chunks, chunk];
|
|
78
|
+
const nextLineCount = this.lineCount + lines.length;
|
|
79
|
+
this.writeIndex(nextChunks, nextLineCount);
|
|
80
|
+
this.chunks = nextChunks;
|
|
81
|
+
this.lineCount = nextLineCount;
|
|
82
|
+
return true;
|
|
83
|
+
} catch {
|
|
84
|
+
try {
|
|
85
|
+
fs.rmSync(chunkPath, { force: true });
|
|
86
|
+
} catch {}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
readRange(start, end) {
|
|
92
|
+
if (!Number.isFinite(start) || !Number.isFinite(end)) return [];
|
|
93
|
+
if (start >= end || start >= this.lineCount) return [];
|
|
94
|
+
const boundedStart = Math.max(0, Math.floor(start));
|
|
95
|
+
const boundedEnd = Math.min(this.lineCount, Math.floor(end));
|
|
96
|
+
const output = [];
|
|
97
|
+
|
|
98
|
+
for (let index = 0; index < this.chunks.length; index++) {
|
|
99
|
+
const chunk = this.chunks[index];
|
|
100
|
+
const chunkEnd = chunk.startLine + chunk.lineCount;
|
|
101
|
+
if (chunkEnd <= boundedStart) continue;
|
|
102
|
+
if (chunk.startLine >= boundedEnd) break;
|
|
103
|
+
const lines = this.readChunk(index);
|
|
104
|
+
const sliceStart = Math.max(0, boundedStart - chunk.startLine);
|
|
105
|
+
const sliceEnd = Math.min(lines.length, boundedEnd - chunk.startLine);
|
|
106
|
+
output.push(...lines.slice(sliceStart, sliceEnd));
|
|
107
|
+
}
|
|
108
|
+
return output;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
reset() {
|
|
112
|
+
try {
|
|
113
|
+
fs.rmSync(this.directory, { recursive: true, force: true });
|
|
114
|
+
} catch {}
|
|
115
|
+
this.chunks = [];
|
|
116
|
+
this.loadedChunks.clear();
|
|
117
|
+
this.lineCount = 0;
|
|
118
|
+
this.loadedExisting = false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
clear() {
|
|
122
|
+
this.reset();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
dispose() {
|
|
126
|
+
this.loadedChunks.clear();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
loadExisting() {
|
|
130
|
+
const indexPath = path.join(this.directory, INDEX_FILE);
|
|
131
|
+
try {
|
|
132
|
+
const parsed = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
133
|
+
if (
|
|
134
|
+
parsed?.schemaVersion !== ARCHIVE_SCHEMA_VERSION
|
|
135
|
+
|| !isNonNegativeInteger(parsed.totalLines)
|
|
136
|
+
|| !Array.isArray(parsed.chunks)
|
|
137
|
+
) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let nextLine = 0;
|
|
142
|
+
const chunks = [];
|
|
143
|
+
for (const candidate of parsed.chunks) {
|
|
144
|
+
if (
|
|
145
|
+
typeof candidate?.file !== 'string'
|
|
146
|
+
|| path.basename(candidate.file) !== candidate.file
|
|
147
|
+
|| !candidate.file.startsWith('chunk-')
|
|
148
|
+
|| !candidate.file.endsWith('.json')
|
|
149
|
+
|| candidate.startLine !== nextLine
|
|
150
|
+
|| !Number.isSafeInteger(candidate.lineCount)
|
|
151
|
+
|| candidate.lineCount <= 0
|
|
152
|
+
) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const chunkPath = path.join(this.directory, candidate.file);
|
|
156
|
+
if (!fs.statSync(chunkPath).isFile()) return;
|
|
157
|
+
chunks.push({
|
|
158
|
+
file: candidate.file,
|
|
159
|
+
startLine: candidate.startLine,
|
|
160
|
+
lineCount: candidate.lineCount,
|
|
161
|
+
});
|
|
162
|
+
nextLine += candidate.lineCount;
|
|
163
|
+
}
|
|
164
|
+
if (nextLine !== parsed.totalLines) return;
|
|
165
|
+
|
|
166
|
+
this.chunks = chunks;
|
|
167
|
+
this.lineCount = parsed.totalLines;
|
|
168
|
+
this.loadedExisting = true;
|
|
169
|
+
} catch {}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
readChunk(index) {
|
|
173
|
+
const loaded = this.loadedChunks.get(index);
|
|
174
|
+
if (loaded !== undefined) return loaded;
|
|
175
|
+
const chunk = this.chunks[index];
|
|
176
|
+
if (chunk === undefined) return [];
|
|
177
|
+
try {
|
|
178
|
+
const value = JSON.parse(fs.readFileSync(path.join(this.directory, chunk.file), 'utf8'));
|
|
179
|
+
if (
|
|
180
|
+
!Array.isArray(value)
|
|
181
|
+
|| value.length !== chunk.lineCount
|
|
182
|
+
|| !value.every((line) => typeof line === 'string')
|
|
183
|
+
) {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
this.loadedChunks.set(index, value);
|
|
187
|
+
return value;
|
|
188
|
+
} catch {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
writeIndex(chunks, totalLines) {
|
|
194
|
+
writeAtomic(path.join(this.directory, INDEX_FILE), JSON.stringify({
|
|
195
|
+
schemaVersion: ARCHIVE_SCHEMA_VERSION,
|
|
196
|
+
totalLines,
|
|
197
|
+
chunks,
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = {
|
|
203
|
+
ARCHIVE_SCHEMA_VERSION,
|
|
204
|
+
SessionScrollbackArchive,
|
|
205
|
+
sessionScrollbackArchiveDirectory,
|
|
206
|
+
};
|
package/blun.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import runtimeExitLedger from "./bin/runtime-exit-ledger.cjs";
|
|
|
12
12
|
import compactionModelPolicy from "./bin/compaction-model-policy.cjs";
|
|
13
13
|
import agentResumeSnapshot from "./bin/agent-resume-snapshot.cjs";
|
|
14
14
|
import sessionResumeCheckpoint from "./bin/session-resume-checkpoint.cjs";
|
|
15
|
+
import sessionScrollbackArchive from "./bin/session-scrollback-archive.cjs";
|
|
15
16
|
import crypto$1, { createHash, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
|
|
16
17
|
import * as fs$16 from "node:fs";
|
|
17
18
|
import Kt, { accessSync, appendFileSync, chmodSync, closeSync, constants, copyFileSync, createReadStream, createWriteStream, existsSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
@@ -48,6 +49,7 @@ const { recordRuntimeExit } = runtimeExitLedger;
|
|
|
48
49
|
const { resolveCompactionModelAlias } = compactionModelPolicy;
|
|
49
50
|
const { createAgentResumeSnapshot, restoreAgentResumeSnapshot } = agentResumeSnapshot;
|
|
50
51
|
const { loadResumeCheckpoint, writeResumeCheckpoint } = sessionResumeCheckpoint;
|
|
52
|
+
const { SessionScrollbackArchive, sessionScrollbackArchiveDirectory } = sessionScrollbackArchive;
|
|
51
53
|
import { EventEmitter as EventEmitter$1 } from "node:events";
|
|
52
54
|
import { StringDecoder } from "node:string_decoder";
|
|
53
55
|
import co from "node:assert";
|
|
@@ -235236,6 +235238,7 @@ var init_records = __esmMin((() => {
|
|
|
235236
235238
|
persistence;
|
|
235237
235239
|
_restoring = null;
|
|
235238
235240
|
metadataInitialized = false;
|
|
235241
|
+
resumeCheckpointRestored = false;
|
|
235239
235242
|
messageTimes = new WeakMap();
|
|
235240
235243
|
constructor(agent, persistence) {
|
|
235241
235244
|
this.agent = agent;
|
|
@@ -235274,6 +235277,7 @@ var init_records = __esmMin((() => {
|
|
|
235274
235277
|
}
|
|
235275
235278
|
async replay(options = {}) {
|
|
235276
235279
|
if (!this.persistence) throw new Error("No persistence provided for AgentRecords");
|
|
235280
|
+
this.resumeCheckpointRestored = false;
|
|
235277
235281
|
const rewriteMigratedRecords = options.rewriteMigratedRecords ?? true;
|
|
235278
235282
|
if (rewriteMigratedRecords && await this.tryReplayResumeCheckpoint()) return {};
|
|
235279
235283
|
let migrations = [];
|
|
@@ -235331,6 +235335,7 @@ var init_records = __esmMin((() => {
|
|
|
235331
235335
|
}
|
|
235332
235336
|
this.persistence.persistedRecordCount = checkpoint.recordCount + tailRecordCount;
|
|
235333
235337
|
if (this.agent.blobStore !== void 0) for (const msg of this.agent.context.history) await this.agent.blobStore.rehydrateParts(msg.content);
|
|
235338
|
+
this.resumeCheckpointRestored = true;
|
|
235334
235339
|
return true;
|
|
235335
235340
|
}
|
|
235336
235341
|
async writeResumeCheckpoint() {
|
|
@@ -316822,6 +316827,8 @@ async function resumeSessionResult(summary, session, warning) {
|
|
|
316822
316827
|
const usage = await api.getUsage({ agentId });
|
|
316823
316828
|
agents[agentId] = {
|
|
316824
316829
|
type: agent.type,
|
|
316830
|
+
resumeCheckpointRestored: agent.records.resumeCheckpointRestored === true,
|
|
316831
|
+
sessionWirePath: agent.records.persistence instanceof FileSystemAgentRecordPersistence ? agent.records.persistence.filePath : void 0,
|
|
316825
316832
|
config,
|
|
316826
316833
|
context,
|
|
316827
316834
|
replay: agent.replayBuilder.buildResult(),
|
|
@@ -506093,6 +506100,27 @@ var ScrollbackBuffer = class {
|
|
|
506093
506100
|
archiveLines(lines) {
|
|
506094
506101
|
return this.archive.append(lines);
|
|
506095
506102
|
}
|
|
506103
|
+
usePersistentArchive(directory, options) {
|
|
506104
|
+
this.releaseArchive();
|
|
506105
|
+
const archive = new SessionScrollbackArchive({
|
|
506106
|
+
directory,
|
|
506107
|
+
reset: options.reset,
|
|
506108
|
+
reuse: options.reuse
|
|
506109
|
+
});
|
|
506110
|
+
this.archive = archive;
|
|
506111
|
+
return archive.loadedExisting;
|
|
506112
|
+
}
|
|
506113
|
+
releaseArchive() {
|
|
506114
|
+
if (this.archive instanceof DiskBackedLineArchive) this.archive.clear();
|
|
506115
|
+
else this.archive.dispose();
|
|
506116
|
+
this.archive = new DiskBackedLineArchive();
|
|
506117
|
+
this.resetViewState();
|
|
506118
|
+
}
|
|
506119
|
+
dispose() {
|
|
506120
|
+
if (this.archive instanceof DiskBackedLineArchive) this.archive.clear();
|
|
506121
|
+
else this.archive.dispose();
|
|
506122
|
+
this.resetViewState();
|
|
506123
|
+
}
|
|
506096
506124
|
activate() {
|
|
506097
506125
|
this.active = true;
|
|
506098
506126
|
this.scrollOffset = 0;
|
|
@@ -506103,6 +506131,9 @@ var ScrollbackBuffer = class {
|
|
|
506103
506131
|
}
|
|
506104
506132
|
clear() {
|
|
506105
506133
|
this.archive.clear();
|
|
506134
|
+
this.resetViewState();
|
|
506135
|
+
}
|
|
506136
|
+
resetViewState() {
|
|
506106
506137
|
this.snapshotLines = [];
|
|
506107
506138
|
this.publishedLineCount = 0;
|
|
506108
506139
|
this.deactivate();
|
|
@@ -506414,6 +506445,7 @@ var ScrollbackController = class {
|
|
|
506414
506445
|
state;
|
|
506415
506446
|
buffer;
|
|
506416
506447
|
disposeListener;
|
|
506448
|
+
suppressReplayArchiveWrites = false;
|
|
506417
506449
|
constructor(state) {
|
|
506418
506450
|
this.state = state;
|
|
506419
506451
|
}
|
|
@@ -506428,16 +506460,52 @@ var ScrollbackController = class {
|
|
|
506428
506460
|
dispose() {
|
|
506429
506461
|
this.disposeListener?.();
|
|
506430
506462
|
this.disposeListener = void 0;
|
|
506431
|
-
this.buffer?.
|
|
506463
|
+
this.buffer?.dispose();
|
|
506432
506464
|
if (this.state.ui instanceof BottomPinnedTUI) this.state.ui.scrollbackBuffer = void 0;
|
|
506433
506465
|
this.buffer = void 0;
|
|
506434
506466
|
}
|
|
506435
506467
|
reset() {
|
|
506436
506468
|
this.buffer?.clear();
|
|
506469
|
+
this.suppressReplayArchiveWrites = false;
|
|
506470
|
+
}
|
|
506471
|
+
releaseSessionArchive() {
|
|
506472
|
+
this.buffer?.releaseArchive();
|
|
506473
|
+
this.suppressReplayArchiveWrites = false;
|
|
506474
|
+
}
|
|
506475
|
+
prepareNewSession(session) {
|
|
506476
|
+
const sessionDirectory = session?.summary?.sessionDir;
|
|
506477
|
+
if (typeof sessionDirectory !== "string" || sessionDirectory.length === 0) return false;
|
|
506478
|
+
const wirePath = path.join(sessionDirectory, "agents", "main", "wire.jsonl");
|
|
506479
|
+
this.buffer?.usePersistentArchive(sessionScrollbackArchiveDirectory(wirePath), {
|
|
506480
|
+
reset: true,
|
|
506481
|
+
reuse: false
|
|
506482
|
+
});
|
|
506483
|
+
this.suppressReplayArchiveWrites = false;
|
|
506484
|
+
return true;
|
|
506485
|
+
}
|
|
506486
|
+
prepareSessionReplay(agent) {
|
|
506487
|
+
const buffer = this.buffer;
|
|
506488
|
+
if (buffer === void 0) return false;
|
|
506489
|
+
const persistence = agent?.records?.persistence;
|
|
506490
|
+
let directory;
|
|
506491
|
+
if (typeof persistence?.filePath === "string") directory = sessionScrollbackArchiveDirectory(persistence.filePath);
|
|
506492
|
+
else if (typeof agent?.sessionWirePath === "string") directory = sessionScrollbackArchiveDirectory(agent.sessionWirePath);
|
|
506493
|
+
else return false;
|
|
506494
|
+
const resumeCheckpointRestored = agent?.records?.resumeCheckpointRestored === true || agent?.resumeCheckpointRestored === true;
|
|
506495
|
+
const loadedExisting = buffer.usePersistentArchive(directory, {
|
|
506496
|
+
reset: !resumeCheckpointRestored,
|
|
506497
|
+
reuse: resumeCheckpointRestored
|
|
506498
|
+
});
|
|
506499
|
+
this.suppressReplayArchiveWrites = resumeCheckpointRestored && loadedExisting;
|
|
506500
|
+
return true;
|
|
506501
|
+
}
|
|
506502
|
+
finishSessionReplay() {
|
|
506503
|
+
this.suppressReplayArchiveWrites = false;
|
|
506437
506504
|
}
|
|
506438
506505
|
archiveComponents(components) {
|
|
506439
506506
|
const buffer = this.buffer;
|
|
506440
506507
|
if (buffer === void 0 || components.length === 0) return components.length === 0;
|
|
506508
|
+
if (this.suppressReplayArchiveWrites && this.state.appState.isReplaying) return true;
|
|
506441
506509
|
try {
|
|
506442
506510
|
const width = Math.max(1, this.state.terminal.columns);
|
|
506443
506511
|
const lines = components.flatMap((component) => component.render(width));
|
|
@@ -509723,6 +509791,7 @@ var SessionReplayRenderer = class {
|
|
|
509723
509791
|
this.host.showError(uiText("replay.error.unavailable"));
|
|
509724
509792
|
return false;
|
|
509725
509793
|
}
|
|
509794
|
+
this.host.scrollbackController.prepareSessionReplay(main);
|
|
509726
509795
|
this.hydrateSnapshot(main);
|
|
509727
509796
|
await this.renderRecords(main);
|
|
509728
509797
|
this.applyTerminalBackgroundAgentStatuses(main);
|
|
@@ -509734,6 +509803,7 @@ var SessionReplayRenderer = class {
|
|
|
509734
509803
|
this.host.showError(uiText("replay.error.failed", { error: message }));
|
|
509735
509804
|
return false;
|
|
509736
509805
|
} finally {
|
|
509806
|
+
this.host.scrollbackController.finishSessionReplay();
|
|
509737
509807
|
this.host.setAppState({ isReplaying: false });
|
|
509738
509808
|
}
|
|
509739
509809
|
}
|
|
@@ -516940,7 +517010,7 @@ var BlunTUI = class {
|
|
|
516940
517010
|
if (shouldReplayHistory) {
|
|
516941
517011
|
await this.sessionReplay.hydrateFromReplay(this.requireSession());
|
|
516942
517012
|
this.applyStartupPermissionAndPlanToAppState();
|
|
516943
|
-
}
|
|
517013
|
+
} else if (this.session !== void 0) this.scrollbackController.prepareNewSession(this.session);
|
|
516944
517014
|
const resumeState = this.session?.getResumeState();
|
|
516945
517015
|
if (resumeState?.warning !== void 0) this.showStatus(uiText("blunTui.warning", { warning: resumeState.warning }), "warning");
|
|
516946
517016
|
if (this.session !== void 0) {
|
|
@@ -518902,7 +518972,7 @@ var BlunTUI = class {
|
|
|
518902
518972
|
await this.refreshSkillCommands(this.session);
|
|
518903
518973
|
await this.refreshPluginCommands(this.session);
|
|
518904
518974
|
} catch {}
|
|
518905
|
-
this.clearTranscriptAndRedraw();
|
|
518975
|
+
this.clearTranscriptAndRedraw({ preserveScrollbackArchive: true });
|
|
518906
518976
|
try {
|
|
518907
518977
|
await this.sessionReplay.hydrateFromReplay(session);
|
|
518908
518978
|
} catch (error) {
|
|
@@ -518974,7 +519044,8 @@ var BlunTUI = class {
|
|
|
518974
519044
|
await this.refreshPluginCommands(this.session);
|
|
518975
519045
|
} catch {}
|
|
518976
519046
|
this.sessionEventHandler.startSubscription();
|
|
518977
|
-
this.clearTranscriptAndRedraw();
|
|
519047
|
+
this.clearTranscriptAndRedraw({ preserveScrollbackArchive: true });
|
|
519048
|
+
this.scrollbackController.prepareNewSession(session);
|
|
518978
519049
|
this.showStatus(uiText("blunTui.session.started", { sessionId: session.id }));
|
|
518979
519050
|
this.showSessionWarnings(session);
|
|
518980
519051
|
this.showConfigWarningsIfAny();
|
|
@@ -519090,9 +519161,10 @@ var BlunTUI = class {
|
|
|
519090
519161
|
disposeTranscriptChildren() {
|
|
519091
519162
|
for (const child of this.state.transcriptContainer.children) if (hasDispose(child)) child.dispose();
|
|
519092
519163
|
}
|
|
519093
|
-
clearTranscriptAndRedraw() {
|
|
519164
|
+
clearTranscriptAndRedraw(options = {}) {
|
|
519094
519165
|
this.streamingUI.discardPending();
|
|
519095
|
-
this.scrollbackController.
|
|
519166
|
+
if (options.preserveScrollbackArchive === true) this.scrollbackController.releaseSessionArchive();
|
|
519167
|
+
else this.scrollbackController.reset();
|
|
519096
519168
|
this.state.transcriptEntries = [];
|
|
519097
519169
|
this.streamingUI.disposeActiveCompactionBlock();
|
|
519098
519170
|
this.streamingUI.resetLiveText();
|