@bubblebrain-ai/bubble 0.0.21 → 0.0.23
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 +197 -34
- package/dist/agent/abort-errors.d.ts +14 -0
- package/dist/agent/abort-errors.js +21 -0
- package/dist/agent/budget-ledger.d.ts +41 -0
- package/dist/agent/budget-ledger.js +64 -0
- package/dist/agent/child-runner.d.ts +55 -0
- package/dist/agent/child-runner.js +312 -0
- package/dist/agent/internal-reminder-sanitizer.js +29 -9
- package/dist/agent/profiles.d.ts +8 -0
- package/dist/agent/profiles.js +27 -5
- package/dist/agent/result-integrator.d.ts +22 -0
- package/dist/agent/result-integrator.js +50 -0
- package/dist/agent/subagent-control.d.ts +31 -0
- package/dist/agent/subagent-control.js +27 -0
- package/dist/agent/subagent-lifecycle-reminder.js +11 -2
- package/dist/agent/subagent-scheduler.d.ts +95 -0
- package/dist/agent/subagent-scheduler.js +256 -0
- package/dist/agent/subagent-store.d.ts +41 -0
- package/dist/agent/subagent-store.js +149 -0
- package/dist/agent/subagent-summary.d.ts +30 -0
- package/dist/agent/subagent-summary.js +74 -0
- package/dist/agent/worktree.d.ts +29 -0
- package/dist/agent/worktree.js +73 -0
- package/dist/agent.d.ts +63 -5
- package/dist/agent.js +360 -287
- package/dist/approval/controller.js +9 -1
- package/dist/approval/tool-helper.js +2 -0
- package/dist/approval/types.d.ts +17 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.js +17 -0
- package/dist/feishu/agent-host/approval-card.js +9 -0
- package/dist/feishu/agent-host/run-driver.js +1 -0
- package/dist/main.js +38 -2
- package/dist/model-catalog.js +6 -0
- package/dist/network/errors.d.ts +28 -0
- package/dist/network/errors.js +24 -0
- package/dist/orchestrator/default-hooks.js +5 -1
- package/dist/prompt/compose.js +3 -0
- package/dist/prompt/delegation.d.ts +14 -0
- package/dist/prompt/delegation.js +64 -0
- package/dist/prompt/task-reminders.d.ts +5 -1
- package/dist/prompt/task-reminders.js +10 -2
- package/dist/provider-anthropic.js +23 -0
- package/dist/provider-transform.js +14 -0
- package/dist/provider.js +23 -3
- package/dist/slash-commands/commands.js +29 -2
- package/dist/slash-commands/types.d.ts +2 -0
- package/dist/tools/agent-lifecycle.d.ts +29 -3
- package/dist/tools/agent-lifecycle.js +394 -40
- package/dist/tools/child-tools.d.ts +31 -0
- package/dist/tools/child-tools.js +106 -0
- package/dist/tools/index.js +1 -1
- package/dist/tui/run.d.ts +17 -1
- package/dist/tui/run.js +155 -10
- package/dist/tui/session-picker-data.d.ts +18 -0
- package/dist/tui/session-picker-data.js +21 -0
- package/dist/tui/trace-groups.js +41 -5
- package/dist/tui/wordmark.d.ts +2 -0
- package/dist/tui/wordmark.js +31 -4
- package/dist/tui-ink/approval/approval-dialog.js +10 -0
- package/dist/tui-opentui/approval/approval-dialog.js +10 -0
- package/dist/types.d.ts +17 -0
- package/dist/update/index.d.ts +18 -4
- package/dist/update/index.js +41 -19
- package/package.json +1 -1
|
@@ -77,6 +77,8 @@ function dialogTitle(req) {
|
|
|
77
77
|
return "Bash command";
|
|
78
78
|
case "lsp":
|
|
79
79
|
return "Language server operation";
|
|
80
|
+
case "agent_profile":
|
|
81
|
+
return "Project agent profile";
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
function dialogQuestion(req) {
|
|
@@ -91,6 +93,8 @@ function dialogQuestion(req) {
|
|
|
91
93
|
return "Do you want to proceed?";
|
|
92
94
|
case "lsp":
|
|
93
95
|
return `Do you want to run ${req.operation} on ${basename(req.path)}?`;
|
|
96
|
+
case "agent_profile":
|
|
97
|
+
return `Trust the repository profile "${req.name}" to drive a subagent? It is remembered for this session until the file changes.`;
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
function basename(p) {
|
|
@@ -107,8 +111,14 @@ function RequestPreview({ request }) {
|
|
|
107
111
|
return _jsx(DiffView, { diff: request.diff });
|
|
108
112
|
case "write":
|
|
109
113
|
return _jsx(WritePreview, { path: request.path, content: request.content });
|
|
114
|
+
case "agent_profile":
|
|
115
|
+
return _jsx(AgentProfilePreview, { path: request.path, promptPreview: request.promptPreview });
|
|
110
116
|
}
|
|
111
117
|
}
|
|
118
|
+
function AgentProfilePreview({ path, promptPreview }) {
|
|
119
|
+
const theme = useTheme();
|
|
120
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: theme.muted, children: compressHome(path) }), _jsx(Text, { children: promptPreview }), _jsx(Text, { color: theme.warning, children: "This prompt comes from the repository's .bubble/agents and will drive a subagent." })] }));
|
|
121
|
+
}
|
|
112
122
|
function BashPreview({ command, cwd }) {
|
|
113
123
|
const theme = useTheme();
|
|
114
124
|
const danger = classifyBashDanger(command);
|
|
@@ -84,6 +84,8 @@ function dialogTitle(req) {
|
|
|
84
84
|
return "Bash command";
|
|
85
85
|
case "lsp":
|
|
86
86
|
return "Language server operation";
|
|
87
|
+
case "agent_profile":
|
|
88
|
+
return "Project agent profile";
|
|
87
89
|
}
|
|
88
90
|
}
|
|
89
91
|
function dialogQuestion(req) {
|
|
@@ -98,6 +100,8 @@ function dialogQuestion(req) {
|
|
|
98
100
|
return "Do you want to proceed?";
|
|
99
101
|
case "lsp":
|
|
100
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.`;
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
function basename(p) {
|
|
@@ -114,8 +118,14 @@ function RequestPreview({ request }) {
|
|
|
114
118
|
return _jsx(DiffView, { diff: request.diff });
|
|
115
119
|
case "write":
|
|
116
120
|
return _jsx(WritePreview, { path: request.path, content: request.content });
|
|
121
|
+
case "agent_profile":
|
|
122
|
+
return _jsx(AgentProfilePreview, { path: request.path, promptPreview: request.promptPreview });
|
|
117
123
|
}
|
|
118
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
|
+
}
|
|
119
129
|
function BashPreview({ command, cwd }) {
|
|
120
130
|
const theme = useTheme();
|
|
121
131
|
const danger = classifyBashDanger(command);
|
package/dist/types.d.ts
CHANGED
|
@@ -199,6 +199,16 @@ export interface ToolContext {
|
|
|
199
199
|
}) => Promise<import("./agent/subagent-control.js").SubagentThreadSnapshot>;
|
|
200
200
|
closeSubAgent?: (agentId: string) => Promise<import("./agent/subagent-control.js").SubagentThreadSnapshot>;
|
|
201
201
|
listSubAgents?: () => import("./agent/subagent-control.js").SubagentThreadSnapshot[];
|
|
202
|
+
runAgentTeam?: (cwd: string, options: {
|
|
203
|
+
profile: import("./agent/profiles.js").AgentProfile;
|
|
204
|
+
category?: string;
|
|
205
|
+
promptTemplate: string;
|
|
206
|
+
items: string[];
|
|
207
|
+
parentToolCallId: string;
|
|
208
|
+
emitUpdate?: (update: ToolUpdate) => void;
|
|
209
|
+
abortSignal?: AbortSignal;
|
|
210
|
+
approval?: "fail" | "disabled";
|
|
211
|
+
}) => Promise<import("./agent/subagent-control.js").SubagentThreadSnapshot[]>;
|
|
202
212
|
};
|
|
203
213
|
emitUpdate?: (update: ToolUpdate) => void;
|
|
204
214
|
}
|
|
@@ -291,6 +301,13 @@ export interface Provider {
|
|
|
291
301
|
temperature?: number;
|
|
292
302
|
thinkingLevel?: ThinkingLevel;
|
|
293
303
|
abortSignal?: AbortSignal;
|
|
304
|
+
/**
|
|
305
|
+
* How the transport treats HTTP 429 (design doc §4.5). "handle"
|
|
306
|
+
* (default): retry inside the transport. "defer": throw a typed
|
|
307
|
+
* RateLimitError immediately so the caller owns the backoff — used by
|
|
308
|
+
* subagent routes where the scheduler is the single 429 backoff layer.
|
|
309
|
+
*/
|
|
310
|
+
rateLimitPolicy?: import("./network/errors.js").RateLimitPolicy;
|
|
294
311
|
}): AsyncIterable<StreamChunk>;
|
|
295
312
|
complete(messages: ProviderMessage[], options?: {
|
|
296
313
|
model?: string;
|
package/dist/update/index.d.ts
CHANGED
|
@@ -37,10 +37,24 @@ export declare function upgradeCommandFor(manager: PackageManager): {
|
|
|
37
37
|
export declare function runUpdateCommand(opts?: {
|
|
38
38
|
checkOnly?: boolean;
|
|
39
39
|
}): Promise<number>;
|
|
40
|
+
export interface StartupUpdateCheck {
|
|
41
|
+
/** Notice derived from the local cache — available immediately, no network. */
|
|
42
|
+
notice: string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Resolves once the background registry check completes: a notice string
|
|
45
|
+
* when it finds a version newer than both the running one and the cached
|
|
46
|
+
* `notice`, otherwise null. Never rejects.
|
|
47
|
+
*/
|
|
48
|
+
refreshed: Promise<string | null>;
|
|
49
|
+
}
|
|
40
50
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
51
|
+
* Startup "update available" check. The immediate `notice` comes from the
|
|
52
|
+
* local cache file (fast, no network on the hot path). A registry refresh
|
|
53
|
+
* always runs in the background (throttled to once per 30 minutes) so a
|
|
54
|
+
* release published since the last launch surfaces in the *current* session
|
|
55
|
+
* via `refreshed`, instead of only after the cache TTL plus another restart.
|
|
56
|
+
* Never throws.
|
|
45
57
|
*/
|
|
58
|
+
export declare function startStartupUpdateCheck(): Promise<StartupUpdateCheck>;
|
|
59
|
+
/** Cache-only variant of {@link startStartupUpdateCheck} (still refreshes in the background). */
|
|
46
60
|
export declare function getStartupUpdateNotice(): Promise<string | null>;
|
package/dist/update/index.js
CHANGED
|
@@ -16,7 +16,9 @@ import { getBubbleHome } from "../bubble-home.js";
|
|
|
16
16
|
const require = createRequire(import.meta.url);
|
|
17
17
|
export const PACKAGE_NAME = "@bubblebrain-ai/bubble";
|
|
18
18
|
const REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
19
|
-
|
|
19
|
+
// Throttle for the startup registry check. Short on purpose: with frequent
|
|
20
|
+
// releases, a long TTL means users only learn about a new version a day late.
|
|
21
|
+
const REFRESH_THROTTLE_MS = 30 * 60 * 1000;
|
|
20
22
|
export function getCurrentVersion() {
|
|
21
23
|
try {
|
|
22
24
|
const pkg = require("../../package.json");
|
|
@@ -209,32 +211,52 @@ async function writeCache(cache) {
|
|
|
209
211
|
// best-effort; never fail startup over a cache write
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (latest) {
|
|
215
|
-
await writeCache({ lastCheck: now, latest });
|
|
216
|
-
}
|
|
214
|
+
function formatUpdateNotice(current, latest) {
|
|
215
|
+
return `Update available: v${current} → v${latest} · run \`bubble update\``;
|
|
217
216
|
}
|
|
218
217
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
218
|
+
* Startup "update available" check. The immediate `notice` comes from the
|
|
219
|
+
* local cache file (fast, no network on the hot path). A registry refresh
|
|
220
|
+
* always runs in the background (throttled to once per 30 minutes) so a
|
|
221
|
+
* release published since the last launch surfaces in the *current* session
|
|
222
|
+
* via `refreshed`, instead of only after the cache TTL plus another restart.
|
|
223
|
+
* Never throws.
|
|
223
224
|
*/
|
|
224
|
-
export async function
|
|
225
|
+
export async function startStartupUpdateCheck() {
|
|
225
226
|
try {
|
|
226
227
|
const current = getCurrentVersion();
|
|
227
228
|
const now = Date.now();
|
|
228
229
|
const cache = await readCache();
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
const notice = cache && compareVersions(cache.latest, current) > 0
|
|
231
|
+
? formatUpdateNotice(current, cache.latest)
|
|
232
|
+
: null;
|
|
233
|
+
const refreshed = (async () => {
|
|
234
|
+
try {
|
|
235
|
+
if (cache && now - cache.lastCheck < REFRESH_THROTTLE_MS)
|
|
236
|
+
return null;
|
|
237
|
+
const latest = await fetchLatestVersion(4000);
|
|
238
|
+
if (!latest)
|
|
239
|
+
return null;
|
|
240
|
+
await writeCache({ lastCheck: now, latest });
|
|
241
|
+
if (compareVersions(latest, current) <= 0)
|
|
242
|
+
return null;
|
|
243
|
+
// The cache already surfaced this version in `notice` — stay quiet.
|
|
244
|
+
if (notice && cache && compareVersions(latest, cache.latest) <= 0)
|
|
245
|
+
return null;
|
|
246
|
+
return formatUpdateNotice(current, latest);
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
})();
|
|
252
|
+
return { notice, refreshed };
|
|
236
253
|
}
|
|
237
254
|
catch {
|
|
238
|
-
return null;
|
|
255
|
+
return { notice: null, refreshed: Promise.resolve(null) };
|
|
239
256
|
}
|
|
240
257
|
}
|
|
258
|
+
/** Cache-only variant of {@link startStartupUpdateCheck} (still refreshes in the background). */
|
|
259
|
+
export async function getStartupUpdateNotice() {
|
|
260
|
+
const check = await startStartupUpdateCheck();
|
|
261
|
+
return check.notice;
|
|
262
|
+
}
|