@bubblebrain-ai/bubble 0.0.32 → 0.0.33

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.
@@ -72,6 +72,12 @@ function friendlyCwd(cwd) {
72
72
  return "~" + cwd.slice(home.length);
73
73
  return cwd;
74
74
  }
75
+ function sessionBasename(sessionFile) {
76
+ if (!sessionFile)
77
+ return undefined;
78
+ const base = sessionFile.split("/").pop() ?? sessionFile;
79
+ return base.replace(/\.jsonl$/, "");
80
+ }
75
81
  function truncate(value, max) {
76
82
  if (value.length <= max)
77
83
  return value;
@@ -1686,7 +1692,7 @@ export function App({ agent, args, sessionManager: initialSessionManager, switch
1686
1692
  const showThinkingLabel = Boolean(thinkingLevel)
1687
1693
  && thinkingLevel !== "off"
1688
1694
  && (isMiniMaxProvider || getAvailableThinkingLevels(agent.providerId, agent.apiModel).length > 2);
1689
- const welcomeBannerNode = showWelcome ? (_jsx(WelcomeBanner, { terminalColumns: terminalColumns, tips: buildTips(agent, safeRegistry), updateNotice: currentUpdateNotice, cwd: friendlyCwd(args.cwd), providerId: agent.providerId || safeRegistry.getDefault()?.id, modelLabel: agent.model ? displayModel(agent.model) : undefined, thinkingLabel: showThinkingLabel ? thinkingLevel : undefined })) : null;
1695
+ const welcomeBannerNode = showWelcome ? (_jsx(WelcomeBanner, { terminalColumns: terminalColumns, tips: buildTips(agent, safeRegistry), updateNotice: currentUpdateNotice, cwd: friendlyCwd(args.cwd), sessionLabel: sessionBasename(currentSessionFile()), providerId: agent.providerId || safeRegistry.getDefault()?.id, modelLabel: agent.model ? displayModel(agent.model) : undefined, thinkingLabel: showThinkingLabel ? thinkingLevel : undefined })) : null;
1690
1696
  const commandPaletteItems = useMemo(() => buildCommandPaletteItems(safeSkillRegistry), [safeSkillRegistry]);
1691
1697
  const mcpReconnectItems = useMemo(() => buildMcpReconnectItems(mcpManager), [mcpManager]);
1692
1698
  // No fixed-height frame: settled rows flow into the terminal's native
@@ -17,6 +17,11 @@ export interface Theme {
17
17
  success: string;
18
18
  background: string;
19
19
  accent: string;
20
+ /** Welcome banner border. */
21
+ bannerBorder: string;
22
+ /** Welcome banner logo/title gradient endpoints (top→bottom, left→right). */
23
+ bannerGradientFrom: string;
24
+ bannerGradientTo: string;
20
25
  border: string;
21
26
  borderActive: string;
22
27
  backgroundPanel: string;
@@ -16,6 +16,9 @@ export const darkTheme = {
16
16
  success: "green",
17
17
  background: "#0A0A0A",
18
18
  accent: "cyan",
19
+ bannerBorder: "#38bdf8",
20
+ bannerGradientFrom: "#67e8f9",
21
+ bannerGradientTo: "#a78bfa",
19
22
  border: "gray",
20
23
  borderActive: "cyan",
21
24
  backgroundPanel: "#141414",
@@ -62,6 +65,9 @@ export const lightTheme = {
62
65
  success: "#2F7D4A",
63
66
  background: "#FCFCFA",
64
67
  accent: "#8B4A00",
68
+ bannerBorder: "#356FD2",
69
+ bannerGradientFrom: "#0E7490",
70
+ bannerGradientTo: "#6D28D9",
65
71
  border: "#B9BDB8",
66
72
  borderActive: "#356FD2",
67
73
  backgroundPanel: "#F6F6F3",
@@ -6,6 +6,8 @@ interface WelcomeBannerProps {
6
6
  updateNotice?: string;
7
7
  /** Friendly working directory (~ collapsed). */
8
8
  cwd?: string;
9
+ /** Session identifier (session file basename). */
10
+ sessionLabel?: string;
9
11
  providerId?: string;
10
12
  modelLabel?: string;
11
13
  /** Active thinking level, rendered as part of the model unit (e.g. "xhigh"). */
@@ -16,6 +18,7 @@ interface WelcomeVisibilityInput {
16
18
  startedWithVisibleHistory: boolean;
17
19
  }
18
20
  export declare function shouldShowWelcomeBanner({ startedWithVisibleHistory, }: WelcomeVisibilityInput): boolean;
19
- export declare function WelcomeBanner({ terminalColumns, tips, updateNotice, cwd, providerId, modelLabel, thinkingLabel, }: WelcomeBannerProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function lerpColor(from: string, to: string, t: number): string;
22
+ export declare function WelcomeBanner({ terminalColumns, tips, updateNotice, cwd, sessionLabel, providerId, modelLabel, thinkingLabel, }: WelcomeBannerProps): import("react/jsx-runtime").JSX.Element;
20
23
  export declare function formatModelLine({ providerId, modelLabel, thinkingLabel, tips, }: Pick<WelcomeBannerProps, "providerId" | "modelLabel" | "thinkingLabel" | "tips">): string;
21
24
  export {};
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
3
  import { createRequire } from "node:module";
4
4
  import { useTheme } from "./theme.js";
@@ -18,7 +18,17 @@ export function shouldShowWelcomeBanner({ startedWithVisibleHistory, }) {
18
18
  return false;
19
19
  return true;
20
20
  }
21
- export function WelcomeBanner({ terminalColumns, tips, updateNotice, cwd, providerId, modelLabel, thinkingLabel, }) {
21
+ export function lerpColor(from, to, t) {
22
+ const pa = [1, 3, 5].map((i) => parseInt(from.slice(i, i + 2), 16));
23
+ const pb = [1, 3, 5].map((i) => parseInt(to.slice(i, i + 2), 16));
24
+ const out = pa.map((v, i) => Math.round(v + ((pb[i] ?? v) - v) * t));
25
+ return `#${out.map((v) => v.toString(16).padStart(2, "0")).join("")}`;
26
+ }
27
+ function GradientText({ text, from, to }) {
28
+ const chars = [...text];
29
+ return (_jsx(_Fragment, { children: chars.map((ch, i) => (_jsx(Text, { bold: true, color: lerpColor(from, to, chars.length <= 1 ? 0 : i / (chars.length - 1)), children: ch }, `ch-${i}`))) }));
30
+ }
31
+ export function WelcomeBanner({ terminalColumns, tips, updateNotice, cwd, sessionLabel, providerId, modelLabel, thinkingLabel, }) {
22
32
  const theme = useTheme();
23
33
  const effectiveWidth = Math.max(24, Math.min(terminalColumns - 2, 96));
24
34
  const modelLine = formatModelLine({
@@ -27,7 +37,16 @@ export function WelcomeBanner({ terminalColumns, tips, updateNotice, cwd, provid
27
37
  thinkingLabel,
28
38
  tips,
29
39
  });
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 }) }))] }));
40
+ const infoRows = [];
41
+ if (cwd)
42
+ infoRows.push({ label: "Directory:", value: cwd, color: theme.inputText });
43
+ if (sessionLabel)
44
+ infoRows.push({ label: "Session:", value: sessionLabel, color: theme.muted });
45
+ if (modelLine)
46
+ infoRows.push({ label: "Model:", value: modelLine, color: theme.traceCommand });
47
+ infoRows.push({ label: "Version:", value: PACKAGE_VERSION, color: theme.muted });
48
+ const labelWidth = Math.max(...infoRows.map((row) => row.label.length)) + 1;
49
+ return (_jsxs(Box, { width: effectiveWidth, flexDirection: "column", marginBottom: 1, borderStyle: "round", borderColor: theme.bannerBorder, paddingX: 2, children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { flexDirection: "column", marginRight: 2, flexShrink: 0, children: COMPACT_LOGO.map((line, rowIndex) => (_jsx(Text, { bold: true, color: lerpColor(theme.bannerGradientFrom, theme.bannerGradientTo, COMPACT_LOGO.length <= 1 ? 0 : rowIndex / (COMPACT_LOGO.length - 1)), children: line }, `logo-row-${rowIndex}`))) }), _jsxs(Box, { flexDirection: "column", marginTop: 1, flexGrow: 1, flexShrink: 1, children: [_jsx(Box, { children: _jsx(GradientText, { text: "Welcome to Bubble!", from: theme.bannerGradientFrom, to: theme.bannerGradientTo }) }), _jsx(Text, { color: theme.muted, wrap: "wrap", children: "I am a cat and you can send /help for help information." })] })] }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: infoRows.map((row) => (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: theme.dim, children: row.label.padEnd(labelWidth) }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsx(Text, { color: row.color, wrap: "wrap", children: row.value }) })] }, row.label))) }), updateNotice && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.accent, children: updateNotice }) }))] }));
31
50
  }
32
51
  export function formatModelLine({ providerId, modelLabel, thinkingLabel, tips, }) {
33
52
  const parts = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bubblebrain-ai/bubble",
3
- "version": "0.0.32",
3
+ "version": "0.0.33",
4
4
  "description": "A terminal coding agent",
5
5
  "type": "module",
6
6
  "engines": {