@bike4mind/cli 0.9.1 → 0.9.2
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/{BubblewrapRuntime-BHbtqvLx.mjs → BubblewrapRuntime-CUD3bsgG.mjs} +1 -1
- package/dist/ProxyManager-DIAAw902.mjs +3 -0
- package/dist/{SandboxOrchestrator-CHZgSR3P.mjs → SandboxOrchestrator-C4oDqltp.mjs} +1 -1
- package/dist/{SandboxRuntimeAdapter-C1B4t20N.mjs → SandboxRuntimeAdapter-D1RUReNL.mjs} +2 -2
- package/dist/{SandboxRuntimeAdapter-D7UAG13n.mjs → SandboxRuntimeAdapter-DXa3nFOw.mjs} +1 -1
- package/dist/{SeatbeltRuntime-D4m0VOcD.mjs → SeatbeltRuntime-CTElMR9Q.mjs} +1 -1
- package/dist/commands/doctorCommand.mjs +13 -1
- package/dist/commands/headlessCommand.mjs +4 -4
- package/dist/commands/updateCommand.mjs +33 -15
- package/dist/{grepSearch-DMuEcUSq-D3RsGLCg.mjs → grepSearch-BxucZWO8-lPRv6R6F.mjs} +15 -26
- package/dist/index.mjs +72 -64
- package/dist/ripgrepCheck-DIu4apVE.mjs +39 -0
- package/dist/{tools-ICW0xW8W.mjs → tools-AWSBVqG5.mjs} +241 -18
- package/dist/{updateChecker-Dproz7j-.mjs → updateChecker-Bml_XTCM.mjs} +1 -1
- package/package.json +6 -6
- package/dist/ProxyManager-kiOD1X8-.mjs +0 -3
- /package/dist/{ImageStore-DaKT_Ew8.mjs → ImageStore-BFp_d12J.mjs} +0 -0
- /package/dist/{ProxyManager-Dl2nFk-A.mjs → ProxyManager-BsCoxpns.mjs} +0 -0
- /package/dist/{SandboxOrchestrator-BEW3rqYi.mjs → SandboxOrchestrator-B4GcZdBc.mjs} +0 -0
- /package/dist/{StderrViolationParser-D0afQ3-1.mjs → StderrViolationParser-BFP4bo7I.mjs} +0 -0
- /package/dist/{ViolationLogStore-CZl35HcA.mjs → ViolationLogStore-Dp6HF0nz.mjs} +0 -0
- /package/dist/{bashExecute-pYljpfPn-Bsh-jb3S.mjs → bashExecute-pYljpfPn-BZXHMQEl.mjs} +0 -0
- /package/dist/{createFile-C1JoeuYh-LvIRJtxM.mjs → createFile-C1JoeuYh-metInFKd.mjs} +0 -0
- /package/dist/{deleteFile-BTberNGj-BpBvrcoC.mjs → deleteFile-BTberNGj-CW922hRM.mjs} +0 -0
- /package/dist/{globFiles-Bez8QCbS-DyZsKEJB.mjs → globFiles-Bez8QCbS-DZb6McbJ.mjs} +0 -0
- /package/dist/{terminalSetup-rmr1P8KF.mjs → terminalSetup-DxloCowq.mjs} +0 -0
- /package/dist/{treeSitterEngine-BFTHnDwH.mjs → treeSitterEngine-Cw2LbVZT.mjs} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as isBinaryAvailable, r as expandPath } from "./SandboxRuntimeAdapter-
|
|
2
|
+
import { i as isBinaryAvailable, r as expandPath } from "./SandboxRuntimeAdapter-D1RUReNL.mjs";
|
|
3
3
|
import os from "os";
|
|
4
4
|
//#region src/sandbox/runtime/BubblewrapRuntime.ts
|
|
5
5
|
/**
|
|
@@ -42,12 +42,12 @@ async function createSandboxRuntime() {
|
|
|
42
42
|
const platform = detectPlatform();
|
|
43
43
|
if (!platform) return null;
|
|
44
44
|
if (platform === "darwin") {
|
|
45
|
-
const { SeatbeltRuntime } = await import("./SeatbeltRuntime-
|
|
45
|
+
const { SeatbeltRuntime } = await import("./SeatbeltRuntime-CTElMR9Q.mjs");
|
|
46
46
|
const runtime = new SeatbeltRuntime();
|
|
47
47
|
return runtime.isAvailable() ? runtime : null;
|
|
48
48
|
}
|
|
49
49
|
if (platform === "linux") {
|
|
50
|
-
const { BubblewrapRuntime } = await import("./BubblewrapRuntime-
|
|
50
|
+
const { BubblewrapRuntime } = await import("./BubblewrapRuntime-CUD3bsgG.mjs");
|
|
51
51
|
const runtime = new BubblewrapRuntime();
|
|
52
52
|
return runtime.isAvailable() ? runtime : null;
|
|
53
53
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as isBinaryAvailable, n as detectPlatform, r as expandPath, t as createSandboxRuntime } from "./SandboxRuntimeAdapter-
|
|
2
|
+
import { i as isBinaryAvailable, n as detectPlatform, r as expandPath, t as createSandboxRuntime } from "./SandboxRuntimeAdapter-D1RUReNL.mjs";
|
|
3
3
|
export { createSandboxRuntime, detectPlatform, expandPath, isBinaryAvailable };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as isBinaryAvailable, r as expandPath } from "./SandboxRuntimeAdapter-
|
|
2
|
+
import { i as isBinaryAvailable, r as expandPath } from "./SandboxRuntimeAdapter-D1RUReNL.mjs";
|
|
3
3
|
import { mkdtempSync, writeFileSync } from "fs";
|
|
4
4
|
import os from "os";
|
|
5
5
|
import path from "path";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as version, n as compareSemver, r as fetchLatestVersion } from "../updateChecker-
|
|
2
|
+
import { a as version, n as compareSemver, r as fetchLatestVersion } from "../updateChecker-Bml_XTCM.mjs";
|
|
3
|
+
import { t as checkRipgrep } from "../ripgrepCheck-DIu4apVE.mjs";
|
|
3
4
|
import { execSync } from "child_process";
|
|
4
5
|
import { constants, existsSync, promises } from "fs";
|
|
5
6
|
import { homedir } from "os";
|
|
@@ -74,6 +75,17 @@ async function handleDoctorCommand() {
|
|
|
74
75
|
message: "Could not determine npm prefix"
|
|
75
76
|
});
|
|
76
77
|
}
|
|
78
|
+
const rg = await checkRipgrep();
|
|
79
|
+
if (rg.available) results.push({
|
|
80
|
+
name: "ripgrep (grep_search)",
|
|
81
|
+
status: "pass",
|
|
82
|
+
message: rg.path
|
|
83
|
+
});
|
|
84
|
+
else results.push({
|
|
85
|
+
name: "ripgrep (grep_search)",
|
|
86
|
+
status: "warn",
|
|
87
|
+
message: `${rg.error ?? "not found"} — run: b4m update`
|
|
88
|
+
});
|
|
77
89
|
const configFile = path.join(homedir(), ".bike4mind", "config.json");
|
|
78
90
|
if (existsSync(configFile)) results.push({
|
|
79
91
|
name: "Config file",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as PermissionManager, I as generateCliTools, M as loadContextFiles, N as getApiUrl, O as McpManager, Q as CheckpointStore, S as ApiClient, T as FallbackLlmBackend, W as setWebSocketToolExecutor, X as ReActAgent, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createAgentDelegateTool, b as createSkillTool, d as createFindDefinitionTool, et as SessionStore, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, m as createCoordinateTaskTool, p as createWriteTodosTool, q as buildSystemPrompt, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, y as SubagentOrchestrator } from "../tools-
|
|
2
|
+
import { C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as PermissionManager, I as generateCliTools, M as loadContextFiles, N as getApiUrl, O as McpManager, Q as CheckpointStore, S as ApiClient, T as FallbackLlmBackend, W as setWebSocketToolExecutor, X as ReActAgent, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createAgentDelegateTool, b as createSkillTool, d as createFindDefinitionTool, et as SessionStore, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, m as createCoordinateTaskTool, p as createWriteTodosTool, q as buildSystemPrompt, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, y as SubagentOrchestrator } from "../tools-AWSBVqG5.mjs";
|
|
3
3
|
import { n as logger, t as ConfigStore } from "../ConfigStore-CAKSUXCi.mjs";
|
|
4
4
|
import { t as DEFAULT_SANDBOX_CONFIG } from "../types-DBEjF9YS.mjs";
|
|
5
|
-
import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-
|
|
6
|
-
import { t as SandboxOrchestrator } from "../SandboxOrchestrator-
|
|
7
|
-
import { t as ProxyManager } from "../ProxyManager-
|
|
5
|
+
import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-D1RUReNL.mjs";
|
|
6
|
+
import { t as SandboxOrchestrator } from "../SandboxOrchestrator-B4GcZdBc.mjs";
|
|
7
|
+
import { t as ProxyManager } from "../ProxyManager-BsCoxpns.mjs";
|
|
8
8
|
import { randomBytes } from "crypto";
|
|
9
9
|
import { v4 } from "uuid";
|
|
10
10
|
//#region src/commands/headlessCommand.ts
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as version, i as forceCheckForUpdate } from "../updateChecker-
|
|
2
|
+
import { a as version, i as forceCheckForUpdate } from "../updateChecker-Bml_XTCM.mjs";
|
|
3
|
+
import { t as checkRipgrep } from "../ripgrepCheck-DIu4apVE.mjs";
|
|
3
4
|
import { execSync } from "child_process";
|
|
4
5
|
//#region src/commands/updateCommand.ts
|
|
5
6
|
/**
|
|
@@ -7,6 +8,22 @@ import { execSync } from "child_process";
|
|
|
7
8
|
* Checks for and installs CLI updates.
|
|
8
9
|
* Runs outside the interactive CLI session.
|
|
9
10
|
*/
|
|
11
|
+
const INSTALL_CMD = "npm install -g @bike4mind/cli@latest";
|
|
12
|
+
function runGlobalInstall() {
|
|
13
|
+
try {
|
|
14
|
+
execSync(INSTALL_CMD, {
|
|
15
|
+
stdio: "inherit",
|
|
16
|
+
timeout: 12e4
|
|
17
|
+
});
|
|
18
|
+
return true;
|
|
19
|
+
} catch {
|
|
20
|
+
console.error("\nInstall failed. Try running manually:");
|
|
21
|
+
console.error(` ${INSTALL_CMD}`);
|
|
22
|
+
console.error("\nIf you get permission errors, try:");
|
|
23
|
+
console.error(` sudo ${INSTALL_CMD}`);
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
10
27
|
async function handleUpdateCommand() {
|
|
11
28
|
const currentVersion = version;
|
|
12
29
|
console.log(`Current version: v${currentVersion}`);
|
|
@@ -16,25 +33,26 @@ async function handleUpdateCommand() {
|
|
|
16
33
|
console.error("Failed to check for updates. Check your internet connection.");
|
|
17
34
|
process.exit(1);
|
|
18
35
|
}
|
|
19
|
-
|
|
36
|
+
const rgBefore = await checkRipgrep();
|
|
37
|
+
const needsRepair = !rgBefore.available;
|
|
38
|
+
if (!result.updateAvailable && !needsRepair) {
|
|
20
39
|
console.log(`Already on the latest version (v${currentVersion}).`);
|
|
21
40
|
return;
|
|
22
41
|
}
|
|
23
|
-
console.log(`Update available: v${currentVersion} → v${result.latestVersion}
|
|
24
|
-
console.log("
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
console.
|
|
31
|
-
|
|
32
|
-
console.error(
|
|
33
|
-
console.error(" npm install -g @bike4mind/cli@latest");
|
|
34
|
-
console.error("\nIf you get permission errors, try:");
|
|
35
|
-
console.error(" sudo npm install -g @bike4mind/cli@latest");
|
|
42
|
+
if (result.updateAvailable) console.log(`Update available: v${currentVersion} → v${result.latestVersion}`);
|
|
43
|
+
if (needsRepair) console.log(`Repairing missing ripgrep binary (${rgBefore.error ?? "unknown reason"})`);
|
|
44
|
+
console.log("\nInstalling...\n");
|
|
45
|
+
if (!runGlobalInstall()) process.exit(1);
|
|
46
|
+
const rgAfter = await checkRipgrep();
|
|
47
|
+
if (!rgAfter.available) {
|
|
48
|
+
console.error("\nWarning: ripgrep is still unavailable after install.");
|
|
49
|
+
console.error(` ${rgAfter.error ?? "unknown reason"}`);
|
|
50
|
+
console.error("The grep_search tool will not work. Try a forced reinstall:");
|
|
51
|
+
console.error(` ${INSTALL_CMD} --force`);
|
|
36
52
|
process.exit(1);
|
|
37
53
|
}
|
|
54
|
+
if (result.updateAvailable) console.log(`\nSuccessfully updated to v${result.latestVersion}.`);
|
|
55
|
+
else console.log("\nRipgrep restored.");
|
|
38
56
|
}
|
|
39
57
|
//#endregion
|
|
40
58
|
export { handleUpdateCommand };
|
|
@@ -1,42 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as isPathAllowed } from "./pathValidation-CIytuhr3-Dt5dntLx.mjs";
|
|
3
|
-
import { execFile
|
|
3
|
+
import { execFile } from "child_process";
|
|
4
4
|
import { existsSync } from "fs";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { stat } from "fs/promises";
|
|
7
7
|
import { promisify } from "util";
|
|
8
|
-
|
|
9
|
-
//#region ../../b4m-core/services/dist/grepSearch-DMuEcUSq.mjs
|
|
8
|
+
//#region ../../b4m-core/services/dist/grepSearch-BxucZWO8.mjs
|
|
10
9
|
const execFileAsync = promisify(execFile);
|
|
11
|
-
const require = createRequire(import.meta.url);
|
|
12
10
|
/** Cached ripgrep binary path after first resolution */
|
|
13
11
|
let cachedRgPath = null;
|
|
14
12
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* Resolve ripgrep binary path via the package's exported `rgPath`.
|
|
14
|
+
* `@vscode/ripgrep` is an optional dependency, so we load it lazily; in 1.18+
|
|
15
|
+
* the binary lives in a platform-specific sibling package and is resolved by
|
|
16
|
+
* the package itself — we just have to ask for it.
|
|
18
17
|
*/
|
|
19
|
-
function getRipgrepPath() {
|
|
18
|
+
async function getRipgrepPath() {
|
|
20
19
|
if (cachedRgPath) return cachedRgPath;
|
|
20
|
+
let rgPath;
|
|
21
21
|
try {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (!existsSync(rgBinary)) {
|
|
26
|
-
const postinstallScript = path.join(ripgrepDir, "..", "lib", "postinstall.js");
|
|
27
|
-
if (existsSync(postinstallScript)) execFileSync(process.execPath, [postinstallScript], {
|
|
28
|
-
cwd: path.join(ripgrepDir, ".."),
|
|
29
|
-
stdio: "pipe",
|
|
30
|
-
timeout: 3e4
|
|
31
|
-
});
|
|
32
|
-
if (!existsSync(rgBinary)) throw new Error(`ripgrep binary not found at ${rgBinary}. The postinstall download may have failed. Try running: cd ${path.join(ripgrepDir, "..")} && node lib/postinstall.js`);
|
|
33
|
-
}
|
|
34
|
-
cachedRgPath = rgBinary;
|
|
35
|
-
return rgBinary;
|
|
36
|
-
} catch (error) {
|
|
37
|
-
if (error instanceof Error && error.message.includes("ripgrep binary not found")) throw error;
|
|
38
|
-
throw new Error("ripgrep is not available. Please install @vscode/ripgrep: pnpm add @vscode/ripgrep --filter @bike4mind/services");
|
|
22
|
+
({rgPath} = await import("@vscode/ripgrep"));
|
|
23
|
+
} catch {
|
|
24
|
+
throw new Error("ripgrep is not available. Install the optional dependency: pnpm add @vscode/ripgrep --filter @bike4mind/services");
|
|
39
25
|
}
|
|
26
|
+
if (!rgPath || !existsSync(rgPath)) throw new Error(`ripgrep binary not found at ${rgPath ?? "<unresolved>"}. Ensure @vscode/ripgrep platform optional dependencies are installed for ${process.platform}-${process.arch}.`);
|
|
27
|
+
cachedRgPath = rgPath;
|
|
28
|
+
return rgPath;
|
|
40
29
|
}
|
|
41
30
|
/**
|
|
42
31
|
* Converts a glob pattern to ripgrep glob patterns
|
|
@@ -62,7 +51,7 @@ async function searchFiles(params, allowedDirectories) {
|
|
|
62
51
|
if (error.code === "ENOENT") throw new Error(`Path does not exist: ${dir_path}`);
|
|
63
52
|
throw error;
|
|
64
53
|
}
|
|
65
|
-
const rgPath = getRipgrepPath();
|
|
54
|
+
const rgPath = await getRipgrepPath();
|
|
66
55
|
const rgArgs = [
|
|
67
56
|
"--json",
|
|
68
57
|
"--max-count",
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-DLduYYGR.mjs";
|
|
3
|
-
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 { $ 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-AWSBVqG5.mjs";
|
|
4
4
|
import { Nt as validateJupyterKernelName, Pt as validateNotebookPath$1, g as ChatModels, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-CAKSUXCi.mjs";
|
|
5
|
-
import { a as version, t as checkForUpdate } from "./updateChecker-
|
|
5
|
+
import { a as version, t as checkForUpdate } from "./updateChecker-Bml_XTCM.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";
|
|
@@ -2078,8 +2078,7 @@ const MessageItem = React.memo(function MessageItem({ message, showThoughts = tr
|
|
|
2078
2078
|
const paddedUserPromptText = userPromptText.length >= terminalCols ? userPromptText : userPromptText.padEnd(terminalCols);
|
|
2079
2079
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, isUser && message.content && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, {
|
|
2080
2080
|
backgroundColor: "whiteBright",
|
|
2081
|
-
color: "black"
|
|
2082
|
-
wrap: "truncate-end"
|
|
2081
|
+
color: "black"
|
|
2083
2082
|
}, paddedUserPromptText)), !isUser && message.metadata?.steps && message.metadata.steps.filter((s) => showThoughts && s.type === "thought" || s.type === "action").length > 0 && /* @__PURE__ */ React.createElement(Box, {
|
|
2084
2083
|
paddingLeft: 2,
|
|
2085
2084
|
flexDirection: "column",
|
|
@@ -5442,6 +5441,67 @@ function summarizeUserQuestion(payload) {
|
|
|
5442
5441
|
const first = payload.questions?.[0]?.question;
|
|
5443
5442
|
return first ? first.slice(0, 240) : void 0;
|
|
5444
5443
|
}
|
|
5444
|
+
/**
|
|
5445
|
+
* Render the B4M ASCII banner with an optional startup log column to the right.
|
|
5446
|
+
* Used on startup and after /clear so the user always sees the banner at the
|
|
5447
|
+
* top of a fresh session.
|
|
5448
|
+
*/
|
|
5449
|
+
function renderBanner(startupLog = []) {
|
|
5450
|
+
const bannerLines = [
|
|
5451
|
+
{
|
|
5452
|
+
text: "██████╗ ██╗ ██╗███╗ ███╗",
|
|
5453
|
+
ansi: "\x1B[36m\x1B[1m"
|
|
5454
|
+
},
|
|
5455
|
+
{
|
|
5456
|
+
text: "██╔══██╗██║ ██║████╗ ████║",
|
|
5457
|
+
ansi: "\x1B[36m\x1B[1m"
|
|
5458
|
+
},
|
|
5459
|
+
{
|
|
5460
|
+
text: "██████╔╝███████║██╔████╔██║",
|
|
5461
|
+
ansi: "\x1B[36m\x1B[1m"
|
|
5462
|
+
},
|
|
5463
|
+
{
|
|
5464
|
+
text: "██╔══██╗╚════██║██║╚██╔╝██║",
|
|
5465
|
+
ansi: "\x1B[36m\x1B[1m"
|
|
5466
|
+
},
|
|
5467
|
+
{
|
|
5468
|
+
text: "██████╔╝ ██║██║ ╚═╝ ██║",
|
|
5469
|
+
ansi: "\x1B[36m\x1B[1m"
|
|
5470
|
+
},
|
|
5471
|
+
{
|
|
5472
|
+
text: "╚═════╝ ╚═╝╚═╝ ╚═╝",
|
|
5473
|
+
ansi: "\x1B[36m\x1B[1m"
|
|
5474
|
+
},
|
|
5475
|
+
{
|
|
5476
|
+
text: "",
|
|
5477
|
+
ansi: ""
|
|
5478
|
+
},
|
|
5479
|
+
{
|
|
5480
|
+
text: `v${version} - AI-Powered CLI`,
|
|
5481
|
+
ansi: "\x1B[2m"
|
|
5482
|
+
},
|
|
5483
|
+
{
|
|
5484
|
+
text: "/help for more information",
|
|
5485
|
+
ansi: "\x1B[2m"
|
|
5486
|
+
}
|
|
5487
|
+
];
|
|
5488
|
+
const bannerWidth = 30;
|
|
5489
|
+
const rightColWidth = (process.stdout.columns || 80) - bannerWidth - 2;
|
|
5490
|
+
const truncate = (str, max) => {
|
|
5491
|
+
if (str.length > max) return str.slice(0, max - 1) + "…";
|
|
5492
|
+
return str;
|
|
5493
|
+
};
|
|
5494
|
+
const totalLines = Math.max(bannerLines.length, startupLog.length);
|
|
5495
|
+
for (let i = 0; i < totalLines; i++) {
|
|
5496
|
+
const banner = bannerLines[i];
|
|
5497
|
+
const leftText = banner?.text || "";
|
|
5498
|
+
const leftAnsi = banner?.ansi || "";
|
|
5499
|
+
const right = startupLog[i] || "";
|
|
5500
|
+
const coloredLeft = leftText ? `${leftAnsi}${leftText}\x1b[0m` : "";
|
|
5501
|
+
const gap = " ".repeat(bannerWidth - leftText.length + 2);
|
|
5502
|
+
console.log(coloredLeft + gap + truncate(right, rightColWidth));
|
|
5503
|
+
}
|
|
5504
|
+
}
|
|
5445
5505
|
let exitTimestamp = null;
|
|
5446
5506
|
let exitInProgress = false;
|
|
5447
5507
|
const EXIT_TIMEOUT_MS = 2e3;
|
|
@@ -5794,11 +5854,11 @@ function CliApp() {
|
|
|
5794
5854
|
};
|
|
5795
5855
|
const permissionManager = new PermissionManager(config.trustedTools || [], void 0, config.tools.disabled || []);
|
|
5796
5856
|
const [{ createSandboxRuntime }, { SandboxOrchestrator }, { DEFAULT_SANDBOX_CONFIG }, { ProxyManager }, { ViolationLogStore }] = await Promise.all([
|
|
5797
|
-
import("./SandboxRuntimeAdapter-
|
|
5798
|
-
import("./SandboxOrchestrator-
|
|
5857
|
+
import("./SandboxRuntimeAdapter-DXa3nFOw.mjs"),
|
|
5858
|
+
import("./SandboxOrchestrator-C4oDqltp.mjs"),
|
|
5799
5859
|
import("./types-DK3P88Px.mjs"),
|
|
5800
|
-
import("./ProxyManager-
|
|
5801
|
-
import("./ViolationLogStore-
|
|
5860
|
+
import("./ProxyManager-DIAAw902.mjs"),
|
|
5861
|
+
import("./ViolationLogStore-Dp6HF0nz.mjs")
|
|
5802
5862
|
]);
|
|
5803
5863
|
const sandboxConfig = config.sandbox ?? DEFAULT_SANDBOX_CONFIG;
|
|
5804
5864
|
const checkpointStore = new CheckpointStore(state.configStore.getProjectConfigDir() || process.cwd());
|
|
@@ -6170,60 +6230,7 @@ function CliApp() {
|
|
|
6170
6230
|
featureRegistry
|
|
6171
6231
|
}));
|
|
6172
6232
|
setStoreSession(newSession);
|
|
6173
|
-
|
|
6174
|
-
{
|
|
6175
|
-
text: "██████╗ ██╗ ██╗███╗ ███╗",
|
|
6176
|
-
ansi: "\x1B[36m\x1B[1m"
|
|
6177
|
-
},
|
|
6178
|
-
{
|
|
6179
|
-
text: "██╔══██╗██║ ██║████╗ ████║",
|
|
6180
|
-
ansi: "\x1B[36m\x1B[1m"
|
|
6181
|
-
},
|
|
6182
|
-
{
|
|
6183
|
-
text: "██████╔╝███████║██╔████╔██║",
|
|
6184
|
-
ansi: "\x1B[36m\x1B[1m"
|
|
6185
|
-
},
|
|
6186
|
-
{
|
|
6187
|
-
text: "██╔══██╗╚════██║██║╚██╔╝██║",
|
|
6188
|
-
ansi: "\x1B[36m\x1B[1m"
|
|
6189
|
-
},
|
|
6190
|
-
{
|
|
6191
|
-
text: "██████╔╝ ██║██║ ╚═╝ ██║",
|
|
6192
|
-
ansi: "\x1B[36m\x1B[1m"
|
|
6193
|
-
},
|
|
6194
|
-
{
|
|
6195
|
-
text: "╚═════╝ ╚═╝╚═╝ ╚═╝",
|
|
6196
|
-
ansi: "\x1B[36m\x1B[1m"
|
|
6197
|
-
},
|
|
6198
|
-
{
|
|
6199
|
-
text: "",
|
|
6200
|
-
ansi: ""
|
|
6201
|
-
},
|
|
6202
|
-
{
|
|
6203
|
-
text: `v${version} - AI-Powered CLI`,
|
|
6204
|
-
ansi: "\x1B[2m"
|
|
6205
|
-
},
|
|
6206
|
-
{
|
|
6207
|
-
text: "/help for more information",
|
|
6208
|
-
ansi: "\x1B[2m"
|
|
6209
|
-
}
|
|
6210
|
-
];
|
|
6211
|
-
const bannerWidth = 30;
|
|
6212
|
-
const rightColWidth = (process.stdout.columns || 80) - bannerWidth - 2;
|
|
6213
|
-
const truncate = (str, max) => {
|
|
6214
|
-
if (str.length > max) return str.slice(0, max - 1) + "…";
|
|
6215
|
-
return str;
|
|
6216
|
-
};
|
|
6217
|
-
const totalLines = Math.max(bannerLines.length, startupLog.length);
|
|
6218
|
-
for (let i = 0; i < totalLines; i++) {
|
|
6219
|
-
const banner = bannerLines[i];
|
|
6220
|
-
const leftText = banner?.text || "";
|
|
6221
|
-
const leftAnsi = banner?.ansi || "";
|
|
6222
|
-
const right = startupLog[i] || "";
|
|
6223
|
-
const coloredLeft = leftText ? `${leftAnsi}${leftText}\x1b[0m` : "";
|
|
6224
|
-
const gap = " ".repeat(bannerWidth - leftText.length + 2);
|
|
6225
|
-
console.log(coloredLeft + gap + truncate(right, rightColWidth));
|
|
6226
|
-
}
|
|
6233
|
+
renderBanner(startupLog);
|
|
6227
6234
|
setIsInitialized(true);
|
|
6228
6235
|
console.log("");
|
|
6229
6236
|
} catch (error) {
|
|
@@ -6868,7 +6875,7 @@ function CliApp() {
|
|
|
6868
6875
|
let imageStore = state.imageStore;
|
|
6869
6876
|
if (!imageStore) {
|
|
6870
6877
|
if (!imageStoreInitPromise.current) imageStoreInitPromise.current = (async () => {
|
|
6871
|
-
const { ImageStore: ImageStoreClass } = await import("./ImageStore-
|
|
6878
|
+
const { ImageStore: ImageStoreClass } = await import("./ImageStore-BFp_d12J.mjs");
|
|
6872
6879
|
const newImageStore = new ImageStoreClass();
|
|
6873
6880
|
setState((prev) => ({
|
|
6874
6881
|
...prev,
|
|
@@ -7475,6 +7482,7 @@ Multi-line Input:
|
|
|
7475
7482
|
case "clear":
|
|
7476
7483
|
case "new": {
|
|
7477
7484
|
console.clear();
|
|
7485
|
+
renderBanner();
|
|
7478
7486
|
const model = state.session?.model || state.config?.defaultModel || ChatModels.CLAUDE_4_5_SONNET;
|
|
7479
7487
|
const newSession = {
|
|
7480
7488
|
id: v4(),
|
|
@@ -8146,7 +8154,7 @@ Multi-line Input:
|
|
|
8146
8154
|
break;
|
|
8147
8155
|
}
|
|
8148
8156
|
case "terminal-setup": {
|
|
8149
|
-
const { runTerminalSetup } = await import("./terminalSetup-
|
|
8157
|
+
const { runTerminalSetup } = await import("./terminalSetup-DxloCowq.mjs");
|
|
8150
8158
|
await runTerminalSetup();
|
|
8151
8159
|
break;
|
|
8152
8160
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { access, constants } from "fs/promises";
|
|
3
|
+
//#region src/utils/ripgrepCheck.ts
|
|
4
|
+
/**
|
|
5
|
+
* Probe `@vscode/ripgrep` the same way `grep_search` does: dynamic-import the
|
|
6
|
+
* package, take its exported `rgPath`, and verify it's executable on disk.
|
|
7
|
+
* The package is an optional dependency, so any failure mode (missing package,
|
|
8
|
+
* missing platform sibling, missing binary) is reported as `available: false`.
|
|
9
|
+
*/
|
|
10
|
+
async function checkRipgrep() {
|
|
11
|
+
let rgPath;
|
|
12
|
+
try {
|
|
13
|
+
({rgPath} = await import("@vscode/ripgrep"));
|
|
14
|
+
} catch (err) {
|
|
15
|
+
return {
|
|
16
|
+
available: false,
|
|
17
|
+
error: err instanceof Error ? err.message : String(err)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (!rgPath) return {
|
|
21
|
+
available: false,
|
|
22
|
+
error: "@vscode/ripgrep did not export rgPath"
|
|
23
|
+
};
|
|
24
|
+
try {
|
|
25
|
+
await access(rgPath, constants.X_OK);
|
|
26
|
+
return {
|
|
27
|
+
available: true,
|
|
28
|
+
path: rgPath
|
|
29
|
+
};
|
|
30
|
+
} catch {
|
|
31
|
+
return {
|
|
32
|
+
available: false,
|
|
33
|
+
path: rgPath,
|
|
34
|
+
error: `binary not executable at ${rgPath}`
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { checkRipgrep as t };
|
|
@@ -83,7 +83,6 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
83
83
|
import { fileURLToPath } from "url";
|
|
84
84
|
import WsWebSocket from "ws";
|
|
85
85
|
import { createParser } from "eventsource-parser";
|
|
86
|
-
import { createRequire } from "module";
|
|
87
86
|
//#region src/utils/fileSearch.ts
|
|
88
87
|
/**
|
|
89
88
|
* Load gitignore rules from project root
|
|
@@ -2286,6 +2285,31 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
|
|
|
2286
2285
|
return this.iterations;
|
|
2287
2286
|
}
|
|
2288
2287
|
/**
|
|
2288
|
+
* Surgically replace the observation content of the most recent tool_result
|
|
2289
|
+
* message matching `toolCallId`. Used to inject a Lambda-dispatched
|
|
2290
|
+
* subagent's terminal answer into the parent's message history without
|
|
2291
|
+
* appending a new message (Anthropic rejects consecutive user-role messages,
|
|
2292
|
+
* so we replace the placeholder observation in place).
|
|
2293
|
+
*
|
|
2294
|
+
* Throws if the underlying backend doesn't support this surgery or if no
|
|
2295
|
+
* matching message is found.
|
|
2296
|
+
*/
|
|
2297
|
+
replaceLastToolResultObservation(toolCallId, newObservation) {
|
|
2298
|
+
if (!this.context.llm.replaceLastToolResultObservation) throw new Error(`ReActAgent.replaceLastToolResultObservation: backend (${this.context.llm.currentModel}) does not implement replaceLastToolResultObservation — cannot resume after subagent handoff`);
|
|
2299
|
+
this.context.llm.replaceLastToolResultObservation(this.messages, toolCallId, newObservation);
|
|
2300
|
+
}
|
|
2301
|
+
/**
|
|
2302
|
+
* Locate the LLM-assigned id of the most recent tool call with the given name.
|
|
2303
|
+
* Delegates to the backend so each provider's message shape (Anthropic
|
|
2304
|
+
* content-block `tool_use` vs OpenAI `assistant.tool_calls`) is handled
|
|
2305
|
+
* correctly. Returns `undefined` if the backend doesn't implement the lookup
|
|
2306
|
+
* or no matching call exists.
|
|
2307
|
+
*/
|
|
2308
|
+
getLatestToolCallId(toolName) {
|
|
2309
|
+
if (!this.context.llm.getLatestToolCallId) return void 0;
|
|
2310
|
+
return this.context.llm.getLatestToolCallId(this.messages, toolName);
|
|
2311
|
+
}
|
|
2312
|
+
/**
|
|
2289
2313
|
* Serialize the agent's current execution state for persistence.
|
|
2290
2314
|
*
|
|
2291
2315
|
* Call this after each iteration to create a durable checkpoint that can
|
|
@@ -2884,6 +2908,153 @@ function trimConversationHistory(messages, maxIterations, protectedPrefixCount)
|
|
|
2884
2908
|
const keepFrom = dynamicStart + nudgeIndices[nudgeIndices.length - maxIterations];
|
|
2885
2909
|
messages.splice(dynamicStart, keepFrom - dynamicStart);
|
|
2886
2910
|
}
|
|
2911
|
+
String.raw`
|
|
2912
|
+
const { parentPort } = require('node:worker_threads');
|
|
2913
|
+
const vm = require('node:vm');
|
|
2914
|
+
|
|
2915
|
+
const STDOUT_HEAD_BYTES = ${5e3};
|
|
2916
|
+
const STDOUT_TAIL_BYTES = ${2e3};
|
|
2917
|
+
const HARD_PER_LINE_BYTES = ${5e4};
|
|
2918
|
+
|
|
2919
|
+
let stdoutChunks = [];
|
|
2920
|
+
let stdoutBytes = 0;
|
|
2921
|
+
let truncated = false;
|
|
2922
|
+
function captureLine(args) {
|
|
2923
|
+
const line = args.map(a => {
|
|
2924
|
+
if (typeof a === 'string') return a;
|
|
2925
|
+
if (a === undefined) return 'undefined';
|
|
2926
|
+
if (a === null) return 'null';
|
|
2927
|
+
try { return JSON.stringify(a, jsonReplacer, 2); } catch { return String(a); }
|
|
2928
|
+
}).join(' ');
|
|
2929
|
+
const capped = line.length > HARD_PER_LINE_BYTES
|
|
2930
|
+
? line.slice(0, HARD_PER_LINE_BYTES) + ' [...line truncated]'
|
|
2931
|
+
: line;
|
|
2932
|
+
stdoutChunks.push(capped);
|
|
2933
|
+
stdoutBytes += capped.length + 1;
|
|
2934
|
+
}
|
|
2935
|
+
function jsonReplacer(_k, v) {
|
|
2936
|
+
if (v instanceof Error) return { name: v.name, message: v.message };
|
|
2937
|
+
if (typeof v === 'bigint') return v.toString() + 'n';
|
|
2938
|
+
return v;
|
|
2939
|
+
}
|
|
2940
|
+
function collectStdout() {
|
|
2941
|
+
const joined = stdoutChunks.join('\n');
|
|
2942
|
+
if (joined.length <= STDOUT_HEAD_BYTES + STDOUT_TAIL_BYTES) return joined;
|
|
2943
|
+
truncated = true;
|
|
2944
|
+
const head = joined.slice(0, STDOUT_HEAD_BYTES);
|
|
2945
|
+
const tail = joined.slice(joined.length - STDOUT_TAIL_BYTES);
|
|
2946
|
+
const elidedBytes = joined.length - STDOUT_HEAD_BYTES - STDOUT_TAIL_BYTES;
|
|
2947
|
+
return head + '\n[...' + elidedBytes + ' bytes truncated...]\n' + tail;
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
const sandbox = {
|
|
2951
|
+
console: {
|
|
2952
|
+
log: (...a) => captureLine(a),
|
|
2953
|
+
warn: (...a) => captureLine(a),
|
|
2954
|
+
error: (...a) => captureLine(a),
|
|
2955
|
+
info: (...a) => captureLine(a),
|
|
2956
|
+
},
|
|
2957
|
+
Math, JSON, Date, RegExp, Error, TypeError, RangeError, Promise,
|
|
2958
|
+
Array, Object, String, Number, Boolean, Map, Set, WeakMap, WeakSet, Symbol,
|
|
2959
|
+
// Number coercion / validation builtins — kept in sync with ReplContext
|
|
2960
|
+
// sandbox so worker and in-process backends behave identically.
|
|
2961
|
+
parseInt, parseFloat, isNaN, isFinite,
|
|
2962
|
+
structuredClone: globalThis.structuredClone,
|
|
2963
|
+
};
|
|
2964
|
+
// strings: false disables eval / new Function inside the worker context.
|
|
2965
|
+
// Same posture as the in-process ReplContext (Ken's P2 #2).
|
|
2966
|
+
const ctx = vm.createContext(sandbox, { codeGeneration: { strings: false, wasm: false } });
|
|
2967
|
+
|
|
2968
|
+
// Tool stubs: each in-REPL call posts a toolCall and awaits matching toolResult.
|
|
2969
|
+
let nextToolCallId = 0;
|
|
2970
|
+
const pendingToolCalls = new Map();
|
|
2971
|
+
function makeToolStub(name) {
|
|
2972
|
+
return (...args) => {
|
|
2973
|
+
const id = nextToolCallId++;
|
|
2974
|
+
return new Promise((resolve, reject) => {
|
|
2975
|
+
pendingToolCalls.set(id, { resolve, reject });
|
|
2976
|
+
// Args go through structured cloning. Functions, classes, etc. don't
|
|
2977
|
+
// survive the boundary — that's fine for our tool surface.
|
|
2978
|
+
try {
|
|
2979
|
+
parentPort.postMessage({ type: 'toolCall', id, name, args });
|
|
2980
|
+
} catch (e) {
|
|
2981
|
+
pendingToolCalls.delete(id);
|
|
2982
|
+
reject(new Error('postMessage failed for tool ' + name + ': ' + (e && e.message)));
|
|
2983
|
+
}
|
|
2984
|
+
});
|
|
2985
|
+
};
|
|
2986
|
+
}
|
|
2987
|
+
function setToolStubs(toolNames) {
|
|
2988
|
+
for (const name of toolNames) {
|
|
2989
|
+
sandbox[name] = makeToolStub(name);
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
function serializeError(e) {
|
|
2994
|
+
if (e instanceof Error) {
|
|
2995
|
+
const stack = e.stack ? '\n' + e.stack.split('\n').slice(0, 6).join('\n') : '';
|
|
2996
|
+
return e.name + ': ' + e.message + stack;
|
|
2997
|
+
}
|
|
2998
|
+
const t = typeof e;
|
|
2999
|
+
if (t === 'object' && e !== null) {
|
|
3000
|
+
let s = '';
|
|
3001
|
+
try { s = JSON.stringify(e); } catch { s = '[unserializable]'; }
|
|
3002
|
+
if (s === '{}' || s === '[]') {
|
|
3003
|
+
const ctor = (e && e.constructor && e.constructor.name) || 'Object';
|
|
3004
|
+
return '[non-Error throw: empty ' + ctor + ' — likely \`throw {}\` or thrown DOM exception]';
|
|
3005
|
+
}
|
|
3006
|
+
return '[non-Error throw: ' + s.slice(0, 500) + ']';
|
|
3007
|
+
}
|
|
3008
|
+
return '[' + t + ' throw: ' + String(e).slice(0, 200) + ']';
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
let timeoutMsDefault = 30000;
|
|
3012
|
+
|
|
3013
|
+
parentPort.on('message', async (msg) => {
|
|
3014
|
+
if (msg.type === 'init') {
|
|
3015
|
+
timeoutMsDefault = msg.timeoutMs || 30000;
|
|
3016
|
+
setToolStubs(msg.toolNames || []);
|
|
3017
|
+
parentPort.postMessage({ type: 'ready' });
|
|
3018
|
+
return;
|
|
3019
|
+
}
|
|
3020
|
+
if (msg.type === 'setTools') {
|
|
3021
|
+
setToolStubs(msg.toolNames || []);
|
|
3022
|
+
return;
|
|
3023
|
+
}
|
|
3024
|
+
if (msg.type === 'toolResult') {
|
|
3025
|
+
const pending = pendingToolCalls.get(msg.id);
|
|
3026
|
+
if (!pending) return;
|
|
3027
|
+
pendingToolCalls.delete(msg.id);
|
|
3028
|
+
if (msg.ok) pending.resolve(msg.value);
|
|
3029
|
+
else pending.reject(new Error(msg.error || 'tool call failed'));
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
if (msg.type === 'runCode') {
|
|
3033
|
+
const t0 = Date.now();
|
|
3034
|
+
stdoutChunks = []; stdoutBytes = 0; truncated = false;
|
|
3035
|
+
let error = null;
|
|
3036
|
+
const wrapped = '(async () => {\n' + msg.code + '\n})()';
|
|
3037
|
+
try {
|
|
3038
|
+
const promise = vm.runInContext(wrapped, ctx, {
|
|
3039
|
+
timeout: msg.timeoutMs || timeoutMsDefault,
|
|
3040
|
+
displayErrors: true,
|
|
3041
|
+
});
|
|
3042
|
+
await promise;
|
|
3043
|
+
} catch (e) {
|
|
3044
|
+
error = serializeError(e);
|
|
3045
|
+
}
|
|
3046
|
+
parentPort.postMessage({
|
|
3047
|
+
type: 'runResult',
|
|
3048
|
+
id: msg.id,
|
|
3049
|
+
stdout: collectStdout(),
|
|
3050
|
+
error,
|
|
3051
|
+
truncated,
|
|
3052
|
+
durationMs: Date.now() - t0,
|
|
3053
|
+
});
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
});
|
|
3057
|
+
`;
|
|
2887
3058
|
//#endregion
|
|
2888
3059
|
//#region src/config/toolSafety.ts
|
|
2889
3060
|
/**
|
|
@@ -3055,7 +3226,7 @@ function buildPlanModePromptSection(planModeFilePath) {
|
|
|
3055
3226
|
|
|
3056
3227
|
The user has cycled into plan mode (Shift+Tab). Plan mode restricts WRITING, not READING. You still have a complete read toolkit — use it.
|
|
3057
3228
|
|
|
3058
|
-
**Tools available in plan mode
|
|
3229
|
+
**Tools available in plan mode:**
|
|
3059
3230
|
- \`grep_search\` — find symbols, strings, patterns across files
|
|
3060
3231
|
- \`glob_files\` — list files by pattern (use this instead of \`ls\` / \`find\`)
|
|
3061
3232
|
- \`file_read\` — read file contents
|
|
@@ -3080,8 +3251,8 @@ Ground every claim in files you have actually read. Do not write pseudocode in c
|
|
|
3080
3251
|
Follow this phased workflow. Do not skip phases.
|
|
3081
3252
|
|
|
3082
3253
|
### Phase 1 — Understand
|
|
3083
|
-
-
|
|
3084
|
-
-
|
|
3254
|
+
- **Default to delegation.** For any task touching more than 2-3 files, delegate to the 'explore' subagent via agent_delegate *first*. Read directly only for narrow single-file lookups or to verify a specific line after the subagent reports back.
|
|
3255
|
+
- **Read budget: each file at most once.** If you've used ~5 read tools and still feel uncertain about scope, the spec is ambiguous — call ask_user_question instead of reading more. Additional reads will not resolve ambiguity; they will just bloat context.
|
|
3085
3256
|
- Identify what already exists vs. what needs to be built. Reuse existing functions and patterns rather than proposing new ones.
|
|
3086
3257
|
|
|
3087
3258
|
### Phase 2 — Clarify (REQUIRED if anything is ambiguous)
|
|
@@ -3389,6 +3560,42 @@ function isWriteTargetingPlanFile(toolName, args, cwd = process.cwd()) {
|
|
|
3389
3560
|
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
3390
3561
|
}
|
|
3391
3562
|
//#endregion
|
|
3563
|
+
//#region ../../b4m-core/utils/dist/llm/backend.mjs
|
|
3564
|
+
/**
|
|
3565
|
+
* Shared implementation for OpenAI-style backends that store separate
|
|
3566
|
+
* `role: 'tool'` messages with `tool_call_id`. Mutates in place.
|
|
3567
|
+
*/
|
|
3568
|
+
function replaceLastToolResultObservationOpenAI(messages, toolCallId, newObservation) {
|
|
3569
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
3570
|
+
const msg = messages[i];
|
|
3571
|
+
if (msg.role === "tool" && msg.tool_call_id === toolCallId) {
|
|
3572
|
+
msg.content = newObservation;
|
|
3573
|
+
return;
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
throw new Error(`replaceLastToolResultObservation: no role=tool message with tool_call_id="${toolCallId}" found in messages`);
|
|
3577
|
+
}
|
|
3578
|
+
/**
|
|
3579
|
+
* Shared implementation for `getLatestToolCallId` on OpenAI-style backends.
|
|
3580
|
+
* Scans assistant messages backwards for a `tool_calls` array (set by
|
|
3581
|
+
* `pushToolMessages`) containing a function call with matching `name`.
|
|
3582
|
+
*
|
|
3583
|
+
* Tie-break: when a single assistant message contains multiple matching calls
|
|
3584
|
+
* (parallel tool use), this returns the LAST entry in `tool_calls` array order.
|
|
3585
|
+
* Callers that need to disambiguate between parallel calls must track the id
|
|
3586
|
+
* at dispatch time rather than recover it from history.
|
|
3587
|
+
*/
|
|
3588
|
+
function getLatestToolCallIdOpenAI(messages, toolName) {
|
|
3589
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
3590
|
+
const msg = messages[i];
|
|
3591
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls)) continue;
|
|
3592
|
+
for (let j = msg.tool_calls.length - 1; j >= 0; j--) {
|
|
3593
|
+
const call = msg.tool_calls[j];
|
|
3594
|
+
if (call.function?.name === toolName && call.id) return call.id;
|
|
3595
|
+
}
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
//#endregion
|
|
3392
3599
|
//#region ../../b4m-core/utils/dist/imageGeneration/AIImageService.mjs
|
|
3393
3600
|
/**
|
|
3394
3601
|
* Abstract class for AI Image Service
|
|
@@ -5534,6 +5741,12 @@ var OpenAIBackend = class {
|
|
|
5534
5741
|
tool_call_id: tool.id
|
|
5535
5742
|
});
|
|
5536
5743
|
}
|
|
5744
|
+
replaceLastToolResultObservation(messages, toolCallId, newObservation) {
|
|
5745
|
+
replaceLastToolResultObservationOpenAI(messages, toolCallId, newObservation);
|
|
5746
|
+
}
|
|
5747
|
+
getLatestToolCallId(messages, toolName) {
|
|
5748
|
+
return getLatestToolCallIdOpenAI(messages, toolName);
|
|
5749
|
+
}
|
|
5537
5750
|
formatTools(tools = []) {
|
|
5538
5751
|
return tools.map((tool) => ({
|
|
5539
5752
|
type: "function",
|
|
@@ -18429,11 +18642,11 @@ function parseQuery(query) {
|
|
|
18429
18642
|
*/
|
|
18430
18643
|
const getCliOnlyTools = async () => {
|
|
18431
18644
|
const [{ createFileTool }, { globFilesTool }, { grepSearchTool }, { deleteFileTool }, { bashExecuteTool }] = await Promise.all([
|
|
18432
|
-
import("./createFile-C1JoeuYh-
|
|
18433
|
-
import("./globFiles-Bez8QCbS-
|
|
18434
|
-
import("./grepSearch-
|
|
18435
|
-
import("./deleteFile-BTberNGj-
|
|
18436
|
-
import("./bashExecute-pYljpfPn-
|
|
18645
|
+
import("./createFile-C1JoeuYh-metInFKd.mjs"),
|
|
18646
|
+
import("./globFiles-Bez8QCbS-DZb6McbJ.mjs"),
|
|
18647
|
+
import("./grepSearch-BxucZWO8-lPRv6R6F.mjs"),
|
|
18648
|
+
import("./deleteFile-BTberNGj-CW922hRM.mjs"),
|
|
18649
|
+
import("./bashExecute-pYljpfPn-BZXHMQEl.mjs")
|
|
18437
18650
|
]);
|
|
18438
18651
|
return {
|
|
18439
18652
|
file_read: fileReadTool,
|
|
@@ -19089,7 +19302,7 @@ function cleanupSandboxFiles(paths) {
|
|
|
19089
19302
|
*/
|
|
19090
19303
|
async function captureViolations(isSandboxed, result, command, orchestrator) {
|
|
19091
19304
|
if (!isSandboxed || !orchestrator || !command) return;
|
|
19092
|
-
const { parseSandboxStderr, toSandboxViolations } = await import("./StderrViolationParser-
|
|
19305
|
+
const { parseSandboxStderr, toSandboxViolations } = await import("./StderrViolationParser-BFP4bo7I.mjs");
|
|
19093
19306
|
const parsed = parseSandboxStderr(result);
|
|
19094
19307
|
if (parsed.length > 0) {
|
|
19095
19308
|
const violations = toSandboxViolations(parsed, command);
|
|
@@ -23522,7 +23735,8 @@ function createTodoStore(onUpdate) {
|
|
|
23522
23735
|
//#endregion
|
|
23523
23736
|
//#region src/tools/findDefinitionTool.ts
|
|
23524
23737
|
const execFileAsync = promisify(execFile);
|
|
23525
|
-
|
|
23738
|
+
/** Cached ripgrep binary path after first resolution */
|
|
23739
|
+
let cachedRgPath = null;
|
|
23526
23740
|
const VALID_KINDS = [
|
|
23527
23741
|
"class",
|
|
23528
23742
|
"function",
|
|
@@ -23566,14 +23780,23 @@ const KIND_KEYWORDS = {
|
|
|
23566
23780
|
]
|
|
23567
23781
|
};
|
|
23568
23782
|
const ALL_KEYWORDS = Object.values(KIND_KEYWORDS).flat();
|
|
23569
|
-
|
|
23783
|
+
/**
|
|
23784
|
+
* Resolve ripgrep binary path via the package's exported `rgPath`.
|
|
23785
|
+
* `@vscode/ripgrep` is an optional dependency, so we load it lazily; in 1.18+
|
|
23786
|
+
* the binary lives in a platform-specific sibling package and is resolved by
|
|
23787
|
+
* the package itself — we just have to ask for it.
|
|
23788
|
+
*/
|
|
23789
|
+
async function getRipgrepPath() {
|
|
23790
|
+
if (cachedRgPath) return cachedRgPath;
|
|
23791
|
+
let rgPath;
|
|
23570
23792
|
try {
|
|
23571
|
-
|
|
23572
|
-
const ripgrepDir = path.dirname(ripgrepPath);
|
|
23573
|
-
return path.join(ripgrepDir, "..", "bin", "rg" + (process.platform === "win32" ? ".exe" : ""));
|
|
23793
|
+
({rgPath} = await import("@vscode/ripgrep"));
|
|
23574
23794
|
} catch {
|
|
23575
|
-
throw new Error("ripgrep is not available.
|
|
23795
|
+
throw new Error("ripgrep is not available. Install the optional dependency: pnpm add @vscode/ripgrep --filter @bike4mind/cli");
|
|
23576
23796
|
}
|
|
23797
|
+
if (!rgPath || !existsSync(rgPath)) throw new Error(`ripgrep binary not found at ${rgPath ?? "<unresolved>"}. Ensure @vscode/ripgrep platform optional dependencies are installed for ${process.platform}-${process.arch}.`);
|
|
23798
|
+
cachedRgPath = rgPath;
|
|
23799
|
+
return rgPath;
|
|
23577
23800
|
}
|
|
23578
23801
|
function isPathWithinWorkspace(targetPath, baseCwd) {
|
|
23579
23802
|
const resolvedTarget = path.resolve(targetPath);
|
|
@@ -23627,7 +23850,7 @@ async function findDefinitions(params) {
|
|
|
23627
23850
|
if (error.code === "ENOENT") throw new Error(`Path does not exist: ${search_path}`);
|
|
23628
23851
|
throw error;
|
|
23629
23852
|
}
|
|
23630
|
-
const rgPath = getRipgrepPath();
|
|
23853
|
+
const rgPath = await getRipgrepPath();
|
|
23631
23854
|
const rgArgs = [
|
|
23632
23855
|
"--json",
|
|
23633
23856
|
"--max-count",
|
|
@@ -23804,7 +24027,7 @@ function createGetFileStructureTool() {
|
|
|
23804
24027
|
if (stats.isDirectory()) return `Error: Path is a directory, not a file: ${params.path}`;
|
|
23805
24028
|
if (stats.size > MAX_FILE_SIZE) return `Error: File too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Max: ${MAX_FILE_SIZE / 1024 / 1024}MB`;
|
|
23806
24029
|
const ext = path.extname(resolvedPath).toLowerCase();
|
|
23807
|
-
const { getLanguageForExtension, parseFileStructure, getSupportedLanguages } = await import("./treeSitterEngine-
|
|
24030
|
+
const { getLanguageForExtension, parseFileStructure, getSupportedLanguages } = await import("./treeSitterEngine-Cw2LbVZT.mjs");
|
|
23808
24031
|
const languageId = getLanguageForExtension(ext);
|
|
23809
24032
|
if (!languageId) return `Error: Unsupported file type "${ext}". Supported languages: ${getSupportedLanguages().join(", ")}`;
|
|
23810
24033
|
const sourceCode = await promises.readFile(resolvedPath, "utf-8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -121,11 +121,11 @@
|
|
|
121
121
|
"tsx": "^4.21.0",
|
|
122
122
|
"typescript": "^5.9.3",
|
|
123
123
|
"vitest": "^4.1.2",
|
|
124
|
-
"@bike4mind/agents": "0.
|
|
125
|
-
"@bike4mind/common": "2.
|
|
126
|
-
"@bike4mind/mcp": "1.37.
|
|
127
|
-
"@bike4mind/services": "2.
|
|
128
|
-
"@bike4mind/utils": "2.
|
|
124
|
+
"@bike4mind/agents": "0.9.0",
|
|
125
|
+
"@bike4mind/common": "2.95.0",
|
|
126
|
+
"@bike4mind/mcp": "1.37.8",
|
|
127
|
+
"@bike4mind/services": "2.83.0",
|
|
128
|
+
"@bike4mind/utils": "2.21.0"
|
|
129
129
|
},
|
|
130
130
|
"optionalDependencies": {
|
|
131
131
|
"@vscode/ripgrep": "^1.17.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|