praxis-agent 0.35.0 → 0.37.0
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.md +20 -2
- package/dist/application/background-agent-manager.d.ts +16 -6
- package/dist/application/background-agent-manager.js +139 -97
- package/dist/application/context-engine.d.ts +56 -0
- package/dist/application/context-engine.js +129 -0
- package/dist/application/durable-follow-up.d.ts +14 -0
- package/dist/application/durable-follow-up.js +52 -0
- package/dist/application/native-session-transcript.d.ts +72 -0
- package/dist/application/native-session-transcript.js +351 -0
- package/dist/application/native-sidechain-transcript.d.ts +34 -0
- package/dist/application/native-sidechain-transcript.js +156 -0
- package/dist/application/session-service.d.ts +23 -4
- package/dist/application/session-service.js +1130 -494
- package/dist/application/subagent-service.d.ts +5 -1
- package/dist/application/subagent-service.js +749 -320
- package/dist/application/team-agent-runtime.d.ts +29 -0
- package/dist/application/team-agent-runtime.js +169 -0
- package/dist/application/team-capability.d.ts +27 -0
- package/dist/application/team-capability.js +41 -0
- package/dist/application/team-lead-operations.d.ts +38 -0
- package/dist/application/team-lead-operations.js +155 -0
- package/dist/application/team-mailbox.d.ts +54 -0
- package/dist/application/team-mailbox.js +196 -0
- package/dist/application/team-manager.d.ts +113 -0
- package/dist/application/team-manager.js +681 -0
- package/dist/application/team-workspace.d.ts +29 -0
- package/dist/application/team-workspace.js +197 -0
- package/dist/application/top-level-agent-manager.d.ts +1 -0
- package/dist/application/top-level-agent-manager.js +1025 -403
- package/dist/application/transcript-projection.d.ts +35 -0
- package/dist/application/transcript-projection.js +139 -0
- package/dist/application/turn-lifecycle.d.ts +2 -0
- package/dist/application/turn-memory-coordinator.d.ts +43 -0
- package/dist/application/turn-memory-coordinator.js +98 -0
- package/dist/cli/agents-dashboard.js +10 -5
- package/dist/cli/interactive.d.ts +7 -0
- package/dist/cli/interactive.js +645 -334
- package/dist/cli/tui/claude-style.d.ts +8 -25
- package/dist/cli/tui/claude-style.js +299 -277
- package/dist/cli/tui/decision-surface-model.d.ts +71 -0
- package/dist/cli/tui/decision-surface-model.js +131 -0
- package/dist/cli/tui/decision-surface.d.ts +7 -0
- package/dist/cli/tui/decision-surface.js +41 -0
- package/dist/cli/tui/help-surface-model.d.ts +68 -0
- package/dist/cli/tui/help-surface-model.js +131 -0
- package/dist/cli/tui/mcp-panel.js +1 -2
- package/dist/cli/tui/permission-surface-model.d.ts +195 -0
- package/dist/cli/tui/permission-surface-model.js +360 -0
- package/dist/cli/tui/permission-surface.d.ts +7 -0
- package/dist/cli/tui/permission-surface.js +69 -0
- package/dist/cli/tui/presentation-environment.d.ts +32 -0
- package/dist/cli/tui/presentation-environment.js +149 -0
- package/dist/cli/tui/task-panel.js +10 -1
- package/dist/cli/tui/theme.d.ts +46 -3
- package/dist/cli/tui/theme.js +414 -56
- package/dist/cli/tui/tool-permission.js +16 -8
- package/dist/cli/tui/transcript-presentation.d.ts +19 -1
- package/dist/cli/tui/transcript-presentation.js +26 -6
- package/dist/cli/tui/transcript-viewport.d.ts +18 -0
- package/dist/cli/tui/transcript-viewport.js +517 -111
- package/dist/cli/tui/transcript-window-model.d.ts +108 -0
- package/dist/cli/tui/transcript-window-model.js +772 -0
- package/dist/cli/tui/tui-interaction-router.d.ts +78 -0
- package/dist/cli/tui/tui-interaction-router.js +127 -0
- package/dist/cli/tui/tui-screen-model.d.ts +114 -0
- package/dist/cli/tui/tui-screen-model.js +210 -0
- package/dist/cli/tui/tui-view-model.d.ts +2 -49
- package/dist/cli/tui/tui-view-model.js +1 -68
- package/dist/cli-runtime.d.ts +4 -2
- package/dist/cli-runtime.js +397 -32
- package/dist/compatibility/claude/transcript-codec.js +6 -0
- package/dist/core/agent-orchestration.d.ts +31 -0
- package/dist/core/agent-orchestration.js +235 -0
- package/dist/core/permission-policy.d.ts +4 -0
- package/dist/core/permission-policy.js +21 -0
- package/dist/core/runtime.d.ts +6 -0
- package/dist/core/runtime.js +20 -2
- package/dist/core/team-mailbox.d.ts +54 -0
- package/dist/core/team-mailbox.js +212 -0
- package/dist/core/team-ownership.d.ts +84 -0
- package/dist/core/team-ownership.js +505 -0
- package/dist/core/tool-execution-scheduler.js +6 -1
- package/dist/core/transcript-event.d.ts +5 -1
- package/dist/core/transcript-event.js +12 -0
- package/dist/persistence/claude-job-store.d.ts +58 -0
- package/dist/persistence/claude-job-store.js +483 -1
- package/dist/persistence/claude-transcript-store.d.ts +2 -1
- package/dist/persistence/claude-transcript-store.js +2 -10
- package/dist/persistence/native-team-mailbox.d.ts +68 -0
- package/dist/persistence/native-team-mailbox.js +542 -0
- package/dist/persistence/native-team-store.d.ts +34 -0
- package/dist/persistence/native-team-store.js +257 -0
- package/dist/persistence/native-transcript-reader.d.ts +53 -0
- package/dist/persistence/native-transcript-reader.js +283 -0
- package/dist/persistence/native-transcript-store.d.ts +69 -0
- package/dist/persistence/native-transcript-store.js +321 -0
- package/dist/persistence/subagent-lifecycle-store.d.ts +41 -8
- package/dist/persistence/subagent-lifecycle-store.js +373 -146
- package/dist/persistence/transcript-file-append.d.ts +2 -0
- package/dist/persistence/transcript-file-append.js +10 -0
- package/dist/platform/exclusive-file-lease.d.ts +3 -0
- package/dist/platform/exclusive-file-lease.js +3 -0
- package/dist/tools/claude-capabilities.d.ts +4 -0
- package/dist/tools/claude-capabilities.js +18 -2
- package/dist/tools/team-lead-tools.d.ts +19 -0
- package/dist/tools/team-lead-tools.js +479 -0
- package/dist/tools/team-member-tools.d.ts +21 -0
- package/dist/tools/team-member-tools.js +259 -0
- package/package.json +1 -1
- package/dist/cli/tui/fullscreen-renderer.d.ts +0 -14
- package/dist/cli/tui/fullscreen-renderer.js +0 -13
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
import { projectTranscriptPresentation, transcriptPresentationEntryKey, transcriptReadSummaryKey, } from './transcript-presentation.js';
|
|
2
|
+
import { createTranscriptEntryViewportIndex, estimateTranscriptEntryLines, projectTranscriptEntryRange, } from './transcript-viewport.js';
|
|
3
|
+
const historyChangeLineage = Symbol('tui-history-change-lineage');
|
|
4
|
+
function retainedHistoryChange(revision, changedFrom, history, previousHistory) {
|
|
5
|
+
const change = { revision, changedFrom };
|
|
6
|
+
Object.defineProperty(change, historyChangeLineage, {
|
|
7
|
+
value: Object.freeze({
|
|
8
|
+
history,
|
|
9
|
+
...(previousHistory ? { previousHistory } : {}),
|
|
10
|
+
}),
|
|
11
|
+
enumerable: false,
|
|
12
|
+
});
|
|
13
|
+
return Object.freeze(change);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates a caller-owned immutable mutation fact with non-persisted provenance.
|
|
17
|
+
* Provenance lets the retained model verify an append in O(1); unbranded or
|
|
18
|
+
* inconsistent facts remain valid inputs but deliberately take the cold path.
|
|
19
|
+
*/
|
|
20
|
+
export function createTuiHistoryChange(revision, changedFrom, history, previousHistory) {
|
|
21
|
+
if (previousHistory) {
|
|
22
|
+
if (changedFrom > previousHistory.length || changedFrom > history.length)
|
|
23
|
+
return Object.freeze({ revision, changedFrom });
|
|
24
|
+
for (let index = 0; index < changedFrom; index += 1) {
|
|
25
|
+
if (history[index] !== previousHistory[index])
|
|
26
|
+
return Object.freeze({ revision, changedFrom });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return retainedHistoryChange(revision, changedFrom, history, previousHistory);
|
|
30
|
+
}
|
|
31
|
+
/** Constructs an append and its lineage proof without scanning the old prefix. */
|
|
32
|
+
export function appendTuiHistory(revision, previousHistory, suffix) {
|
|
33
|
+
const history = [...previousHistory, ...suffix];
|
|
34
|
+
return {
|
|
35
|
+
history,
|
|
36
|
+
change: retainedHistoryChange(revision, previousHistory.length, history, previousHistory),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** @internal Brands an append already constructed by the React history owner. */
|
|
40
|
+
export function createTuiAppendHistoryChange(revision, previousHistory, history) {
|
|
41
|
+
if (history.length <= previousHistory.length)
|
|
42
|
+
return Object.freeze({
|
|
43
|
+
revision,
|
|
44
|
+
changedFrom: previousHistory.length,
|
|
45
|
+
});
|
|
46
|
+
return retainedHistoryChange(revision, previousHistory.length, history, previousHistory);
|
|
47
|
+
}
|
|
48
|
+
const LEAF_SIZE = 64;
|
|
49
|
+
const VIEWPORT_INDEX_THRESHOLD = 64;
|
|
50
|
+
function leaf(entries, rows, viewportIndexes = []) {
|
|
51
|
+
return {
|
|
52
|
+
kind: 'leaf',
|
|
53
|
+
entries,
|
|
54
|
+
rows,
|
|
55
|
+
viewportIndexes,
|
|
56
|
+
entryCount: entries.length,
|
|
57
|
+
totalRows: rows.reduce((total, count) => total + count, 0),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function nodeHeight(node) {
|
|
61
|
+
return node.kind === 'branch' ? node.height : 1;
|
|
62
|
+
}
|
|
63
|
+
function branch(left, right) {
|
|
64
|
+
return {
|
|
65
|
+
kind: 'branch',
|
|
66
|
+
left,
|
|
67
|
+
right,
|
|
68
|
+
entryCount: left.entryCount + right.entryCount,
|
|
69
|
+
totalRows: left.totalRows + right.totalRows,
|
|
70
|
+
height: Math.max(nodeHeight(left), nodeHeight(right)) + 1,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function rotateRowLeft(node) {
|
|
74
|
+
if (node.right.kind !== 'branch')
|
|
75
|
+
return node;
|
|
76
|
+
return branch(branch(node.left, node.right.left), node.right.right);
|
|
77
|
+
}
|
|
78
|
+
function rotateRowRight(node) {
|
|
79
|
+
if (node.left.kind !== 'branch')
|
|
80
|
+
return node;
|
|
81
|
+
return branch(node.left.left, branch(node.left.right, node.right));
|
|
82
|
+
}
|
|
83
|
+
function balanceRow(node) {
|
|
84
|
+
const factor = nodeHeight(node.left) - nodeHeight(node.right);
|
|
85
|
+
if (factor > 1 && node.left.kind === 'branch') {
|
|
86
|
+
const left = nodeHeight(node.left.left) < nodeHeight(node.left.right)
|
|
87
|
+
? rotateRowLeft(node.left)
|
|
88
|
+
: node.left;
|
|
89
|
+
return rotateRowRight(branch(left, node.right));
|
|
90
|
+
}
|
|
91
|
+
if (factor < -1 && node.right.kind === 'branch') {
|
|
92
|
+
const right = nodeHeight(node.right.right) < nodeHeight(node.right.left)
|
|
93
|
+
? rotateRowRight(node.right)
|
|
94
|
+
: node.right;
|
|
95
|
+
return rotateRowLeft(branch(node.left, right));
|
|
96
|
+
}
|
|
97
|
+
return node;
|
|
98
|
+
}
|
|
99
|
+
function buildBalancedRows(leaves) {
|
|
100
|
+
if (leaves.length === 0)
|
|
101
|
+
return leaf([], []);
|
|
102
|
+
const build = (start, end) => {
|
|
103
|
+
if (end - start === 1)
|
|
104
|
+
return leaves[start] ?? leaf([], []);
|
|
105
|
+
const middle = start + Math.floor((end - start) / 2);
|
|
106
|
+
return branch(build(start, middle), build(middle, end));
|
|
107
|
+
};
|
|
108
|
+
return build(0, leaves.length);
|
|
109
|
+
}
|
|
110
|
+
function buildTree(entries, rows, viewportIndexes) {
|
|
111
|
+
const leaves = [];
|
|
112
|
+
for (let start = 0; start < entries.length; start += LEAF_SIZE) {
|
|
113
|
+
leaves.push(leaf(entries.slice(start, start + LEAF_SIZE), rows.slice(start, start + LEAF_SIZE), viewportIndexes.slice(start, start + LEAF_SIZE)));
|
|
114
|
+
}
|
|
115
|
+
return buildBalancedRows(leaves);
|
|
116
|
+
}
|
|
117
|
+
function appendTree(node, entry, rows, viewportIndex) {
|
|
118
|
+
if (node.kind === 'leaf') {
|
|
119
|
+
if (node.entries.length < LEAF_SIZE)
|
|
120
|
+
return leaf([...node.entries, entry], [...node.rows, rows], [...node.viewportIndexes, viewportIndex]);
|
|
121
|
+
return branch(node, leaf([entry], [rows], [viewportIndex]));
|
|
122
|
+
}
|
|
123
|
+
return balanceRow(branch(node.left, appendTree(node.right, entry, rows, viewportIndex)));
|
|
124
|
+
}
|
|
125
|
+
function updateTree(node, index, entry, rows, viewportIndex) {
|
|
126
|
+
if (node.kind === 'leaf') {
|
|
127
|
+
if (index < 0 || index >= node.entryCount)
|
|
128
|
+
return node;
|
|
129
|
+
const entries = [...node.entries];
|
|
130
|
+
const counts = [...node.rows];
|
|
131
|
+
const viewportIndexes = [...node.viewportIndexes];
|
|
132
|
+
entries[index] = entry;
|
|
133
|
+
counts[index] = rows;
|
|
134
|
+
viewportIndexes[index] = viewportIndex;
|
|
135
|
+
return leaf(entries, counts, viewportIndexes);
|
|
136
|
+
}
|
|
137
|
+
return index < node.left.entryCount
|
|
138
|
+
? branch(updateTree(node.left, index, entry, rows, viewportIndex), node.right)
|
|
139
|
+
: branch(node.left, updateTree(node.right, index - node.left.entryCount, entry, rows, viewportIndex));
|
|
140
|
+
}
|
|
141
|
+
function joinRows(left, right) {
|
|
142
|
+
if (left.entryCount === 0)
|
|
143
|
+
return right;
|
|
144
|
+
if (right.entryCount === 0)
|
|
145
|
+
return left;
|
|
146
|
+
if (nodeHeight(left) > nodeHeight(right) + 1 && left.kind === 'branch')
|
|
147
|
+
return balanceRow(branch(left.left, joinRows(left.right, right)));
|
|
148
|
+
if (nodeHeight(right) > nodeHeight(left) + 1 && right.kind === 'branch')
|
|
149
|
+
return balanceRow(branch(joinRows(left, right.left), right.right));
|
|
150
|
+
return branch(left, right);
|
|
151
|
+
}
|
|
152
|
+
function takeTree(node, count) {
|
|
153
|
+
if (count <= 0)
|
|
154
|
+
return leaf([], []);
|
|
155
|
+
if (count >= node.entryCount)
|
|
156
|
+
return node;
|
|
157
|
+
if (node.kind === 'leaf')
|
|
158
|
+
return leaf(node.entries.slice(0, count), node.rows.slice(0, count), node.viewportIndexes.slice(0, count));
|
|
159
|
+
if (count <= node.left.entryCount)
|
|
160
|
+
return takeTree(node.left, count);
|
|
161
|
+
return joinRows(node.left, takeTree(node.right, count - node.left.entryCount));
|
|
162
|
+
}
|
|
163
|
+
function treeAt(node, index) {
|
|
164
|
+
if (index < 0 || index >= node.entryCount)
|
|
165
|
+
return undefined;
|
|
166
|
+
if (node.kind === 'leaf')
|
|
167
|
+
return node.entries[index];
|
|
168
|
+
return index < node.left.entryCount
|
|
169
|
+
? treeAt(node.left, index)
|
|
170
|
+
: treeAt(node.right, index - node.left.entryCount);
|
|
171
|
+
}
|
|
172
|
+
function treeEntries(node, output = []) {
|
|
173
|
+
if (node.kind === 'leaf')
|
|
174
|
+
output.push(...node.entries);
|
|
175
|
+
else {
|
|
176
|
+
treeEntries(node.left, output);
|
|
177
|
+
treeEntries(node.right, output);
|
|
178
|
+
}
|
|
179
|
+
return output;
|
|
180
|
+
}
|
|
181
|
+
function collectRange(node, start, end, base = 0, output = []) {
|
|
182
|
+
if (end <= base || start >= base + node.totalRows)
|
|
183
|
+
return output;
|
|
184
|
+
if (node.kind === 'leaf') {
|
|
185
|
+
let cursor = base;
|
|
186
|
+
for (let index = 0; index < node.entryCount; index += 1) {
|
|
187
|
+
const count = node.rows[index] ?? 0;
|
|
188
|
+
const entry = node.entries[index];
|
|
189
|
+
const viewportIndex = node.viewportIndexes[index];
|
|
190
|
+
if (entry && cursor + count > start && cursor < end)
|
|
191
|
+
output.push({
|
|
192
|
+
entry,
|
|
193
|
+
start: cursor,
|
|
194
|
+
rows: count,
|
|
195
|
+
...(viewportIndex ? { viewportIndex } : {}),
|
|
196
|
+
});
|
|
197
|
+
cursor += count;
|
|
198
|
+
}
|
|
199
|
+
return output;
|
|
200
|
+
}
|
|
201
|
+
collectRange(node.left, start, end, base, output);
|
|
202
|
+
collectRange(node.right, start, end, base + node.left.totalRows, output);
|
|
203
|
+
return output;
|
|
204
|
+
}
|
|
205
|
+
function pendingHeight(node) {
|
|
206
|
+
return node?.height ?? 0;
|
|
207
|
+
}
|
|
208
|
+
function pendingNode(key, queue, left, right) {
|
|
209
|
+
return {
|
|
210
|
+
key,
|
|
211
|
+
queue,
|
|
212
|
+
...(left ? { left } : {}),
|
|
213
|
+
...(right ? { right } : {}),
|
|
214
|
+
height: Math.max(pendingHeight(left), pendingHeight(right)) + 1,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function rotatePendingLeft(node) {
|
|
218
|
+
const right = node.right;
|
|
219
|
+
if (!right)
|
|
220
|
+
return node;
|
|
221
|
+
return pendingNode(right.key, right.queue, pendingNode(node.key, node.queue, node.left, right.left), right.right);
|
|
222
|
+
}
|
|
223
|
+
function rotatePendingRight(node) {
|
|
224
|
+
const left = node.left;
|
|
225
|
+
if (!left)
|
|
226
|
+
return node;
|
|
227
|
+
return pendingNode(left.key, left.queue, left.left, pendingNode(node.key, node.queue, left.right, node.right));
|
|
228
|
+
}
|
|
229
|
+
function balancePending(node) {
|
|
230
|
+
const factor = pendingHeight(node.left) - pendingHeight(node.right);
|
|
231
|
+
if (factor > 1 && node.left) {
|
|
232
|
+
const left = pendingHeight(node.left.left) < pendingHeight(node.left.right)
|
|
233
|
+
? rotatePendingLeft(node.left)
|
|
234
|
+
: node.left;
|
|
235
|
+
return rotatePendingRight(pendingNode(node.key, node.queue, left, node.right));
|
|
236
|
+
}
|
|
237
|
+
if (factor < -1 && node.right) {
|
|
238
|
+
const right = pendingHeight(node.right.right) < pendingHeight(node.right.left)
|
|
239
|
+
? rotatePendingRight(node.right)
|
|
240
|
+
: node.right;
|
|
241
|
+
return rotatePendingLeft(pendingNode(node.key, node.queue, node.left, right));
|
|
242
|
+
}
|
|
243
|
+
return node;
|
|
244
|
+
}
|
|
245
|
+
function pendingGet(node, key) {
|
|
246
|
+
let cursor = node;
|
|
247
|
+
while (cursor) {
|
|
248
|
+
if (key === cursor.key)
|
|
249
|
+
return cursor.queue;
|
|
250
|
+
cursor = key < cursor.key ? cursor.left : cursor.right;
|
|
251
|
+
}
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
function pendingSet(node, key, queue) {
|
|
255
|
+
if (!node)
|
|
256
|
+
return pendingNode(key, queue);
|
|
257
|
+
if (key === node.key)
|
|
258
|
+
return pendingNode(key, queue, node.left, node.right);
|
|
259
|
+
return key < node.key
|
|
260
|
+
? balancePending(pendingNode(node.key, node.queue, pendingSet(node.left, key, queue), node.right))
|
|
261
|
+
: balancePending(pendingNode(node.key, node.queue, node.left, pendingSet(node.right, key, queue)));
|
|
262
|
+
}
|
|
263
|
+
function pendingMinimum(node) {
|
|
264
|
+
let cursor = node;
|
|
265
|
+
while (cursor.left)
|
|
266
|
+
cursor = cursor.left;
|
|
267
|
+
return cursor;
|
|
268
|
+
}
|
|
269
|
+
function pendingDelete(node, key) {
|
|
270
|
+
if (!node)
|
|
271
|
+
return undefined;
|
|
272
|
+
if (key < node.key) {
|
|
273
|
+
const left = pendingDelete(node.left, key);
|
|
274
|
+
return balancePending(pendingNode(node.key, node.queue, left, node.right));
|
|
275
|
+
}
|
|
276
|
+
if (key > node.key) {
|
|
277
|
+
const right = pendingDelete(node.right, key);
|
|
278
|
+
return balancePending(pendingNode(node.key, node.queue, node.left, right));
|
|
279
|
+
}
|
|
280
|
+
if (!node.left)
|
|
281
|
+
return node.right;
|
|
282
|
+
if (!node.right)
|
|
283
|
+
return node.left;
|
|
284
|
+
const successor = pendingMinimum(node.right);
|
|
285
|
+
return balancePending(pendingNode(successor.key, successor.queue, node.left, pendingDelete(node.right, successor.key)));
|
|
286
|
+
}
|
|
287
|
+
function pendingPush(root, key, call) {
|
|
288
|
+
const queue = pendingGet(root, key) ?? { length: 0 };
|
|
289
|
+
return pendingSet(root, key, {
|
|
290
|
+
...queue,
|
|
291
|
+
back: { value: call, ...(queue.back ? { next: queue.back } : {}) },
|
|
292
|
+
length: queue.length + 1,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
function reversePendingList(list) {
|
|
296
|
+
let cursor = list;
|
|
297
|
+
let reversed;
|
|
298
|
+
while (cursor) {
|
|
299
|
+
reversed = {
|
|
300
|
+
value: cursor.value,
|
|
301
|
+
...(reversed ? { next: reversed } : {}),
|
|
302
|
+
};
|
|
303
|
+
cursor = cursor.next;
|
|
304
|
+
}
|
|
305
|
+
return reversed;
|
|
306
|
+
}
|
|
307
|
+
function pendingFirst(queue) {
|
|
308
|
+
if (queue?.front)
|
|
309
|
+
return queue.front.value;
|
|
310
|
+
let cursor = queue?.back;
|
|
311
|
+
while (cursor?.next)
|
|
312
|
+
cursor = cursor.next;
|
|
313
|
+
return cursor?.value;
|
|
314
|
+
}
|
|
315
|
+
function pendingPop(root, key) {
|
|
316
|
+
const queue = pendingGet(root, key);
|
|
317
|
+
if (!queue || queue.length === 0)
|
|
318
|
+
return [undefined, root];
|
|
319
|
+
const front = queue.front ?? reversePendingList(queue.back);
|
|
320
|
+
const first = front?.value;
|
|
321
|
+
if (!first)
|
|
322
|
+
return [undefined, root];
|
|
323
|
+
const remaining = {
|
|
324
|
+
...(front.next ? { front: front.next } : {}),
|
|
325
|
+
...(queue.front && queue.back ? { back: queue.back } : {}),
|
|
326
|
+
length: queue.length - 1,
|
|
327
|
+
};
|
|
328
|
+
return [
|
|
329
|
+
first,
|
|
330
|
+
remaining.length > 0
|
|
331
|
+
? pendingSet(root, key, remaining)
|
|
332
|
+
: pendingDelete(root, key),
|
|
333
|
+
];
|
|
334
|
+
}
|
|
335
|
+
function coldPairing(history, entries) {
|
|
336
|
+
const entryIndexes = new Map(entries.map((entry, index) => [entry.key, index]));
|
|
337
|
+
const tools = new Map();
|
|
338
|
+
const shells = new Map();
|
|
339
|
+
const pairedToolCallByResult = new Map();
|
|
340
|
+
const toolResultByCall = new Map();
|
|
341
|
+
for (let sourceIndex = 0; sourceIndex < history.length; sourceIndex += 1) {
|
|
342
|
+
const item = history[sourceIndex];
|
|
343
|
+
if (!item)
|
|
344
|
+
continue;
|
|
345
|
+
if (item.kind === 'tool') {
|
|
346
|
+
const pending = tools.get(item.call.id) ?? { calls: [], next: 0 };
|
|
347
|
+
pending.calls.push({
|
|
348
|
+
sourceIndex,
|
|
349
|
+
presentationIndex: entryIndexes.get(transcriptPresentationEntryKey(item, sourceIndex)) ??
|
|
350
|
+
-1,
|
|
351
|
+
item,
|
|
352
|
+
});
|
|
353
|
+
tools.set(item.call.id, pending);
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (item.kind === 'tool-result') {
|
|
357
|
+
const pending = tools.get(item.callId);
|
|
358
|
+
const call = pending?.calls[pending.next];
|
|
359
|
+
if (pending && call) {
|
|
360
|
+
pending.next += 1;
|
|
361
|
+
pairedToolCallByResult.set(sourceIndex, call);
|
|
362
|
+
toolResultByCall.set(call.sourceIndex, item);
|
|
363
|
+
if (pending.next === pending.calls.length)
|
|
364
|
+
tools.delete(item.callId);
|
|
365
|
+
}
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (item.kind === 'shell') {
|
|
369
|
+
const pending = shells.get(item.callId) ?? { calls: [], next: 0 };
|
|
370
|
+
pending.calls.push({
|
|
371
|
+
sourceIndex,
|
|
372
|
+
presentationIndex: entryIndexes.get(transcriptPresentationEntryKey(item, sourceIndex)) ??
|
|
373
|
+
-1,
|
|
374
|
+
item,
|
|
375
|
+
});
|
|
376
|
+
shells.set(item.callId, pending);
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (item.kind === 'shell-result') {
|
|
380
|
+
const pending = shells.get(item.callId);
|
|
381
|
+
if (pending?.calls[pending.next])
|
|
382
|
+
pending.next += 1;
|
|
383
|
+
if (pending && pending.next === pending.calls.length)
|
|
384
|
+
shells.delete(item.callId);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
let pendingTools;
|
|
388
|
+
for (const [key, pending] of tools) {
|
|
389
|
+
for (const call of pending.calls.slice(pending.next))
|
|
390
|
+
pendingTools = pendingPush(pendingTools, key, call);
|
|
391
|
+
}
|
|
392
|
+
let pendingShells;
|
|
393
|
+
for (const [key, pending] of shells) {
|
|
394
|
+
for (const call of pending.calls.slice(pending.next))
|
|
395
|
+
pendingShells = pendingPush(pendingShells, key, call);
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
...(pendingTools ? { pendingTools } : {}),
|
|
399
|
+
...(pendingShells ? { pendingShells } : {}),
|
|
400
|
+
entryIndexes,
|
|
401
|
+
pairedToolCallByResult,
|
|
402
|
+
toolResultByCall,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function coldTailReadRun(history, pairing) {
|
|
406
|
+
let start = history.length;
|
|
407
|
+
while (start > 0) {
|
|
408
|
+
const item = history[start - 1];
|
|
409
|
+
if (item?.kind === 'tool' && item.call.name === 'Read') {
|
|
410
|
+
start -= 1;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (item?.kind === 'tool-result' && !item.isError) {
|
|
414
|
+
const call = pairing.pairedToolCallByResult.get(start - 1);
|
|
415
|
+
if (call?.item.kind === 'tool' && call.item.call.name === 'Read') {
|
|
416
|
+
start -= 1;
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
if (start >= history.length)
|
|
423
|
+
return undefined;
|
|
424
|
+
const readCalls = [];
|
|
425
|
+
for (let index = start; index < history.length; index += 1) {
|
|
426
|
+
const item = history[index];
|
|
427
|
+
if (item?.kind === 'tool' && item.call.name === 'Read') {
|
|
428
|
+
const result = pairing.toolResultByCall.get(index);
|
|
429
|
+
readCalls.push({
|
|
430
|
+
sourceIndex: index,
|
|
431
|
+
entry: {
|
|
432
|
+
kind: 'tool',
|
|
433
|
+
key: transcriptPresentationEntryKey(item, index),
|
|
434
|
+
item,
|
|
435
|
+
...(result ? { result } : {}),
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (item?.kind === 'tool-result') {
|
|
441
|
+
const call = pairing.pairedToolCallByResult.get(index);
|
|
442
|
+
if (!call || call.sourceIndex < start || item.isError)
|
|
443
|
+
return undefined;
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
return undefined;
|
|
447
|
+
}
|
|
448
|
+
if (readCalls.length === 0)
|
|
449
|
+
return undefined;
|
|
450
|
+
const summarized = readCalls.every((call) => call.entry.result !== undefined);
|
|
451
|
+
const firstCall = readCalls[0];
|
|
452
|
+
if (!firstCall)
|
|
453
|
+
return undefined;
|
|
454
|
+
const targetKey = summarized
|
|
455
|
+
? transcriptReadSummaryKey(start)
|
|
456
|
+
: firstCall.entry.key;
|
|
457
|
+
const startPresentationIndex = pairing.entryIndexes.get(targetKey);
|
|
458
|
+
if (startPresentationIndex === undefined)
|
|
459
|
+
return undefined;
|
|
460
|
+
return {
|
|
461
|
+
startSourceIndex: start,
|
|
462
|
+
startPresentationIndex,
|
|
463
|
+
nextSourceIndex: history.length,
|
|
464
|
+
calls: readCalls,
|
|
465
|
+
summarized,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function canReuseEntry(previous, next) {
|
|
469
|
+
if (previous.kind !== next.kind || previous.key !== next.key)
|
|
470
|
+
return false;
|
|
471
|
+
if (previous.kind === 'read-summary' && next.kind === 'read-summary')
|
|
472
|
+
return previous.count === next.count;
|
|
473
|
+
if (previous.kind === 'item' && next.kind === 'item')
|
|
474
|
+
return previous.item === next.item;
|
|
475
|
+
if (previous.kind === 'tool' && next.kind === 'tool')
|
|
476
|
+
return previous.item === next.item && previous.result === next.result;
|
|
477
|
+
if (previous.kind === 'shell' && next.kind === 'shell')
|
|
478
|
+
return previous.item === next.item && previous.result === next.result;
|
|
479
|
+
if (previous.kind === 'orphan-tool-result' &&
|
|
480
|
+
next.kind === 'orphan-tool-result')
|
|
481
|
+
return previous.item === next.item;
|
|
482
|
+
if (previous.kind === 'orphan-shell-result' &&
|
|
483
|
+
next.kind === 'orphan-shell-result')
|
|
484
|
+
return previous.item === next.item;
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
function reuseColdEntries(previous, entries) {
|
|
488
|
+
if (!previous)
|
|
489
|
+
return entries;
|
|
490
|
+
const byKey = new Map(treeEntries(previous.tree).map((entry) => [entry.key, entry]));
|
|
491
|
+
return entries.map((entry) => {
|
|
492
|
+
const prior = byKey.get(entry.key);
|
|
493
|
+
return prior && canReuseEntry(prior, entry) ? prior : entry;
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
function coldState(input, previous) {
|
|
497
|
+
const projected = projectTranscriptPresentation(input.history, input.mode);
|
|
498
|
+
const entries = reuseColdEntries(previous, projected);
|
|
499
|
+
const rows = entries.map((entry) => estimateTranscriptEntryLines(entry, input.width, input.mode));
|
|
500
|
+
const viewportIndexes = entries.map((entry, index) => {
|
|
501
|
+
const rowCount = rows[index] ?? 0;
|
|
502
|
+
if (rowCount <= VIEWPORT_INDEX_THRESHOLD)
|
|
503
|
+
return undefined;
|
|
504
|
+
const viewportIndex = createTranscriptEntryViewportIndex(entry, input.width, input.mode);
|
|
505
|
+
return viewportIndex?.rows.length === rowCount ? viewportIndex : undefined;
|
|
506
|
+
});
|
|
507
|
+
const pairing = coldPairing(input.history, entries);
|
|
508
|
+
const tailReadRun = input.mode === 'normal'
|
|
509
|
+
? coldTailReadRun(input.history, pairing)
|
|
510
|
+
: undefined;
|
|
511
|
+
return {
|
|
512
|
+
history: input.history,
|
|
513
|
+
mode: input.mode,
|
|
514
|
+
width: input.width,
|
|
515
|
+
tree: buildTree(entries, rows, viewportIndexes),
|
|
516
|
+
...(pairing.pendingTools ? { pendingTools: pairing.pendingTools } : {}),
|
|
517
|
+
...(pairing.pendingShells ? { pendingShells: pairing.pendingShells } : {}),
|
|
518
|
+
...(tailReadRun ? { tailReadRun } : {}),
|
|
519
|
+
revision: input.revision,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function entryForItem(item, sourceIndex) {
|
|
523
|
+
const key = transcriptPresentationEntryKey(item, sourceIndex);
|
|
524
|
+
if (item.kind === 'tool')
|
|
525
|
+
return { kind: 'tool', key, item };
|
|
526
|
+
if (item.kind === 'tool-result')
|
|
527
|
+
return { kind: 'orphan-tool-result', key, item };
|
|
528
|
+
if (item.kind === 'shell')
|
|
529
|
+
return { kind: 'shell', key, item };
|
|
530
|
+
if (item.kind === 'shell-result')
|
|
531
|
+
return { kind: 'orphan-shell-result', key, item };
|
|
532
|
+
return { kind: 'item', key, item };
|
|
533
|
+
}
|
|
534
|
+
function appendEntry(tree, entry, width, mode) {
|
|
535
|
+
const rowCount = estimateTranscriptEntryLines(entry, width, mode);
|
|
536
|
+
const viewportIndex = rowCount > VIEWPORT_INDEX_THRESHOLD
|
|
537
|
+
? createTranscriptEntryViewportIndex(entry, width, mode)
|
|
538
|
+
: undefined;
|
|
539
|
+
return appendTree(tree, entry, rowCount, viewportIndex?.rows.length === rowCount ? viewportIndex : undefined);
|
|
540
|
+
}
|
|
541
|
+
function updateEntry(tree, index, entry, width, mode) {
|
|
542
|
+
const rowCount = estimateTranscriptEntryLines(entry, width, mode);
|
|
543
|
+
const viewportIndex = rowCount > VIEWPORT_INDEX_THRESHOLD
|
|
544
|
+
? createTranscriptEntryViewportIndex(entry, width, mode)
|
|
545
|
+
: undefined;
|
|
546
|
+
return updateTree(tree, index, entry, rowCount, viewportIndex?.rows.length === rowCount ? viewportIndex : undefined);
|
|
547
|
+
}
|
|
548
|
+
function appendState(input, previous, change) {
|
|
549
|
+
const changedFrom = change.changedFrom;
|
|
550
|
+
const lineage = change[historyChangeLineage];
|
|
551
|
+
const previousLength = previous.history.length;
|
|
552
|
+
if (lineage?.history !== input.history ||
|
|
553
|
+
lineage.previousHistory !== previous.history ||
|
|
554
|
+
input.mode !== previous.mode ||
|
|
555
|
+
input.width !== previous.width ||
|
|
556
|
+
input.revision !== previous.revision + 1 ||
|
|
557
|
+
changedFrom !== previousLength ||
|
|
558
|
+
input.history.length <= previousLength ||
|
|
559
|
+
(previousLength > 0 &&
|
|
560
|
+
input.history[previousLength - 1] !==
|
|
561
|
+
previous.history[previousLength - 1]))
|
|
562
|
+
return undefined;
|
|
563
|
+
const suffix = input.history.slice(previousLength);
|
|
564
|
+
let tree = previous.tree;
|
|
565
|
+
let pendingTools = previous.pendingTools;
|
|
566
|
+
let pendingShells = previous.pendingShells;
|
|
567
|
+
let tailReadRun = previous.tailReadRun;
|
|
568
|
+
for (let offset = 0; offset < suffix.length; offset += 1) {
|
|
569
|
+
const sourceIndex = previousLength + offset;
|
|
570
|
+
const item = suffix[offset];
|
|
571
|
+
if (!item)
|
|
572
|
+
continue;
|
|
573
|
+
const pendingTool = item.kind === 'tool-result'
|
|
574
|
+
? pendingFirst(pendingGet(pendingTools, item.callId))
|
|
575
|
+
: undefined;
|
|
576
|
+
const continuesReadRun = input.mode === 'normal' &&
|
|
577
|
+
tailReadRun?.nextSourceIndex === sourceIndex &&
|
|
578
|
+
((item.kind === 'tool' && item.call.name === 'Read') ||
|
|
579
|
+
(item.kind === 'tool-result' &&
|
|
580
|
+
pendingTool?.item.kind === 'tool' &&
|
|
581
|
+
pendingTool.item.call.name === 'Read' &&
|
|
582
|
+
tailReadRun.calls.some((call) => call.sourceIndex === pendingTool.sourceIndex)));
|
|
583
|
+
if (!continuesReadRun)
|
|
584
|
+
tailReadRun = undefined;
|
|
585
|
+
if (item.kind === 'tool') {
|
|
586
|
+
if (item.call.name === 'Read' && input.mode === 'normal') {
|
|
587
|
+
if (tailReadRun?.summarized) {
|
|
588
|
+
tree = takeTree(tree, tailReadRun.startPresentationIndex);
|
|
589
|
+
for (const call of tailReadRun.calls)
|
|
590
|
+
tree = appendEntry(tree, call.entry, input.width, input.mode);
|
|
591
|
+
}
|
|
592
|
+
const entry = entryForItem(item, sourceIndex);
|
|
593
|
+
if (entry.kind !== 'tool')
|
|
594
|
+
return undefined;
|
|
595
|
+
const presentationIndex = tree.entryCount;
|
|
596
|
+
tree = appendEntry(tree, entry, input.width, input.mode);
|
|
597
|
+
pendingTools = pendingPush(pendingTools, item.call.id, {
|
|
598
|
+
sourceIndex,
|
|
599
|
+
presentationIndex,
|
|
600
|
+
item,
|
|
601
|
+
});
|
|
602
|
+
tailReadRun = tailReadRun
|
|
603
|
+
? {
|
|
604
|
+
...tailReadRun,
|
|
605
|
+
nextSourceIndex: sourceIndex + 1,
|
|
606
|
+
calls: [...tailReadRun.calls, { sourceIndex, entry }],
|
|
607
|
+
summarized: false,
|
|
608
|
+
}
|
|
609
|
+
: {
|
|
610
|
+
startSourceIndex: sourceIndex,
|
|
611
|
+
startPresentationIndex: presentationIndex,
|
|
612
|
+
nextSourceIndex: sourceIndex + 1,
|
|
613
|
+
calls: [{ sourceIndex, entry }],
|
|
614
|
+
summarized: false,
|
|
615
|
+
};
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
const entry = entryForItem(item, sourceIndex);
|
|
619
|
+
const presentationIndex = tree.entryCount;
|
|
620
|
+
tree = appendEntry(tree, entry, input.width, input.mode);
|
|
621
|
+
pendingTools = pendingPush(pendingTools, item.call.id, {
|
|
622
|
+
sourceIndex,
|
|
623
|
+
presentationIndex,
|
|
624
|
+
item,
|
|
625
|
+
});
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (item.kind === 'tool-result') {
|
|
629
|
+
const [pending, nextPendingTools] = pendingPop(pendingTools, item.callId);
|
|
630
|
+
pendingTools = nextPendingTools;
|
|
631
|
+
if (!pending) {
|
|
632
|
+
tree = appendEntry(tree, entryForItem(item, sourceIndex), input.width, input.mode);
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
const prior = treeAt(tree, pending.presentationIndex);
|
|
636
|
+
if (prior?.kind !== 'tool')
|
|
637
|
+
return undefined;
|
|
638
|
+
const next = { ...prior, result: item };
|
|
639
|
+
tree = updateEntry(tree, pending.presentationIndex, next, input.width, input.mode);
|
|
640
|
+
if (continuesReadRun && tailReadRun) {
|
|
641
|
+
const calls = tailReadRun.calls.map((call) => call.sourceIndex === pending.sourceIndex
|
|
642
|
+
? { ...call, entry: next }
|
|
643
|
+
: call);
|
|
644
|
+
if (item.isError) {
|
|
645
|
+
tailReadRun = undefined;
|
|
646
|
+
}
|
|
647
|
+
else if (calls.every((call) => call.entry.result !== undefined)) {
|
|
648
|
+
tree = takeTree(tree, tailReadRun.startPresentationIndex);
|
|
649
|
+
tree = appendEntry(tree, {
|
|
650
|
+
kind: 'read-summary',
|
|
651
|
+
key: transcriptReadSummaryKey(tailReadRun.startSourceIndex),
|
|
652
|
+
count: calls.length,
|
|
653
|
+
}, input.width, input.mode);
|
|
654
|
+
tailReadRun = {
|
|
655
|
+
...tailReadRun,
|
|
656
|
+
nextSourceIndex: sourceIndex + 1,
|
|
657
|
+
calls,
|
|
658
|
+
summarized: true,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
tailReadRun = {
|
|
663
|
+
...tailReadRun,
|
|
664
|
+
nextSourceIndex: sourceIndex + 1,
|
|
665
|
+
calls,
|
|
666
|
+
summarized: false,
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
if (item.kind === 'shell') {
|
|
673
|
+
const entry = entryForItem(item, sourceIndex);
|
|
674
|
+
const presentationIndex = tree.entryCount;
|
|
675
|
+
tree = appendEntry(tree, entry, input.width, input.mode);
|
|
676
|
+
pendingShells = pendingPush(pendingShells, item.callId, {
|
|
677
|
+
sourceIndex,
|
|
678
|
+
presentationIndex,
|
|
679
|
+
item,
|
|
680
|
+
});
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (item.kind === 'shell-result') {
|
|
684
|
+
const [pending, nextPendingShells] = pendingPop(pendingShells, item.callId);
|
|
685
|
+
pendingShells = nextPendingShells;
|
|
686
|
+
if (!pending) {
|
|
687
|
+
tree = appendEntry(tree, entryForItem(item, sourceIndex), input.width, input.mode);
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
const prior = treeAt(tree, pending.presentationIndex);
|
|
691
|
+
if (prior?.kind !== 'shell')
|
|
692
|
+
return undefined;
|
|
693
|
+
const next = { ...prior, result: item };
|
|
694
|
+
tree = updateEntry(tree, pending.presentationIndex, next, input.width, input.mode);
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
tree = appendEntry(tree, entryForItem(item, sourceIndex), input.width, input.mode);
|
|
698
|
+
}
|
|
699
|
+
return {
|
|
700
|
+
history: input.history,
|
|
701
|
+
mode: input.mode,
|
|
702
|
+
width: input.width,
|
|
703
|
+
tree,
|
|
704
|
+
...(pendingTools ? { pendingTools } : {}),
|
|
705
|
+
...(pendingShells ? { pendingShells } : {}),
|
|
706
|
+
...(tailReadRun ? { tailReadRun } : {}),
|
|
707
|
+
revision: input.revision,
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function select(state, pageRows, offset, width, mode) {
|
|
711
|
+
const max = Math.max(0, state.tree.totalRows - pageRows);
|
|
712
|
+
const clamped = Math.min(Math.max(0, offset), max);
|
|
713
|
+
const end = state.tree.totalRows - clamped;
|
|
714
|
+
const start = Math.max(0, end - pageRows);
|
|
715
|
+
const candidates = collectRange(state.tree, start, end);
|
|
716
|
+
const selected = [];
|
|
717
|
+
for (const candidate of candidates) {
|
|
718
|
+
const candidateEnd = candidate.start + candidate.rows;
|
|
719
|
+
const overlapStart = Math.max(start, candidate.start);
|
|
720
|
+
const overlapEnd = Math.min(end, candidateEnd);
|
|
721
|
+
if (overlapStart >= overlapEnd)
|
|
722
|
+
continue;
|
|
723
|
+
const localStart = overlapStart - candidate.start;
|
|
724
|
+
const overlapRows = overlapEnd - overlapStart;
|
|
725
|
+
if (localStart === 0 && overlapRows === candidate.rows) {
|
|
726
|
+
selected.push(candidate.entry);
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
if (clamped === 0 && candidateEnd < end)
|
|
730
|
+
continue;
|
|
731
|
+
const projected = projectTranscriptEntryRange(candidate.entry, localStart, overlapRows, width, mode, candidate.viewportIndex);
|
|
732
|
+
const projectedRows = projected.viewportSlice?.rows ?? candidate.rows;
|
|
733
|
+
if (projectedRows <= overlapRows)
|
|
734
|
+
selected.push(projected);
|
|
735
|
+
}
|
|
736
|
+
return selected;
|
|
737
|
+
}
|
|
738
|
+
export function projectTranscriptWindow(input, previous, change) {
|
|
739
|
+
const validFacts = change !== undefined &&
|
|
740
|
+
change.revision === input.revision &&
|
|
741
|
+
Number.isInteger(input.revision) &&
|
|
742
|
+
input.revision >= 0 &&
|
|
743
|
+
Number.isInteger(change.changedFrom) &&
|
|
744
|
+
change.changedFrom >= 0 &&
|
|
745
|
+
change.changedFrom <= input.history.length;
|
|
746
|
+
const advanced = previous && validFacts && change
|
|
747
|
+
? appendState(input, previous, change)
|
|
748
|
+
: undefined;
|
|
749
|
+
const same = !advanced &&
|
|
750
|
+
validFacts &&
|
|
751
|
+
previous !== undefined &&
|
|
752
|
+
input.revision === previous.revision &&
|
|
753
|
+
input.history === previous.history &&
|
|
754
|
+
input.mode === previous.mode &&
|
|
755
|
+
input.width === previous.width;
|
|
756
|
+
const state = advanced ?? (same ? previous : coldState(input, previous));
|
|
757
|
+
const transition = advanced
|
|
758
|
+
? 'append'
|
|
759
|
+
: same
|
|
760
|
+
? 'same'
|
|
761
|
+
: 'cold';
|
|
762
|
+
const totalRows = state.tree.totalRows;
|
|
763
|
+
const maxOffset = Math.max(0, totalRows - input.pageRows);
|
|
764
|
+
const allEntries = input.bounded ? [] : treeEntries(state.tree);
|
|
765
|
+
const entries = input.bounded
|
|
766
|
+
? input.pageRows >= totalRows
|
|
767
|
+
? treeEntries(state.tree)
|
|
768
|
+
: select(state, input.pageRows, input.scrollOffset, input.width, input.mode)
|
|
769
|
+
: allEntries;
|
|
770
|
+
return { state, allEntries, entries, totalRows, maxOffset, transition };
|
|
771
|
+
}
|
|
772
|
+
//# sourceMappingURL=transcript-window-model.js.map
|