@bike4mind/cli 0.2.10-feat-cli-multi-directory-workspace.17245 → 0.2.10-feat-explore-subagent-implementation.17245
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/bin/bike4mind-cli.mjs +0 -12
- package/dist/index.js +447 -663
- package/package.json +6 -7
package/dist/index.js
CHANGED
|
@@ -91,13 +91,8 @@ import { Box as Box10, Text as Text10, Static } from "ink";
|
|
|
91
91
|
// src/components/StatusBar.tsx
|
|
92
92
|
import React from "react";
|
|
93
93
|
import { Box, Text } from "ink";
|
|
94
|
-
var StatusBar = React.memo(function StatusBar2({
|
|
95
|
-
sessionName,
|
|
96
|
-
model,
|
|
97
|
-
tokenUsage,
|
|
98
|
-
workspaceCount
|
|
99
|
-
}) {
|
|
100
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", justifyContent: "space-between", width: "100%", paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, sessionName), /* @__PURE__ */ React.createElement(Box, { gap: 2 }, workspaceCount && workspaceCount > 1 && /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u{1F4C1} ", workspaceCount, " dirs"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, tokenUsage.toLocaleString(), " tokens"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, model)));
|
|
94
|
+
var StatusBar = React.memo(function StatusBar2({ sessionName, model, tokenUsage }) {
|
|
95
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", justifyContent: "space-between", width: "100%", paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, sessionName), /* @__PURE__ */ React.createElement(Box, { gap: 2 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, tokenUsage.toLocaleString(), " tokens"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, model)));
|
|
101
96
|
});
|
|
102
97
|
|
|
103
98
|
// src/components/InputPrompt.tsx
|
|
@@ -1430,7 +1425,6 @@ function App({
|
|
|
1430
1425
|
const sessionName = useCliStore((state) => state.session?.name || "New Session");
|
|
1431
1426
|
const currentModel = useCliStore((state) => state.session?.model || "claude-sonnet-4-5-20250929");
|
|
1432
1427
|
const totalTokens = useCliStore((state) => state.session?.metadata.totalTokens || 0);
|
|
1433
|
-
const workspaceCount = useCliStore((state) => state.session?.workingDirectories?.length || 1);
|
|
1434
1428
|
const isThinking = useCliStore((state) => state.isThinking);
|
|
1435
1429
|
const permissionPrompt = useCliStore((state) => state.permissionPrompt);
|
|
1436
1430
|
const showConfigEditor = useCliStore((state) => state.showConfigEditor);
|
|
@@ -1496,15 +1490,7 @@ ${errorBlock}`;
|
|
|
1496
1490
|
onPrefillConsumed,
|
|
1497
1491
|
onBashModeChange: setIsBashMode
|
|
1498
1492
|
}
|
|
1499
|
-
)), /* @__PURE__ */ React11.createElement(
|
|
1500
|
-
StatusBar,
|
|
1501
|
-
{
|
|
1502
|
-
sessionName,
|
|
1503
|
-
model: currentModel,
|
|
1504
|
-
tokenUsage: totalTokens,
|
|
1505
|
-
workspaceCount
|
|
1506
|
-
}
|
|
1507
|
-
)));
|
|
1493
|
+
)), /* @__PURE__ */ React11.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens })));
|
|
1508
1494
|
}
|
|
1509
1495
|
|
|
1510
1496
|
// src/components/MessageList.tsx
|
|
@@ -5165,8 +5151,8 @@ async function processAndStoreImages(images, context) {
|
|
|
5165
5151
|
const buffer = await downloadImage(image);
|
|
5166
5152
|
const fileType = await fileTypeFromBuffer2(buffer);
|
|
5167
5153
|
const filename = `${uuidv45()}.${fileType?.ext}`;
|
|
5168
|
-
const
|
|
5169
|
-
return
|
|
5154
|
+
const path15 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
5155
|
+
return path15;
|
|
5170
5156
|
}));
|
|
5171
5157
|
}
|
|
5172
5158
|
async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
|
|
@@ -6378,8 +6364,8 @@ async function processAndStoreImage(imageUrl, context) {
|
|
|
6378
6364
|
const buffer = await downloadImage2(imageUrl);
|
|
6379
6365
|
const fileType = await fileTypeFromBuffer3(buffer);
|
|
6380
6366
|
const filename = `${uuidv46()}.${fileType?.ext}`;
|
|
6381
|
-
const
|
|
6382
|
-
return
|
|
6367
|
+
const path15 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
6368
|
+
return path15;
|
|
6383
6369
|
}
|
|
6384
6370
|
async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
|
|
6385
6371
|
await context.onFinish?.("edit_image", storedImagePath);
|
|
@@ -9470,7 +9456,7 @@ async function generateFileDeletePreview(args) {
|
|
|
9470
9456
|
if (!existsSync7(args.path)) {
|
|
9471
9457
|
return `[File does not exist: ${args.path}]`;
|
|
9472
9458
|
}
|
|
9473
|
-
const stats = await import("fs/promises").then((
|
|
9459
|
+
const stats = await import("fs/promises").then((fs12) => fs12.stat(args.path));
|
|
9474
9460
|
return `[File will be deleted]
|
|
9475
9461
|
|
|
9476
9462
|
Path: ${args.path}
|
|
@@ -9815,330 +9801,26 @@ async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
|
9815
9801
|
}
|
|
9816
9802
|
}
|
|
9817
9803
|
|
|
9818
|
-
// src/tools/workspaceAwareFileTools.ts
|
|
9819
|
-
import path13 from "path";
|
|
9820
|
-
import fs11 from "fs/promises";
|
|
9821
|
-
import { existsSync as existsSync8 } from "fs";
|
|
9822
|
-
function validatePathInWorkspace(filePath, workspaceManager) {
|
|
9823
|
-
try {
|
|
9824
|
-
return workspaceManager.resolvePath(filePath);
|
|
9825
|
-
} catch (error) {
|
|
9826
|
-
throw error;
|
|
9827
|
-
}
|
|
9828
|
-
}
|
|
9829
|
-
function createWorkspaceAwareFileRead(workspaceManager) {
|
|
9830
|
-
return {
|
|
9831
|
-
toolSchema: {
|
|
9832
|
-
name: "file_read",
|
|
9833
|
-
description: "Read contents of a file from the workspace. Returns file contents as a string.",
|
|
9834
|
-
parameters: {
|
|
9835
|
-
type: "object",
|
|
9836
|
-
properties: {
|
|
9837
|
-
path: {
|
|
9838
|
-
type: "string",
|
|
9839
|
-
description: "Path to the file to read (relative to workspace or absolute)"
|
|
9840
|
-
}
|
|
9841
|
-
},
|
|
9842
|
-
required: ["path"]
|
|
9843
|
-
}
|
|
9844
|
-
},
|
|
9845
|
-
toolFn: async (parameters) => {
|
|
9846
|
-
const args = parameters;
|
|
9847
|
-
const { path: filePath } = args;
|
|
9848
|
-
const resolvedPath = validatePathInWorkspace(filePath, workspaceManager);
|
|
9849
|
-
if (!existsSync8(resolvedPath)) {
|
|
9850
|
-
throw new Error(`File not found: ${filePath}`);
|
|
9851
|
-
}
|
|
9852
|
-
const content = await fs11.readFile(resolvedPath, "utf-8");
|
|
9853
|
-
return content;
|
|
9854
|
-
}
|
|
9855
|
-
};
|
|
9856
|
-
}
|
|
9857
|
-
function createWorkspaceAwareCreateFile(workspaceManager) {
|
|
9858
|
-
return {
|
|
9859
|
-
toolSchema: {
|
|
9860
|
-
name: "create_file",
|
|
9861
|
-
description: "Create a new file with the given content in the workspace.",
|
|
9862
|
-
parameters: {
|
|
9863
|
-
type: "object",
|
|
9864
|
-
properties: {
|
|
9865
|
-
path: {
|
|
9866
|
-
type: "string",
|
|
9867
|
-
description: "Path where the file should be created (relative to workspace or absolute)"
|
|
9868
|
-
},
|
|
9869
|
-
content: {
|
|
9870
|
-
type: "string",
|
|
9871
|
-
description: "Content to write to the file"
|
|
9872
|
-
}
|
|
9873
|
-
},
|
|
9874
|
-
required: ["path", "content"]
|
|
9875
|
-
}
|
|
9876
|
-
},
|
|
9877
|
-
toolFn: async (parameters) => {
|
|
9878
|
-
const args = parameters;
|
|
9879
|
-
const { path: filePath, content } = args;
|
|
9880
|
-
const resolvedPath = validatePathInWorkspace(filePath, workspaceManager);
|
|
9881
|
-
if (existsSync8(resolvedPath)) {
|
|
9882
|
-
throw new Error(`File already exists: ${filePath}. Use edit_file to modify existing files.`);
|
|
9883
|
-
}
|
|
9884
|
-
const parentDir = path13.dirname(resolvedPath);
|
|
9885
|
-
await fs11.mkdir(parentDir, { recursive: true });
|
|
9886
|
-
await fs11.writeFile(resolvedPath, content, "utf-8");
|
|
9887
|
-
return `File created successfully: ${filePath}`;
|
|
9888
|
-
}
|
|
9889
|
-
};
|
|
9890
|
-
}
|
|
9891
|
-
function createWorkspaceAwareEditFile(workspaceManager) {
|
|
9892
|
-
return {
|
|
9893
|
-
toolSchema: {
|
|
9894
|
-
name: "edit_file",
|
|
9895
|
-
description: "Edit an existing file by replacing its entire content.",
|
|
9896
|
-
parameters: {
|
|
9897
|
-
type: "object",
|
|
9898
|
-
properties: {
|
|
9899
|
-
path: {
|
|
9900
|
-
type: "string",
|
|
9901
|
-
description: "Path to the file to edit (relative to workspace or absolute)"
|
|
9902
|
-
},
|
|
9903
|
-
content: {
|
|
9904
|
-
type: "string",
|
|
9905
|
-
description: "New content for the file"
|
|
9906
|
-
}
|
|
9907
|
-
},
|
|
9908
|
-
required: ["path", "content"]
|
|
9909
|
-
}
|
|
9910
|
-
},
|
|
9911
|
-
toolFn: async (parameters) => {
|
|
9912
|
-
const args = parameters;
|
|
9913
|
-
const { path: filePath, content } = args;
|
|
9914
|
-
const resolvedPath = validatePathInWorkspace(filePath, workspaceManager);
|
|
9915
|
-
if (!existsSync8(resolvedPath)) {
|
|
9916
|
-
throw new Error(`File not found: ${filePath}. Use create_file to create new files.`);
|
|
9917
|
-
}
|
|
9918
|
-
await fs11.writeFile(resolvedPath, content, "utf-8");
|
|
9919
|
-
return `File edited successfully: ${filePath}`;
|
|
9920
|
-
}
|
|
9921
|
-
};
|
|
9922
|
-
}
|
|
9923
|
-
function createWorkspaceAwareDeleteFile(workspaceManager) {
|
|
9924
|
-
return {
|
|
9925
|
-
toolSchema: {
|
|
9926
|
-
name: "delete_file",
|
|
9927
|
-
description: "Delete a file from the workspace.",
|
|
9928
|
-
parameters: {
|
|
9929
|
-
type: "object",
|
|
9930
|
-
properties: {
|
|
9931
|
-
path: {
|
|
9932
|
-
type: "string",
|
|
9933
|
-
description: "Path to the file to delete (relative to workspace or absolute)"
|
|
9934
|
-
}
|
|
9935
|
-
},
|
|
9936
|
-
required: ["path"]
|
|
9937
|
-
}
|
|
9938
|
-
},
|
|
9939
|
-
toolFn: async (parameters) => {
|
|
9940
|
-
const args = parameters;
|
|
9941
|
-
const { path: filePath } = args;
|
|
9942
|
-
const resolvedPath = validatePathInWorkspace(filePath, workspaceManager);
|
|
9943
|
-
if (!existsSync8(resolvedPath)) {
|
|
9944
|
-
throw new Error(`File not found: ${filePath}`);
|
|
9945
|
-
}
|
|
9946
|
-
await fs11.unlink(resolvedPath);
|
|
9947
|
-
return `File deleted successfully: ${filePath}`;
|
|
9948
|
-
}
|
|
9949
|
-
};
|
|
9950
|
-
}
|
|
9951
|
-
function createWorkspaceAwareGlobFiles(workspaceManager) {
|
|
9952
|
-
return {
|
|
9953
|
-
toolSchema: {
|
|
9954
|
-
name: "glob_files",
|
|
9955
|
-
description: "Search for files matching a glob pattern in the workspace.",
|
|
9956
|
-
parameters: {
|
|
9957
|
-
type: "object",
|
|
9958
|
-
properties: {
|
|
9959
|
-
pattern: {
|
|
9960
|
-
type: "string",
|
|
9961
|
-
description: 'Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js")'
|
|
9962
|
-
},
|
|
9963
|
-
cwd: {
|
|
9964
|
-
type: "string",
|
|
9965
|
-
description: "Directory to search from (relative to primary workspace or absolute)"
|
|
9966
|
-
}
|
|
9967
|
-
},
|
|
9968
|
-
required: ["pattern"]
|
|
9969
|
-
}
|
|
9970
|
-
},
|
|
9971
|
-
toolFn: async (parameters) => {
|
|
9972
|
-
const args = parameters;
|
|
9973
|
-
const { pattern, cwd: relativeCwd } = args;
|
|
9974
|
-
const primaryWorkspace = workspaceManager.getPrimaryWorkspace();
|
|
9975
|
-
let searchDir = primaryWorkspace;
|
|
9976
|
-
if (relativeCwd) {
|
|
9977
|
-
searchDir = validatePathInWorkspace(relativeCwd, workspaceManager);
|
|
9978
|
-
}
|
|
9979
|
-
const glob = (await import("fast-glob")).default;
|
|
9980
|
-
const files = await glob(pattern, {
|
|
9981
|
-
cwd: searchDir,
|
|
9982
|
-
absolute: false,
|
|
9983
|
-
onlyFiles: true
|
|
9984
|
-
});
|
|
9985
|
-
const result = {
|
|
9986
|
-
pattern,
|
|
9987
|
-
cwd: searchDir,
|
|
9988
|
-
files: files.map((f) => path13.join(searchDir, f)),
|
|
9989
|
-
count: files.length
|
|
9990
|
-
};
|
|
9991
|
-
return JSON.stringify(result);
|
|
9992
|
-
}
|
|
9993
|
-
};
|
|
9994
|
-
}
|
|
9995
|
-
function createWorkspaceAwareGrepSearch(workspaceManager) {
|
|
9996
|
-
return {
|
|
9997
|
-
toolSchema: {
|
|
9998
|
-
name: "grep_search",
|
|
9999
|
-
description: "Search for text patterns in files within the workspace using grep.",
|
|
10000
|
-
parameters: {
|
|
10001
|
-
type: "object",
|
|
10002
|
-
properties: {
|
|
10003
|
-
pattern: {
|
|
10004
|
-
type: "string",
|
|
10005
|
-
description: "Regular expression pattern to search for"
|
|
10006
|
-
},
|
|
10007
|
-
path: {
|
|
10008
|
-
type: "string",
|
|
10009
|
-
description: "Directory or file to search (relative to primary workspace or absolute)"
|
|
10010
|
-
},
|
|
10011
|
-
filePattern: {
|
|
10012
|
-
type: "string",
|
|
10013
|
-
description: 'File pattern to filter files (e.g., "*.ts", "*.js")'
|
|
10014
|
-
}
|
|
10015
|
-
},
|
|
10016
|
-
required: ["pattern"]
|
|
10017
|
-
}
|
|
10018
|
-
},
|
|
10019
|
-
toolFn: async (parameters) => {
|
|
10020
|
-
const args = parameters;
|
|
10021
|
-
const { pattern, path: searchPath, filePattern } = args;
|
|
10022
|
-
const primaryWorkspace = workspaceManager.getPrimaryWorkspace();
|
|
10023
|
-
let searchDir = primaryWorkspace;
|
|
10024
|
-
if (searchPath) {
|
|
10025
|
-
searchDir = validatePathInWorkspace(searchPath, workspaceManager);
|
|
10026
|
-
}
|
|
10027
|
-
const glob = (await import("fast-glob")).default;
|
|
10028
|
-
const globPattern = filePattern || "**/*";
|
|
10029
|
-
const files = await glob(globPattern, {
|
|
10030
|
-
cwd: searchDir,
|
|
10031
|
-
absolute: true,
|
|
10032
|
-
onlyFiles: true
|
|
10033
|
-
});
|
|
10034
|
-
const matches = [];
|
|
10035
|
-
const regex = new RegExp(pattern, "gi");
|
|
10036
|
-
for (const file of files) {
|
|
10037
|
-
try {
|
|
10038
|
-
const content = await fs11.readFile(file, "utf-8");
|
|
10039
|
-
const lines = content.split("\n");
|
|
10040
|
-
lines.forEach((line, index) => {
|
|
10041
|
-
if (regex.test(line)) {
|
|
10042
|
-
matches.push({
|
|
10043
|
-
file: path13.relative(primaryWorkspace, file),
|
|
10044
|
-
line: index + 1,
|
|
10045
|
-
content: line.trim()
|
|
10046
|
-
});
|
|
10047
|
-
}
|
|
10048
|
-
});
|
|
10049
|
-
} catch (error) {
|
|
10050
|
-
}
|
|
10051
|
-
}
|
|
10052
|
-
const result = {
|
|
10053
|
-
pattern,
|
|
10054
|
-
searchDir,
|
|
10055
|
-
matches,
|
|
10056
|
-
totalMatches: matches.length
|
|
10057
|
-
};
|
|
10058
|
-
return JSON.stringify(result);
|
|
10059
|
-
}
|
|
10060
|
-
};
|
|
10061
|
-
}
|
|
10062
|
-
function createWorkspaceAwareBashExecute(workspaceManager) {
|
|
10063
|
-
return {
|
|
10064
|
-
toolSchema: {
|
|
10065
|
-
name: "bash_execute",
|
|
10066
|
-
description: "Execute a bash command in the workspace. Use with caution.",
|
|
10067
|
-
parameters: {
|
|
10068
|
-
type: "object",
|
|
10069
|
-
properties: {
|
|
10070
|
-
command: {
|
|
10071
|
-
type: "string",
|
|
10072
|
-
description: "Bash command to execute"
|
|
10073
|
-
},
|
|
10074
|
-
cwd: {
|
|
10075
|
-
type: "string",
|
|
10076
|
-
description: "Working directory for command execution (relative to primary workspace or absolute)"
|
|
10077
|
-
},
|
|
10078
|
-
timeout: {
|
|
10079
|
-
type: "number",
|
|
10080
|
-
description: "Timeout in milliseconds (default: 30000)"
|
|
10081
|
-
}
|
|
10082
|
-
},
|
|
10083
|
-
required: ["command"]
|
|
10084
|
-
}
|
|
10085
|
-
},
|
|
10086
|
-
toolFn: async (parameters) => {
|
|
10087
|
-
const args = parameters;
|
|
10088
|
-
const { command, cwd: relativeCwd, timeout = 3e4 } = args;
|
|
10089
|
-
const primaryWorkspace = workspaceManager.getPrimaryWorkspace();
|
|
10090
|
-
let execDir = primaryWorkspace;
|
|
10091
|
-
if (relativeCwd) {
|
|
10092
|
-
execDir = path13.resolve(primaryWorkspace, relativeCwd);
|
|
10093
|
-
}
|
|
10094
|
-
const { execSync: execSync2 } = await import("child_process");
|
|
10095
|
-
try {
|
|
10096
|
-
const output = execSync2(command, {
|
|
10097
|
-
cwd: execDir,
|
|
10098
|
-
encoding: "utf-8",
|
|
10099
|
-
timeout,
|
|
10100
|
-
maxBuffer: 10 * 1024 * 1024
|
|
10101
|
-
// 10MB
|
|
10102
|
-
});
|
|
10103
|
-
const result = {
|
|
10104
|
-
success: true,
|
|
10105
|
-
output: output.toString(),
|
|
10106
|
-
exitCode: 0
|
|
10107
|
-
};
|
|
10108
|
-
return JSON.stringify(result);
|
|
10109
|
-
} catch (error) {
|
|
10110
|
-
const result = {
|
|
10111
|
-
success: false,
|
|
10112
|
-
output: error.stdout?.toString() || "",
|
|
10113
|
-
error: error.stderr?.toString() || error.message,
|
|
10114
|
-
exitCode: error.status || 1
|
|
10115
|
-
};
|
|
10116
|
-
return JSON.stringify(result);
|
|
10117
|
-
}
|
|
10118
|
-
}
|
|
10119
|
-
};
|
|
10120
|
-
}
|
|
10121
|
-
|
|
10122
9804
|
// src/utils/toolsAdapter.ts
|
|
10123
9805
|
var NoOpStorage = class extends BaseStorage {
|
|
10124
9806
|
async upload(input, destination, options) {
|
|
10125
9807
|
return `/tmp/${destination}`;
|
|
10126
9808
|
}
|
|
10127
|
-
async download(
|
|
9809
|
+
async download(path15) {
|
|
10128
9810
|
throw new Error("Download not supported in CLI");
|
|
10129
9811
|
}
|
|
10130
|
-
async delete(
|
|
9812
|
+
async delete(path15) {
|
|
10131
9813
|
}
|
|
10132
|
-
async getSignedUrl(
|
|
10133
|
-
return `/tmp/${
|
|
9814
|
+
async getSignedUrl(path15) {
|
|
9815
|
+
return `/tmp/${path15}`;
|
|
10134
9816
|
}
|
|
10135
|
-
getPublicUrl(
|
|
10136
|
-
return `/tmp/${
|
|
9817
|
+
getPublicUrl(path15) {
|
|
9818
|
+
return `/tmp/${path15}`;
|
|
10137
9819
|
}
|
|
10138
|
-
async getPreview(
|
|
10139
|
-
return `/tmp/${
|
|
9820
|
+
async getPreview(path15) {
|
|
9821
|
+
return `/tmp/${path15}`;
|
|
10140
9822
|
}
|
|
10141
|
-
async getMetadata(
|
|
9823
|
+
async getMetadata(path15) {
|
|
10142
9824
|
return { size: 0, contentType: "application/octet-stream" };
|
|
10143
9825
|
}
|
|
10144
9826
|
};
|
|
@@ -10232,7 +9914,31 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
10232
9914
|
}
|
|
10233
9915
|
};
|
|
10234
9916
|
}
|
|
10235
|
-
|
|
9917
|
+
var TOOL_NAME_MAPPING = {
|
|
9918
|
+
// Claude Code -> B4M
|
|
9919
|
+
read: "file_read",
|
|
9920
|
+
write: "create_file",
|
|
9921
|
+
edit: "edit_file",
|
|
9922
|
+
delete: "delete_file",
|
|
9923
|
+
glob: "glob_files",
|
|
9924
|
+
grep: "grep_search",
|
|
9925
|
+
bash: "bash_execute",
|
|
9926
|
+
// B4M -> Claude Code (reverse mapping)
|
|
9927
|
+
file_read: "read",
|
|
9928
|
+
create_file: "write",
|
|
9929
|
+
edit_file: "edit",
|
|
9930
|
+
delete_file: "delete",
|
|
9931
|
+
glob_files: "glob",
|
|
9932
|
+
grep_search: "grep",
|
|
9933
|
+
bash_execute: "bash"
|
|
9934
|
+
};
|
|
9935
|
+
function normalizeToolName(toolName) {
|
|
9936
|
+
if (toolName.includes("_")) {
|
|
9937
|
+
return toolName;
|
|
9938
|
+
}
|
|
9939
|
+
return TOOL_NAME_MAPPING[toolName] || toolName;
|
|
9940
|
+
}
|
|
9941
|
+
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, toolFilter) {
|
|
10236
9942
|
const logger2 = new CliLogger();
|
|
10237
9943
|
const storage = new NoOpStorage();
|
|
10238
9944
|
const user = {
|
|
@@ -10302,32 +10008,25 @@ function generateCliTools(userId, llm, model, permissionManager, workspaceManage
|
|
|
10302
10008
|
toolConfig,
|
|
10303
10009
|
model
|
|
10304
10010
|
);
|
|
10305
|
-
|
|
10011
|
+
let tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
|
|
10306
10012
|
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient)
|
|
10307
10013
|
);
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
createWorkspaceAwareBashExecute(workspaceManager)
|
|
10325
|
-
];
|
|
10326
|
-
const filteredTools = tools2.filter((tool) => !fileToolNames.includes(tool.toolSchema.name));
|
|
10327
|
-
const wrappedWorkspaceTools = workspaceAwareTools.map(
|
|
10328
|
-
(tool) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient)
|
|
10329
|
-
);
|
|
10330
|
-
return { tools: [...filteredTools, ...wrappedWorkspaceTools], agentContext };
|
|
10014
|
+
if (toolFilter) {
|
|
10015
|
+
const { allowedTools, deniedTools } = toolFilter;
|
|
10016
|
+
const normalizedAllowed = allowedTools?.map(normalizeToolName);
|
|
10017
|
+
const normalizedDenied = deniedTools?.map(normalizeToolName);
|
|
10018
|
+
tools2 = tools2.filter((tool) => {
|
|
10019
|
+
const toolName = tool.toolSchema.name;
|
|
10020
|
+
if (normalizedDenied && normalizedDenied.includes(toolName)) {
|
|
10021
|
+
return false;
|
|
10022
|
+
}
|
|
10023
|
+
if (normalizedAllowed && normalizedAllowed.length > 0) {
|
|
10024
|
+
return normalizedAllowed.includes(toolName);
|
|
10025
|
+
}
|
|
10026
|
+
return true;
|
|
10027
|
+
});
|
|
10028
|
+
}
|
|
10029
|
+
return { tools: tools2, agentContext };
|
|
10331
10030
|
}
|
|
10332
10031
|
|
|
10333
10032
|
// src/config/toolSafety.ts
|
|
@@ -10506,174 +10205,6 @@ var PermissionManager = class {
|
|
|
10506
10205
|
}
|
|
10507
10206
|
};
|
|
10508
10207
|
|
|
10509
|
-
// src/utils/WorkspaceManager.ts
|
|
10510
|
-
import path14 from "path";
|
|
10511
|
-
import fs12 from "fs";
|
|
10512
|
-
var WorkspaceManager = class _WorkspaceManager {
|
|
10513
|
-
constructor(initialWorkspaces = [process.cwd()]) {
|
|
10514
|
-
this.workspaces = [];
|
|
10515
|
-
this.workspaces = initialWorkspaces.length > 0 ? initialWorkspaces.map((dir) => path14.resolve(dir)) : [path14.resolve(process.cwd())];
|
|
10516
|
-
}
|
|
10517
|
-
static {
|
|
10518
|
-
/**
|
|
10519
|
-
* System directories that should never be added as workspaces
|
|
10520
|
-
*/
|
|
10521
|
-
this.FORBIDDEN_PATHS = [
|
|
10522
|
-
"/",
|
|
10523
|
-
"/bin",
|
|
10524
|
-
"/boot",
|
|
10525
|
-
"/dev",
|
|
10526
|
-
"/etc",
|
|
10527
|
-
"/lib",
|
|
10528
|
-
"/lib64",
|
|
10529
|
-
"/proc",
|
|
10530
|
-
"/root",
|
|
10531
|
-
"/sbin",
|
|
10532
|
-
"/sys",
|
|
10533
|
-
"/usr",
|
|
10534
|
-
"/var",
|
|
10535
|
-
"/tmp",
|
|
10536
|
-
"/System",
|
|
10537
|
-
"/Library",
|
|
10538
|
-
"/Applications",
|
|
10539
|
-
"/Windows",
|
|
10540
|
-
"/Program Files",
|
|
10541
|
-
"/Program Files (x86)"
|
|
10542
|
-
];
|
|
10543
|
-
}
|
|
10544
|
-
/**
|
|
10545
|
-
* Get all workspace directories
|
|
10546
|
-
*/
|
|
10547
|
-
getWorkspaces() {
|
|
10548
|
-
return [...this.workspaces];
|
|
10549
|
-
}
|
|
10550
|
-
/**
|
|
10551
|
-
* Get the primary workspace (first in list, used as default)
|
|
10552
|
-
*/
|
|
10553
|
-
getPrimaryWorkspace() {
|
|
10554
|
-
return this.workspaces[0] || process.cwd();
|
|
10555
|
-
}
|
|
10556
|
-
/**
|
|
10557
|
-
* Add a new workspace directory
|
|
10558
|
-
* @throws Error if directory is invalid, doesn't exist, or is forbidden
|
|
10559
|
-
*/
|
|
10560
|
-
addWorkspace(directory) {
|
|
10561
|
-
const resolvedPath = path14.resolve(directory);
|
|
10562
|
-
if (!fs12.existsSync(resolvedPath)) {
|
|
10563
|
-
throw new Error(`Directory does not exist: ${resolvedPath}`);
|
|
10564
|
-
}
|
|
10565
|
-
const stat = fs12.statSync(resolvedPath);
|
|
10566
|
-
if (!stat.isDirectory()) {
|
|
10567
|
-
throw new Error(`Path is not a directory: ${resolvedPath}`);
|
|
10568
|
-
}
|
|
10569
|
-
if (_WorkspaceManager.isForbiddenPath(resolvedPath)) {
|
|
10570
|
-
throw new Error(
|
|
10571
|
-
`Cannot add system directory as workspace: ${resolvedPath}
|
|
10572
|
-
Adding system directories like /, /usr, /etc is not allowed for security reasons.`
|
|
10573
|
-
);
|
|
10574
|
-
}
|
|
10575
|
-
if (this.workspaces.includes(resolvedPath)) {
|
|
10576
|
-
throw new Error(`Directory already in workspace: ${resolvedPath}`);
|
|
10577
|
-
}
|
|
10578
|
-
this.workspaces.push(resolvedPath);
|
|
10579
|
-
}
|
|
10580
|
-
/**
|
|
10581
|
-
* Remove a workspace directory
|
|
10582
|
-
* @throws Error if trying to remove the last/primary workspace
|
|
10583
|
-
*/
|
|
10584
|
-
removeWorkspace(directory) {
|
|
10585
|
-
const resolvedPath = path14.resolve(directory);
|
|
10586
|
-
const index = this.workspaces.indexOf(resolvedPath);
|
|
10587
|
-
if (index === -1) {
|
|
10588
|
-
throw new Error(`Directory not in workspace: ${resolvedPath}`);
|
|
10589
|
-
}
|
|
10590
|
-
if (this.workspaces.length === 1) {
|
|
10591
|
-
throw new Error("Cannot remove the last workspace directory");
|
|
10592
|
-
}
|
|
10593
|
-
if (index === 0) {
|
|
10594
|
-
throw new Error(
|
|
10595
|
-
"Cannot remove the primary workspace. Remove other directories first, or use /clear to start a new session."
|
|
10596
|
-
);
|
|
10597
|
-
}
|
|
10598
|
-
this.workspaces.splice(index, 1);
|
|
10599
|
-
}
|
|
10600
|
-
/**
|
|
10601
|
-
* Check if a path is within any workspace
|
|
10602
|
-
* @param filePath Absolute or relative path to check
|
|
10603
|
-
* @returns true if path is within an allowed workspace
|
|
10604
|
-
*/
|
|
10605
|
-
isPathInWorkspace(filePath) {
|
|
10606
|
-
const absolutePath = path14.isAbsolute(filePath) ? filePath : path14.resolve(this.getPrimaryWorkspace(), filePath);
|
|
10607
|
-
return this.workspaces.some(
|
|
10608
|
-
(workspace) => absolutePath.startsWith(workspace + path14.sep) || absolutePath === workspace
|
|
10609
|
-
);
|
|
10610
|
-
}
|
|
10611
|
-
/**
|
|
10612
|
-
* Resolve a file path across all workspaces
|
|
10613
|
-
* For relative paths: searches all workspaces and returns first match
|
|
10614
|
-
* For absolute paths: validates it's within a workspace
|
|
10615
|
-
* @throws Error if path is outside all workspaces
|
|
10616
|
-
*/
|
|
10617
|
-
resolvePath(filePath) {
|
|
10618
|
-
if (path14.isAbsolute(filePath)) {
|
|
10619
|
-
if (!this.isPathInWorkspace(filePath)) {
|
|
10620
|
-
throw new Error(
|
|
10621
|
-
`Access denied: Path is outside all workspace directories.
|
|
10622
|
-
Path: ${filePath}
|
|
10623
|
-
Workspaces: ${this.workspaces.join(", ")}
|
|
10624
|
-
Use '/directory add <path>' to add the directory to your workspace.`
|
|
10625
|
-
);
|
|
10626
|
-
}
|
|
10627
|
-
return filePath;
|
|
10628
|
-
}
|
|
10629
|
-
const primaryResolved = path14.resolve(this.getPrimaryWorkspace(), filePath);
|
|
10630
|
-
if (fs12.existsSync(primaryResolved)) {
|
|
10631
|
-
return primaryResolved;
|
|
10632
|
-
}
|
|
10633
|
-
for (let i = 1; i < this.workspaces.length; i++) {
|
|
10634
|
-
const candidatePath = path14.resolve(this.workspaces[i], filePath);
|
|
10635
|
-
if (fs12.existsSync(candidatePath)) {
|
|
10636
|
-
return candidatePath;
|
|
10637
|
-
}
|
|
10638
|
-
}
|
|
10639
|
-
return primaryResolved;
|
|
10640
|
-
}
|
|
10641
|
-
/**
|
|
10642
|
-
* Get the workspace that contains a given path
|
|
10643
|
-
* @returns The workspace directory, or null if not in any workspace
|
|
10644
|
-
*/
|
|
10645
|
-
getWorkspaceForPath(filePath) {
|
|
10646
|
-
const absolutePath = path14.isAbsolute(filePath) ? filePath : path14.resolve(this.getPrimaryWorkspace(), filePath);
|
|
10647
|
-
for (const workspace of this.workspaces) {
|
|
10648
|
-
if (absolutePath.startsWith(workspace + path14.sep) || absolutePath === workspace) {
|
|
10649
|
-
return workspace;
|
|
10650
|
-
}
|
|
10651
|
-
}
|
|
10652
|
-
return null;
|
|
10653
|
-
}
|
|
10654
|
-
/**
|
|
10655
|
-
* Check if a path is a forbidden system directory
|
|
10656
|
-
*/
|
|
10657
|
-
static isForbiddenPath(resolvedPath) {
|
|
10658
|
-
if (_WorkspaceManager.FORBIDDEN_PATHS.includes(resolvedPath)) {
|
|
10659
|
-
return true;
|
|
10660
|
-
}
|
|
10661
|
-
return _WorkspaceManager.FORBIDDEN_PATHS.some((forbidden) => resolvedPath.startsWith(forbidden + path14.sep));
|
|
10662
|
-
}
|
|
10663
|
-
/**
|
|
10664
|
-
* Serialize workspace state for storage in session
|
|
10665
|
-
*/
|
|
10666
|
-
toJSON() {
|
|
10667
|
-
return this.getWorkspaces();
|
|
10668
|
-
}
|
|
10669
|
-
/**
|
|
10670
|
-
* Create WorkspaceManager from serialized state
|
|
10671
|
-
*/
|
|
10672
|
-
static fromJSON(workspaces) {
|
|
10673
|
-
return new _WorkspaceManager(workspaces);
|
|
10674
|
-
}
|
|
10675
|
-
};
|
|
10676
|
-
|
|
10677
10208
|
// src/utils/apiUrl.ts
|
|
10678
10209
|
var BIKE4MIND_URL = "https://app.bike4mind.com";
|
|
10679
10210
|
function getApiUrl(configApiConfig) {
|
|
@@ -10690,8 +10221,8 @@ function getEnvironmentName(configApiConfig) {
|
|
|
10690
10221
|
}
|
|
10691
10222
|
|
|
10692
10223
|
// src/utils/contextLoader.ts
|
|
10693
|
-
import * as
|
|
10694
|
-
import * as
|
|
10224
|
+
import * as fs11 from "fs";
|
|
10225
|
+
import * as path13 from "path";
|
|
10695
10226
|
import { homedir as homedir4 } from "os";
|
|
10696
10227
|
var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
|
|
10697
10228
|
var PROJECT_CONTEXT_FILES = [
|
|
@@ -10712,9 +10243,9 @@ function formatFileSize2(bytes) {
|
|
|
10712
10243
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
10713
10244
|
}
|
|
10714
10245
|
function tryReadContextFile(dir, filename, source) {
|
|
10715
|
-
const filePath =
|
|
10246
|
+
const filePath = path13.join(dir, filename);
|
|
10716
10247
|
try {
|
|
10717
|
-
const stats =
|
|
10248
|
+
const stats = fs11.lstatSync(filePath);
|
|
10718
10249
|
if (stats.isDirectory()) {
|
|
10719
10250
|
return null;
|
|
10720
10251
|
}
|
|
@@ -10728,7 +10259,7 @@ function tryReadContextFile(dir, filename, source) {
|
|
|
10728
10259
|
error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
|
|
10729
10260
|
};
|
|
10730
10261
|
}
|
|
10731
|
-
const content =
|
|
10262
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
10732
10263
|
return {
|
|
10733
10264
|
filename,
|
|
10734
10265
|
content,
|
|
@@ -10780,7 +10311,7 @@ ${project.content}`;
|
|
|
10780
10311
|
}
|
|
10781
10312
|
async function loadContextFiles(projectDir) {
|
|
10782
10313
|
const errors = [];
|
|
10783
|
-
const globalDir =
|
|
10314
|
+
const globalDir = path13.join(homedir4(), ".bike4mind");
|
|
10784
10315
|
const projectDirectory = projectDir || process.cwd();
|
|
10785
10316
|
const [globalResult, projectResult] = await Promise.all([
|
|
10786
10317
|
Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
|
|
@@ -10804,8 +10335,8 @@ async function loadContextFiles(projectDir) {
|
|
|
10804
10335
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
10805
10336
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10806
10337
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10807
|
-
import
|
|
10808
|
-
import { existsSync as
|
|
10338
|
+
import path14 from "path";
|
|
10339
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
10809
10340
|
var MCPClient = class {
|
|
10810
10341
|
// Note: This class handles MCP server communication with repository filtering
|
|
10811
10342
|
mcp;
|
|
@@ -10845,18 +10376,18 @@ var MCPClient = class {
|
|
|
10845
10376
|
const root = process.env.INIT_CWD || process.cwd();
|
|
10846
10377
|
const candidatePaths = [
|
|
10847
10378
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
10848
|
-
|
|
10379
|
+
path14.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
10849
10380
|
// When running from SST Lambda deployed environment (/var/task)
|
|
10850
|
-
|
|
10381
|
+
path14.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10851
10382
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
10852
|
-
|
|
10383
|
+
path14.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10853
10384
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
10854
|
-
|
|
10385
|
+
path14.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10855
10386
|
// Original paths (backward compatibility)
|
|
10856
|
-
|
|
10857
|
-
|
|
10387
|
+
path14.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10388
|
+
path14.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
10858
10389
|
];
|
|
10859
|
-
const serverScriptPath = candidatePaths.find((p) =>
|
|
10390
|
+
const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
|
|
10860
10391
|
if (!serverScriptPath) {
|
|
10861
10392
|
const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
10862
10393
|
console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
|
|
@@ -11658,7 +11189,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
11658
11189
|
// package.json
|
|
11659
11190
|
var package_default = {
|
|
11660
11191
|
name: "@bike4mind/cli",
|
|
11661
|
-
version: "0.2.10-feat-
|
|
11192
|
+
version: "0.2.10-feat-explore-subagent-implementation.17245+d73e88b84",
|
|
11662
11193
|
type: "module",
|
|
11663
11194
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
11664
11195
|
license: "UNLICENSED",
|
|
@@ -11726,7 +11257,6 @@ var package_default = {
|
|
|
11726
11257
|
diff: "^8.0.2",
|
|
11727
11258
|
dotenv: "^16.3.1",
|
|
11728
11259
|
"eventsource-parser": "^3.0.6",
|
|
11729
|
-
"fast-glob": "^3.3.3",
|
|
11730
11260
|
"file-type": "^18.7.0",
|
|
11731
11261
|
"fuse.js": "^7.1.0",
|
|
11732
11262
|
ink: "^6.5.1",
|
|
@@ -11762,10 +11292,10 @@ var package_default = {
|
|
|
11762
11292
|
},
|
|
11763
11293
|
devDependencies: {
|
|
11764
11294
|
"@bike4mind/agents": "0.1.0",
|
|
11765
|
-
"@bike4mind/common": "2.39.1-feat-
|
|
11766
|
-
"@bike4mind/mcp": "1.20.4-feat-
|
|
11767
|
-
"@bike4mind/services": "2.34.2-feat-
|
|
11768
|
-
"@bike4mind/utils": "2.1.4-feat-
|
|
11295
|
+
"@bike4mind/common": "2.39.1-feat-explore-subagent-implementation.17245+d73e88b84",
|
|
11296
|
+
"@bike4mind/mcp": "1.20.4-feat-explore-subagent-implementation.17245+d73e88b84",
|
|
11297
|
+
"@bike4mind/services": "2.34.2-feat-explore-subagent-implementation.17245+d73e88b84",
|
|
11298
|
+
"@bike4mind/utils": "2.1.4-feat-explore-subagent-implementation.17245+d73e88b84",
|
|
11769
11299
|
"@types/better-sqlite3": "^7.6.13",
|
|
11770
11300
|
"@types/diff": "^5.0.9",
|
|
11771
11301
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -11778,7 +11308,7 @@ var package_default = {
|
|
|
11778
11308
|
typescript: "^5.9.3",
|
|
11779
11309
|
vitest: "^3.2.4"
|
|
11780
11310
|
},
|
|
11781
|
-
gitHead: "
|
|
11311
|
+
gitHead: "d73e88b84cc88ea33861cf5270ee1e23eb953ed1"
|
|
11782
11312
|
};
|
|
11783
11313
|
|
|
11784
11314
|
// src/config/constants.ts
|
|
@@ -11786,6 +11316,331 @@ var USAGE_DAYS = 30;
|
|
|
11786
11316
|
var MODEL_NAME_COLUMN_WIDTH = 18;
|
|
11787
11317
|
var USAGE_CACHE_TTL = 5 * 60 * 1e3;
|
|
11788
11318
|
|
|
11319
|
+
// src/agents/SubagentOrchestrator.ts
|
|
11320
|
+
var SubagentOrchestrator = class {
|
|
11321
|
+
constructor(deps) {
|
|
11322
|
+
this.deps = deps;
|
|
11323
|
+
}
|
|
11324
|
+
/**
|
|
11325
|
+
* Delegate a task to a specialized subagent
|
|
11326
|
+
*
|
|
11327
|
+
* @param options - Configuration for subagent execution
|
|
11328
|
+
* @returns Subagent result with summary
|
|
11329
|
+
*/
|
|
11330
|
+
async delegateToSubagent(options) {
|
|
11331
|
+
const { task, type, thoroughness, parentSessionId, config: configOverride } = options;
|
|
11332
|
+
const baseConfig = this.deps.subagentConfigs.get(type);
|
|
11333
|
+
if (!baseConfig) {
|
|
11334
|
+
throw new Error(`No configuration found for subagent type: ${type}`);
|
|
11335
|
+
}
|
|
11336
|
+
const config = {
|
|
11337
|
+
...baseConfig,
|
|
11338
|
+
...configOverride,
|
|
11339
|
+
type
|
|
11340
|
+
};
|
|
11341
|
+
const model = config.model || "claude-3-5-haiku-20241022";
|
|
11342
|
+
const maxIterations = this.getMaxIterations(config, thoroughness);
|
|
11343
|
+
const toolFilter = {
|
|
11344
|
+
allowedTools: config.allowedTools,
|
|
11345
|
+
deniedTools: config.deniedTools
|
|
11346
|
+
};
|
|
11347
|
+
const agentContext = {
|
|
11348
|
+
currentAgent: null,
|
|
11349
|
+
observationQueue: []
|
|
11350
|
+
};
|
|
11351
|
+
const { tools: tools2, agentContext: updatedContext } = generateCliTools(
|
|
11352
|
+
this.deps.userId,
|
|
11353
|
+
this.deps.llm,
|
|
11354
|
+
model,
|
|
11355
|
+
this.deps.permissionManager,
|
|
11356
|
+
this.deps.showPermissionPrompt,
|
|
11357
|
+
agentContext,
|
|
11358
|
+
this.deps.configStore,
|
|
11359
|
+
this.deps.apiClient,
|
|
11360
|
+
toolFilter
|
|
11361
|
+
);
|
|
11362
|
+
this.deps.logger.debug(`Spawning ${type} subagent with ${tools2.length} tools, thoroughness: ${thoroughness}`);
|
|
11363
|
+
const subagent = new ReActAgent({
|
|
11364
|
+
userId: this.deps.userId,
|
|
11365
|
+
logger: this.deps.logger,
|
|
11366
|
+
llm: this.deps.llm,
|
|
11367
|
+
model,
|
|
11368
|
+
tools: tools2,
|
|
11369
|
+
maxIterations,
|
|
11370
|
+
systemPrompt: config.systemPrompt || this.getDefaultSystemPrompt(type)
|
|
11371
|
+
});
|
|
11372
|
+
updatedContext.currentAgent = subagent;
|
|
11373
|
+
const startTime = Date.now();
|
|
11374
|
+
const result = await subagent.run(task, {
|
|
11375
|
+
maxIterations
|
|
11376
|
+
});
|
|
11377
|
+
const duration = Date.now() - startTime;
|
|
11378
|
+
this.deps.logger.debug(
|
|
11379
|
+
`Subagent completed in ${duration}ms, ${result.completionInfo.iterations} iterations, ${result.completionInfo.totalTokens} tokens`
|
|
11380
|
+
);
|
|
11381
|
+
const summary = this.summarizeResult(result, type);
|
|
11382
|
+
const subagentResult = {
|
|
11383
|
+
...result,
|
|
11384
|
+
subagentType: type,
|
|
11385
|
+
thoroughness,
|
|
11386
|
+
summary,
|
|
11387
|
+
parentSessionId
|
|
11388
|
+
};
|
|
11389
|
+
return subagentResult;
|
|
11390
|
+
}
|
|
11391
|
+
/**
|
|
11392
|
+
* Get max iterations based on thoroughness and config
|
|
11393
|
+
*/
|
|
11394
|
+
getMaxIterations(config, thoroughness) {
|
|
11395
|
+
const defaults = {
|
|
11396
|
+
quick: 2,
|
|
11397
|
+
medium: 5,
|
|
11398
|
+
very_thorough: 10
|
|
11399
|
+
};
|
|
11400
|
+
const configIterations = config.maxIterations || defaults;
|
|
11401
|
+
return configIterations[thoroughness];
|
|
11402
|
+
}
|
|
11403
|
+
/**
|
|
11404
|
+
* Get default system prompt for subagent type
|
|
11405
|
+
*/
|
|
11406
|
+
getDefaultSystemPrompt(type) {
|
|
11407
|
+
switch (type) {
|
|
11408
|
+
case "explore":
|
|
11409
|
+
return `You are a code exploration specialist. Your job is to search and analyze codebases efficiently.
|
|
11410
|
+
|
|
11411
|
+
Focus on:
|
|
11412
|
+
- Finding relevant files and functions
|
|
11413
|
+
- Understanding code structure and patterns
|
|
11414
|
+
- Providing clear, concise summaries
|
|
11415
|
+
|
|
11416
|
+
You have read-only access. Use file_read, grep_search, and glob_files to explore.
|
|
11417
|
+
|
|
11418
|
+
When you find what you're looking for, provide a clear summary including:
|
|
11419
|
+
1. What you found (files, functions, patterns)
|
|
11420
|
+
2. Key insights or observations
|
|
11421
|
+
3. Relevant code locations
|
|
11422
|
+
|
|
11423
|
+
Be thorough but concise. Your summary will be used by the main agent.`;
|
|
11424
|
+
case "plan":
|
|
11425
|
+
return `You are a task planning specialist. Your job is to break down complex tasks into clear, actionable steps.
|
|
11426
|
+
|
|
11427
|
+
Focus on:
|
|
11428
|
+
- Identifying dependencies and blockers
|
|
11429
|
+
- Creating logical sequence of steps
|
|
11430
|
+
- Estimating scope and priorities
|
|
11431
|
+
|
|
11432
|
+
Provide a structured plan that the main agent can execute.`;
|
|
11433
|
+
case "review":
|
|
11434
|
+
return `You are a code review specialist. Your job is to analyze code quality and identify issues.
|
|
11435
|
+
|
|
11436
|
+
Focus on:
|
|
11437
|
+
- Code quality and best practices
|
|
11438
|
+
- Potential bugs and edge cases
|
|
11439
|
+
- Performance and security considerations
|
|
11440
|
+
|
|
11441
|
+
Provide actionable feedback with specific file and line references.`;
|
|
11442
|
+
default:
|
|
11443
|
+
return "You are a helpful AI assistant.";
|
|
11444
|
+
}
|
|
11445
|
+
}
|
|
11446
|
+
/**
|
|
11447
|
+
* Summarize subagent result for parent agent
|
|
11448
|
+
*/
|
|
11449
|
+
summarizeResult(result, type) {
|
|
11450
|
+
const { finalAnswer, steps, completionInfo } = result;
|
|
11451
|
+
const toolCalls = steps.filter((s) => s.type === "action");
|
|
11452
|
+
const filesRead = toolCalls.filter((s) => s.metadata?.toolName === "file_read").length;
|
|
11453
|
+
const searches = toolCalls.filter((s) => s.metadata?.toolName === "grep_search").length;
|
|
11454
|
+
const globs = toolCalls.filter((s) => s.metadata?.toolName === "glob_files").length;
|
|
11455
|
+
let summary = `**${type.charAt(0).toUpperCase() + type.slice(1)} Subagent Results**
|
|
11456
|
+
|
|
11457
|
+
`;
|
|
11458
|
+
summary += `*Execution: ${completionInfo.iterations} iterations, ${completionInfo.toolCalls} tool calls*
|
|
11459
|
+
|
|
11460
|
+
`;
|
|
11461
|
+
if (type === "explore") {
|
|
11462
|
+
summary += `*Exploration: ${filesRead} files read, ${searches} searches, ${globs} glob patterns*
|
|
11463
|
+
|
|
11464
|
+
`;
|
|
11465
|
+
}
|
|
11466
|
+
const maxLength = 1e3;
|
|
11467
|
+
if (finalAnswer.length > maxLength) {
|
|
11468
|
+
summary += finalAnswer.slice(0, maxLength) + "\n\n...(truncated)";
|
|
11469
|
+
} else {
|
|
11470
|
+
summary += finalAnswer;
|
|
11471
|
+
}
|
|
11472
|
+
return summary;
|
|
11473
|
+
}
|
|
11474
|
+
};
|
|
11475
|
+
|
|
11476
|
+
// src/agents/configs.ts
|
|
11477
|
+
var EXPLORE_CONFIG = {
|
|
11478
|
+
type: "explore",
|
|
11479
|
+
model: "claude-3-5-haiku-20241022",
|
|
11480
|
+
systemPrompt: `You are a code exploration specialist. Your job is to search and analyze codebases efficiently.
|
|
11481
|
+
|
|
11482
|
+
Focus on:
|
|
11483
|
+
- Finding relevant files and functions
|
|
11484
|
+
- Understanding code structure and patterns
|
|
11485
|
+
- Providing clear, concise summaries
|
|
11486
|
+
|
|
11487
|
+
You have read-only access. Use file_read, grep_search, and glob_files to explore.
|
|
11488
|
+
|
|
11489
|
+
When you find what you're looking for, provide a clear summary including:
|
|
11490
|
+
1. What you found (files, functions, patterns)
|
|
11491
|
+
2. Key insights or observations
|
|
11492
|
+
3. Relevant code locations
|
|
11493
|
+
|
|
11494
|
+
Be thorough but concise. Your summary will be used by the main agent.`,
|
|
11495
|
+
allowedTools: [
|
|
11496
|
+
"file_read",
|
|
11497
|
+
"grep_search",
|
|
11498
|
+
"glob_files",
|
|
11499
|
+
"bash_execute",
|
|
11500
|
+
// Only for read-only commands like ls, cat, find
|
|
11501
|
+
"current_datetime",
|
|
11502
|
+
"math_evaluate"
|
|
11503
|
+
],
|
|
11504
|
+
deniedTools: [
|
|
11505
|
+
"create_file",
|
|
11506
|
+
"edit_file",
|
|
11507
|
+
"delete_file",
|
|
11508
|
+
"web_search",
|
|
11509
|
+
"weather_info",
|
|
11510
|
+
"blog_publish",
|
|
11511
|
+
"blog_edit",
|
|
11512
|
+
"blog_draft"
|
|
11513
|
+
],
|
|
11514
|
+
maxIterations: {
|
|
11515
|
+
quick: 2,
|
|
11516
|
+
medium: 5,
|
|
11517
|
+
very_thorough: 10
|
|
11518
|
+
},
|
|
11519
|
+
defaultThoroughness: "medium"
|
|
11520
|
+
};
|
|
11521
|
+
var PLAN_CONFIG = {
|
|
11522
|
+
type: "plan",
|
|
11523
|
+
model: "claude-3-5-haiku-20241022",
|
|
11524
|
+
systemPrompt: `You are a task planning specialist. Your job is to break down complex tasks into clear, actionable steps.
|
|
11525
|
+
|
|
11526
|
+
Focus on:
|
|
11527
|
+
- Identifying dependencies and blockers
|
|
11528
|
+
- Creating logical sequence of steps
|
|
11529
|
+
- Estimating scope and priorities
|
|
11530
|
+
|
|
11531
|
+
You can explore the codebase to understand the current architecture before planning.
|
|
11532
|
+
|
|
11533
|
+
Provide a structured plan that the main agent can execute.`,
|
|
11534
|
+
allowedTools: ["file_read", "grep_search", "glob_files", "bash_execute", "current_datetime", "math_evaluate"],
|
|
11535
|
+
deniedTools: ["create_file", "edit_file", "delete_file", "web_search", "weather_info"],
|
|
11536
|
+
maxIterations: {
|
|
11537
|
+
quick: 3,
|
|
11538
|
+
medium: 7,
|
|
11539
|
+
very_thorough: 12
|
|
11540
|
+
},
|
|
11541
|
+
defaultThoroughness: "medium"
|
|
11542
|
+
};
|
|
11543
|
+
var REVIEW_CONFIG = {
|
|
11544
|
+
type: "review",
|
|
11545
|
+
model: "claude-3-5-sonnet-20241022",
|
|
11546
|
+
// Use Sonnet for better reasoning
|
|
11547
|
+
systemPrompt: `You are a code review specialist. Your job is to analyze code quality and identify issues.
|
|
11548
|
+
|
|
11549
|
+
Focus on:
|
|
11550
|
+
- Code quality and best practices
|
|
11551
|
+
- Potential bugs and edge cases
|
|
11552
|
+
- Performance and security considerations
|
|
11553
|
+
|
|
11554
|
+
You have read-only access to analyze code.
|
|
11555
|
+
|
|
11556
|
+
Provide actionable feedback with specific file and line references.`,
|
|
11557
|
+
allowedTools: ["file_read", "grep_search", "glob_files", "bash_execute", "current_datetime"],
|
|
11558
|
+
deniedTools: ["create_file", "edit_file", "delete_file", "web_search", "weather_info"],
|
|
11559
|
+
maxIterations: {
|
|
11560
|
+
quick: 3,
|
|
11561
|
+
medium: 8,
|
|
11562
|
+
very_thorough: 15
|
|
11563
|
+
},
|
|
11564
|
+
defaultThoroughness: "medium"
|
|
11565
|
+
};
|
|
11566
|
+
function getDefaultSubagentConfigs() {
|
|
11567
|
+
return /* @__PURE__ */ new Map([
|
|
11568
|
+
["explore", EXPLORE_CONFIG],
|
|
11569
|
+
["plan", PLAN_CONFIG],
|
|
11570
|
+
["review", REVIEW_CONFIG]
|
|
11571
|
+
]);
|
|
11572
|
+
}
|
|
11573
|
+
|
|
11574
|
+
// src/agents/delegateTool.ts
|
|
11575
|
+
function createSubagentDelegateTool(orchestrator, parentSessionId) {
|
|
11576
|
+
return {
|
|
11577
|
+
toolFn: async (args) => {
|
|
11578
|
+
const params = args;
|
|
11579
|
+
if (!params.task) {
|
|
11580
|
+
throw new Error("subagent_delegate: task parameter is required");
|
|
11581
|
+
}
|
|
11582
|
+
if (!params.type) {
|
|
11583
|
+
throw new Error("subagent_delegate: type parameter is required");
|
|
11584
|
+
}
|
|
11585
|
+
const thoroughness = params.thoroughness || "medium";
|
|
11586
|
+
const type = params.type;
|
|
11587
|
+
const result = await orchestrator.delegateToSubagent({
|
|
11588
|
+
task: params.task,
|
|
11589
|
+
type,
|
|
11590
|
+
thoroughness,
|
|
11591
|
+
parentSessionId
|
|
11592
|
+
});
|
|
11593
|
+
return result.summary;
|
|
11594
|
+
},
|
|
11595
|
+
toolSchema: {
|
|
11596
|
+
name: "subagent_delegate",
|
|
11597
|
+
description: `Delegate a task to a specialized subagent for focused work.
|
|
11598
|
+
|
|
11599
|
+
**When to use this tool:**
|
|
11600
|
+
- **Explore**: When you need to search through the codebase, find files, or understand code structure (read-only)
|
|
11601
|
+
- **Plan**: When you need to break down a complex task into actionable steps
|
|
11602
|
+
- **Review**: When you need to analyze code quality and identify potential issues
|
|
11603
|
+
|
|
11604
|
+
**Benefits:**
|
|
11605
|
+
- Keeps main conversation focused and clean
|
|
11606
|
+
- Uses specialized prompts optimized for each task type
|
|
11607
|
+
- Faster execution with appropriate models (Haiku for explore/plan, Sonnet for review)
|
|
11608
|
+
|
|
11609
|
+
**Example uses:**
|
|
11610
|
+
- "Find all files that use the authentication system" \u2192 explore
|
|
11611
|
+
- "Search for components that handle user input" \u2192 explore
|
|
11612
|
+
- "Break down implementing a new feature into steps" \u2192 plan
|
|
11613
|
+
- "Review this module for potential bugs" \u2192 review`,
|
|
11614
|
+
parameters: {
|
|
11615
|
+
type: "object",
|
|
11616
|
+
properties: {
|
|
11617
|
+
task: {
|
|
11618
|
+
type: "string",
|
|
11619
|
+
description: "Clear description of what you want the subagent to do. Be specific about what you're looking for or what needs to be accomplished."
|
|
11620
|
+
},
|
|
11621
|
+
type: {
|
|
11622
|
+
type: "string",
|
|
11623
|
+
enum: ["explore", "plan", "review"],
|
|
11624
|
+
description: `Type of subagent to use:
|
|
11625
|
+
- explore: Read-only codebase exploration and search (fast, uses Haiku)
|
|
11626
|
+
- plan: Task breakdown and planning (uses Haiku)
|
|
11627
|
+
- review: Code quality analysis and review (uses Sonnet for better reasoning)`
|
|
11628
|
+
},
|
|
11629
|
+
thoroughness: {
|
|
11630
|
+
type: "string",
|
|
11631
|
+
enum: ["quick", "medium", "very_thorough"],
|
|
11632
|
+
description: `How thoroughly to execute:
|
|
11633
|
+
- quick: Fast lookup, 1-2 iterations
|
|
11634
|
+
- medium: Balanced exploration, 3-5 iterations (default)
|
|
11635
|
+
- very_thorough: Comprehensive analysis, 8-10 iterations`
|
|
11636
|
+
}
|
|
11637
|
+
},
|
|
11638
|
+
required: ["task", "type"]
|
|
11639
|
+
}
|
|
11640
|
+
}
|
|
11641
|
+
};
|
|
11642
|
+
}
|
|
11643
|
+
|
|
11789
11644
|
// src/index.tsx
|
|
11790
11645
|
process.removeAllListeners("warning");
|
|
11791
11646
|
process.on("warning", (warning) => {
|
|
@@ -11800,19 +11655,6 @@ var usageCache = null;
|
|
|
11800
11655
|
function CliApp() {
|
|
11801
11656
|
const { exit } = useApp();
|
|
11802
11657
|
const imageRenderer = new ImageRenderer();
|
|
11803
|
-
const getInitialWorkspaces = () => {
|
|
11804
|
-
const workspaces = [process.cwd()];
|
|
11805
|
-
const addDirsEnv = process.env.B4M_ADD_DIRS;
|
|
11806
|
-
if (addDirsEnv) {
|
|
11807
|
-
try {
|
|
11808
|
-
const additionalDirs = JSON.parse(addDirsEnv);
|
|
11809
|
-
workspaces.push(...additionalDirs);
|
|
11810
|
-
} catch (error) {
|
|
11811
|
-
logger.warn(`Failed to parse B4M_ADD_DIRS environment variable: ${error}`);
|
|
11812
|
-
}
|
|
11813
|
-
}
|
|
11814
|
-
return workspaces;
|
|
11815
|
-
};
|
|
11816
11658
|
const [state, setState] = useState8({
|
|
11817
11659
|
session: null,
|
|
11818
11660
|
sessionStore: new SessionStore(),
|
|
@@ -11825,7 +11667,6 @@ function CliApp() {
|
|
|
11825
11667
|
agent: null,
|
|
11826
11668
|
mcpManager: null,
|
|
11827
11669
|
permissionManager: null,
|
|
11828
|
-
workspaceManager: new WorkspaceManager(getInitialWorkspaces()),
|
|
11829
11670
|
permissionPrompt: null,
|
|
11830
11671
|
trustLocationSelector: null,
|
|
11831
11672
|
rewindSelector: null,
|
|
@@ -11930,8 +11771,7 @@ function CliApp() {
|
|
|
11930
11771
|
totalTokens: 0,
|
|
11931
11772
|
totalCost: 0,
|
|
11932
11773
|
toolCallCount: 0
|
|
11933
|
-
}
|
|
11934
|
-
workingDirectories: state.workspaceManager.getWorkspaces()
|
|
11774
|
+
}
|
|
11935
11775
|
};
|
|
11936
11776
|
setState((prev) => ({
|
|
11937
11777
|
...prev,
|
|
@@ -11976,8 +11816,7 @@ function CliApp() {
|
|
|
11976
11816
|
totalTokens: 0,
|
|
11977
11817
|
totalCost: 0,
|
|
11978
11818
|
toolCallCount: 0
|
|
11979
|
-
}
|
|
11980
|
-
workingDirectories: state.workspaceManager.getWorkspaces()
|
|
11819
|
+
}
|
|
11981
11820
|
};
|
|
11982
11821
|
await logger.initialize(newSession.id);
|
|
11983
11822
|
logger.setVerbose(process.env.B4M_VERBOSE === "1");
|
|
@@ -12024,7 +11863,6 @@ function CliApp() {
|
|
|
12024
11863
|
llm,
|
|
12025
11864
|
modelInfo.id,
|
|
12026
11865
|
permissionManager,
|
|
12027
|
-
state.workspaceManager,
|
|
12028
11866
|
promptFn,
|
|
12029
11867
|
agentContext,
|
|
12030
11868
|
state.configStore,
|
|
@@ -12040,7 +11878,34 @@ function CliApp() {
|
|
|
12040
11878
|
console.log(` \u{1F4E1} ${serverName}: ${count} tool(s)`);
|
|
12041
11879
|
});
|
|
12042
11880
|
}
|
|
12043
|
-
const
|
|
11881
|
+
const subagentConfigs = getDefaultSubagentConfigs();
|
|
11882
|
+
if (config.subagents) {
|
|
11883
|
+
if (config.subagents.explore) {
|
|
11884
|
+
const currentConfig = subagentConfigs.get("explore");
|
|
11885
|
+
subagentConfigs.set("explore", { ...currentConfig, ...config.subagents.explore });
|
|
11886
|
+
}
|
|
11887
|
+
if (config.subagents.plan) {
|
|
11888
|
+
const currentConfig = subagentConfigs.get("plan");
|
|
11889
|
+
subagentConfigs.set("plan", { ...currentConfig, ...config.subagents.plan });
|
|
11890
|
+
}
|
|
11891
|
+
if (config.subagents.review) {
|
|
11892
|
+
const currentConfig = subagentConfigs.get("review");
|
|
11893
|
+
subagentConfigs.set("review", { ...currentConfig, ...config.subagents.review });
|
|
11894
|
+
}
|
|
11895
|
+
}
|
|
11896
|
+
const orchestrator = new SubagentOrchestrator({
|
|
11897
|
+
userId: config.userId,
|
|
11898
|
+
llm,
|
|
11899
|
+
logger: silentLogger,
|
|
11900
|
+
permissionManager,
|
|
11901
|
+
showPermissionPrompt: promptFn,
|
|
11902
|
+
configStore: state.configStore,
|
|
11903
|
+
apiClient,
|
|
11904
|
+
subagentConfigs
|
|
11905
|
+
});
|
|
11906
|
+
const subagentDelegateTool = createSubagentDelegateTool(orchestrator, newSession.id);
|
|
11907
|
+
const allTools = [...b4mTools, ...mcpTools, subagentDelegateTool];
|
|
11908
|
+
console.log(`\u{1F916} Subagent delegation enabled (explore, plan, review)`);
|
|
12044
11909
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
12045
11910
|
const contextResult = await loadContextFiles(projectDir);
|
|
12046
11911
|
if (contextResult.globalContext) {
|
|
@@ -12077,6 +11942,15 @@ FOR CODING TASKS:
|
|
|
12077
11942
|
- When searching for code: Use grep_search or glob_files to find relevant files
|
|
12078
11943
|
- Permission system will ask for approval before any file writes
|
|
12079
11944
|
|
|
11945
|
+
SUBAGENT DELEGATION:
|
|
11946
|
+
- You have access to specialized subagents via the subagent_delegate tool
|
|
11947
|
+
- Use subagents for focused exploration, planning, or review tasks:
|
|
11948
|
+
* explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
|
|
11949
|
+
* plan: Break down complex tasks into actionable steps
|
|
11950
|
+
* review: Analyze code quality and identify issues
|
|
11951
|
+
- Subagents keep the main conversation clean and run faster with optimized models
|
|
11952
|
+
- Delegate when you need to search extensively or analyze code structure
|
|
11953
|
+
|
|
12080
11954
|
FOR GENERAL TASKS:
|
|
12081
11955
|
- Use available tools to get information (weather, web search, calculations, etc.)
|
|
12082
11956
|
- When user asks follow-up questions, use conversation context to understand what they're referring to
|
|
@@ -12087,6 +11961,7 @@ EXAMPLES:
|
|
|
12087
11961
|
- "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
|
|
12088
11962
|
- "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
|
|
12089
11963
|
- "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
|
|
11964
|
+
- "find all components using React hooks" \u2192 subagent_delegate(task="find all components using React hooks", type="explore")
|
|
12090
11965
|
|
|
12091
11966
|
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
12092
11967
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
@@ -12365,11 +12240,6 @@ Tool Permissions:
|
|
|
12365
12240
|
/untrust <tool-name> - Remove tool from trusted list
|
|
12366
12241
|
/trusted - List all trusted tools
|
|
12367
12242
|
|
|
12368
|
-
Workspace Management:
|
|
12369
|
-
/directory show - Show all workspace directories
|
|
12370
|
-
/directory add <path> - Add directory to workspace
|
|
12371
|
-
/directory remove <path> - Remove directory from workspace
|
|
12372
|
-
|
|
12373
12243
|
Project Configuration:
|
|
12374
12244
|
/project-config - Show merged project configuration
|
|
12375
12245
|
`);
|
|
@@ -12411,24 +12281,7 @@ Project Configuration:
|
|
|
12411
12281
|
}
|
|
12412
12282
|
await logger.initialize(loadedSession.id);
|
|
12413
12283
|
logger.debug("=== Session Resumed ===");
|
|
12414
|
-
|
|
12415
|
-
try {
|
|
12416
|
-
const restoredWorkspaceManager = WorkspaceManager.fromJSON(loadedSession.workingDirectories);
|
|
12417
|
-
setState((prev) => ({
|
|
12418
|
-
...prev,
|
|
12419
|
-
session: loadedSession,
|
|
12420
|
-
workspaceManager: restoredWorkspaceManager
|
|
12421
|
-
}));
|
|
12422
|
-
console.log(
|
|
12423
|
-
`\u{1F4C1} Restored ${loadedSession.workingDirectories.length} workspace director${loadedSession.workingDirectories.length !== 1 ? "ies" : "y"}`
|
|
12424
|
-
);
|
|
12425
|
-
} catch (error) {
|
|
12426
|
-
logger.warn(`Failed to restore workspace directories from session: ${error}`);
|
|
12427
|
-
setState((prev) => ({ ...prev, session: loadedSession }));
|
|
12428
|
-
}
|
|
12429
|
-
} else {
|
|
12430
|
-
setState((prev) => ({ ...prev, session: loadedSession }));
|
|
12431
|
-
}
|
|
12284
|
+
setState((prev) => ({ ...prev, session: loadedSession }));
|
|
12432
12285
|
setStoreSession(loadedSession);
|
|
12433
12286
|
useCliStore.getState().clearAgentSteps();
|
|
12434
12287
|
useCliStore.getState().clearPendingMessages();
|
|
@@ -12624,74 +12477,6 @@ Project Configuration:
|
|
|
12624
12477
|
}
|
|
12625
12478
|
console.log("");
|
|
12626
12479
|
break;
|
|
12627
|
-
case "directory": {
|
|
12628
|
-
const subcommand = args[0];
|
|
12629
|
-
if (!subcommand || subcommand === "show") {
|
|
12630
|
-
const workspaces = state.workspaceManager.getWorkspaces();
|
|
12631
|
-
console.log("\n\u{1F4C1} Workspace Directories:\n");
|
|
12632
|
-
workspaces.forEach((dir, index) => {
|
|
12633
|
-
const label = index === 0 ? " (primary)" : "";
|
|
12634
|
-
console.log(` ${index + 1}. ${dir}${label}`);
|
|
12635
|
-
});
|
|
12636
|
-
console.log("");
|
|
12637
|
-
break;
|
|
12638
|
-
}
|
|
12639
|
-
if (subcommand === "add") {
|
|
12640
|
-
const dirPath = args[1];
|
|
12641
|
-
if (!dirPath) {
|
|
12642
|
-
console.log("Usage: /directory add <path>");
|
|
12643
|
-
console.log("Example: /directory add ../other-project");
|
|
12644
|
-
break;
|
|
12645
|
-
}
|
|
12646
|
-
try {
|
|
12647
|
-
state.workspaceManager.addWorkspace(dirPath);
|
|
12648
|
-
if (state.session) {
|
|
12649
|
-
const updatedSession = {
|
|
12650
|
-
...state.session,
|
|
12651
|
-
workingDirectories: state.workspaceManager.getWorkspaces()
|
|
12652
|
-
};
|
|
12653
|
-
setState((prev) => ({ ...prev, session: updatedSession }));
|
|
12654
|
-
await state.sessionStore.save(updatedSession);
|
|
12655
|
-
}
|
|
12656
|
-
console.log(`\u2705 Added directory to workspace: ${dirPath}`);
|
|
12657
|
-
console.log(`\u{1F4C1} Workspace now has ${state.workspaceManager.getWorkspaces().length} directories`);
|
|
12658
|
-
} catch (error) {
|
|
12659
|
-
console.log(`\u274C Failed to add directory: ${error.message}`);
|
|
12660
|
-
}
|
|
12661
|
-
break;
|
|
12662
|
-
}
|
|
12663
|
-
if (subcommand === "remove") {
|
|
12664
|
-
const dirPath = args[1];
|
|
12665
|
-
if (!dirPath) {
|
|
12666
|
-
console.log("Usage: /directory remove <path>");
|
|
12667
|
-
console.log("Example: /directory remove ../other-project");
|
|
12668
|
-
break;
|
|
12669
|
-
}
|
|
12670
|
-
try {
|
|
12671
|
-
state.workspaceManager.removeWorkspace(dirPath);
|
|
12672
|
-
if (state.session) {
|
|
12673
|
-
const updatedSession = {
|
|
12674
|
-
...state.session,
|
|
12675
|
-
workingDirectories: state.workspaceManager.getWorkspaces()
|
|
12676
|
-
};
|
|
12677
|
-
setState((prev) => ({ ...prev, session: updatedSession }));
|
|
12678
|
-
await state.sessionStore.save(updatedSession);
|
|
12679
|
-
}
|
|
12680
|
-
console.log(`\u2705 Removed directory from workspace: ${dirPath}`);
|
|
12681
|
-
console.log(
|
|
12682
|
-
`\u{1F4C1} Workspace now has ${state.workspaceManager.getWorkspaces().length} director${state.workspaceManager.getWorkspaces().length !== 1 ? "ies" : "y"}`
|
|
12683
|
-
);
|
|
12684
|
-
} catch (error) {
|
|
12685
|
-
console.log(`\u274C Failed to remove directory: ${error.message}`);
|
|
12686
|
-
}
|
|
12687
|
-
break;
|
|
12688
|
-
}
|
|
12689
|
-
console.log("Unknown subcommand. Usage:");
|
|
12690
|
-
console.log(" /directory show - Show all workspace directories");
|
|
12691
|
-
console.log(" /directory add <path> - Add directory to workspace");
|
|
12692
|
-
console.log(" /directory remove <path> - Remove directory from workspace");
|
|
12693
|
-
break;
|
|
12694
|
-
}
|
|
12695
12480
|
case "login":
|
|
12696
12481
|
setState((prev) => ({ ...prev, showLoginFlow: true }));
|
|
12697
12482
|
break;
|
|
@@ -12728,8 +12513,7 @@ Project Configuration:
|
|
|
12728
12513
|
totalTokens: 0,
|
|
12729
12514
|
totalCost: 0,
|
|
12730
12515
|
toolCallCount: 0
|
|
12731
|
-
}
|
|
12732
|
-
workingDirectories: state.workspaceManager.getWorkspaces()
|
|
12516
|
+
}
|
|
12733
12517
|
};
|
|
12734
12518
|
await logger.initialize(newSession.id);
|
|
12735
12519
|
logger.debug("=== New Session Started via /clear ===");
|