@bubblebrain-ai/bubble 0.0.35 → 0.0.37
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 +27 -7
- package/dist/agent/categories.d.ts +66 -2
- package/dist/agent/categories.js +120 -19
- package/dist/agent/discovery-barrier.js +1 -1
- package/dist/agent/profiles.d.ts +1 -0
- package/dist/agent/profiles.js +25 -11
- package/dist/agent/routing-catalog.d.ts +113 -0
- package/dist/agent/routing-catalog.js +240 -0
- package/dist/agent/workflow/control.d.ts +14 -0
- package/dist/agent/workflow/control.js +30 -9
- package/dist/agent.d.ts +75 -5
- package/dist/agent.js +313 -61
- package/dist/approval/controller.js +28 -0
- package/dist/approval/tool-helper.js +2 -0
- package/dist/approval/types.d.ts +21 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +2 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +4 -0
- package/dist/context/compact-llm.d.ts +2 -2
- package/dist/external-runtime/grok-acp.d.ts +56 -0
- package/dist/external-runtime/grok-acp.js +386 -0
- package/dist/external-runtime/grok-binary.d.ts +25 -0
- package/dist/external-runtime/grok-binary.js +108 -0
- package/dist/external-runtime/grok-errors.d.ts +7 -0
- package/dist/external-runtime/grok-errors.js +15 -0
- package/dist/external-runtime/grok-input-policy.d.ts +58 -0
- package/dist/external-runtime/grok-input-policy.js +52 -0
- package/dist/external-runtime/grok-ndjson.d.ts +14 -0
- package/dist/external-runtime/grok-ndjson.js +193 -0
- package/dist/external-runtime/grok-network.d.ts +15 -0
- package/dist/external-runtime/grok-network.js +81 -0
- package/dist/external-runtime/grok-preflight.d.ts +28 -0
- package/dist/external-runtime/grok-preflight.js +194 -0
- package/dist/external-runtime/grok-process.d.ts +26 -0
- package/dist/external-runtime/grok-process.js +184 -0
- package/dist/external-runtime/grok-profile.d.ts +32 -0
- package/dist/external-runtime/grok-profile.js +419 -0
- package/dist/external-runtime/grok-provider.d.ts +31 -0
- package/dist/external-runtime/grok-provider.js +41 -0
- package/dist/external-runtime/grok-runtime.d.ts +91 -0
- package/dist/external-runtime/grok-runtime.js +882 -0
- package/dist/external-runtime/index.d.ts +13 -0
- package/dist/external-runtime/index.js +13 -0
- package/dist/external-runtime/session-policy.d.ts +11 -0
- package/dist/external-runtime/session-policy.js +30 -0
- package/dist/external-runtime/types.d.ts +65 -0
- package/dist/external-runtime/types.js +1 -0
- package/dist/feishu/agent-host/approval-card.js +21 -0
- package/dist/feishu/agent-host/run-driver.js +19 -3
- package/dist/feishu/serve.js +1 -0
- package/dist/goal/tools.d.ts +6 -3
- package/dist/goal/tools.js +7 -19
- package/dist/main.js +105 -27
- package/dist/memory/db.d.ts +2 -0
- package/dist/memory/db.js +10 -0
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.js +1 -0
- package/dist/memory/phase1.js +14 -2
- package/dist/memory/phase2.js +21 -2
- package/dist/memory/prompts.js +1 -1
- package/dist/memory/session-policy.d.ts +25 -0
- package/dist/memory/session-policy.js +55 -0
- package/dist/memory/storage.d.ts +1 -0
- package/dist/memory/storage.js +13 -0
- package/dist/model-catalog.d.ts +18 -0
- package/dist/model-catalog.js +87 -41
- package/dist/model-config.d.ts +3 -1
- package/dist/model-config.js +11 -0
- package/dist/oauth/grok.d.ts +25 -0
- package/dist/oauth/grok.js +218 -0
- package/dist/oauth/index.d.ts +1 -0
- package/dist/oauth/index.js +1 -0
- package/dist/oauth/storage.d.ts +9 -0
- package/dist/oauth/storage.js +25 -0
- package/dist/orchestrator/default-hooks.js +17 -7
- package/dist/prompt/compose.d.ts +3 -0
- package/dist/prompt/compose.js +3 -0
- package/dist/prompt/delegation.js +22 -3
- package/dist/prompt/environment.js +0 -4
- package/dist/prompt/reminders.d.ts +0 -1
- package/dist/prompt/reminders.js +1 -11
- package/dist/prompt/routing.d.ts +14 -0
- package/dist/prompt/routing.js +71 -0
- package/dist/prompt/runtime.js +1 -1
- package/dist/prompt/task-reminders.d.ts +19 -0
- package/dist/prompt/task-reminders.js +49 -0
- package/dist/provider-ai-sdk.js +2 -2
- package/dist/provider-grok.d.ts +26 -0
- package/dist/provider-grok.js +59 -0
- package/dist/provider-openai-codex.d.ts +17 -1
- package/dist/provider-openai-codex.js +101 -29
- package/dist/provider-registry.d.ts +72 -0
- package/dist/provider-registry.js +336 -59
- package/dist/provider-transform.d.ts +1 -1
- package/dist/provider-transform.js +28 -5
- package/dist/provider.d.ts +3 -0
- package/dist/provider.js +14 -0
- package/dist/session-types.d.ts +19 -1
- package/dist/session.d.ts +1 -0
- package/dist/session.js +4 -0
- package/dist/slash-commands/commands.js +224 -14
- package/dist/slash-commands/types.d.ts +14 -1
- package/dist/system-prompt.d.ts +2 -0
- package/dist/tools/agent-lifecycle.js +9 -11
- package/dist/tools/bash.js +1 -1
- package/dist/tools/child-tools.js +2 -0
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js +7 -5
- package/dist/tools/lsp.js +1 -0
- package/dist/tools/memory.d.ts +7 -2
- package/dist/tools/memory.js +28 -43
- package/dist/tools/server.js +4 -0
- package/dist/tools/tool-search.d.ts +1 -1
- package/dist/tools/tool-search.js +23 -3
- package/dist/tui/model-switch.d.ts +7 -0
- package/dist/tui/model-switch.js +15 -5
- package/dist/tui-ink/app.d.ts +3 -1
- package/dist/tui-ink/app.js +649 -233
- package/dist/tui-ink/approval/approval-dialog.js +36 -0
- package/dist/tui-ink/composer-buffer.d.ts +55 -0
- package/dist/tui-ink/composer-buffer.js +317 -0
- package/dist/tui-ink/footer.d.ts +1 -0
- package/dist/tui-ink/footer.js +7 -2
- package/dist/tui-ink/input-box.d.ts +35 -1
- package/dist/tui-ink/input-box.js +215 -122
- package/dist/tui-ink/message-list.js +5 -5
- package/dist/tui-ink/model-picker.d.ts +61 -4
- package/dist/tui-ink/model-picker.js +486 -133
- package/dist/tui-ink/paste-operation-tracker.d.ts +13 -0
- package/dist/tui-ink/paste-operation-tracker.js +25 -0
- package/dist/tui-ink/run.d.ts +3 -0
- package/dist/tui-ink/run.js +1 -1
- package/dist/tui-ink/subagent-view.d.ts +31 -0
- package/dist/tui-ink/subagent-view.js +82 -1
- package/dist/types.d.ts +5 -5
- package/dist/types.js +1 -1
- package/dist/variant/thinking-level.d.ts +2 -2
- package/dist/variant/thinking-level.js +2 -1
- package/dist/variant/variant-resolver.d.ts +9 -0
- package/dist/variant/variant-resolver.js +17 -0
- package/package.json +2 -1
- package/dist/tools/task.d.ts +0 -2
- package/dist/tools/task.js +0 -58
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./grok-errors.js";
|
|
3
|
+
export * from "./grok-network.js";
|
|
4
|
+
export * from "./grok-provider.js";
|
|
5
|
+
export * from "./grok-input-policy.js";
|
|
6
|
+
export * from "./session-policy.js";
|
|
7
|
+
export * from "./grok-binary.js";
|
|
8
|
+
export * from "./grok-profile.js";
|
|
9
|
+
export * from "./grok-preflight.js";
|
|
10
|
+
export * from "./grok-process.js";
|
|
11
|
+
export * from "./grok-ndjson.js";
|
|
12
|
+
export * from "./grok-acp.js";
|
|
13
|
+
export * from "./grok-runtime.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./grok-errors.js";
|
|
3
|
+
export * from "./grok-network.js";
|
|
4
|
+
export * from "./grok-provider.js";
|
|
5
|
+
export * from "./grok-input-policy.js";
|
|
6
|
+
export * from "./session-policy.js";
|
|
7
|
+
export * from "./grok-binary.js";
|
|
8
|
+
export * from "./grok-profile.js";
|
|
9
|
+
export * from "./grok-preflight.js";
|
|
10
|
+
export * from "./grok-process.js";
|
|
11
|
+
export * from "./grok-ndjson.js";
|
|
12
|
+
export * from "./grok-acp.js";
|
|
13
|
+
export * from "./grok-runtime.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ExternalRuntimeManager } from "./types.js";
|
|
2
|
+
export type ExternalRuntimeBindingKind = "none" | "grok" | "unsupported";
|
|
3
|
+
/**
|
|
4
|
+
* Treat every persisted external-runtime marker as non-native. Known aliases
|
|
5
|
+
* normalize to Grok; malformed or future IDs stay fail-closed instead of
|
|
6
|
+
* falling through to Bubble's native agent/tool path.
|
|
7
|
+
*/
|
|
8
|
+
export declare function classifyExternalRuntimeBinding(binding: unknown): ExternalRuntimeBindingKind;
|
|
9
|
+
export declare function stopExternalRuntimeForSessionSwitch(runtime: ExternalRuntimeManager | undefined, sessionId?: string): Promise<void>;
|
|
10
|
+
/** Never replay a Grok-owned transcript through Bubble's native print path. */
|
|
11
|
+
export declare function shouldRejectGrokSessionInPrintMode(externalRuntimeBinding: unknown, printMode: boolean): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isGrokSubscriptionProviderId } from "./grok-provider.js";
|
|
2
|
+
/**
|
|
3
|
+
* Treat every persisted external-runtime marker as non-native. Known aliases
|
|
4
|
+
* normalize to Grok; malformed or future IDs stay fail-closed instead of
|
|
5
|
+
* falling through to Bubble's native agent/tool path.
|
|
6
|
+
*/
|
|
7
|
+
export function classifyExternalRuntimeBinding(binding) {
|
|
8
|
+
if (binding === undefined)
|
|
9
|
+
return "none";
|
|
10
|
+
const id = typeof binding === "string"
|
|
11
|
+
? binding
|
|
12
|
+
: binding !== null && typeof binding === "object" && "id" in binding
|
|
13
|
+
? binding.id
|
|
14
|
+
: undefined;
|
|
15
|
+
return typeof id === "string" && isGrokSubscriptionProviderId(id)
|
|
16
|
+
? "grok"
|
|
17
|
+
: "unsupported";
|
|
18
|
+
}
|
|
19
|
+
export async function stopExternalRuntimeForSessionSwitch(runtime, sessionId) {
|
|
20
|
+
if (!runtime) {
|
|
21
|
+
throw new Error("The external runtime manager is unavailable; the current session was not changed.");
|
|
22
|
+
}
|
|
23
|
+
if (sessionId)
|
|
24
|
+
await runtime.cancel(sessionId);
|
|
25
|
+
await runtime.dispose();
|
|
26
|
+
}
|
|
27
|
+
/** Never replay a Grok-owned transcript through Bubble's native print path. */
|
|
28
|
+
export function shouldRejectGrokSessionInPrintMode(externalRuntimeBinding, printMode) {
|
|
29
|
+
return printMode && classifyExternalRuntimeBinding(externalRuntimeBinding) !== "none";
|
|
30
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AgentEvent } from "../types.js";
|
|
2
|
+
import type { ThinkingLevel } from "../types.js";
|
|
3
|
+
export type ExternalRuntimeState = "unavailable" | "signed_out" | "ready" | "running" | "failed" | "disposed";
|
|
4
|
+
export interface ExternalRuntimeCapabilities {
|
|
5
|
+
chat: boolean;
|
|
6
|
+
tools: boolean;
|
|
7
|
+
memory: boolean;
|
|
8
|
+
subagents: boolean;
|
|
9
|
+
plan: boolean;
|
|
10
|
+
web: boolean;
|
|
11
|
+
sessionLoad: boolean;
|
|
12
|
+
workspace: boolean;
|
|
13
|
+
modelControl: boolean;
|
|
14
|
+
reasoningControl: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface ExternalRuntimeBinaryInfo {
|
|
17
|
+
path: string;
|
|
18
|
+
version: string;
|
|
19
|
+
sha256: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ExternalRuntimeStatus {
|
|
22
|
+
provider: "grok";
|
|
23
|
+
state: ExternalRuntimeState;
|
|
24
|
+
capabilities: ExternalRuntimeCapabilities;
|
|
25
|
+
binary?: ExternalRuntimeBinaryInfo;
|
|
26
|
+
sessionId?: string;
|
|
27
|
+
/** A deliberately terse, credential-free diagnostic suitable for the TUI. */
|
|
28
|
+
message?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ExternalRuntimeSession {
|
|
31
|
+
id: string;
|
|
32
|
+
provider: "grok";
|
|
33
|
+
modelId?: string;
|
|
34
|
+
reasoningEffort?: ThinkingLevel;
|
|
35
|
+
}
|
|
36
|
+
export interface ExternalRuntimeModel {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
reasoningLevels: ThinkingLevel[];
|
|
40
|
+
defaultReasoningLevel: ThinkingLevel;
|
|
41
|
+
}
|
|
42
|
+
export interface ExternalRuntimeModelSelection {
|
|
43
|
+
modelId?: string;
|
|
44
|
+
reasoningEffort: ThinkingLevel;
|
|
45
|
+
}
|
|
46
|
+
export interface ExternalRuntimeRunOptions {
|
|
47
|
+
sessionId?: string;
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
/** Lets callers invalidate late ACP notifications after a UI generation swap. */
|
|
50
|
+
generation?: number;
|
|
51
|
+
}
|
|
52
|
+
export interface ExternalRuntimeManager {
|
|
53
|
+
inspect(): Promise<ExternalRuntimeStatus>;
|
|
54
|
+
login(signal?: AbortSignal, onBrowserOpened?: () => void): Promise<void>;
|
|
55
|
+
logout(): Promise<void>;
|
|
56
|
+
newSession(): Promise<ExternalRuntimeSession>;
|
|
57
|
+
loadSession(id: string): Promise<ExternalRuntimeSession>;
|
|
58
|
+
hydrateSession(id: string, modelId?: string, reasoningEffort?: ThinkingLevel): Promise<ExternalRuntimeSession>;
|
|
59
|
+
listModels(): Promise<ExternalRuntimeModel[]>;
|
|
60
|
+
getModelSelection(): ExternalRuntimeModelSelection;
|
|
61
|
+
setModel(modelId: string, reasoningEffort?: ThinkingLevel): Promise<ExternalRuntimeModelSelection>;
|
|
62
|
+
run(prompt: string, options?: ExternalRuntimeRunOptions): AsyncIterable<AgentEvent>;
|
|
63
|
+
cancel(sessionId?: string): Promise<void>;
|
|
64
|
+
dispose(): Promise<void>;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -55,6 +55,27 @@ export function formatApprovalRequest(req) {
|
|
|
55
55
|
"\n该 profile 来自仓库本地 `.bubble/agents`,其 prompt 会驱动一个子代理。仅在信任该仓库时批准。",
|
|
56
56
|
].join("\n"),
|
|
57
57
|
};
|
|
58
|
+
case "external_tool":
|
|
59
|
+
return {
|
|
60
|
+
title: `外部工具:${req.title}`,
|
|
61
|
+
body: [
|
|
62
|
+
`**kind:** \`${truncate(req.kind, 80)}\``,
|
|
63
|
+
req.locations?.length
|
|
64
|
+
? `**paths:** ${req.locations.map((location) => `\`${truncate(location.path, PATH_PREVIEW_MAX)}\``).join(", ")}`
|
|
65
|
+
: "",
|
|
66
|
+
req.rawInput === undefined
|
|
67
|
+
? ""
|
|
68
|
+
: `\n**input:**\n\`\`\`json\n${truncate(safeJson(req.rawInput), CONTENT_PREVIEW_MAX)}\n\`\`\``,
|
|
69
|
+
].filter(Boolean).join("\n"),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function safeJson(value) {
|
|
74
|
+
try {
|
|
75
|
+
return JSON.stringify(value, null, 2);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return "[unserializable input]";
|
|
58
79
|
}
|
|
59
80
|
}
|
|
60
81
|
function truncate(s, max) {
|
|
@@ -19,11 +19,13 @@ import { BashAllowlist } from "../../approval/session-cache.js";
|
|
|
19
19
|
import { getLspService } from "../../lsp/index.js";
|
|
20
20
|
import { ExternalHookController } from "../../hooks/index.js";
|
|
21
21
|
import { buildSystemPrompt } from "../../system-prompt.js";
|
|
22
|
+
import { createRoutableModelIndex, createRoutingSnapshotAccessor } from "../../agent/routing-catalog.js";
|
|
23
|
+
import { buildModelRoutingPrompt } from "../../prompt/routing.js";
|
|
22
24
|
import { FileStateTracker } from "../../tools/file-state.js";
|
|
23
25
|
import { buildToolPromptOptions, createAllTools } from "../../tools/index.js";
|
|
24
26
|
import { displayModel, encodeModel, decodeModel } from "../../provider-registry.js";
|
|
25
27
|
import { buildMemoryPrompt, recordMemoryCitations } from "../../memory/index.js";
|
|
26
|
-
import { getDefaultThinkingLevel } from "../../provider-transform.js";
|
|
28
|
+
import { getAvailableThinkingLevels, getDefaultThinkingLevel, normalizeThinkingLevel } from "../../provider-transform.js";
|
|
27
29
|
import { createSessionTitleUpdater } from "../../session-title.js";
|
|
28
30
|
import { applyCardBudget } from "../card/budget.js";
|
|
29
31
|
import { renderCard } from "../card/renderer.js";
|
|
@@ -87,9 +89,16 @@ export class RunDriver {
|
|
|
87
89
|
const { provider, providerId, model } = await this.resolveProvider(session, promptCacheKey);
|
|
88
90
|
const skills = this.opts.deps.skillRegistry.summaries();
|
|
89
91
|
const memoryPrompt = buildMemoryPrompt(session.cwd);
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
+
const modelId = decodeModel(model).modelId;
|
|
93
|
+
const configuredThinkingLevel = this.opts.deps.userConfig.getDefaultThinkingLevel();
|
|
94
|
+
const thinkingLevel = configuredThinkingLevel !== undefined
|
|
95
|
+
? normalizeThinkingLevel(configuredThinkingLevel, getAvailableThinkingLevels(providerId, modelId))
|
|
96
|
+
: getDefaultThinkingLevel(providerId, modelId);
|
|
92
97
|
const initialMode = session.permissionMode;
|
|
98
|
+
// Routing accessor built before the prompt (design §1.5): the prompt is
|
|
99
|
+
// composed before the Agent exists, same ordering constraint as main.ts.
|
|
100
|
+
const agentRouting = this.opts.deps.userConfig.getAgentRouting();
|
|
101
|
+
const routingSnapshotAccessor = createRoutingSnapshotAccessor(this.opts.deps.providerRegistry, () => this.opts.deps.userConfig.getAgentCategories(), () => agentRouting);
|
|
93
102
|
const systemPrompt = buildSystemPrompt({
|
|
94
103
|
agentName: "Bubble",
|
|
95
104
|
configuredProvider: providerId || "none",
|
|
@@ -100,6 +109,9 @@ export class RunDriver {
|
|
|
100
109
|
workingDir: session.cwd,
|
|
101
110
|
...buildToolPromptOptions(tools.filter((tool) => !tool.deferred)),
|
|
102
111
|
memoryPrompt,
|
|
112
|
+
modelRoutingPrompt: providerId && modelId
|
|
113
|
+
? buildModelRoutingPrompt(routingSnapshotAccessor({ providerId, model: modelId }), agentRouting)
|
|
114
|
+
: undefined,
|
|
103
115
|
});
|
|
104
116
|
const budgetLedger = new BudgetLedger();
|
|
105
117
|
let sessionTitleUpdater;
|
|
@@ -140,6 +152,9 @@ export class RunDriver {
|
|
|
140
152
|
memoryPrompt,
|
|
141
153
|
fileStateTracker,
|
|
142
154
|
agentCategories: this.opts.deps.userConfig.getAgentCategories(),
|
|
155
|
+
agentRouting,
|
|
156
|
+
routingSnapshot: routingSnapshotAccessor,
|
|
157
|
+
routableModels: createRoutableModelIndex(this.opts.deps.providerRegistry),
|
|
143
158
|
subagents: this.opts.deps.userConfig.getSubagents(),
|
|
144
159
|
providerFactory: (route) => this.opts.deps.createProviderForRoute(route, promptCacheKey),
|
|
145
160
|
externalHooks: hookController,
|
|
@@ -175,6 +190,7 @@ export class RunDriver {
|
|
|
175
190
|
agent.messages = [{ role: "system", content: systemPrompt }, ...history];
|
|
176
191
|
if (agent.mode === "plan")
|
|
177
192
|
agent.injectModeReminder();
|
|
193
|
+
agent.injectDeferredToolsReminder();
|
|
178
194
|
}
|
|
179
195
|
}
|
|
180
196
|
// 4. Build RunState + stream the card.
|
package/dist/feishu/serve.js
CHANGED
|
@@ -98,6 +98,7 @@ export async function serveFeishu(opts = {}) {
|
|
|
98
98
|
promptCacheKey,
|
|
99
99
|
protocol: providerRegistry.getConfigured().find((provider) => provider.id === providerId)?.protocol,
|
|
100
100
|
openAICodexAuth: providerRegistry.createOpenAICodexAuthAdapter(providerId),
|
|
101
|
+
grokAuth: providerRegistry.createGrokAuthAdapter(providerId),
|
|
101
102
|
});
|
|
102
103
|
const createProviderForRoute = async (route, promptCacheKey) => {
|
|
103
104
|
const target = providerRegistry.getConfigured().find((p) => p.id === route.providerId);
|
package/dist/goal/tools.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Model-facing goal
|
|
2
|
+
* Model-facing goal tool: update_goal.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* It writes the shared GoalStore so the model's completion/blocked signal
|
|
5
5
|
* stops the TUI's auto-continuation loop. The user sets goals via `/goal`, so
|
|
6
|
-
* there is intentionally no model-facing create_goal tool
|
|
6
|
+
* there is intentionally no model-facing create_goal tool — and no read tool:
|
|
7
|
+
* the goal engine already injects the objective plus budget state into every
|
|
8
|
+
* goal turn's prompt, so a get_goal call could only return what the model was
|
|
9
|
+
* just told.
|
|
7
10
|
*/
|
|
8
11
|
import type { ToolRegistryEntry } from "../types.js";
|
|
9
12
|
import type { GoalStore } from "./store.js";
|
package/dist/goal/tools.js
CHANGED
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Model-facing goal
|
|
2
|
+
* Model-facing goal tool: update_goal.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* It writes the shared GoalStore so the model's completion/blocked signal
|
|
5
5
|
* stops the TUI's auto-continuation loop. The user sets goals via `/goal`, so
|
|
6
|
-
* there is intentionally no model-facing create_goal tool
|
|
6
|
+
* there is intentionally no model-facing create_goal tool — and no read tool:
|
|
7
|
+
* the goal engine already injects the objective plus budget state into every
|
|
8
|
+
* goal turn's prompt, so a get_goal call could only return what the model was
|
|
9
|
+
* just told.
|
|
7
10
|
*/
|
|
8
|
-
import { goalSummaryText } from "./format.js";
|
|
9
11
|
const UPDATE_GOAL_DESCRIPTION = `Update the active thread goal's status. Use this tool only to mark the goal achieved or genuinely blocked; it returns an error if there is no active goal.
|
|
10
12
|
Set status to "complete" only when the objective has actually been achieved and no required work remains — never merely because the budget is nearly exhausted or you are stopping.
|
|
11
13
|
Set status to "blocked" only when the same blocking condition has repeated for at least three consecutive goal turns (counting the original turn and automatic continuations) and you cannot make meaningful progress without user input or an external-state change. Do not use "blocked" because work is hard, slow, uncertain, or incomplete.
|
|
12
14
|
You cannot pause, resume, or set a budget through this tool; those are controlled by the user.`;
|
|
13
15
|
export function createGoalTools(store) {
|
|
14
|
-
const getGoal = {
|
|
15
|
-
name: "get_goal",
|
|
16
|
-
description: "Get the current thread goal: objective, status, turns and tokens used, and remaining token budget. Returns an error if there is no goal.",
|
|
17
|
-
parameters: { type: "object", properties: {}, required: [], additionalProperties: false },
|
|
18
|
-
readOnly: true,
|
|
19
|
-
effect: "read",
|
|
20
|
-
promptSnippet: "Inspect the active goal's status and remaining token budget.",
|
|
21
|
-
async execute() {
|
|
22
|
-
const goal = store.snapshot();
|
|
23
|
-
if (!goal)
|
|
24
|
-
return { content: "No active goal.", isError: true };
|
|
25
|
-
return { content: goalSummaryText(goal) };
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
16
|
const updateGoal = {
|
|
29
17
|
name: "update_goal",
|
|
30
18
|
description: UPDATE_GOAL_DESCRIPTION,
|
|
@@ -66,5 +54,5 @@ export function createGoalTools(store) {
|
|
|
66
54
|
};
|
|
67
55
|
},
|
|
68
56
|
};
|
|
69
|
-
return [
|
|
57
|
+
return [updateGoal];
|
|
70
58
|
}
|
package/dist/main.js
CHANGED
|
@@ -9,11 +9,13 @@ import { parseArgs, printHelp } from "./cli.js";
|
|
|
9
9
|
import { effectiveThemeModeForTerminal, shouldProbeTerminalTheme, UserConfig } from "./config.js";
|
|
10
10
|
import { createProviderInstance, createUnavailableProvider } from "./provider.js";
|
|
11
11
|
import { resolveConfiguredModel } from "./model-selection.js";
|
|
12
|
-
import { getDefaultThinkingLevel } from "./provider-transform.js";
|
|
12
|
+
import { getAvailableThinkingLevels, getDefaultThinkingLevel, normalizeThinkingLevel } from "./provider-transform.js";
|
|
13
13
|
import { ProviderRegistry, displayModel, encodeModel, decodeModel } from "./provider-registry.js";
|
|
14
14
|
import { SessionManager } from "./session.js";
|
|
15
15
|
import { createSessionTitleUpdater } from "./session-title.js";
|
|
16
16
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
17
|
+
import { createRoutableModelIndex, createRoutingSnapshotAccessor } from "./agent/routing-catalog.js";
|
|
18
|
+
import { buildModelRoutingPrompt } from "./prompt/routing.js";
|
|
17
19
|
import { SkillRegistry } from "./skills/registry.js";
|
|
18
20
|
import { buildToolPromptOptions, createAllTools } from "./tools/index.js";
|
|
19
21
|
import { FileStateTracker } from "./tools/file-state.js";
|
|
@@ -25,12 +27,14 @@ import { ExternalHookController } from "./hooks/index.js";
|
|
|
25
27
|
import { getLspService } from "./lsp/index.js";
|
|
26
28
|
import { loadMcpConfig } from "./mcp/config.js";
|
|
27
29
|
import { McpManager } from "./mcp/manager.js";
|
|
30
|
+
import { normalizeInheritedThinkingLevel } from "./variant/variant-resolver.js";
|
|
28
31
|
import { QuestionController } from "./question/index.js";
|
|
29
|
-
import { buildMemoryPrompt, formatMemoryStartupResult, recordMemoryCitations, runMemoryPhase2, runMemoryStartupPipeline, startMemoryStartupTask, } from "./memory/index.js";
|
|
32
|
+
import { buildMemoryPrompt, formatMemoryStartupResult, purgeUnsafeMemorySources, recordMemoryCitations, runMemoryPhase2, runMemoryStartupPipeline, startMemoryStartupTask, } from "./memory/index.js";
|
|
30
33
|
import { basename } from "node:path";
|
|
31
34
|
import { normalizeSingleLine, truncateVisual } from "./text-display.js";
|
|
32
35
|
import { BUBBLE_WORDMARK } from "./tui/wordmark.js";
|
|
33
36
|
import { configureDebugTrace, summarizeAgentEventForTrace, summarizeTraceMessage, traceEvent, } from "./debug-trace.js";
|
|
37
|
+
import { shouldRejectGrokSessionInPrintMode } from "./external-runtime/session-policy.js";
|
|
34
38
|
async function main() {
|
|
35
39
|
const args = parseArgs(process.argv.slice(2));
|
|
36
40
|
if (process.argv.includes("-h") || process.argv.includes("--help")) {
|
|
@@ -88,6 +92,7 @@ async function main() {
|
|
|
88
92
|
promptCacheKey: sessionPromptCacheKey,
|
|
89
93
|
protocol: defaultProvider.protocol,
|
|
90
94
|
openAICodexAuth: registry.createOpenAICodexAuthAdapter(defaultProvider.id),
|
|
95
|
+
grokAuth: registry.createGrokAuthAdapter(defaultProvider.id),
|
|
91
96
|
})
|
|
92
97
|
: createUnavailableProvider(unavailableProviderMessage);
|
|
93
98
|
const createProvider = (providerId, apiKey, baseURL) => createProviderInstance({
|
|
@@ -98,6 +103,7 @@ async function main() {
|
|
|
98
103
|
promptCacheKey: sessionPromptCacheKey,
|
|
99
104
|
protocol: registry.getConfigured().find((provider) => provider.id === providerId)?.protocol,
|
|
100
105
|
openAICodexAuth: registry.createOpenAICodexAuthAdapter(providerId),
|
|
106
|
+
grokAuth: registry.createGrokAuthAdapter(providerId),
|
|
101
107
|
});
|
|
102
108
|
const createProviderForRoute = async (route) => {
|
|
103
109
|
const providerId = route.providerId;
|
|
@@ -156,7 +162,7 @@ async function main() {
|
|
|
156
162
|
};
|
|
157
163
|
const lspService = getLspService(args.cwd, settingsManager.getMerged().lsp);
|
|
158
164
|
const fileStateTracker = new FileStateTracker(args.cwd);
|
|
159
|
-
// Shared between the goal
|
|
165
|
+
// Shared between the goal tool (model-facing update_goal) and the
|
|
160
166
|
// TUI's auto-continuation engine / status-line indicator.
|
|
161
167
|
const goalStore = new GoalStore();
|
|
162
168
|
const tools = createAllTools(args.cwd, skillRegistry, {
|
|
@@ -178,6 +184,7 @@ async function main() {
|
|
|
178
184
|
console.error(chalk.yellow(`[mcp:${d.scope}] ${d.path}: ${d.message}`));
|
|
179
185
|
}
|
|
180
186
|
const mcpManager = new McpManager({ servers: mcpLoaded.servers });
|
|
187
|
+
let externalRuntime;
|
|
181
188
|
if (mcpLoaded.servers.length > 0) {
|
|
182
189
|
await mcpManager.start();
|
|
183
190
|
// Only surface failures at startup. Successful connections would push the
|
|
@@ -206,8 +213,19 @@ async function main() {
|
|
|
206
213
|
// ignore — we're exiting anyway
|
|
207
214
|
}
|
|
208
215
|
};
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
const shutdownExternalRuntime = async () => {
|
|
217
|
+
try {
|
|
218
|
+
await externalRuntime?.dispose();
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// ignore — we're exiting anyway
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
const shutdownSidecars = async () => {
|
|
225
|
+
await Promise.allSettled([shutdownMcp(), shutdownExternalRuntime()]);
|
|
226
|
+
};
|
|
227
|
+
process.once("SIGINT", () => { void shutdownSidecars().then(() => process.exit(130)); });
|
|
228
|
+
process.once("SIGTERM", () => { void shutdownSidecars().then(() => process.exit(143)); });
|
|
211
229
|
// Session management:
|
|
212
230
|
// - default: always start a fresh session
|
|
213
231
|
// - --resume --session <name>: restore the named session
|
|
@@ -296,15 +314,30 @@ async function main() {
|
|
|
296
314
|
activeProviderId = "";
|
|
297
315
|
}
|
|
298
316
|
const initialThinkingLevel = activeModel
|
|
299
|
-
?
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
317
|
+
? args.thinkingLevel !== undefined
|
|
318
|
+
? normalizeThinkingLevel(args.thinkingLevel, getAvailableThinkingLevels(activeProviderId, effectiveModelId))
|
|
319
|
+
: sessionThinkingLevel !== undefined
|
|
320
|
+
? normalizeInheritedThinkingLevel(activeProviderId, effectiveModelId, sessionThinkingLevel)
|
|
321
|
+
: configuredThinkingLevel !== undefined
|
|
322
|
+
? normalizeThinkingLevel(configuredThinkingLevel, getAvailableThinkingLevels(activeProviderId, effectiveModelId))
|
|
323
|
+
: getDefaultThinkingLevel(activeProviderId, effectiveModelId)
|
|
324
|
+
: (args.thinkingLevel ?? sessionThinkingLevel ?? configuredThinkingLevel ?? "off");
|
|
304
325
|
const restoredTodos = sessionManager?.getTodos() ?? [];
|
|
305
326
|
const initialMode = args.mode ?? "default";
|
|
306
327
|
const skillSummaries = skillRegistry.summaries();
|
|
328
|
+
// This synchronous provenance gate must run before buildMemoryPrompt: the
|
|
329
|
+
// background startup pipeline is too late once text has entered the native
|
|
330
|
+
// provider's system prompt.
|
|
331
|
+
purgeUnsafeMemorySources(args.cwd);
|
|
307
332
|
const memoryPrompt = buildMemoryPrompt(args.cwd);
|
|
333
|
+
// Routing snapshot accessor (model-routing design §1.5): built before the
|
|
334
|
+
// system prompt because startup composes the prompt before the Agent exists;
|
|
335
|
+
// the same accessor is then handed to the Agent constructor.
|
|
336
|
+
const agentRouting = userConfig.getAgentRouting();
|
|
337
|
+
const routingSnapshotAccessor = createRoutingSnapshotAccessor(registry, () => userConfig.getAgentCategories(), () => agentRouting);
|
|
338
|
+
const initialRoutingParent = activeProviderId && activeModel
|
|
339
|
+
? { providerId: activeProviderId, model: decodeModel(activeModel).modelId }
|
|
340
|
+
: undefined;
|
|
308
341
|
const systemPrompt = buildSystemPrompt({
|
|
309
342
|
agentName: "Bubble",
|
|
310
343
|
configuredProvider: activeProviderId || "none",
|
|
@@ -315,6 +348,9 @@ async function main() {
|
|
|
315
348
|
workingDir: args.cwd,
|
|
316
349
|
...buildToolPromptOptions(tools.filter((tool) => !tool.deferred)),
|
|
317
350
|
memoryPrompt,
|
|
351
|
+
modelRoutingPrompt: initialRoutingParent
|
|
352
|
+
? buildModelRoutingPrompt(routingSnapshotAccessor(initialRoutingParent), agentRouting)
|
|
353
|
+
: undefined,
|
|
318
354
|
});
|
|
319
355
|
const traceInfo = configureDebugTrace({
|
|
320
356
|
cwd: args.cwd,
|
|
@@ -389,6 +425,9 @@ async function main() {
|
|
|
389
425
|
memoryPrompt,
|
|
390
426
|
fileStateTracker,
|
|
391
427
|
agentCategories: userConfig.getAgentCategories(),
|
|
428
|
+
agentRouting,
|
|
429
|
+
routingSnapshot: routingSnapshotAccessor,
|
|
430
|
+
routableModels: createRoutableModelIndex(registry),
|
|
392
431
|
subagents: userConfig.getSubagents(),
|
|
393
432
|
providerFactory: createProviderForRoute,
|
|
394
433
|
externalHooks: hookController,
|
|
@@ -426,20 +465,26 @@ async function main() {
|
|
|
426
465
|
// not perform an ad-hoc extraction of the just-finished session.
|
|
427
466
|
};
|
|
428
467
|
const shutdownRuntime = async () => {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
468
|
+
try {
|
|
469
|
+
await hookController.runEvent({
|
|
470
|
+
eventName: "SessionEnd",
|
|
471
|
+
cwd: args.cwd,
|
|
472
|
+
sessionId: sessionManager?.getSessionFile(),
|
|
473
|
+
agentRole: "driver",
|
|
474
|
+
target: "session",
|
|
475
|
+
payload: {
|
|
476
|
+
providerId: agent.providerId,
|
|
477
|
+
model: agent.apiModel,
|
|
478
|
+
},
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
catch {
|
|
482
|
+
// Shutdown must still release child processes when a hook fails.
|
|
483
|
+
}
|
|
440
484
|
const results = await Promise.allSettled([
|
|
441
485
|
flushMemory(),
|
|
442
486
|
shutdownMcp(),
|
|
487
|
+
shutdownExternalRuntime(),
|
|
443
488
|
lspService.shutdown(),
|
|
444
489
|
]);
|
|
445
490
|
for (const result of results) {
|
|
@@ -480,12 +525,18 @@ async function main() {
|
|
|
480
525
|
if (agent.mode === "plan") {
|
|
481
526
|
agent.injectModeReminder();
|
|
482
527
|
}
|
|
528
|
+
agent.injectDeferredToolsReminder();
|
|
483
529
|
console.log(chalk.dim(`Resumed session: ${sessionManager.getSessionFile()}`));
|
|
484
530
|
}
|
|
485
531
|
}
|
|
486
532
|
try {
|
|
487
533
|
// Print mode: single prompt, then exit
|
|
488
534
|
if (args.print || args.prompt) {
|
|
535
|
+
if (shouldRejectGrokSessionInPrintMode(sessionManager?.getMetadata().externalRuntime, true)) {
|
|
536
|
+
console.error(chalk.red("Error: Grok subscription sessions are interactive. Resume this workspace session in the TUI, or start a fresh native session for --print."));
|
|
537
|
+
process.exitCode = 1;
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
489
540
|
const prompt = args.prompt || (await readPipedStdin()) || "";
|
|
490
541
|
if (!prompt) {
|
|
491
542
|
console.error(chalk.red("Error: No prompt provided."));
|
|
@@ -543,9 +594,8 @@ async function main() {
|
|
|
543
594
|
try {
|
|
544
595
|
const next = new SessionManager(sessionFile);
|
|
545
596
|
const history = next.getMessages();
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
sessionTitleUpdater = createSessionTitleUpdater({
|
|
597
|
+
const nextPromptCacheKey = next.getOrCreatePromptCacheKey();
|
|
598
|
+
const nextTitleUpdater = createSessionTitleUpdater({
|
|
549
599
|
sessionManager: next,
|
|
550
600
|
complete: (messages, completeOptions) => agent.complete(messages, completeOptions),
|
|
551
601
|
});
|
|
@@ -558,9 +608,26 @@ async function main() {
|
|
|
558
608
|
// Keep the live system/meta head (mode reminders survive the switch),
|
|
559
609
|
// mirroring the /rewind history-replacement pattern.
|
|
560
610
|
const head = agent.messages.filter((m) => m.role === "system" || m.role === "meta");
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
611
|
+
const nextMessages = [...head, ...history];
|
|
612
|
+
const nextTodos = next.getTodos();
|
|
613
|
+
// Commit only after every file read/write and reconstruction step has
|
|
614
|
+
// succeeded. Callers can safely prepare candidate sessions without a
|
|
615
|
+
// failed switch rebinding persistence or replacing the live history.
|
|
616
|
+
sessionManager = next;
|
|
617
|
+
sessionPromptCacheKey = nextPromptCacheKey;
|
|
618
|
+
sessionTitleUpdater = nextTitleUpdater;
|
|
619
|
+
agent.messages = nextMessages;
|
|
620
|
+
// These update only live in-memory/UI mirrors after the persistence
|
|
621
|
+
// commit. A best-effort callback failure must not report the switch as
|
|
622
|
+
// rolled back after the outer session binding has already changed.
|
|
623
|
+
try {
|
|
624
|
+
agent.setTodos(nextTodos);
|
|
625
|
+
}
|
|
626
|
+
catch { /* candidate already committed */ }
|
|
627
|
+
try {
|
|
628
|
+
agent.resetContextUsageAnchor();
|
|
629
|
+
}
|
|
630
|
+
catch { /* derived counter only */ }
|
|
564
631
|
return { manager: next };
|
|
565
632
|
}
|
|
566
633
|
catch (error) {
|
|
@@ -587,6 +654,16 @@ async function main() {
|
|
|
587
654
|
runMemorySummary,
|
|
588
655
|
runMemoryRefresh,
|
|
589
656
|
};
|
|
657
|
+
// Grok Subscription is a first-class interactive provider target. Manager
|
|
658
|
+
// construction is deliberately lazy: it does not inspect, spawn, or reach
|
|
659
|
+
// the network until the user selects Grok or runs /login grok. Print,
|
|
660
|
+
// Feishu, help, and version paths return before this import.
|
|
661
|
+
const { createGrokRuntimeManager } = await import("./external-runtime/grok-runtime.js");
|
|
662
|
+
externalRuntime = createGrokRuntimeManager({
|
|
663
|
+
workspace: args.cwd,
|
|
664
|
+
approvalController,
|
|
665
|
+
getPermissionMode: () => agentRef?.mode ?? "default",
|
|
666
|
+
});
|
|
590
667
|
const { startStartupUpdateCheck } = await import("./update/index.js");
|
|
591
668
|
const updateCheck = await startStartupUpdateCheck();
|
|
592
669
|
const updateNotice = updateCheck.notice;
|
|
@@ -599,6 +676,7 @@ async function main() {
|
|
|
599
676
|
onThemeModeChange: (mode) => userConfig.setThemeMode(mode),
|
|
600
677
|
updateNotice: updateNotice ?? undefined,
|
|
601
678
|
updateNoticeRefresh: updateCheck.refreshed,
|
|
679
|
+
externalRuntime,
|
|
602
680
|
});
|
|
603
681
|
const exitWallMs = summary?.wallMs;
|
|
604
682
|
if (sessionManager) {
|
package/dist/memory/db.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export declare class MemoryDatabase {
|
|
|
40
40
|
};
|
|
41
41
|
finishPhase1Job(sessionFile: string, ok: boolean, error?: string): void;
|
|
42
42
|
listStage1Outputs(limit?: number): Stage1Output[];
|
|
43
|
+
listAllStage1Outputs(): Stage1Output[];
|
|
44
|
+
deleteStage1Output(sessionFile: string): boolean;
|
|
43
45
|
listPreviouslySelectedNotIn(sessionFiles: string[]): Stage1Output[];
|
|
44
46
|
markSelectedForPhase2(outputs: Stage1Output[]): void;
|
|
45
47
|
recordUsage(sessionFiles: string[], now?: Date): number;
|
package/dist/memory/db.js
CHANGED
|
@@ -95,6 +95,16 @@ export class MemoryDatabase {
|
|
|
95
95
|
LIMIT ?
|
|
96
96
|
`).all(limit).map((row) => mapStage1(row));
|
|
97
97
|
}
|
|
98
|
+
listAllStage1Outputs() {
|
|
99
|
+
return this.db.prepare(`
|
|
100
|
+
SELECT * FROM memory_stage1_outputs
|
|
101
|
+
ORDER BY usage_count DESC, COALESCE(last_usage, generated_at) DESC, source_updated_at DESC
|
|
102
|
+
`).all().map((row) => mapStage1(row));
|
|
103
|
+
}
|
|
104
|
+
deleteStage1Output(sessionFile) {
|
|
105
|
+
return (this.db.prepare("DELETE FROM memory_stage1_outputs WHERE session_file = ?")
|
|
106
|
+
.run(sessionFile).changes ?? 0) > 0;
|
|
107
|
+
}
|
|
98
108
|
listPreviouslySelectedNotIn(sessionFiles) {
|
|
99
109
|
if (sessionFiles.length === 0) {
|
|
100
110
|
return this.db.prepare("SELECT * FROM memory_stage1_outputs WHERE selected_for_phase2 = 1")
|
package/dist/memory/index.d.ts
CHANGED
package/dist/memory/index.js
CHANGED
package/dist/memory/phase1.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { SessionManager } from "../session.js";
|
|
5
4
|
import { MemoryDatabase } from "./db.js";
|
|
6
5
|
import { getBubbleHome } from "./paths.js";
|
|
7
6
|
import { buildStageOneMessages, parseJsonObject } from "./prompts.js";
|
|
7
|
+
import { classifyMemorySession } from "./session-policy.js";
|
|
8
|
+
import { clearGeneratedMemoryOutputs } from "./storage.js";
|
|
8
9
|
import { redactSecrets } from "./store.js";
|
|
9
10
|
const DEFAULT_MIN_ENTRIES = 4;
|
|
10
11
|
const DEFAULT_LIMIT = 24;
|
|
@@ -22,11 +23,22 @@ export async function runMemoryPhase1(options) {
|
|
|
22
23
|
const sessions = listEligibleSessionFiles(options.limit ?? DEFAULT_LIMIT);
|
|
23
24
|
result.scanned = sessions.length;
|
|
24
25
|
for (const sessionFile of sessions) {
|
|
26
|
+
const source = classifyMemorySession(sessionFile);
|
|
27
|
+
if (source.kind !== "native") {
|
|
28
|
+
if (db.getStage1Output(sessionFile)) {
|
|
29
|
+
// Clear before deleting the provenance row so interruption cannot
|
|
30
|
+
// leave an unsafe generated artifact that looks source-less later.
|
|
31
|
+
clearGeneratedMemoryOutputs(options.cwd);
|
|
32
|
+
db.deleteStage1Output(sessionFile);
|
|
33
|
+
}
|
|
34
|
+
result.skipped++;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
25
37
|
if (db.getThreadMemoryMode(sessionFile) === "disabled") {
|
|
26
38
|
result.skipped++;
|
|
27
39
|
continue;
|
|
28
40
|
}
|
|
29
|
-
const session =
|
|
41
|
+
const session = source.session;
|
|
30
42
|
const sessionCwd = session.getMetadata().cwd ?? options.cwd;
|
|
31
43
|
const entries = session.getEntries();
|
|
32
44
|
const entryCount = entries.length;
|