@bike4mind/cli 0.2.7-feat-cli-tool-lambda-v2.17129 → 0.2.7-feat-organization-overview-enhancements.17130
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/index.js +295 -355
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -8763,338 +8763,6 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
8763
8763
|
}
|
|
8764
8764
|
}
|
|
8765
8765
|
|
|
8766
|
-
// src/utils/Logger.ts
|
|
8767
|
-
import fs10 from "fs/promises";
|
|
8768
|
-
import path11 from "path";
|
|
8769
|
-
import os from "os";
|
|
8770
|
-
var Logger2 = class _Logger {
|
|
8771
|
-
constructor() {
|
|
8772
|
-
this.logFilePath = null;
|
|
8773
|
-
this.sessionId = null;
|
|
8774
|
-
this.fileLoggingEnabled = true;
|
|
8775
|
-
this.consoleVerbose = false;
|
|
8776
|
-
}
|
|
8777
|
-
static {
|
|
8778
|
-
this.instance = null;
|
|
8779
|
-
}
|
|
8780
|
-
static getInstance() {
|
|
8781
|
-
if (!_Logger.instance) {
|
|
8782
|
-
_Logger.instance = new _Logger();
|
|
8783
|
-
}
|
|
8784
|
-
return _Logger.instance;
|
|
8785
|
-
}
|
|
8786
|
-
/**
|
|
8787
|
-
* Initialize the logger with a session ID
|
|
8788
|
-
*/
|
|
8789
|
-
async initialize(sessionId) {
|
|
8790
|
-
this.sessionId = sessionId;
|
|
8791
|
-
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
8792
|
-
await fs10.mkdir(debugDir, { recursive: true });
|
|
8793
|
-
this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
|
|
8794
|
-
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
8795
|
-
}
|
|
8796
|
-
/**
|
|
8797
|
-
* Set whether verbose console logging is enabled
|
|
8798
|
-
*/
|
|
8799
|
-
setVerbose(enabled) {
|
|
8800
|
-
this.consoleVerbose = enabled;
|
|
8801
|
-
}
|
|
8802
|
-
/**
|
|
8803
|
-
* Set whether file logging is enabled
|
|
8804
|
-
*/
|
|
8805
|
-
setFileLoggingEnabled(enabled) {
|
|
8806
|
-
this.fileLoggingEnabled = enabled;
|
|
8807
|
-
}
|
|
8808
|
-
/**
|
|
8809
|
-
* DEBUG level - verbose-only console, always file
|
|
8810
|
-
*/
|
|
8811
|
-
debug(message) {
|
|
8812
|
-
this.writeToFile("DEBUG", message).catch(() => {
|
|
8813
|
-
});
|
|
8814
|
-
if (this.consoleVerbose) {
|
|
8815
|
-
console.log(message);
|
|
8816
|
-
}
|
|
8817
|
-
}
|
|
8818
|
-
/**
|
|
8819
|
-
* INFO level - always shown to user
|
|
8820
|
-
*/
|
|
8821
|
-
info(message) {
|
|
8822
|
-
this.writeToFile("INFO", message).catch(() => {
|
|
8823
|
-
});
|
|
8824
|
-
console.log(message);
|
|
8825
|
-
}
|
|
8826
|
-
/**
|
|
8827
|
-
* WARN level - always shown to user
|
|
8828
|
-
*/
|
|
8829
|
-
warn(message) {
|
|
8830
|
-
this.writeToFile("WARN", message).catch(() => {
|
|
8831
|
-
});
|
|
8832
|
-
console.warn(message);
|
|
8833
|
-
}
|
|
8834
|
-
/**
|
|
8835
|
-
* ERROR level - always shown to user
|
|
8836
|
-
*/
|
|
8837
|
-
error(message, err) {
|
|
8838
|
-
this.writeToFile("ERROR", message).catch(() => {
|
|
8839
|
-
});
|
|
8840
|
-
if (err) {
|
|
8841
|
-
this.logErrorDetailsToFile(err).catch(() => {
|
|
8842
|
-
});
|
|
8843
|
-
}
|
|
8844
|
-
console.error(message);
|
|
8845
|
-
}
|
|
8846
|
-
/**
|
|
8847
|
-
* Write log entry to file
|
|
8848
|
-
*/
|
|
8849
|
-
async writeToFile(level, message) {
|
|
8850
|
-
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
8851
|
-
return;
|
|
8852
|
-
}
|
|
8853
|
-
try {
|
|
8854
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
8855
|
-
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
8856
|
-
`;
|
|
8857
|
-
await fs10.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
8858
|
-
} catch (error) {
|
|
8859
|
-
console.error("File logging failed:", error);
|
|
8860
|
-
}
|
|
8861
|
-
}
|
|
8862
|
-
/**
|
|
8863
|
-
* Log error details to file
|
|
8864
|
-
*/
|
|
8865
|
-
async logErrorDetailsToFile(err) {
|
|
8866
|
-
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
8867
|
-
return;
|
|
8868
|
-
}
|
|
8869
|
-
try {
|
|
8870
|
-
if (err && typeof err === "object" && "response" in err && err.response) {
|
|
8871
|
-
const response = err.response;
|
|
8872
|
-
const config = err && typeof err === "object" && "config" in err ? err.config : void 0;
|
|
8873
|
-
await this.writeToFile("ERROR", ` Status: ${response.status} ${response.statusText || ""}`);
|
|
8874
|
-
await this.writeToFile("ERROR", ` URL: ${config?.url || "unknown"}`);
|
|
8875
|
-
await this.writeToFile("ERROR", ` Headers: ${this.safeStringify(response.headers)}`);
|
|
8876
|
-
if (response.data) {
|
|
8877
|
-
const errorText = this.extractErrorMessage(response.data);
|
|
8878
|
-
if (errorText.trim().startsWith("<!DOCTYPE") || errorText.trim().startsWith("<html")) {
|
|
8879
|
-
await this.writeToFile("ERROR", ` Response Type: HTML Error Page`);
|
|
8880
|
-
const parsedError = this.parseHtmlError(errorText);
|
|
8881
|
-
if (parsedError) {
|
|
8882
|
-
await this.writeToFile("ERROR", ` Error Message: ${parsedError}`);
|
|
8883
|
-
}
|
|
8884
|
-
await this.writeToFile("ERROR", ` Raw HTML: ${this.truncate(errorText, 1e3)}`);
|
|
8885
|
-
} else {
|
|
8886
|
-
const preview = this.truncate(errorText, 500);
|
|
8887
|
-
await this.writeToFile("ERROR", ` Response: ${preview}`);
|
|
8888
|
-
}
|
|
8889
|
-
} else {
|
|
8890
|
-
await this.writeToFile("ERROR", ` Response: (no data)`);
|
|
8891
|
-
}
|
|
8892
|
-
}
|
|
8893
|
-
if (err && typeof err === "object" && "stack" in err && typeof err.stack === "string") {
|
|
8894
|
-
const stackLines = err.stack.split("\n").slice(0, 5).join("\n ");
|
|
8895
|
-
await this.writeToFile("ERROR", ` Stack: ${stackLines}`);
|
|
8896
|
-
} else if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
8897
|
-
await this.writeToFile("ERROR", ` Message: ${err.message}`);
|
|
8898
|
-
}
|
|
8899
|
-
} catch (error) {
|
|
8900
|
-
}
|
|
8901
|
-
}
|
|
8902
|
-
/**
|
|
8903
|
-
* Safely stringify object, handling circular references
|
|
8904
|
-
*/
|
|
8905
|
-
safeStringify(obj) {
|
|
8906
|
-
try {
|
|
8907
|
-
return JSON.stringify(obj);
|
|
8908
|
-
} catch (error) {
|
|
8909
|
-
if (error instanceof Error && error.message.includes("circular")) {
|
|
8910
|
-
try {
|
|
8911
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
8912
|
-
return JSON.stringify(obj, (key, value) => {
|
|
8913
|
-
if (typeof value === "object" && value !== null) {
|
|
8914
|
-
if (seen.has(value)) {
|
|
8915
|
-
return "[Circular]";
|
|
8916
|
-
}
|
|
8917
|
-
seen.add(value);
|
|
8918
|
-
}
|
|
8919
|
-
return value;
|
|
8920
|
-
});
|
|
8921
|
-
} catch {
|
|
8922
|
-
return "[Unable to stringify]";
|
|
8923
|
-
}
|
|
8924
|
-
}
|
|
8925
|
-
return "[Stringify error]";
|
|
8926
|
-
}
|
|
8927
|
-
}
|
|
8928
|
-
/**
|
|
8929
|
-
* Extract readable text from error response data
|
|
8930
|
-
*/
|
|
8931
|
-
extractErrorMessage(data) {
|
|
8932
|
-
if (Buffer.isBuffer(data)) {
|
|
8933
|
-
return data.toString("utf-8");
|
|
8934
|
-
}
|
|
8935
|
-
if (typeof data === "string") {
|
|
8936
|
-
return data;
|
|
8937
|
-
}
|
|
8938
|
-
if (data && typeof data === "object" && "_readableState" in data && data._readableState && typeof data._readableState === "object" && "buffer" in data._readableState && Array.isArray(data._readableState.buffer) && data._readableState.buffer.length > 0) {
|
|
8939
|
-
const chunks = [];
|
|
8940
|
-
for (const chunk of data._readableState.buffer) {
|
|
8941
|
-
if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "Buffer" && "data" in chunk && Array.isArray(chunk.data)) {
|
|
8942
|
-
chunks.push(Buffer.from(chunk.data));
|
|
8943
|
-
} else if (Buffer.isBuffer(chunk)) {
|
|
8944
|
-
chunks.push(chunk);
|
|
8945
|
-
} else if (chunk && typeof chunk === "object" && "data" in chunk) {
|
|
8946
|
-
if (Buffer.isBuffer(chunk.data)) {
|
|
8947
|
-
chunks.push(chunk.data);
|
|
8948
|
-
} else if (Array.isArray(chunk.data)) {
|
|
8949
|
-
chunks.push(Buffer.from(chunk.data));
|
|
8950
|
-
}
|
|
8951
|
-
}
|
|
8952
|
-
}
|
|
8953
|
-
if (chunks.length > 0) {
|
|
8954
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
8955
|
-
}
|
|
8956
|
-
}
|
|
8957
|
-
return this.safeStringify(data);
|
|
8958
|
-
}
|
|
8959
|
-
/**
|
|
8960
|
-
* Parse HTML error page to extract error message
|
|
8961
|
-
*/
|
|
8962
|
-
parseHtmlError(html) {
|
|
8963
|
-
const titleMatch = html.match(/<title>(.*?)<\/title>/i);
|
|
8964
|
-
const h1Match = html.match(/<h1>(.*?)<\/h1>/i);
|
|
8965
|
-
const bodyMatch = html.match(/<body[^>]*>(.*?)<\/body>/is);
|
|
8966
|
-
if (titleMatch && titleMatch[1] !== "Error") {
|
|
8967
|
-
return titleMatch[1].trim();
|
|
8968
|
-
}
|
|
8969
|
-
if (h1Match) {
|
|
8970
|
-
return h1Match[1].trim();
|
|
8971
|
-
}
|
|
8972
|
-
if (bodyMatch) {
|
|
8973
|
-
const text = bodyMatch[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8974
|
-
return text.substring(0, 200);
|
|
8975
|
-
}
|
|
8976
|
-
return null;
|
|
8977
|
-
}
|
|
8978
|
-
/**
|
|
8979
|
-
* Truncate string to max length with ellipsis
|
|
8980
|
-
*/
|
|
8981
|
-
truncate(str, maxLength) {
|
|
8982
|
-
if (str.length <= maxLength) {
|
|
8983
|
-
return str;
|
|
8984
|
-
}
|
|
8985
|
-
return str.substring(0, maxLength) + "... [truncated]";
|
|
8986
|
-
}
|
|
8987
|
-
/**
|
|
8988
|
-
* Format bytes to human-readable size
|
|
8989
|
-
*/
|
|
8990
|
-
formatBytes(bytes) {
|
|
8991
|
-
if (bytes === 0) return "0 B";
|
|
8992
|
-
const k = 1024;
|
|
8993
|
-
const sizes = ["B", "KB", "MB", "GB"];
|
|
8994
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
8995
|
-
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
8996
|
-
}
|
|
8997
|
-
/**
|
|
8998
|
-
* Clean up old debug logs (older than 30 days)
|
|
8999
|
-
*/
|
|
9000
|
-
async cleanupOldLogs() {
|
|
9001
|
-
if (!this.fileLoggingEnabled) return;
|
|
9002
|
-
try {
|
|
9003
|
-
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9004
|
-
const files = await fs10.readdir(debugDir);
|
|
9005
|
-
const now = Date.now();
|
|
9006
|
-
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9007
|
-
for (const file of files) {
|
|
9008
|
-
const filePath = path11.join(debugDir, file);
|
|
9009
|
-
const stats = await fs10.stat(filePath);
|
|
9010
|
-
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9011
|
-
await fs10.unlink(filePath);
|
|
9012
|
-
}
|
|
9013
|
-
}
|
|
9014
|
-
} catch (error) {
|
|
9015
|
-
console.error("Failed to cleanup old logs:", error);
|
|
9016
|
-
}
|
|
9017
|
-
}
|
|
9018
|
-
};
|
|
9019
|
-
var logger = Logger2.getInstance();
|
|
9020
|
-
|
|
9021
|
-
// src/llm/ServerToolExecutor.ts
|
|
9022
|
-
var ServerToolExecutor = class {
|
|
9023
|
-
constructor(apiClient) {
|
|
9024
|
-
this.toolsEndpoint = "/api/ai/v1/tools";
|
|
9025
|
-
this.apiClient = apiClient;
|
|
9026
|
-
}
|
|
9027
|
-
/**
|
|
9028
|
-
* Execute a tool server-side
|
|
9029
|
-
*
|
|
9030
|
-
* @param toolName - Name of the tool to execute (e.g., 'weather_info', 'web_search')
|
|
9031
|
-
* @param input - Tool input parameters
|
|
9032
|
-
* @returns Tool execution result (content or error)
|
|
9033
|
-
*/
|
|
9034
|
-
async executeTool(toolName, input) {
|
|
9035
|
-
logger.debug(`[ServerToolExecutor] Executing tool: ${toolName}`);
|
|
9036
|
-
logger.debug(`[ServerToolExecutor] Endpoint: ${this.toolsEndpoint}`);
|
|
9037
|
-
logger.debug(`[ServerToolExecutor] Input: ${JSON.stringify(input)}`);
|
|
9038
|
-
try {
|
|
9039
|
-
const result = await this.apiClient.post(this.toolsEndpoint, {
|
|
9040
|
-
toolName,
|
|
9041
|
-
input
|
|
9042
|
-
});
|
|
9043
|
-
logger.debug(`[ServerToolExecutor] Response: ${JSON.stringify(result)}`);
|
|
9044
|
-
if (!result.success) {
|
|
9045
|
-
const errorMessage = result.error || "Tool execution failed";
|
|
9046
|
-
logger.error(`[ServerToolExecutor] Tool ${toolName} failed: ${errorMessage}`);
|
|
9047
|
-
return `Error executing ${toolName}: ${errorMessage}`;
|
|
9048
|
-
}
|
|
9049
|
-
logger.debug(`[ServerToolExecutor] Tool ${toolName} succeeded in ${result.executionTimeMs}ms`);
|
|
9050
|
-
return result.content || "";
|
|
9051
|
-
} catch (error) {
|
|
9052
|
-
const err = error;
|
|
9053
|
-
const errorMessage = err?.response?.data?.error || err?.message || "Unknown error";
|
|
9054
|
-
const status = err?.response?.status || "unknown";
|
|
9055
|
-
logger.error(`[ServerToolExecutor] Request failed for ${toolName}: ${errorMessage} (status: ${status})`);
|
|
9056
|
-
logger.error(`[ServerToolExecutor] Full error: ${JSON.stringify(err, null, 2)}`);
|
|
9057
|
-
return `Error executing ${toolName}: ${errorMessage}`;
|
|
9058
|
-
}
|
|
9059
|
-
}
|
|
9060
|
-
};
|
|
9061
|
-
|
|
9062
|
-
// src/llm/ToolRouter.ts
|
|
9063
|
-
var SERVER_TOOLS = ["weather_info", "web_search"];
|
|
9064
|
-
var LOCAL_TOOLS = [
|
|
9065
|
-
"file_read",
|
|
9066
|
-
"create_file",
|
|
9067
|
-
"glob_files",
|
|
9068
|
-
"grep_search",
|
|
9069
|
-
"delete_file",
|
|
9070
|
-
"edit_file",
|
|
9071
|
-
"dice_roll",
|
|
9072
|
-
"math_evaluate",
|
|
9073
|
-
"current_datetime"
|
|
9074
|
-
];
|
|
9075
|
-
function isServerTool(toolName) {
|
|
9076
|
-
return SERVER_TOOLS.includes(toolName);
|
|
9077
|
-
}
|
|
9078
|
-
function isLocalTool(toolName) {
|
|
9079
|
-
return LOCAL_TOOLS.includes(toolName);
|
|
9080
|
-
}
|
|
9081
|
-
async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
9082
|
-
if (isServerTool(toolName)) {
|
|
9083
|
-
logger.debug(`[ToolRouter] Routing ${toolName} to server`);
|
|
9084
|
-
const executor = new ServerToolExecutor(apiClient);
|
|
9085
|
-
return await executor.executeTool(toolName, input);
|
|
9086
|
-
} else if (isLocalTool(toolName)) {
|
|
9087
|
-
logger.debug(`[ToolRouter] Executing ${toolName} locally`);
|
|
9088
|
-
if (!localToolFn) {
|
|
9089
|
-
throw new Error(`Local tool ${toolName} has no implementation`);
|
|
9090
|
-
}
|
|
9091
|
-
const result = await localToolFn(input);
|
|
9092
|
-
return typeof result === "string" ? result : JSON.stringify(result);
|
|
9093
|
-
} else {
|
|
9094
|
-
throw new Error(`Unknown tool: ${toolName}`);
|
|
9095
|
-
}
|
|
9096
|
-
}
|
|
9097
|
-
|
|
9098
8766
|
// src/utils/toolsAdapter.ts
|
|
9099
8767
|
var NoOpStorage = class extends BaseStorage {
|
|
9100
8768
|
async upload(input, destination, options) {
|
|
@@ -9134,14 +8802,14 @@ var CliLogger = class extends Logger {
|
|
|
9134
8802
|
log(...args) {
|
|
9135
8803
|
}
|
|
9136
8804
|
};
|
|
9137
|
-
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore
|
|
8805
|
+
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore) {
|
|
9138
8806
|
const originalFn = tool.toolFn;
|
|
9139
8807
|
const toolName = tool.toolSchema.name;
|
|
9140
8808
|
return {
|
|
9141
8809
|
...tool,
|
|
9142
8810
|
toolFn: async (args) => {
|
|
9143
8811
|
if (!permissionManager.needsPermission(toolName)) {
|
|
9144
|
-
const result2 = await
|
|
8812
|
+
const result2 = await originalFn(args);
|
|
9145
8813
|
agentContext.observationQueue.push({ toolName, result: result2 });
|
|
9146
8814
|
return result2;
|
|
9147
8815
|
}
|
|
@@ -9198,13 +8866,13 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
9198
8866
|
}
|
|
9199
8867
|
}
|
|
9200
8868
|
}
|
|
9201
|
-
const result = await
|
|
8869
|
+
const result = await originalFn(args);
|
|
9202
8870
|
agentContext.observationQueue.push({ toolName, result });
|
|
9203
8871
|
return result;
|
|
9204
8872
|
}
|
|
9205
8873
|
};
|
|
9206
8874
|
}
|
|
9207
|
-
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore,
|
|
8875
|
+
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, toolApiKeys) {
|
|
9208
8876
|
const logger2 = new CliLogger();
|
|
9209
8877
|
const storage = new NoOpStorage();
|
|
9210
8878
|
const user = {
|
|
@@ -9221,6 +8889,18 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9221
8889
|
};
|
|
9222
8890
|
const mockAdminSettings = {
|
|
9223
8891
|
findBySettingName: async (settingName) => {
|
|
8892
|
+
if (settingName === "OpenWeatherKey") {
|
|
8893
|
+
const key = toolApiKeys?.openweather || process.env.OPENWEATHER_API_KEY;
|
|
8894
|
+
if (key) {
|
|
8895
|
+
return { settingValue: key };
|
|
8896
|
+
}
|
|
8897
|
+
}
|
|
8898
|
+
if (settingName === "SerperKey") {
|
|
8899
|
+
const key = toolApiKeys?.serper || process.env.SERPER_API_KEY;
|
|
8900
|
+
if (key) {
|
|
8901
|
+
return { settingValue: key };
|
|
8902
|
+
}
|
|
8903
|
+
}
|
|
9224
8904
|
return null;
|
|
9225
8905
|
}
|
|
9226
8906
|
};
|
|
@@ -9230,22 +8910,27 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9230
8910
|
adminSettings: mockAdminSettings
|
|
9231
8911
|
}
|
|
9232
8912
|
};
|
|
8913
|
+
const hasSerperKey = !!(toolApiKeys?.serper || process.env.SERPER_API_KEY);
|
|
8914
|
+
const hasOpenWeatherKey = !!(toolApiKeys?.openweather || process.env.OPENWEATHER_API_KEY);
|
|
9233
8915
|
const toolConfig = {
|
|
9234
|
-
//
|
|
8916
|
+
// Enable these tools for CLI (no external API keys needed)
|
|
9235
8917
|
dice_roll: {},
|
|
9236
8918
|
math_evaluate: {},
|
|
9237
8919
|
current_datetime: {},
|
|
9238
8920
|
prompt_enhancement: {},
|
|
9239
|
-
// File operation tools (CLI-specific
|
|
8921
|
+
// File operation tools (CLI-specific)
|
|
9240
8922
|
file_read: {},
|
|
9241
8923
|
create_file: {},
|
|
9242
8924
|
glob_files: {},
|
|
9243
8925
|
grep_search: {},
|
|
9244
8926
|
delete_file: {},
|
|
9245
|
-
//
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
8927
|
+
// Tools requiring API keys (only include if API key is available)
|
|
8928
|
+
...hasSerperKey && { web_search: {} },
|
|
8929
|
+
// Requires SERPER_API_KEY
|
|
8930
|
+
...hasOpenWeatherKey && { weather_info: {} },
|
|
8931
|
+
// Requires OPENWEATHER_API_KEY
|
|
8932
|
+
...hasSerperKey && { deep_research: {} }
|
|
8933
|
+
// Requires SERPER_API_KEY
|
|
9249
8934
|
// Disable web-only tools
|
|
9250
8935
|
// blog_publish: undefined,
|
|
9251
8936
|
// blog_edit: undefined,
|
|
@@ -9255,7 +8940,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9255
8940
|
// mermaid_chart: undefined,
|
|
9256
8941
|
// recharts: undefined,
|
|
9257
8942
|
// edit_file: undefined,
|
|
9258
|
-
// deep_research: undefined,
|
|
9259
8943
|
};
|
|
9260
8944
|
const toolsMap = generateTools(
|
|
9261
8945
|
userId,
|
|
@@ -9273,7 +8957,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9273
8957
|
model
|
|
9274
8958
|
);
|
|
9275
8959
|
const tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
|
|
9276
|
-
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore
|
|
8960
|
+
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore)
|
|
9277
8961
|
);
|
|
9278
8962
|
return { tools: tools2, agentContext };
|
|
9279
8963
|
}
|
|
@@ -9468,6 +9152,261 @@ function getEnvironmentName(configApiConfig) {
|
|
|
9468
9152
|
return "Bike4Mind";
|
|
9469
9153
|
}
|
|
9470
9154
|
|
|
9155
|
+
// src/utils/Logger.ts
|
|
9156
|
+
import fs10 from "fs/promises";
|
|
9157
|
+
import path11 from "path";
|
|
9158
|
+
import os from "os";
|
|
9159
|
+
var Logger2 = class _Logger {
|
|
9160
|
+
constructor() {
|
|
9161
|
+
this.logFilePath = null;
|
|
9162
|
+
this.sessionId = null;
|
|
9163
|
+
this.fileLoggingEnabled = true;
|
|
9164
|
+
this.consoleVerbose = false;
|
|
9165
|
+
}
|
|
9166
|
+
static {
|
|
9167
|
+
this.instance = null;
|
|
9168
|
+
}
|
|
9169
|
+
static getInstance() {
|
|
9170
|
+
if (!_Logger.instance) {
|
|
9171
|
+
_Logger.instance = new _Logger();
|
|
9172
|
+
}
|
|
9173
|
+
return _Logger.instance;
|
|
9174
|
+
}
|
|
9175
|
+
/**
|
|
9176
|
+
* Initialize the logger with a session ID
|
|
9177
|
+
*/
|
|
9178
|
+
async initialize(sessionId) {
|
|
9179
|
+
this.sessionId = sessionId;
|
|
9180
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9181
|
+
await fs10.mkdir(debugDir, { recursive: true });
|
|
9182
|
+
this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
|
|
9183
|
+
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
9184
|
+
}
|
|
9185
|
+
/**
|
|
9186
|
+
* Set whether verbose console logging is enabled
|
|
9187
|
+
*/
|
|
9188
|
+
setVerbose(enabled) {
|
|
9189
|
+
this.consoleVerbose = enabled;
|
|
9190
|
+
}
|
|
9191
|
+
/**
|
|
9192
|
+
* Set whether file logging is enabled
|
|
9193
|
+
*/
|
|
9194
|
+
setFileLoggingEnabled(enabled) {
|
|
9195
|
+
this.fileLoggingEnabled = enabled;
|
|
9196
|
+
}
|
|
9197
|
+
/**
|
|
9198
|
+
* DEBUG level - verbose-only console, always file
|
|
9199
|
+
*/
|
|
9200
|
+
debug(message) {
|
|
9201
|
+
this.writeToFile("DEBUG", message).catch(() => {
|
|
9202
|
+
});
|
|
9203
|
+
if (this.consoleVerbose) {
|
|
9204
|
+
console.log(message);
|
|
9205
|
+
}
|
|
9206
|
+
}
|
|
9207
|
+
/**
|
|
9208
|
+
* INFO level - always shown to user
|
|
9209
|
+
*/
|
|
9210
|
+
info(message) {
|
|
9211
|
+
this.writeToFile("INFO", message).catch(() => {
|
|
9212
|
+
});
|
|
9213
|
+
console.log(message);
|
|
9214
|
+
}
|
|
9215
|
+
/**
|
|
9216
|
+
* WARN level - always shown to user
|
|
9217
|
+
*/
|
|
9218
|
+
warn(message) {
|
|
9219
|
+
this.writeToFile("WARN", message).catch(() => {
|
|
9220
|
+
});
|
|
9221
|
+
console.warn(message);
|
|
9222
|
+
}
|
|
9223
|
+
/**
|
|
9224
|
+
* ERROR level - always shown to user
|
|
9225
|
+
*/
|
|
9226
|
+
error(message, err) {
|
|
9227
|
+
this.writeToFile("ERROR", message).catch(() => {
|
|
9228
|
+
});
|
|
9229
|
+
if (err) {
|
|
9230
|
+
this.logErrorDetailsToFile(err).catch(() => {
|
|
9231
|
+
});
|
|
9232
|
+
}
|
|
9233
|
+
console.error(message);
|
|
9234
|
+
}
|
|
9235
|
+
/**
|
|
9236
|
+
* Write log entry to file
|
|
9237
|
+
*/
|
|
9238
|
+
async writeToFile(level, message) {
|
|
9239
|
+
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
9240
|
+
return;
|
|
9241
|
+
}
|
|
9242
|
+
try {
|
|
9243
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
9244
|
+
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
9245
|
+
`;
|
|
9246
|
+
await fs10.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
9247
|
+
} catch (error) {
|
|
9248
|
+
console.error("File logging failed:", error);
|
|
9249
|
+
}
|
|
9250
|
+
}
|
|
9251
|
+
/**
|
|
9252
|
+
* Log error details to file
|
|
9253
|
+
*/
|
|
9254
|
+
async logErrorDetailsToFile(err) {
|
|
9255
|
+
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
9256
|
+
return;
|
|
9257
|
+
}
|
|
9258
|
+
try {
|
|
9259
|
+
if (err && typeof err === "object" && "response" in err && err.response) {
|
|
9260
|
+
const response = err.response;
|
|
9261
|
+
const config = err && typeof err === "object" && "config" in err ? err.config : void 0;
|
|
9262
|
+
await this.writeToFile("ERROR", ` Status: ${response.status} ${response.statusText || ""}`);
|
|
9263
|
+
await this.writeToFile("ERROR", ` URL: ${config?.url || "unknown"}`);
|
|
9264
|
+
await this.writeToFile("ERROR", ` Headers: ${this.safeStringify(response.headers)}`);
|
|
9265
|
+
if (response.data) {
|
|
9266
|
+
const errorText = this.extractErrorMessage(response.data);
|
|
9267
|
+
if (errorText.trim().startsWith("<!DOCTYPE") || errorText.trim().startsWith("<html")) {
|
|
9268
|
+
await this.writeToFile("ERROR", ` Response Type: HTML Error Page`);
|
|
9269
|
+
const parsedError = this.parseHtmlError(errorText);
|
|
9270
|
+
if (parsedError) {
|
|
9271
|
+
await this.writeToFile("ERROR", ` Error Message: ${parsedError}`);
|
|
9272
|
+
}
|
|
9273
|
+
await this.writeToFile("ERROR", ` Raw HTML: ${this.truncate(errorText, 1e3)}`);
|
|
9274
|
+
} else {
|
|
9275
|
+
const preview = this.truncate(errorText, 500);
|
|
9276
|
+
await this.writeToFile("ERROR", ` Response: ${preview}`);
|
|
9277
|
+
}
|
|
9278
|
+
} else {
|
|
9279
|
+
await this.writeToFile("ERROR", ` Response: (no data)`);
|
|
9280
|
+
}
|
|
9281
|
+
}
|
|
9282
|
+
if (err && typeof err === "object" && "stack" in err && typeof err.stack === "string") {
|
|
9283
|
+
const stackLines = err.stack.split("\n").slice(0, 5).join("\n ");
|
|
9284
|
+
await this.writeToFile("ERROR", ` Stack: ${stackLines}`);
|
|
9285
|
+
} else if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
9286
|
+
await this.writeToFile("ERROR", ` Message: ${err.message}`);
|
|
9287
|
+
}
|
|
9288
|
+
} catch (error) {
|
|
9289
|
+
}
|
|
9290
|
+
}
|
|
9291
|
+
/**
|
|
9292
|
+
* Safely stringify object, handling circular references
|
|
9293
|
+
*/
|
|
9294
|
+
safeStringify(obj) {
|
|
9295
|
+
try {
|
|
9296
|
+
return JSON.stringify(obj);
|
|
9297
|
+
} catch (error) {
|
|
9298
|
+
if (error instanceof Error && error.message.includes("circular")) {
|
|
9299
|
+
try {
|
|
9300
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
9301
|
+
return JSON.stringify(obj, (key, value) => {
|
|
9302
|
+
if (typeof value === "object" && value !== null) {
|
|
9303
|
+
if (seen.has(value)) {
|
|
9304
|
+
return "[Circular]";
|
|
9305
|
+
}
|
|
9306
|
+
seen.add(value);
|
|
9307
|
+
}
|
|
9308
|
+
return value;
|
|
9309
|
+
});
|
|
9310
|
+
} catch {
|
|
9311
|
+
return "[Unable to stringify]";
|
|
9312
|
+
}
|
|
9313
|
+
}
|
|
9314
|
+
return "[Stringify error]";
|
|
9315
|
+
}
|
|
9316
|
+
}
|
|
9317
|
+
/**
|
|
9318
|
+
* Extract readable text from error response data
|
|
9319
|
+
*/
|
|
9320
|
+
extractErrorMessage(data) {
|
|
9321
|
+
if (Buffer.isBuffer(data)) {
|
|
9322
|
+
return data.toString("utf-8");
|
|
9323
|
+
}
|
|
9324
|
+
if (typeof data === "string") {
|
|
9325
|
+
return data;
|
|
9326
|
+
}
|
|
9327
|
+
if (data && typeof data === "object" && "_readableState" in data && data._readableState && typeof data._readableState === "object" && "buffer" in data._readableState && Array.isArray(data._readableState.buffer) && data._readableState.buffer.length > 0) {
|
|
9328
|
+
const chunks = [];
|
|
9329
|
+
for (const chunk of data._readableState.buffer) {
|
|
9330
|
+
if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "Buffer" && "data" in chunk && Array.isArray(chunk.data)) {
|
|
9331
|
+
chunks.push(Buffer.from(chunk.data));
|
|
9332
|
+
} else if (Buffer.isBuffer(chunk)) {
|
|
9333
|
+
chunks.push(chunk);
|
|
9334
|
+
} else if (chunk && typeof chunk === "object" && "data" in chunk) {
|
|
9335
|
+
if (Buffer.isBuffer(chunk.data)) {
|
|
9336
|
+
chunks.push(chunk.data);
|
|
9337
|
+
} else if (Array.isArray(chunk.data)) {
|
|
9338
|
+
chunks.push(Buffer.from(chunk.data));
|
|
9339
|
+
}
|
|
9340
|
+
}
|
|
9341
|
+
}
|
|
9342
|
+
if (chunks.length > 0) {
|
|
9343
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9346
|
+
return this.safeStringify(data);
|
|
9347
|
+
}
|
|
9348
|
+
/**
|
|
9349
|
+
* Parse HTML error page to extract error message
|
|
9350
|
+
*/
|
|
9351
|
+
parseHtmlError(html) {
|
|
9352
|
+
const titleMatch = html.match(/<title>(.*?)<\/title>/i);
|
|
9353
|
+
const h1Match = html.match(/<h1>(.*?)<\/h1>/i);
|
|
9354
|
+
const bodyMatch = html.match(/<body[^>]*>(.*?)<\/body>/is);
|
|
9355
|
+
if (titleMatch && titleMatch[1] !== "Error") {
|
|
9356
|
+
return titleMatch[1].trim();
|
|
9357
|
+
}
|
|
9358
|
+
if (h1Match) {
|
|
9359
|
+
return h1Match[1].trim();
|
|
9360
|
+
}
|
|
9361
|
+
if (bodyMatch) {
|
|
9362
|
+
const text = bodyMatch[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
9363
|
+
return text.substring(0, 200);
|
|
9364
|
+
}
|
|
9365
|
+
return null;
|
|
9366
|
+
}
|
|
9367
|
+
/**
|
|
9368
|
+
* Truncate string to max length with ellipsis
|
|
9369
|
+
*/
|
|
9370
|
+
truncate(str, maxLength) {
|
|
9371
|
+
if (str.length <= maxLength) {
|
|
9372
|
+
return str;
|
|
9373
|
+
}
|
|
9374
|
+
return str.substring(0, maxLength) + "... [truncated]";
|
|
9375
|
+
}
|
|
9376
|
+
/**
|
|
9377
|
+
* Format bytes to human-readable size
|
|
9378
|
+
*/
|
|
9379
|
+
formatBytes(bytes) {
|
|
9380
|
+
if (bytes === 0) return "0 B";
|
|
9381
|
+
const k = 1024;
|
|
9382
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
9383
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
9384
|
+
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
9385
|
+
}
|
|
9386
|
+
/**
|
|
9387
|
+
* Clean up old debug logs (older than 30 days)
|
|
9388
|
+
*/
|
|
9389
|
+
async cleanupOldLogs() {
|
|
9390
|
+
if (!this.fileLoggingEnabled) return;
|
|
9391
|
+
try {
|
|
9392
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9393
|
+
const files = await fs10.readdir(debugDir);
|
|
9394
|
+
const now = Date.now();
|
|
9395
|
+
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9396
|
+
for (const file of files) {
|
|
9397
|
+
const filePath = path11.join(debugDir, file);
|
|
9398
|
+
const stats = await fs10.stat(filePath);
|
|
9399
|
+
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9400
|
+
await fs10.unlink(filePath);
|
|
9401
|
+
}
|
|
9402
|
+
}
|
|
9403
|
+
} catch (error) {
|
|
9404
|
+
console.error("Failed to cleanup old logs:", error);
|
|
9405
|
+
}
|
|
9406
|
+
}
|
|
9407
|
+
};
|
|
9408
|
+
var logger = Logger2.getInstance();
|
|
9409
|
+
|
|
9471
9410
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
9472
9411
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
9473
9412
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -10271,10 +10210,7 @@ var ApiClient = class {
|
|
|
10271
10210
|
* Make a POST request
|
|
10272
10211
|
*/
|
|
10273
10212
|
async post(url, data, config) {
|
|
10274
|
-
logger.debug(`[ApiClient] POST ${this.client.defaults.baseURL}${url}`);
|
|
10275
|
-
logger.debug(`[ApiClient] Request body: ${JSON.stringify(data)}`);
|
|
10276
10213
|
const response = await this.client.post(url, data, config);
|
|
10277
|
-
logger.debug(`[ApiClient] Response status: ${response.status}`);
|
|
10278
10214
|
return response.data;
|
|
10279
10215
|
}
|
|
10280
10216
|
/**
|
|
@@ -10325,7 +10261,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
10325
10261
|
// package.json
|
|
10326
10262
|
var package_default = {
|
|
10327
10263
|
name: "@bike4mind/cli",
|
|
10328
|
-
version: "0.2.7-feat-
|
|
10264
|
+
version: "0.2.7-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
10329
10265
|
type: "module",
|
|
10330
10266
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
10331
10267
|
license: "UNLICENSED",
|
|
@@ -10428,11 +10364,11 @@ var package_default = {
|
|
|
10428
10364
|
},
|
|
10429
10365
|
devDependencies: {
|
|
10430
10366
|
"@bike4mind/agents": "0.1.0",
|
|
10431
|
-
"@bike4mind/common": "2.38.1-feat-
|
|
10432
|
-
"@bike4mind/mcp": "1.20.1-feat-
|
|
10433
|
-
"@bike4mind/services": "2.33.1-feat-
|
|
10434
|
-
"@bike4mind/utils": "2.1.2-feat-
|
|
10435
|
-
"@types/better-sqlite3": "^7.6.
|
|
10367
|
+
"@bike4mind/common": "2.38.1-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
10368
|
+
"@bike4mind/mcp": "1.20.1-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
10369
|
+
"@bike4mind/services": "2.33.1-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
10370
|
+
"@bike4mind/utils": "2.1.2-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
10371
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
10436
10372
|
"@types/diff": "^5.0.9",
|
|
10437
10373
|
"@types/jsonwebtoken": "^9.0.4",
|
|
10438
10374
|
"@types/node": "^22.9.0",
|
|
@@ -10444,7 +10380,7 @@ var package_default = {
|
|
|
10444
10380
|
typescript: "^5.9.3",
|
|
10445
10381
|
vitest: "^3.2.4"
|
|
10446
10382
|
},
|
|
10447
|
-
gitHead: "
|
|
10383
|
+
gitHead: "2e676f9bedcd3876486314a5bcade6acc1491e3f"
|
|
10448
10384
|
};
|
|
10449
10385
|
|
|
10450
10386
|
// src/config/constants.ts
|
|
@@ -10668,6 +10604,10 @@ function CliApp() {
|
|
|
10668
10604
|
setPermissionPrompt(prompt);
|
|
10669
10605
|
});
|
|
10670
10606
|
};
|
|
10607
|
+
console.log("\u{1F511} Tool API Keys:", {
|
|
10608
|
+
openweather: config.toolApiKeys?.openweather ? "\u2713 configured" : "\u2717 missing",
|
|
10609
|
+
serper: config.toolApiKeys?.serper ? "\u2713 configured" : "\u2717 missing"
|
|
10610
|
+
});
|
|
10671
10611
|
const agentContext = {
|
|
10672
10612
|
currentAgent: null,
|
|
10673
10613
|
observationQueue: []
|
|
@@ -10680,7 +10620,7 @@ function CliApp() {
|
|
|
10680
10620
|
promptFn,
|
|
10681
10621
|
agentContext,
|
|
10682
10622
|
state.configStore,
|
|
10683
|
-
|
|
10623
|
+
config.toolApiKeys
|
|
10684
10624
|
);
|
|
10685
10625
|
console.log(`\u{1F6E0}\uFE0F Loaded ${b4mTools.length} B4M tool(s)`);
|
|
10686
10626
|
const mcpManager = new McpManager(config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.7-feat-
|
|
3
|
+
"version": "0.2.7-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -103,11 +103,11 @@
|
|
|
103
103
|
},
|
|
104
104
|
"devDependencies": {
|
|
105
105
|
"@bike4mind/agents": "0.1.0",
|
|
106
|
-
"@bike4mind/common": "2.38.1-feat-
|
|
107
|
-
"@bike4mind/mcp": "1.20.1-feat-
|
|
108
|
-
"@bike4mind/services": "2.33.1-feat-
|
|
109
|
-
"@bike4mind/utils": "2.1.2-feat-
|
|
110
|
-
"@types/better-sqlite3": "^7.6.
|
|
106
|
+
"@bike4mind/common": "2.38.1-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
107
|
+
"@bike4mind/mcp": "1.20.1-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
108
|
+
"@bike4mind/services": "2.33.1-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
109
|
+
"@bike4mind/utils": "2.1.2-feat-organization-overview-enhancements.17130+2e676f9be",
|
|
110
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
111
111
|
"@types/diff": "^5.0.9",
|
|
112
112
|
"@types/jsonwebtoken": "^9.0.4",
|
|
113
113
|
"@types/node": "^22.9.0",
|
|
@@ -119,5 +119,5 @@
|
|
|
119
119
|
"typescript": "^5.9.3",
|
|
120
120
|
"vitest": "^3.2.4"
|
|
121
121
|
},
|
|
122
|
-
"gitHead": "
|
|
122
|
+
"gitHead": "2e676f9bedcd3876486314a5bcade6acc1491e3f"
|
|
123
123
|
}
|