@tutti-os/workspace-terminal 0.0.1

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.
@@ -0,0 +1,607 @@
1
+ import {
2
+ createTerminalNodeI18nRuntime
3
+ } from "./chunk-65BWWZQV.js";
4
+
5
+ // src/core/sessionDiagnostics.ts
6
+ function createTerminalSurfaceDiagnostics(input) {
7
+ return {
8
+ dispose() {
9
+ input.diagnostics.log("dispose", resolveContext(input));
10
+ },
11
+ mount() {
12
+ input.diagnostics.log("mount", resolveContext(input));
13
+ },
14
+ outputSync({
15
+ contentEpoch,
16
+ nextCommittedBytes,
17
+ plan,
18
+ previousCommittedBytes,
19
+ rawBytes,
20
+ writeBytes
21
+ }) {
22
+ input.diagnostics.log("surface-output-sync", {
23
+ ...resolveContext(input),
24
+ contentEpoch,
25
+ nextCommittedBytes,
26
+ plan,
27
+ previousCommittedBytes,
28
+ rawBytes,
29
+ writeBytes
30
+ });
31
+ },
32
+ outputWritten({
33
+ bufferCursorX,
34
+ bufferCursorY,
35
+ bufferLength,
36
+ bytes,
37
+ canvasClientHeight,
38
+ canvasClientWidth,
39
+ canvasCount,
40
+ cols,
41
+ containerClientHeight,
42
+ containerClientWidth,
43
+ cursorLinePreview,
44
+ firstLinePreview,
45
+ helperChildCount,
46
+ mode,
47
+ remainingChunkCount,
48
+ renderDimensionsReady,
49
+ rowContainerChildCount,
50
+ rowContainerTextPreview,
51
+ rows,
52
+ screenChildCount,
53
+ screenClientHeight,
54
+ screenClientWidth,
55
+ screenDisplay,
56
+ screenOpacity,
57
+ screenVisibility,
58
+ serializedBytes,
59
+ xtermClientHeight,
60
+ xtermClientWidth,
61
+ xtermDisplay,
62
+ xtermOpacity,
63
+ xtermVisibility
64
+ }) {
65
+ input.diagnostics.log("surface-output-written", {
66
+ ...resolveContext(input),
67
+ bufferCursorX,
68
+ bufferCursorY,
69
+ bufferLength,
70
+ bytes,
71
+ canvasClientHeight,
72
+ canvasClientWidth,
73
+ canvasCount,
74
+ cols,
75
+ containerClientHeight,
76
+ containerClientWidth,
77
+ cursorLinePreview,
78
+ firstLinePreview,
79
+ helperChildCount,
80
+ mode,
81
+ remainingChunkCount,
82
+ renderDimensionsReady,
83
+ rowContainerChildCount,
84
+ rowContainerTextPreview,
85
+ rows,
86
+ screenChildCount,
87
+ screenClientHeight,
88
+ screenClientWidth,
89
+ screenDisplay,
90
+ screenOpacity,
91
+ screenVisibility,
92
+ serializedBytes,
93
+ xtermClientHeight,
94
+ xtermClientWidth,
95
+ xtermDisplay,
96
+ xtermOpacity,
97
+ xtermVisibility
98
+ });
99
+ },
100
+ resize({ cols, rows }) {
101
+ input.diagnostics.log("resize", {
102
+ ...resolveContext(input),
103
+ cols,
104
+ rows
105
+ });
106
+ }
107
+ };
108
+ }
109
+ function createTerminalCloseDiagnostics(input) {
110
+ return {
111
+ confirmed() {
112
+ input.diagnostics.log("close-confirmed", {
113
+ sessionId: input.sessionId
114
+ });
115
+ },
116
+ requested() {
117
+ input.diagnostics.log("close-requested", {
118
+ sessionId: input.sessionId
119
+ });
120
+ }
121
+ };
122
+ }
123
+ function createTerminalSessionRecoveryDiagnostics(input) {
124
+ return {
125
+ attachComplete() {
126
+ input.diagnostics.log("attach-complete", resolveContext(input));
127
+ },
128
+ attachError() {
129
+ input.diagnostics.log("attach-error", resolveContext(input));
130
+ },
131
+ attachStart(afterSeq) {
132
+ input.diagnostics.log("attach-start", {
133
+ ...resolveContext(input),
134
+ afterSeq
135
+ });
136
+ },
137
+ hydrationComplete(replayChunkCount) {
138
+ input.diagnostics.log("hydration-complete", {
139
+ ...resolveContext(input),
140
+ replayChunkCount
141
+ });
142
+ },
143
+ hydrationGap({ fromSeq, toSeq }) {
144
+ input.diagnostics.log("hydration-gap", {
145
+ ...resolveContext(input),
146
+ fromSeq,
147
+ toSeq
148
+ });
149
+ },
150
+ hydrationStart() {
151
+ input.diagnostics.log("hydration-start", resolveContext(input));
152
+ },
153
+ outputProjected({
154
+ contentEpoch,
155
+ previewHead,
156
+ previewTail,
157
+ rawBytes,
158
+ source,
159
+ writeBytes
160
+ }) {
161
+ input.diagnostics.log("output-projected", {
162
+ ...resolveContext(input),
163
+ contentEpoch,
164
+ previewHead,
165
+ previewTail,
166
+ rawBytes,
167
+ source,
168
+ writeBytes
169
+ });
170
+ },
171
+ snapshotComplete({ toSeq, truncated }) {
172
+ input.diagnostics.log("snapshot-complete", {
173
+ ...resolveContext(input),
174
+ toSeq,
175
+ truncated
176
+ });
177
+ },
178
+ snapshotStart() {
179
+ input.diagnostics.log("snapshot-start", resolveContext(input));
180
+ }
181
+ };
182
+ }
183
+ function resolveContext(input) {
184
+ return {
185
+ nodeId: input.nodeId,
186
+ sessionId: input.sessionId
187
+ };
188
+ }
189
+
190
+ // src/core/sessionProjection.ts
191
+ function isTerminalSessionEndedStatus(status) {
192
+ return status === "exited" || status === "failed";
193
+ }
194
+
195
+ // src/core/closeFlow.ts
196
+ async function closeTerminalSession({
197
+ confirm,
198
+ feature,
199
+ sessionId,
200
+ status
201
+ }) {
202
+ if (!sessionId || status && isTerminalSessionEndedStatus(status)) {
203
+ return "closed";
204
+ }
205
+ const closeDiagnostics = createTerminalCloseDiagnostics({
206
+ diagnostics: feature.diagnostics,
207
+ sessionId
208
+ });
209
+ closeDiagnostics.requested();
210
+ const guard = await feature.closeGuard.check({ sessionId });
211
+ if (isTerminalSessionEndedStatus(guard.status)) {
212
+ closeDiagnostics.confirmed();
213
+ return "closed";
214
+ }
215
+ if (guard.requiresConfirmation) {
216
+ const confirmed = await confirm?.(guard);
217
+ if (!confirmed) {
218
+ return "kept-open";
219
+ }
220
+ }
221
+ await feature.launchService.terminate({ sessionId });
222
+ closeDiagnostics.confirmed();
223
+ return "closed";
224
+ }
225
+
226
+ // src/core/feature.ts
227
+ var defaultTerminalNodeLimits = {
228
+ maxScrollbackLines: 1e4,
229
+ maxWriteBatchBytes: 64 * 1024,
230
+ snapshotChunkBytes: 256 * 1024
231
+ };
232
+ var noopTerminalDiagnostics = {
233
+ log() {
234
+ return void 0;
235
+ }
236
+ };
237
+ var defaultResolveTerminalTheme = () => ({});
238
+ function createTerminalNodeFeature(input) {
239
+ return {
240
+ closeGuard: input.closeGuard,
241
+ diagnostics: input.diagnostics ?? noopTerminalDiagnostics,
242
+ dropInput: input.dropInput,
243
+ i18n: createTerminalNodeI18nRuntime(input.i18n),
244
+ launchService: input.launchService,
245
+ limits: {
246
+ ...defaultTerminalNodeLimits,
247
+ ...input.limits
248
+ },
249
+ linkHandler: input.linkHandler,
250
+ outputTransform: input.outputTransform,
251
+ resolveTheme: input.resolveTheme ?? defaultResolveTerminalTheme,
252
+ transport: input.transport
253
+ };
254
+ }
255
+
256
+ // src/core/attachmentController.ts
257
+ function createTerminalAttachmentController(input) {
258
+ let attached = false;
259
+ let attachPromise = null;
260
+ let detachIssued = false;
261
+ let detachPromise = null;
262
+ let detachRequested = false;
263
+ const issueDetach = async () => {
264
+ if (detachIssued || !attached) {
265
+ return;
266
+ }
267
+ detachIssued = true;
268
+ attached = false;
269
+ await input.transport.detach({
270
+ clientId: input.clientId,
271
+ sessionId: input.sessionId
272
+ });
273
+ };
274
+ return {
275
+ attach(afterSeq) {
276
+ if (attachPromise) {
277
+ return attachPromise;
278
+ }
279
+ if (attached) {
280
+ return Promise.resolve();
281
+ }
282
+ attachPromise = input.transport.attach({
283
+ afterSeq,
284
+ clientId: input.clientId,
285
+ sessionId: input.sessionId
286
+ }).then(async () => {
287
+ attached = true;
288
+ attachPromise = null;
289
+ if (detachRequested) {
290
+ await issueDetach();
291
+ }
292
+ }).catch((error) => {
293
+ attachPromise = null;
294
+ throw error;
295
+ });
296
+ return attachPromise;
297
+ },
298
+ async detach() {
299
+ detachRequested = true;
300
+ if (detachPromise) {
301
+ return detachPromise;
302
+ }
303
+ detachPromise = Promise.resolve(attachPromise).catch(() => void 0).then(async () => {
304
+ await issueDetach();
305
+ }).finally(() => {
306
+ attachPromise = null;
307
+ detachIssued = false;
308
+ detachPromise = null;
309
+ detachRequested = false;
310
+ });
311
+ return detachPromise;
312
+ },
313
+ markDetached() {
314
+ attached = false;
315
+ attachPromise = null;
316
+ detachIssued = false;
317
+ detachPromise = null;
318
+ detachRequested = false;
319
+ }
320
+ };
321
+ }
322
+
323
+ // src/core/inputQueue.ts
324
+ function createBufferedTerminalInputQueue() {
325
+ const entries = [];
326
+ return {
327
+ enqueue(data, encoding = "utf8") {
328
+ if (data.length === 0) {
329
+ return;
330
+ }
331
+ entries.push({ data, encoding });
332
+ },
333
+ async flush(writer) {
334
+ const queued = entries.splice(0);
335
+ for (const entry of queued) {
336
+ await writer(entry);
337
+ }
338
+ },
339
+ reset() {
340
+ entries.length = 0;
341
+ }
342
+ };
343
+ }
344
+ async function writeQueuedTerminalInput(input) {
345
+ await input.queue.flush(
346
+ (entry) => input.transport.write({
347
+ data: entry.data,
348
+ encoding: entry.encoding,
349
+ provenance: "user",
350
+ sessionId: input.sessionId
351
+ })
352
+ );
353
+ }
354
+
355
+ // src/core/linkDetection.ts
356
+ var pathCandidatePattern = /(?<path>(?:~|\.{1,2}|\/)[^\s"'`<>|:([\]]+|[A-Za-z0-9_.-]+\/[^\s"'`<>|:([\]]+)(?<suffix>(?::(?<lineColon>\d+)(?::(?<columnColon>\d+))?)|(?:\((?<lineParen>\d+)(?:,\s*(?<columnParen>\d+))?\))|(?:\[(?<lineBracket>\d+)(?:,\s*(?<columnBracket>\d+))?\]))?/g;
357
+ function detectTerminalFileLinks(text) {
358
+ const links = [];
359
+ pathCandidatePattern.lastIndex = 0;
360
+ let match = pathCandidatePattern.exec(text);
361
+ while (match) {
362
+ const groups = match.groups ?? {};
363
+ const rawPath = groups.path ?? "";
364
+ const suffix = groups.suffix ?? "";
365
+ const candidateText = `${rawPath}${suffix}`;
366
+ const trimmed = trimTerminalPathCandidate(rawPath);
367
+ const trimAmount = rawPath.length - trimmed.length;
368
+ if (isTerminalPathCandidate(trimmed, text, match.index)) {
369
+ const line = parsePositiveInteger(
370
+ groups.lineColon ?? groups.lineParen ?? groups.lineBracket
371
+ );
372
+ const column = parsePositiveInteger(
373
+ groups.columnColon ?? groups.columnParen ?? groups.columnBracket
374
+ );
375
+ links.push({
376
+ column,
377
+ index: match.index,
378
+ line,
379
+ path: trimmed,
380
+ text: candidateText.slice(0, candidateText.length - trimAmount)
381
+ });
382
+ }
383
+ match = pathCandidatePattern.exec(text);
384
+ }
385
+ return links;
386
+ }
387
+ function toTerminalLinkTarget(link) {
388
+ return {
389
+ column: link.column,
390
+ line: link.line,
391
+ path: link.path
392
+ };
393
+ }
394
+ function trimTerminalPathCandidate(value) {
395
+ let result = value.trim();
396
+ while (/[),.;:!?]$/.test(result) && !looksLikeFileExtension(result)) {
397
+ result = result.slice(0, -1);
398
+ }
399
+ return result;
400
+ }
401
+ function looksLikeFileExtension(value) {
402
+ return /\.[A-Za-z0-9]{1,8}$/.test(value);
403
+ }
404
+ function isTerminalPathCandidate(value, sourceText, index) {
405
+ if (value.length === 0) {
406
+ return false;
407
+ }
408
+ if (/^\d+(?::\d+)*$/.test(value)) {
409
+ return false;
410
+ }
411
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value)) {
412
+ return false;
413
+ }
414
+ if (value.startsWith("//") || sourceText[index - 1] === ":") {
415
+ return false;
416
+ }
417
+ if (value.startsWith("node:")) {
418
+ return false;
419
+ }
420
+ return value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("~/") || value.includes("/");
421
+ }
422
+ function parsePositiveInteger(value) {
423
+ if (!value) {
424
+ return void 0;
425
+ }
426
+ const parsed = Number.parseInt(value, 10);
427
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
428
+ }
429
+
430
+ // src/core/screenStateCache.ts
431
+ function createTerminalScreenStateCache() {
432
+ const screenStateByNodeId = /* @__PURE__ */ new Map();
433
+ const invalidatedSessionIdByNodeId = /* @__PURE__ */ new Map();
434
+ const get = (nodeId, sessionId) => {
435
+ const normalizedNodeId = normalizeId(nodeId);
436
+ const normalizedSessionId = normalizeId(sessionId);
437
+ if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {
438
+ return null;
439
+ }
440
+ if (invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId) {
441
+ return null;
442
+ }
443
+ const cached = screenStateByNodeId.get(normalizedNodeId);
444
+ if (!cached || cached.sessionId !== normalizedSessionId) {
445
+ return null;
446
+ }
447
+ return cached;
448
+ };
449
+ const peek = (nodeId) => {
450
+ const normalizedNodeId = normalizeId(nodeId);
451
+ if (normalizedNodeId.length === 0) {
452
+ return null;
453
+ }
454
+ return screenStateByNodeId.get(normalizedNodeId) ?? null;
455
+ };
456
+ const set = (nodeId, state) => {
457
+ const normalizedNodeId = normalizeId(nodeId);
458
+ const normalizedSessionId = normalizeId(state.sessionId);
459
+ if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0 || state.serialized.length === 0) {
460
+ return;
461
+ }
462
+ if (invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId) {
463
+ invalidatedSessionIdByNodeId.delete(normalizedNodeId);
464
+ return;
465
+ }
466
+ invalidatedSessionIdByNodeId.delete(normalizedNodeId);
467
+ screenStateByNodeId.set(normalizedNodeId, {
468
+ cols: normalizeDimension(state.cols, 80),
469
+ rawSnapshot: state.rawSnapshot,
470
+ rows: normalizeDimension(state.rows, 24),
471
+ serialized: state.serialized,
472
+ sessionId: normalizedSessionId
473
+ });
474
+ };
475
+ const remove = (nodeId, sessionId) => {
476
+ const normalizedNodeId = normalizeId(nodeId);
477
+ const normalizedSessionId = normalizeId(sessionId);
478
+ if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {
479
+ return;
480
+ }
481
+ const cached = screenStateByNodeId.get(normalizedNodeId);
482
+ if (cached?.sessionId === normalizedSessionId) {
483
+ screenStateByNodeId.delete(normalizedNodeId);
484
+ }
485
+ if (invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId) {
486
+ invalidatedSessionIdByNodeId.delete(normalizedNodeId);
487
+ }
488
+ };
489
+ const invalidate = (nodeId, sessionId) => {
490
+ const normalizedNodeId = normalizeId(nodeId);
491
+ const normalizedSessionId = normalizeId(sessionId);
492
+ if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {
493
+ return;
494
+ }
495
+ screenStateByNodeId.delete(normalizedNodeId);
496
+ invalidatedSessionIdByNodeId.set(normalizedNodeId, normalizedSessionId);
497
+ };
498
+ const isInvalidated = (nodeId, sessionId) => {
499
+ const normalizedNodeId = normalizeId(nodeId);
500
+ const normalizedSessionId = normalizeId(sessionId);
501
+ if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {
502
+ return false;
503
+ }
504
+ return invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId;
505
+ };
506
+ const clearInvalidation = (nodeId, sessionId) => {
507
+ const normalizedNodeId = normalizeId(nodeId);
508
+ const normalizedSessionId = normalizeId(sessionId);
509
+ if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {
510
+ return;
511
+ }
512
+ if (invalidatedSessionIdByNodeId.get(normalizedNodeId) !== normalizedSessionId) {
513
+ return;
514
+ }
515
+ invalidatedSessionIdByNodeId.delete(normalizedNodeId);
516
+ };
517
+ const clear = () => {
518
+ screenStateByNodeId.clear();
519
+ invalidatedSessionIdByNodeId.clear();
520
+ };
521
+ return {
522
+ clear,
523
+ clearInvalidation,
524
+ get,
525
+ invalidate,
526
+ isInvalidated,
527
+ peek,
528
+ remove,
529
+ set
530
+ };
531
+ }
532
+ function normalizeId(value) {
533
+ return value.trim();
534
+ }
535
+ function normalizeDimension(value, fallback) {
536
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
537
+ }
538
+
539
+ // src/core/stringOverlap.ts
540
+ function resolveSuffixPrefixOverlap(left, right) {
541
+ if (left.length === 0 || right.length === 0) {
542
+ return 0;
543
+ }
544
+ const max = Math.min(left.length, right.length);
545
+ const leftTail = left.slice(-max);
546
+ const rightPrefix = right.slice(0, max);
547
+ const combined = `${rightPrefix}\0${leftTail}`;
548
+ const prefix = new Uint32Array(combined.length);
549
+ let cursor = 0;
550
+ for (let index = 1; index < combined.length; index += 1) {
551
+ while (cursor > 0 && combined[index] !== combined[cursor]) {
552
+ cursor = prefix[cursor - 1] ?? 0;
553
+ }
554
+ if (combined[index] === combined[cursor]) {
555
+ cursor += 1;
556
+ prefix[index] = cursor;
557
+ }
558
+ }
559
+ return prefix[combined.length - 1] ?? 0;
560
+ }
561
+
562
+ // src/core/scrollback.ts
563
+ var defaultMaxTerminalScrollbackChars = 4e5;
564
+ function truncateTerminalScrollback(snapshot, options) {
565
+ const maxChars = normalizeMaxChars(options?.maxChars);
566
+ if (snapshot.length <= maxChars) {
567
+ return snapshot;
568
+ }
569
+ return snapshot.slice(-maxChars);
570
+ }
571
+ function resolveTerminalScrollbackDelta(previous, next, options) {
572
+ const previousSnapshot = truncateTerminalScrollback(previous, options);
573
+ const nextSnapshot = truncateTerminalScrollback(next, options);
574
+ if (previousSnapshot.length === 0) {
575
+ return nextSnapshot;
576
+ }
577
+ if (nextSnapshot.length === 0 || previousSnapshot === nextSnapshot) {
578
+ return "";
579
+ }
580
+ if (previousSnapshot.includes(nextSnapshot)) {
581
+ return "";
582
+ }
583
+ const overlap = resolveSuffixPrefixOverlap(previousSnapshot, nextSnapshot);
584
+ return nextSnapshot.slice(overlap);
585
+ }
586
+ function normalizeMaxChars(value) {
587
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : defaultMaxTerminalScrollbackChars;
588
+ }
589
+
590
+ export {
591
+ createTerminalAttachmentController,
592
+ createTerminalSurfaceDiagnostics,
593
+ createTerminalCloseDiagnostics,
594
+ createTerminalSessionRecoveryDiagnostics,
595
+ isTerminalSessionEndedStatus,
596
+ closeTerminalSession,
597
+ defaultTerminalNodeLimits,
598
+ createTerminalNodeFeature,
599
+ createBufferedTerminalInputQueue,
600
+ writeQueuedTerminalInput,
601
+ detectTerminalFileLinks,
602
+ toTerminalLinkTarget,
603
+ createTerminalScreenStateCache,
604
+ truncateTerminalScrollback,
605
+ resolveTerminalScrollbackDelta
606
+ };
607
+ //# sourceMappingURL=chunk-56B5GYMU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/sessionDiagnostics.ts","../src/core/sessionProjection.ts","../src/core/closeFlow.ts","../src/core/feature.ts","../src/core/attachmentController.ts","../src/core/inputQueue.ts","../src/core/linkDetection.ts","../src/core/screenStateCache.ts","../src/core/stringOverlap.ts","../src/core/scrollback.ts"],"sourcesContent":["import type { TerminalDiagnostics } from \"../contracts/index.ts\";\n\nexport interface TerminalCloseDiagnostics {\n confirmed(): void;\n requested(): void;\n}\n\nexport interface TerminalSurfaceDiagnostics {\n dispose(): void;\n mount(): void;\n outputSync(input: {\n contentEpoch: number;\n nextCommittedBytes: number;\n plan: \"append\" | \"replace\" | \"reset\" | \"skip\";\n previousCommittedBytes: number;\n rawBytes: number;\n writeBytes: number;\n }): void;\n outputWritten(input: {\n bufferCursorX: number;\n bufferCursorY: number;\n bufferLength: number;\n bytes: number;\n canvasClientHeight: number;\n canvasClientWidth: number;\n canvasCount: number;\n cols: number;\n containerClientHeight: number;\n containerClientWidth: number;\n cursorLinePreview: string;\n firstLinePreview: string;\n helperChildCount: number;\n mode: \"append\" | \"cache\" | \"replace\" | \"reset\";\n remainingChunkCount: number;\n renderDimensionsReady: boolean;\n rowContainerChildCount: number;\n rowContainerTextPreview: string;\n rows: number;\n screenChildCount: number;\n screenClientHeight: number;\n screenClientWidth: number;\n screenDisplay: string;\n screenOpacity: string;\n screenVisibility: string;\n serializedBytes: number;\n xtermClientHeight: number;\n xtermClientWidth: number;\n xtermDisplay: string;\n xtermOpacity: string;\n xtermVisibility: string;\n }): void;\n resize(input: { cols: number; rows: number }): void;\n}\n\nexport interface TerminalSessionRecoveryDiagnostics {\n attachComplete(): void;\n attachError(): void;\n attachStart(afterSeq: number | null): void;\n hydrationComplete(replayChunkCount: number): void;\n hydrationGap(input: { fromSeq: number; toSeq: number }): void;\n hydrationStart(): void;\n outputProjected(input: {\n contentEpoch: number;\n previewHead: string;\n previewTail: string;\n rawBytes: number;\n source: \"replay\" | \"snapshot\";\n writeBytes: number;\n }): void;\n snapshotComplete(input: { toSeq: number | null; truncated: boolean }): void;\n snapshotStart(): void;\n}\n\nexport function createTerminalSurfaceDiagnostics(input: {\n diagnostics: TerminalDiagnostics;\n nodeId: string;\n sessionId: string;\n}): TerminalSurfaceDiagnostics {\n return {\n dispose() {\n input.diagnostics.log(\"dispose\", resolveContext(input));\n },\n mount() {\n input.diagnostics.log(\"mount\", resolveContext(input));\n },\n outputSync({\n contentEpoch,\n nextCommittedBytes,\n plan,\n previousCommittedBytes,\n rawBytes,\n writeBytes\n }) {\n input.diagnostics.log(\"surface-output-sync\", {\n ...resolveContext(input),\n contentEpoch,\n nextCommittedBytes,\n plan,\n previousCommittedBytes,\n rawBytes,\n writeBytes\n });\n },\n outputWritten({\n bufferCursorX,\n bufferCursorY,\n bufferLength,\n bytes,\n canvasClientHeight,\n canvasClientWidth,\n canvasCount,\n cols,\n containerClientHeight,\n containerClientWidth,\n cursorLinePreview,\n firstLinePreview,\n helperChildCount,\n mode,\n remainingChunkCount,\n renderDimensionsReady,\n rowContainerChildCount,\n rowContainerTextPreview,\n rows,\n screenChildCount,\n screenClientHeight,\n screenClientWidth,\n screenDisplay,\n screenOpacity,\n screenVisibility,\n serializedBytes,\n xtermClientHeight,\n xtermClientWidth,\n xtermDisplay,\n xtermOpacity,\n xtermVisibility\n }) {\n input.diagnostics.log(\"surface-output-written\", {\n ...resolveContext(input),\n bufferCursorX,\n bufferCursorY,\n bufferLength,\n bytes,\n canvasClientHeight,\n canvasClientWidth,\n canvasCount,\n cols,\n containerClientHeight,\n containerClientWidth,\n cursorLinePreview,\n firstLinePreview,\n helperChildCount,\n mode,\n remainingChunkCount,\n renderDimensionsReady,\n rowContainerChildCount,\n rowContainerTextPreview,\n rows,\n screenChildCount,\n screenClientHeight,\n screenClientWidth,\n screenDisplay,\n screenOpacity,\n screenVisibility,\n serializedBytes,\n xtermClientHeight,\n xtermClientWidth,\n xtermDisplay,\n xtermOpacity,\n xtermVisibility\n });\n },\n resize({ cols, rows }) {\n input.diagnostics.log(\"resize\", {\n ...resolveContext(input),\n cols,\n rows\n });\n }\n };\n}\n\nexport function createTerminalCloseDiagnostics(input: {\n diagnostics: TerminalDiagnostics;\n sessionId: string;\n}): TerminalCloseDiagnostics {\n return {\n confirmed() {\n input.diagnostics.log(\"close-confirmed\", {\n sessionId: input.sessionId\n });\n },\n requested() {\n input.diagnostics.log(\"close-requested\", {\n sessionId: input.sessionId\n });\n }\n };\n}\n\nexport function createTerminalSessionRecoveryDiagnostics(input: {\n diagnostics: TerminalDiagnostics;\n nodeId: string;\n sessionId: string;\n}): TerminalSessionRecoveryDiagnostics {\n return {\n attachComplete() {\n input.diagnostics.log(\"attach-complete\", resolveContext(input));\n },\n attachError() {\n input.diagnostics.log(\"attach-error\", resolveContext(input));\n },\n attachStart(afterSeq) {\n input.diagnostics.log(\"attach-start\", {\n ...resolveContext(input),\n afterSeq\n });\n },\n hydrationComplete(replayChunkCount) {\n input.diagnostics.log(\"hydration-complete\", {\n ...resolveContext(input),\n replayChunkCount\n });\n },\n hydrationGap({ fromSeq, toSeq }) {\n input.diagnostics.log(\"hydration-gap\", {\n ...resolveContext(input),\n fromSeq,\n toSeq\n });\n },\n hydrationStart() {\n input.diagnostics.log(\"hydration-start\", resolveContext(input));\n },\n outputProjected({\n contentEpoch,\n previewHead,\n previewTail,\n rawBytes,\n source,\n writeBytes\n }) {\n input.diagnostics.log(\"output-projected\", {\n ...resolveContext(input),\n contentEpoch,\n previewHead,\n previewTail,\n rawBytes,\n source,\n writeBytes\n });\n },\n snapshotComplete({ toSeq, truncated }) {\n input.diagnostics.log(\"snapshot-complete\", {\n ...resolveContext(input),\n toSeq,\n truncated\n });\n },\n snapshotStart() {\n input.diagnostics.log(\"snapshot-start\", resolveContext(input));\n }\n };\n}\n\nfunction resolveContext(input: { nodeId: string; sessionId: string }) {\n return {\n nodeId: input.nodeId,\n sessionId: input.sessionId\n };\n}\n","import type {\n TerminalNodeExternalState,\n TerminalSessionStatus\n} from \"../contracts/index.ts\";\n\nexport const terminalSessionLostMessage = \"Terminal session was lost.\";\n\nexport interface TerminalSessionStatusProjection {\n lastError: string | null;\n status: TerminalSessionStatus;\n}\n\nexport function createTerminalSessionExitProjection(): TerminalSessionStatusProjection {\n return {\n lastError: null,\n status: \"exited\"\n };\n}\n\nexport function createTerminalSessionFailedProjection(\n lastError = terminalSessionLostMessage\n): TerminalSessionStatusProjection {\n return {\n lastError,\n status: \"failed\"\n };\n}\n\nexport function applyTerminalSessionStatusProjection<\n THostMetadata extends Record<string, unknown> = Record<string, unknown>\n>(\n current: TerminalNodeExternalState<THostMetadata>,\n projection: TerminalSessionStatusProjection,\n now: () => string = () => new Date().toISOString()\n): TerminalNodeExternalState<THostMetadata> {\n if (\n current.endedAt &&\n isTerminalSessionEndedStatus(current.status) &&\n !isTerminalSessionEndedStatus(projection.status)\n ) {\n return current;\n }\n\n return {\n ...current,\n endedAt: isTerminalSessionEndedStatus(projection.status)\n ? (current.endedAt ?? now())\n : current.endedAt,\n lastError: projection.lastError,\n status: projection.status\n };\n}\n\nexport function applyTerminalSessionTitleProjection<\n THostMetadata extends Record<string, unknown> = Record<string, unknown>\n>(\n current: TerminalNodeExternalState<THostMetadata>,\n title: string\n): TerminalNodeExternalState<THostMetadata> {\n return {\n ...current,\n title\n };\n}\n\nexport function isTerminalSessionEndedStatus(\n status: TerminalSessionStatus\n): boolean {\n return status === \"exited\" || status === \"failed\";\n}\n","import type {\n TerminalCloseGuardResult,\n TerminalLaunchService,\n TerminalSessionStatus\n} from \"../contracts/index.ts\";\nimport { createTerminalCloseDiagnostics } from \"./sessionDiagnostics.ts\";\nimport type { TerminalNodeFeature } from \"./feature.ts\";\nimport { isTerminalSessionEndedStatus } from \"./sessionProjection.ts\";\n\nexport type TerminalCloseConfirmation = (\n guard: TerminalCloseGuardResult\n) => Promise<boolean> | boolean;\n\nexport type TerminalCloseResult = \"closed\" | \"kept-open\";\n\nexport interface CloseTerminalSessionInput {\n confirm?: TerminalCloseConfirmation;\n feature: Pick<TerminalNodeFeature, \"closeGuard\" | \"diagnostics\"> & {\n launchService: Pick<TerminalLaunchService, \"terminate\">;\n };\n sessionId: string | null | undefined;\n status?: TerminalSessionStatus | null | undefined;\n}\n\nexport async function closeTerminalSession({\n confirm,\n feature,\n sessionId,\n status\n}: CloseTerminalSessionInput): Promise<TerminalCloseResult> {\n if (!sessionId || (status && isTerminalSessionEndedStatus(status))) {\n return \"closed\";\n }\n\n const closeDiagnostics = createTerminalCloseDiagnostics({\n diagnostics: feature.diagnostics,\n sessionId\n });\n\n closeDiagnostics.requested();\n const guard = await feature.closeGuard.check({ sessionId });\n if (isTerminalSessionEndedStatus(guard.status)) {\n closeDiagnostics.confirmed();\n return \"closed\";\n }\n if (guard.requiresConfirmation) {\n const confirmed = await confirm?.(guard);\n if (!confirmed) {\n return \"kept-open\";\n }\n }\n\n await feature.launchService.terminate({ sessionId });\n closeDiagnostics.confirmed();\n return \"closed\";\n}\n","import type { I18nRuntime } from \"@tutti-os/ui-i18n-runtime\";\nimport {\n createTerminalNodeI18nRuntime,\n type TerminalNodeI18nRuntime\n} from \"../i18n/terminalNodeI18n.ts\";\nimport type {\n TerminalCloseGuardService,\n TerminalDiagnostics,\n TerminalDropInputResolver,\n TerminalLaunchService,\n TerminalLinkHandler,\n TerminalNodeLimits,\n TerminalOutputTransform,\n TerminalThemeResolver,\n TerminalTransport\n} from \"../contracts/index.ts\";\n\nexport interface TerminalNodeFeature {\n closeGuard: TerminalCloseGuardService;\n diagnostics: TerminalDiagnostics;\n dropInput?: TerminalDropInputResolver;\n i18n: TerminalNodeI18nRuntime;\n launchService: TerminalLaunchService;\n limits: TerminalNodeLimits;\n linkHandler?: TerminalLinkHandler;\n outputTransform?: TerminalOutputTransform;\n resolveTheme: TerminalThemeResolver;\n transport: TerminalTransport;\n}\n\nexport interface CreateTerminalNodeFeatureInput {\n closeGuard: TerminalCloseGuardService;\n diagnostics?: TerminalDiagnostics;\n dropInput?: TerminalDropInputResolver;\n i18n?: I18nRuntime<string>;\n launchService: TerminalLaunchService;\n limits?: Partial<TerminalNodeLimits>;\n linkHandler?: TerminalLinkHandler;\n outputTransform?: TerminalOutputTransform;\n resolveTheme?: TerminalThemeResolver;\n transport: TerminalTransport;\n}\n\nexport const defaultTerminalNodeLimits: TerminalNodeLimits = {\n maxScrollbackLines: 10_000,\n maxWriteBatchBytes: 64 * 1024,\n snapshotChunkBytes: 256 * 1024\n};\n\nconst noopTerminalDiagnostics: TerminalDiagnostics = {\n log() {\n return undefined;\n }\n};\n\nconst defaultResolveTerminalTheme: TerminalThemeResolver = () => ({});\n\nexport function createTerminalNodeFeature(\n input: CreateTerminalNodeFeatureInput\n): TerminalNodeFeature {\n return {\n closeGuard: input.closeGuard,\n diagnostics: input.diagnostics ?? noopTerminalDiagnostics,\n dropInput: input.dropInput,\n i18n: createTerminalNodeI18nRuntime(input.i18n),\n launchService: input.launchService,\n limits: {\n ...defaultTerminalNodeLimits,\n ...input.limits\n },\n linkHandler: input.linkHandler,\n outputTransform: input.outputTransform,\n resolveTheme: input.resolveTheme ?? defaultResolveTerminalTheme,\n transport: input.transport\n };\n}\n","import type { TerminalTransport } from \"../contracts/index.ts\";\n\nexport interface TerminalAttachmentController {\n attach(afterSeq?: number): Promise<void>;\n detach(): Promise<void>;\n markDetached(): void;\n}\n\nexport function createTerminalAttachmentController(input: {\n clientId: string;\n sessionId: string;\n transport: Pick<TerminalTransport, \"attach\" | \"detach\">;\n}): TerminalAttachmentController {\n let attached = false;\n let attachPromise: Promise<void> | null = null;\n let detachIssued = false;\n let detachPromise: Promise<void> | null = null;\n let detachRequested = false;\n\n const issueDetach = async () => {\n if (detachIssued || !attached) {\n return;\n }\n detachIssued = true;\n attached = false;\n await input.transport.detach({\n clientId: input.clientId,\n sessionId: input.sessionId\n });\n };\n\n return {\n attach(afterSeq) {\n if (attachPromise) {\n return attachPromise;\n }\n if (attached) {\n return Promise.resolve();\n }\n\n attachPromise = input.transport\n .attach({\n afterSeq,\n clientId: input.clientId,\n sessionId: input.sessionId\n })\n .then(async () => {\n attached = true;\n attachPromise = null;\n if (detachRequested) {\n await issueDetach();\n }\n })\n .catch((error: unknown) => {\n attachPromise = null;\n throw error;\n });\n\n return attachPromise;\n },\n async detach() {\n detachRequested = true;\n if (detachPromise) {\n return detachPromise;\n }\n detachPromise = Promise.resolve(attachPromise)\n .catch(() => undefined)\n .then(async () => {\n await issueDetach();\n })\n .finally(() => {\n attachPromise = null;\n detachIssued = false;\n detachPromise = null;\n detachRequested = false;\n });\n return detachPromise;\n },\n markDetached() {\n attached = false;\n attachPromise = null;\n detachIssued = false;\n detachPromise = null;\n detachRequested = false;\n }\n };\n}\n","import type {\n TerminalTransport,\n TerminalWriteEncoding\n} from \"../contracts/index.ts\";\n\nexport interface QueuedTerminalInput {\n data: string;\n encoding: TerminalWriteEncoding;\n}\n\nexport interface BufferedTerminalInputQueue {\n enqueue(data: string, encoding?: TerminalWriteEncoding): void;\n flush(writer: (entry: QueuedTerminalInput) => Promise<void>): Promise<void>;\n reset(): void;\n}\n\nexport function createBufferedTerminalInputQueue(): BufferedTerminalInputQueue {\n const entries: QueuedTerminalInput[] = [];\n\n return {\n enqueue(data, encoding = \"utf8\") {\n if (data.length === 0) {\n return;\n }\n entries.push({ data, encoding });\n },\n async flush(writer) {\n const queued = entries.splice(0);\n for (const entry of queued) {\n await writer(entry);\n }\n },\n reset() {\n entries.length = 0;\n }\n };\n}\n\nexport async function writeQueuedTerminalInput(input: {\n queue: BufferedTerminalInputQueue;\n sessionId: string;\n transport: Pick<TerminalTransport, \"write\">;\n}): Promise<void> {\n await input.queue.flush((entry) =>\n input.transport.write({\n data: entry.data,\n encoding: entry.encoding,\n provenance: \"user\",\n sessionId: input.sessionId\n })\n );\n}\n","import type { TerminalLinkTarget } from \"../contracts/index.ts\";\n\nexport interface DetectedTerminalFileLink {\n column?: number;\n index: number;\n line?: number;\n path: string;\n text: string;\n}\n\nconst pathCandidatePattern =\n /(?<path>(?:~|\\.{1,2}|\\/)[^\\s\"'`<>|:([\\]]+|[A-Za-z0-9_.-]+\\/[^\\s\"'`<>|:([\\]]+)(?<suffix>(?::(?<lineColon>\\d+)(?::(?<columnColon>\\d+))?)|(?:\\((?<lineParen>\\d+)(?:,\\s*(?<columnParen>\\d+))?\\))|(?:\\[(?<lineBracket>\\d+)(?:,\\s*(?<columnBracket>\\d+))?\\]))?/g;\n\nexport function detectTerminalFileLinks(\n text: string\n): DetectedTerminalFileLink[] {\n const links: DetectedTerminalFileLink[] = [];\n pathCandidatePattern.lastIndex = 0;\n\n let match = pathCandidatePattern.exec(text);\n while (match) {\n const groups = match.groups ?? {};\n const rawPath = groups.path ?? \"\";\n const suffix = groups.suffix ?? \"\";\n const candidateText = `${rawPath}${suffix}`;\n const trimmed = trimTerminalPathCandidate(rawPath);\n const trimAmount = rawPath.length - trimmed.length;\n\n if (isTerminalPathCandidate(trimmed, text, match.index)) {\n const line = parsePositiveInteger(\n groups.lineColon ?? groups.lineParen ?? groups.lineBracket\n );\n const column = parsePositiveInteger(\n groups.columnColon ?? groups.columnParen ?? groups.columnBracket\n );\n links.push({\n column,\n index: match.index,\n line,\n path: trimmed,\n text: candidateText.slice(0, candidateText.length - trimAmount)\n });\n }\n\n match = pathCandidatePattern.exec(text);\n }\n\n return links;\n}\n\nexport function toTerminalLinkTarget(\n link: DetectedTerminalFileLink\n): TerminalLinkTarget {\n return {\n column: link.column,\n line: link.line,\n path: link.path\n };\n}\n\nfunction trimTerminalPathCandidate(value: string): string {\n let result = value.trim();\n while (/[),.;:!?]$/.test(result) && !looksLikeFileExtension(result)) {\n result = result.slice(0, -1);\n }\n return result;\n}\n\nfunction looksLikeFileExtension(value: string): boolean {\n return /\\.[A-Za-z0-9]{1,8}$/.test(value);\n}\n\nfunction isTerminalPathCandidate(\n value: string,\n sourceText: string,\n index: number\n): boolean {\n if (value.length === 0) {\n return false;\n }\n if (/^\\d+(?::\\d+)*$/.test(value)) {\n return false;\n }\n if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(value)) {\n return false;\n }\n if (value.startsWith(\"//\") || sourceText[index - 1] === \":\") {\n return false;\n }\n if (value.startsWith(\"node:\")) {\n return false;\n }\n return (\n value.startsWith(\"/\") ||\n value.startsWith(\"./\") ||\n value.startsWith(\"../\") ||\n value.startsWith(\"~/\") ||\n value.includes(\"/\")\n );\n}\n\nfunction parsePositiveInteger(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n}\n","export interface CachedTerminalScreenState {\n cols: number;\n rawSnapshot: string;\n rows: number;\n serialized: string;\n sessionId: string;\n}\n\nexport interface TerminalScreenStateCache {\n clear(): void;\n clearInvalidation(nodeId: string, sessionId: string): void;\n get(nodeId: string, sessionId: string): CachedTerminalScreenState | null;\n invalidate(nodeId: string, sessionId: string): void;\n isInvalidated(nodeId: string, sessionId: string): boolean;\n peek(nodeId: string): CachedTerminalScreenState | null;\n remove(nodeId: string, sessionId: string): void;\n set(nodeId: string, state: CachedTerminalScreenState): void;\n}\n\nexport function createTerminalScreenStateCache(): TerminalScreenStateCache {\n const screenStateByNodeId = new Map<string, CachedTerminalScreenState>();\n const invalidatedSessionIdByNodeId = new Map<string, string>();\n\n const get = (\n nodeId: string,\n sessionId: string\n ): CachedTerminalScreenState | null => {\n const normalizedNodeId = normalizeId(nodeId);\n const normalizedSessionId = normalizeId(sessionId);\n\n if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {\n return null;\n }\n\n if (\n invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId\n ) {\n return null;\n }\n\n const cached = screenStateByNodeId.get(normalizedNodeId);\n if (!cached || cached.sessionId !== normalizedSessionId) {\n return null;\n }\n\n return cached;\n };\n\n const peek = (nodeId: string): CachedTerminalScreenState | null => {\n const normalizedNodeId = normalizeId(nodeId);\n if (normalizedNodeId.length === 0) {\n return null;\n }\n\n return screenStateByNodeId.get(normalizedNodeId) ?? null;\n };\n\n const set = (nodeId: string, state: CachedTerminalScreenState): void => {\n const normalizedNodeId = normalizeId(nodeId);\n const normalizedSessionId = normalizeId(state.sessionId);\n\n if (\n normalizedNodeId.length === 0 ||\n normalizedSessionId.length === 0 ||\n state.serialized.length === 0\n ) {\n return;\n }\n\n if (\n invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId\n ) {\n invalidatedSessionIdByNodeId.delete(normalizedNodeId);\n return;\n }\n\n invalidatedSessionIdByNodeId.delete(normalizedNodeId);\n screenStateByNodeId.set(normalizedNodeId, {\n cols: normalizeDimension(state.cols, 80),\n rawSnapshot: state.rawSnapshot,\n rows: normalizeDimension(state.rows, 24),\n serialized: state.serialized,\n sessionId: normalizedSessionId\n });\n };\n\n const remove = (nodeId: string, sessionId: string): void => {\n const normalizedNodeId = normalizeId(nodeId);\n const normalizedSessionId = normalizeId(sessionId);\n\n if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {\n return;\n }\n\n const cached = screenStateByNodeId.get(normalizedNodeId);\n if (cached?.sessionId === normalizedSessionId) {\n screenStateByNodeId.delete(normalizedNodeId);\n }\n\n if (\n invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId\n ) {\n invalidatedSessionIdByNodeId.delete(normalizedNodeId);\n }\n };\n\n const invalidate = (nodeId: string, sessionId: string): void => {\n const normalizedNodeId = normalizeId(nodeId);\n const normalizedSessionId = normalizeId(sessionId);\n\n if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {\n return;\n }\n\n screenStateByNodeId.delete(normalizedNodeId);\n invalidatedSessionIdByNodeId.set(normalizedNodeId, normalizedSessionId);\n };\n\n const isInvalidated = (nodeId: string, sessionId: string): boolean => {\n const normalizedNodeId = normalizeId(nodeId);\n const normalizedSessionId = normalizeId(sessionId);\n\n if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {\n return false;\n }\n\n return (\n invalidatedSessionIdByNodeId.get(normalizedNodeId) === normalizedSessionId\n );\n };\n\n const clearInvalidation = (nodeId: string, sessionId: string): void => {\n const normalizedNodeId = normalizeId(nodeId);\n const normalizedSessionId = normalizeId(sessionId);\n\n if (normalizedNodeId.length === 0 || normalizedSessionId.length === 0) {\n return;\n }\n\n if (\n invalidatedSessionIdByNodeId.get(normalizedNodeId) !== normalizedSessionId\n ) {\n return;\n }\n\n invalidatedSessionIdByNodeId.delete(normalizedNodeId);\n };\n\n const clear = (): void => {\n screenStateByNodeId.clear();\n invalidatedSessionIdByNodeId.clear();\n };\n\n return {\n clear,\n clearInvalidation,\n get,\n invalidate,\n isInvalidated,\n peek,\n remove,\n set\n };\n}\n\nfunction normalizeId(value: string): string {\n return value.trim();\n}\n\nfunction normalizeDimension(value: number, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n ? Math.floor(value)\n : fallback;\n}\n","export function resolveSuffixPrefixOverlap(\n left: string,\n right: string\n): number {\n if (left.length === 0 || right.length === 0) {\n return 0;\n }\n\n const max = Math.min(left.length, right.length);\n const leftTail = left.slice(-max);\n const rightPrefix = right.slice(0, max);\n const combined = `${rightPrefix}\\u0000${leftTail}`;\n const prefix = new Uint32Array(combined.length);\n let cursor = 0;\n\n for (let index = 1; index < combined.length; index += 1) {\n while (cursor > 0 && combined[index] !== combined[cursor]) {\n cursor = prefix[cursor - 1] ?? 0;\n }\n\n if (combined[index] === combined[cursor]) {\n cursor += 1;\n prefix[index] = cursor;\n }\n }\n\n return prefix[combined.length - 1] ?? 0;\n}\n","import { resolveSuffixPrefixOverlap } from \"./stringOverlap.ts\";\n\nexport const defaultMaxTerminalScrollbackChars = 400_000;\n\nexport interface TerminalScrollbackOptions {\n maxChars?: number;\n}\n\nexport function truncateTerminalScrollback(\n snapshot: string,\n options?: TerminalScrollbackOptions\n): string {\n const maxChars = normalizeMaxChars(options?.maxChars);\n if (snapshot.length <= maxChars) {\n return snapshot;\n }\n\n return snapshot.slice(-maxChars);\n}\n\nexport function resolveTerminalScrollbackDelta(\n previous: string,\n next: string,\n options?: TerminalScrollbackOptions\n): string {\n const previousSnapshot = truncateTerminalScrollback(previous, options);\n const nextSnapshot = truncateTerminalScrollback(next, options);\n\n if (previousSnapshot.length === 0) {\n return nextSnapshot;\n }\n\n if (nextSnapshot.length === 0 || previousSnapshot === nextSnapshot) {\n return \"\";\n }\n\n if (previousSnapshot.includes(nextSnapshot)) {\n return \"\";\n }\n\n const overlap = resolveSuffixPrefixOverlap(previousSnapshot, nextSnapshot);\n return nextSnapshot.slice(overlap);\n}\n\nexport function mergeTerminalScrollbackSnapshots(\n persisted: string,\n live: string,\n options?: TerminalScrollbackOptions\n): string {\n const persistedSnapshot = truncateTerminalScrollback(persisted, options);\n const liveSnapshot = truncateTerminalScrollback(live, options);\n\n if (persistedSnapshot.length === 0) {\n return liveSnapshot;\n }\n\n if (liveSnapshot.length === 0) {\n return persistedSnapshot;\n }\n\n if (persistedSnapshot === liveSnapshot) {\n return liveSnapshot;\n }\n\n if (liveSnapshot.includes(persistedSnapshot)) {\n return liveSnapshot;\n }\n\n if (persistedSnapshot.includes(liveSnapshot)) {\n return persistedSnapshot;\n }\n\n const overlap = resolveSuffixPrefixOverlap(persistedSnapshot, liveSnapshot);\n return truncateTerminalScrollback(\n `${persistedSnapshot}${liveSnapshot.slice(overlap)}`,\n options\n );\n}\n\nfunction normalizeMaxChars(value: number | undefined): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n ? Math.floor(value)\n : defaultMaxTerminalScrollbackChars;\n}\n"],"mappings":"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","names":[]}