@bike4mind/cli 0.9.3 → 0.10.1
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 +13 -3
- package/bin/bike4mind-cli.mjs +44 -1
- package/dist/{BubblewrapRuntime-CUD3bsgG.mjs → BubblewrapRuntime-CkL9-gnG.mjs} +1 -1
- package/dist/{ConfigStore-BauEpjvT.mjs → ConfigStore-aeJGqjKm.mjs} +116 -15
- package/dist/ProxyManager-ByuAHFMq.mjs +3 -0
- package/dist/{SandboxOrchestrator-C4oDqltp.mjs → SandboxOrchestrator-BS6gALNq.mjs} +1 -1
- package/dist/{SandboxOrchestrator-B4GcZdBc.mjs → SandboxOrchestrator-BoINxbX4.mjs} +1 -1
- package/dist/{SandboxRuntimeAdapter-DXa3nFOw.mjs → SandboxRuntimeAdapter-CKelGICD.mjs} +1 -1
- package/dist/{SandboxRuntimeAdapter-D1RUReNL.mjs → SandboxRuntimeAdapter-ChGlxSGQ.mjs} +2 -2
- package/dist/{SeatbeltRuntime-CTElMR9Q.mjs → SeatbeltRuntime-Qqt19cAN.mjs} +1 -1
- package/dist/{bashExecute-pYljpfPn-BZXHMQEl.mjs → bashExecute-B1N1lMOS-TZVDbcQ4.mjs} +1 -1
- package/dist/commands/apiCommand.mjs +45 -0
- package/dist/commands/doctorCommand.mjs +2 -2
- package/dist/commands/headlessCommand.mjs +6 -6
- package/dist/commands/mcpCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +2 -2
- package/dist/{createFile-C1JoeuYh-metInFKd.mjs → createFile-DPv180yF-BnWFIxey.mjs} +2 -2
- package/dist/{deleteFile-BTberNGj-CW922hRM.mjs → deleteFile-BdjUwUQF-B3XOJmg3.mjs} +2 -2
- package/dist/{globFiles-Bez8QCbS-DZb6McbJ.mjs → globFiles-DjfDGaUK-CNR8pMRC.mjs} +2 -2
- package/dist/{grepSearch-BxucZWO8-lPRv6R6F.mjs → grepSearch-DJs-cubo-Bm0Y8oS3.mjs} +2 -2
- package/dist/index.mjs +258 -39
- package/dist/{pathValidation-CIytuhr3-Dt5dntLx.mjs → pathValidation-D8tjkQXE-1HwvsuYT.mjs} +1 -1
- package/dist/store-DgzCTRkN.mjs +3 -0
- package/dist/{tools-CpWE3Qif.mjs → tools-RdGu37Lw.mjs} +11217 -10240
- package/dist/types-CqscS34o.mjs +3 -0
- package/dist/{updateChecker-DhWcEKAu.mjs → updateChecker-CP_jeER9.mjs} +1 -1
- package/dist/utils-BGtSXfce.mjs +3 -0
- package/dist/utils-PpNti-tY.mjs +146 -0
- package/package.json +31 -31
- package/dist/ProxyManager-DIAAw902.mjs +0 -3
- package/dist/store-5PXzE9DM.mjs +0 -3
- package/dist/types-DK3P88Px.mjs +0 -3
- /package/dist/{ImageStore-BFp_d12J.mjs → ImageStore-BVmEG1xc.mjs} +0 -0
- /package/dist/{ProxyManager-BsCoxpns.mjs → ProxyManager-CV94yZUW.mjs} +0 -0
- /package/dist/{StderrViolationParser-BFP4bo7I.mjs → StderrViolationParser-CS43a-TP.mjs} +0 -0
- /package/dist/{ViolationLogStore-Dp6HF0nz.mjs → ViolationLogStore-B-plqJfn.mjs} +0 -0
- /package/dist/{ripgrepCheck-DIu4apVE.mjs → ripgrepCheck-BmkyTK2i.mjs} +0 -0
- /package/dist/{store-BonrwrMi.mjs → store-DV5s-qni.mjs} +0 -0
- /package/dist/{terminalSetup-DxloCowq.mjs → terminalSetup-BbJt04ZG.mjs} +0 -0
- /package/dist/{treeSitterEngine-Cw2LbVZT.mjs → treeSitterEngine-BRbQ9b7I.mjs} +0 -0
- /package/dist/{types-DBEjF9YS.mjs → types-LyRNHOiS.mjs} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as CommandHistoryStore, A as formatStep, B as DEFAULT_RETRY_CONFIG, C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as PermissionManager, G as OllamaBackend, H as clearFeatureModuleTools, I as generateCliTools, J as buildSkillsPromptSection, K as getPlanModeFilePath, L as ALWAYS_DENIED_FOR_AGENTS, M as loadContextFiles, N as getApiUrl, O as McpManager, P as getEnvironmentName, Q as CheckpointStore, R as DEFAULT_AGENT_MODEL, S as ApiClient, T as FallbackLlmBackend, U as registerFeatureModuleTools, V as DEFAULT_THOROUGHNESS, W as setWebSocketToolExecutor, X as ReActAgent, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createAgentDelegateTool, a as createBlockerTools, at as mergeCommands, b as createSkillTool, c as createDecisionStore, ct as warmFileCache, d as createFindDefinitionTool, et as SessionStore, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, i as createBlockerStore, it as searchCommands, j as extractCompactInstructions, k as substituteArguments, l as formatDecisionsOutput, m as createCoordinateTaskTool, n as createReviewGateTool, nt as hasFileReferences, o as formatBlockersOutput, ot as formatFileSize, p as createWriteTodosTool, q as buildSystemPrompt, r as formatReviewGatesOutput, rt as processFileReferences, s as createDecisionLogTool, st as searchFiles, t as createReviewGateStore, tt as OAuthClient, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, x as parseAgentConfig, y as SubagentOrchestrator, z as DEFAULT_MAX_ITERATIONS } from "./tools-
|
|
3
|
-
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-
|
|
4
|
-
import { Xt as validateNotebookPath$1, Yt as validateJupyterKernelName, g as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore, v as ChatModels } from "./ConfigStore-
|
|
5
|
-
import { a as version, t as checkForUpdate } from "./updateChecker-
|
|
2
|
+
import { $ as CommandHistoryStore, A as formatStep, B as DEFAULT_RETRY_CONFIG, C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as PermissionManager, G as OllamaBackend, H as clearFeatureModuleTools, I as generateCliTools, J as buildSkillsPromptSection, K as getPlanModeFilePath, L as ALWAYS_DENIED_FOR_AGENTS, M as loadContextFiles, N as getApiUrl, O as McpManager, P as getEnvironmentName, Q as CheckpointStore, R as DEFAULT_AGENT_MODEL, S as ApiClient, T as FallbackLlmBackend, U as registerFeatureModuleTools, V as DEFAULT_THOROUGHNESS, W as setWebSocketToolExecutor, X as ReActAgent, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createAgentDelegateTool, a as createBlockerTools, at as mergeCommands, b as createSkillTool, c as createDecisionStore, ct as warmFileCache, d as createFindDefinitionTool, et as SessionStore, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, i as createBlockerStore, it as searchCommands, j as extractCompactInstructions, k as substituteArguments, l as formatDecisionsOutput, m as createCoordinateTaskTool, n as createReviewGateTool, nt as hasFileReferences, o as formatBlockersOutput, ot as formatFileSize, p as createWriteTodosTool, q as buildSystemPrompt, r as formatReviewGatesOutput, rt as processFileReferences, s as createDecisionLogTool, st as searchFiles, t as createReviewGateStore, tt as OAuthClient, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, x as parseAgentConfig, y as SubagentOrchestrator, z as DEFAULT_MAX_ITERATIONS } from "./tools-RdGu37Lw.mjs";
|
|
3
|
+
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-DV5s-qni.mjs";
|
|
4
|
+
import { Xt as validateNotebookPath$1, Yt as validateJupyterKernelName, g as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore, v as ChatModels } from "./ConfigStore-aeJGqjKm.mjs";
|
|
5
|
+
import { a as version, t as checkForUpdate } from "./updateChecker-CP_jeER9.mjs";
|
|
6
6
|
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
7
7
|
import { Box, Static, Text, render, useApp, useInput, usePaste, useStdout } from "ink";
|
|
8
8
|
import { execSync } from "child_process";
|
|
@@ -287,8 +287,7 @@ function CommandAutocomplete({ commands, selectedIndex }) {
|
|
|
287
287
|
let startIndex = 0;
|
|
288
288
|
let endIndex = Math.min(VIEWPORT_SIZE, totalCommands);
|
|
289
289
|
if (totalCommands > VIEWPORT_SIZE) {
|
|
290
|
-
|
|
291
|
-
startIndex = Math.max(0, selectedIndex - halfViewport);
|
|
290
|
+
startIndex = Math.max(0, selectedIndex - Math.floor(VIEWPORT_SIZE / 2));
|
|
292
291
|
endIndex = Math.min(totalCommands, startIndex + VIEWPORT_SIZE);
|
|
293
292
|
if (endIndex === totalCommands) startIndex = Math.max(0, totalCommands - VIEWPORT_SIZE);
|
|
294
293
|
}
|
|
@@ -329,8 +328,7 @@ function FileAutocomplete({ files, selectedIndex, query }) {
|
|
|
329
328
|
let startIndex = 0;
|
|
330
329
|
let endIndex = Math.min(VIEWPORT_SIZE, totalFiles);
|
|
331
330
|
if (totalFiles > VIEWPORT_SIZE) {
|
|
332
|
-
|
|
333
|
-
startIndex = Math.max(0, selectedIndex - halfViewport);
|
|
331
|
+
startIndex = Math.max(0, selectedIndex - Math.floor(VIEWPORT_SIZE / 2));
|
|
334
332
|
endIndex = Math.min(totalFiles, startIndex + VIEWPORT_SIZE);
|
|
335
333
|
if (endIndex === totalFiles) startIndex = Math.max(0, totalFiles - VIEWPORT_SIZE);
|
|
336
334
|
}
|
|
@@ -2164,6 +2162,10 @@ function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPe
|
|
|
2164
2162
|
await onCommand(command, args);
|
|
2165
2163
|
return;
|
|
2166
2164
|
}
|
|
2165
|
+
if (trimmed === "exit" || trimmed === "quit") {
|
|
2166
|
+
await onCommand(trimmed, []);
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2167
2169
|
let messageToSend = trimmed;
|
|
2168
2170
|
if (hasFileReferences(trimmed)) {
|
|
2169
2171
|
const processed = await processFileReferences(trimmed);
|
|
@@ -2668,7 +2670,7 @@ const ROLE_LABELS = {
|
|
|
2668
2670
|
function buildHandoffPrompt(session) {
|
|
2669
2671
|
if (session.messages.length < 4) return "";
|
|
2670
2672
|
const filtered = session.messages.filter((m) => !isInjectedHandoff(m));
|
|
2671
|
-
const conversation = filtered.length > MAX_CONVERSATION_MESSAGES ? filtered.slice(-
|
|
2673
|
+
const conversation = filtered.length > MAX_CONVERSATION_MESSAGES ? filtered.slice(-50) : filtered;
|
|
2672
2674
|
let prompt = `You are generating a structured session handoff so the next session (or another agent) can pick up seamlessly without re-reading the full chat history.
|
|
2673
2675
|
|
|
2674
2676
|
Output a single JSON object — no prose, no markdown fences — with exactly these fields:
|
|
@@ -3759,6 +3761,196 @@ Unlike agent_delegate (which uses pre-defined agents), this tool lets you compos
|
|
|
3759
3761
|
};
|
|
3760
3762
|
}
|
|
3761
3763
|
//#endregion
|
|
3764
|
+
//#region src/tools/deferredToolRegistry.ts
|
|
3765
|
+
/**
|
|
3766
|
+
* Registry of tool schemas that are NOT loaded into the model's initial tool
|
|
3767
|
+
* list. The model sees only the names (via the system prompt directory) and
|
|
3768
|
+
* must call the `tool_search` meta-tool to load schemas on demand.
|
|
3769
|
+
*
|
|
3770
|
+
* This mirrors Claude Code's deferred-tool pattern. The win is large for
|
|
3771
|
+
* heavy MCP integrations (e.g. 41 GitHub MCP tools at ~250-350 tokens of
|
|
3772
|
+
* JSONSchema each = ~10-15k tokens per turn that's now ~1-1.5k of names).
|
|
3773
|
+
*/
|
|
3774
|
+
var DeferredToolRegistry = class {
|
|
3775
|
+
constructor() {
|
|
3776
|
+
this.byName = /* @__PURE__ */ new Map();
|
|
3777
|
+
}
|
|
3778
|
+
/** Replace registry contents with the supplied tools. Idempotent. */
|
|
3779
|
+
register(tools) {
|
|
3780
|
+
this.byName.clear();
|
|
3781
|
+
for (const tool of tools) this.byName.set(tool.toolSchema.name, tool);
|
|
3782
|
+
logger.debug(`[DeferredToolRegistry] Registered ${tools.length} deferred tool(s)`);
|
|
3783
|
+
}
|
|
3784
|
+
clear() {
|
|
3785
|
+
this.byName.clear();
|
|
3786
|
+
}
|
|
3787
|
+
size() {
|
|
3788
|
+
return this.byName.size;
|
|
3789
|
+
}
|
|
3790
|
+
has(name) {
|
|
3791
|
+
return this.byName.has(name);
|
|
3792
|
+
}
|
|
3793
|
+
get(name) {
|
|
3794
|
+
return this.byName.get(name);
|
|
3795
|
+
}
|
|
3796
|
+
getAll() {
|
|
3797
|
+
return Array.from(this.byName.values());
|
|
3798
|
+
}
|
|
3799
|
+
/** Return tools whose names appear in the supplied list, in input order. */
|
|
3800
|
+
getByNames(names) {
|
|
3801
|
+
const found = [];
|
|
3802
|
+
for (const name of names) {
|
|
3803
|
+
const tool = this.byName.get(name);
|
|
3804
|
+
if (tool) found.push(tool);
|
|
3805
|
+
}
|
|
3806
|
+
return found;
|
|
3807
|
+
}
|
|
3808
|
+
/**
|
|
3809
|
+
* Rank-search deferred tools by query terms. Name matches outrank
|
|
3810
|
+
* description matches; exact substring on name wins ties.
|
|
3811
|
+
*/
|
|
3812
|
+
searchByKeywords(query, maxResults) {
|
|
3813
|
+
const terms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 0);
|
|
3814
|
+
if (terms.length === 0) return [];
|
|
3815
|
+
const scored = [];
|
|
3816
|
+
for (const tool of this.byName.values()) {
|
|
3817
|
+
const name = tool.toolSchema.name.toLowerCase();
|
|
3818
|
+
const desc = (tool.toolSchema.description || "").toLowerCase();
|
|
3819
|
+
let score = 0;
|
|
3820
|
+
for (const term of terms) {
|
|
3821
|
+
if (name.includes(term)) score += 10;
|
|
3822
|
+
if (desc.includes(term)) score += 1;
|
|
3823
|
+
}
|
|
3824
|
+
if (score > 0) scored.push({
|
|
3825
|
+
tool,
|
|
3826
|
+
score
|
|
3827
|
+
});
|
|
3828
|
+
}
|
|
3829
|
+
scored.sort((a, b) => b.score - a.score);
|
|
3830
|
+
return scored.slice(0, maxResults).map((s) => s.tool);
|
|
3831
|
+
}
|
|
3832
|
+
/** Return the directory entries used to render the system-prompt reminder. */
|
|
3833
|
+
getDirectoryNames() {
|
|
3834
|
+
return Array.from(this.byName.keys()).sort();
|
|
3835
|
+
}
|
|
3836
|
+
};
|
|
3837
|
+
const deferredToolRegistry = new DeferredToolRegistry();
|
|
3838
|
+
//#endregion
|
|
3839
|
+
//#region src/tools/toolSearchTool.ts
|
|
3840
|
+
/**
|
|
3841
|
+
* Default number of tools returned for a keyword search. Matches Claude
|
|
3842
|
+
* Code's ToolSearch convention. 5 keeps the response payload small while
|
|
3843
|
+
* surfacing enough alternatives for the model to refine its query.
|
|
3844
|
+
*/
|
|
3845
|
+
const DEFAULT_MAX_RESULTS = 5;
|
|
3846
|
+
/**
|
|
3847
|
+
* Runtime validation for tool_search params. The LLM produces these
|
|
3848
|
+
* values, so we validate at this boundary rather than trusting the
|
|
3849
|
+
* shape. Coerces `max_results` from string→number for models that emit
|
|
3850
|
+
* numeric-looking strings.
|
|
3851
|
+
*/
|
|
3852
|
+
const ToolSearchParamsSchema = z.object({
|
|
3853
|
+
query: z.string().min(1, "query must be a non-empty string"),
|
|
3854
|
+
max_results: z.coerce.number().int().min(1).max(20).optional()
|
|
3855
|
+
});
|
|
3856
|
+
/**
|
|
3857
|
+
* Parse the query string. Two forms:
|
|
3858
|
+
* - `select:name1,name2,...` — exact-name selection
|
|
3859
|
+
* - free text — keyword search across name + description
|
|
3860
|
+
*/
|
|
3861
|
+
function parseQuery(query) {
|
|
3862
|
+
const trimmed = query.trim();
|
|
3863
|
+
const selectMatch = trimmed.match(/^select:(.+)$/i);
|
|
3864
|
+
if (selectMatch) return {
|
|
3865
|
+
mode: "select",
|
|
3866
|
+
names: selectMatch[1].split(",").map((n) => n.trim()).filter((n) => n.length > 0)
|
|
3867
|
+
};
|
|
3868
|
+
return {
|
|
3869
|
+
mode: "search",
|
|
3870
|
+
text: trimmed
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3873
|
+
/**
|
|
3874
|
+
* Format the loaded-tools response. Mirrors Claude Code's convention:
|
|
3875
|
+
* one <function>{...}</function> line per matched tool. The model has
|
|
3876
|
+
* already seen this format in its tool-registration system messages, so
|
|
3877
|
+
* it parses without additional explanation.
|
|
3878
|
+
*
|
|
3879
|
+
* Note: the schemas are *also* injected into context.tools by the caller,
|
|
3880
|
+
* so on the next iteration the model gets them as native tool definitions.
|
|
3881
|
+
* The text response here is for in-turn awareness and audit trail.
|
|
3882
|
+
*/
|
|
3883
|
+
function renderToolsBlock(tools) {
|
|
3884
|
+
if (tools.length === 0) return "";
|
|
3885
|
+
return `<functions>\n${tools.map((tool) => {
|
|
3886
|
+
const schema = {
|
|
3887
|
+
description: tool.toolSchema.description,
|
|
3888
|
+
name: tool.toolSchema.name,
|
|
3889
|
+
parameters: tool.toolSchema.parameters
|
|
3890
|
+
};
|
|
3891
|
+
return `<function>${JSON.stringify(schema)}</function>`;
|
|
3892
|
+
}).join("\n")}\n</functions>`;
|
|
3893
|
+
}
|
|
3894
|
+
/**
|
|
3895
|
+
* Build the tool_search meta-tool. The returned tool has a closure over
|
|
3896
|
+
* the supplied `toolListAccessor`, which it uses to push newly-resolved
|
|
3897
|
+
* tool schemas into the live agent context.
|
|
3898
|
+
*
|
|
3899
|
+
* Idempotent: re-loading a tool that's already in the context is a no-op.
|
|
3900
|
+
*/
|
|
3901
|
+
function createToolSearchTool(toolListAccessor) {
|
|
3902
|
+
return {
|
|
3903
|
+
toolSchema: {
|
|
3904
|
+
name: "tool_search",
|
|
3905
|
+
description: "Fetches full schema definitions for deferred tools so they can be called. Deferred tools appear by name only in a system reminder; their parameter schemas are NOT loaded by default. Use this tool to load schemas on demand. Query forms: 'select:name1,name2' for exact selection, or free-text keywords to search by name and description. Once a tool's schema is returned, it becomes callable in subsequent turns.",
|
|
3906
|
+
parameters: {
|
|
3907
|
+
type: "object",
|
|
3908
|
+
properties: {
|
|
3909
|
+
query: {
|
|
3910
|
+
type: "string",
|
|
3911
|
+
description: "Either 'select:<comma-separated names>' to fetch specific tools, or free-text keywords (e.g. 'github pull request') to rank-search deferred tools."
|
|
3912
|
+
},
|
|
3913
|
+
max_results: {
|
|
3914
|
+
type: "number",
|
|
3915
|
+
description: `Maximum number of tools to return for keyword search. Defaults to ${DEFAULT_MAX_RESULTS}. Ignored for 'select:' queries.`
|
|
3916
|
+
}
|
|
3917
|
+
},
|
|
3918
|
+
required: ["query"]
|
|
3919
|
+
}
|
|
3920
|
+
},
|
|
3921
|
+
toolFn: async (params) => {
|
|
3922
|
+
const parsedParams = ToolSearchParamsSchema.safeParse(params ?? {});
|
|
3923
|
+
if (!parsedParams.success) {
|
|
3924
|
+
const issue = parsedParams.error.issues[0];
|
|
3925
|
+
return `tool_search: invalid parameters — ${issue.path.join(".") || "params"}: ${issue.message}`;
|
|
3926
|
+
}
|
|
3927
|
+
const { query, max_results } = parsedParams.data;
|
|
3928
|
+
const parsed = parseQuery(query);
|
|
3929
|
+
let matched;
|
|
3930
|
+
let unmatched = [];
|
|
3931
|
+
if (parsed.mode === "select") {
|
|
3932
|
+
matched = deferredToolRegistry.getByNames(parsed.names);
|
|
3933
|
+
const foundNames = new Set(matched.map((t) => t.toolSchema.name));
|
|
3934
|
+
unmatched = parsed.names.filter((n) => !foundNames.has(n));
|
|
3935
|
+
} else {
|
|
3936
|
+
const max = max_results ?? DEFAULT_MAX_RESULTS;
|
|
3937
|
+
matched = deferredToolRegistry.searchByKeywords(parsed.text, max);
|
|
3938
|
+
}
|
|
3939
|
+
if (matched.length === 0) return parsed.mode === "select" ? `tool_search: no deferred tools matched ${parsed.names.join(", ")}. Use a free-text query to search.` : `tool_search: no deferred tools matched query "${parsed.text}".`;
|
|
3940
|
+
const liveTools = toolListAccessor();
|
|
3941
|
+
const liveNames = new Set(liveTools.map((t) => t.toolSchema.name));
|
|
3942
|
+
let added = 0;
|
|
3943
|
+
for (const tool of matched) if (!liveNames.has(tool.toolSchema.name)) {
|
|
3944
|
+
liveTools.push(tool);
|
|
3945
|
+
added++;
|
|
3946
|
+
}
|
|
3947
|
+
logger.debug(`[tool_search] query="${query}" matched=${matched.length} added=${added} alreadyLoaded=${matched.length - added}`);
|
|
3948
|
+
const block = renderToolsBlock(matched);
|
|
3949
|
+
return `${`Loaded ${added} new tool schema(s)${added < matched.length ? ` (${matched.length - added} already loaded)` : ""}. These are now callable in your next message.${unmatched.length > 0 ? `\n\nNot found: ${unmatched.join(", ")}` : ""}`}\n\n${block}`;
|
|
3950
|
+
}
|
|
3951
|
+
};
|
|
3952
|
+
}
|
|
3953
|
+
//#endregion
|
|
3762
3954
|
//#region src/features/FeatureModuleRegistry.ts
|
|
3763
3955
|
/**
|
|
3764
3956
|
* Manages the lifecycle of opt-in CLI feature modules.
|
|
@@ -5854,11 +6046,11 @@ function CliApp() {
|
|
|
5854
6046
|
};
|
|
5855
6047
|
const permissionManager = new PermissionManager(config.trustedTools || [], void 0, config.tools.disabled || []);
|
|
5856
6048
|
const [{ createSandboxRuntime }, { SandboxOrchestrator }, { DEFAULT_SANDBOX_CONFIG }, { ProxyManager }, { ViolationLogStore }] = await Promise.all([
|
|
5857
|
-
import("./SandboxRuntimeAdapter-
|
|
5858
|
-
import("./SandboxOrchestrator-
|
|
5859
|
-
import("./types-
|
|
5860
|
-
import("./ProxyManager-
|
|
5861
|
-
import("./ViolationLogStore-
|
|
6049
|
+
import("./SandboxRuntimeAdapter-CKelGICD.mjs"),
|
|
6050
|
+
import("./SandboxOrchestrator-BS6gALNq.mjs"),
|
|
6051
|
+
import("./types-CqscS34o.mjs"),
|
|
6052
|
+
import("./ProxyManager-ByuAHFMq.mjs"),
|
|
6053
|
+
import("./ViolationLogStore-B-plqJfn.mjs")
|
|
5862
6054
|
]);
|
|
5863
6055
|
const sandboxConfig = config.sandbox ?? DEFAULT_SANDBOX_CONFIG;
|
|
5864
6056
|
const checkpointStore = new CheckpointStore(state.configStore.getProjectConfigDir() || process.cwd());
|
|
@@ -5974,10 +6166,23 @@ function CliApp() {
|
|
|
5974
6166
|
loadContextFiles(agentProjectDir)
|
|
5975
6167
|
]);
|
|
5976
6168
|
const mcpTools = mcpManager.getTools();
|
|
6169
|
+
const deferredB4mToolNames = new Set([
|
|
6170
|
+
"math_evaluate",
|
|
6171
|
+
"dice_roll",
|
|
6172
|
+
"current_datetime",
|
|
6173
|
+
"recent_changes",
|
|
6174
|
+
"prompt_enhancement"
|
|
6175
|
+
]);
|
|
6176
|
+
const deferredB4mTools = b4mTools.filter((t) => deferredB4mToolNames.has(t.toolSchema.name));
|
|
6177
|
+
const loadedB4mTools = b4mTools.filter((t) => !deferredB4mToolNames.has(t.toolSchema.name));
|
|
6178
|
+
deferredToolRegistry.register([...mcpTools, ...deferredB4mTools]);
|
|
5977
6179
|
if (mcpTools.length > 0) {
|
|
5978
6180
|
const serverSummaries = mcpManager.getToolCount().map((s) => `${s.serverName} (${s.count})`).join(", ");
|
|
5979
|
-
startupLog.push(`🛠️ Loaded ${
|
|
5980
|
-
} else
|
|
6181
|
+
startupLog.push(`🛠️ Loaded ${loadedB4mTools.length} B4M + ${mcpTools.length} MCP tool(s, ${deferredB4mTools.length + mcpTools.length} deferred): ${serverSummaries}`);
|
|
6182
|
+
} else {
|
|
6183
|
+
const suffix = deferredB4mTools.length > 0 ? ` (${deferredB4mTools.length} deferred)` : "";
|
|
6184
|
+
startupLog.push(`🛠️ Loaded ${loadedB4mTools.length} B4M tool(s)${suffix}, no MCP tools`);
|
|
6185
|
+
}
|
|
5981
6186
|
const agentSummary = agentStore.getSummary();
|
|
5982
6187
|
startupLog.push(`🤖 Loaded ${agentSummary.total} agent(s): ${agentSummary.builtin} built-in, ${agentSummary.global} global, ${agentSummary.project} project`);
|
|
5983
6188
|
const orchestrator = new SubagentOrchestrator({
|
|
@@ -6051,9 +6256,14 @@ function CliApp() {
|
|
|
6051
6256
|
cliTools.push(coordinateTaskTool);
|
|
6052
6257
|
}
|
|
6053
6258
|
const featureTools = featureRegistry.getAllTools();
|
|
6259
|
+
const agentToolsRef = { current: null };
|
|
6260
|
+
const toolSearchTool = deferredToolRegistry.size() > 0 ? createToolSearchTool(() => {
|
|
6261
|
+
if (!agentToolsRef.current) throw new Error("tool_search invoked before agent context was wired");
|
|
6262
|
+
return agentToolsRef.current;
|
|
6263
|
+
}) : null;
|
|
6054
6264
|
const allTools = [
|
|
6055
|
-
...
|
|
6056
|
-
...
|
|
6265
|
+
...loadedB4mTools,
|
|
6266
|
+
...toolSearchTool ? [toolSearchTool] : [],
|
|
6057
6267
|
...cliTools,
|
|
6058
6268
|
...featureTools
|
|
6059
6269
|
];
|
|
@@ -6068,7 +6278,7 @@ function CliApp() {
|
|
|
6068
6278
|
const moduleNames = featureRegistry.getModuleNames().join(", ");
|
|
6069
6279
|
startupLog.push(`🏰 Feature modules: ${moduleNames} (${featureTools.length} tools)`);
|
|
6070
6280
|
}
|
|
6071
|
-
logger.debug(`Total tools available to agent: ${allTools.length} (${
|
|
6281
|
+
logger.debug(`Total tools available to agent: ${allTools.length} (${loadedB4mTools.length} B4M loaded + ${cliTools.length} CLI + ${featureTools.length} feature + ${toolSearchTool ? 1 : 0} tool_search, ${deferredB4mTools.length} B4M + ${mcpTools.length} MCP deferred)`);
|
|
6072
6282
|
if (contextResult.globalContext) startupLog.push(`📄 Global context: ${contextResult.globalContext.filename}`);
|
|
6073
6283
|
if (contextResult.projectContext) startupLog.push(`📄 Project context: ${contextResult.projectContext.filename}`);
|
|
6074
6284
|
for (const error of contextResult.errors) startupLog.push(`⚠️ Context file error: ${error}`);
|
|
@@ -6082,7 +6292,8 @@ function CliApp() {
|
|
|
6082
6292
|
enableDynamicAgentCreation: config.preferences.enableDynamicAgentCreation === true,
|
|
6083
6293
|
additionalDirectories,
|
|
6084
6294
|
featureModulePrompts: featureModulePrompts || void 0,
|
|
6085
|
-
planModeFilePath: mode === "plan" ? getPlanModeFilePath(newSession.id) : void 0
|
|
6295
|
+
planModeFilePath: mode === "plan" ? getPlanModeFilePath(newSession.id) : void 0,
|
|
6296
|
+
deferredToolNames: deferredToolRegistry.getDirectoryNames()
|
|
6086
6297
|
});
|
|
6087
6298
|
const cliSystemPrompt = buildPromptForMode(useCliStore.getState().interactionMode);
|
|
6088
6299
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
@@ -6095,16 +6306,17 @@ function CliApp() {
|
|
|
6095
6306
|
maxIterations,
|
|
6096
6307
|
maxTokens: config.preferences.maxTokens,
|
|
6097
6308
|
temperature: config.preferences.temperature,
|
|
6098
|
-
systemPrompt: cliSystemPrompt
|
|
6309
|
+
systemPrompt: cliSystemPrompt,
|
|
6310
|
+
unknownToolResolver: async (toolName) => deferredToolRegistry.get(toolName) ?? null
|
|
6099
6311
|
});
|
|
6312
|
+
agentToolsRef.current = agent.getTools();
|
|
6100
6313
|
agentContext.currentAgent = agent;
|
|
6101
|
-
const agentInternalContext = agent.context;
|
|
6102
6314
|
let lastInteractionMode = useCliStore.getState().interactionMode;
|
|
6103
6315
|
useCliStore.subscribe((s) => {
|
|
6104
6316
|
if (s.interactionMode === lastInteractionMode) return;
|
|
6105
6317
|
lastInteractionMode = s.interactionMode;
|
|
6106
6318
|
if (agentContext.currentAgent !== agent) return;
|
|
6107
|
-
|
|
6319
|
+
agent.setSystemPrompt(buildPromptForMode(s.interactionMode));
|
|
6108
6320
|
});
|
|
6109
6321
|
agent.observationQueue = agentContext.observationQueue;
|
|
6110
6322
|
const stepHandler = (step) => {
|
|
@@ -6560,7 +6772,8 @@ function CliApp() {
|
|
|
6560
6772
|
customCommands: state.customCommandStore.getAllCommands(),
|
|
6561
6773
|
enableSkillTool: config?.preferences.enableSkillTool !== false,
|
|
6562
6774
|
additionalDirectories: state.additionalDirectories,
|
|
6563
|
-
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
|
|
6775
|
+
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0,
|
|
6776
|
+
deferredToolNames: deferredToolRegistry.getDirectoryNames()
|
|
6564
6777
|
});
|
|
6565
6778
|
if (tokenCounter.countSessionTokens(activeSession, systemPrompt).totalTokens >= threshold) {
|
|
6566
6779
|
console.log("\n⚠️ Context window 80% full. Auto-compacting...\n");
|
|
@@ -6875,7 +7088,7 @@ function CliApp() {
|
|
|
6875
7088
|
let imageStore = state.imageStore;
|
|
6876
7089
|
if (!imageStore) {
|
|
6877
7090
|
if (!imageStoreInitPromise.current) imageStoreInitPromise.current = (async () => {
|
|
6878
|
-
const { ImageStore: ImageStoreClass } = await import("./ImageStore-
|
|
7091
|
+
const { ImageStore: ImageStoreClass } = await import("./ImageStore-BVmEG1xc.mjs");
|
|
6879
7092
|
const newImageStore = new ImageStoreClass();
|
|
6880
7093
|
setState((prev) => ({
|
|
6881
7094
|
...prev,
|
|
@@ -6924,8 +7137,7 @@ function CliApp() {
|
|
|
6924
7137
|
console.log(`${emoji} ${label}:`);
|
|
6925
7138
|
const terminalWidth = process.stdout.columns || 80;
|
|
6926
7139
|
const nameWidth = 25;
|
|
6927
|
-
const
|
|
6928
|
-
const maxDescLength = Math.max(20, terminalWidth - prefixWidth);
|
|
7140
|
+
const maxDescLength = Math.max(20, terminalWidth - 30);
|
|
6929
7141
|
agents.forEach((agent) => {
|
|
6930
7142
|
const desc = agent.description.length > maxDescLength ? agent.description.slice(0, maxDescLength - 3) + "..." : agent.description;
|
|
6931
7143
|
console.log(` ${agent.name.padEnd(nameWidth)} - ${desc}`);
|
|
@@ -7752,7 +7964,7 @@ Multi-line Input:
|
|
|
7752
7964
|
const skillsTokens = skillsSection ? tokenCounter.countTokens(skillsSection) : 0;
|
|
7753
7965
|
const agentDirectoryTokens = state.agentStore ? tokenCounter.countTokens(state.agentStore.getDirectoryContext()) : 0;
|
|
7754
7966
|
const mcpTools = state.mcpManager?.getTools() || [];
|
|
7755
|
-
const
|
|
7967
|
+
const deferredNames = deferredToolRegistry.getDirectoryNames();
|
|
7756
7968
|
const mcpToolCount = state.mcpManager?.getToolCount() || [];
|
|
7757
7969
|
const systemPrompt = buildSystemPrompt(variantForCount, {
|
|
7758
7970
|
contextContent: state.contextContent,
|
|
@@ -7760,10 +7972,13 @@ Multi-line Input:
|
|
|
7760
7972
|
customCommands: commands,
|
|
7761
7973
|
enableSkillTool: state.config?.preferences.enableSkillTool !== false,
|
|
7762
7974
|
additionalDirectories: state.additionalDirectories,
|
|
7763
|
-
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
|
|
7975
|
+
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0,
|
|
7976
|
+
deferredToolNames: deferredNames
|
|
7764
7977
|
});
|
|
7765
7978
|
const usage = tokenCounter.countSessionTokens(state.session, systemPrompt);
|
|
7766
|
-
const
|
|
7979
|
+
const agentTools = state.agent?.getTools() ?? [];
|
|
7980
|
+
const agentToolsTokens = tokenCounter.countToolSchemaTokens(agentTools);
|
|
7981
|
+
const totalWithTools = usage.totalTokens + agentToolsTokens;
|
|
7767
7982
|
const usagePercent = totalWithTools / contextWindow * 100;
|
|
7768
7983
|
const BAR_WIDTH = 40;
|
|
7769
7984
|
const filledWidth = Math.min(Math.round(usagePercent / 100 * BAR_WIDTH), BAR_WIDTH);
|
|
@@ -7780,10 +7995,14 @@ Multi-line Input:
|
|
|
7780
7995
|
console.log(` Agent Directory: ${agentDirectoryTokens.toLocaleString()} tokens (${agentCount} agents)`);
|
|
7781
7996
|
}
|
|
7782
7997
|
if (mcpTools.length > 0) {
|
|
7783
|
-
console.log("\nMCP Tools:");
|
|
7784
|
-
console.log(`
|
|
7998
|
+
console.log("\nMCP Tools (deferred):");
|
|
7999
|
+
console.log(` Schemas: load on demand via tool_search (${mcpTools.length} tools available)`);
|
|
7785
8000
|
for (const { serverName, count } of mcpToolCount) console.log(` ${serverName}: ${count} tools`);
|
|
7786
8001
|
}
|
|
8002
|
+
if (agentTools.length > 0) {
|
|
8003
|
+
console.log("\nLoaded Tool Schemas:");
|
|
8004
|
+
console.log(` Schemas: ${agentToolsTokens.toLocaleString()} tokens (${agentTools.length} tools active)`);
|
|
8005
|
+
}
|
|
7787
8006
|
console.log("\nConversation:");
|
|
7788
8007
|
console.log(` Messages: ${usage.messageTokens.toLocaleString()} tokens (${state.session.messages.length} messages)`);
|
|
7789
8008
|
if (usagePercent >= 80) {
|
|
@@ -8154,7 +8373,7 @@ Multi-line Input:
|
|
|
8154
8373
|
break;
|
|
8155
8374
|
}
|
|
8156
8375
|
case "terminal-setup": {
|
|
8157
|
-
const { runTerminalSetup } = await import("./terminalSetup-
|
|
8376
|
+
const { runTerminalSetup } = await import("./terminalSetup-BbJt04ZG.mjs");
|
|
8158
8377
|
await runTerminalSetup();
|
|
8159
8378
|
break;
|
|
8160
8379
|
}
|
|
@@ -8319,14 +8538,13 @@ Multi-line Input:
|
|
|
8319
8538
|
const newToolNames = newFeatureRegistry.getAllToolNames();
|
|
8320
8539
|
if (newToolNames.length > 0) registerFeatureModuleTools(newToolNames);
|
|
8321
8540
|
if (state.wsManager && newFeatureRegistry.hasModules) newFeatureRegistry.registerAllWsHandlers(state.wsManager);
|
|
8322
|
-
const agentContext = state.agent.context;
|
|
8323
8541
|
const oldFeatureToolNames = new Set(state.featureRegistry?.getAllToolNames() ?? []);
|
|
8324
|
-
const baseTools =
|
|
8542
|
+
const baseTools = state.agent.getTools().filter((t) => !oldFeatureToolNames.has(t.toolSchema.name));
|
|
8325
8543
|
const newFeatureTools = newFeatureRegistry.getAllTools();
|
|
8326
|
-
|
|
8544
|
+
state.agent.setTools([...baseTools, ...newFeatureTools]);
|
|
8327
8545
|
const newFeaturePrompts = newFeatureRegistry.getSystemPromptSections();
|
|
8328
8546
|
const planFilePathForRebuild = useCliStore.getState().interactionMode === "plan" && state.session ? getPlanModeFilePath(state.session.id) : void 0;
|
|
8329
|
-
|
|
8547
|
+
state.agent.setSystemPrompt(buildSystemPrompt(updatedConfig.preferences.promptVariant ?? "current", {
|
|
8330
8548
|
contextContent: state.contextContent,
|
|
8331
8549
|
agentStore: state.agentStore || void 0,
|
|
8332
8550
|
customCommands: state.customCommandStore.getAllCommands(),
|
|
@@ -8334,8 +8552,9 @@ Multi-line Input:
|
|
|
8334
8552
|
enableDynamicAgentCreation: updatedConfig.preferences.enableDynamicAgentCreation === true,
|
|
8335
8553
|
additionalDirectories: state.additionalDirectories,
|
|
8336
8554
|
featureModulePrompts: newFeaturePrompts || void 0,
|
|
8337
|
-
planModeFilePath: planFilePathForRebuild
|
|
8338
|
-
|
|
8555
|
+
planModeFilePath: planFilePathForRebuild,
|
|
8556
|
+
deferredToolNames: deferredToolRegistry.getDirectoryNames()
|
|
8557
|
+
}));
|
|
8339
8558
|
const moduleNames = newFeatureRegistry.getModuleNames();
|
|
8340
8559
|
if (moduleNames.length > 0) console.error(`\n\x1b[36m🏰 Feature modules hot-reloaded: ${moduleNames.join(", ")}\x1b[0m`);
|
|
8341
8560
|
else console.error(`\n\x1b[36m🏰 Feature modules disabled\x1b[0m`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { realpathSync } from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
//#region ../../b4m-core/services/dist/pathValidation-
|
|
4
|
+
//#region ../../b4m-core/services/dist/pathValidation-D8tjkQXE.mjs
|
|
5
5
|
/**
|
|
6
6
|
* Resolves a path to its canonical form, following symlinks.
|
|
7
7
|
* If the path doesn't exist (e.g., file being created), resolves the
|