@bubblebrain-ai/bubble 0.0.10 → 0.0.12
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.d.ts +1 -0
- package/dist/agent.js +6 -2
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +31 -3
- package/dist/feedback/collect.d.ts +7 -0
- package/dist/feedback/collect.js +119 -0
- package/dist/feedback/config.d.ts +14 -0
- package/dist/feedback/config.js +16 -0
- package/dist/feedback/redact.d.ts +1 -0
- package/dist/feedback/redact.js +25 -0
- package/dist/feedback/submit.d.ts +6 -0
- package/dist/feedback/submit.js +43 -0
- package/dist/feedback/types.d.ts +22 -0
- package/dist/feishu/agent-host/approval-card.d.ts +11 -0
- package/dist/feishu/agent-host/approval-card.js +46 -0
- package/dist/feishu/agent-host/approval-ui.d.ts +59 -0
- package/dist/feishu/agent-host/approval-ui.js +214 -0
- package/dist/feishu/agent-host/run-driver.d.ts +51 -0
- package/dist/feishu/agent-host/run-driver.js +302 -0
- package/dist/feishu/agent-host/runtime-deps.d.ts +33 -0
- package/dist/feishu/agent-host/runtime-deps.js +8 -0
- package/dist/feishu/card/budget.d.ts +40 -0
- package/dist/feishu/card/budget.js +134 -0
- package/dist/feishu/card/renderer.d.ts +29 -0
- package/dist/feishu/card/renderer.js +245 -0
- package/dist/feishu/card/run-state-types.d.ts +49 -0
- package/dist/feishu/card/run-state-types.js +15 -0
- package/dist/feishu/card/run-state.d.ts +21 -0
- package/dist/feishu/card/run-state.js +217 -0
- package/dist/feishu/channel/channel.d.ts +52 -0
- package/dist/feishu/channel/channel.js +74 -0
- package/dist/feishu/config.d.ts +24 -0
- package/dist/feishu/config.js +97 -0
- package/dist/feishu/format.d.ts +6 -0
- package/dist/feishu/format.js +14 -0
- package/dist/feishu/index.d.ts +4 -0
- package/dist/feishu/index.js +4 -0
- package/dist/feishu/logger.d.ts +31 -0
- package/dist/feishu/logger.js +62 -0
- package/dist/feishu/paths.d.ts +12 -0
- package/dist/feishu/paths.js +38 -0
- package/dist/feishu/process-registry.d.ts +29 -0
- package/dist/feishu/process-registry.js +90 -0
- package/dist/feishu/router/commands.d.ts +38 -0
- package/dist/feishu/router/commands.js +286 -0
- package/dist/feishu/router/event-router.d.ts +40 -0
- package/dist/feishu/router/event-router.js +208 -0
- package/dist/feishu/router/whitelist.d.ts +23 -0
- package/dist/feishu/router/whitelist.js +20 -0
- package/dist/feishu/runtime/active-runs.d.ts +32 -0
- package/dist/feishu/runtime/active-runs.js +84 -0
- package/dist/feishu/runtime/pending-queue.d.ts +36 -0
- package/dist/feishu/runtime/pending-queue.js +98 -0
- package/dist/feishu/runtime/process-pool.d.ts +29 -0
- package/dist/feishu/runtime/process-pool.js +49 -0
- package/dist/feishu/schema.d.ts +17 -0
- package/dist/feishu/schema.js +252 -0
- package/dist/feishu/scope/scope-registry.d.ts +39 -0
- package/dist/feishu/scope/scope-registry.js +148 -0
- package/dist/feishu/scope/session-binder.d.ts +44 -0
- package/dist/feishu/scope/session-binder.js +100 -0
- package/dist/feishu/scope/session-store.d.ts +24 -0
- package/dist/feishu/scope/session-store.js +73 -0
- package/dist/feishu/secrets.d.ts +37 -0
- package/dist/feishu/secrets.js +129 -0
- package/dist/feishu/serve.d.ts +12 -0
- package/dist/feishu/serve.js +288 -0
- package/dist/feishu/types.d.ts +75 -0
- package/dist/feishu/types.js +23 -0
- package/dist/feishu/wizard.d.ts +24 -0
- package/dist/feishu/wizard.js +121 -0
- package/dist/main.js +98 -32
- package/dist/model-catalog.js +3 -0
- package/dist/prompt/compose.js +3 -3
- package/dist/prompt/environment.js +2 -0
- package/dist/prompt/reminders.js +1 -1
- package/dist/provider-openai-codex.d.ts +8 -1
- package/dist/provider-openai-codex.js +33 -9
- package/dist/provider.d.ts +2 -0
- package/dist/session-title.d.ts +16 -0
- package/dist/session-title.js +134 -0
- package/dist/session-types.d.ts +5 -0
- package/dist/session.d.ts +16 -0
- package/dist/session.js +154 -2
- package/dist/skills/invocation.js +0 -18
- package/dist/skills/registry.d.ts +1 -0
- package/dist/skills/registry.js +2 -0
- package/dist/slash-commands/commands.js +15 -22
- package/dist/slash-commands/feishu.d.ts +17 -0
- package/dist/slash-commands/feishu.js +400 -0
- package/dist/slash-commands/registry.js +1 -1
- package/dist/slash-commands/types.d.ts +3 -1
- package/dist/text-display.d.ts +3 -0
- package/dist/text-display.js +25 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +3 -1
- package/dist/tools/skill-search.d.ts +10 -0
- package/dist/tools/skill-search.js +134 -0
- package/dist/tools/skill.js +1 -4
- package/dist/tui-ink/app.js +265 -118
- package/dist/tui-ink/code-highlight.js +2 -3
- package/dist/tui-ink/detect-theme.d.ts +1 -18
- package/dist/tui-ink/detect-theme.js +1 -37
- package/dist/tui-ink/display-history.d.ts +20 -3
- package/dist/tui-ink/display-history.js +26 -27
- package/dist/tui-ink/feedback-dialog.d.ts +19 -0
- package/dist/tui-ink/feedback-dialog.js +123 -0
- package/dist/tui-ink/feishu-setup-picker.d.ts +5 -0
- package/dist/tui-ink/feishu-setup-picker.js +261 -0
- package/dist/tui-ink/input-box.d.ts +25 -1
- package/dist/tui-ink/input-box.js +132 -11
- package/dist/tui-ink/input-history.js +3 -5
- package/dist/tui-ink/markdown.d.ts +32 -0
- package/dist/tui-ink/markdown.js +111 -4
- package/dist/tui-ink/message-list.d.ts +1 -6
- package/dist/tui-ink/message-list.js +86 -34
- package/dist/tui-ink/model-picker.d.ts +18 -0
- package/dist/tui-ink/model-picker.js +81 -27
- package/dist/tui-ink/run-session-picker.d.ts +10 -0
- package/dist/tui-ink/run-session-picker.js +22 -0
- package/dist/tui-ink/run.js +7 -2
- package/dist/tui-ink/session-picker.d.ts +10 -0
- package/dist/tui-ink/session-picker.js +110 -0
- package/dist/tui-ink/terminal-mouse.d.ts +4 -0
- package/dist/tui-ink/terminal-mouse.js +23 -0
- package/dist/tui-ink/theme.js +2 -2
- package/dist/tui-ink/trace-groups.js +25 -2
- package/dist/tui-ink/welcome.js +2 -4
- package/package.json +4 -5
- package/dist/tui/clipboard.d.ts +0 -1
- package/dist/tui/clipboard.js +0 -53
- package/dist/tui/display-history.d.ts +0 -44
- package/dist/tui/display-history.js +0 -243
- package/dist/tui/escape-confirmation.d.ts +0 -15
- package/dist/tui/escape-confirmation.js +0 -30
- package/dist/tui/file-mentions.d.ts +0 -29
- package/dist/tui/file-mentions.js +0 -174
- package/dist/tui/global-key-router.d.ts +0 -3
- package/dist/tui/global-key-router.js +0 -87
- package/dist/tui/image-paste.d.ts +0 -95
- package/dist/tui/image-paste.js +0 -505
- 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 -21
- 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/recent-activity.d.ts +0 -8
- package/dist/tui/recent-activity.js +0 -71
- package/dist/tui/render-signature.d.ts +0 -1
- package/dist/tui/render-signature.js +0 -7
- package/dist/tui/run.d.ts +0 -38
- package/dist/tui/run.js +0 -6996
- 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 -114
- package/dist/tui/tool-renderers/types.d.ts +0 -36
- package/dist/tui/tool-renderers/write-preview.d.ts +0 -12
- package/dist/tui/tool-renderers/write-preview.js +0 -30
- package/dist/tui/tool-renderers/write.d.ts +0 -6
- package/dist/tui/tool-renderers/write.js +0 -88
- /package/dist/{tui/tool-renderers → feedback}/types.js +0 -0
package/dist/session.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session Manager - Append-only JSONL persistence over a structured session log.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { mkdirSync, appendFileSync, existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { basename, dirname, join } from "node:path";
|
|
6
7
|
import { getBubbleHome } from "./bubble-home.js";
|
|
7
8
|
import { compactSessionEntries } from "./context/compact.js";
|
|
8
9
|
import { SessionLog } from "./session-log.js";
|
|
10
|
+
import { normalizeSingleLine, truncateVisual } from "./text-display.js";
|
|
11
|
+
import { deterministicTitleFromUserContent } from "./session-title.js";
|
|
9
12
|
const AUTO_COMPACT_ENTRY_THRESHOLD = 180;
|
|
10
13
|
const AUTO_COMPACT_KEEP_RECENT_TURNS = 3;
|
|
11
14
|
export class SessionManager {
|
|
@@ -42,6 +45,44 @@ export class SessionManager {
|
|
|
42
45
|
return [];
|
|
43
46
|
return readdirSync(sessionsDir).filter((file) => file.endsWith(".jsonl"));
|
|
44
47
|
}
|
|
48
|
+
static summarizeSessionsForCwd(cwd) {
|
|
49
|
+
const dir = getSessionsDir(cwd);
|
|
50
|
+
if (!existsSync(dir))
|
|
51
|
+
return [];
|
|
52
|
+
const summaries = [];
|
|
53
|
+
for (const file of readdirSync(dir)) {
|
|
54
|
+
if (!file.endsWith(".jsonl"))
|
|
55
|
+
continue;
|
|
56
|
+
const summary = summarizeSessionFile(join(dir, file), basename(dir));
|
|
57
|
+
if (summary)
|
|
58
|
+
summaries.push(summary);
|
|
59
|
+
}
|
|
60
|
+
return summaries.sort((a, b) => b.mtime - a.mtime);
|
|
61
|
+
}
|
|
62
|
+
static listAllSessions() {
|
|
63
|
+
const root = join(getBubbleHome(), "sessions");
|
|
64
|
+
if (!existsSync(root))
|
|
65
|
+
return [];
|
|
66
|
+
const summaries = [];
|
|
67
|
+
for (const cwdDir of readdirSync(root)) {
|
|
68
|
+
const dir = join(root, cwdDir);
|
|
69
|
+
try {
|
|
70
|
+
if (!statSync(dir).isDirectory())
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
for (const file of readdirSync(dir)) {
|
|
77
|
+
if (!file.endsWith(".jsonl"))
|
|
78
|
+
continue;
|
|
79
|
+
const summary = summarizeSessionFile(join(dir, file), cwdDir);
|
|
80
|
+
if (summary)
|
|
81
|
+
summaries.push(summary);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return summaries.sort((a, b) => b.mtime - a.mtime);
|
|
85
|
+
}
|
|
45
86
|
load() {
|
|
46
87
|
const content = readFileSync(this.sessionFile, "utf-8");
|
|
47
88
|
const lines = content.split("\n").filter((line) => line.trim() !== "");
|
|
@@ -69,10 +110,28 @@ export class SessionManager {
|
|
|
69
110
|
getMetadata() {
|
|
70
111
|
return this.log.getMetadata();
|
|
71
112
|
}
|
|
113
|
+
getOrCreatePromptCacheKey() {
|
|
114
|
+
const existing = this.log.getMetadata().promptCacheKey;
|
|
115
|
+
if (existing)
|
|
116
|
+
return existing;
|
|
117
|
+
const promptCacheKey = randomUUID();
|
|
118
|
+
this.updateMetadata({ promptCacheKey });
|
|
119
|
+
return promptCacheKey;
|
|
120
|
+
}
|
|
72
121
|
setMetadata(metadata) {
|
|
73
122
|
const nextEntries = this.log.setMetadata(metadata);
|
|
74
123
|
this.rewrite(nextEntries);
|
|
75
124
|
}
|
|
125
|
+
updateMetadata(patch) {
|
|
126
|
+
this.setMetadata({
|
|
127
|
+
...this.log.getMetadata(),
|
|
128
|
+
...dropUndefined(patch),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
clearTitleMetadata() {
|
|
132
|
+
const { title: _title, titleSource: _titleSource, titleUpdatedAt: _titleUpdatedAt, titleUserMessageId: _titleUserMessageId, ...metadata } = this.log.getMetadata();
|
|
133
|
+
this.setMetadata(metadata);
|
|
134
|
+
}
|
|
76
135
|
appendMessage(message) {
|
|
77
136
|
const entries = this.log.appendMessage(message);
|
|
78
137
|
this.persist(entries);
|
|
@@ -133,3 +192,96 @@ export function getSessionsDir(cwd) {
|
|
|
133
192
|
function resolveSessionFile(cwd, sessionName) {
|
|
134
193
|
return join(getSessionsDir(cwd), sessionName);
|
|
135
194
|
}
|
|
195
|
+
function summarizeSessionFile(file, cwdDir) {
|
|
196
|
+
let stat;
|
|
197
|
+
try {
|
|
198
|
+
stat = statSync(file);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
let content;
|
|
204
|
+
try {
|
|
205
|
+
content = readFileSync(file, "utf-8");
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
const lines = content.split("\n").filter((line) => line.trim() !== "");
|
|
211
|
+
if (lines.length === 0)
|
|
212
|
+
return undefined;
|
|
213
|
+
const log = new SessionLog();
|
|
214
|
+
log.load(lines);
|
|
215
|
+
const metadata = log.getMetadata();
|
|
216
|
+
const entries = log.list();
|
|
217
|
+
const messages = log.toMessages();
|
|
218
|
+
const firstUserEntry = firstUserEntryAfterLatestClear(entries);
|
|
219
|
+
const firstUserText = firstUserEntry ? messageText(firstUserEntry.message) : "";
|
|
220
|
+
const preview = firstUserText
|
|
221
|
+
? sessionPreviewFromText(firstUserText)
|
|
222
|
+
: (messages.length > 0 ? "No user message" : "No messages");
|
|
223
|
+
const title = usableStoredTitle(metadata, entries)
|
|
224
|
+
?? (firstUserEntry ? deterministicTitleFromUserContent(firstUserEntry.message.content) : (messages.length > 0 ? "Assistant-only session" : "Empty session"));
|
|
225
|
+
return {
|
|
226
|
+
file,
|
|
227
|
+
name: basename(file).replace(/\.jsonl$/, ""),
|
|
228
|
+
cwd: metadata.cwd,
|
|
229
|
+
cwdLabel: metadata.cwd ?? decodeCwdDir(cwdDir),
|
|
230
|
+
title,
|
|
231
|
+
preview,
|
|
232
|
+
firstUserMessage: preview,
|
|
233
|
+
messageCount: messages.length,
|
|
234
|
+
mtime: stat.mtimeMs,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function decodeCwdDir(safe) {
|
|
238
|
+
// safeCwd is cwd.replace(/[/\\:]/g, "_") — not perfectly reversible because we
|
|
239
|
+
// can't tell underscores apart from path separators. For typical absolute
|
|
240
|
+
// Unix paths this still produces a readable approximation.
|
|
241
|
+
if (safe.startsWith("_"))
|
|
242
|
+
return "/" + safe.slice(1).replace(/_/g, "/");
|
|
243
|
+
return safe.replace(/_/g, "/");
|
|
244
|
+
}
|
|
245
|
+
function dropUndefined(value) {
|
|
246
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
247
|
+
}
|
|
248
|
+
function firstUserEntryAfterLatestClear(entries) {
|
|
249
|
+
const startIndex = latestClearIndex(entries) + 1;
|
|
250
|
+
for (let i = startIndex; i < entries.length; i++) {
|
|
251
|
+
const entry = entries[i];
|
|
252
|
+
if (entry.type === "user_message")
|
|
253
|
+
return entry;
|
|
254
|
+
}
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
function latestClearIndex(entries) {
|
|
258
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
259
|
+
const entry = entries[i];
|
|
260
|
+
if (entry.type === "marker" && entry.kind === "conversation_clear")
|
|
261
|
+
return i;
|
|
262
|
+
}
|
|
263
|
+
return -1;
|
|
264
|
+
}
|
|
265
|
+
function usableStoredTitle(metadata, entries) {
|
|
266
|
+
const title = normalizeSingleLine(metadata.title ?? "");
|
|
267
|
+
if (!title)
|
|
268
|
+
return undefined;
|
|
269
|
+
if (!metadata.titleUserMessageId)
|
|
270
|
+
return title;
|
|
271
|
+
const anchorIndex = entries.findIndex((entry) => entry.id === metadata.titleUserMessageId);
|
|
272
|
+
if (anchorIndex < 0)
|
|
273
|
+
return undefined;
|
|
274
|
+
if (anchorIndex <= latestClearIndex(entries))
|
|
275
|
+
return undefined;
|
|
276
|
+
return title;
|
|
277
|
+
}
|
|
278
|
+
function messageText(message) {
|
|
279
|
+
if (message.role !== "user")
|
|
280
|
+
return "";
|
|
281
|
+
if (typeof message.content === "string")
|
|
282
|
+
return message.content;
|
|
283
|
+
return message.content.map((part) => part.type === "text" ? part.text : "").join("\n");
|
|
284
|
+
}
|
|
285
|
+
function sessionPreviewFromText(text) {
|
|
286
|
+
return truncateVisual(normalizeSingleLine(text), 100) || "No user message";
|
|
287
|
+
}
|
|
@@ -5,24 +5,6 @@ export function parseSkillInvocation(input, registry) {
|
|
|
5
5
|
const withoutSlash = trimmed.slice(1).trim();
|
|
6
6
|
if (!withoutSlash)
|
|
7
7
|
return undefined;
|
|
8
|
-
if (withoutSlash.startsWith("skill ")) {
|
|
9
|
-
const rest = withoutSlash.slice("skill ".length).trim();
|
|
10
|
-
const firstSpace = rest.indexOf(" ");
|
|
11
|
-
if (firstSpace === -1)
|
|
12
|
-
return undefined;
|
|
13
|
-
const skillName = rest.slice(0, firstSpace).trim();
|
|
14
|
-
const task = rest.slice(firstSpace + 1).trim();
|
|
15
|
-
if (!skillName || !task)
|
|
16
|
-
return undefined;
|
|
17
|
-
const skill = registry.get(skillName);
|
|
18
|
-
if (!skill)
|
|
19
|
-
return undefined;
|
|
20
|
-
return {
|
|
21
|
-
skill,
|
|
22
|
-
task,
|
|
23
|
-
actualPrompt: buildSkillExecutionPrompt(skill, task),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
8
|
const firstSpace = withoutSlash.indexOf(" ");
|
|
27
9
|
if (firstSpace === -1)
|
|
28
10
|
return undefined;
|
package/dist/skills/registry.js
CHANGED
|
@@ -9,9 +9,11 @@ export class SkillRegistry {
|
|
|
9
9
|
const cwd = options.cwd ?? process.cwd();
|
|
10
10
|
const bubbleHome = options.bubbleHome ?? getBubbleHome();
|
|
11
11
|
const agentsHome = options.agentsHome ?? join(homedir(), ".agents");
|
|
12
|
+
const claudeHome = options.claudeHome ?? join(homedir(), ".claude");
|
|
12
13
|
const roots = [
|
|
13
14
|
{ path: join(bubbleHome, "skills"), source: "user" },
|
|
14
15
|
{ path: join(agentsHome, "skills"), source: "user" },
|
|
16
|
+
{ path: join(claudeHome, "skills"), source: "user" },
|
|
15
17
|
{ path: join(cwd, ".bubble", "skills"), source: "project" },
|
|
16
18
|
...(options.skillPaths ?? []).map((path) => ({ path, source: "configured" })),
|
|
17
19
|
];
|
|
@@ -6,9 +6,9 @@ import { parseRule } from "../permissions/rule.js";
|
|
|
6
6
|
import { encodeModel, decodeModel, displayModel, BUILTIN_PROVIDERS, isUserVisibleProvider } from "../provider-registry.js";
|
|
7
7
|
import { getAvailableThinkingLevels, normalizeThinkingLevel } from "../provider-transform.js";
|
|
8
8
|
import { buildSystemPrompt } from "../system-prompt.js";
|
|
9
|
-
import { formatLoadedSkill } from "../tools/skill.js";
|
|
10
9
|
import { isThinkingLevel } from "../variant/thinking-level.js";
|
|
11
10
|
import { buildMemoryPrompt, getMemoryStatus, isMemoryDisabled, resetMemory, searchMemory, } from "../memory/index.js";
|
|
11
|
+
import { feishuCommand } from "./feishu.js";
|
|
12
12
|
const VALID_SCOPES = ["user", "project", "local"];
|
|
13
13
|
const VALID_LISTS = ["allow", "deny"];
|
|
14
14
|
function isScope(value) {
|
|
@@ -54,7 +54,7 @@ function persistSelectedModel(model, ctx) {
|
|
|
54
54
|
userConfig.setDefaultThinkingLevel(ctx.agent.thinking);
|
|
55
55
|
userConfig.pushRecentModel(model);
|
|
56
56
|
if (ctx.sessionManager) {
|
|
57
|
-
ctx.sessionManager.
|
|
57
|
+
ctx.sessionManager.updateMetadata({ model, thinkingLevel: ctx.agent.thinking, reasoningEffort: ctx.agent.thinking });
|
|
58
58
|
ctx.sessionManager.appendMarker("model_switch", model);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -67,7 +67,6 @@ function syncSystemPrompt(ctx, model) {
|
|
|
67
67
|
configuredModelId: model,
|
|
68
68
|
thinkingLevel: ctx.agent.thinking,
|
|
69
69
|
workingDir: ctx.cwd,
|
|
70
|
-
skills: ctx.skillRegistry.summaries(),
|
|
71
70
|
memoryPrompt: buildMemoryPrompt(ctx.cwd),
|
|
72
71
|
}));
|
|
73
72
|
}
|
|
@@ -256,25 +255,6 @@ const builtinSlashCommandEntries = [
|
|
|
256
255
|
ctx.openPicker("skill");
|
|
257
256
|
},
|
|
258
257
|
},
|
|
259
|
-
{
|
|
260
|
-
name: "skill",
|
|
261
|
-
description: "Load a skill explicitly. Usage: /skill <name>",
|
|
262
|
-
async handler(args, ctx) {
|
|
263
|
-
const name = args.trim();
|
|
264
|
-
if (!name) {
|
|
265
|
-
return "Usage: /skill <name>";
|
|
266
|
-
}
|
|
267
|
-
const skill = ctx.skillRegistry.get(name);
|
|
268
|
-
if (!skill) {
|
|
269
|
-
const available = ctx.skillRegistry.summaries().map((item) => item.name).join(", ");
|
|
270
|
-
return available
|
|
271
|
-
? `Unknown skill "${name}". Available skills: ${available}`
|
|
272
|
-
: `Unknown skill "${name}". No skills are currently available.`;
|
|
273
|
-
}
|
|
274
|
-
ctx.sessionManager?.appendMarker("skill_activated", skill.meta.name);
|
|
275
|
-
return formatLoadedSkill(skill);
|
|
276
|
-
},
|
|
277
|
-
},
|
|
278
258
|
{
|
|
279
259
|
name: "help",
|
|
280
260
|
description: "Show available slash commands",
|
|
@@ -338,6 +318,7 @@ const builtinSlashCommandEntries = [
|
|
|
338
318
|
async handler(args, ctx) {
|
|
339
319
|
ctx.agent.messages = ctx.agent.messages.filter((m) => m.role === "system" || m.role === "meta");
|
|
340
320
|
ctx.sessionManager?.appendMarker("conversation_clear", "");
|
|
321
|
+
ctx.sessionManager?.clearTitleMetadata?.();
|
|
341
322
|
if (ctx.agent.getTodos().length > 0) {
|
|
342
323
|
ctx.agent.setTodos([]);
|
|
343
324
|
}
|
|
@@ -782,10 +763,22 @@ const builtinSlashCommandEntries = [
|
|
|
782
763
|
...(systemMessage ? [systemMessage] : []),
|
|
783
764
|
...ctx.sessionManager.getMessages(),
|
|
784
765
|
];
|
|
766
|
+
ctx.agent.resetContextUsageAnchor();
|
|
785
767
|
const dropped = result.droppedEntries ?? 0;
|
|
786
768
|
return `✓ Compaction complete · ${dropped} log entr${dropped === 1 ? "y" : "ies"} summarized`;
|
|
787
769
|
},
|
|
788
770
|
},
|
|
771
|
+
{
|
|
772
|
+
name: "feedback",
|
|
773
|
+
description: "Send feedback or report a bug to Bubble developers",
|
|
774
|
+
async handler(args, ctx) {
|
|
775
|
+
if (!ctx.openFeedback) {
|
|
776
|
+
return "Feedback is only available in interactive TUI mode.";
|
|
777
|
+
}
|
|
778
|
+
ctx.openFeedback(args ?? "");
|
|
779
|
+
},
|
|
780
|
+
},
|
|
781
|
+
feishuCommand,
|
|
789
782
|
];
|
|
790
783
|
/**
|
|
791
784
|
* Public export — built-in commands tagged with `source: "builtin"` so the
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/feishu` slash command — control the Feishu remote-access serve process
|
|
3
|
+
* from inside the Bubble TUI without leaving it.
|
|
4
|
+
*
|
|
5
|
+
* Subcommands:
|
|
6
|
+
* /feishu equivalent to `/feishu status`
|
|
7
|
+
* /feishu status show running state and configured scopes
|
|
8
|
+
* /feishu start spawn `bubble serve --feishu` detached
|
|
9
|
+
* /feishu stop SIGTERM the running serve instance
|
|
10
|
+
* /feishu logs [N] tail last N lines of today's log (default 30)
|
|
11
|
+
*
|
|
12
|
+
* The serve subprocess runs independently of the TUI — closing the TUI
|
|
13
|
+
* does not stop it. Use `/feishu stop` (or kill the PID directly) to
|
|
14
|
+
* terminate.
|
|
15
|
+
*/
|
|
16
|
+
import type { SlashCommand } from "./types.js";
|
|
17
|
+
export declare const feishuCommand: SlashCommand;
|