@alisio/alisio-code 0.1.0-alpha.9 → 0.1.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.
Files changed (56) hide show
  1. package/README.md +95 -16
  2. package/dist/analysis.d.ts +27 -0
  3. package/dist/analysis.js +145 -0
  4. package/dist/banner.js +2 -1
  5. package/dist/builtin.d.ts +3 -1
  6. package/dist/builtin.js +0 -24
  7. package/dist/main.js +133 -6
  8. package/dist/serve.d.ts +15 -0
  9. package/dist/serve.js +99 -0
  10. package/dist/tui/agent-manager.d.ts +105 -0
  11. package/dist/tui/agent-manager.js +269 -0
  12. package/dist/tui/agents.d.ts +5 -0
  13. package/dist/tui/agents.js +5 -0
  14. package/dist/tui/app.d.ts +42 -1
  15. package/dist/tui/app.js +1895 -97
  16. package/dist/tui/artifact-preview.d.ts +52 -0
  17. package/dist/tui/artifact-preview.js +212 -0
  18. package/dist/tui/artifacts.d.ts +54 -0
  19. package/dist/tui/artifacts.js +207 -0
  20. package/dist/tui/btw.d.ts +57 -0
  21. package/dist/tui/btw.js +76 -0
  22. package/dist/tui/components.d.ts +174 -12
  23. package/dist/tui/components.js +962 -66
  24. package/dist/tui/connect-input.d.ts +2 -0
  25. package/dist/tui/connect-input.js +1 -1
  26. package/dist/tui/exit.d.ts +10 -0
  27. package/dist/tui/exit.js +15 -0
  28. package/dist/tui/git-branch.d.ts +48 -0
  29. package/dist/tui/git-branch.js +99 -0
  30. package/dist/tui/goal.d.ts +75 -0
  31. package/dist/tui/goal.js +171 -0
  32. package/dist/tui/modes.d.ts +71 -0
  33. package/dist/tui/modes.js +90 -0
  34. package/dist/tui/open-path.d.ts +38 -0
  35. package/dist/tui/open-path.js +80 -0
  36. package/dist/tui/plan-review.d.ts +48 -0
  37. package/dist/tui/plan-review.js +76 -0
  38. package/dist/tui/queue.d.ts +2 -0
  39. package/dist/tui/queue.js +5 -1
  40. package/dist/tui/scroll.d.ts +8 -0
  41. package/dist/tui/scroll.js +12 -0
  42. package/dist/tui/settings-menu.d.ts +40 -0
  43. package/dist/tui/settings-menu.js +132 -0
  44. package/dist/tui/settings.d.ts +194 -0
  45. package/dist/tui/settings.js +482 -0
  46. package/dist/tui/state.d.ts +343 -7
  47. package/dist/tui/state.js +823 -54
  48. package/dist/tui/tasks.d.ts +123 -0
  49. package/dist/tui/tasks.js +369 -0
  50. package/dist/tui/theme.d.ts +42 -1
  51. package/dist/tui/theme.js +516 -1
  52. package/dist/tui/viewer-state.d.ts +7 -0
  53. package/dist/tui/viewer-state.js +36 -0
  54. package/dist/version.d.ts +7 -5
  55. package/dist/version.js +44 -8
  56. package/package.json +7 -9
@@ -1,8 +1,4 @@
1
- /**
2
- * Pure presentation logic for the TUI: formatting, command parsing and the reduction of
3
- * versioned runner events into a view model. No terminal or pi-tui imports here.
4
- */
5
- import type { Message, ModelInfo, RunEvent } from "@alisio/sdk";
1
+ import type { Message, ModelInfo, RunEvent, ToolResult, TreeNode, UiBlock } from "@alisio/sdk";
6
2
  export type Level = "ok" | "warn" | "danger";
7
3
  export declare function formatTokens(n: number): string;
8
4
  /** Prefixes every model with its owning provider so identical model ids are never ambiguous. */
@@ -39,11 +35,46 @@ export interface PluginCatalogView {
39
35
  }
40
36
  /** Text markers remain meaningful without color: [x] active, [ ] inactive, [!] failed, [*] pending. */
41
37
  /** Group headings are derived from the primary category (or "General") of each plugin. */
42
- export declare function pluginCatalogItems(entries: PluginCatalogView[]): {
38
+ /**
39
+ * Reserved value prefix marking a non-selectable group-header row in picker item lists. It can
40
+ * never collide with real entry ids (plugin ids, server names), which never start with "_".
41
+ */
42
+ export declare const GROUP_HEADER_PREFIX = "__group:";
43
+ /** True when the item is a group header emitted under GROUP_HEADER_PREFIX (never selectable). */
44
+ export declare const isGroupHeader: (item: {
45
+ value: string;
46
+ }) => boolean;
47
+ /**
48
+ * Nearest non-header index from `index` stepping `dir` (1 = down, -1 = up), wrapping at the
49
+ * edges exactly like a plain list would, so navigation skips header rows in both directions and
50
+ * never stops on one. Returns -1 for an empty list and `index` unchanged when every item is a
51
+ * header (callers then treat it as "no move").
52
+ */
53
+ export declare function skipGroupHeaders(items: readonly {
54
+ value: string;
55
+ }[], index: number, dir: 1 | -1): number;
56
+ /**
57
+ * The display sequence a picker should render for a filter: rows matching SelectList's own
58
+ * prefix semantics, plus the group header of every group that still has at least one visible
59
+ * row, in original order. Groups with no match emit no header.
60
+ */
61
+ export declare function visibleGroupedItems(items: ReadonlyArray<{
62
+ value: string;
63
+ label: string;
64
+ description?: string;
65
+ }>, filter: string): Array<{
66
+ value: string;
67
+ label: string;
68
+ description?: string;
69
+ }>;
70
+ export declare function pluginCatalogItems(entries: PluginCatalogView[]): ({
71
+ value: string;
72
+ label: string;
73
+ } | {
43
74
  value: string;
44
75
  label: string;
45
76
  description: string;
46
- }[];
77
+ })[];
47
78
  export declare const pluginToggleNeedsConfirmation: (entry: PluginCatalogView) => boolean;
48
79
  export interface McpServerView {
49
80
  name: string;
@@ -116,6 +147,10 @@ export interface CommandSpec {
116
147
  argumentHint?: string;
117
148
  aliases?: string[];
118
149
  }
150
+ /**
151
+ * Built-in slash commands the TUI offers, derived from the core `CommandCatalog` (the TUI
152
+ * surface of `BUILTIN_COMMANDS`). Kept as `COMMANDS` for compatibility.
153
+ */
119
154
  export declare const COMMANDS: CommandSpec[];
120
155
  /** Every TUI slash name (commands, aliases and routing prefixes); templates cannot take them. */
121
156
  export declare function reservedCommandNames(): string[];
@@ -124,6 +159,117 @@ export declare function parseCommand(input: string): {
124
159
  name: string;
125
160
  args: string;
126
161
  } | undefined;
162
+ /** Reasoning-effort capability advertised by a model's catalog entry (`ModelInfo.effort`). */
163
+ export interface EffortCapability {
164
+ supportedLevels: string[];
165
+ defaultLevel?: string;
166
+ }
167
+ /**
168
+ * The effective reasoning effort to send for a model: the persisted level when the model
169
+ * supports it, otherwise the model's default level (silent fallback), and nothing when the
170
+ * model advertises no effort levels at all.
171
+ */
172
+ export declare function effectiveEffort(persisted: string | undefined, capability: EffortCapability | undefined): string | undefined;
173
+ /** Validates a `/effort <level>` argument against the active model; returns an error or nothing. */
174
+ export declare function validateEffortLevel(level: string, capability: EffortCapability | undefined): string | undefined;
175
+ export declare function effortPickerItems(capability: EffortCapability, active: string | undefined): Array<{
176
+ value: string;
177
+ label: string;
178
+ description?: string;
179
+ }>;
180
+ /** Role of a status-line identity part; the renderer maps each role to a distinct color. */
181
+ export type IdentityRole = "agent" | "mode" | "model" | "provider" | "effort";
182
+ export interface IdentityPart extends Segment {
183
+ role: IdentityRole;
184
+ }
185
+ export interface IdentityInput {
186
+ agent: string;
187
+ /** Permission mode (`ask`, `auto`, `full`, `custom`, `read-only`); omitted when unknown. */
188
+ mode?: string;
189
+ model: string;
190
+ provider?: string;
191
+ effort?: string;
192
+ }
193
+ /**
194
+ * The ordered identity parts for the status line below the editor:
195
+ * `agent: <name> · <model> · <provider> · <effort>`, with the effort part omitted when the
196
+ * active model advertises no supported levels (`effort === undefined`). Colors are applied by
197
+ * the renderer per role; this module stays terminal-free and testable.
198
+ */
199
+ export declare function identityParts(input: IdentityInput): IdentityPart[];
200
+ /** Drops the lowest-priority identity parts until the line fits `width`; truncates the survivor. */
201
+ export declare function fitIdentityParts(input: IdentityInput, width: number): IdentityPart[];
202
+ /** Minimal structural view of a skill for slash autocompletion (subset of the core catalog entry). */
203
+ export interface SkillCompletionEntry {
204
+ id: string;
205
+ name: string;
206
+ displayId: string;
207
+ description: string;
208
+ /** Catalog scope of the skill: user | project | config | plugin (drives the [u]/[p]/[c]/[l] marker). */
209
+ scope?: string;
210
+ enabled: boolean;
211
+ locked: boolean;
212
+ effective: boolean;
213
+ }
214
+ export interface SlashCompletionItem {
215
+ value: string;
216
+ label: string;
217
+ description?: string;
218
+ }
219
+ export declare const SKILL_COMPLETION_DESCRIPTION_LIMIT = 80;
220
+ /**
221
+ * OpenCode-style scope marker for a skill's slash entry, mirroring the catalog scopes the /skills
222
+ * manager shows: user, project, config and plugin (plugin skills are locked by their owner plugin).
223
+ */
224
+ export declare const skillScopeMarker: (skill: SkillCompletionEntry) => string | undefined;
225
+ /**
226
+ * Description for a skill's first-class `skill:<id>` slash entry: scope marker, status hint, then
227
+ * the skill description truncated to the shared limit. The marker and status are prepended before
228
+ * truncating, so they survive the cap just like the /skills argument completions.
229
+ */
230
+ export declare function skillSlashDescription(skill: SkillCompletionEntry): string;
231
+ /**
232
+ * Suggested completions for `/skills <prefix>`: every entry the /skills manager shows, filtered by
233
+ * prefix (case-insensitive) on name or description. Selecting a suggestion only fills the argument;
234
+ * submitting still opens the skills manager.
235
+ */
236
+ export declare function skillCompletions(catalog: SkillCompletionEntry[], prefix: string, limit?: number): SlashCompletionItem[];
237
+ export interface SlashCompletionSource {
238
+ name: string;
239
+ description?: string;
240
+ argumentHint?: string;
241
+ aliases?: string[];
242
+ }
243
+ export interface SlashCompletionContext {
244
+ /** Live session rows for `/resume`: already filtered to the typed prefix and mapped. */
245
+ sessions?: (prefix: string) => SlashCompletionItem[];
246
+ /** Effective skill catalog backing `/skills` (the same entries the skills manager shows). */
247
+ skills: SkillCompletionEntry[];
248
+ }
249
+ /**
250
+ * Builds the editor slash-autocomplete command list. Aliases get their own entries with the same
251
+ * description and argument completions, because the provider matches commands by fuzzy name.
252
+ * Effective skills are appended as first-class `skill:<id>` entries so `/ski…`, `/skill:b…` and
253
+ * even `/branch…` all surface them; submitting already routes `skill:` commands to skill load, so
254
+ * selecting an entry only needs to insert the command name. `options.skillEntries: false` gates
255
+ * ONLY those standalone `skill:` entries (e.g. the `tui.skillSlashCommands` toggle): the `/skills`
256
+ * manager and its argument completion keep working, since `context.skills` still feeds both.
257
+ */
258
+ export interface SlashCompletionOptions {
259
+ /** Include first-class `skill:<id>` entries for effective skills (default true). */
260
+ skillEntries?: boolean;
261
+ }
262
+ export declare function slashCompletionCommands(sources: SlashCompletionSource[], context: SlashCompletionContext, options?: SlashCompletionOptions): ({
263
+ getArgumentCompletions: (prefix: string) => SlashCompletionItem[];
264
+ name: string;
265
+ description: string | undefined;
266
+ argumentHint?: string | undefined;
267
+ } | {
268
+ getArgumentCompletions?: undefined;
269
+ name: string;
270
+ description: string | undefined;
271
+ argumentHint?: string | undefined;
272
+ })[];
127
273
  export declare function summarizeToolArgs(name: string, args: string): string;
128
274
  export interface DiffLine {
129
275
  sign: "+" | "-";
@@ -137,6 +283,8 @@ export interface EditSummary {
137
283
  }
138
284
  export declare function editSummary(name: string, args: string): EditSummary | undefined;
139
285
  export type ToolStatus = "running" | "approval" | "ok" | "error";
286
+ /** Capability kind of a tool call; drives grouping labels and batch display. */
287
+ export type ToolKind = "read" | "write" | "process" | "mcp" | "internal" | "other";
140
288
  export type TranscriptItem = {
141
289
  kind: "user";
142
290
  text: string;
@@ -145,6 +293,10 @@ export type TranscriptItem = {
145
293
  text: string;
146
294
  reasoning: string;
147
295
  done: boolean;
296
+ /** Epoch ms of the first reasoning delta; with `reasoningDoneAt` it approximates the thinking interval. */
297
+ reasoningStartedAt?: number;
298
+ /** Epoch ms of the last reasoning delta (the end of the visible thought section). */
299
+ reasoningDoneAt?: number;
148
300
  } | {
149
301
  kind: "tool";
150
302
  id: string;
@@ -154,6 +306,17 @@ export type TranscriptItem = {
154
306
  status: ToolStatus;
155
307
  durationMs?: number;
156
308
  preview?: string;
309
+ /** Structured block rendered natively by the TUI (from a `{type:"ui"}` result part). */
310
+ ui?: UiBlock;
311
+ /** Base64 image rendered inline by the TUI when the terminal supports it (from a `{type:"image"}` part). */
312
+ image?: {
313
+ mimeType: string;
314
+ data: string;
315
+ };
316
+ /** Effect-derived kind (grouping label); name-heuristic fallback for replayed history. */
317
+ toolKind?: ToolKind;
318
+ /** Exit code derived safely from the JSON preview when the tool reports one (run_process/shell/search_text). */
319
+ exitCode?: number;
157
320
  } | {
158
321
  kind: "notice";
159
322
  text: string;
@@ -182,6 +345,16 @@ export interface ViewState {
182
345
  items: TranscriptItem[];
183
346
  streaming: boolean;
184
347
  compacting: boolean;
348
+ /** The runner is sending a silent request again (`request_retry`); cleared by any output. */
349
+ retry?: {
350
+ attempt: number;
351
+ of: number;
352
+ };
353
+ /** The response was cut by the output limit and is requested again (`truncation_recovery`). */
354
+ recovery?: {
355
+ attempt: number;
356
+ of: number;
357
+ };
185
358
  model: string;
186
359
  /** Context size in tokens: provider-reported, or estimated (`~`). */
187
360
  context?: {
@@ -189,11 +362,174 @@ export interface ViewState {
189
362
  estimated: boolean;
190
363
  };
191
364
  runStartedAt?: number;
365
+ /** Epoch ms of the latest event of the live run (any type); undefined when no run is live. */
366
+ lastEventAt?: number;
192
367
  stats: Stats;
193
368
  }
194
369
  export declare function initialViewState(model: string, now?: number): ViewState;
195
370
  export declare function addItem(state: ViewState, item: TranscriptItem): ViewState;
371
+ /** Approximated thinking interval of a completed reasoning section, when the events carried timestamps. */
372
+ export declare function reasoningDurationMs(item: {
373
+ reasoningStartedAt?: number;
374
+ reasoningDoneAt?: number;
375
+ }): number | undefined;
196
376
  export declare function reduceEvent(state: ViewState, event: RunEvent): ViewState;
377
+ /** No event for this long: the footer says how long the run has been quiet. */
378
+ export declare const QUIET_MS = 15000;
379
+ /** No event for this long: the footer marks the run as possibly stuck. */
380
+ export declare const STALLED_MS = 60000;
381
+ export interface RunPhase {
382
+ label: string;
383
+ /** Silence is expected here (the user's turn, or a sub-agent working in its own session). */
384
+ silentByDesign: boolean;
385
+ }
386
+ /** What the live run is doing, from the transcript items and flags the events already update. */
387
+ export declare function runPhase(view: ViewState): RunPhase;
388
+ /** Milliseconds of silence worth reporting (0 when the run is busy, or silent by design). */
389
+ export declare function quietFor(view: ViewState, now: number): number;
197
390
  export declare function lastAssistantText(items: TranscriptItem[]): string | undefined;
391
+ /**
392
+ * True when a printable key should copy the last assistant response instead of typing: bound to
393
+ * `c`/`y` (and uppercase) on an EMPTY editor line, while no autocomplete is showing and no turn
394
+ * is running — the same "empty input" convention Enter and Ctrl+D already use. A non-empty input
395
+ * never triggers, so typing `c` or `y` mid-message is unaffected.
396
+ */
397
+ export declare function editorCopyKey(data: string, input: {
398
+ text: string;
399
+ autocomplete: boolean;
400
+ busy: boolean;
401
+ }): boolean;
402
+ /** True when an unknown event value is a `Node` of a tree UI block. */
403
+ export declare function isTreeNode(value: unknown): value is TreeNode;
404
+ /** True when an unknown event value is an Alisio `UiBlock` (validated defensively). */
405
+ export declare function isUiBlock(value: unknown): value is UiBlock;
406
+ /** True when an unknown event value is a `{type:"image"}`-style part (mime + base64 data). */
407
+ export declare function isImagePart(value: unknown): value is {
408
+ mimeType: string;
409
+ data: string;
410
+ };
411
+ /** Rich (ui/image) parts of a persisted tool result, if any. */
412
+ export declare function richPartsOf(result: ToolResult | undefined, toolName?: string): {
413
+ ui?: UiBlock;
414
+ image?: {
415
+ mimeType: string;
416
+ data: string;
417
+ };
418
+ };
419
+ /**
420
+ * `read_file` → `Read File`, `search_text` → `Search Text`, `mcp_devforge_time_diff` →
421
+ * `MCP · Devforge Time Diff`. Splits on `_`/`-`/`.`/spaces, keeps known acronyms (MCP, HTTP…)
422
+ * and bare numeric suffixes (`read_file_2` → `Read File 2`). The machine name stays available
423
+ * dimmed in grouped detail rows and in the `/tools` and `/stats` reports.
424
+ */
425
+ export declare function humanizeToolName(name: string): string;
426
+ /** Verb and count noun used by grouped batch rows per tool kind. */
427
+ export declare const TOOL_KIND_VERB: Record<ToolKind, string>;
428
+ export declare const TOOL_KIND_WORD: Record<ToolKind, string>;
429
+ /**
430
+ * Capability kind of a tool call. Live events carry the registry `effect` (exact); replayed
431
+ * history falls back to conservative name heuristics. `mcp_*` is always the mcp kind.
432
+ */
433
+ export declare function toolKindOf(name: string, effect?: string): ToolKind;
434
+ /** Terminal-preview caps for collapsed rows (same values the renderer always used). */
435
+ export declare const OUTPUT_PREVIEW_LINES_OK = 3;
436
+ export declare const OUTPUT_PREVIEW_LINES_ERROR = 6;
437
+ export declare const previewLinesFor: (status: ToolStatus) => number;
438
+ /** Preview rows as the renderer shows them: blank lines dropped, tabs kept for the caller to expand. */
439
+ export declare const previewRows: (preview: string) => string[];
440
+ /** True when the preview exceeds the collapsed cap (the row becomes a collapsible "output"). */
441
+ export declare function previewTruncated(preview: string | undefined, status: ToolStatus): boolean;
442
+ /**
443
+ * Exit code derived safely from a text preview. `run_process`/`shell`/`search_text` return
444
+ * `{stdout, stderr, exitCode, truncated}` JSON; read-effect tools may carry an appended
445
+ * `\n<instructions>…` block, retried on the JSON prefix. Any other shape yields nothing.
446
+ */
447
+ export declare function exitCodeOf(preview: string | undefined): number | undefined;
448
+ /** Renderable view of one tool call (singleton row, or a member of a grouped batch). */
449
+ export interface ToolItemView {
450
+ id: string;
451
+ /** Machine name (kept for dimmed detail display). */
452
+ name: string;
453
+ /** Humanized display name. */
454
+ humanName: string;
455
+ kind: ToolKind;
456
+ summary: string;
457
+ status: ToolStatus;
458
+ durationMs?: number;
459
+ preview?: string;
460
+ ui?: UiBlock;
461
+ image?: {
462
+ mimeType: string;
463
+ data: string;
464
+ };
465
+ exitCode?: number;
466
+ }
467
+ /** A batch of consecutive same-kind, finished tool calls rendered as ONE collapsible row. */
468
+ export interface GroupedTool {
469
+ /** Id of the first member call (stable fold key while the batch grows). */
470
+ id: string;
471
+ members: ToolItemView[];
472
+ kind: ToolKind;
473
+ /** Aggregate: `error` when any member failed, else `ok` (members are all terminal). */
474
+ status: ToolStatus;
475
+ /** Sum of member durations. */
476
+ totalMs: number;
477
+ /** Header name: the shared humanized tool name, or the kind verb for mixed batches. */
478
+ label: string;
479
+ /** Count noun matching `label` (`reads`, `files`, `commands`…). */
480
+ word: string;
481
+ }
482
+ /** Everything the transcript renders: a plain item, or one grouped batch row. */
483
+ export type TranscriptEntry = TranscriptItem | {
484
+ kind: "group";
485
+ group: GroupedTool;
486
+ };
487
+ export declare function toolItemView(item: Extract<TranscriptItem, {
488
+ kind: "tool";
489
+ }>): ToolItemView;
490
+ /**
491
+ * Consecutive tool calls of the same kind whose statuses are ALL terminal (ok/error) merge into
492
+ * one `group` entry; running/approval calls always stay singleton so their spinner and live state
493
+ * stay visible. A kind change splits the run (`read` never merges with `shell`). Order is
494
+ * preserved; every entry carries its index within `items` (fold keys for assistant items need
495
+ * it). One linear pass — called on state changes only, never per frame.
496
+ */
497
+ export declare function groupToolEntries(items: TranscriptItem[]): Array<{
498
+ entry: TranscriptEntry;
499
+ at: number;
500
+ }>;
501
+ /** Content identity of a group (fold/diff purposes): member ids, statuses and durations. */
502
+ export declare function groupIdentity(group: GroupedTool): string;
503
+ export type FoldableKind = "reasoning" | "group" | "output";
504
+ /** A collapsible region of the transcript and how to address it (fold key, toggle target). */
505
+ export interface FoldCandidate {
506
+ /** Stable key for the fold state map (`a:` assistant index, `g:`/`t:` tool ids). */
507
+ key: string;
508
+ kind: FoldableKind;
509
+ /** Running/live content defaults expanded; finished reasoning, batches and long output collapse. */
510
+ defaultExpanded: boolean;
511
+ }
512
+ /** Cap for the reasoning text when expanded; longer sections show a truncation note. */
513
+ export declare const REASONING_EXPAND_MAX_LINES = 40;
514
+ /**
515
+ * The fold contract of one transcript entry: nothing (not collapsible), or a candidate with its
516
+ * default state. `at` is the entry's index within the ORIGINAL items array (assistant fold keys
517
+ * are stable because transcript items are append-only).
518
+ */
519
+ export declare function foldCandidateOf(entry: TranscriptEntry, at: number): FoldCandidate | undefined;
520
+ /** Stable key of a transcript entry (used by the component sync to reuse row instances). */
521
+ export declare function entryKeyOf(entry: TranscriptEntry, at: number): string;
522
+ /** Every fold candidate of the transcript in display order; the keybinding targets the last one. */
523
+ export declare function foldCandidates(items: TranscriptItem[]): FoldCandidate[];
524
+ /**
525
+ * True when a printable key should toggle the nearest collapsible transcript row instead of
526
+ * typing: bound to `x`/`X` on an EMPTY editor line (no autocomplete), the same "empty input"
527
+ * convention Enter, Ctrl+D and `c`/`y` already use. Unlike copy, it also works while a turn runs
528
+ * (the nearest candidate may still exist mid-stream). A non-empty input never triggers.
529
+ */
530
+ export declare function foldToggleKey(data: string, input: {
531
+ text: string;
532
+ autocomplete: boolean;
533
+ }): boolean;
198
534
  /** Rebuilds transcript items from persisted history (used by /resume). */
199
535
  export declare function itemsFromHistory(messages: Message[]): TranscriptItem[];