@itookit/dsht 0.2.1 → 0.2.4
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/README.i18n.yaml +2 -2
- package/README.md +47 -26
- package/README.zh.md +47 -26
- package/dist/app.d.ts +16 -1
- package/dist/app.js +450 -73
- package/dist/cli.js +6 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.js +3 -0
- package/dist/controller.d.ts +80 -3
- package/dist/controller.js +350 -75
- package/dist/cost-view.js +3 -1
- package/dist/history-view.d.ts +8 -0
- package/dist/history-view.js +12 -0
- package/dist/history.d.ts +29 -12
- package/dist/history.js +172 -27
- package/dist/input-history.d.ts +19 -0
- package/dist/input-history.js +43 -0
- package/dist/input.d.ts +3 -1
- package/dist/input.js +3 -1
- package/dist/memory.d.ts +13 -0
- package/dist/memory.js +22 -0
- package/dist/mouse.d.ts +3 -1
- package/dist/mouse.js +15 -4
- package/dist/navigation.d.ts +1 -1
- package/dist/navigation.js +2 -2
- package/dist/status.d.ts +3 -1
- package/dist/status.js +63 -42
- package/dist/telemetry.d.ts +3 -0
- package/dist/telemetry.js +9 -0
- package/dist/theme.d.ts +15 -0
- package/dist/theme.js +15 -0
- package/dist/transcript.d.ts +91 -6
- package/dist/transcript.js +393 -49
- package/dsht.png +0 -0
- package/package.json +4 -2
package/dist/status.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/** Terminal status from host projections; cumulative usage and estimated context stay distinct. */
|
|
3
|
+
import { useTheme } from "./theme.js";
|
|
3
4
|
import { memo, useEffect, useState } from 'react';
|
|
4
5
|
import { Box, Text, useStdout } from 'ink';
|
|
5
6
|
import wrapAnsi from 'wrap-ansi';
|
|
6
7
|
import { costText } from "./cost.js";
|
|
8
|
+
import { toolLine } from "./transcript.js";
|
|
7
9
|
import { safeText } from "./wire.js";
|
|
8
10
|
/** Format elapsed wall time, clamping clock skew instead of displaying negative durations.
|
|
9
11
|
* @param milliseconds - Elapsed duration.
|
|
@@ -12,6 +14,8 @@ import { safeText } from "./wire.js";
|
|
|
12
14
|
export function elapsedTime(milliseconds) {
|
|
13
15
|
const seconds = Math.max(0, Math.floor(milliseconds / 1000));
|
|
14
16
|
const minutes = Math.floor(seconds / 60);
|
|
17
|
+
if (minutes === 0)
|
|
18
|
+
return `${seconds}s`;
|
|
15
19
|
return `${minutes >= 60 ? `${Math.floor(minutes / 60)}h ` : ''}${minutes % 60}m ${seconds % 60}s`;
|
|
16
20
|
}
|
|
17
21
|
/** Produce compact metadata lines without inferring missing provider measurements.
|
|
@@ -41,47 +45,55 @@ export function metricLines(values, defaultModel, running) {
|
|
|
41
45
|
];
|
|
42
46
|
}
|
|
43
47
|
/** Fit the status summary to one terminal row; details remain available through /status.
|
|
44
|
-
* @param fields -
|
|
48
|
+
* @param fields - Activity, model, cost, context, and cumulative usage groups in display order.
|
|
45
49
|
* @param width - Available terminal columns.
|
|
46
50
|
* @returns A terminal-safe single line, shortened by display width.
|
|
47
51
|
*/
|
|
48
52
|
export function compactStatus(fields, width) {
|
|
53
|
+
return compactStatusFields(fields, width).filter(Boolean).join(' ');
|
|
54
|
+
}
|
|
55
|
+
/** Keep group identities while fitting plain text; ANSI styling is applied only after layout. */
|
|
56
|
+
function compactStatusFields(fields, width) {
|
|
57
|
+
if (width <= 0)
|
|
58
|
+
return [];
|
|
49
59
|
const clean = fields.map(value => safeText(value).replace(/[\r\n\t]/g, ' '));
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
const join = () => clean.filter(Boolean).join(' ');
|
|
61
|
+
const fits = () => !wrapAnsi(join(), width, { hard: true, wordWrap: false, trim: false }).includes('\n');
|
|
62
|
+
if (fits())
|
|
63
|
+
return clean;
|
|
64
|
+
// Keep the stable activity column while it fits; reclaim it on narrow terminals.
|
|
65
|
+
clean[0] = clean[0]?.trimEnd() ?? '';
|
|
66
|
+
if (fits())
|
|
67
|
+
return clean;
|
|
68
|
+
clean[3] = (clean[3] ?? '').replace(/[█░]+ /u, '');
|
|
69
|
+
if (fits())
|
|
70
|
+
return clean;
|
|
71
|
+
clean[1] = toolLine(clean[1] ?? '', Math.max(8, Math.min(24, Math.floor(width / 4))));
|
|
72
|
+
if (fits())
|
|
73
|
+
return clean;
|
|
74
|
+
for (const index of [4, 2, 1, 3]) {
|
|
75
|
+
clean[index] = '';
|
|
76
|
+
if (fits())
|
|
77
|
+
return clean;
|
|
66
78
|
}
|
|
67
|
-
|
|
68
|
-
while (extras.length && !fits(joins([...core, ...extras])))
|
|
69
|
-
extras.pop();
|
|
70
|
-
return fit(joins([...core, ...extras]), width);
|
|
79
|
+
return [toolLine(join(), width)];
|
|
71
80
|
}
|
|
81
|
+
/** Compact token counts; one formatter is reused because construction dominates the format cost. */
|
|
82
|
+
const compactNumber = new Intl.NumberFormat('en', { notation: 'compact', maximumFractionDigits: 1 });
|
|
72
83
|
/** Render a live clock and selected-session metadata; the timer belongs to this mounted bar. */
|
|
73
|
-
export const StatusBar = memo(function StatusBar({ controller, expanded = false }) {
|
|
84
|
+
export const StatusBar = memo(function StatusBar({ controller, expanded = false, width, paused = false }) {
|
|
85
|
+
const theme = useTheme();
|
|
74
86
|
const { stdout } = useStdout();
|
|
75
87
|
const [now, setNow] = useState(Date.now);
|
|
76
88
|
const running = controller.running;
|
|
77
89
|
const since = controller.workingSince;
|
|
78
90
|
useEffect(() => {
|
|
79
91
|
setNow(Date.now());
|
|
80
|
-
if (!running)
|
|
92
|
+
if (!running || paused)
|
|
81
93
|
return;
|
|
82
94
|
const timer = setInterval(() => setNow(Date.now()), 1000);
|
|
83
95
|
return () => clearInterval(timer);
|
|
84
|
-
}, [running, since]);
|
|
96
|
+
}, [running, since, paused]);
|
|
85
97
|
const state = controller.state;
|
|
86
98
|
const workspace = state.workspaces.find(item => item.workspaceId === state.workspaceId);
|
|
87
99
|
const view = controller.telemetry.view(state.sessionId);
|
|
@@ -94,32 +106,38 @@ export const StatusBar = memo(function StatusBar({ controller, expanded = false
|
|
|
94
106
|
if (!expanded) {
|
|
95
107
|
const selection = record(view.values.modelSelection);
|
|
96
108
|
const route = record(running ? selection.lastUsed ?? selection.next ?? state.defaultModel : selection.next ?? selection.lastUsed ?? state.defaultModel);
|
|
97
|
-
const model = typeof route.model === 'string' ? `${route.model}${typeof route.reasoningEffort === 'string' ? `
|
|
109
|
+
const model = typeof route.model === 'string' ? `${route.model.replace(/^deepseek-/, '')}${typeof route.reasoningEffort === 'string' ? ` · ${route.reasoningEffort}` : ''}` : 'model ?';
|
|
98
110
|
const pressure = record(view.values.contextPressure);
|
|
99
111
|
const used = numeric(pressure.projectedTokens) ?? numeric(pressure.pressureTokens);
|
|
100
112
|
const capacity = numeric(pressure.contextWindow);
|
|
113
|
+
const percent = used !== undefined && capacity !== undefined && capacity > 0 ? Math.min(100, Math.round(used / capacity * 100)) : undefined;
|
|
114
|
+
const filled = percent === undefined ? 0 : Math.round(percent / 10);
|
|
115
|
+
const context = percent === undefined ? 'ctx ?' : `${'█'.repeat(filled)}${'░'.repeat(10 - filled)} ~${percent}%`;
|
|
101
116
|
const usage = record(view.values.tokenUsage);
|
|
102
117
|
const buckets = [usage.uncachedInputTokens, usage.outputTokens, usage.cacheReadTokens, usage.cacheWriteTokens].map(numeric);
|
|
103
118
|
const total = buckets.every(value => value !== undefined) ? buckets.reduce((a, b) => a + b, 0) : undefined;
|
|
104
|
-
const compactCount = (value) => value === undefined ? '?' :
|
|
105
|
-
const activity = running ?
|
|
119
|
+
const compactCount = (value) => value === undefined ? '?' : compactNumber.format(value);
|
|
120
|
+
const activity = running ? `◐ Working · ${since === undefined ? '?' : elapsedTime(now - since)}${state.transcript.activeTurnStartedAt === undefined ? '~' : ''} · Ctrl+C Stop` : '● Ready';
|
|
121
|
+
const warning = state.controlError || state.modelError || coverage === 'partial' ? '! ' : '';
|
|
106
122
|
const fields = [
|
|
107
|
-
`${!state.online ? 'Offline · ' : ''}${
|
|
108
|
-
model,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
123
|
+
`${warning}${!state.online ? 'Offline · ' : ''}${activity}`.padEnd(31),
|
|
124
|
+
model,
|
|
125
|
+
costs ? `${costs.hasSession(state.sessionId) ? compactCost(costs.total(state.sessionId)) : '?'}/${compactCost(costs.total(undefined, 1, Date.now()))}` : '?/?',
|
|
126
|
+
context,
|
|
127
|
+
`${count(numeric(record(view.values.sessionStats).turns))} turns · ${compactCount(total)} tok`,
|
|
128
|
+
];
|
|
129
|
+
const fitted = compactStatusFields(fields, width ?? Math.max(1, (stdout.columns ?? 80) - 2));
|
|
130
|
+
const colors = [
|
|
131
|
+
!state.online ? theme.status.offline : warning ? theme.status.warning : running ? theme.status.working : theme.status.ready,
|
|
132
|
+
theme.status.model, costs ? theme.status.cost : theme.status.usage,
|
|
133
|
+
percent === undefined ? theme.status.usage : percent >= 95 ? theme.status.critical : percent >= 80 ? theme.status.warning : theme.status.context,
|
|
134
|
+
theme.status.usage,
|
|
115
135
|
];
|
|
116
|
-
|
|
117
|
-
const fee = costs ? ` · S:${sessionCost} D:${todayCost}` : '';
|
|
118
|
-
return _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [compactStatus(fields, Math.max(1, width - fee.length)), fee] });
|
|
136
|
+
return _jsx(Text, { wrap: "truncate-end", children: fitted.map((text, index) => text ? _jsxs(Text, { children: [fitted.slice(0, index).some(Boolean) && _jsx(Text, { color: theme.colors.muted, children: ' ' }), _jsx(Text, { color: colors[index], bold: index === 0, children: text })] }, index) : null) });
|
|
119
137
|
}
|
|
120
|
-
return _jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor:
|
|
121
|
-
?
|
|
122
|
-
: '
|
|
138
|
+
return _jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.border, paddingX: 1, children: [_jsxs(Text, { color: running ? theme.colors.context : theme.colors.muted, children: [running
|
|
139
|
+
? `◐ Working · ${since === undefined ? 'unknown duration' : elapsedTime(now - since)}${state.transcript.activeTurnStartedAt === undefined ? ' (observed)' : ''} · Ctrl+C Stop`
|
|
140
|
+
: '● Ready · Ctrl+C exit', !state.online ? ' · disconnected, last known status' : ''] }), _jsxs(Text, { wrap: "truncate-end", children: ["Host: ", safeText(controller.base), " \u00B7 ", safeText(state.status)] }), state.sessionId && _jsxs(Text, { children: ["Session ID: ", safeText(state.sessionId)] }), controller.sessionMode && _jsxs(Text, { children: ["Mode: ", safeText(controller.sessionMode)] }), _jsxs(Text, { wrap: "truncate-end", children: ["Workspace: ", safeText(label)] }), metricLines(view.values, state.defaultModel, running).map((line, index) => _jsx(Text, { dimColor: true, children: safeText(line) }, index)), costs && _jsxs(Text, { dimColor: true, children: ["Cost (CNY estimate): Session ", sessionCost, " \u00B7 Today ", todayCost] }), costs && coverage === 'partial' && _jsxs(Text, { color: theme.colors.context, children: ["Cost coverage incomplete: ", costs.error ? safeText(costs.error) : 'no complete scan yet'] }), _jsxs(Text, { dimColor: true, children: ["Turns: ", count(numeric(record(view.values.sessionStats).turns))] }), _jsxs(Text, { dimColor: true, children: ["Queued: ", count(view.queued), " \u00B7 Active jobs: ", count(view.jobs)] }), state.controlError && _jsx(Text, { color: theme.colors.context, children: safeText(state.controlError) }), state.presetError && _jsxs(Text, { color: theme.colors.context, children: ["Preset names unavailable: ", safeText(state.presetError)] }), state.modelError && _jsxs(Text, { color: theme.colors.context, children: ["Model catalog unavailable: ", safeText(state.modelError)] })] });
|
|
123
141
|
});
|
|
124
142
|
function record(value) {
|
|
125
143
|
return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
@@ -134,3 +152,6 @@ function modelName(value) {
|
|
|
134
152
|
return 'unknown';
|
|
135
153
|
return safeText(`${model.provider}/${model.model}${typeof model.reasoningEffort === 'string' ? ` (${model.reasoningEffort})` : ''}`);
|
|
136
154
|
}
|
|
155
|
+
function compactCost(total) {
|
|
156
|
+
return `~¥${total.amount.toFixed(2)}${total.unknown || total.estimated ? '*' : ''}`;
|
|
157
|
+
}
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
import { type ObjectValue } from './wire.ts';
|
|
3
3
|
/** Generation-local projection, inbox and background-job data for every session. */
|
|
4
4
|
export declare class Telemetry {
|
|
5
|
+
private readonly retainedKeys?;
|
|
5
6
|
private entries;
|
|
6
7
|
private queues;
|
|
7
8
|
private jobs;
|
|
8
9
|
ready: boolean;
|
|
10
|
+
/** Optionally retain only projection capabilities consumed by this client. */
|
|
11
|
+
constructor(retainedKeys?: ReadonlySet<string> | undefined);
|
|
9
12
|
/** Replace all control state on a new stream baseline, then accept replacement frames.
|
|
10
13
|
* @param value - One decoded session/control frame.
|
|
11
14
|
*/
|
package/dist/telemetry.js
CHANGED
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
import { array, object, string } from "./wire.js";
|
|
3
3
|
/** Generation-local projection, inbox and background-job data for every session. */
|
|
4
4
|
export class Telemetry {
|
|
5
|
+
retainedKeys;
|
|
5
6
|
entries = new Map();
|
|
6
7
|
queues = new Map();
|
|
7
8
|
jobs = new Map();
|
|
8
9
|
ready = false;
|
|
10
|
+
/** Optionally retain only projection capabilities consumed by this client. */
|
|
11
|
+
constructor(retainedKeys) {
|
|
12
|
+
this.retainedKeys = retainedKeys;
|
|
13
|
+
}
|
|
9
14
|
/** Replace all control state on a new stream baseline, then accept replacement frames.
|
|
10
15
|
* @param value - One decoded session/control frame.
|
|
11
16
|
*/
|
|
@@ -36,6 +41,8 @@ export class Telemetry {
|
|
|
36
41
|
return;
|
|
37
42
|
if (frame.value === undefined)
|
|
38
43
|
throw new Error('Missing projection value');
|
|
44
|
+
if (this.retainedKeys && !this.retainedKeys.has(key))
|
|
45
|
+
return;
|
|
39
46
|
entry.values[key] = frame.value;
|
|
40
47
|
entry.revisions.set(key, seq);
|
|
41
48
|
}
|
|
@@ -60,6 +67,8 @@ export class Telemetry {
|
|
|
60
67
|
if (seq < entry.baseline)
|
|
61
68
|
return;
|
|
62
69
|
for (const key of new Set([...Object.keys(entry.values), ...Object.keys(values)])) {
|
|
70
|
+
if (this.retainedKeys && !this.retainedKeys.has(key))
|
|
71
|
+
continue;
|
|
63
72
|
if ((entry.revisions.get(key) ?? -1) > seq)
|
|
64
73
|
continue;
|
|
65
74
|
if (Object.hasOwn(values, key))
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RowKind } from './history.ts';
|
|
2
|
+
/** Themes provide semantic roles so components never depend on palette-specific color names. */
|
|
3
|
+
export interface Theme {
|
|
4
|
+
name: string;
|
|
5
|
+
colors: Record<RowKind, string>;
|
|
6
|
+
status: Record<'working' | 'ready' | 'offline' | 'model' | 'cost' | 'context' | 'warning' | 'critical' | 'usage', string>;
|
|
7
|
+
accent: string;
|
|
8
|
+
border: string;
|
|
9
|
+
}
|
|
10
|
+
/** Catppuccin Mocha, preserving the terminal background and its color-capability fallback. */
|
|
11
|
+
export declare const mocha: Theme;
|
|
12
|
+
/** Components read semantic colors from the current application theme. */
|
|
13
|
+
export declare const ThemeContext: import("react").Context<Theme>;
|
|
14
|
+
/** Return the theme selected by the surrounding application provider. */
|
|
15
|
+
export declare function useTheme(): Theme;
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Semantic terminal palette. Source: https://catppuccin.com/palette/ (Mocha). */
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
/** Catppuccin Mocha, preserving the terminal background and its color-capability fallback. */
|
|
4
|
+
export const mocha = {
|
|
5
|
+
name: 'Catppuccin Mocha',
|
|
6
|
+
colors: { user: '#89b4fa', assistant: '#a6e3a1', context: '#f9e2af', text: '#cdd6f4',
|
|
7
|
+
reasoning: '#cba6f7', tool: '#89dceb', success: '#a6e3a1', error: '#f38ba8', muted: '#a6adc8' },
|
|
8
|
+
status: { working: '#f9e2af', ready: '#a6e3a1', offline: '#f38ba8', model: '#cba6f7',
|
|
9
|
+
cost: '#89dceb', context: '#a6e3a1', warning: '#f9e2af', critical: '#f38ba8', usage: '#a6adc8' },
|
|
10
|
+
accent: '#cba6f7', border: '#6c7086',
|
|
11
|
+
};
|
|
12
|
+
/** Components read semantic colors from the current application theme. */
|
|
13
|
+
export const ThemeContext = createContext(mocha);
|
|
14
|
+
/** Return the theme selected by the surrounding application provider. */
|
|
15
|
+
export function useTheme() { return useContext(ThemeContext); }
|
package/dist/transcript.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { HistoryLimits } from './memory.ts';
|
|
1
2
|
import { type Json } from './wire.ts';
|
|
2
3
|
interface ToolSummary {
|
|
3
4
|
name: string;
|
|
4
5
|
operation?: string;
|
|
6
|
+
command?: string;
|
|
5
7
|
}
|
|
6
8
|
/** Fit a tool operation to one terminal row without exposing the result body.
|
|
7
9
|
* @param text - Tool name, status icon and optional operation.
|
|
@@ -9,23 +11,69 @@ interface ToolSummary {
|
|
|
9
11
|
* @returns A single line with an ellipsis when shortened.
|
|
10
12
|
*/
|
|
11
13
|
export declare function toolLine(text: string, width: number): string;
|
|
12
|
-
/** Render known content blocks and preserve unknown plugin blocks as JSON.
|
|
13
|
-
|
|
14
|
+
/** Render known content blocks and preserve unknown plugin blocks as JSON.
|
|
15
|
+
* @param content - Message content blocks.
|
|
16
|
+
* @param tools - Tool summaries by call ID, when retained history provides them.
|
|
17
|
+
* @param width - Available terminal columns.
|
|
18
|
+
* @param reasoning - `full` keeps streamed reasoning at length; `row` folds a committed block into one row.
|
|
19
|
+
* @returns Blocks joined by newlines.
|
|
20
|
+
*/
|
|
21
|
+
export declare function contentText(content: Json | undefined, tools?: ReadonlyMap<string, ToolSummary>, width?: number, reasoning?: 'row' | 'full'): string;
|
|
22
|
+
/** Semantic content stays separate from terminal rows, styles, and fold state. */
|
|
23
|
+
export interface MessagePart {
|
|
24
|
+
kind: 'text' | 'reasoning' | 'tool' | 'success' | 'error';
|
|
25
|
+
text: string;
|
|
26
|
+
/** Closed live reasoning can fold before the assistant message is committed. */
|
|
27
|
+
closed?: boolean;
|
|
28
|
+
}
|
|
14
29
|
/** A displayed message retains the durable sequence for stable reconciliation. */
|
|
15
30
|
export interface Message {
|
|
16
31
|
seq: number;
|
|
17
32
|
role: string;
|
|
18
33
|
text: string;
|
|
34
|
+
parts: MessagePart[];
|
|
19
35
|
compact?: boolean;
|
|
36
|
+
/** One-row rendering of committed reasoning, used only while the conversation folds reasoning. */
|
|
37
|
+
folded?: string;
|
|
38
|
+
}
|
|
39
|
+
/** Lightweight reasoning navigation row; summaries never contain a copy of the full thought. */
|
|
40
|
+
export interface ThoughtEntry {
|
|
41
|
+
seq: number;
|
|
42
|
+
promptSeq?: number;
|
|
43
|
+
prompt: string;
|
|
44
|
+
preview: string;
|
|
20
45
|
}
|
|
21
46
|
/** Opening snapshots replace all state; durable events are deduplicated by sequence. */
|
|
22
47
|
export declare class Transcript {
|
|
48
|
+
private sizes;
|
|
49
|
+
private storedBytes;
|
|
50
|
+
private throughSeq;
|
|
51
|
+
private promptBeforeWindow;
|
|
52
|
+
private disposed;
|
|
53
|
+
/** Increments when cached bodies are evicted, so view state can drop obsolete references. */
|
|
54
|
+
memoryRevision: number;
|
|
55
|
+
private transientSeqs;
|
|
23
56
|
private events;
|
|
24
57
|
private blocks;
|
|
58
|
+
private thoughtIndex;
|
|
59
|
+
private liveProjection;
|
|
60
|
+
private closedBlocks;
|
|
61
|
+
private oldestSeq;
|
|
62
|
+
private turnMarker;
|
|
25
63
|
private attempt;
|
|
26
64
|
private nextIndex;
|
|
27
65
|
private revision;
|
|
28
66
|
private legacyStream;
|
|
67
|
+
private keysDirty;
|
|
68
|
+
private sortedSeqs;
|
|
69
|
+
private projectionRevision;
|
|
70
|
+
private projection;
|
|
71
|
+
private displaySeqsRevision;
|
|
72
|
+
private displayed;
|
|
73
|
+
private displayedMessages;
|
|
74
|
+
private legacyDirty;
|
|
75
|
+
private legacyPosition;
|
|
76
|
+
private legacySeq;
|
|
29
77
|
/** Changes whenever a follow frame or older page can affect the rendered transcript. */
|
|
30
78
|
version: number;
|
|
31
79
|
cursor: number;
|
|
@@ -35,19 +83,49 @@ export declare class Transcript {
|
|
|
35
83
|
accept(value: unknown): void;
|
|
36
84
|
/** Add an older page without replacing the live tail. */
|
|
37
85
|
addPage(value: unknown): void;
|
|
86
|
+
/** Durable read cutoff includes followed records that were not present in the opening snapshot. */
|
|
87
|
+
get readThrough(): number;
|
|
88
|
+
/** Estimated UTF-16 JSON payload bytes; excludes object overhead and unfinished stream blocks. */
|
|
89
|
+
get retainedBytes(): number;
|
|
90
|
+
/** Release reloadable prefix records with hysteresis, retaining a recent tail and active legacy chunks.
|
|
91
|
+
* @param limits - Soft record and payload budgets; callers suspend this operation while reading history.
|
|
92
|
+
* @returns Number of removed records. Paging remains possible at the advanced durable cutoff.
|
|
93
|
+
*/
|
|
94
|
+
trimHistory(limits: HistoryLimits): number;
|
|
95
|
+
/** Empty an inactive session immediately; late frames cannot repopulate a disposed transcript. */
|
|
96
|
+
dispose(): void;
|
|
97
|
+
private dropProjections;
|
|
98
|
+
private storeEvent;
|
|
99
|
+
private deleteEvent;
|
|
38
100
|
/** Start of the open durable turn, when its timestamp is present in the retained window. */
|
|
39
101
|
get activeTurnStartedAt(): number | undefined;
|
|
40
|
-
/**
|
|
102
|
+
/** Cached prompt/reasoning summaries, oldest first; stream deltas never invalidate this index. */
|
|
103
|
+
get thoughts(): ThoughtEntry[];
|
|
104
|
+
/** Latest loaded user prompt summary, sharing the durable thought index. */
|
|
105
|
+
get latestPrompt(): string;
|
|
106
|
+
/** Number of semantic records and unfinished legacy chunks held by the client. */
|
|
107
|
+
get retainedRecordCount(): number;
|
|
108
|
+
/** Earliest loaded record, used with the opening cursor for backward paging. */
|
|
41
109
|
get beforeSeq(): number | undefined;
|
|
110
|
+
/** Retained sequences in ascending order; resorted only when a retained event changes. */
|
|
111
|
+
private sortedKeys;
|
|
112
|
+
/** Sequences of the event types that contribute a displayed message. */
|
|
113
|
+
private displaySeqs;
|
|
42
114
|
/** Return append-origin conversation only; model-only replacement copies stay hidden. */
|
|
43
115
|
get messages(): Message[];
|
|
44
116
|
/** Project history with single-row tool operations at the caller's terminal width.
|
|
45
117
|
* @param width - Available terminal columns.
|
|
46
|
-
* @returns Conversation messages with compact tool-only rows.
|
|
118
|
+
* @returns Conversation messages with compact tool-only rows; the array is shared and must not be mutated.
|
|
47
119
|
*/
|
|
48
120
|
messagesForWidth(width: number): Message[];
|
|
121
|
+
/** Build the message list, reusing each unchanged event's earlier projection at the same width. */
|
|
122
|
+
private project;
|
|
49
123
|
/** Text from the active attempt is transient and never duplicated into durable history. */
|
|
50
124
|
get liveText(): string;
|
|
125
|
+
/** Attempt identity resets the view's live fold preference between responses. */
|
|
126
|
+
get liveAttemptKey(): string | undefined;
|
|
127
|
+
/** Whether an active attempt has content, without joining its potentially long reasoning. */
|
|
128
|
+
get hasLiveContent(): boolean;
|
|
51
129
|
/** Whether the active stream contains only tool operations, with no assistant prose. */
|
|
52
130
|
get liveToolOnly(): boolean;
|
|
53
131
|
/** Render live tool operations within a terminal row.
|
|
@@ -55,9 +133,16 @@ export declare class Transcript {
|
|
|
55
133
|
* @returns Transient assistant text with clipped tool rows.
|
|
56
134
|
*/
|
|
57
135
|
liveTextForWidth(width: number): string;
|
|
136
|
+
/** Live semantic blocks; completed reasoning folds independently of the unfinished answer.
|
|
137
|
+
* @param width - Terminal width used for compact tool summaries.
|
|
138
|
+
* @returns Ordered blocks without terminal style escapes.
|
|
139
|
+
*/
|
|
140
|
+
liveParts(width: number): MessagePart[];
|
|
58
141
|
private addRecords;
|
|
59
|
-
/** Older hosts log chunks directly;
|
|
60
|
-
|
|
142
|
+
/** Older hosts log chunks directly; fold the unfinished attempt into the live tail for display.
|
|
143
|
+
* A page behind the folded position, or a replaced event, forces a full re-fold; streamed chunks extend it.
|
|
144
|
+
*/
|
|
145
|
+
private foldLegacy;
|
|
61
146
|
private validatePackedTiming;
|
|
62
147
|
private chunk;
|
|
63
148
|
}
|