@bubblebrain-ai/bubble 0.0.20 → 0.0.21
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/dist/agent.d.ts +1 -0
- package/dist/agent.js +5 -1
- package/dist/checkpoints.d.ts +57 -0
- package/dist/checkpoints.js +0 -0
- package/dist/feishu/agent-host/run-driver.js +1 -0
- package/dist/main.js +54 -13
- package/dist/session.d.ts +31 -0
- package/dist/session.js +69 -0
- package/dist/slash-commands/commands.js +80 -0
- package/dist/slash-commands/types.d.ts +4 -0
- package/dist/tools/bash.js +4 -0
- package/dist/tools/edit.d.ts +2 -1
- package/dist/tools/edit.js +2 -1
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.js +2 -2
- package/dist/tools/write.d.ts +2 -1
- package/dist/tools/write.js +2 -1
- package/dist/tui/image-paste.d.ts +18 -0
- package/dist/tui/image-paste.js +60 -0
- package/dist/tui/run.js +309 -69
- package/dist/tui/trace-groups.d.ts +16 -0
- package/dist/tui/trace-groups.js +42 -1
- package/dist/tui/transcript-scroll.d.ts +25 -0
- package/dist/tui/transcript-scroll.js +20 -0
- package/dist/tui-ink/app.d.ts +4 -1
- package/dist/tui-ink/app.js +301 -247
- package/dist/tui-ink/display-history.d.ts +16 -1
- package/dist/tui-ink/display-history.js +50 -21
- package/dist/tui-ink/footer.d.ts +6 -12
- package/dist/tui-ink/footer.js +10 -29
- package/dist/tui-ink/image-paste.d.ts +59 -0
- package/dist/tui-ink/image-paste.js +277 -0
- package/dist/tui-ink/input-box.d.ts +26 -1
- package/dist/tui-ink/input-box.js +171 -41
- package/dist/tui-ink/message-list.d.ts +1 -1
- package/dist/tui-ink/message-list.js +46 -29
- package/dist/tui-ink/run.d.ts +7 -2
- package/dist/tui-ink/run.js +73 -23
- package/dist/tui-ink/terminal-mouse.d.ts +1 -0
- package/dist/tui-ink/terminal-mouse.js +4 -0
- package/dist/tui-ink/trace-groups.d.ts +16 -0
- package/dist/tui-ink/trace-groups.js +50 -2
- package/dist/tui-ink/transcript-viewport-math.d.ts +11 -0
- package/dist/tui-ink/transcript-viewport-math.js +17 -0
- package/dist/tui-ink/transcript-viewport.d.ts +24 -0
- package/dist/tui-ink/transcript-viewport.js +83 -0
- package/dist/tui-ink/welcome.d.ts +9 -7
- package/dist/tui-ink/welcome.js +7 -33
- package/package.json +1 -1
|
@@ -7,6 +7,10 @@ export interface TraceGroup {
|
|
|
7
7
|
count?: number;
|
|
8
8
|
noun?: string;
|
|
9
9
|
command?: string;
|
|
10
|
+
/** Model-provided one-line summary of what the command does (bash `description` arg). */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Original command split into lines, line breaks preserved (execute groups only). */
|
|
13
|
+
commandLines?: string[];
|
|
10
14
|
items: string[];
|
|
11
15
|
previewLines: string[];
|
|
12
16
|
errorLines: string[];
|
|
@@ -25,3 +29,15 @@ export declare function buildTraceGroups(toolCalls: DisplayToolCall[], options?:
|
|
|
25
29
|
export declare function formatTracePath(value: unknown, homeDir?: string): string;
|
|
26
30
|
export declare function formatElapsed(startedAt: number | undefined, now?: number): string | null;
|
|
27
31
|
export declare function traceGroupLabel(group: TraceGroup): string;
|
|
32
|
+
/**
|
|
33
|
+
* An execute command is shown inline in the header only when nothing is lost:
|
|
34
|
+
* no description competing for the slot, a single logical line, and it fits
|
|
35
|
+
* the width budget. Otherwise the full command renders as a wrapped block
|
|
36
|
+
* below the header — commands are never clipped mid-line.
|
|
37
|
+
*/
|
|
38
|
+
export declare function shouldInlineExecuteCommand(group: TraceGroup, widthBudget: number): boolean;
|
|
39
|
+
/** Visible command-block lines for compact rendering, capped at `maxLines`. */
|
|
40
|
+
export declare function executeCommandBlock(group: TraceGroup, maxLines: number): {
|
|
41
|
+
lines: string[];
|
|
42
|
+
omitted: number;
|
|
43
|
+
};
|
package/dist/tui/trace-groups.js
CHANGED
|
@@ -65,12 +65,36 @@ export function formatElapsed(startedAt, now = Date.now()) {
|
|
|
65
65
|
return `${minutes}m${remainder.toString().padStart(2, "0")}s`;
|
|
66
66
|
}
|
|
67
67
|
export function traceGroupLabel(group) {
|
|
68
|
+
if (group.description)
|
|
69
|
+
return `${group.title} ${group.description}`;
|
|
68
70
|
if (group.command)
|
|
69
71
|
return `${group.title} ${group.command}`;
|
|
70
72
|
if (group.count !== undefined && group.noun)
|
|
71
73
|
return `${group.title} ${group.count} ${group.noun}`;
|
|
72
74
|
return group.title;
|
|
73
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* An execute command is shown inline in the header only when nothing is lost:
|
|
78
|
+
* no description competing for the slot, a single logical line, and it fits
|
|
79
|
+
* the width budget. Otherwise the full command renders as a wrapped block
|
|
80
|
+
* below the header — commands are never clipped mid-line.
|
|
81
|
+
*/
|
|
82
|
+
export function shouldInlineExecuteCommand(group, widthBudget) {
|
|
83
|
+
if (group.kind !== "execute" || !group.command)
|
|
84
|
+
return false;
|
|
85
|
+
if (group.description)
|
|
86
|
+
return false;
|
|
87
|
+
const lines = group.commandLines ?? [];
|
|
88
|
+
if (lines.length > 1)
|
|
89
|
+
return false;
|
|
90
|
+
return group.command.length <= widthBudget;
|
|
91
|
+
}
|
|
92
|
+
/** Visible command-block lines for compact rendering, capped at `maxLines`. */
|
|
93
|
+
export function executeCommandBlock(group, maxLines) {
|
|
94
|
+
const lines = group.commandLines ?? [];
|
|
95
|
+
const shown = lines.slice(0, maxLines);
|
|
96
|
+
return { lines: shown, omitted: Math.max(0, lines.length - shown.length) };
|
|
97
|
+
}
|
|
74
98
|
function classifyTool(toolCall) {
|
|
75
99
|
if (toolCall.metadata?.kind === "subagent") {
|
|
76
100
|
return { kind: "subagent", title: "Subagents", bucketKey: `subagent:${toolCall.id}`, groupable: false };
|
|
@@ -244,11 +268,15 @@ function buildSearchGroup(classifier, raw, options, pending, startedAt, hasError
|
|
|
244
268
|
function buildExecuteGroup(classifier, tool, options, pending, startedAt, hasError, errorCount) {
|
|
245
269
|
const lines = resultLines(tool.result).map((line) => formatTracePath(line, options.homeDir));
|
|
246
270
|
const { shown, omitted } = take(lines, options.maxPreviewLines);
|
|
271
|
+
const rawCommand = String(tool.args.command ?? tool.args.cmd ?? commandFromRawArguments(tool.rawArguments) ?? "");
|
|
272
|
+
const description = String(tool.args.description ?? "").trim() || undefined;
|
|
247
273
|
return {
|
|
248
274
|
kind: "execute",
|
|
249
275
|
title: classifier.title,
|
|
250
276
|
raw: [tool],
|
|
251
|
-
command: normalizeCommand(
|
|
277
|
+
command: normalizeCommand(rawCommand),
|
|
278
|
+
description,
|
|
279
|
+
commandLines: commandLinesOf(rawCommand),
|
|
252
280
|
items: [],
|
|
253
281
|
previewLines: shown,
|
|
254
282
|
errorLines: [],
|
|
@@ -400,6 +428,19 @@ function normalizeCommand(value) {
|
|
|
400
428
|
const command = String(value ?? "").replace(/\s+/g, " ").trim();
|
|
401
429
|
return command;
|
|
402
430
|
}
|
|
431
|
+
// Preserves the command's own line structure (heredocs, && chains the model
|
|
432
|
+
// formatted across lines); only trims trailing whitespace and outer blank lines.
|
|
433
|
+
function commandLinesOf(rawCommand) {
|
|
434
|
+
const lines = rawCommand
|
|
435
|
+
.replace(/\r\n/g, "\n")
|
|
436
|
+
.split("\n")
|
|
437
|
+
.map((line) => line.trimEnd());
|
|
438
|
+
while (lines.length > 0 && lines[0].trim() === "")
|
|
439
|
+
lines.shift();
|
|
440
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "")
|
|
441
|
+
lines.pop();
|
|
442
|
+
return lines;
|
|
443
|
+
}
|
|
403
444
|
function commandFromRawArguments(rawArguments) {
|
|
404
445
|
if (!rawArguments)
|
|
405
446
|
return "";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcript scroll-follow policy.
|
|
3
|
+
*
|
|
4
|
+
* The transcript snaps to the bottom ("follows") while the user is at the
|
|
5
|
+
* bottom, and stays put while they read older history. Two events override a
|
|
6
|
+
* scrolled-up position and re-engage following:
|
|
7
|
+
* - the user sends a message (explicit intent to watch the newest turn)
|
|
8
|
+
* - an approval prompt appears (requires the user's attention)
|
|
9
|
+
*
|
|
10
|
+
* Those renders set `forcePending`, which must survive until the deferred
|
|
11
|
+
* scroll actually runs: streaming redraws in the interim recompute the follow
|
|
12
|
+
* flag from the (still unscrolled) position and would otherwise cancel the
|
|
13
|
+
* snap. A user mouse scroll clears the pending force — their latest gesture
|
|
14
|
+
* always wins.
|
|
15
|
+
*/
|
|
16
|
+
export interface TranscriptScrollState {
|
|
17
|
+
/** A forceFollow render is waiting for its deferred scroll to execute. */
|
|
18
|
+
forcePending: boolean;
|
|
19
|
+
/** The viewport was at the bottom when the update was scheduled. */
|
|
20
|
+
shouldFollow: boolean;
|
|
21
|
+
/** Live follow flag, recomputed from the viewport position on each render. */
|
|
22
|
+
following: boolean;
|
|
23
|
+
}
|
|
24
|
+
export type TranscriptScrollAction = "scroll-bottom" | "sync-position";
|
|
25
|
+
export declare function resolveTranscriptScroll(state: TranscriptScrollState): TranscriptScrollAction;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcript scroll-follow policy.
|
|
3
|
+
*
|
|
4
|
+
* The transcript snaps to the bottom ("follows") while the user is at the
|
|
5
|
+
* bottom, and stays put while they read older history. Two events override a
|
|
6
|
+
* scrolled-up position and re-engage following:
|
|
7
|
+
* - the user sends a message (explicit intent to watch the newest turn)
|
|
8
|
+
* - an approval prompt appears (requires the user's attention)
|
|
9
|
+
*
|
|
10
|
+
* Those renders set `forcePending`, which must survive until the deferred
|
|
11
|
+
* scroll actually runs: streaming redraws in the interim recompute the follow
|
|
12
|
+
* flag from the (still unscrolled) position and would otherwise cancel the
|
|
13
|
+
* snap. A user mouse scroll clears the pending force — their latest gesture
|
|
14
|
+
* always wins.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveTranscriptScroll(state) {
|
|
17
|
+
if (state.forcePending)
|
|
18
|
+
return "scroll-bottom";
|
|
19
|
+
return state.shouldFollow && state.following ? "scroll-bottom" : "sync-position";
|
|
20
|
+
}
|
package/dist/tui-ink/app.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { McpManager } from "../mcp/manager.js";
|
|
|
12
12
|
import type { LspService } from "../lsp/index.js";
|
|
13
13
|
import type { QuestionController } from "../question/index.js";
|
|
14
14
|
import type { MemoryScope } from "../memory/index.js";
|
|
15
|
+
import type { ExternalHookController } from "../hooks/controller.js";
|
|
15
16
|
export interface PlanHandlerRef {
|
|
16
17
|
current?: (plan: string) => Promise<PlanDecision>;
|
|
17
18
|
}
|
|
@@ -42,11 +43,13 @@ interface AppProps {
|
|
|
42
43
|
runMemoryRefresh?: (scope?: MemoryScope) => Promise<string>;
|
|
43
44
|
/** Whether the bypassPermissions mode is reachable via Shift+Tab cycling. */
|
|
44
45
|
bypassEnabled?: boolean;
|
|
46
|
+
updateNotice?: string;
|
|
47
|
+
hookController?: ExternalHookController;
|
|
45
48
|
onExit?: (summary: ExitSummary) => void;
|
|
46
49
|
}
|
|
47
50
|
export interface ExitSummary {
|
|
48
51
|
/** Wall-clock duration of the session, in milliseconds. */
|
|
49
52
|
wallMs: number;
|
|
50
53
|
}
|
|
51
|
-
export declare function App({ agent, args, sessionManager, createProvider, registry, skillRegistry, planHandlerRef, approvalHandlerRef, questionController, bashAllowlist, settingsManager, lspService, mcpManager, themeMode: initialThemeMode, themeOverrides, detectedTheme, onThemeModeChange, flushMemory, runMemoryCompaction, runMemorySummary, runMemoryRefresh, bypassEnabled, onExit }: AppProps): import("react/jsx-runtime").JSX.Element;
|
|
54
|
+
export declare function App({ agent, args, sessionManager, createProvider, registry, skillRegistry, planHandlerRef, approvalHandlerRef, questionController, bashAllowlist, settingsManager, lspService, mcpManager, themeMode: initialThemeMode, themeOverrides, detectedTheme, onThemeModeChange, flushMemory, runMemoryCompaction, runMemorySummary, runMemoryRefresh, bypassEnabled, updateNotice, hookController, onExit }: AppProps): import("react/jsx-runtime").JSX.Element;
|
|
52
55
|
export {};
|