@bubblebrain-ai/bubble 0.0.24 → 0.0.26
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 +5 -3
- package/dist/agent.js +1 -1
- package/dist/clipboard.d.ts +14 -0
- package/dist/clipboard.js +132 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +22 -6
- package/dist/goal/format.js +34 -4
- package/dist/goal/store.d.ts +3 -0
- package/dist/goal/store.js +14 -1
- package/dist/goal/usage.d.ts +2 -0
- package/dist/goal/usage.js +3 -0
- package/dist/main.js +23 -42
- package/dist/model-catalog.d.ts +3 -1
- package/dist/model-catalog.js +17 -28
- package/dist/prompt/compose.js +1 -1
- package/dist/provider-anthropic.d.ts +4 -0
- package/dist/provider-anthropic.js +31 -0
- package/dist/provider-ark-responses.d.ts +17 -0
- package/dist/provider-ark-responses.js +462 -0
- package/dist/provider-transform.js +7 -0
- package/dist/provider.d.ts +7 -0
- package/dist/provider.js +170 -27
- package/dist/slash-commands/commands.js +22 -0
- package/dist/tools/todo.js +22 -38
- package/dist/tui/detect-theme.d.ts +1 -0
- package/dist/tui/detect-theme.js +23 -0
- package/dist/tui/image-display.d.ts +13 -0
- package/dist/tui/image-display.js +49 -0
- package/dist/tui/input-history.d.ts +37 -6
- package/dist/tui/input-history.js +194 -23
- package/dist/tui/model-switch.d.ts +42 -0
- package/dist/tui/model-switch.js +55 -0
- package/dist/tui-ink/app.d.ts +32 -2
- package/dist/tui-ink/app.js +1409 -549
- package/dist/tui-ink/approval/select.js +10 -0
- package/dist/tui-ink/detect-theme.d.ts +1 -2
- package/dist/tui-ink/detect-theme.js +1 -87
- package/dist/tui-ink/display-history.d.ts +1 -0
- package/dist/tui-ink/display-history.js +11 -0
- package/dist/tui-ink/feedback-dialog.js +10 -0
- package/dist/tui-ink/feishu-setup-picker.js +10 -0
- package/dist/tui-ink/footer.d.ts +1 -0
- package/dist/tui-ink/footer.js +8 -2
- package/dist/tui-ink/input-box.d.ts +71 -9
- package/dist/tui-ink/input-box.js +359 -121
- package/dist/tui-ink/input-history.d.ts +1 -16
- package/dist/tui-ink/input-history.js +1 -79
- package/dist/tui-ink/input-queue.d.ts +12 -0
- package/dist/tui-ink/input-queue.js +17 -0
- package/dist/tui-ink/key-events.d.ts +9 -0
- package/dist/tui-ink/key-events.js +8 -0
- package/dist/tui-ink/markdown.js +1 -1
- package/dist/tui-ink/message-list.d.ts +19 -1
- package/dist/tui-ink/message-list.js +111 -32
- package/dist/tui-ink/model-picker.d.ts +25 -2
- package/dist/tui-ink/model-picker.js +237 -20
- package/dist/tui-ink/plan-confirm.js +10 -0
- package/dist/tui-ink/question-dialog.js +46 -10
- package/dist/tui-ink/run.d.ts +10 -1
- package/dist/tui-ink/run.js +27 -42
- package/dist/tui-ink/session-picker.js +3 -0
- package/dist/tui-ink/submit-dedupe.d.ts +5 -0
- package/dist/tui-ink/submit-dedupe.js +25 -0
- package/dist/tui-ink/terminal-mouse.d.ts +24 -1
- package/dist/tui-ink/terminal-mouse.js +76 -21
- package/dist/tui-ink/theme.d.ts +6 -3
- package/dist/tui-ink/theme.js +10 -4
- package/dist/tui-ink/welcome.d.ts +1 -0
- package/dist/tui-ink/welcome.js +34 -27
- package/dist/variant/variant-resolver.js +4 -1
- package/package.json +1 -5
- package/dist/tui/clipboard.d.ts +0 -1
- package/dist/tui/clipboard.js +0 -53
- package/dist/tui/escape-confirmation.d.ts +0 -15
- package/dist/tui/escape-confirmation.js +0 -30
- package/dist/tui/global-key-router.d.ts +0 -3
- package/dist/tui/global-key-router.js +0 -87
- package/dist/tui/markdown-inline.d.ts +0 -22
- package/dist/tui/markdown-inline.js +0 -68
- package/dist/tui/markdown-theme-rules.d.ts +0 -23
- package/dist/tui/markdown-theme-rules.js +0 -164
- package/dist/tui/markdown-theme.d.ts +0 -5
- package/dist/tui/markdown-theme.js +0 -27
- package/dist/tui/opencode-spinner.d.ts +0 -22
- package/dist/tui/opencode-spinner.js +0 -216
- package/dist/tui/prompt-keybindings.d.ts +0 -42
- package/dist/tui/prompt-keybindings.js +0 -35
- package/dist/tui/render-signature.d.ts +0 -1
- package/dist/tui/render-signature.js +0 -7
- package/dist/tui/run.d.ts +0 -67
- package/dist/tui/run.js +0 -10166
- package/dist/tui/sidebar-mcp.d.ts +0 -31
- package/dist/tui/sidebar-mcp.js +0 -62
- package/dist/tui/sidebar-state.d.ts +0 -12
- package/dist/tui/sidebar-state.js +0 -69
- package/dist/tui/streaming-tool-args.d.ts +0 -15
- package/dist/tui/streaming-tool-args.js +0 -30
- package/dist/tui/tool-renderers/fallback.d.ts +0 -2
- package/dist/tui/tool-renderers/fallback.js +0 -75
- package/dist/tui/tool-renderers/registry.d.ts +0 -3
- package/dist/tui/tool-renderers/registry.js +0 -11
- package/dist/tui/tool-renderers/subagent.d.ts +0 -2
- package/dist/tui/tool-renderers/subagent.js +0 -135
- package/dist/tui/tool-renderers/types.d.ts +0 -36
- package/dist/tui/tool-renderers/types.js +0 -1
- package/dist/tui/tool-renderers/write-preview.d.ts +0 -12
- package/dist/tui/tool-renderers/write-preview.js +0 -32
- package/dist/tui/tool-renderers/write.d.ts +0 -6
- package/dist/tui/tool-renderers/write.js +0 -88
- package/dist/tui/transcript-scroll.d.ts +0 -25
- package/dist/tui/transcript-scroll.js +0 -20
- package/dist/tui-ink/transcript-viewport-math.d.ts +0 -11
- package/dist/tui-ink/transcript-viewport-math.js +0 -17
- package/dist/tui-ink/transcript-viewport.d.ts +0 -24
- package/dist/tui-ink/transcript-viewport.js +0 -83
- package/dist/tui-opentui/app.d.ts +0 -54
- package/dist/tui-opentui/app.js +0 -1371
- package/dist/tui-opentui/approval/approval-dialog.d.ts +0 -15
- package/dist/tui-opentui/approval/approval-dialog.js +0 -155
- package/dist/tui-opentui/approval/diff-view.d.ts +0 -9
- package/dist/tui-opentui/approval/diff-view.js +0 -43
- package/dist/tui-opentui/approval/select.d.ts +0 -37
- package/dist/tui-opentui/approval/select.js +0 -91
- package/dist/tui-opentui/detect-theme.d.ts +0 -2
- package/dist/tui-opentui/detect-theme.js +0 -87
- package/dist/tui-opentui/display-history.d.ts +0 -56
- package/dist/tui-opentui/display-history.js +0 -130
- package/dist/tui-opentui/edit-diff.d.ts +0 -11
- package/dist/tui-opentui/edit-diff.js +0 -57
- package/dist/tui-opentui/feedback-dialog.d.ts +0 -21
- package/dist/tui-opentui/feedback-dialog.js +0 -164
- package/dist/tui-opentui/feishu-setup-picker.d.ts +0 -7
- package/dist/tui-opentui/feishu-setup-picker.js +0 -272
- package/dist/tui-opentui/file-mentions.d.ts +0 -29
- package/dist/tui-opentui/file-mentions.js +0 -174
- package/dist/tui-opentui/footer.d.ts +0 -26
- package/dist/tui-opentui/footer.js +0 -40
- package/dist/tui-opentui/image-paste.d.ts +0 -54
- package/dist/tui-opentui/image-paste.js +0 -288
- package/dist/tui-opentui/input-box.d.ts +0 -32
- package/dist/tui-opentui/input-box.js +0 -462
- package/dist/tui-opentui/input-history.d.ts +0 -16
- package/dist/tui-opentui/input-history.js +0 -79
- package/dist/tui-opentui/markdown.d.ts +0 -66
- package/dist/tui-opentui/markdown.js +0 -127
- package/dist/tui-opentui/message-list.d.ts +0 -31
- package/dist/tui-opentui/message-list.js +0 -131
- package/dist/tui-opentui/model-picker.d.ts +0 -63
- package/dist/tui-opentui/model-picker.js +0 -450
- package/dist/tui-opentui/plan-confirm.d.ts +0 -9
- package/dist/tui-opentui/plan-confirm.js +0 -124
- package/dist/tui-opentui/question-dialog.d.ts +0 -10
- package/dist/tui-opentui/question-dialog.js +0 -110
- package/dist/tui-opentui/recent-activity.d.ts +0 -8
- package/dist/tui-opentui/recent-activity.js +0 -71
- package/dist/tui-opentui/run-session-picker.d.ts +0 -10
- package/dist/tui-opentui/run-session-picker.js +0 -28
- package/dist/tui-opentui/run.d.ts +0 -38
- package/dist/tui-opentui/run.js +0 -48
- package/dist/tui-opentui/session-picker.d.ts +0 -12
- package/dist/tui-opentui/session-picker.js +0 -120
- package/dist/tui-opentui/theme.d.ts +0 -89
- package/dist/tui-opentui/theme.js +0 -157
- package/dist/tui-opentui/todos.d.ts +0 -9
- package/dist/tui-opentui/todos.js +0 -45
- package/dist/tui-opentui/trace-groups.d.ts +0 -27
- package/dist/tui-opentui/trace-groups.js +0 -455
- package/dist/tui-opentui/use-terminal-size.d.ts +0 -4
- package/dist/tui-opentui/use-terminal-size.js +0 -5
- package/dist/tui-opentui/welcome.d.ts +0 -25
- package/dist/tui-opentui/welcome.js +0 -77
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/react */
|
|
2
|
-
import React from "react";
|
|
3
|
-
import type { ApprovalDecision, ApprovalRequest } from "../../approval/types.js";
|
|
4
|
-
interface ApprovalDialogProps {
|
|
5
|
-
request: ApprovalRequest;
|
|
6
|
-
onDecision: (decision: ApprovalDecision) => void;
|
|
7
|
-
/**
|
|
8
|
-
* Selecting "Yes, and don't ask again for <prefix>" calls this with the
|
|
9
|
-
* (possibly user-edited) prefix so the harness can register it in the
|
|
10
|
-
* session-scoped bash allowlist.
|
|
11
|
-
*/
|
|
12
|
-
onAllowBashPrefix?: (prefix: string) => void;
|
|
13
|
-
}
|
|
14
|
-
export declare function ApprovalDialog({ request, onDecision, onAllowBashPrefix, }: ApprovalDialogProps): React.ReactNode;
|
|
15
|
-
export {};
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
-
import { useTheme } from "../theme.js";
|
|
3
|
-
import { ApprovalSelect } from "./select.js";
|
|
4
|
-
import { DiffView } from "./diff-view.js";
|
|
5
|
-
import { inferBashPrefix } from "../../approval/session-cache.js";
|
|
6
|
-
import { classifyBashDanger } from "../../approval/danger.js";
|
|
7
|
-
export function ApprovalDialog({ request, onDecision, onAllowBashPrefix, }) {
|
|
8
|
-
const theme = useTheme();
|
|
9
|
-
const options = buildOptions(request);
|
|
10
|
-
const onSubmit = (id, extras) => {
|
|
11
|
-
switch (id) {
|
|
12
|
-
case "yes":
|
|
13
|
-
onDecision({ action: "approve", feedback: extras.feedback });
|
|
14
|
-
return;
|
|
15
|
-
case "yes-bash-prefix": {
|
|
16
|
-
const prefix = (extras.editedValue ?? "").trim();
|
|
17
|
-
if (prefix)
|
|
18
|
-
onAllowBashPrefix?.(prefix);
|
|
19
|
-
onDecision({ action: "approve" });
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
case "no":
|
|
23
|
-
default:
|
|
24
|
-
onDecision({ action: "reject", feedback: extras.feedback });
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
const onCancel = () => onDecision({ action: "reject" });
|
|
29
|
-
const title = dialogTitle(request);
|
|
30
|
-
const question = dialogQuestion(request);
|
|
31
|
-
return (_jsxs("box", { style: {
|
|
32
|
-
flexDirection: "column",
|
|
33
|
-
border: true,
|
|
34
|
-
borderColor: theme.accent,
|
|
35
|
-
paddingLeft: 1,
|
|
36
|
-
paddingRight: 1,
|
|
37
|
-
marginTop: 1,
|
|
38
|
-
marginBottom: 1,
|
|
39
|
-
}, children: [_jsx("text", { fg: theme.accent, attributes: 1, children: title }), _jsx("box", { style: { flexDirection: "column", marginTop: 1 }, children: _jsx(RequestPreview, { request: request }) }), _jsx("box", { style: { marginTop: 1 }, children: _jsx("text", { children: question }) }), _jsx("box", { style: { marginTop: 1 }, children: _jsx(ApprovalSelect, { options: options, onSubmit: onSubmit, onCancel: onCancel, hint: "\u2191\u2193 choose \u00B7 Enter select \u00B7 Tab add feedback \u00B7 Esc reject" }) })] }));
|
|
40
|
-
}
|
|
41
|
-
function buildOptions(request) {
|
|
42
|
-
if (request.type === "bash") {
|
|
43
|
-
const prefix = inferBashPrefix(request.command);
|
|
44
|
-
return [
|
|
45
|
-
{ id: "yes", label: "Yes", allowAmend: true, amendPlaceholder: "and tell Claude what to do next" },
|
|
46
|
-
{
|
|
47
|
-
id: "yes-bash-prefix",
|
|
48
|
-
label: "Yes, and don't ask again for",
|
|
49
|
-
editableValue: {
|
|
50
|
-
initial: prefix,
|
|
51
|
-
placeholder: "command prefix (e.g. npm run:*)",
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
id: "no",
|
|
56
|
-
label: "No",
|
|
57
|
-
description: "(tab to add feedback)",
|
|
58
|
-
allowAmend: true,
|
|
59
|
-
amendPlaceholder: "and tell Claude what to do differently",
|
|
60
|
-
},
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
|
-
// edit / write / patch
|
|
64
|
-
return [
|
|
65
|
-
{ id: "yes", label: "Yes", allowAmend: true, amendPlaceholder: "and tell Claude what to do next" },
|
|
66
|
-
{
|
|
67
|
-
id: "no",
|
|
68
|
-
label: "No",
|
|
69
|
-
description: "(tab to add feedback)",
|
|
70
|
-
allowAmend: true,
|
|
71
|
-
amendPlaceholder: "and tell Claude what to do differently",
|
|
72
|
-
},
|
|
73
|
-
];
|
|
74
|
-
}
|
|
75
|
-
function dialogTitle(req) {
|
|
76
|
-
switch (req.type) {
|
|
77
|
-
case "edit":
|
|
78
|
-
return "Edit file";
|
|
79
|
-
case "patch":
|
|
80
|
-
return "Apply patch";
|
|
81
|
-
case "write":
|
|
82
|
-
return req.fileExists ? "Overwrite file" : "Create file";
|
|
83
|
-
case "bash":
|
|
84
|
-
return "Bash command";
|
|
85
|
-
case "lsp":
|
|
86
|
-
return "Language server operation";
|
|
87
|
-
case "agent_profile":
|
|
88
|
-
return "Project agent profile";
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function dialogQuestion(req) {
|
|
92
|
-
switch (req.type) {
|
|
93
|
-
case "edit":
|
|
94
|
-
return `Do you want to make this edit to ${basename(req.path)}?`;
|
|
95
|
-
case "patch":
|
|
96
|
-
return `Do you want to apply this patch to ${req.paths.length} file${req.paths.length === 1 ? "" : "s"}?`;
|
|
97
|
-
case "write":
|
|
98
|
-
return `Do you want to ${req.fileExists ? "overwrite" : "create"} ${basename(req.path)}?`;
|
|
99
|
-
case "bash":
|
|
100
|
-
return "Do you want to proceed?";
|
|
101
|
-
case "lsp":
|
|
102
|
-
return `Do you want to run ${req.operation} on ${basename(req.path)}?`;
|
|
103
|
-
case "agent_profile":
|
|
104
|
-
return `Trust the repository profile "${req.name}" to drive a subagent? It is remembered for this session until the file changes.`;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
function basename(p) {
|
|
108
|
-
const idx = p.lastIndexOf("/");
|
|
109
|
-
return idx >= 0 ? p.slice(idx + 1) : p;
|
|
110
|
-
}
|
|
111
|
-
function RequestPreview({ request }) {
|
|
112
|
-
switch (request.type) {
|
|
113
|
-
case "bash":
|
|
114
|
-
return _jsx(BashPreview, { command: request.command, cwd: request.cwd });
|
|
115
|
-
case "edit":
|
|
116
|
-
return _jsx(DiffView, { diff: request.diff });
|
|
117
|
-
case "patch":
|
|
118
|
-
return _jsx(DiffView, { diff: request.diff });
|
|
119
|
-
case "write":
|
|
120
|
-
return _jsx(WritePreview, { path: request.path, content: request.content });
|
|
121
|
-
case "agent_profile":
|
|
122
|
-
return _jsx(AgentProfilePreview, { path: request.path, promptPreview: request.promptPreview });
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
function AgentProfilePreview({ path, promptPreview }) {
|
|
126
|
-
const theme = useTheme();
|
|
127
|
-
return (_jsxs("box", { style: { flexDirection: "column" }, children: [_jsx("text", { fg: theme.muted, children: compressHome(path) }), _jsx("text", { children: promptPreview }), _jsx("box", { style: { marginTop: 1 }, children: _jsx("text", { fg: theme.warning, children: "This prompt comes from the repository's .bubble/agents and will drive a subagent." }) })] }));
|
|
128
|
-
}
|
|
129
|
-
function BashPreview({ command, cwd }) {
|
|
130
|
-
const theme = useTheme();
|
|
131
|
-
const danger = classifyBashDanger(command);
|
|
132
|
-
return (_jsxs("box", { style: { flexDirection: "column" }, children: [_jsxs("box", { style: { flexDirection: "row" }, children: [_jsx("text", { fg: theme.muted, children: "$ " }), _jsx("text", { children: command })] }), _jsx("text", { fg: theme.muted, children: `cwd: ${compressHome(cwd)}` }), danger && (_jsxs("box", { style: { marginTop: 1, flexDirection: "row" }, children: [_jsx("text", { fg: theme.warning, attributes: 1, children: `⚠ ${danger.pattern}:` }), _jsx("text", { fg: theme.warning, children: ` ${danger.message}` })] }))] }));
|
|
133
|
-
}
|
|
134
|
-
const MAX_WRITE_PREVIEW_LINES = 20;
|
|
135
|
-
function WritePreview({ path, content }) {
|
|
136
|
-
const theme = useTheme();
|
|
137
|
-
const lines = content.split("\n");
|
|
138
|
-
const shown = lines.slice(0, MAX_WRITE_PREVIEW_LINES);
|
|
139
|
-
const overflow = lines.length - shown.length;
|
|
140
|
-
const totalBytes = Buffer.byteLength(content, "utf-8");
|
|
141
|
-
return (_jsxs("box", { style: { flexDirection: "column" }, children: [_jsxs("box", { style: { flexDirection: "row" }, children: [_jsx("text", { fg: theme.muted, children: compressHome(path) }), _jsx("text", { fg: theme.muted, children: ` · ${lines.length} line${lines.length === 1 ? "" : "s"} · ${formatBytes(totalBytes)}` })] }), _jsxs("box", { style: { flexDirection: "column", marginTop: 1 }, children: [shown.map((line, i) => (_jsxs("text", { fg: "green", children: ["+ ", line || " "] }, i))), overflow > 0 && (_jsx("text", { fg: theme.muted, children: `… ${overflow} more line${overflow === 1 ? "" : "s"}` }))] })] }));
|
|
142
|
-
}
|
|
143
|
-
function formatBytes(n) {
|
|
144
|
-
if (n < 1024)
|
|
145
|
-
return `${n}B`;
|
|
146
|
-
if (n < 1024 * 1024)
|
|
147
|
-
return `${(n / 1024).toFixed(1)}KB`;
|
|
148
|
-
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
149
|
-
}
|
|
150
|
-
function compressHome(p) {
|
|
151
|
-
const home = process.env.HOME || "";
|
|
152
|
-
if (home && p.startsWith(home))
|
|
153
|
-
return `~${p.slice(home.length)}`;
|
|
154
|
-
return p;
|
|
155
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/react */
|
|
2
|
-
import React from "react";
|
|
3
|
-
interface DiffViewProps {
|
|
4
|
-
diff: string;
|
|
5
|
-
/** Hard cap on total rendered lines across all hunks. Excess is truncated. */
|
|
6
|
-
maxLines?: number;
|
|
7
|
-
}
|
|
8
|
-
export declare function DiffView({ diff, maxLines }: DiffViewProps): React.ReactNode;
|
|
9
|
-
export {};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
-
import { useTheme } from "../theme.js";
|
|
3
|
-
import { parseDiffHunks } from "../../approval/diff-hunks.js";
|
|
4
|
-
const DEFAULT_MAX_LINES = 40;
|
|
5
|
-
export function DiffView({ diff, maxLines = DEFAULT_MAX_LINES }) {
|
|
6
|
-
const theme = useTheme();
|
|
7
|
-
const hunks = parseDiffHunks(diff);
|
|
8
|
-
if (hunks.length === 0) {
|
|
9
|
-
return (_jsx("text", { fg: theme.muted, content: "(no diff body to display)" }));
|
|
10
|
-
}
|
|
11
|
-
// Distribute the line budget across hunks. Simple approach: render hunks in
|
|
12
|
-
// order until the budget is exhausted; if a hunk overflows, keep its header,
|
|
13
|
-
// show as many body lines as fit, then emit a "… N more" marker.
|
|
14
|
-
let remaining = maxLines;
|
|
15
|
-
const rendered = [];
|
|
16
|
-
let trailingSkipped = 0;
|
|
17
|
-
for (let i = 0; i < hunks.length; i++) {
|
|
18
|
-
const hunk = hunks[i];
|
|
19
|
-
if (remaining <= 1) {
|
|
20
|
-
trailingSkipped += hunk.lines.length + 1;
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
remaining -= 1; // header line
|
|
24
|
-
const available = Math.max(0, remaining);
|
|
25
|
-
if (hunk.lines.length <= available) {
|
|
26
|
-
rendered.push({ hunk, shown: hunk.lines, truncatedBy: 0 });
|
|
27
|
-
remaining -= hunk.lines.length;
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
const shown = hunk.lines.slice(0, available);
|
|
31
|
-
rendered.push({ hunk, shown, truncatedBy: hunk.lines.length - available });
|
|
32
|
-
remaining = 0;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return (_jsxs("box", { style: { flexDirection: "column" }, children: [rendered.map(({ hunk, shown, truncatedBy }, i) => (_jsxs("box", { style: { flexDirection: "column" }, children: [_jsx("text", { fg: theme.accent, children: hunk.header }), shown.map((line, j) => (_jsx("text", { fg: colorForDiffLine(line), children: line || " " }, j))), truncatedBy > 0 && (_jsx("text", { fg: theme.muted, children: `… ${truncatedBy} more line${truncatedBy === 1 ? "" : "s"} in this hunk` }))] }, i))), trailingSkipped > 0 && (_jsx("text", { fg: theme.muted, children: `… ${trailingSkipped} more line${trailingSkipped === 1 ? "" : "s"} across later hunks` }))] }));
|
|
36
|
-
}
|
|
37
|
-
function colorForDiffLine(line) {
|
|
38
|
-
if (line.startsWith("+"))
|
|
39
|
-
return "green";
|
|
40
|
-
if (line.startsWith("-"))
|
|
41
|
-
return "red";
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/react */
|
|
2
|
-
import React from "react";
|
|
3
|
-
export interface ApprovalOption {
|
|
4
|
-
/** Stable identifier returned to the parent. */
|
|
5
|
-
id: string;
|
|
6
|
-
/** Primary label shown in the menu. */
|
|
7
|
-
label: string;
|
|
8
|
-
/** Dim description appended after the label. */
|
|
9
|
-
description?: string;
|
|
10
|
-
/** If true, Tab on this option turns it into a feedback input. */
|
|
11
|
-
allowAmend?: boolean;
|
|
12
|
-
/** Placeholder shown in the amend input. */
|
|
13
|
-
amendPlaceholder?: string;
|
|
14
|
-
/**
|
|
15
|
-
* If set, this option has an inline-editable data value (rendered right
|
|
16
|
-
* after `label`). When the option is focused, typing modifies the value;
|
|
17
|
-
* backspace removes the last character. Use-case: "Yes, and don't ask
|
|
18
|
-
* again for `<prefix>`" — the prefix is editable before submit.
|
|
19
|
-
*/
|
|
20
|
-
editableValue?: {
|
|
21
|
-
initial: string;
|
|
22
|
-
placeholder?: string;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export type ApprovalSubmit = (optionId: string, extras: {
|
|
26
|
-
feedback?: string;
|
|
27
|
-
editedValue?: string;
|
|
28
|
-
}) => void;
|
|
29
|
-
interface ApprovalSelectProps {
|
|
30
|
-
options: ApprovalOption[];
|
|
31
|
-
onSubmit: ApprovalSubmit;
|
|
32
|
-
onCancel: () => void;
|
|
33
|
-
hint?: string;
|
|
34
|
-
initialIndex?: number;
|
|
35
|
-
}
|
|
36
|
-
export declare function ApprovalSelect({ options, onSubmit, onCancel, hint, initialIndex, }: ApprovalSelectProps): React.ReactNode;
|
|
37
|
-
export {};
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@opentui/react/jsx-runtime";
|
|
2
|
-
/** @jsxImportSource @opentui/react */
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { useKeyboard } from "@opentui/react";
|
|
5
|
-
import { useTheme } from "../theme.js";
|
|
6
|
-
export function ApprovalSelect({ options, onSubmit, onCancel, hint, initialIndex = 0, }) {
|
|
7
|
-
const theme = useTheme();
|
|
8
|
-
const [focusIndex, setFocusIndex] = useState(Math.max(0, Math.min(initialIndex, options.length - 1)));
|
|
9
|
-
const [amending, setAmending] = useState(false);
|
|
10
|
-
const [amendText, setAmendText] = useState("");
|
|
11
|
-
// Map of option.id → current edited value. Populated lazily so navigating
|
|
12
|
-
// away and back preserves edits.
|
|
13
|
-
const [editedValues, setEditedValues] = useState(() => {
|
|
14
|
-
const seed = {};
|
|
15
|
-
for (const opt of options) {
|
|
16
|
-
if (opt.editableValue)
|
|
17
|
-
seed[opt.id] = opt.editableValue.initial;
|
|
18
|
-
}
|
|
19
|
-
return seed;
|
|
20
|
-
});
|
|
21
|
-
const focused = options[focusIndex];
|
|
22
|
-
const canAmend = !!focused?.allowAmend;
|
|
23
|
-
const hasEditableValue = !!focused?.editableValue;
|
|
24
|
-
const currentValue = focused?.editableValue ? editedValues[focused.id] ?? "" : "";
|
|
25
|
-
useKeyboard((key) => {
|
|
26
|
-
if (key.eventType === "release")
|
|
27
|
-
return;
|
|
28
|
-
if (amending) {
|
|
29
|
-
if (key.name === "escape") {
|
|
30
|
-
setAmending(false);
|
|
31
|
-
setAmendText("");
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (key.name === "return") {
|
|
35
|
-
const editedValue = focused.editableValue ? currentValue : undefined;
|
|
36
|
-
onSubmit(focused.id, { feedback: amendText.trim() || undefined, editedValue });
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (key.name === "backspace" || key.name === "delete") {
|
|
40
|
-
setAmendText((prev) => prev.slice(0, -1));
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
if (key.name && key.name.length === 1) {
|
|
44
|
-
setAmendText((prev) => prev + key.name);
|
|
45
|
-
}
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
if (key.name === "escape") {
|
|
49
|
-
onCancel();
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// Vertical nav always works regardless of editable value, so the user can
|
|
53
|
-
// still move off an option they don't want.
|
|
54
|
-
if (key.name === "up") {
|
|
55
|
-
setFocusIndex((i) => (i - 1 + options.length) % options.length);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
if (key.name === "down") {
|
|
59
|
-
setFocusIndex((i) => (i + 1) % options.length);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (key.name === "return") {
|
|
63
|
-
const editedValue = focused.editableValue ? currentValue : undefined;
|
|
64
|
-
onSubmit(focused.id, { editedValue });
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (key.name === "tab" && canAmend) {
|
|
68
|
-
setAmending(true);
|
|
69
|
-
setAmendText("");
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
// When the focused option has an editable value, plain keypresses mutate it.
|
|
73
|
-
if (hasEditableValue) {
|
|
74
|
-
if (key.name === "backspace" || key.name === "delete") {
|
|
75
|
-
setEditedValues((prev) => ({ ...prev, [focused.id]: (prev[focused.id] ?? "").slice(0, -1) }));
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (key.name && key.name.length === 1 && !key.ctrl && !key.option) {
|
|
79
|
-
setEditedValues((prev) => ({ ...prev, [focused.id]: (prev[focused.id] ?? "") + key.name }));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
return (_jsxs("box", { style: { flexDirection: "column" }, children: [options.map((option, idx) => {
|
|
84
|
-
const isFocused = idx === focusIndex;
|
|
85
|
-
const value = option.editableValue ? editedValues[option.id] ?? "" : undefined;
|
|
86
|
-
if (isFocused && amending) {
|
|
87
|
-
return (_jsxs("box", { style: { flexDirection: "row" }, children: [_jsx("text", { fg: theme.accent, children: "› " }), _jsx("text", { attributes: 1, children: `${option.label}:` }), _jsx("text", { children: " " }), _jsx("text", { fg: amendText ? undefined : theme.muted, children: amendText || option.amendPlaceholder || "type feedback…" }), _jsx("text", { bg: "white", fg: "black", children: " " })] }, option.id));
|
|
88
|
-
}
|
|
89
|
-
return (_jsxs("box", { style: { flexDirection: "row" }, children: [_jsx("text", { fg: isFocused ? theme.accent : theme.muted, children: isFocused ? "› " : " " }), _jsx("text", { attributes: isFocused ? 1 : 0, fg: isFocused ? undefined : theme.muted, children: option.label }), option.editableValue && (_jsxs(_Fragment, { children: [_jsx("text", { fg: theme.muted, children: " " }), _jsx("text", { fg: isFocused ? theme.accent : theme.muted, children: "[" }), _jsx("text", { fg: isFocused ? undefined : theme.muted, children: value || option.editableValue.placeholder || "" }), isFocused && (_jsx("text", { bg: "white", fg: "black", children: " " })), _jsx("text", { fg: isFocused ? theme.accent : theme.muted, children: "]" })] })), option.description && (_jsxs(_Fragment, { children: [_jsx("text", { children: " " }), _jsx("text", { fg: theme.muted, children: option.description })] }))] }, option.id));
|
|
90
|
-
}), hint && (_jsx("box", { style: { marginTop: 1 }, children: _jsx("text", { fg: theme.muted, children: hint }) }))] }));
|
|
91
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
export async function detectTerminalTheme(timeoutMs = 150) {
|
|
2
|
-
const fromEnv = parseColorFgBg(process.env.COLORFGBG);
|
|
3
|
-
if (fromEnv)
|
|
4
|
-
return fromEnv;
|
|
5
|
-
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
6
|
-
const fromOsc = await queryOsc11(timeoutMs);
|
|
7
|
-
if (fromOsc)
|
|
8
|
-
return fromOsc;
|
|
9
|
-
}
|
|
10
|
-
return "dark";
|
|
11
|
-
}
|
|
12
|
-
function parseColorFgBg(value) {
|
|
13
|
-
if (!value)
|
|
14
|
-
return null;
|
|
15
|
-
const parts = value.split(";");
|
|
16
|
-
const last = parts[parts.length - 1];
|
|
17
|
-
if (!last)
|
|
18
|
-
return null;
|
|
19
|
-
const bg = parseInt(last, 10);
|
|
20
|
-
if (Number.isNaN(bg))
|
|
21
|
-
return null;
|
|
22
|
-
if (bg >= 0 && bg <= 6)
|
|
23
|
-
return "dark";
|
|
24
|
-
if (bg >= 7 && bg <= 15)
|
|
25
|
-
return "light";
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
function queryOsc11(timeoutMs) {
|
|
29
|
-
return new Promise((resolve) => {
|
|
30
|
-
const stdin = process.stdin;
|
|
31
|
-
const stdout = process.stdout;
|
|
32
|
-
let settled = false;
|
|
33
|
-
const originalRaw = stdin.isRaw;
|
|
34
|
-
let buffer = "";
|
|
35
|
-
const cleanup = () => {
|
|
36
|
-
stdin.removeListener("data", onData);
|
|
37
|
-
try {
|
|
38
|
-
stdin.setRawMode(originalRaw);
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
// ignore - terminal may have already restored
|
|
42
|
-
}
|
|
43
|
-
stdin.pause();
|
|
44
|
-
};
|
|
45
|
-
const finish = (result) => {
|
|
46
|
-
if (settled)
|
|
47
|
-
return;
|
|
48
|
-
settled = true;
|
|
49
|
-
clearTimeout(timer);
|
|
50
|
-
cleanup();
|
|
51
|
-
resolve(result);
|
|
52
|
-
};
|
|
53
|
-
const onData = (chunk) => {
|
|
54
|
-
buffer += chunk.toString("utf8");
|
|
55
|
-
const match = buffer.match(/\x1b\]11;rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)(?:\x07|\x1b\\)/);
|
|
56
|
-
if (!match)
|
|
57
|
-
return;
|
|
58
|
-
const [, r, g, b] = match;
|
|
59
|
-
const lum = relativeLuminance(parseHexChannel(r), parseHexChannel(g), parseHexChannel(b));
|
|
60
|
-
finish(lum > 0.5 ? "light" : "dark");
|
|
61
|
-
};
|
|
62
|
-
try {
|
|
63
|
-
stdin.setRawMode(true);
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
resolve(null);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
stdin.resume();
|
|
70
|
-
stdin.on("data", onData);
|
|
71
|
-
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
72
|
-
try {
|
|
73
|
-
stdout.write("\x1b]11;?\x07");
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
finish(null);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
function parseHexChannel(hex) {
|
|
81
|
-
const max = (1 << (hex.length * 4)) - 1;
|
|
82
|
-
return parseInt(hex, 16) / max;
|
|
83
|
-
}
|
|
84
|
-
function relativeLuminance(r, g, b) {
|
|
85
|
-
const channel = (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
86
|
-
return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
|
|
87
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { Message, ToolResultMetadata } from "../types.js";
|
|
2
|
-
export interface DisplayMessage {
|
|
3
|
-
/** Stable identity, used as the transcript list key. Generated by the UI layer. */
|
|
4
|
-
key?: string;
|
|
5
|
-
role: "user" | "assistant" | "error";
|
|
6
|
-
content: string;
|
|
7
|
-
reasoning?: string;
|
|
8
|
-
toolCalls?: DisplayToolCall[];
|
|
9
|
-
parts?: DisplayMessagePart[];
|
|
10
|
-
syntheticKind?: "ui_summary" | "ui_compact_summary";
|
|
11
|
-
/** Markdown body shown inside a `ui_compact_summary` card. */
|
|
12
|
-
compactionSummary?: string;
|
|
13
|
-
hiddenCount?: number;
|
|
14
|
-
taskElapsedMs?: number;
|
|
15
|
-
}
|
|
16
|
-
export type DisplayMessagePart = DisplayTextPart | DisplayToolsPart;
|
|
17
|
-
export interface DisplayTextPart {
|
|
18
|
-
type: "text";
|
|
19
|
-
content: string;
|
|
20
|
-
}
|
|
21
|
-
export interface DisplayToolsPart {
|
|
22
|
-
type: "tools";
|
|
23
|
-
toolCalls: DisplayToolCall[];
|
|
24
|
-
}
|
|
25
|
-
export interface DisplayToolCall {
|
|
26
|
-
id: string;
|
|
27
|
-
name: string;
|
|
28
|
-
args: Record<string, any>;
|
|
29
|
-
/**
|
|
30
|
-
* Unparsed JSON string for tool arguments, populated during partial-streaming
|
|
31
|
-
* before `args` resolves. Used as a fallback by trace-groups when extracting
|
|
32
|
-
* a command preview.
|
|
33
|
-
*/
|
|
34
|
-
rawArguments?: string;
|
|
35
|
-
result?: string;
|
|
36
|
-
resultCollapsed?: boolean;
|
|
37
|
-
isError?: boolean;
|
|
38
|
-
metadata?: ToolResultMetadata;
|
|
39
|
-
/** Set when the tool_start event was received. Used to render elapsed time. */
|
|
40
|
-
startedAt?: number;
|
|
41
|
-
}
|
|
42
|
-
export declare function nextDisplayMessageKey(prefix?: string): string;
|
|
43
|
-
export declare function appendTextPart(parts: DisplayMessagePart[], content: string): void;
|
|
44
|
-
export declare function appendToolPart(parts: DisplayMessagePart[], toolCall: DisplayToolCall): void;
|
|
45
|
-
export declare function snapshotDisplayParts(parts: DisplayMessagePart[]): DisplayMessagePart[];
|
|
46
|
-
export declare function contentFromParts(parts: DisplayMessagePart[]): string;
|
|
47
|
-
export declare function toolCallsFromParts(parts: DisplayMessagePart[]): DisplayToolCall[];
|
|
48
|
-
export declare function compactDisplayMessages(messages: DisplayMessage[]): DisplayMessage[];
|
|
49
|
-
/**
|
|
50
|
-
* Find the most recent compaction summary embedded in the agent's system
|
|
51
|
-
* messages. Bubble's compaction step rewrites the system transcript so that
|
|
52
|
-
* the long-form summary lives in either a "Previous conversation summary:"
|
|
53
|
-
* block or an "Earlier in this turn" block; we walk from newest to oldest and
|
|
54
|
-
* return the first match so the UI can show the freshest summary.
|
|
55
|
-
*/
|
|
56
|
-
export declare function latestCompactionSummary(agentMessages: Message[]): string | undefined;
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
let __displayMessageCounter = 0;
|
|
2
|
-
export function nextDisplayMessageKey(prefix = "msg") {
|
|
3
|
-
__displayMessageCounter += 1;
|
|
4
|
-
return `${prefix}-${__displayMessageCounter}`;
|
|
5
|
-
}
|
|
6
|
-
export function appendTextPart(parts, content) {
|
|
7
|
-
if (!content)
|
|
8
|
-
return;
|
|
9
|
-
const last = parts[parts.length - 1];
|
|
10
|
-
if (last?.type === "text") {
|
|
11
|
-
last.content += content;
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
parts.push({ type: "text", content });
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export function appendToolPart(parts, toolCall) {
|
|
18
|
-
const last = parts[parts.length - 1];
|
|
19
|
-
if (last?.type === "tools") {
|
|
20
|
-
last.toolCalls.push(toolCall);
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
parts.push({ type: "tools", toolCalls: [toolCall] });
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
export function snapshotDisplayParts(parts) {
|
|
27
|
-
return parts.map((part) => {
|
|
28
|
-
if (part.type === "text") {
|
|
29
|
-
return { ...part };
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
type: "tools",
|
|
33
|
-
toolCalls: part.toolCalls.map(cloneToolCall),
|
|
34
|
-
};
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
export function contentFromParts(parts) {
|
|
38
|
-
return parts
|
|
39
|
-
.filter((part) => part.type === "text")
|
|
40
|
-
.map((part) => part.content)
|
|
41
|
-
.join("");
|
|
42
|
-
}
|
|
43
|
-
export function toolCallsFromParts(parts) {
|
|
44
|
-
return parts.flatMap((part) => part.type === "tools" ? part.toolCalls : []);
|
|
45
|
-
}
|
|
46
|
-
const FULL_DETAIL_WINDOW = 24;
|
|
47
|
-
const MAX_OLD_CONTENT_CHARS = 1200;
|
|
48
|
-
const MAX_OLD_REASONING_CHARS = 600;
|
|
49
|
-
export function compactDisplayMessages(messages) {
|
|
50
|
-
if (messages.length === 0) {
|
|
51
|
-
return messages;
|
|
52
|
-
}
|
|
53
|
-
const visible = messages.filter((message) => message.syntheticKind !== "ui_summary");
|
|
54
|
-
const detailStart = Math.max(0, visible.length - FULL_DETAIL_WINDOW);
|
|
55
|
-
return visible.map((message, index) => (index < detailStart ? compactDisplayMessage(message) : message));
|
|
56
|
-
}
|
|
57
|
-
function compactDisplayMessage(message) {
|
|
58
|
-
if (message.syntheticKind === "ui_summary" || message.syntheticKind === "ui_compact_summary") {
|
|
59
|
-
return message;
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
...message,
|
|
63
|
-
content: truncateText(message.content, MAX_OLD_CONTENT_CHARS),
|
|
64
|
-
reasoning: message.reasoning
|
|
65
|
-
? truncateText(message.reasoning, MAX_OLD_REASONING_CHARS)
|
|
66
|
-
: message.reasoning,
|
|
67
|
-
toolCalls: message.toolCalls?.map(compactToolCall),
|
|
68
|
-
parts: message.parts?.map(compactDisplayPart),
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function truncateText(value, maxChars) {
|
|
72
|
-
if (value.length <= maxChars) {
|
|
73
|
-
return value;
|
|
74
|
-
}
|
|
75
|
-
const head = Math.max(1, Math.floor(maxChars * 0.7));
|
|
76
|
-
const tail = Math.max(1, maxChars - head - 32);
|
|
77
|
-
const omitted = value.length - head - tail;
|
|
78
|
-
return `${value.slice(0, head)}\n...[${omitted} chars omitted for UI]...\n${value.slice(-tail)}`;
|
|
79
|
-
}
|
|
80
|
-
function cloneToolCall(toolCall) {
|
|
81
|
-
return {
|
|
82
|
-
...toolCall,
|
|
83
|
-
args: { ...toolCall.args },
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function compactDisplayPart(part) {
|
|
87
|
-
if (part.type === "text") {
|
|
88
|
-
return {
|
|
89
|
-
...part,
|
|
90
|
-
content: truncateText(part.content, MAX_OLD_CONTENT_CHARS),
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
type: "tools",
|
|
95
|
-
toolCalls: part.toolCalls.map(compactToolCall),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
function compactToolCall(toolCall) {
|
|
99
|
-
if (toolCall.result === undefined) {
|
|
100
|
-
return toolCall;
|
|
101
|
-
}
|
|
102
|
-
return {
|
|
103
|
-
...toolCall,
|
|
104
|
-
result: undefined,
|
|
105
|
-
resultCollapsed: true,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
const PREVIOUS_SUMMARY_PREFIX = /^Previous conversation summary:\s*\n?([\s\S]*)$/;
|
|
109
|
-
const TURN_SUMMARY_PREFIX = /^Earlier in this turn \(compacted to free context\):\s*\n?([\s\S]*)$/;
|
|
110
|
-
/**
|
|
111
|
-
* Find the most recent compaction summary embedded in the agent's system
|
|
112
|
-
* messages. Bubble's compaction step rewrites the system transcript so that
|
|
113
|
-
* the long-form summary lives in either a "Previous conversation summary:"
|
|
114
|
-
* block or an "Earlier in this turn" block; we walk from newest to oldest and
|
|
115
|
-
* return the first match so the UI can show the freshest summary.
|
|
116
|
-
*/
|
|
117
|
-
export function latestCompactionSummary(agentMessages) {
|
|
118
|
-
for (let index = agentMessages.length - 1; index >= 0; index--) {
|
|
119
|
-
const message = agentMessages[index];
|
|
120
|
-
if (!message || message.role !== "system" || typeof message.content !== "string")
|
|
121
|
-
continue;
|
|
122
|
-
const previousMatch = message.content.match(PREVIOUS_SUMMARY_PREFIX);
|
|
123
|
-
if (previousMatch?.[1]?.trim())
|
|
124
|
-
return previousMatch[1].trim();
|
|
125
|
-
const turnMatch = message.content.match(TURN_SUMMARY_PREFIX);
|
|
126
|
-
if (turnMatch?.[1]?.trim())
|
|
127
|
-
return turnMatch[1].trim();
|
|
128
|
-
}
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { DisplayToolCall } from "./display-history.js";
|
|
2
|
-
export declare const EDIT_COLLAPSED_DIFF_LINES = 20;
|
|
3
|
-
export interface EditDiffDetails {
|
|
4
|
-
diff: string;
|
|
5
|
-
added: number;
|
|
6
|
-
removed: number;
|
|
7
|
-
path?: string;
|
|
8
|
-
}
|
|
9
|
-
export declare function getEditDiffDetails(tool: DisplayToolCall): EditDiffDetails | null;
|
|
10
|
-
export declare function formatEditSuccessSummary(details: EditDiffDetails | null): string;
|
|
11
|
-
export declare function formatEditStats(added: number, removed: number): string;
|