@bubblebrain-ai/bubble 0.0.49 → 0.0.51

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.
Files changed (64) hide show
  1. package/dist/agent/abort-errors.d.ts +4 -0
  2. package/dist/agent/abort-errors.js +30 -0
  3. package/dist/agent/profiles.js +3 -4
  4. package/dist/agent/provider-fingerprint.d.ts +6 -0
  5. package/dist/agent/provider-fingerprint.js +89 -0
  6. package/dist/agent/resident-history.d.ts +7 -0
  7. package/dist/agent/resident-history.js +61 -0
  8. package/dist/agent/subtask-policy.js +4 -4
  9. package/dist/agent/transcript-helpers.d.ts +20 -0
  10. package/dist/agent/transcript-helpers.js +62 -0
  11. package/dist/agent/update-queue.d.ts +13 -0
  12. package/dist/agent/update-queue.js +69 -0
  13. package/dist/agent.d.ts +33 -26
  14. package/dist/agent.js +80 -334
  15. package/dist/debug-trace.js +0 -2
  16. package/dist/external-runtime/grok-runtime.js +1 -1
  17. package/dist/feishu/agent-host/run-driver.js +1 -8
  18. package/dist/feishu/card/run-state.js +0 -3
  19. package/dist/lsp/service.js +2 -2
  20. package/dist/main.js +0 -15
  21. package/dist/memory/phase1.js +0 -2
  22. package/dist/model-catalog.js +8 -6
  23. package/dist/permissions/settings.d.ts +0 -1
  24. package/dist/permissions/settings.js +0 -2
  25. package/dist/prompt/compose.js +0 -3
  26. package/dist/prompt/environment.js +0 -2
  27. package/dist/prompt/reminders.js +1 -1
  28. package/dist/provider-registry.js +13 -1
  29. package/dist/provider-transform.js +7 -8
  30. package/dist/sdk/index.d.ts +17 -2
  31. package/dist/sdk/index.js +37 -6
  32. package/dist/session-log.d.ts +2 -4
  33. package/dist/session-log.js +0 -23
  34. package/dist/session-types.d.ts +2 -6
  35. package/dist/session.d.ts +1 -3
  36. package/dist/session.js +0 -8
  37. package/dist/slash-commands/commands.js +13 -13
  38. package/dist/tools/child-tools.d.ts +1 -1
  39. package/dist/tools/child-tools.js +1 -1
  40. package/dist/tools/grep.js +1 -1
  41. package/dist/tools/index.d.ts +0 -3
  42. package/dist/tools/index.js +0 -3
  43. package/dist/tui-ink/app-helpers.d.ts +43 -0
  44. package/dist/tui-ink/app-helpers.js +150 -0
  45. package/dist/tui-ink/app.d.ts +4 -11
  46. package/dist/tui-ink/app.js +57 -657
  47. package/dist/tui-ink/command-palette.d.ts +32 -0
  48. package/dist/tui-ink/command-palette.js +158 -0
  49. package/dist/tui-ink/display-reconstruct.d.ts +3 -0
  50. package/dist/tui-ink/display-reconstruct.js +82 -0
  51. package/dist/tui-ink/message-list.js +0 -1
  52. package/dist/tui-ink/rewind-picker.d.ts +8 -0
  53. package/dist/tui-ink/rewind-picker.js +102 -0
  54. package/dist/tui-ink/session-picker.js +1 -1
  55. package/dist/tui-ink/stats-panel.d.ts +11 -0
  56. package/dist/tui-ink/stats-panel.js +65 -0
  57. package/dist/tui-ink/waiting-indicator.d.ts +12 -0
  58. package/dist/tui-ink/waiting-indicator.js +129 -0
  59. package/dist/types.d.ts +0 -9
  60. package/package.json +1 -1
  61. package/dist/tools/todo.d.ts +0 -12
  62. package/dist/tools/todo.js +0 -136
  63. package/dist/tui-ink/todos.d.ts +0 -7
  64. package/dist/tui-ink/todos.js +0 -46
@@ -0,0 +1,43 @@
1
+ import type { Agent } from "../agent.js";
2
+ import { type ProviderRegistry } from "../provider-registry.js";
3
+ import type { BackgroundTaskInfo } from "../tasks/manager.js";
4
+ import { type DisplayMessage } from "./display-history.js";
5
+ export declare const TASK_WAKE_DEBOUNCE_MS = 2000;
6
+ export declare function buildTips(agent: Agent, registry: ProviderRegistry, grokActive?: boolean): string[];
7
+ /**
8
+ * Slash-command results arrive as plain strings; recognize the /model
9
+ * confirmations by shape so they render as accent-colored UI notices — the
10
+ * same treatment the picker path applies — instead of assistant prose.
11
+ */
12
+ export declare function slashResultNoticeKind(result: string): DisplayMessage["syntheticKind"] | undefined;
13
+ /** Status-row summary for running background tasks (design §2.5). */
14
+ export declare function taskRowSummary(tasks: BackgroundTaskInfo[], nowTick: number): string;
15
+ export declare function friendlyCwd(cwd: string): string;
16
+ export declare function sessionBasename(sessionFile: string | undefined): string | undefined;
17
+ export declare function truncate(value: string, max: number): string;
18
+ export declare function formatCompactTokens(n: number): string;
19
+ export declare function formatContextUsageLabel(snapshot: {
20
+ usedTokens: number;
21
+ contextWindow?: number;
22
+ }): string;
23
+ /**
24
+ * Streaming tool arguments arrive as an incomplete JSON buffer. We can't
25
+ * JSON.parse() until the closing brace lands, but the user wants to see the
26
+ * short identifying fields (path, command, …) as soon as the model emits
27
+ * them so the tool row header reflects what's happening.
28
+ *
29
+ * Intentionally limited to short, single-line fields. Long fields like
30
+ * `content` are *not* surfaced live: rendering thousands of partial lines
31
+ * per delta floods the terminal and the partial value can break around
32
+ * unescaped sequences. The final value lands when the tool actually
33
+ * executes and tool_start delivers canonical args.
34
+ */
35
+ export declare function parsePartialArgs(buffer: string, previous: Record<string, any>): Record<string, any>;
36
+ /**
37
+ * Coerce a freshly-constructed DisplayMessage into one that carries a stable
38
+ * `key`. Centralizes the safety net so callers don't have to remember to call
39
+ * nextDisplayMessageKey on every push.
40
+ */
41
+ export declare function withMessageKey(message: DisplayMessage): DisplayMessage;
42
+ export declare const STREAMING_FLUSH_INTERVAL_MS = 40;
43
+ export declare function clampWindowStartForIndex(total: number, selectedIndex: number, maxVisible: number): number;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Pure helpers for the Ink app: welcome tips, status-row summaries,
3
+ * cwd/session labels, truncation, context-usage formatting, partial
4
+ * streaming-arg extraction, display-message keying, and the scrolling-window
5
+ * clamp shared by the picker overlays.
6
+ */
7
+ import os from "node:os";
8
+ import { displayModel } from "../provider-registry.js";
9
+ import { nextDisplayMessageKey } from "./display-history.js";
10
+ export const TASK_WAKE_DEBOUNCE_MS = 2000;
11
+ export function buildTips(agent, registry, grokActive = false) {
12
+ const tips = [];
13
+ if (grokActive) {
14
+ return [
15
+ "Grok Subscription is active with workspace tools and Bubble approvals",
16
+ "Use /model to choose the Grok model and reasoning effort",
17
+ "Use /logout grok to return to a fresh native session",
18
+ ];
19
+ }
20
+ const hasProvider = registry.getEnabled().length > 0;
21
+ if (!hasProvider) {
22
+ tips.push("Run /login or /provider --add to configure a model");
23
+ }
24
+ else if (agent.model) {
25
+ tips.push(`Ready with ${displayModel(agent.model)}`);
26
+ }
27
+ else {
28
+ tips.push("Run /model to pick a model");
29
+ }
30
+ tips.push("Type @ to reference a file");
31
+ tips.push("Type / for commands and skills");
32
+ return tips;
33
+ }
34
+ /**
35
+ * Slash-command results arrive as plain strings; recognize the /model
36
+ * confirmations by shape so they render as accent-colored UI notices — the
37
+ * same treatment the picker path applies — instead of assistant prose.
38
+ */
39
+ export function slashResultNoticeKind(result) {
40
+ return /^(Grok m|M)odel switched to /.test(result) ? "ui_notice" : undefined;
41
+ }
42
+ /** Status-row summary for running background tasks (design §2.5). */
43
+ export function taskRowSummary(tasks, nowTick) {
44
+ const first = tasks[0];
45
+ const label = first.description?.trim() || first.command.replace(/\s+/g, " ").slice(0, 32);
46
+ const elapsed = Math.max(0, Math.round((nowTick - first.startedAt) / 1000));
47
+ return `${label} ${elapsed}s`;
48
+ }
49
+ export function friendlyCwd(cwd) {
50
+ const home = os.homedir();
51
+ if (cwd === home)
52
+ return "~";
53
+ if (cwd.startsWith(home + "/"))
54
+ return "~" + cwd.slice(home.length);
55
+ return cwd;
56
+ }
57
+ export function sessionBasename(sessionFile) {
58
+ if (!sessionFile)
59
+ return undefined;
60
+ const base = sessionFile.split("/").pop() ?? sessionFile;
61
+ return base.replace(/\.jsonl$/, "");
62
+ }
63
+ export function truncate(value, max) {
64
+ if (value.length <= max)
65
+ return value;
66
+ return `${value.slice(0, Math.max(0, max - 1))}…`;
67
+ }
68
+ export function formatCompactTokens(n) {
69
+ if (n < 1000)
70
+ return `${Math.round(n)}`;
71
+ if (n < 1_000_000)
72
+ return `${(n / 1000).toFixed(n >= 10000 ? 0 : 1)}K`;
73
+ return `${(n / 1_000_000).toFixed(n >= 10_000_000 ? 0 : 1)}M`;
74
+ }
75
+ export function formatContextUsageLabel(snapshot) {
76
+ if (!snapshot.contextWindow || snapshot.contextWindow <= 0) {
77
+ return `${formatCompactTokens(snapshot.usedTokens)} context`;
78
+ }
79
+ const percent = (snapshot.usedTokens / snapshot.contextWindow) * 100;
80
+ const label = percent >= 10
81
+ ? `${Math.round(percent)}%`
82
+ : percent >= 0.05
83
+ ? `${percent.toFixed(1)}%`
84
+ : "<0.1%";
85
+ return `${label} context`;
86
+ }
87
+ /**
88
+ * Streaming tool arguments arrive as an incomplete JSON buffer. We can't
89
+ * JSON.parse() until the closing brace lands, but the user wants to see the
90
+ * short identifying fields (path, command, …) as soon as the model emits
91
+ * them so the tool row header reflects what's happening.
92
+ *
93
+ * Intentionally limited to short, single-line fields. Long fields like
94
+ * `content` are *not* surfaced live: rendering thousands of partial lines
95
+ * per delta floods the terminal and the partial value can break around
96
+ * unescaped sequences. The final value lands when the tool actually
97
+ * executes and tool_start delivers canonical args.
98
+ */
99
+ export function parsePartialArgs(buffer, previous) {
100
+ // If the buffer is now valid JSON, prefer the real parse.
101
+ try {
102
+ const parsed = JSON.parse(buffer);
103
+ if (parsed && typeof parsed === "object")
104
+ return parsed;
105
+ }
106
+ catch {
107
+ // fall through to partial extraction below
108
+ }
109
+ const result = { ...previous };
110
+ const FIELDS = ["path", "command", "pattern", "url", "query"];
111
+ for (const field of FIELDS) {
112
+ // Match a complete-looking quoted string. Requires a closing quote so we
113
+ // don't surface half-typed paths that may still change as bytes arrive.
114
+ const match = buffer.match(new RegExp(`"${field}"\\s*:\\s*"((?:\\\\.|[^"\\\\])*)"`));
115
+ if (match) {
116
+ const raw = match[1] ?? "";
117
+ result[field] = raw
118
+ .replace(/\\n/g, "\n")
119
+ .replace(/\\t/g, "\t")
120
+ .replace(/\\"/g, '"')
121
+ .replace(/\\\\/g, "\\");
122
+ }
123
+ }
124
+ return result;
125
+ }
126
+ /**
127
+ * Coerce a freshly-constructed DisplayMessage into one that carries a stable
128
+ * `key`. Centralizes the safety net so callers don't have to remember to call
129
+ * nextDisplayMessageKey on every push.
130
+ */
131
+ export function withMessageKey(message) {
132
+ if (message.key)
133
+ return message;
134
+ const prefix = message.role === "user" ? "user" : message.role === "error" ? "err" : "asst";
135
+ return { ...message, key: nextDisplayMessageKey(prefix) };
136
+ }
137
+ // Batch streaming text deltas before committing them to React state. Without
138
+ // <Static>, every commit re-renders the full-screen frame; per-token commits
139
+ // would make Yoga re-lay-out the transcript for every few bytes of output.
140
+ // 40ms keeps perceived latency invisible while capping layout work at 25fps.
141
+ export const STREAMING_FLUSH_INTERVAL_MS = 40;
142
+ export function clampWindowStartForIndex(total, selectedIndex, maxVisible) {
143
+ if (total <= maxVisible)
144
+ return 0;
145
+ const half = Math.floor(maxVisible / 2);
146
+ let start = Math.max(0, selectedIndex - half);
147
+ if (start + maxVisible > total)
148
+ start = total - maxVisible;
149
+ return Math.max(0, start);
150
+ }
@@ -1,8 +1,7 @@
1
1
  import { type Agent } from "../agent.js";
2
2
  import type { CliArgs } from "../cli.js";
3
3
  import { SessionManager } from "../session.js";
4
- import type { Message, PlanDecision, Provider } from "../types.js";
5
- import { type DisplayMessage } from "./display-history.js";
4
+ import type { PlanDecision, Provider } from "../types.js";
6
5
  import { type ResolvedTheme, type ThemeMode } from "./theme.js";
7
6
  import { ProviderRegistry } from "../provider-registry.js";
8
7
  import { SkillRegistry } from "../skills/registry.js";
@@ -18,6 +17,8 @@ import type { GoalStore } from "../goal/store.js";
18
17
  import { isInternalBlockOnlyContent } from "../agent/internal-reminder-sanitizer.js";
19
18
  import type { ProcessManager } from "../tasks/manager.js";
20
19
  import type { PromotionChannel } from "../tasks/promotion.js";
20
+ export { reconstructDisplayMessages } from "./display-reconstruct.js";
21
+ export { INK_LOCAL_SLASH_COMMANDS } from "./command-palette.js";
21
22
  import type { ExternalRuntimeManager } from "../external-runtime/types.js";
22
23
  export interface PlanHandlerRef {
23
24
  current?: (plan: string) => Promise<PlanDecision>;
@@ -72,12 +73,4 @@ export interface ExitSummary {
72
73
  wallMs: number;
73
74
  }
74
75
  export { isInternalBlockOnlyContent };
75
- export declare function reconstructDisplayMessages(agentMessages: Message[]): DisplayMessage[];
76
- export declare const INK_LOCAL_SLASH_COMMANDS: readonly [{
77
- readonly name: "goal";
78
- readonly description: "Set/manage an autonomous goal (/goal <objective>|clear|pause|resume|edit)";
79
- }, {
80
- readonly name: "loop";
81
- readonly description: "Run a prompt on a recurring interval (/loop 5m <prompt>|list|stop [id])";
82
- }];
83
- export declare function App({ agent, args, sessionManager: initialSessionManager, switchSession, createProvider, registry, skillRegistry, planHandlerRef, approvalHandlerRef, questionController, bashAllowlist, settingsManager, lspService, mcpManager, themeMode: initialThemeMode, themeOverrides, detectedTheme, onThemeModeChange, flushMemory, runMemoryCompaction, runMemorySummary, runMemoryRefresh, goalStore, processManager, tasksAutoResume, promotionChannel, bypassEnabled, updateNotice, updateNoticeRefresh, hookController, externalRuntime, onExit }: AppProps): import("react/jsx-runtime").JSX.Element;
76
+ export declare function App({ agent, args, sessionManager: initialSessionManager, switchSession, createProvider, registry, skillRegistry, planHandlerRef, approvalHandlerRef, questionController, bashAllowlist, settingsManager, lspService, mcpManager, themeMode: initialThemeMode, themeOverrides, detectedTheme, onThemeModeChange, flushMemory, runMemoryCompaction, runMemorySummary, runMemoryRefresh, goalStore, processManager, tasksAutoResume, promotionChannel, updateNotice, updateNoticeRefresh, hookController, externalRuntime, onExit }: AppProps): import("react/jsx-runtime").JSX.Element;