amness 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +237 -2
- package/dist/cli/acpcli.d.ts +7 -0
- package/dist/cli/acpcli.js +14 -0
- package/dist/cli/amness.d.ts +2 -0
- package/dist/cli/amness.js +694 -0
- package/dist/cli/benchcli.d.ts +5 -0
- package/dist/cli/benchcli.js +160 -0
- package/dist/cli/config.d.ts +79 -0
- package/dist/cli/config.js +111 -0
- package/dist/cli/demo.d.ts +13 -0
- package/dist/cli/demo.js +44 -0
- package/dist/cli/detect.d.ts +2 -0
- package/dist/cli/detect.js +20 -0
- package/dist/cli/evalcli.d.ts +15 -0
- package/dist/cli/evalcli.js +198 -0
- package/dist/cli/format.d.ts +5 -0
- package/dist/cli/format.js +55 -0
- package/dist/cli/headless.d.ts +2 -0
- package/dist/cli/headless.js +169 -0
- package/dist/cli/keystore.d.ts +9 -0
- package/dist/cli/keystore.js +108 -0
- package/dist/cli/model.d.ts +11 -0
- package/dist/cli/model.js +19 -0
- package/dist/cli/plugincli.d.ts +2 -0
- package/dist/cli/plugincli.js +176 -0
- package/dist/cli/schedulecli.d.ts +2 -0
- package/dist/cli/schedulecli.js +66 -0
- package/dist/cli/state.d.ts +11 -0
- package/dist/cli/state.js +19 -0
- package/dist/cli/tui/ansi.d.ts +38 -0
- package/dist/cli/tui/ansi.js +142 -0
- package/dist/cli/tui/app.d.ts +328 -0
- package/dist/cli/tui/app.js +1358 -0
- package/dist/cli/tui/blocks.d.ts +151 -0
- package/dist/cli/tui/blocks.js +128 -0
- package/dist/cli/tui/brand.d.ts +9 -0
- package/dist/cli/tui/brand.js +16 -0
- package/dist/cli/tui/canvas.d.ts +92 -0
- package/dist/cli/tui/canvas.js +199 -0
- package/dist/cli/tui/cards.d.ts +44 -0
- package/dist/cli/tui/cards.js +215 -0
- package/dist/cli/tui/clipboard.d.ts +5 -0
- package/dist/cli/tui/clipboard.js +29 -0
- package/dist/cli/tui/commands.d.ts +10 -0
- package/dist/cli/tui/commands.js +650 -0
- package/dist/cli/tui/complete.d.ts +39 -0
- package/dist/cli/tui/complete.js +113 -0
- package/dist/cli/tui/custom.d.ts +9 -0
- package/dist/cli/tui/custom.js +34 -0
- package/dist/cli/tui/diffview.d.ts +25 -0
- package/dist/cli/tui/diffview.js +130 -0
- package/dist/cli/tui/editor.d.ts +60 -0
- package/dist/cli/tui/editor.js +230 -0
- package/dist/cli/tui/full.d.ts +86 -0
- package/dist/cli/tui/full.js +630 -0
- package/dist/cli/tui/keys.d.ts +31 -0
- package/dist/cli/tui/keys.js +134 -0
- package/dist/cli/tui/markdown.d.ts +37 -0
- package/dist/cli/tui/markdown.js +155 -0
- package/dist/cli/tui/mentions.d.ts +15 -0
- package/dist/cli/tui/mentions.js +48 -0
- package/dist/cli/tui/modal.d.ts +26 -0
- package/dist/cli/tui/modal.js +107 -0
- package/dist/cli/tui/overlays.d.ts +98 -0
- package/dist/cli/tui/overlays.js +237 -0
- package/dist/cli/tui/pager.d.ts +15 -0
- package/dist/cli/tui/pager.js +66 -0
- package/dist/cli/tui/pricing.d.ts +9 -0
- package/dist/cli/tui/pricing.js +23 -0
- package/dist/cli/tui/rich.d.ts +16 -0
- package/dist/cli/tui/rich.js +72 -0
- package/dist/cli/tui/screen.d.ts +30 -0
- package/dist/cli/tui/screen.js +62 -0
- package/dist/cli/tui/session.d.ts +77 -0
- package/dist/cli/tui/session.js +103 -0
- package/dist/cli/tui/sidebar.d.ts +84 -0
- package/dist/cli/tui/sidebar.js +114 -0
- package/dist/cli/tui/text.d.ts +15 -0
- package/dist/cli/tui/text.js +94 -0
- package/dist/cli/tui/theme.d.ts +59 -0
- package/dist/cli/tui/theme.js +148 -0
- package/dist/cli/tui/themes.d.ts +56 -0
- package/dist/cli/tui/themes.js +80 -0
- package/dist/cli/tui/tokens.d.ts +39 -0
- package/dist/cli/tui/tokens.js +71 -0
- package/dist/cli/tui/view.d.ts +60 -0
- package/dist/cli/tui/view.js +178 -0
- package/dist/cli/ui.d.ts +34 -0
- package/dist/cli/ui.js +224 -0
- package/dist/src/acp.d.ts +28 -0
- package/dist/src/acp.js +111 -0
- package/dist/src/agents.d.ts +23 -0
- package/dist/src/agents.js +71 -0
- package/dist/src/anthropic.d.ts +30 -0
- package/dist/src/anthropic.js +91 -0
- package/dist/src/approver.d.ts +15 -0
- package/dist/src/approver.js +40 -0
- package/dist/src/bench.d.ts +67 -0
- package/dist/src/bench.js +201 -0
- package/dist/src/bundle.d.ts +36 -0
- package/dist/src/bundle.js +55 -0
- package/dist/src/chaos.d.ts +15 -0
- package/dist/src/chaos.js +26 -0
- package/dist/src/code.d.ts +187 -0
- package/dist/src/code.js +590 -0
- package/dist/src/codeindex.d.ts +65 -0
- package/dist/src/codeindex.js +300 -0
- package/dist/src/deep.d.ts +62 -0
- package/dist/src/deep.js +177 -0
- package/dist/src/diff.d.ts +8 -0
- package/dist/src/diff.js +74 -0
- package/dist/src/dynamic.d.ts +42 -0
- package/dist/src/dynamic.js +133 -0
- package/dist/src/embed.d.ts +8 -0
- package/dist/src/embed.js +25 -0
- package/dist/src/evalcases.d.ts +11 -0
- package/dist/src/evalcases.js +196 -0
- package/dist/src/evals.d.ts +197 -0
- package/dist/src/evals.js +340 -0
- package/dist/src/gitflow.d.ts +27 -0
- package/dist/src/gitflow.js +56 -0
- package/dist/src/grade.d.ts +42 -0
- package/dist/src/grade.js +96 -0
- package/dist/src/guidance.d.ts +15 -0
- package/dist/src/guidance.js +68 -0
- package/dist/src/hardcases.d.ts +2 -0
- package/dist/src/hardcases.js +94 -0
- package/dist/src/harness.d.ts +411 -0
- package/dist/src/harness.js +725 -0
- package/dist/src/hooks.d.ts +44 -0
- package/dist/src/hooks.js +116 -0
- package/dist/src/images.d.ts +13 -0
- package/dist/src/images.js +27 -0
- package/dist/src/index.d.ts +57 -0
- package/dist/src/index.js +57 -0
- package/dist/src/ledger.d.ts +58 -0
- package/dist/src/ledger.js +78 -0
- package/dist/src/live.d.ts +16 -0
- package/dist/src/live.js +80 -0
- package/dist/src/lsp.d.ts +31 -0
- package/dist/src/lsp.js +147 -0
- package/dist/src/memory.d.ts +128 -0
- package/dist/src/memory.js +390 -0
- package/dist/src/metrics.d.ts +3 -0
- package/dist/src/metrics.js +42 -0
- package/dist/src/mining.d.ts +49 -0
- package/dist/src/mining.js +126 -0
- package/dist/src/openai.d.ts +50 -0
- package/dist/src/openai.js +307 -0
- package/dist/src/parallel.d.ts +66 -0
- package/dist/src/parallel.js +135 -0
- package/dist/src/patch.d.ts +45 -0
- package/dist/src/patch.js +219 -0
- package/dist/src/permissions.d.ts +46 -0
- package/dist/src/permissions.js +245 -0
- package/dist/src/plugins.d.ts +148 -0
- package/dist/src/plugins.js +225 -0
- package/dist/src/pluginscan.d.ts +8 -0
- package/dist/src/pluginscan.js +20 -0
- package/dist/src/procs.d.ts +41 -0
- package/dist/src/procs.js +94 -0
- package/dist/src/profiles.d.ts +36 -0
- package/dist/src/profiles.js +61 -0
- package/dist/src/progress.d.ts +29 -0
- package/dist/src/progress.js +75 -0
- package/dist/src/prompts.d.ts +10 -0
- package/dist/src/prompts.js +28 -0
- package/dist/src/ratelimit.d.ts +34 -0
- package/dist/src/ratelimit.js +116 -0
- package/dist/src/replay.d.ts +25 -0
- package/dist/src/replay.js +99 -0
- package/dist/src/review.d.ts +20 -0
- package/dist/src/review.js +49 -0
- package/dist/src/route.d.ts +9 -0
- package/dist/src/route.js +30 -0
- package/dist/src/router.d.ts +61 -0
- package/dist/src/router.js +126 -0
- package/dist/src/sandbox.d.ts +13 -0
- package/dist/src/sandbox.js +68 -0
- package/dist/src/schedule.d.ts +20 -0
- package/dist/src/schedule.js +59 -0
- package/dist/src/schema.d.ts +13 -0
- package/dist/src/schema.js +36 -0
- package/dist/src/secrets.d.ts +10 -0
- package/dist/src/secrets.js +41 -0
- package/dist/src/shell.d.ts +34 -0
- package/dist/src/shell.js +95 -0
- package/dist/src/skills.d.ts +20 -0
- package/dist/src/skills.js +112 -0
- package/dist/src/snapshot.d.ts +20 -0
- package/dist/src/snapshot.js +93 -0
- package/dist/src/stats.d.ts +24 -0
- package/dist/src/stats.js +62 -0
- package/dist/src/strategies.d.ts +16 -0
- package/dist/src/strategies.js +35 -0
- package/dist/src/suites.d.ts +30 -0
- package/dist/src/suites.js +112 -0
- package/dist/src/trace.d.ts +63 -0
- package/dist/src/trace.js +153 -0
- package/dist/src/tune.d.ts +38 -0
- package/dist/src/tune.js +49 -0
- package/dist/src/web.d.ts +19 -0
- package/dist/src/web.js +56 -0
- package/dist/src/worktree.d.ts +24 -0
- package/dist/src/worktree.js +85 -0
- package/docs/agent-loop.md +222 -0
- package/docs/architecture.md +228 -0
- package/docs/bench.md +292 -0
- package/docs/budgets.md +185 -0
- package/docs/build-your-own-harness.md +424 -0
- package/docs/cookbook.md +375 -0
- package/docs/development.md +150 -0
- package/docs/evaluation.md +450 -0
- package/docs/features.md +1320 -0
- package/docs/getting-started.md +205 -0
- package/docs/headless.md +188 -0
- package/docs/images/approval.png +0 -0
- package/docs/images/chat.png +0 -0
- package/docs/images/daylight.png +0 -0
- package/docs/images/loop.png +0 -0
- package/docs/images/palette.png +0 -0
- package/docs/images/running.png +0 -0
- package/docs/images/subagent-done.png +0 -0
- package/docs/images/subagent-running.png +0 -0
- package/docs/images/welcome.png +0 -0
- package/docs/index.md +25 -0
- package/docs/library.md +267 -0
- package/docs/plugins.md +691 -0
- package/docs/providers.md +175 -0
- package/docs/safety.md +250 -0
- package/docs/usage.md +348 -0
- package/docs/why.md +155 -0
- package/docs/writing-guide.md +39 -0
- package/package.json +66 -4
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { Message } from "../../src/index.ts";
|
|
2
|
+
export type Edit = {
|
|
3
|
+
path: string;
|
|
4
|
+
created: boolean;
|
|
5
|
+
added: number;
|
|
6
|
+
removed: number;
|
|
7
|
+
diff: string;
|
|
8
|
+
};
|
|
9
|
+
export type Block = {
|
|
10
|
+
id: number;
|
|
11
|
+
kind: "user";
|
|
12
|
+
text: string;
|
|
13
|
+
note?: string;
|
|
14
|
+
queued?: boolean;
|
|
15
|
+
} | {
|
|
16
|
+
id: number;
|
|
17
|
+
kind: "assistant";
|
|
18
|
+
text: string;
|
|
19
|
+
streaming: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
id: number;
|
|
22
|
+
kind: "tool";
|
|
23
|
+
callId: string;
|
|
24
|
+
name: string;
|
|
25
|
+
args: string;
|
|
26
|
+
status: "running" | "ok" | "fail";
|
|
27
|
+
result?: string;
|
|
28
|
+
edit?: Edit;
|
|
29
|
+
agent?: string; /** call id of the subagent card this step belongs to */
|
|
30
|
+
parent?: string;
|
|
31
|
+
t0: number;
|
|
32
|
+
ms?: number;
|
|
33
|
+
expanded?: boolean; /** show every diff row, not just the first screenful */
|
|
34
|
+
more?: boolean;
|
|
35
|
+
} | {
|
|
36
|
+
id: number;
|
|
37
|
+
kind: "thinking";
|
|
38
|
+
text: string;
|
|
39
|
+
active: boolean;
|
|
40
|
+
t0: number;
|
|
41
|
+
ms?: number;
|
|
42
|
+
expanded?: boolean;
|
|
43
|
+
} | {
|
|
44
|
+
id: number;
|
|
45
|
+
kind: "notice";
|
|
46
|
+
level: "info" | "warn" | "error" | "ok";
|
|
47
|
+
text: string;
|
|
48
|
+
} | {
|
|
49
|
+
id: number;
|
|
50
|
+
kind: "summary";
|
|
51
|
+
text: string;
|
|
52
|
+
} | {
|
|
53
|
+
id: number;
|
|
54
|
+
kind: "raw";
|
|
55
|
+
lines: string[];
|
|
56
|
+
};
|
|
57
|
+
export type BlockKind = Block["kind"];
|
|
58
|
+
export declare class BlockStore {
|
|
59
|
+
blocks: Block[];
|
|
60
|
+
version: number;
|
|
61
|
+
private n;
|
|
62
|
+
private openAssistant?;
|
|
63
|
+
private openThinking?;
|
|
64
|
+
private add;
|
|
65
|
+
get(id: number): Block | undefined;
|
|
66
|
+
private last;
|
|
67
|
+
clear(): void;
|
|
68
|
+
addUser(text: string, note?: string, queued?: boolean): {
|
|
69
|
+
id: number;
|
|
70
|
+
kind: "user";
|
|
71
|
+
text: string;
|
|
72
|
+
note?: string;
|
|
73
|
+
queued?: boolean;
|
|
74
|
+
};
|
|
75
|
+
/** Append streamed assistant text (starts a new block if none is open). */
|
|
76
|
+
streamAssistant(delta: string): void;
|
|
77
|
+
/** The model's complete message (used when nothing was streamed). */
|
|
78
|
+
setAssistant(text: string): void;
|
|
79
|
+
endAssistant(): void;
|
|
80
|
+
streamThinking(delta: string): void;
|
|
81
|
+
endThinking(): void;
|
|
82
|
+
toolStart(id: string, name: string, args: string, agent?: string, parent?: string): {
|
|
83
|
+
id: number;
|
|
84
|
+
kind: "tool";
|
|
85
|
+
callId: string;
|
|
86
|
+
name: string;
|
|
87
|
+
args: string;
|
|
88
|
+
status: "running" | "ok" | "fail";
|
|
89
|
+
result?: string;
|
|
90
|
+
edit?: Edit;
|
|
91
|
+
agent?: string; /** call id of the subagent card this step belongs to */
|
|
92
|
+
parent?: string;
|
|
93
|
+
t0: number;
|
|
94
|
+
ms?: number;
|
|
95
|
+
expanded?: boolean; /** show every diff row, not just the first screenful */
|
|
96
|
+
more?: boolean;
|
|
97
|
+
};
|
|
98
|
+
/** The steps a subagent card ran, in order. */
|
|
99
|
+
kids(callId: string): {
|
|
100
|
+
id: number;
|
|
101
|
+
kind: "tool";
|
|
102
|
+
callId: string;
|
|
103
|
+
name: string;
|
|
104
|
+
args: string;
|
|
105
|
+
status: "running" | "ok" | "fail";
|
|
106
|
+
result?: string;
|
|
107
|
+
edit?: Edit;
|
|
108
|
+
agent?: string; /** call id of the subagent card this step belongs to */
|
|
109
|
+
parent?: string;
|
|
110
|
+
t0: number;
|
|
111
|
+
ms?: number;
|
|
112
|
+
expanded?: boolean; /** show every diff row, not just the first screenful */
|
|
113
|
+
more?: boolean;
|
|
114
|
+
}[];
|
|
115
|
+
tool(callId: string): Extract<Block, {
|
|
116
|
+
kind: "tool";
|
|
117
|
+
}> | undefined;
|
|
118
|
+
toolEnd(callId: string, result: string, edit?: Edit): void;
|
|
119
|
+
/** A turn has ended (finished, interrupted or failed): any tool card still "running" can never complete, so close it instead of leaving a spinner on screen. */
|
|
120
|
+
closeRunning(note?: string): number;
|
|
121
|
+
notice(level: "info" | "warn" | "error" | "ok", text: string): {
|
|
122
|
+
id: number;
|
|
123
|
+
kind: "notice";
|
|
124
|
+
level: "info" | "warn" | "error" | "ok";
|
|
125
|
+
text: string;
|
|
126
|
+
};
|
|
127
|
+
summary(text: string): {
|
|
128
|
+
id: number;
|
|
129
|
+
kind: "summary";
|
|
130
|
+
text: string;
|
|
131
|
+
};
|
|
132
|
+
raw(lines: string[]): {
|
|
133
|
+
id: number;
|
|
134
|
+
kind: "raw";
|
|
135
|
+
lines: string[];
|
|
136
|
+
};
|
|
137
|
+
toggle(id: number): void;
|
|
138
|
+
/** Every user message with its block index (for sticky headers and prompt jumping). */
|
|
139
|
+
prompts(): {
|
|
140
|
+
block: {
|
|
141
|
+
id: number;
|
|
142
|
+
kind: "user";
|
|
143
|
+
text: string;
|
|
144
|
+
note?: string;
|
|
145
|
+
queued?: boolean;
|
|
146
|
+
};
|
|
147
|
+
index: number;
|
|
148
|
+
}[];
|
|
149
|
+
/** Rebuild from a saved conversation (resume, undo, compact). Tool results are matched to their calls; edit diffs are reconstructed from the call arguments. */
|
|
150
|
+
loadMessages(messages: Message[]): void;
|
|
151
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { unifiedDiff } from "../../src/diff.js";
|
|
2
|
+
const failed = (r) => /^(ERROR|DENIED|REJECTED)/.test(r) || /^stopped: (interrupted|no progress|no measurable)/.test(r) || /^exit=(?!0\b)/.test(r);
|
|
3
|
+
export class BlockStore {
|
|
4
|
+
blocks = [];
|
|
5
|
+
version = 0;
|
|
6
|
+
n = 0;
|
|
7
|
+
openAssistant;
|
|
8
|
+
openThinking;
|
|
9
|
+
add(b) { const blk = { ...b, id: ++this.n }; this.blocks.push(blk); this.version++; return blk; }
|
|
10
|
+
get(id) { return this.blocks.find((b) => b.id === id); }
|
|
11
|
+
last(kind, open) { return open === undefined ? undefined : this.blocks.find((b) => b.id === open && b.kind === kind); }
|
|
12
|
+
clear() { this.blocks = []; this.openAssistant = this.openThinking = undefined; this.version++; }
|
|
13
|
+
addUser(text, note, queued) { this.endAssistant(); return this.add({ kind: "user", text, note, queued }); }
|
|
14
|
+
/** Append streamed assistant text (starts a new block if none is open). */
|
|
15
|
+
streamAssistant(delta) {
|
|
16
|
+
this.endThinking();
|
|
17
|
+
let b = this.last("assistant", this.openAssistant);
|
|
18
|
+
if (!b) {
|
|
19
|
+
b = this.add({ kind: "assistant", text: "", streaming: true });
|
|
20
|
+
this.openAssistant = b.id;
|
|
21
|
+
}
|
|
22
|
+
b.text += delta;
|
|
23
|
+
this.version++;
|
|
24
|
+
}
|
|
25
|
+
/** The model's complete message (used when nothing was streamed). */
|
|
26
|
+
setAssistant(text) { if (!this.last("assistant", this.openAssistant))
|
|
27
|
+
this.streamAssistant(text); }
|
|
28
|
+
endAssistant() { const b = this.last("assistant", this.openAssistant); if (b) {
|
|
29
|
+
b.streaming = false;
|
|
30
|
+
this.version++;
|
|
31
|
+
} this.openAssistant = undefined; }
|
|
32
|
+
streamThinking(delta) {
|
|
33
|
+
let b = this.last("thinking", this.openThinking);
|
|
34
|
+
if (!b) {
|
|
35
|
+
b = this.add({ kind: "thinking", text: "", active: true, t0: Date.now() });
|
|
36
|
+
this.openThinking = b.id;
|
|
37
|
+
}
|
|
38
|
+
b.text += delta;
|
|
39
|
+
this.version++;
|
|
40
|
+
}
|
|
41
|
+
endThinking() { const b = this.last("thinking", this.openThinking); if (b) {
|
|
42
|
+
b.active = false;
|
|
43
|
+
b.ms = Date.now() - b.t0;
|
|
44
|
+
this.version++;
|
|
45
|
+
} this.openThinking = undefined; }
|
|
46
|
+
toolStart(id, name, args, agent, parent) { this.endAssistant(); this.endThinking(); return this.add({ kind: "tool", callId: id, name, args, status: "running", agent, parent, t0: Date.now() }); }
|
|
47
|
+
/** The steps a subagent card ran, in order. */
|
|
48
|
+
kids(callId) { return this.blocks.filter((b) => b.kind === "tool" && b.parent === callId); }
|
|
49
|
+
tool(callId) { return [...this.blocks].reverse().find((b) => b.kind === "tool" && b.callId === callId); }
|
|
50
|
+
toolEnd(callId, result, edit) {
|
|
51
|
+
const b = this.tool(callId);
|
|
52
|
+
if (!b)
|
|
53
|
+
return;
|
|
54
|
+
b.result = result;
|
|
55
|
+
b.status = failed(result) ? "fail" : "ok";
|
|
56
|
+
b.ms = Date.now() - b.t0;
|
|
57
|
+
if (edit)
|
|
58
|
+
b.edit = edit;
|
|
59
|
+
this.version++;
|
|
60
|
+
}
|
|
61
|
+
/** A turn has ended (finished, interrupted or failed): any tool card still "running" can never complete, so close it instead of leaving a spinner on screen. */
|
|
62
|
+
closeRunning(note = "interrupted") {
|
|
63
|
+
let n = 0;
|
|
64
|
+
for (const b of this.blocks)
|
|
65
|
+
if (b.kind === "tool" && b.status === "running") {
|
|
66
|
+
b.status = "fail";
|
|
67
|
+
b.result = b.result ?? `(${note})`;
|
|
68
|
+
b.ms = Date.now() - b.t0;
|
|
69
|
+
n++;
|
|
70
|
+
}
|
|
71
|
+
if (n)
|
|
72
|
+
this.version++;
|
|
73
|
+
return n;
|
|
74
|
+
}
|
|
75
|
+
notice(level, text) { this.endAssistant(); return this.add({ kind: "notice", level, text }); }
|
|
76
|
+
summary(text) { this.endAssistant(); return this.add({ kind: "summary", text }); }
|
|
77
|
+
raw(lines) { return this.add({ kind: "raw", lines }); }
|
|
78
|
+
toggle(id) { const b = this.get(id); if (b && (b.kind === "tool" || b.kind === "thinking")) {
|
|
79
|
+
if (b.kind === "tool")
|
|
80
|
+
b.more = false;
|
|
81
|
+
b.expanded = !(b.expanded ?? (b.kind === "tool" && !!(b.edit || b.status === "fail")));
|
|
82
|
+
this.version++;
|
|
83
|
+
} }
|
|
84
|
+
/** Every user message with its block index (for sticky headers and prompt jumping). */
|
|
85
|
+
prompts() { return this.blocks.flatMap((b, i) => (b.kind === "user" ? [{ block: b, index: i }] : [])); }
|
|
86
|
+
/** Rebuild from a saved conversation (resume, undo, compact). Tool results are matched to their calls; edit diffs are reconstructed from the call arguments. */
|
|
87
|
+
loadMessages(messages) {
|
|
88
|
+
this.clear();
|
|
89
|
+
const results = new Map();
|
|
90
|
+
for (const m of messages)
|
|
91
|
+
if (m.role === "tool" && m.tool_call_id)
|
|
92
|
+
results.set(m.tool_call_id, m.content ?? "");
|
|
93
|
+
for (const m of messages) {
|
|
94
|
+
if (m.role === "user") {
|
|
95
|
+
const t = (m.content ?? "").split("\n\n<attached>")[0].split("\n\n## ")[0].replace(/^\[mode:[^\]]*\]\n\n/, "");
|
|
96
|
+
if (t.trim())
|
|
97
|
+
this.addUser(t);
|
|
98
|
+
}
|
|
99
|
+
else if (m.role === "assistant") {
|
|
100
|
+
if (m.content?.trim()) {
|
|
101
|
+
this.streamAssistant(m.content);
|
|
102
|
+
this.endAssistant();
|
|
103
|
+
}
|
|
104
|
+
for (const c of m.tool_calls ?? []) {
|
|
105
|
+
if (c.function.name === "finish")
|
|
106
|
+
continue;
|
|
107
|
+
const b = this.toolStart(c.id, c.function.name, c.function.arguments), res = results.get(c.id);
|
|
108
|
+
let edit;
|
|
109
|
+
try {
|
|
110
|
+
const a = JSON.parse(c.function.arguments);
|
|
111
|
+
if (c.function.name === "edit_file" && a.old !== undefined)
|
|
112
|
+
edit = { path: a.path, created: false, ...(({ added, removed, diff }) => ({ added, removed, diff }))(unifiedDiff(a.path, a.old, a.new ?? "")) };
|
|
113
|
+
else if (c.function.name === "write_file")
|
|
114
|
+
edit = { path: a.path, created: true, ...(({ added, removed, diff }) => ({ added, removed, diff }))(unifiedDiff(a.path, null, a.content ?? "")) };
|
|
115
|
+
}
|
|
116
|
+
catch { /* unparsable arguments: show the call without a diff */ }
|
|
117
|
+
if (res !== undefined) {
|
|
118
|
+
this.toolEnd(c.id, res, res && !failed(res) ? edit : undefined);
|
|
119
|
+
b.ms = undefined;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
b.status = "ok";
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Theme } from "./themes.ts";
|
|
2
|
+
/** Provider/model identity (glyph + colour) for the active theme. */
|
|
3
|
+
export declare function brandOfModel(model: string, provider: string, t: Theme): {
|
|
4
|
+
icon: string;
|
|
5
|
+
color: number;
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
/** Pixel mascot + wordmark (plain text; colour is applied per theme). */
|
|
9
|
+
export declare const LOGO_ART: string[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Provider/model identity (glyph + colour) for the active theme. */
|
|
2
|
+
export function brandOfModel(model, provider, t) {
|
|
3
|
+
if (/claude|fable|mythos/i.test(model) || provider === "anthropic")
|
|
4
|
+
return { icon: "✻", color: 0xd97757, name: "Claude" };
|
|
5
|
+
if (/gpt|o[134]-|openai/i.test(model) || provider === "openai")
|
|
6
|
+
return { icon: "◈", color: 0x10a37f, name: "OpenAI" };
|
|
7
|
+
if (/llama|qwen|mistral|gemma|phi|deepseek|ollama/i.test(model) || provider === "ollama")
|
|
8
|
+
return { icon: "⬢", color: t.dim, name: "Local" };
|
|
9
|
+
return { icon: "◆", color: t.info, name: "Custom" };
|
|
10
|
+
}
|
|
11
|
+
/** Pixel mascot + wordmark (plain text; colour is applied per theme). */
|
|
12
|
+
export const LOGO_ART = [
|
|
13
|
+
" ▗▄▄▄▄▄▄▖",
|
|
14
|
+
" █ ◖ ◗ █ ▄▀█ █▀▄▀█ █▄ █ █▀▀ █▀ █▀",
|
|
15
|
+
" ▝▀▀▀▀▀▀▘ █▀█ █ ▀ █ █ ▀█ ██▄ ▄█ ▄█",
|
|
16
|
+
];
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type Cell } from "./ansi.ts";
|
|
2
|
+
export type Style = {
|
|
3
|
+
fg?: number;
|
|
4
|
+
bg?: number;
|
|
5
|
+
attr?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const BORDERS: {
|
|
8
|
+
readonly round: {
|
|
9
|
+
readonly tl: "╭";
|
|
10
|
+
readonly tr: "╮";
|
|
11
|
+
readonly bl: "╰";
|
|
12
|
+
readonly br: "╯";
|
|
13
|
+
readonly h: "─";
|
|
14
|
+
readonly v: "│";
|
|
15
|
+
};
|
|
16
|
+
readonly square: {
|
|
17
|
+
readonly tl: "┌";
|
|
18
|
+
readonly tr: "┐";
|
|
19
|
+
readonly bl: "└";
|
|
20
|
+
readonly br: "┘";
|
|
21
|
+
readonly h: "─";
|
|
22
|
+
readonly v: "│";
|
|
23
|
+
};
|
|
24
|
+
readonly thick: {
|
|
25
|
+
readonly tl: "┏";
|
|
26
|
+
readonly tr: "┓";
|
|
27
|
+
readonly bl: "┗";
|
|
28
|
+
readonly br: "┛";
|
|
29
|
+
readonly h: "━";
|
|
30
|
+
readonly v: "┃";
|
|
31
|
+
};
|
|
32
|
+
readonly double: {
|
|
33
|
+
readonly tl: "╔";
|
|
34
|
+
readonly tr: "╗";
|
|
35
|
+
readonly bl: "╚";
|
|
36
|
+
readonly br: "╝";
|
|
37
|
+
readonly h: "═";
|
|
38
|
+
readonly v: "║";
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
/** Reduce a 24-bit colour to what the terminal can show. level: 3 truecolor, 2 = 256 colours, 1 = 16 colours, 0 = none. */
|
|
42
|
+
export declare function quantize(c: number, level: 0 | 1 | 2 | 3, isBg?: boolean): number;
|
|
43
|
+
export declare class Canvas {
|
|
44
|
+
w: number;
|
|
45
|
+
h: number;
|
|
46
|
+
ch: string[];
|
|
47
|
+
fg: Int32Array;
|
|
48
|
+
bg: Int32Array;
|
|
49
|
+
attr: Uint8Array;
|
|
50
|
+
private prev?;
|
|
51
|
+
cursor: {
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
} | null;
|
|
55
|
+
level: 0 | 1 | 2 | 3;
|
|
56
|
+
defaultBg: number;
|
|
57
|
+
constructor(w: number, h: number, defaultBg?: number);
|
|
58
|
+
private i;
|
|
59
|
+
inside(x: number, y: number): boolean;
|
|
60
|
+
clear(bg?: number, fg?: number): void;
|
|
61
|
+
/** Fill a rectangle with a background (and optionally a glyph). */
|
|
62
|
+
fill(x: number, y: number, w: number, h: number, bg: number, ch?: string, fg?: number): void;
|
|
63
|
+
/** Blank whatever wide glyph occupies cell (x,y) (either half), so no orphaned half is left behind. */
|
|
64
|
+
private breakGlyph;
|
|
65
|
+
setCell(x: number, y: number, c: Cell, keepBg?: boolean): void;
|
|
66
|
+
/** Draw styled cells; returns the width used. Cells with the default background keep what is underneath. */
|
|
67
|
+
put(x: number, y: number, cells: Cell[], maxW?: number): number;
|
|
68
|
+
/** Draw a plain string with one style. */
|
|
69
|
+
text(x: number, y: number, s: string, st?: Style, maxW?: number): number;
|
|
70
|
+
/** Draw an ANSI string (as produced by the renderers). */
|
|
71
|
+
ansi(x: number, y: number, s: string, base?: Style, maxW?: number): number;
|
|
72
|
+
hline(x: number, y: number, w: number, ch: string, st: Style): void;
|
|
73
|
+
/** A bordered box; the interior is filled with `bg`. A title sits in the top border. */
|
|
74
|
+
box(x: number, y: number, w: number, h: number, o?: {
|
|
75
|
+
border?: number;
|
|
76
|
+
bg?: number;
|
|
77
|
+
style?: keyof typeof BORDERS;
|
|
78
|
+
title?: string;
|
|
79
|
+
titleFg?: number;
|
|
80
|
+
titleBg?: number;
|
|
81
|
+
}): void;
|
|
82
|
+
/** Fade everything inside a rectangle toward `toward` (modal backdrop). */
|
|
83
|
+
dim(x: number, y: number, w: number, h: number, t: number, toward: number, defFg: number, defBg: number): void;
|
|
84
|
+
/** Tint the background of a rectangle (selection, hover). */
|
|
85
|
+
tint(x: number, y: number, w: number, h: number, bg: number): void;
|
|
86
|
+
/** Text of a row range (for copy), trailing spaces trimmed. */
|
|
87
|
+
readRow(y: number, x0?: number, x1?: number): string;
|
|
88
|
+
/** Emit the minimal escape sequence that turns the previous frame into this one. `full` repaints everything. */
|
|
89
|
+
flush(full?: boolean): string;
|
|
90
|
+
/** Forget what is on the terminal (after a resize or an external clear) so the next flush repaints everything. */
|
|
91
|
+
invalidate(): void;
|
|
92
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// A character-cell canvas. Draw into it freely, then `flush()` emits only the cells that changed since the last frame
|
|
2
|
+
// (inside synchronized-output markers), which is what makes a full-screen UI flicker-free and cheap over SSH.
|
|
3
|
+
import { A, DEFAULT, mix, parseAnsi, sgrFor, toRgb } from "./ansi.js";
|
|
4
|
+
import { cpWidth } from "./text.js";
|
|
5
|
+
export const BORDERS = {
|
|
6
|
+
round: { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" },
|
|
7
|
+
square: { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" },
|
|
8
|
+
thick: { tl: "┏", tr: "┓", bl: "┗", br: "┛", h: "━", v: "┃" },
|
|
9
|
+
double: { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" },
|
|
10
|
+
};
|
|
11
|
+
/** Reduce a 24-bit colour to what the terminal can show. level: 3 truecolor, 2 = 256 colours, 1 = 16 colours, 0 = none. */
|
|
12
|
+
export function quantize(c, level, isBg = false) {
|
|
13
|
+
if (c === DEFAULT || level === 0 || c >= 0x1000000)
|
|
14
|
+
return level === 0 ? DEFAULT : c;
|
|
15
|
+
if (level === 3)
|
|
16
|
+
return c;
|
|
17
|
+
const r = (c >> 16) & 255, g = (c >> 8) & 255, b = c & 255;
|
|
18
|
+
if (level === 2) {
|
|
19
|
+
if (Math.abs(r - g) < 9 && Math.abs(g - b) < 9) {
|
|
20
|
+
const v = Math.round(((r + g + b) / 3 - 8) / 10);
|
|
21
|
+
return 0x1000000 + (v < 0 ? 16 : v > 23 ? 231 : 232 + v);
|
|
22
|
+
}
|
|
23
|
+
const q = (x) => Math.round((x / 255) * 5);
|
|
24
|
+
return 0x1000000 + 16 + 36 * q(r) + 6 * q(g) + q(b);
|
|
25
|
+
}
|
|
26
|
+
const bright = Math.max(r, g, b) > (isBg ? 230 : 190), idx = (r > 127 ? 1 : 0) | (g > 127 ? 2 : 0) | (b > 127 ? 4 : 0);
|
|
27
|
+
return 0x1000000 + (bright && !isBg ? 8 : 0) + (idx === 0 && !bright ? 0 : idx || 7);
|
|
28
|
+
}
|
|
29
|
+
export class Canvas {
|
|
30
|
+
w;
|
|
31
|
+
h;
|
|
32
|
+
ch;
|
|
33
|
+
fg;
|
|
34
|
+
bg;
|
|
35
|
+
attr;
|
|
36
|
+
prev;
|
|
37
|
+
cursor = null;
|
|
38
|
+
level = 3;
|
|
39
|
+
defaultBg;
|
|
40
|
+
constructor(w, h, defaultBg = DEFAULT) {
|
|
41
|
+
this.w = w;
|
|
42
|
+
this.h = h;
|
|
43
|
+
this.defaultBg = defaultBg;
|
|
44
|
+
this.ch = new Array(w * h).fill(" ");
|
|
45
|
+
this.fg = new Int32Array(w * h).fill(DEFAULT);
|
|
46
|
+
this.bg = new Int32Array(w * h).fill(defaultBg);
|
|
47
|
+
this.attr = new Uint8Array(w * h);
|
|
48
|
+
}
|
|
49
|
+
i(x, y) { return y * this.w + x; }
|
|
50
|
+
inside(x, y) { return x >= 0 && y >= 0 && x < this.w && y < this.h; }
|
|
51
|
+
clear(bg = this.defaultBg, fg = DEFAULT) { this.ch.fill(" "); this.fg.fill(fg); this.bg.fill(bg); this.attr.fill(0); }
|
|
52
|
+
/** Fill a rectangle with a background (and optionally a glyph). */
|
|
53
|
+
fill(x, y, w, h, bg, ch = " ", fg = DEFAULT) {
|
|
54
|
+
for (let yy = Math.max(0, y); yy < Math.min(this.h, y + h); yy++)
|
|
55
|
+
for (let xx = Math.max(0, x); xx < Math.min(this.w, x + w); xx++) {
|
|
56
|
+
this.breakGlyph(xx, yy);
|
|
57
|
+
const i = this.i(xx, yy);
|
|
58
|
+
this.ch[i] = ch;
|
|
59
|
+
this.bg[i] = bg;
|
|
60
|
+
this.fg[i] = fg;
|
|
61
|
+
this.attr[i] = 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Blank whatever wide glyph occupies cell (x,y) (either half), so no orphaned half is left behind. */
|
|
65
|
+
breakGlyph(x, y) {
|
|
66
|
+
const i = this.i(x, y);
|
|
67
|
+
if (this.ch[i] === "" && x > 0)
|
|
68
|
+
this.ch[i - 1] = " "; // overwriting the right half destroys the glyph
|
|
69
|
+
if (x + 1 < this.w && this.ch[i + 1] === "")
|
|
70
|
+
this.ch[i + 1] = " "; // overwriting the left half orphans the right half
|
|
71
|
+
}
|
|
72
|
+
setCell(x, y, c, keepBg = false) {
|
|
73
|
+
if (!this.inside(x, y))
|
|
74
|
+
return;
|
|
75
|
+
if (c.w === 2 && x + 1 >= this.w) {
|
|
76
|
+
c = { ...c, ch: " ", w: 1 };
|
|
77
|
+
} // a wide glyph never straddles the edge
|
|
78
|
+
this.breakGlyph(x, y);
|
|
79
|
+
if (c.w === 2)
|
|
80
|
+
this.breakGlyph(x + 1, y);
|
|
81
|
+
const i = this.i(x, y);
|
|
82
|
+
this.ch[i] = c.ch;
|
|
83
|
+
this.fg[i] = c.fg;
|
|
84
|
+
this.attr[i] = c.attr;
|
|
85
|
+
if (!keepBg || c.bg !== DEFAULT)
|
|
86
|
+
this.bg[i] = c.bg;
|
|
87
|
+
if (c.w === 2) {
|
|
88
|
+
const j = i + 1;
|
|
89
|
+
this.ch[j] = "";
|
|
90
|
+
this.fg[j] = c.fg;
|
|
91
|
+
this.bg[j] = this.bg[i];
|
|
92
|
+
this.attr[j] = c.attr;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Draw styled cells; returns the width used. Cells with the default background keep what is underneath. */
|
|
96
|
+
put(x, y, cells, maxW = this.w - x) {
|
|
97
|
+
let used = 0;
|
|
98
|
+
for (const c of cells) {
|
|
99
|
+
if (used + c.w > maxW)
|
|
100
|
+
break;
|
|
101
|
+
this.setCell(x + used, y, c, true);
|
|
102
|
+
used += c.w;
|
|
103
|
+
}
|
|
104
|
+
return used;
|
|
105
|
+
}
|
|
106
|
+
/** Draw a plain string with one style. */
|
|
107
|
+
text(x, y, s, st = {}, maxW = this.w - x) {
|
|
108
|
+
const cells = [];
|
|
109
|
+
for (const g of s) {
|
|
110
|
+
const w = cpWidth(g.codePointAt(0));
|
|
111
|
+
if (w === 0)
|
|
112
|
+
continue;
|
|
113
|
+
cells.push({ ch: g, w, fg: st.fg ?? DEFAULT, bg: st.bg ?? DEFAULT, attr: st.attr ?? 0 });
|
|
114
|
+
}
|
|
115
|
+
return this.put(x, y, cells, maxW);
|
|
116
|
+
}
|
|
117
|
+
/** Draw an ANSI string (as produced by the renderers). */
|
|
118
|
+
ansi(x, y, s, base = {}, maxW = this.w - x) { return this.put(x, y, parseAnsi(s, base), maxW); }
|
|
119
|
+
hline(x, y, w, ch, st) { for (let k = 0; k < w; k++)
|
|
120
|
+
this.text(x + k, y, ch, st); }
|
|
121
|
+
/** A bordered box; the interior is filled with `bg`. A title sits in the top border. */
|
|
122
|
+
box(x, y, w, h, o = {}) {
|
|
123
|
+
const b = BORDERS[o.style ?? "round"], st = { fg: o.border ?? DEFAULT, bg: o.bg ?? DEFAULT };
|
|
124
|
+
if (w < 2 || h < 2)
|
|
125
|
+
return;
|
|
126
|
+
if (o.bg !== undefined)
|
|
127
|
+
this.fill(x, y, w, h, o.bg);
|
|
128
|
+
this.text(x, y, b.tl + b.h.repeat(w - 2) + b.tr, st);
|
|
129
|
+
this.text(x, y + h - 1, b.bl + b.h.repeat(w - 2) + b.br, st);
|
|
130
|
+
for (let yy = y + 1; yy < y + h - 1; yy++) {
|
|
131
|
+
this.text(x, yy, b.v, st);
|
|
132
|
+
this.text(x + w - 1, yy, b.v, st);
|
|
133
|
+
}
|
|
134
|
+
if (o.title)
|
|
135
|
+
this.text(x + 2, y, ` ${o.title} `, { fg: o.titleFg ?? o.border, bg: o.titleBg ?? o.bg, attr: A.bold }, w - 4);
|
|
136
|
+
}
|
|
137
|
+
/** Fade everything inside a rectangle toward `toward` (modal backdrop). */
|
|
138
|
+
dim(x, y, w, h, t, toward, defFg, defBg) {
|
|
139
|
+
for (let yy = Math.max(0, y); yy < Math.min(this.h, y + h); yy++)
|
|
140
|
+
for (let xx = Math.max(0, x); xx < Math.min(this.w, x + w); xx++) {
|
|
141
|
+
const i = this.i(xx, yy);
|
|
142
|
+
this.fg[i] = mix(toRgb(this.fg[i], defFg), toward, t);
|
|
143
|
+
this.bg[i] = mix(toRgb(this.bg[i], defBg), toward, t * 0.8);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Tint the background of a rectangle (selection, hover). */
|
|
147
|
+
tint(x, y, w, h, bg) { for (let yy = Math.max(0, y); yy < Math.min(this.h, y + h); yy++)
|
|
148
|
+
for (let xx = Math.max(0, x); xx < Math.min(this.w, x + w); xx++)
|
|
149
|
+
this.bg[this.i(xx, yy)] = bg; }
|
|
150
|
+
/** Text of a row range (for copy), trailing spaces trimmed. */
|
|
151
|
+
readRow(y, x0 = 0, x1 = this.w) { let s = ""; for (let x = x0; x < x1; x++)
|
|
152
|
+
s += this.ch[this.i(x, y)]; return s.replace(/\s+$/, ""); }
|
|
153
|
+
/** Emit the minimal escape sequence that turns the previous frame into this one. `full` repaints everything. */
|
|
154
|
+
flush(full = false) {
|
|
155
|
+
for (let i = 0; i < this.ch.length; i++)
|
|
156
|
+
if (this.ch[i] === "" && i % this.w > 0) {
|
|
157
|
+
this.bg[i] = this.bg[i - 1];
|
|
158
|
+
this.fg[i] = this.fg[i - 1];
|
|
159
|
+
this.attr[i] = this.attr[i - 1];
|
|
160
|
+
}
|
|
161
|
+
const prev = full ? undefined : this.prev;
|
|
162
|
+
let out = "", lastFg = -2, lastBg = -2, lastAttr = -1, penX = -1, penY = -1;
|
|
163
|
+
const q = (c, bg) => quantize(c, this.level, bg);
|
|
164
|
+
for (let y = 0; y < this.h; y++) {
|
|
165
|
+
let x = 0;
|
|
166
|
+
while (x < this.w) {
|
|
167
|
+
const i = this.i(x, y);
|
|
168
|
+
if (prev && prev.ch[i] === this.ch[i] && prev.fg[i] === this.fg[i] && prev.bg[i] === this.bg[i] && prev.attr[i] === this.attr[i]) {
|
|
169
|
+
x++;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (this.ch[i] === "") {
|
|
173
|
+
x++;
|
|
174
|
+
continue;
|
|
175
|
+
} // second half of a wide character
|
|
176
|
+
if (x !== penX || y !== penY)
|
|
177
|
+
out += `\x1b[${y + 1};${x + 1}H`;
|
|
178
|
+
const f = q(this.fg[i], false), b = q(this.bg[i], true), a = this.attr[i];
|
|
179
|
+
if (f !== lastFg || b !== lastBg || a !== lastAttr) {
|
|
180
|
+
out += sgrFor(f, b, a);
|
|
181
|
+
lastFg = f;
|
|
182
|
+
lastBg = b;
|
|
183
|
+
lastAttr = a;
|
|
184
|
+
}
|
|
185
|
+
out += this.ch[i];
|
|
186
|
+
const w = x + 1 < this.w && this.ch[i + 1] === "" ? 2 : 1;
|
|
187
|
+
x += w;
|
|
188
|
+
penX = x;
|
|
189
|
+
penY = y;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (out)
|
|
193
|
+
out += "\x1b[0m";
|
|
194
|
+
this.prev = { ch: this.ch.slice(), fg: this.fg.slice(), bg: this.bg.slice(), attr: this.attr.slice() };
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
/** Forget what is on the terminal (after a resize or an external clear) so the next flush repaints everything. */
|
|
198
|
+
invalidate() { this.prev = undefined; }
|
|
199
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Block } from "./blocks.ts";
|
|
2
|
+
import { type Cell } from "./ansi.ts";
|
|
3
|
+
import type { Theme } from "./themes.ts";
|
|
4
|
+
export type RenderCtx = {
|
|
5
|
+
theme: Theme;
|
|
6
|
+
width: number;
|
|
7
|
+
now: number;
|
|
8
|
+
frame: number;
|
|
9
|
+
expandAll: boolean;
|
|
10
|
+
live: boolean;
|
|
11
|
+
/** the steps a subagent card ran (full-screen view nests them inside the card) */ kids?: (callId: string) => ToolBlock[];
|
|
12
|
+
brand: {
|
|
13
|
+
icon: string;
|
|
14
|
+
color: number;
|
|
15
|
+
};
|
|
16
|
+
diffMode: "auto" | "stacked" | "split";
|
|
17
|
+
/** The block above is also a tool call: draw no blank line between them, so a run of tool calls reads as one unit. */
|
|
18
|
+
tight?: boolean;
|
|
19
|
+
};
|
|
20
|
+
export type Hit = {
|
|
21
|
+
row: number;
|
|
22
|
+
x0: number;
|
|
23
|
+
x1: number;
|
|
24
|
+
kind: "toggle" | "more" | "copy";
|
|
25
|
+
id: number; /** for "copy": what lands on the clipboard */
|
|
26
|
+
text?: string;
|
|
27
|
+
};
|
|
28
|
+
export type Rendered = {
|
|
29
|
+
rows: Cell[][];
|
|
30
|
+
hits: Hit[];
|
|
31
|
+
text: string[];
|
|
32
|
+
};
|
|
33
|
+
/** Short, honest one-line summary of a tool result for the card header. */
|
|
34
|
+
export declare function summarize(name: string, raw: string, result: string): string;
|
|
35
|
+
type ToolBlock = Extract<Block, {
|
|
36
|
+
kind: "tool";
|
|
37
|
+
}>;
|
|
38
|
+
/** Tool calls that only look at things. A run of them collapses into one "Explored" row; edits, commands and failures always stand alone. */
|
|
39
|
+
export declare const isQuiet: (b: Block) => b is ToolBlock;
|
|
40
|
+
/** "3 files read · 2 searches": what a group of quiet tool calls did, in one phrase. */
|
|
41
|
+
export declare function groupSummary(bs: ToolBlock[]): string;
|
|
42
|
+
export declare function renderGroup(bs: ToolBlock[], open: boolean, c: RenderCtx): Rendered;
|
|
43
|
+
export declare function renderBlock(b: Block, c: RenderCtx): Rendered;
|
|
44
|
+
export {};
|