@bubblebrain-ai/bubble 0.0.45 → 0.0.47
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/child-runner.js +11 -0
- package/dist/agent/internal-reminder-sanitizer.d.ts +7 -0
- package/dist/agent/internal-reminder-sanitizer.js +13 -0
- package/dist/agent/subagent/router.d.ts +65 -0
- package/dist/agent/subagent/router.js +198 -0
- package/dist/agent/subagent/runtime.d.ts +203 -0
- package/dist/agent/subagent/runtime.js +789 -0
- package/dist/agent/subagent-control.d.ts +5 -0
- package/dist/agent/subagent-store.d.ts +18 -2
- package/dist/agent/subagent-store.js +32 -1
- package/dist/agent/tool-intent.d.ts +10 -0
- package/dist/agent/tool-intent.js +18 -0
- package/dist/agent/tool-visibility.d.ts +10 -0
- package/dist/agent/tool-visibility.js +6 -0
- package/dist/agent/workflow/runs.d.ts +72 -0
- package/dist/agent/workflow/runs.js +157 -0
- package/dist/agent.d.ts +78 -96
- package/dist/agent.js +266 -1072
- package/dist/context/compact-llm.js +14 -5
- package/dist/context/compact.d.ts +9 -0
- package/dist/context/compact.js +36 -10
- package/dist/context/compaction-files.d.ts +44 -0
- package/dist/context/compaction-files.js +148 -0
- package/dist/context/llm-compactor.js +24 -5
- package/dist/feishu/agent-host/run-driver.js +3 -0
- package/dist/feishu/serve.js +13 -9
- package/dist/goal/tools.js +12 -3
- package/dist/main.js +24 -19
- package/dist/model-catalog.js +36 -2
- package/dist/model-config.d.ts +2 -0
- package/dist/model-data.generated.d.ts +16 -0
- package/dist/model-data.generated.js +275 -0
- package/dist/model-pricing.d.ts +11 -7
- package/dist/model-pricing.js +0 -0
- package/dist/oauth/grok.d.ts +1 -1
- package/dist/oauth/grok.js +58 -29
- package/dist/oauth/openai-codex.js +13 -0
- package/dist/oauth/storage.d.ts +9 -2
- package/dist/oauth/storage.js +16 -9
- package/dist/orchestrator/default-hooks.d.ts +20 -0
- package/dist/orchestrator/default-hooks.js +47 -295
- package/dist/orchestrator/hooks.d.ts +6 -39
- package/dist/permission/mode.js +1 -1
- package/dist/prompt/reminders.d.ts +9 -35
- package/dist/prompt/reminders.js +30 -136
- package/dist/prompt/task-reminders.d.ts +0 -31
- package/dist/prompt/task-reminders.js +0 -87
- package/dist/provider-ai-sdk.d.ts +2 -0
- package/dist/provider-ai-sdk.js +1 -0
- package/dist/provider-anthropic.d.ts +2 -0
- package/dist/provider-anthropic.js +3 -1
- package/dist/provider-ark-responses.d.ts +2 -0
- package/dist/provider-ark-responses.js +1 -0
- package/dist/provider-registry.d.ts +13 -0
- package/dist/provider-registry.js +83 -0
- package/dist/provider-transform.js +37 -1
- package/dist/provider.d.ts +7 -0
- package/dist/provider.js +13 -1
- package/dist/sdk/index.d.ts +152 -0
- package/dist/sdk/index.js +400 -0
- package/dist/session.js +9 -1
- package/dist/slash-commands/commands.js +33 -19
- package/dist/tools/exit-plan-mode.js +8 -0
- package/dist/tui/detect-theme.d.ts +1 -0
- package/dist/tui/detect-theme.js +11 -5
- package/dist/tui-ink/app.d.ts +2 -6
- package/dist/tui-ink/app.js +11 -18
- package/dist/tui-ink/display-history.d.ts +0 -2
- package/dist/tui-ink/display-history.js +0 -52
- package/dist/tui-ink/footer.js +2 -2
- package/dist/tui-ink/message-list.js +62 -23
- package/dist/tui-ink/run.js +10 -5
- package/dist/tui-ink/sync-output.d.ts +17 -0
- package/dist/tui-ink/sync-output.js +35 -0
- package/dist/tui-ink/theme.d.ts +0 -1
- package/dist/tui-ink/theme.js +0 -2
- package/dist/tui-ink/trace-groups.js +1 -1
- package/dist/types.d.ts +21 -1
- package/package.json +16 -2
- package/dist/agent/discovery-barrier.d.ts +0 -21
- package/dist/agent/discovery-barrier.js +0 -173
- package/dist/agent/evidence-tracker.d.ts +0 -15
- package/dist/agent/evidence-tracker.js +0 -93
- package/dist/agent/execution-governor.d.ts +0 -36
- package/dist/agent/execution-governor.js +0 -218
- package/dist/agent/task-classifier.d.ts +0 -3
- package/dist/agent/task-classifier.js +0 -114
- package/dist/agent/task-size.d.ts +0 -9
- package/dist/agent/task-size.js +0 -33
- package/dist/agent/tool-arbiter.d.ts +0 -7
- package/dist/agent/tool-arbiter.js +0 -33
- package/dist/orchestrator/workflow.d.ts +0 -10
- package/dist/orchestrator/workflow.js +0 -22
package/dist/oauth/grok.js
CHANGED
|
@@ -34,11 +34,28 @@ function openBrowser(url) {
|
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* xAI's OAuth client allows dynamic loopback ports, so listen on an ephemeral
|
|
37
|
-
* port
|
|
37
|
+
* port. Awaiting this returns only once the socket is actually bound, so the
|
|
38
|
+
* caller can never build an authorization URL around an empty redirect URI.
|
|
38
39
|
*/
|
|
39
|
-
async function startCallbackServer(timeoutMs,
|
|
40
|
-
|
|
40
|
+
async function startCallbackServer(timeoutMs, onStatus) {
|
|
41
|
+
let settle = () => { };
|
|
42
|
+
let fail = () => { };
|
|
43
|
+
const result = new Promise((resolve, reject) => {
|
|
44
|
+
settle = resolve;
|
|
45
|
+
fail = reject;
|
|
46
|
+
});
|
|
47
|
+
// Nothing awaits `result` until the caller has a redirect URI, and an early
|
|
48
|
+
// rejection (bind failure) would otherwise be an unhandled rejection.
|
|
49
|
+
result.catch(() => { });
|
|
50
|
+
return new Promise((resolveListening, rejectListening) => {
|
|
41
51
|
let resolved = false;
|
|
52
|
+
const finish = (action) => {
|
|
53
|
+
if (resolved)
|
|
54
|
+
return;
|
|
55
|
+
resolved = true;
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
server.close(action);
|
|
58
|
+
};
|
|
42
59
|
const server = createServer((req, res) => {
|
|
43
60
|
try {
|
|
44
61
|
const port = server.address().port;
|
|
@@ -51,19 +68,13 @@ async function startCallbackServer(timeoutMs, onListening, onStatus) {
|
|
|
51
68
|
if (error) {
|
|
52
69
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
53
70
|
res.end(`<html><body><h1>Authorization failed</h1><p>${errorDesc || error}</p></body></html>`);
|
|
54
|
-
|
|
55
|
-
resolved = true;
|
|
56
|
-
server.close(() => reject(new Error(`OAuth error: ${errorDesc || error}`)));
|
|
57
|
-
}
|
|
71
|
+
finish(() => fail(new Error(`OAuth error: ${errorDesc || error}`)));
|
|
58
72
|
return;
|
|
59
73
|
}
|
|
60
74
|
if (code) {
|
|
61
75
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
62
76
|
res.end("<html><body><h1>Authorization successful</h1><p>You can close this window and return to the terminal.</p></body></html>");
|
|
63
|
-
|
|
64
|
-
resolved = true;
|
|
65
|
-
server.close(() => resolve({ code, state: state || "" }));
|
|
66
|
-
}
|
|
77
|
+
finish(() => settle({ code, state: state || "" }));
|
|
67
78
|
return;
|
|
68
79
|
}
|
|
69
80
|
}
|
|
@@ -75,17 +86,32 @@ async function startCallbackServer(timeoutMs, onListening, onStatus) {
|
|
|
75
86
|
res.end("Error");
|
|
76
87
|
}
|
|
77
88
|
});
|
|
89
|
+
// Unref'd so a pending login never keeps the process alive on its own,
|
|
90
|
+
// and cleared on completion so a successful login does not leave the
|
|
91
|
+
// event loop holding a five-minute timer.
|
|
92
|
+
const timer = setTimeout(() => {
|
|
93
|
+
finish(() => fail(new Error(`OAuth login timed out after ${timeoutMs / 1000}s`)));
|
|
94
|
+
}, timeoutMs);
|
|
95
|
+
timer.unref?.();
|
|
96
|
+
// Without this, a failed bind (port exhausted, sandbox denies listening)
|
|
97
|
+
// never rejects anything — the login just hangs until the timeout.
|
|
98
|
+
server.on("error", (error) => {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
if (resolved)
|
|
101
|
+
return;
|
|
102
|
+
resolved = true;
|
|
103
|
+
rejectListening(error instanceof Error ? error : new Error(String(error)));
|
|
104
|
+
fail(error instanceof Error ? error : new Error(String(error)));
|
|
105
|
+
});
|
|
78
106
|
server.listen(0, "127.0.0.1", () => {
|
|
79
107
|
const port = server.address().port;
|
|
80
108
|
onStatus?.(`Local server listening on http://127.0.0.1:${port}`);
|
|
81
|
-
|
|
109
|
+
// Resolve only once the socket is genuinely bound. The caller used to
|
|
110
|
+
// race this with a single setImmediate tick and declare failure if the
|
|
111
|
+
// listen callback had not fired yet — which it frequently has not, since
|
|
112
|
+
// binding is real async I/O.
|
|
113
|
+
resolveListening({ redirectUri: `http://127.0.0.1:${port}/callback`, result });
|
|
82
114
|
});
|
|
83
|
-
setTimeout(() => {
|
|
84
|
-
if (!resolved) {
|
|
85
|
-
resolved = true;
|
|
86
|
-
server.close(() => reject(new Error(`OAuth login timed out after ${timeoutMs / 1000}s`)));
|
|
87
|
-
}
|
|
88
|
-
}, timeoutMs);
|
|
89
115
|
});
|
|
90
116
|
}
|
|
91
117
|
function parseTokenResponse(data, fallbackRefreshToken) {
|
|
@@ -109,15 +135,15 @@ export async function loginGrok(callbacks, options = {}) {
|
|
|
109
135
|
const pkce = generatePKCE();
|
|
110
136
|
const state = generateOpaqueId();
|
|
111
137
|
const nonce = generateOpaqueId();
|
|
112
|
-
let redirectUri
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
throw new Error(
|
|
138
|
+
let redirectUri;
|
|
139
|
+
let serverPromise;
|
|
140
|
+
try {
|
|
141
|
+
const server = await startCallbackServer(5 * 60 * 1000, callbacks?.onStatus);
|
|
142
|
+
redirectUri = server.redirectUri;
|
|
143
|
+
serverPromise = server.result;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
throw new Error(`The local OAuth callback server could not start: ${error instanceof Error ? error.message : String(error)}`);
|
|
121
147
|
}
|
|
122
148
|
const params = new URLSearchParams({
|
|
123
149
|
response_type: "code",
|
|
@@ -181,10 +207,13 @@ export async function refreshGrok(refreshToken, options = {}) {
|
|
|
181
207
|
* Bubble's isolated runtime profile or the user's real ~/.grok). Users who
|
|
182
208
|
* already completed `grok login` skip the browser round-trip entirely.
|
|
183
209
|
*/
|
|
184
|
-
export function importGrokCliCredentials(bubbleHome = join(homedir(), ".bubble")
|
|
210
|
+
export function importGrokCliCredentials(bubbleHome = join(homedir(), ".bubble"),
|
|
211
|
+
// Injectable so tests can isolate the ~/.grok fallback from the real home
|
|
212
|
+
// directory; production callers rely on the default.
|
|
213
|
+
homeDir = homedir()) {
|
|
185
214
|
const candidates = [
|
|
186
215
|
join(bubbleHome, "runtimes", "grok", "grok-home", "auth.json"),
|
|
187
|
-
join(
|
|
216
|
+
join(homeDir, ".grok", "auth.json"),
|
|
188
217
|
];
|
|
189
218
|
for (const path of candidates) {
|
|
190
219
|
let parsed;
|
|
@@ -63,6 +63,19 @@ async function startCallbackServer(port, timeoutMs, onStatus) {
|
|
|
63
63
|
res.end("Error");
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
|
+
// This flow binds a FIXED port (the provider only whitelists one redirect
|
|
67
|
+
// URI), so EADDRINUSE is a realistic outcome — a stale login, or any other
|
|
68
|
+
// process on the port. Without this handler nothing rejects and the user
|
|
69
|
+
// stares at "waiting for authorization" for the full timeout.
|
|
70
|
+
server.on("error", (error) => {
|
|
71
|
+
if (resolved)
|
|
72
|
+
return;
|
|
73
|
+
resolved = true;
|
|
74
|
+
const detail = error?.code === "EADDRINUSE"
|
|
75
|
+
? `port ${port} is already in use — close any other sign-in still running and retry`
|
|
76
|
+
: error instanceof Error ? error.message : String(error);
|
|
77
|
+
reject(new Error(`The local OAuth callback server could not start: ${detail}`));
|
|
78
|
+
});
|
|
66
79
|
server.listen(port, "127.0.0.1", () => {
|
|
67
80
|
onStatus?.(`Local server listening on http://127.0.0.1:${port}`);
|
|
68
81
|
});
|
package/dist/oauth/storage.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OAuth credential storage in
|
|
2
|
+
* OAuth credential storage in <bubble home>/auth.json.
|
|
3
|
+
*
|
|
4
|
+
* The path is resolved at CONSTRUCTION time through getBubbleHome(), never at
|
|
5
|
+
* module load: a module-level constant froze the real ~/.bubble at import,
|
|
6
|
+
* which no test could isolate (known-defects #7) and which ignored
|
|
7
|
+
* BUBBLE_HOME / dev mode while every other config file honored them
|
|
8
|
+
* (config.json, sessions, memory all derive from getBubbleHome).
|
|
3
9
|
*/
|
|
4
10
|
import type { OAuthCredentials } from "./types.js";
|
|
5
11
|
export declare class AuthStorage {
|
|
6
12
|
private data;
|
|
7
13
|
private mutationListeners;
|
|
8
|
-
|
|
14
|
+
private readonly authPath;
|
|
15
|
+
constructor(authPath?: string);
|
|
9
16
|
/**
|
|
10
17
|
* Observe credential writes/removals. Callers across the codebase mutate
|
|
11
18
|
* this storage directly (login/logout flows), so consumers that must react
|
package/dist/oauth/storage.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OAuth credential storage in
|
|
2
|
+
* OAuth credential storage in <bubble home>/auth.json.
|
|
3
|
+
*
|
|
4
|
+
* The path is resolved at CONSTRUCTION time through getBubbleHome(), never at
|
|
5
|
+
* module load: a module-level constant froze the real ~/.bubble at import,
|
|
6
|
+
* which no test could isolate (known-defects #7) and which ignored
|
|
7
|
+
* BUBBLE_HOME / dev mode while every other config file honored them
|
|
8
|
+
* (config.json, sessions, memory all derive from getBubbleHome).
|
|
3
9
|
*/
|
|
4
10
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
11
|
import { dirname, join } from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
const AUTH_PATH = join(homedir(), ".bubble", "auth.json");
|
|
12
|
+
import { getBubbleHome } from "../bubble-home.js";
|
|
8
13
|
export class AuthStorage {
|
|
9
14
|
data = {};
|
|
10
15
|
mutationListeners = [];
|
|
11
|
-
|
|
16
|
+
authPath;
|
|
17
|
+
constructor(authPath = join(getBubbleHome(), "auth.json")) {
|
|
18
|
+
this.authPath = authPath;
|
|
12
19
|
this.load();
|
|
13
20
|
}
|
|
14
21
|
/**
|
|
@@ -34,10 +41,10 @@ export class AuthStorage {
|
|
|
34
41
|
}
|
|
35
42
|
}
|
|
36
43
|
load() {
|
|
37
|
-
if (!existsSync(
|
|
44
|
+
if (!existsSync(this.authPath))
|
|
38
45
|
return;
|
|
39
46
|
try {
|
|
40
|
-
const raw = readFileSync(
|
|
47
|
+
const raw = readFileSync(this.authPath, "utf-8");
|
|
41
48
|
const parsed = JSON.parse(raw);
|
|
42
49
|
this.data = parsed;
|
|
43
50
|
}
|
|
@@ -46,13 +53,13 @@ export class AuthStorage {
|
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
save() {
|
|
49
|
-
const dir = dirname(
|
|
56
|
+
const dir = dirname(this.authPath);
|
|
50
57
|
if (!existsSync(dir))
|
|
51
58
|
mkdirSync(dir, { recursive: true });
|
|
52
|
-
writeFileSync(
|
|
59
|
+
writeFileSync(this.authPath, JSON.stringify(this.data, null, 2) + "\n", { mode: 0o600 });
|
|
53
60
|
}
|
|
54
61
|
getPath() {
|
|
55
|
-
return
|
|
62
|
+
return this.authPath;
|
|
56
63
|
}
|
|
57
64
|
get(providerId) {
|
|
58
65
|
return this.data[providerId];
|
|
@@ -1,2 +1,22 @@
|
|
|
1
1
|
import type { TurnHooks } from "./hooks.js";
|
|
2
|
+
/**
|
|
3
|
+
* Default hooks: infrastructure and information only.
|
|
4
|
+
*
|
|
5
|
+
* The cognitive-governance layer that used to live here (task classifier,
|
|
6
|
+
* step-budget governor, discovery barrier, evidence tracker, bash-search
|
|
7
|
+
* arbitration, delegation nudge, completion self-check) was removed — see
|
|
8
|
+
* docs/harness-thinning.md. The TurnHooks mechanism itself stays, pi-style:
|
|
9
|
+
* hosts may install their own policies, the core ships none.
|
|
10
|
+
*
|
|
11
|
+
* What remains, and why it passes the ruler in that document:
|
|
12
|
+
* - resident-history compaction calls (infrastructure)
|
|
13
|
+
* - background-task and subagent-lifecycle reminders (facts the model
|
|
14
|
+
* cannot otherwise see)
|
|
15
|
+
* - orchestrationRequestReminder (deliberately retained policy: amplifies
|
|
16
|
+
* the user's EXPLICIT orchestration request at the decision turn)
|
|
17
|
+
* - userNamedModelReminder (deterministic catalog resolution of a model the
|
|
18
|
+
* user named — information the model would otherwise retype from priors)
|
|
19
|
+
* - modified-existing-tests disclosure (git ground truth: bash writes and
|
|
20
|
+
* subagent worktree merges do not appear in the model's own tool memory)
|
|
21
|
+
*/
|
|
2
22
|
export declare function createDefaultHooks(): TurnHooks[];
|