@oh-my-pi/pi-tui 18.13.0 → 18.13.2
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/CHANGELOG.md +36 -32
- package/dist/types/chrome/context-map.d.ts +15 -0
- package/dist/types/chrome/context-presentation.d.ts +48 -0
- package/dist/types/chrome/context-view-model.d.ts +77 -0
- package/dist/types/overlays/advisor-config.d.ts +6 -0
- package/dist/types/overlays/ask-dialog.d.ts +12 -3
- package/dist/types/overlays/context-viewer-format.d.ts +42 -0
- package/dist/types/overlays/context-viewer-overview.d.ts +70 -0
- package/dist/types/overlays/context-viewer.d.ts +25 -0
- package/dist/types/overlays/hook-input.d.ts +1 -0
- package/dist/types/overlays/pause-screen.d.ts +13 -3
- package/dist/types/overlays/running-subagent-badge.d.ts +7 -1
- package/dist/types/status-line/component.d.ts +2 -2
- package/dist/types/status-line/context-usage.d.ts +15 -30
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/tools/ask.d.ts +4 -0
- package/dist/types/tools/fetch.d.ts +1 -0
- package/dist/types/tools/github.d.ts +3 -0
- package/dist/types/tools/read.d.ts +3 -0
- package/dist/types/tools/wait.d.ts +6 -0
- package/dist/types/tui.d.ts +2 -0
- package/package.json +9 -9
- package/src/chrome/context-map.ts +62 -0
- package/src/chrome/context-presentation.ts +26 -0
- package/src/chrome/context-view-model.ts +73 -0
- package/src/components/editor.ts +23 -0
- package/src/components/markdown.ts +14 -2
- package/src/overlays/advisor-config.ts +9 -2
- package/src/overlays/ask-dialog.ts +122 -35
- package/src/overlays/context-viewer-format.ts +145 -0
- package/src/overlays/context-viewer-overview.ts +381 -0
- package/src/overlays/context-viewer.ts +728 -0
- package/src/overlays/hook-input.ts +2 -0
- package/src/overlays/pause-screen.ts +166 -37
- package/src/overlays/running-subagent-badge.ts +12 -1
- package/src/render/output-pane.ts +3 -3
- package/src/status-line/component.ts +6 -4
- package/src/status-line/context-usage.ts +56 -580
- package/src/theme/symbols.ts +16 -0
- package/src/tools/ask.ts +4 -0
- package/src/tools/bash.ts +5 -23
- package/src/tools/fetch.ts +1 -0
- package/src/tools/github.ts +23 -3
- package/src/tools/read.ts +3 -1
- package/src/tools/wait.ts +6 -0
- package/src/tui.ts +23 -3
|
@@ -85,6 +85,7 @@ export interface GhRunWatchFailedLogDetails {
|
|
|
85
85
|
conclusion?: string;
|
|
86
86
|
tail?: string;
|
|
87
87
|
available: boolean;
|
|
88
|
+
unavailableReason?: string;
|
|
88
89
|
}
|
|
89
90
|
/** Live workflow watcher display snapshot. */
|
|
90
91
|
export interface GhRunWatchViewDetails {
|
|
@@ -130,6 +131,8 @@ export interface GhFailedJobLog {
|
|
|
130
131
|
full?: string;
|
|
131
132
|
tail?: string;
|
|
132
133
|
available: boolean;
|
|
134
|
+
unavailableReason?: string;
|
|
135
|
+
truncated?: boolean;
|
|
133
136
|
}
|
|
134
137
|
/** Choose the terminal conclusion or current job state. */
|
|
135
138
|
export declare function formatJobState(job: GhRunJobSnapshot): string;
|
|
@@ -29,7 +29,10 @@ export interface ReadToolDetails {
|
|
|
29
29
|
suffixResolution?: {
|
|
30
30
|
from: string;
|
|
31
31
|
to: string;
|
|
32
|
+
raw?: boolean;
|
|
32
33
|
};
|
|
34
|
+
/** Raw source output keeps descriptive diagnostics in details, not in the body. */
|
|
35
|
+
raw?: boolean;
|
|
33
36
|
url?: string;
|
|
34
37
|
finalUrl?: string;
|
|
35
38
|
contentType?: string;
|
|
@@ -55,6 +55,12 @@ export interface JobSnapshot {
|
|
|
55
55
|
* on collision, else the job id itself. See {@link AsyncJob.agentId}.
|
|
56
56
|
*/
|
|
57
57
|
agentUrlId?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Whether this job's turn published `<agentUrlId>.md`. False where the job
|
|
60
|
+
* body reported that it wrote none, so `agent://` still holds an earlier
|
|
61
|
+
* turn's output; undefined where the body does not report it.
|
|
62
|
+
*/
|
|
63
|
+
agentOutputPublished?: boolean;
|
|
58
64
|
}
|
|
59
65
|
/** Outcome of cancelling one background job. */
|
|
60
66
|
export type CancelStatus = "cancelled" | "not_found" | "already_completed";
|
package/dist/types/tui.d.ts
CHANGED
|
@@ -363,6 +363,8 @@ export declare class TUI extends Container {
|
|
|
363
363
|
* observers (live stream publisher, session recorder) coexist.
|
|
364
364
|
*/
|
|
365
365
|
addPaintListener(listener: PaintListener): () => void;
|
|
366
|
+
/** Observe actual ANSI frame writes, including transient resize paints; returns the unsubscribe. */
|
|
367
|
+
addFrameWriteListener(listener: (data: string) => void): () => void;
|
|
366
368
|
/** Install the product-owned bounded frame provider. */
|
|
367
369
|
setFrameProvider(provider: TerminalFrameProvider | undefined): void;
|
|
368
370
|
get fullRedraws(): number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-tui",
|
|
4
|
-
"version": "18.13.
|
|
4
|
+
"version": "18.13.2",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": {
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"gen:glyphs": "bun scripts/gen-glyphs.ts"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@oh-my-pi/omptype": "18.13.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "18.13.
|
|
46
|
-
"@oh-my-pi/pi-ai": "18.13.
|
|
47
|
-
"@oh-my-pi/pi-catalog": "18.13.
|
|
48
|
-
"@oh-my-pi/pi-natives": "18.13.
|
|
49
|
-
"@oh-my-pi/pi-utils": "18.13.
|
|
50
|
-
"@oh-my-pi/pi-wire": "18.13.
|
|
51
|
-
"@oh-my-pi/snapcompact": "18.13.
|
|
44
|
+
"@oh-my-pi/omptype": "18.13.2",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "18.13.2",
|
|
46
|
+
"@oh-my-pi/pi-ai": "18.13.2",
|
|
47
|
+
"@oh-my-pi/pi-catalog": "18.13.2",
|
|
48
|
+
"@oh-my-pi/pi-natives": "18.13.2",
|
|
49
|
+
"@oh-my-pi/pi-utils": "18.13.2",
|
|
50
|
+
"@oh-my-pi/pi-wire": "18.13.2",
|
|
51
|
+
"@oh-my-pi/snapcompact": "18.13.2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Pure occupancy calculations for contiguous token segments, independent of themes and renderers. */
|
|
2
|
+
export interface ContextMapSegment<T> {
|
|
3
|
+
readonly id: T;
|
|
4
|
+
readonly tokens: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ContextMapCell<T> {
|
|
8
|
+
readonly id: T;
|
|
9
|
+
readonly full: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Lays `segments` out in order over a `columns` × `rows` grid representing `windowTokens`; each cell takes the
|
|
14
|
+
* segment covering most of it and is `full` at 70% coverage or more. Returns `[]` when the window or grid
|
|
15
|
+
* size is unusable, and omits cells no segment touches.
|
|
16
|
+
*/
|
|
17
|
+
export function planContextMap<T>(
|
|
18
|
+
segments: readonly ContextMapSegment<T>[],
|
|
19
|
+
windowTokens: number,
|
|
20
|
+
columns: number,
|
|
21
|
+
rows: number,
|
|
22
|
+
): ContextMapCell<T>[] {
|
|
23
|
+
if (
|
|
24
|
+
!Number.isFinite(windowTokens) ||
|
|
25
|
+
windowTokens <= 0 ||
|
|
26
|
+
!Number.isInteger(columns) ||
|
|
27
|
+
!Number.isInteger(rows) ||
|
|
28
|
+
columns <= 0 ||
|
|
29
|
+
rows <= 0
|
|
30
|
+
)
|
|
31
|
+
return [];
|
|
32
|
+
const cellCount = columns * rows;
|
|
33
|
+
const tokensPerCell = windowTokens / cellCount;
|
|
34
|
+
const ranges: { id: T; start: number; end: number }[] = [];
|
|
35
|
+
let cursor = 0;
|
|
36
|
+
for (const segment of segments) {
|
|
37
|
+
if (!Number.isFinite(segment.tokens) || segment.tokens <= 0) continue;
|
|
38
|
+
const end = Math.min(windowTokens, cursor + segment.tokens);
|
|
39
|
+
if (end > cursor) ranges.push({ id: segment.id, start: cursor, end });
|
|
40
|
+
cursor = end;
|
|
41
|
+
if (cursor >= windowTokens) break;
|
|
42
|
+
}
|
|
43
|
+
const cells: ContextMapCell<T>[] = [];
|
|
44
|
+
let first = 0;
|
|
45
|
+
for (let index = 0; index < cellCount; index++) {
|
|
46
|
+
const start = index * tokensPerCell;
|
|
47
|
+
const end = (index + 1) * tokensPerCell;
|
|
48
|
+
while (first < ranges.length && ranges[first]!.end <= start) first++;
|
|
49
|
+
let winner: T | undefined;
|
|
50
|
+
let overlap = 0;
|
|
51
|
+
for (let part = first; part < ranges.length && ranges[part]!.start < end; part++) {
|
|
52
|
+
const range = ranges[part]!;
|
|
53
|
+
const covered = Math.min(end, range.end) - Math.max(start, range.start);
|
|
54
|
+
if (covered > overlap) {
|
|
55
|
+
overlap = covered;
|
|
56
|
+
winner = range.id;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (winner !== undefined) cells.push({ id: winner, full: overlap / tokensPerCell >= 0.7 });
|
|
60
|
+
}
|
|
61
|
+
return cells;
|
|
62
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ThemeColor } from "../theme";
|
|
2
|
+
import type { SymbolKey } from "../theme/symbols";
|
|
3
|
+
import type { ContextCategoryId } from "./context-view-model";
|
|
4
|
+
|
|
5
|
+
/** Shared category styles for maps and interactive legends; resolve glyphs at render time. */
|
|
6
|
+
const SYSTEM = { color: "accent", symbol: "context.content" } as const;
|
|
7
|
+
const DETAILS = { color: "customMessageLabel", symbol: "context.content" } as const;
|
|
8
|
+
const TOOLS = { color: "warning", symbol: "context.content" } as const;
|
|
9
|
+
const SKILLS = { color: "success", symbol: "context.content" } as const;
|
|
10
|
+
const MESSAGES = { color: "userMessageText", symbol: "context.messages" } as const;
|
|
11
|
+
const OUTPUT = { color: "muted", symbol: "context.messages" } as const;
|
|
12
|
+
export const CONTEXT_PRESENTATION = {
|
|
13
|
+
"system-prompt": SYSTEM,
|
|
14
|
+
skills: SKILLS,
|
|
15
|
+
"built-in-tools": TOOLS,
|
|
16
|
+
"custom-tools": DETAILS,
|
|
17
|
+
// Shares the System Prompt color; the message glyph tells them apart in the map.
|
|
18
|
+
"user-messages": { color: "accent", symbol: "context.messages" },
|
|
19
|
+
"assistant-messages": MESSAGES,
|
|
20
|
+
"assistant-thinking": DETAILS,
|
|
21
|
+
"tool-calls": TOOLS,
|
|
22
|
+
"tool-output": OUTPUT,
|
|
23
|
+
buffer: { color: "warning", symbol: "context.buffer" },
|
|
24
|
+
free: { color: "dim", symbol: "context.free" },
|
|
25
|
+
} as const satisfies Record<ContextPresentationId, { color: ThemeColor; symbol: SymbolKey }>;
|
|
26
|
+
export type ContextPresentationId = ContextCategoryId | "buffer" | "free";
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/** Context snapshot shapes shared by the session snapshot builder and the context viewer. */
|
|
2
|
+
import type { ContextBreakdown } from "../status-line/context-usage";
|
|
3
|
+
|
|
4
|
+
interface ContextCategoryDescriptor {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly label: string;
|
|
7
|
+
/** Overview row label when the Overview weight differs from the category's content. */
|
|
8
|
+
readonly overviewLabel?: string;
|
|
9
|
+
/** Listed with its weight but never opened. */
|
|
10
|
+
readonly openable?: false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Context categories in display order. */
|
|
14
|
+
export const CONTEXT_CATEGORIES = [
|
|
15
|
+
// The Overview weight excludes the Skills listing; content views keep complete system blocks.
|
|
16
|
+
{ id: "system-prompt", label: "System Prompt", overviewLabel: "System Prompt (excluding Skills)" },
|
|
17
|
+
// An estimate of the prompt's skill listing, without entries of its own.
|
|
18
|
+
{ id: "skills", label: "Skills", openable: false },
|
|
19
|
+
{ id: "built-in-tools", label: "Built-in Tools" },
|
|
20
|
+
{ id: "custom-tools", label: "Custom Tools" },
|
|
21
|
+
{ id: "user-messages", label: "User / Developer Messages" },
|
|
22
|
+
{ id: "assistant-messages", label: "Assistant Messages" },
|
|
23
|
+
{ id: "assistant-thinking", label: "Assistant Thinking" },
|
|
24
|
+
{ id: "tool-calls", label: "Tool Calls" },
|
|
25
|
+
{ id: "tool-output", label: "Tool Output" },
|
|
26
|
+
] as const satisfies readonly ContextCategoryDescriptor[];
|
|
27
|
+
|
|
28
|
+
export type ContextCategoryId = (typeof CONTEXT_CATEGORIES)[number]["id"];
|
|
29
|
+
|
|
30
|
+
const DESCRIPTORS_BY_ID = new Map<ContextCategoryId, ContextCategoryDescriptor>(
|
|
31
|
+
CONTEXT_CATEGORIES.map(descriptor => [descriptor.id, descriptor]),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
/** Descriptor of a category id: its label, optional Overview label, and whether it can be opened. */
|
|
35
|
+
export function contextCategoryDescriptor(id: ContextCategoryId): ContextCategoryDescriptor {
|
|
36
|
+
return DESCRIPTORS_BY_ID.get(id)!;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ContextThinkingGroup {
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly label: string;
|
|
42
|
+
readonly tokens: number;
|
|
43
|
+
readonly interrupted?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ContextViewEntry {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
readonly label: string;
|
|
49
|
+
readonly text: string;
|
|
50
|
+
/** Aggregation weight for the unscaled replay estimate; shared blocks contribute through their group. */
|
|
51
|
+
readonly tokens: number;
|
|
52
|
+
readonly interrupted?: boolean;
|
|
53
|
+
readonly thinkingGroup?: ContextThinkingGroup;
|
|
54
|
+
readonly path?: string;
|
|
55
|
+
readonly info?: string;
|
|
56
|
+
readonly timestamp?: number;
|
|
57
|
+
readonly callId?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ContextViewCategory {
|
|
61
|
+
id: ContextCategoryId;
|
|
62
|
+
key?: string;
|
|
63
|
+
label: string;
|
|
64
|
+
/** Overview attribution weight, not reported usage; may differ from the entry sum (e.g. Skills subtraction). */
|
|
65
|
+
tokens: number;
|
|
66
|
+
entries: ContextViewEntry[];
|
|
67
|
+
children?: ContextViewCategory[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ContextViewData {
|
|
71
|
+
readonly breakdown: ContextBreakdown;
|
|
72
|
+
readonly categories: readonly ContextViewCategory[];
|
|
73
|
+
}
|
package/src/components/editor.ts
CHANGED
|
@@ -2431,10 +2431,12 @@ export class Editor implements Component, Focusable {
|
|
|
2431
2431
|
// Word left
|
|
2432
2432
|
this.#resetKillSequence();
|
|
2433
2433
|
this.#moveWordBackwards();
|
|
2434
|
+
this.#dismissAutocomplete();
|
|
2434
2435
|
} else if (kb.matchesCanonical(canonical, "tui.editor.cursorWordRight")) {
|
|
2435
2436
|
// Word right
|
|
2436
2437
|
this.#resetKillSequence();
|
|
2437
2438
|
this.#moveWordForwards();
|
|
2439
|
+
this.#dismissAutocomplete();
|
|
2438
2440
|
}
|
|
2439
2441
|
// Arrow keys
|
|
2440
2442
|
else if (kb.matchesCanonical(canonical, "tui.editor.cursorUp")) {
|
|
@@ -3900,6 +3902,9 @@ export class Editor implements Component, Focusable {
|
|
|
3900
3902
|
const dropSpace = this.#hasProvisionalSpace();
|
|
3901
3903
|
this.#historyIndex = -1; // Exit history browsing mode
|
|
3902
3904
|
this.#resetKillSequence();
|
|
3905
|
+
// The cursor leaves the trigger token's line, so any open popup is stale:
|
|
3906
|
+
// keeping it would float on the new line and Enter would submit past it.
|
|
3907
|
+
this.#dismissAutocomplete();
|
|
3903
3908
|
this.#recordUndoState();
|
|
3904
3909
|
|
|
3905
3910
|
const currentLine = this.#state.lines[this.#state.cursorLine] || "";
|
|
@@ -4201,23 +4206,27 @@ export class Editor implements Component, Focusable {
|
|
|
4201
4206
|
|
|
4202
4207
|
#moveToLineStart(): void {
|
|
4203
4208
|
this.#resetKillSequence();
|
|
4209
|
+
this.#dismissAutocomplete();
|
|
4204
4210
|
this.#setCursorCol(0);
|
|
4205
4211
|
}
|
|
4206
4212
|
|
|
4207
4213
|
#moveToLineEnd(): void {
|
|
4208
4214
|
this.#resetKillSequence();
|
|
4215
|
+
this.#dismissAutocomplete();
|
|
4209
4216
|
const currentLine = this.#state.lines[this.#state.cursorLine] || "";
|
|
4210
4217
|
this.#setCursorCol(currentLine.length);
|
|
4211
4218
|
}
|
|
4212
4219
|
|
|
4213
4220
|
#moveToMessageStart(): void {
|
|
4214
4221
|
this.#resetKillSequence();
|
|
4222
|
+
this.#dismissAutocomplete();
|
|
4215
4223
|
this.#state.cursorLine = 0;
|
|
4216
4224
|
this.#setCursorCol(0);
|
|
4217
4225
|
}
|
|
4218
4226
|
|
|
4219
4227
|
#moveToMessageEnd(): void {
|
|
4220
4228
|
this.#resetKillSequence();
|
|
4229
|
+
this.#dismissAutocomplete();
|
|
4221
4230
|
this.#state.cursorLine = this.#state.lines.length - 1;
|
|
4222
4231
|
const currentLine = this.#state.lines[this.#state.cursorLine] || "";
|
|
4223
4232
|
this.#setCursorCol(currentLine.length);
|
|
@@ -4697,6 +4706,7 @@ export class Editor implements Component, Focusable {
|
|
|
4697
4706
|
|
|
4698
4707
|
#moveCursor(deltaLine: number, deltaCol: number): void {
|
|
4699
4708
|
this.#resetKillSequence();
|
|
4709
|
+
this.#dismissAutocomplete();
|
|
4700
4710
|
const visualLines = this.#buildVisualLineMap(this.#caretRowWidth);
|
|
4701
4711
|
const currentVisualLine = this.#findCurrentVisualLine(visualLines);
|
|
4702
4712
|
|
|
@@ -4749,6 +4759,7 @@ export class Editor implements Component, Focusable {
|
|
|
4749
4759
|
|
|
4750
4760
|
#pageScroll(direction: -1 | 1): void {
|
|
4751
4761
|
this.#resetKillSequence();
|
|
4762
|
+
this.#dismissAutocomplete();
|
|
4752
4763
|
const visualLines = this.#buildVisualLineMap(this.#caretRowWidth);
|
|
4753
4764
|
const currentVisualLine = this.#findCurrentVisualLine(visualLines);
|
|
4754
4765
|
const step = this.#getPageScrollStep(visualLines.length);
|
|
@@ -4779,6 +4790,7 @@ export class Editor implements Component, Focusable {
|
|
|
4779
4790
|
*/
|
|
4780
4791
|
#jumpToChar(char: string, direction: "forward" | "backward"): void {
|
|
4781
4792
|
this.#resetKillSequence();
|
|
4793
|
+
this.#dismissAutocomplete();
|
|
4782
4794
|
const isForward = direction === "forward";
|
|
4783
4795
|
const lines = this.#state.lines;
|
|
4784
4796
|
|
|
@@ -5195,6 +5207,17 @@ export class Editor implements Component, Focusable {
|
|
|
5195
5207
|
}
|
|
5196
5208
|
}
|
|
5197
5209
|
|
|
5210
|
+
/**
|
|
5211
|
+
* Close the popup when the cursor leaves the token it was opened for (newline,
|
|
5212
|
+
* pure cursor motion). Its prefix no longer matches the text before the cursor,
|
|
5213
|
+
* so it could neither accept nor refresh and would linger stale.
|
|
5214
|
+
*/
|
|
5215
|
+
#dismissAutocomplete(): void {
|
|
5216
|
+
if (this.#autocompleteState === null) return;
|
|
5217
|
+
this.#cancelAutocomplete();
|
|
5218
|
+
this.onAutocompleteUpdate?.();
|
|
5219
|
+
}
|
|
5220
|
+
|
|
5198
5221
|
/**
|
|
5199
5222
|
* Whether an autocomplete popup is on screen. An `@` list narrowed to no match
|
|
5200
5223
|
* while its refresh is pending stays open internally but is hidden, so it does
|
|
@@ -4346,7 +4346,13 @@ export class Markdown implements Component {
|
|
|
4346
4346
|
|
|
4347
4347
|
// Process item tokens; nested-list lines arrive structurally tagged and
|
|
4348
4348
|
// already carry their own full indent.
|
|
4349
|
-
const itemLines = this.#renderListItem(
|
|
4349
|
+
const itemLines = this.#renderListItem(
|
|
4350
|
+
item.tokens || [],
|
|
4351
|
+
depth,
|
|
4352
|
+
width,
|
|
4353
|
+
Math.max(1, width - visibleWidth(continuationIndent)),
|
|
4354
|
+
styleContext,
|
|
4355
|
+
);
|
|
4350
4356
|
|
|
4351
4357
|
if (itemLines.length > 0) {
|
|
4352
4358
|
const firstLine = itemLines[0]!;
|
|
@@ -4398,11 +4404,13 @@ export class Markdown implements Component {
|
|
|
4398
4404
|
tokens: Token[],
|
|
4399
4405
|
parentDepth: number,
|
|
4400
4406
|
width: number,
|
|
4407
|
+
contentWidth: number,
|
|
4401
4408
|
styleContext?: InlineStyleContext,
|
|
4402
4409
|
): RenderedListItemLine[] {
|
|
4403
4410
|
const lines: RenderedListItemLine[] = [];
|
|
4404
4411
|
|
|
4405
|
-
for (
|
|
4412
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
4413
|
+
const token = tokens[i]!;
|
|
4406
4414
|
if (token.type === "list") {
|
|
4407
4415
|
// Nested list - render with one additional indent level
|
|
4408
4416
|
// These lines carry their own indent, so tag them for pass-through
|
|
@@ -4442,6 +4450,10 @@ export class Markdown implements Component {
|
|
|
4442
4450
|
lines.push({ ...bodyLine, nested: false });
|
|
4443
4451
|
}
|
|
4444
4452
|
lines.push({ text: this.#theme.codeBlockBorder("```"), nested: false });
|
|
4453
|
+
} else if (token.type === "table") {
|
|
4454
|
+
for (const row of this.#renderTable(token as TableToken, contentWidth, tokens[i + 1]?.type, styleContext)) {
|
|
4455
|
+
lines.push({ text: row, nested: false });
|
|
4456
|
+
}
|
|
4445
4457
|
} else if (isMathToken(token)) {
|
|
4446
4458
|
// Display math block inside a list item: stack fractions / matrix rows.
|
|
4447
4459
|
const apply = styleContext?.applyText ?? ((t: string) => this.#applyDefaultStyle(t));
|
|
@@ -64,10 +64,11 @@ import { getThinkingLevelMetadata, parseThinkingLevel } from "../thinking";
|
|
|
64
64
|
|
|
65
65
|
export const ADVISOR_REVIEW_MODES = ["turn", "agent-end"] as const;
|
|
66
66
|
export const ADVISOR_SYNC_BACKLOG_MODES = ["off", "1", "3", "5", "strict"] as const;
|
|
67
|
+
export const ADVISOR_SESSION_SCOPES = ["main", "subagent", "all"] as const;
|
|
67
68
|
|
|
68
69
|
export type AdvisorReviewMode = (typeof ADVISOR_REVIEW_MODES)[number];
|
|
69
70
|
export type AdvisorSyncBacklog = (typeof ADVISOR_SYNC_BACKLOG_MODES)[number];
|
|
70
|
-
|
|
71
|
+
export type AdvisorSessionScope = (typeof ADVISOR_SESSION_SCOPES)[number];
|
|
71
72
|
/** One advisor declared in `WATCHDOG.yml`; its instructions specialize the shared baseline. */
|
|
72
73
|
export interface AdvisorConfig {
|
|
73
74
|
name: string;
|
|
@@ -83,6 +84,10 @@ export interface AdvisorConfig {
|
|
|
83
84
|
reviewMode?: AdvisorReviewMode;
|
|
84
85
|
reviewInterval?: number;
|
|
85
86
|
syncBacklog?: AdvisorSyncBacklog;
|
|
87
|
+
/** Which session kinds this advisor attaches to (`main`, `subagent`, or `all`; defaults to `all`). */
|
|
88
|
+
scope?: AdvisorSessionScope;
|
|
89
|
+
/** Whether primary assistant thinking blocks are included in updates sent to this advisor (defaults to `true`). */
|
|
90
|
+
includeReasoning?: boolean;
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
/** Which level a `WATCHDOG.yml` lives at: the project root or the user agent dir. */
|
|
@@ -1202,7 +1207,9 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1202
1207
|
advisor.syncBacklog === undefined &&
|
|
1203
1208
|
!advisor.instructions?.trim() &&
|
|
1204
1209
|
advisor.enabled !== false &&
|
|
1205
|
-
advisor.maxNotesPerUpdate === undefined
|
|
1210
|
+
advisor.maxNotesPerUpdate === undefined &&
|
|
1211
|
+
advisor.scope === undefined &&
|
|
1212
|
+
advisor.includeReasoning === undefined
|
|
1206
1213
|
);
|
|
1207
1214
|
}
|
|
1208
1215
|
|