@vybestack/llxprt-code-tools 0.10.0 → 0.11.0-nightly.260728.ffaa8d5d7
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/src/index.d.ts +3 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces/IShellToolHost.d.ts +2 -1
- package/dist/src/tools/ast-edit/ast-edit-invocation.d.ts +3 -2
- package/dist/src/tools/ast-edit/ast-edit-invocation.js +38 -11
- package/dist/src/tools/ast-edit/ast-edit-invocation.js.map +1 -1
- package/dist/src/tools/ast-edit/ast-read-file-invocation.d.ts +2 -2
- package/dist/src/tools/ast-edit/ast-read-file-invocation.js.map +1 -1
- package/dist/src/tools/ast-edit/edit-calculator.d.ts +6 -3
- package/dist/src/tools/ast-edit/edit-calculator.js +24 -6
- package/dist/src/tools/ast-edit/edit-calculator.js.map +1 -1
- package/dist/src/tools/ast-edit/validation-categorizer.d.ts +58 -0
- package/dist/src/tools/ast-edit/validation-categorizer.js +207 -0
- package/dist/src/tools/ast-edit/validation-categorizer.js.map +1 -0
- package/dist/src/tools/codesearch.js.map +1 -1
- package/dist/src/tools/direct-web-fetch.js.map +1 -1
- package/dist/src/tools/exa-web-search.js.map +1 -1
- package/dist/src/tools/shell.d.ts +2 -2
- package/dist/src/tools/shell.js +17 -3
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/todo-pause.d.ts +2 -2
- package/dist/src/tools/todo-pause.js +1 -1
- package/dist/src/tools/todo-pause.js.map +1 -1
- package/dist/src/tools/todo-read.d.ts +2 -2
- package/dist/src/tools/todo-read.js +1 -1
- package/dist/src/tools/todo-read.js.map +1 -1
- package/dist/src/tools/todo-write.d.ts +2 -2
- package/dist/src/tools/todo-write.js +1 -1
- package/dist/src/tools/todo-write.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +3 -3
- package/dist/src/tools/tool-registry.js +6 -43
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tools.d.ts +6 -5
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/utils/fileUtils.js +8 -1
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/terminalSerializer.d.ts +12 -0
- package/package.json +151 -1
- package/src/index.ts +11 -0
- package/src/interfaces/IShellToolHost.ts +3 -1
- package/src/tools/ast-edit/ast-edit-invocation.ts +82 -12
- package/src/tools/ast-edit/ast-read-file-invocation.ts +2 -2
- package/src/tools/ast-edit/edit-calculator.ts +26 -6
- package/src/tools/ast-edit/validation-categorizer.ts +263 -0
- package/src/tools/codesearch.ts +2 -1
- package/src/tools/direct-web-fetch.ts +2 -1
- package/src/tools/exa-web-search.ts +2 -1
- package/src/tools/shell.ts +19 -6
- package/src/tools/todo-pause.ts +7 -2
- package/src/tools/todo-read.ts +7 -2
- package/src/tools/todo-write.ts +7 -2
- package/src/tools/tool-registry.ts +16 -82
- package/src/tools/tools.ts +10 -6
- package/src/utils/fileUtils.ts +11 -1
- package/src/utils/terminalSerializer.ts +9 -0
package/src/tools/shell.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type ToolCallConfirmationDetails,
|
|
24
24
|
type ToolExecuteConfirmationDetails,
|
|
25
25
|
type PolicyUpdateOptions,
|
|
26
|
+
type LiveOutputUpdate,
|
|
26
27
|
} from './tools.js';
|
|
27
28
|
import { ToolErrorType } from '../types/tool-error.js';
|
|
28
29
|
import { stringOrDefault } from '../utils/stringCoalescing.js';
|
|
@@ -184,7 +185,7 @@ export class ShellToolInvocation extends BaseToolInvocation<
|
|
|
184
185
|
|
|
185
186
|
async execute(
|
|
186
187
|
signal: AbortSignal,
|
|
187
|
-
updateOutput?: (
|
|
188
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
188
189
|
): Promise<ToolResult> {
|
|
189
190
|
this.validateFilterParams();
|
|
190
191
|
|
|
@@ -243,7 +244,7 @@ export class ShellToolInvocation extends BaseToolInvocation<
|
|
|
243
244
|
timeoutSeconds: number | undefined,
|
|
244
245
|
defaultTimeoutSeconds: number,
|
|
245
246
|
_timeoutId: ReturnType<typeof setTimeout> | null,
|
|
246
|
-
updateOutput?: (
|
|
247
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
247
248
|
): Promise<ToolResult> {
|
|
248
249
|
const combinedSignal = timeoutController.signal;
|
|
249
250
|
const cwd = this.resolveCwd();
|
|
@@ -340,7 +341,7 @@ export class ShellToolInvocation extends BaseToolInvocation<
|
|
|
340
341
|
}
|
|
341
342
|
|
|
342
343
|
private createOutputEventHandler(
|
|
343
|
-
updateOutput: ((
|
|
344
|
+
updateOutput: ((update: LiveOutputUpdate) => void) | undefined,
|
|
344
345
|
): (event: ShellOutputEvent) => void {
|
|
345
346
|
let cumulativeOutput = '';
|
|
346
347
|
let lastUpdateTime = 0;
|
|
@@ -353,8 +354,20 @@ export class ShellToolInvocation extends BaseToolInvocation<
|
|
|
353
354
|
switch (event.type) {
|
|
354
355
|
case 'data': {
|
|
355
356
|
if (isBinaryStream) break;
|
|
356
|
-
|
|
357
|
-
|
|
357
|
+
const chunk = event.chunk;
|
|
358
|
+
if (typeof chunk === 'string') {
|
|
359
|
+
cumulativeOutput = chunk;
|
|
360
|
+
shouldUpdate = true;
|
|
361
|
+
} else if (chunk !== undefined) {
|
|
362
|
+
// PTY terminal-buffer snapshot — replace semantics.
|
|
363
|
+
updateOutput({ mode: 'replace', data: chunk });
|
|
364
|
+
lastUpdateTime = Date.now();
|
|
365
|
+
} else {
|
|
366
|
+
// Preserve pre-migration behavior: an undefined chunk on a data
|
|
367
|
+
// event forwards the (empty) cumulative output as an append.
|
|
368
|
+
cumulativeOutput = '';
|
|
369
|
+
shouldUpdate = true;
|
|
370
|
+
}
|
|
358
371
|
break;
|
|
359
372
|
}
|
|
360
373
|
case 'binary_detected':
|
|
@@ -375,7 +388,7 @@ export class ShellToolInvocation extends BaseToolInvocation<
|
|
|
375
388
|
}
|
|
376
389
|
|
|
377
390
|
if (shouldUpdate) {
|
|
378
|
-
updateOutput(cumulativeOutput);
|
|
391
|
+
updateOutput({ mode: 'append', data: cumulativeOutput });
|
|
379
392
|
lastUpdateTime = Date.now();
|
|
380
393
|
}
|
|
381
394
|
};
|
package/src/tools/todo-pause.ts
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Type } from '../types/schema-type.js';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
BaseTool,
|
|
10
|
+
type ToolResult,
|
|
11
|
+
Kind,
|
|
12
|
+
type LiveOutputUpdate,
|
|
13
|
+
} from './tools.js';
|
|
9
14
|
import type { ITodoService } from '../interfaces/ITodoService.js';
|
|
10
15
|
import type { IToolHost } from '../interfaces/IToolHost.js';
|
|
11
16
|
import { EmojiFilter, isEmojiFilterMode } from '../utils/EmojiFilter.js';
|
|
@@ -118,7 +123,7 @@ export class TodoPause extends BaseTool<TodoPauseParams, ToolResult> {
|
|
|
118
123
|
async execute(
|
|
119
124
|
params: TodoPauseParams,
|
|
120
125
|
_signal: AbortSignal,
|
|
121
|
-
_updateOutput?: (
|
|
126
|
+
_updateOutput?: (update: LiveOutputUpdate) => void,
|
|
122
127
|
): Promise<ToolResult> {
|
|
123
128
|
const reasonResult = this.filterReason(params.reason);
|
|
124
129
|
if (reasonResult.blocked) {
|
package/src/tools/todo-read.ts
CHANGED
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
BaseTool,
|
|
9
|
+
type ToolResult,
|
|
10
|
+
Kind,
|
|
11
|
+
type LiveOutputUpdate,
|
|
12
|
+
} from './tools.js';
|
|
8
13
|
import { type Todo } from '../types/todo-schemas.js';
|
|
9
14
|
import { Type } from '../types/schema-type.js';
|
|
10
15
|
import { TodoReminderService } from '../utils/todoReminderService.js';
|
|
@@ -39,7 +44,7 @@ export class TodoRead extends BaseTool<TodoReadParams, ToolResult> {
|
|
|
39
44
|
async execute(
|
|
40
45
|
_params: TodoReadParams,
|
|
41
46
|
_signal: AbortSignal,
|
|
42
|
-
_updateOutput?: (
|
|
47
|
+
_updateOutput?: (update: LiveOutputUpdate) => void,
|
|
43
48
|
): Promise<ToolResult> {
|
|
44
49
|
// Get session and agent IDs from context
|
|
45
50
|
const sessionId = this.context?.sessionId ?? 'default';
|
package/src/tools/todo-write.ts
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Type } from '../types/schema-type.js';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
BaseTool,
|
|
10
|
+
type ToolResult,
|
|
11
|
+
Kind,
|
|
12
|
+
type LiveOutputUpdate,
|
|
13
|
+
} from './tools.js';
|
|
9
14
|
import { type Todo, TodoArraySchema } from '../types/todo-schemas.js';
|
|
10
15
|
import { DEFAULT_AGENT_ID } from './todo-store.js';
|
|
11
16
|
import { TodoReminderService } from '../utils/todoReminderService.js';
|
|
@@ -147,7 +152,7 @@ export class TodoWrite extends BaseTool<TodoWriteParams, ToolResult> {
|
|
|
147
152
|
async execute(
|
|
148
153
|
params: TodoWriteParams,
|
|
149
154
|
_signal: AbortSignal,
|
|
150
|
-
_updateOutput?: (
|
|
155
|
+
_updateOutput?: (update: LiveOutputUpdate) => void,
|
|
151
156
|
): Promise<ToolResult> {
|
|
152
157
|
const normalizedTodos = this.normalizeTodos(params.todos);
|
|
153
158
|
const validation = this.validateAndFilterTodos(normalizedTodos);
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
type ToolResult,
|
|
12
12
|
BaseTool,
|
|
13
13
|
BaseToolInvocation,
|
|
14
|
+
type LiveOutputUpdate,
|
|
14
15
|
} from './tools.js';
|
|
15
16
|
import { type ToolContext, isContextAwareTool } from '../types/tool-context.js';
|
|
16
17
|
import type { IToolRegistryHost } from '../interfaces/IToolRegistryHost.js';
|
|
@@ -22,6 +23,11 @@ import { ToolErrorType } from '../types/tool-error.js';
|
|
|
22
23
|
import { safeJsonStringify } from '../utils/safeJsonStringify.js';
|
|
23
24
|
import { debugLogger } from '../utils/debugLogger.js';
|
|
24
25
|
import { normalizeToolName } from '../formatters/toolNameUtils.js';
|
|
26
|
+
import {
|
|
27
|
+
buildToolGovernance,
|
|
28
|
+
isToolBlocked,
|
|
29
|
+
type ToolGovernance,
|
|
30
|
+
} from '../formatters/toolGovernanceUtils.js';
|
|
25
31
|
|
|
26
32
|
export const DISCOVERED_TOOL_PREFIX = 'discovered_tool_';
|
|
27
33
|
|
|
@@ -115,7 +121,7 @@ Signal: Signal number or \`(none)\` if no signal was received.
|
|
|
115
121
|
async execute(
|
|
116
122
|
params: ToolParams,
|
|
117
123
|
signal: AbortSignal,
|
|
118
|
-
_updateOutput?: (
|
|
124
|
+
_updateOutput?: (update: LiveOutputUpdate) => void,
|
|
119
125
|
): Promise<ToolResult> {
|
|
120
126
|
const callCommand = this.config.getToolCallCommand?.() ?? '';
|
|
121
127
|
const child = spawn(callCommand, [this.name]);
|
|
@@ -262,7 +268,7 @@ class DiscoveredToolInvocation extends BaseToolInvocation<
|
|
|
262
268
|
|
|
263
269
|
async execute(
|
|
264
270
|
signal: AbortSignal,
|
|
265
|
-
updateOutput?: (
|
|
271
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
266
272
|
): Promise<ToolResult> {
|
|
267
273
|
return this.tool.execute(this.params, signal, updateOutput);
|
|
268
274
|
}
|
|
@@ -287,70 +293,16 @@ export class ToolRegistry {
|
|
|
287
293
|
this.messageBus = messageBus;
|
|
288
294
|
}
|
|
289
295
|
|
|
290
|
-
private getToolGovernance(): {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
typeof this.config.getEphemeralSettings === 'function'
|
|
297
|
-
? (this.config.getEphemeralSettings() as
|
|
298
|
-
| Record<string, unknown>
|
|
299
|
-
| null
|
|
300
|
-
| undefined
|
|
301
|
-
| false
|
|
302
|
-
| 0
|
|
303
|
-
| '')
|
|
304
|
-
: undefined;
|
|
305
|
-
|
|
306
|
-
const ephemerals: Record<string, unknown> =
|
|
307
|
-
resolveEphemerals(rawEphemerals);
|
|
308
|
-
|
|
309
|
-
const allowedRaw = Array.isArray(ephemerals['tools.allowed'])
|
|
310
|
-
? (ephemerals['tools.allowed'] as string[])
|
|
311
|
-
: [];
|
|
312
|
-
|
|
313
|
-
function resolveDisabled(ephemeralsMap: Record<string, unknown>): string[] {
|
|
314
|
-
if (Array.isArray(ephemeralsMap['tools.disabled'])) {
|
|
315
|
-
return ephemeralsMap['tools.disabled'] as string[];
|
|
316
|
-
}
|
|
317
|
-
if (Array.isArray(ephemeralsMap['disabled-tools'])) {
|
|
318
|
-
return ephemeralsMap['disabled-tools'] as string[];
|
|
319
|
-
}
|
|
320
|
-
return [];
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const disabledRaw = resolveDisabled(ephemerals);
|
|
324
|
-
const excludedRaw = this.config.getExcludeTools?.() ?? [];
|
|
325
|
-
|
|
326
|
-
return {
|
|
327
|
-
allowed: new Set(
|
|
328
|
-
allowedRaw.map((name) => normalizeToolName(name) ?? name),
|
|
329
|
-
),
|
|
330
|
-
disabled: new Set(
|
|
331
|
-
disabledRaw.map((name) => normalizeToolName(name) ?? name),
|
|
332
|
-
),
|
|
333
|
-
excluded: new Set(
|
|
334
|
-
excludedRaw.map((name) => normalizeToolName(name) ?? name),
|
|
335
|
-
),
|
|
336
|
-
};
|
|
296
|
+
private getToolGovernance(): ToolGovernance {
|
|
297
|
+
return buildToolGovernance({
|
|
298
|
+
getEphemeralSettings: () =>
|
|
299
|
+
this.config.getEphemeralSettings?.() ?? undefined,
|
|
300
|
+
getExcludeTools: () => this.config.getExcludeTools?.(),
|
|
301
|
+
});
|
|
337
302
|
}
|
|
338
303
|
|
|
339
|
-
private isToolActive(
|
|
340
|
-
toolName
|
|
341
|
-
governance: ReturnType<ToolRegistry['getToolGovernance']>,
|
|
342
|
-
): boolean {
|
|
343
|
-
const canonical = normalizeToolName(toolName) ?? toolName;
|
|
344
|
-
if (governance.excluded.has(canonical)) {
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
347
|
-
if (governance.disabled.has(canonical)) {
|
|
348
|
-
return false;
|
|
349
|
-
}
|
|
350
|
-
if (governance.allowed.size > 0 && !governance.allowed.has(canonical)) {
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
|
-
return true;
|
|
304
|
+
private isToolActive(toolName: string, governance: ToolGovernance): boolean {
|
|
305
|
+
return !isToolBlocked(toolName, governance);
|
|
354
306
|
}
|
|
355
307
|
|
|
356
308
|
/**
|
|
@@ -818,21 +770,3 @@ export class ToolRegistry {
|
|
|
818
770
|
}
|
|
819
771
|
}
|
|
820
772
|
}
|
|
821
|
-
|
|
822
|
-
type EphemeralValue =
|
|
823
|
-
| Record<string, unknown>
|
|
824
|
-
| null
|
|
825
|
-
| undefined
|
|
826
|
-
| false
|
|
827
|
-
| 0
|
|
828
|
-
| '';
|
|
829
|
-
|
|
830
|
-
function resolveEphemerals(raw: EphemeralValue): Record<string, unknown> {
|
|
831
|
-
if (raw === null || raw === undefined || raw === false || raw === 0) {
|
|
832
|
-
return {};
|
|
833
|
-
}
|
|
834
|
-
if (raw === '') {
|
|
835
|
-
return {};
|
|
836
|
-
}
|
|
837
|
-
return raw;
|
|
838
|
-
}
|
package/src/tools/tools.ts
CHANGED
|
@@ -18,7 +18,10 @@ import {
|
|
|
18
18
|
} from '../interfaces/IToolMessageBus.js';
|
|
19
19
|
import type { DiffUpdateResult } from '../interfaces/IIdeService.js';
|
|
20
20
|
import { SchemaValidator } from '../utils/schemaValidator.js';
|
|
21
|
-
import type {
|
|
21
|
+
import type {
|
|
22
|
+
AnsiOutput,
|
|
23
|
+
LiveOutputUpdate,
|
|
24
|
+
} from '../utils/terminalSerializer.js';
|
|
22
25
|
import type { ContextAwareTool, ToolContext } from '../types/tool-context.js';
|
|
23
26
|
import {
|
|
24
27
|
ToolConfirmationOutcome,
|
|
@@ -28,6 +31,7 @@ import { ToolErrorType } from '../types/tool-error.js';
|
|
|
28
31
|
|
|
29
32
|
export { ToolConfirmationOutcome } from '../types/tool-confirmation-types.js';
|
|
30
33
|
export type { ToolConfirmationPayload } from '../types/tool-confirmation-types.js';
|
|
34
|
+
export type { LiveOutputUpdate } from '../utils/terminalSerializer.js';
|
|
31
35
|
|
|
32
36
|
/**
|
|
33
37
|
* Represents a validated and ready-to-execute tool call.
|
|
@@ -74,7 +78,7 @@ export interface ToolInvocation<
|
|
|
74
78
|
*/
|
|
75
79
|
execute(
|
|
76
80
|
signal: AbortSignal,
|
|
77
|
-
updateOutput?: (
|
|
81
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
78
82
|
terminalColumns?: number,
|
|
79
83
|
terminalRows?: number,
|
|
80
84
|
setPidCallback?: (pid: number) => void,
|
|
@@ -419,7 +423,7 @@ export abstract class BaseToolInvocation<
|
|
|
419
423
|
|
|
420
424
|
abstract execute(
|
|
421
425
|
signal: AbortSignal,
|
|
422
|
-
updateOutput?: (
|
|
426
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
423
427
|
terminalColumns?: number,
|
|
424
428
|
terminalRows?: number,
|
|
425
429
|
setPidCallback?: (pid: number) => void,
|
|
@@ -577,7 +581,7 @@ export abstract class DeclarativeTool<
|
|
|
577
581
|
async buildAndExecute(
|
|
578
582
|
params: TParams,
|
|
579
583
|
signal: AbortSignal,
|
|
580
|
-
updateOutput?: (
|
|
584
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
581
585
|
): Promise<TResult> {
|
|
582
586
|
const invocation = this.build(params);
|
|
583
587
|
return invocation.execute(signal, updateOutput);
|
|
@@ -1002,7 +1006,7 @@ export abstract class BaseTool<
|
|
|
1002
1006
|
abstract execute(
|
|
1003
1007
|
params: TParams,
|
|
1004
1008
|
signal: AbortSignal,
|
|
1005
|
-
updateOutput?: (
|
|
1009
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
1006
1010
|
): Promise<TResult>;
|
|
1007
1011
|
|
|
1008
1012
|
/**
|
|
@@ -1043,7 +1047,7 @@ class BaseToolLegacyInvocation<
|
|
|
1043
1047
|
|
|
1044
1048
|
async execute(
|
|
1045
1049
|
signal: AbortSignal,
|
|
1046
|
-
updateOutput?: (
|
|
1050
|
+
updateOutput?: (update: LiveOutputUpdate) => void,
|
|
1047
1051
|
_terminalColumns?: number,
|
|
1048
1052
|
_terminalRows?: number,
|
|
1049
1053
|
_setPidCallback?: (pid: number) => void,
|
package/src/utils/fileUtils.ts
CHANGED
|
@@ -222,8 +222,18 @@ export async function detectFileType(
|
|
|
222
222
|
return 'svg';
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
// mime-db maps the FreeHand family (.fh, .fh4, .fh5, .fh7, .fhc) to
|
|
226
|
+
// image/x-freehand, but these extensions are commonly shader/source text.
|
|
227
|
+
// Exclude them from the image short-circuit below so they fall through to
|
|
228
|
+
// content-based detection (text or binary).
|
|
229
|
+
const freehandExtensions = ['.fh', '.fh4', '.fh5', '.fh7', '.fhc'];
|
|
230
|
+
|
|
225
231
|
const lookedUpMimeType = mime.lookup(filePath);
|
|
226
|
-
if (
|
|
232
|
+
if (
|
|
233
|
+
typeof lookedUpMimeType === 'string' &&
|
|
234
|
+
lookedUpMimeType !== '' &&
|
|
235
|
+
!freehandExtensions.includes(ext)
|
|
236
|
+
) {
|
|
227
237
|
if (lookedUpMimeType.startsWith('image/')) return 'image';
|
|
228
238
|
if (lookedUpMimeType.startsWith('audio/')) return 'audio';
|
|
229
239
|
if (lookedUpMimeType.startsWith('video/')) return 'video';
|
|
@@ -35,3 +35,12 @@ export interface AnsiToken {
|
|
|
35
35
|
|
|
36
36
|
export type AnsiLine = AnsiToken[];
|
|
37
37
|
export type AnsiOutput = AnsiLine[];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Explicit tagged update protocol for live-output streaming. Discriminated
|
|
41
|
+
* by `mode`: text stream producers emit `append` (incremental deltas);
|
|
42
|
+
* terminal-buffer producers emit `replace` (full snapshots).
|
|
43
|
+
*/
|
|
44
|
+
export type LiveOutputUpdate =
|
|
45
|
+
| { mode: 'append'; data: string }
|
|
46
|
+
| { mode: 'replace'; data: AnsiOutput };
|