@bubblebrain-ai/bubble 0.0.24 → 0.0.25
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 +1 -1
- 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/provider.js +20 -5
- 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 +1360 -522
- 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 +70 -9
- package/dist/tui-ink/input-box.js +354 -120
- 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 +3 -1
- package/dist/tui-ink/message-list.js +42 -24
- package/dist/tui-ink/model-picker.d.ts +24 -2
- package/dist/tui-ink/model-picker.js +224 -20
- package/dist/tui-ink/plan-confirm.js +10 -0
- package/dist/tui-ink/question-dialog.js +10 -0
- package/dist/tui-ink/run.d.ts +10 -1
- package/dist/tui-ink/run.js +21 -28
- 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 +13 -1
- package/dist/tui-ink/terminal-mouse.js +63 -21
- package/dist/tui-ink/theme.d.ts +6 -3
- package/dist/tui-ink/theme.js +10 -4
- package/dist/tui-ink/transcript-input.d.ts +8 -0
- package/dist/tui-ink/transcript-input.js +9 -0
- package/dist/tui-ink/transcript-viewport-math.d.ts +1 -2
- package/dist/tui-ink/transcript-viewport-math.js +1 -2
- package/dist/tui-ink/welcome.d.ts +1 -0
- package/dist/tui-ink/welcome.js +25 -28
- 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-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,27 +1,69 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
1
|
+
// DECSET 1007 makes terminals translate wheel gestures into Up/Down arrows
|
|
2
|
+
// while the alternate screen is active. Keep it disabled in Ink; otherwise
|
|
3
|
+
// terminals without kitty event metadata make wheel and keyboard arrows
|
|
4
|
+
// indistinguishable.
|
|
5
|
+
export const ALTERNATE_SCROLL_ENABLE = "\x1b[?1007h";
|
|
6
|
+
export const ALTERNATE_SCROLL_DISABLE = "\x1b[?1007l";
|
|
7
|
+
// Use normal mouse tracking + SGR encoding so wheel events reach the app as
|
|
8
|
+
// mouse reports instead of being translated into keyboard arrows.
|
|
9
|
+
export const MOUSE_REPORTING_ENABLE = "\x1b[?1000h\x1b[?1006h";
|
|
10
|
+
// Disable every common tracking mode defensively in case a crash or another
|
|
11
|
+
// renderer left the terminal in a reporting state.
|
|
12
|
+
export const MOUSE_REPORTING_DISABLE = "\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?1005l\x1b[?1006l\x1b[?1015l";
|
|
13
|
+
const ESCAPED_MOUSE_SEQUENCE_RE = /\x1b(?:\[<(\d+);\d+;\d+([mM])|\[M([\s\S])[\s\S]{2})/g;
|
|
14
|
+
const RAW_SGR_MOUSE_SEQUENCE_RE = /\[?<(\d+);\d+;\d+([mM])/g;
|
|
15
|
+
const RAW_SGR_MOUSE_INPUT_RE = /^(?:\[?<\d+;\d+;\d+[mM])+$/;
|
|
16
|
+
function wheelDirectionFromButtonCode(code) {
|
|
17
|
+
if ((code & 64) !== 64)
|
|
18
|
+
return undefined;
|
|
19
|
+
const wheelButton = code & 0b11;
|
|
20
|
+
if (wheelButton === 0)
|
|
21
|
+
return "up";
|
|
22
|
+
if (wheelButton === 1)
|
|
23
|
+
return "down";
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
function collectWheelDirection(directions, code, final) {
|
|
27
|
+
if (final !== undefined && final !== "M")
|
|
28
|
+
return;
|
|
29
|
+
const direction = wheelDirectionFromButtonCode(code);
|
|
30
|
+
if (direction)
|
|
31
|
+
directions.push(direction);
|
|
32
|
+
}
|
|
33
|
+
export function sanitizeTerminalMouseInput(input) {
|
|
34
|
+
const wheelDirections = [];
|
|
35
|
+
let hasMouse = false;
|
|
36
|
+
ESCAPED_MOUSE_SEQUENCE_RE.lastIndex = 0;
|
|
37
|
+
let strippedInput = input.replace(ESCAPED_MOUSE_SEQUENCE_RE, (_sequence, sgrCode, sgrFinal, x10Button) => {
|
|
38
|
+
hasMouse = true;
|
|
39
|
+
const code = sgrCode !== undefined
|
|
40
|
+
? Number(sgrCode)
|
|
41
|
+
: (x10Button?.charCodeAt(0) ?? 32) - 32;
|
|
42
|
+
collectWheelDirection(wheelDirections, code, sgrFinal);
|
|
43
|
+
return "";
|
|
44
|
+
});
|
|
45
|
+
if (RAW_SGR_MOUSE_INPUT_RE.test(strippedInput)) {
|
|
46
|
+
hasMouse = true;
|
|
47
|
+
RAW_SGR_MOUSE_SEQUENCE_RE.lastIndex = 0;
|
|
48
|
+
strippedInput = strippedInput.replace(RAW_SGR_MOUSE_SEQUENCE_RE, (_sequence, sgrCode, sgrFinal) => {
|
|
49
|
+
collectWheelDirection(wheelDirections, Number(sgrCode), sgrFinal);
|
|
50
|
+
return "";
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return { strippedInput, wheelDirections, hasMouse };
|
|
54
|
+
}
|
|
55
|
+
export function transcriptScrollLinesFromMouseInput(mouseInput, options) {
|
|
56
|
+
if (options.overlayActive)
|
|
57
|
+
return [];
|
|
58
|
+
return mouseInput.wheelDirections.map((direction) => direction === "up" ? -1 : 1);
|
|
59
|
+
}
|
|
7
60
|
export function stripTerminalMouseSequences(input) {
|
|
8
|
-
return input.
|
|
61
|
+
return sanitizeTerminalMouseInput(input).strippedInput;
|
|
9
62
|
}
|
|
10
63
|
export function hasTerminalMouseSequence(input) {
|
|
11
|
-
|
|
12
|
-
return
|
|
64
|
+
ESCAPED_MOUSE_SEQUENCE_RE.lastIndex = 0;
|
|
65
|
+
return ESCAPED_MOUSE_SEQUENCE_RE.test(input) || RAW_SGR_MOUSE_INPUT_RE.test(input);
|
|
13
66
|
}
|
|
14
67
|
export function parseTerminalMouseWheel(input) {
|
|
15
|
-
|
|
16
|
-
SGR_MOUSE_WHEEL_RE.lastIndex = 0;
|
|
17
|
-
for (const match of input.matchAll(SGR_MOUSE_WHEEL_RE)) {
|
|
18
|
-
if (match[2] !== "M")
|
|
19
|
-
continue;
|
|
20
|
-
const code = Number(match[1]);
|
|
21
|
-
if (code === 64)
|
|
22
|
-
directions.push("up");
|
|
23
|
-
if (code === 65)
|
|
24
|
-
directions.push("down");
|
|
25
|
-
}
|
|
26
|
-
return directions;
|
|
68
|
+
return sanitizeTerminalMouseInput(input).wheelDirections;
|
|
27
69
|
}
|
package/dist/tui-ink/theme.d.ts
CHANGED
|
@@ -15,9 +15,12 @@ export interface Theme {
|
|
|
15
15
|
error: string;
|
|
16
16
|
warning: string;
|
|
17
17
|
success: string;
|
|
18
|
+
background: string;
|
|
18
19
|
accent: string;
|
|
19
20
|
border: string;
|
|
20
21
|
borderActive: string;
|
|
22
|
+
backgroundPanel: string;
|
|
23
|
+
backgroundElement: string;
|
|
21
24
|
inputBorder: string;
|
|
22
25
|
inputBorderDisabled: string;
|
|
23
26
|
inputBg: string;
|
|
@@ -49,9 +52,9 @@ export interface Theme {
|
|
|
49
52
|
}
|
|
50
53
|
export declare const darkTheme: Theme;
|
|
51
54
|
/**
|
|
52
|
-
* Light palette
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
+
* Light palette tuned for paper-neutral surfaces, blue focus/user rails, warm
|
|
56
|
+
* command accent, and semantic tool colors with readable contrast on a light
|
|
57
|
+
* terminal background.
|
|
55
58
|
*/
|
|
56
59
|
export declare const lightTheme: Theme;
|
|
57
60
|
export declare const ThemeProvider: import("react").Provider<Theme>;
|
package/dist/tui-ink/theme.js
CHANGED
|
@@ -14,9 +14,12 @@ export const darkTheme = {
|
|
|
14
14
|
error: "red",
|
|
15
15
|
warning: "yellow",
|
|
16
16
|
success: "green",
|
|
17
|
+
background: "#0A0A0A",
|
|
17
18
|
accent: "cyan",
|
|
18
19
|
border: "gray",
|
|
19
20
|
borderActive: "cyan",
|
|
21
|
+
backgroundPanel: "#141414",
|
|
22
|
+
backgroundElement: "#1c1c24",
|
|
20
23
|
inputBorder: "#8A7FC6",
|
|
21
24
|
inputBorderDisabled: "#4a4754",
|
|
22
25
|
inputBg: "#1c1c24",
|
|
@@ -47,9 +50,9 @@ export const darkTheme = {
|
|
|
47
50
|
diffRemoveFg: "#F48771",
|
|
48
51
|
};
|
|
49
52
|
/**
|
|
50
|
-
* Light palette
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
+
* Light palette tuned for paper-neutral surfaces, blue focus/user rails, warm
|
|
54
|
+
* command accent, and semantic tool colors with readable contrast on a light
|
|
55
|
+
* terminal background.
|
|
53
56
|
*/
|
|
54
57
|
export const lightTheme = {
|
|
55
58
|
user: "#356FD2",
|
|
@@ -57,13 +60,16 @@ export const lightTheme = {
|
|
|
57
60
|
error: "#B62633",
|
|
58
61
|
warning: "#8B4A00",
|
|
59
62
|
success: "#2F7D4A",
|
|
63
|
+
background: "#FCFCFA",
|
|
60
64
|
accent: "#8B4A00",
|
|
61
65
|
border: "#B9BDB8",
|
|
62
66
|
borderActive: "#356FD2",
|
|
67
|
+
backgroundPanel: "#F6F6F3",
|
|
68
|
+
backgroundElement: "#ECEDEA",
|
|
63
69
|
inputBorder: "#356FD2",
|
|
64
70
|
inputBorderDisabled: "#D7DAD4",
|
|
65
71
|
inputBg: "#F1F3F0",
|
|
66
|
-
inputBgDisabled: "#
|
|
72
|
+
inputBgDisabled: "#F6F6F3",
|
|
67
73
|
inputText: "#171717",
|
|
68
74
|
inputPlaceholder: "#6F7377",
|
|
69
75
|
muted: "#6F7377",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type TranscriptPageScrollDirection = "up" | "down";
|
|
2
|
+
export interface TranscriptKeyEvent {
|
|
3
|
+
pageUp?: boolean;
|
|
4
|
+
pageDown?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function transcriptPageScrollDirection(key: TranscriptKeyEvent, options: {
|
|
7
|
+
overlayActive: boolean;
|
|
8
|
+
}): TranscriptPageScrollDirection | undefined;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure scroll arithmetic for the alt-screen transcript viewport.
|
|
3
3
|
*
|
|
4
|
-
* Mirrors the
|
|
5
|
-
* transcriptMaxScrollTop / isTranscriptAtBottom): "at bottom" tolerates a
|
|
4
|
+
* Mirrors the historical transcript viewport semantics: "at bottom" tolerates a
|
|
6
5
|
* one-line slack so sub-line rounding never flips the follow flag while the
|
|
7
6
|
* user sits at the end of the transcript.
|
|
8
7
|
*/
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure scroll arithmetic for the alt-screen transcript viewport.
|
|
3
3
|
*
|
|
4
|
-
* Mirrors the
|
|
5
|
-
* transcriptMaxScrollTop / isTranscriptAtBottom): "at bottom" tolerates a
|
|
4
|
+
* Mirrors the historical transcript viewport semantics: "at bottom" tolerates a
|
|
6
5
|
* one-line slack so sub-line rounding never flips the follow flag while the
|
|
7
6
|
* user sits at the end of the transcript.
|
|
8
7
|
*/
|
|
@@ -17,4 +17,5 @@ interface WelcomeVisibilityInput {
|
|
|
17
17
|
}
|
|
18
18
|
export declare function shouldShowWelcomeBanner({ startedWithVisibleHistory, }: WelcomeVisibilityInput): boolean;
|
|
19
19
|
export declare function WelcomeBanner({ terminalColumns, tips, updateNotice, cwd, providerId, modelLabel, thinkingLabel, }: WelcomeBannerProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare function formatModelLine({ providerId, modelLabel, thinkingLabel, tips, }: Pick<WelcomeBannerProps, "providerId" | "modelLabel" | "thinkingLabel" | "tips">): string;
|
|
20
21
|
export {};
|
package/dist/tui-ink/welcome.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
2
|
import { Box, Text } from "ink";
|
|
4
3
|
import { createRequire } from "node:module";
|
|
5
4
|
import { useTheme } from "./theme.js";
|
|
6
|
-
import { bubbleWordmarkForWidth, } from "../tui/wordmark.js";
|
|
7
5
|
const require = createRequire(import.meta.url);
|
|
8
6
|
const PACKAGE_VERSION = readPackageVersion();
|
|
7
|
+
const COMPACT_LOGO = [
|
|
8
|
+
" ▄ ▄ ",
|
|
9
|
+
"██████",
|
|
10
|
+
"█ ██ █",
|
|
11
|
+
"██████",
|
|
12
|
+
" ▀ ▀ ",
|
|
13
|
+
];
|
|
9
14
|
export function shouldShowWelcomeBanner({ startedWithVisibleHistory, }) {
|
|
10
15
|
// Keep banner visibility tied to the initial history, not transient overlays,
|
|
11
16
|
// so opening and closing a picker does not move it in the transcript.
|
|
@@ -15,33 +20,25 @@ export function shouldShowWelcomeBanner({ startedWithVisibleHistory, }) {
|
|
|
15
20
|
}
|
|
16
21
|
export function WelcomeBanner({ terminalColumns, tips, updateNotice, cwd, providerId, modelLabel, thinkingLabel, }) {
|
|
17
22
|
const theme = useTheme();
|
|
18
|
-
const effectiveWidth = Math.max(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
? actionableTips.join(" · ")
|
|
27
|
-
: "Type / for commands and @ to reference files";
|
|
28
|
-
return (_jsxs(Box, { width: effectiveWidth, flexDirection: "column", alignItems: "center", marginBottom: 1, children: [_jsx(Box, { flexDirection: "column", alignItems: "center", children: logoLines.map((line, rowIndex) => (_jsx(LogoRow, { line: line }, `logo-row-${rowIndex}`))) }), _jsx(Box, { marginTop: 2, children: _jsx(Text, { bold: true, color: theme.muted, children: PACKAGE_VERSION }) }), updateNotice && (_jsx(Box, { children: _jsx(Text, { color: theme.accent, children: updateNotice }) })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { bold: true, color: theme.userMessageText, children: "TIP: " }), _jsx(Text, { bold: true, color: theme.userMessageText, children: tip })] }), (cwd || modelLabel) && (_jsxs(Box, { marginTop: 1, children: [cwd && _jsx(Text, { color: theme.muted, children: cwd }), cwd && (providerId || modelLabel) && _jsx(Text, { children: " " }), providerId && _jsxs(Text, { color: theme.muted, dimColor: true, children: [providerId, " \u00B7 "] }), modelLabel && (_jsxs(Text, { bold: true, color: theme.toolName, children: [modelLabel, thinkingLabel ? ` ${thinkingLabel}` : ""] }))] }))] }));
|
|
23
|
+
const effectiveWidth = Math.max(24, Math.min(terminalColumns - 2, 96));
|
|
24
|
+
const modelLine = formatModelLine({
|
|
25
|
+
providerId,
|
|
26
|
+
modelLabel,
|
|
27
|
+
thinkingLabel,
|
|
28
|
+
tips,
|
|
29
|
+
});
|
|
30
|
+
return (_jsxs(Box, { width: effectiveWidth, flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { flexDirection: "column", marginRight: 2, flexShrink: 0, children: COMPACT_LOGO.map((line, rowIndex) => (_jsx(Text, { color: theme.warning, bold: true, children: line }, `logo-row-${rowIndex}`))) }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: theme.inputText, children: "Bubble" }), _jsxs(Text, { color: theme.muted, children: [" ", PACKAGE_VERSION] })] }), modelLine && (_jsx(Text, { color: theme.muted, children: modelLine })), cwd && (_jsx(Text, { color: theme.muted, children: cwd }))] })] }), updateNotice && (_jsx(Box, { children: _jsx(Text, { color: theme.accent, children: updateNotice }) }))] }));
|
|
29
31
|
}
|
|
30
|
-
function
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
case "ink": return theme.userMessageText;
|
|
41
|
-
case "stone": return theme.muted;
|
|
42
|
-
case "soft": return theme.dim;
|
|
43
|
-
case "caption": return theme.muted;
|
|
44
|
-
}
|
|
32
|
+
export function formatModelLine({ providerId, modelLabel, thinkingLabel, tips, }) {
|
|
33
|
+
const parts = [];
|
|
34
|
+
if (modelLabel)
|
|
35
|
+
parts.push(thinkingLabel ? `${modelLabel} with ${thinkingLabel} effort` : modelLabel);
|
|
36
|
+
const readyTip = tips.find((item) => item.startsWith("Ready with"));
|
|
37
|
+
if (!modelLabel && readyTip)
|
|
38
|
+
parts.push(readyTip.replace(/^Ready with\s+/, ""));
|
|
39
|
+
if (providerId)
|
|
40
|
+
parts.push(providerId);
|
|
41
|
+
return parts.join(" · ");
|
|
45
42
|
}
|
|
46
43
|
function readPackageVersion() {
|
|
47
44
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bubblebrain-ai/bubble",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.25",
|
|
4
4
|
"description": "A terminal coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -25,9 +25,6 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@larksuiteoapi/node-sdk": "^1.65.0",
|
|
28
|
-
"@opentui/core": "^0.2.15",
|
|
29
|
-
"@opentui/react": "^0.2.15",
|
|
30
|
-
"@opentui/solid": "^0.2.15",
|
|
31
28
|
"@types/better-sqlite3": "^7.6.13",
|
|
32
29
|
"@types/react": "^19.2.14",
|
|
33
30
|
"@vue/language-server": "^3.2.7",
|
|
@@ -41,7 +38,6 @@
|
|
|
41
38
|
"qrcode-terminal": "^0.12.0",
|
|
42
39
|
"react": "^19.2.6",
|
|
43
40
|
"shiki": "^4.0.2",
|
|
44
|
-
"solid-js": "^1.9.12",
|
|
45
41
|
"string-width": "^8.2.1",
|
|
46
42
|
"typescript-language-server": "^5.1.3",
|
|
47
43
|
"undici": "^6.26.0",
|
package/dist/tui/clipboard.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function copyTextToClipboard(text: string): Promise<void>;
|
package/dist/tui/clipboard.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
export async function copyTextToClipboard(text) {
|
|
3
|
-
if (process.platform === "darwin") {
|
|
4
|
-
await writeToProcess("pbcopy", [], text);
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
if (process.platform === "win32") {
|
|
8
|
-
await writeToProcess("powershell", [
|
|
9
|
-
"-NoProfile",
|
|
10
|
-
"-Command",
|
|
11
|
-
"Set-Clipboard -Value ([Console]::In.ReadToEnd())",
|
|
12
|
-
], text);
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const candidates = [
|
|
16
|
-
["wl-copy", []],
|
|
17
|
-
["xclip", ["-selection", "clipboard"]],
|
|
18
|
-
["xsel", ["--clipboard", "--input"]],
|
|
19
|
-
];
|
|
20
|
-
let lastError;
|
|
21
|
-
for (const [command, args] of candidates) {
|
|
22
|
-
try {
|
|
23
|
-
await writeToProcess(command, args, text);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
lastError = error;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
throw lastError instanceof Error ? lastError : new Error("No clipboard command available");
|
|
31
|
-
}
|
|
32
|
-
function writeToProcess(command, args, input) {
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
const child = spawn(command, args, {
|
|
35
|
-
stdio: ["pipe", "ignore", "pipe"],
|
|
36
|
-
windowsHide: true,
|
|
37
|
-
});
|
|
38
|
-
let stderr = "";
|
|
39
|
-
child.stderr.setEncoding("utf8");
|
|
40
|
-
child.stderr.on("data", (chunk) => {
|
|
41
|
-
stderr += chunk;
|
|
42
|
-
});
|
|
43
|
-
child.on("error", reject);
|
|
44
|
-
child.on("close", (code) => {
|
|
45
|
-
if (code === 0) {
|
|
46
|
-
resolve();
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
reject(new Error(stderr.trim() || `${command} exited with code ${code}`));
|
|
50
|
-
});
|
|
51
|
-
child.stdin.end(input);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type EscapeConfirmationDecision = {
|
|
2
|
-
action: "arm";
|
|
3
|
-
expiresAt: number;
|
|
4
|
-
} | {
|
|
5
|
-
action: "confirm";
|
|
6
|
-
};
|
|
7
|
-
export declare class EscapeConfirmationGate {
|
|
8
|
-
private readonly windowMs;
|
|
9
|
-
private armedRunId;
|
|
10
|
-
private deadline;
|
|
11
|
-
constructor(windowMs: number);
|
|
12
|
-
press(runId: number, now?: number): EscapeConfirmationDecision;
|
|
13
|
-
isArmed(runId: number, now?: number): boolean;
|
|
14
|
-
clear(): void;
|
|
15
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export class EscapeConfirmationGate {
|
|
2
|
-
windowMs;
|
|
3
|
-
armedRunId;
|
|
4
|
-
deadline = 0;
|
|
5
|
-
constructor(windowMs) {
|
|
6
|
-
this.windowMs = windowMs;
|
|
7
|
-
}
|
|
8
|
-
press(runId, now = Date.now()) {
|
|
9
|
-
if (this.armedRunId === runId && now <= this.deadline) {
|
|
10
|
-
this.clear();
|
|
11
|
-
return { action: "confirm" };
|
|
12
|
-
}
|
|
13
|
-
this.armedRunId = runId;
|
|
14
|
-
this.deadline = now + this.windowMs;
|
|
15
|
-
return { action: "arm", expiresAt: this.deadline };
|
|
16
|
-
}
|
|
17
|
-
isArmed(runId, now = Date.now()) {
|
|
18
|
-
if (this.armedRunId !== runId)
|
|
19
|
-
return false;
|
|
20
|
-
if (now > this.deadline) {
|
|
21
|
-
this.clear();
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
clear() {
|
|
27
|
-
this.armedRunId = undefined;
|
|
28
|
-
this.deadline = 0;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { isEscapeSequence } from "./prompt-keybindings.js";
|
|
2
|
-
export function normalizeKeyName(name) {
|
|
3
|
-
const rawName = String(name || "").toLowerCase();
|
|
4
|
-
if (["arrowleft", "left_arrow", "leftarrow", "cursorleft", "left"].includes(rawName))
|
|
5
|
-
return "left";
|
|
6
|
-
if (["arrowright", "right_arrow", "rightarrow", "cursorright", "right"].includes(rawName))
|
|
7
|
-
return "right";
|
|
8
|
-
if (["arrowup", "up_arrow", "uparrow", "cursorup", "up"].includes(rawName))
|
|
9
|
-
return "up";
|
|
10
|
-
if (["arrowdown", "down_arrow", "downarrow", "cursordown", "down"].includes(rawName))
|
|
11
|
-
return "down";
|
|
12
|
-
if (rawName === "return" || rawName === "enter")
|
|
13
|
-
return "enter";
|
|
14
|
-
if (rawName === "esc" || rawName === "escape")
|
|
15
|
-
return "escape";
|
|
16
|
-
if (rawName === "tab")
|
|
17
|
-
return "tab";
|
|
18
|
-
return rawName;
|
|
19
|
-
}
|
|
20
|
-
export function keyNameFromSequence(sequence) {
|
|
21
|
-
if (!sequence)
|
|
22
|
-
return "";
|
|
23
|
-
const kittyName = keyNameFromKittySequence(sequence);
|
|
24
|
-
if (kittyName)
|
|
25
|
-
return kittyName;
|
|
26
|
-
if (sequence === "\x1b[D" || /^\x1b\[[0-9;]*D$/.test(sequence))
|
|
27
|
-
return "left";
|
|
28
|
-
if (sequence === "\x1b[C" || /^\x1b\[[0-9;]*C$/.test(sequence))
|
|
29
|
-
return "right";
|
|
30
|
-
if (sequence === "\x1b[A" || /^\x1b\[[0-9;]*A$/.test(sequence))
|
|
31
|
-
return "up";
|
|
32
|
-
if (sequence === "\x1b[B" || /^\x1b\[[0-9;]*B$/.test(sequence))
|
|
33
|
-
return "down";
|
|
34
|
-
if (sequence === "\x1bOD")
|
|
35
|
-
return "left";
|
|
36
|
-
if (sequence === "\x1bOC")
|
|
37
|
-
return "right";
|
|
38
|
-
if (sequence === "\x1bOA")
|
|
39
|
-
return "up";
|
|
40
|
-
if (sequence === "\x1bOB")
|
|
41
|
-
return "down";
|
|
42
|
-
if (sequence === "\t")
|
|
43
|
-
return "tab";
|
|
44
|
-
if (sequence === "\r" || sequence === "\n")
|
|
45
|
-
return "enter";
|
|
46
|
-
if (isEscapeSequence(sequence))
|
|
47
|
-
return "escape";
|
|
48
|
-
return "";
|
|
49
|
-
}
|
|
50
|
-
function keyNameFromKittySequence(sequence) {
|
|
51
|
-
const kittyMatch = /^\x1b\[(\d+)(?:;[1-9]\d*(?::[1-3])?)?u$/.exec(sequence);
|
|
52
|
-
const kittyCode = kittyMatch?.[1] ? Number(kittyMatch[1]) : NaN;
|
|
53
|
-
if (!Number.isNaN(kittyCode))
|
|
54
|
-
return keyNameFromKittyCode(kittyCode);
|
|
55
|
-
const modifyOtherKeysMatch = /^\x1b\[27;[1-9]\d*(?::[1-3])?;(\d+)~$/.exec(sequence);
|
|
56
|
-
const modifyOtherKeysCode = modifyOtherKeysMatch?.[1] ? Number(modifyOtherKeysMatch[1]) : NaN;
|
|
57
|
-
if (!Number.isNaN(modifyOtherKeysCode))
|
|
58
|
-
return keyNameFromKittyCode(modifyOtherKeysCode);
|
|
59
|
-
return "";
|
|
60
|
-
}
|
|
61
|
-
function keyNameFromKittyCode(code) {
|
|
62
|
-
switch (code) {
|
|
63
|
-
case 27:
|
|
64
|
-
case 57344:
|
|
65
|
-
return "escape";
|
|
66
|
-
case 9:
|
|
67
|
-
case 57346:
|
|
68
|
-
return "tab";
|
|
69
|
-
case 13:
|
|
70
|
-
case 57345:
|
|
71
|
-
return "enter";
|
|
72
|
-
case 57350:
|
|
73
|
-
return "left";
|
|
74
|
-
case 57351:
|
|
75
|
-
return "right";
|
|
76
|
-
case 57352:
|
|
77
|
-
return "up";
|
|
78
|
-
case 57353:
|
|
79
|
-
return "down";
|
|
80
|
-
default:
|
|
81
|
-
return "";
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
export function keyNameFromEvent(event) {
|
|
85
|
-
const rawName = normalizeKeyName(event?.name || event?.key || event?.input);
|
|
86
|
-
return rawName || keyNameFromSequence(event?.raw || event?.sequence);
|
|
87
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export interface MarkdownInlineSegment {
|
|
2
|
-
text: string;
|
|
3
|
-
color?: "text" | "textMuted" | "success" | "warning" | "secondary";
|
|
4
|
-
bold?: boolean;
|
|
5
|
-
italic?: boolean;
|
|
6
|
-
dim?: boolean;
|
|
7
|
-
}
|
|
8
|
-
type InlineToken = {
|
|
9
|
-
type?: string;
|
|
10
|
-
text?: string;
|
|
11
|
-
raw?: string;
|
|
12
|
-
href?: string;
|
|
13
|
-
tokens?: InlineToken[];
|
|
14
|
-
};
|
|
15
|
-
interface InlineStyle {
|
|
16
|
-
bold?: boolean;
|
|
17
|
-
italic?: boolean;
|
|
18
|
-
dim?: boolean;
|
|
19
|
-
color?: MarkdownInlineSegment["color"];
|
|
20
|
-
}
|
|
21
|
-
export declare function markdownInlineSegments(tokens: InlineToken[] | undefined, fallback?: string, style?: InlineStyle): MarkdownInlineSegment[];
|
|
22
|
-
export {};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
export function markdownInlineSegments(tokens, fallback = "", style = {}) {
|
|
2
|
-
const segments = [];
|
|
3
|
-
for (const token of tokens ?? []) {
|
|
4
|
-
appendInlineToken(segments, token, style);
|
|
5
|
-
}
|
|
6
|
-
if (segments.length === 0 && fallback) {
|
|
7
|
-
appendStyled(segments, fallback, style);
|
|
8
|
-
}
|
|
9
|
-
return segments;
|
|
10
|
-
}
|
|
11
|
-
function appendInlineToken(segments, token, style) {
|
|
12
|
-
switch (token.type) {
|
|
13
|
-
case "strong":
|
|
14
|
-
appendInlineTokens(segments, token.tokens, { ...style, bold: true });
|
|
15
|
-
return;
|
|
16
|
-
case "em":
|
|
17
|
-
appendInlineTokens(segments, token.tokens, { ...style, italic: true, color: style.color ?? "warning" });
|
|
18
|
-
return;
|
|
19
|
-
case "del":
|
|
20
|
-
appendInlineTokens(segments, token.tokens, { ...style, dim: true, color: style.color ?? "textMuted" });
|
|
21
|
-
return;
|
|
22
|
-
case "codespan":
|
|
23
|
-
appendStyled(segments, token.text ?? "", { ...style, color: "success" });
|
|
24
|
-
return;
|
|
25
|
-
case "link":
|
|
26
|
-
appendInlineTokens(segments, token.tokens, { ...style, color: style.color ?? "secondary" });
|
|
27
|
-
return;
|
|
28
|
-
case "br":
|
|
29
|
-
appendStyled(segments, "\n", style);
|
|
30
|
-
return;
|
|
31
|
-
case "text":
|
|
32
|
-
case "paragraph":
|
|
33
|
-
case "list_item":
|
|
34
|
-
case "heading":
|
|
35
|
-
if (token.tokens?.length) {
|
|
36
|
-
appendInlineTokens(segments, token.tokens, style);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
appendStyled(segments, token.text ?? token.raw ?? "", style);
|
|
40
|
-
}
|
|
41
|
-
return;
|
|
42
|
-
case "space":
|
|
43
|
-
return;
|
|
44
|
-
default:
|
|
45
|
-
if (token.tokens?.length) {
|
|
46
|
-
appendInlineTokens(segments, token.tokens, style);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
appendStyled(segments, token.text ?? token.raw ?? "", style);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function appendInlineTokens(segments, tokens, style) {
|
|
54
|
-
for (const child of tokens ?? []) {
|
|
55
|
-
appendInlineToken(segments, child, style);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function appendStyled(segments, text, style) {
|
|
59
|
-
if (!text)
|
|
60
|
-
return;
|
|
61
|
-
segments.push({
|
|
62
|
-
text,
|
|
63
|
-
color: style.color ?? "text",
|
|
64
|
-
bold: style.bold,
|
|
65
|
-
italic: style.italic,
|
|
66
|
-
dim: style.dim,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export interface MarkdownThemePalette {
|
|
2
|
-
text: string;
|
|
3
|
-
textMuted: string;
|
|
4
|
-
background: string;
|
|
5
|
-
secondary: string;
|
|
6
|
-
info: string;
|
|
7
|
-
success: string;
|
|
8
|
-
warning: string;
|
|
9
|
-
accent: string;
|
|
10
|
-
error: string;
|
|
11
|
-
}
|
|
12
|
-
export interface SyntaxThemeRule {
|
|
13
|
-
scope: string[];
|
|
14
|
-
style: {
|
|
15
|
-
foreground?: string;
|
|
16
|
-
background?: string;
|
|
17
|
-
bold?: boolean;
|
|
18
|
-
italic?: boolean;
|
|
19
|
-
underline?: boolean;
|
|
20
|
-
dim?: boolean;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export declare function buildMarkdownThemeRules(theme: MarkdownThemePalette): SyntaxThemeRule[];
|