@bike4mind/cli 0.2.28 → 0.2.29-cache-mcp-tools-schema-and-refactor.18845
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{artifactExtractor-36XHJYOZ.js → artifactExtractor-EE753J4D.js} +1 -1
- package/dist/{chunk-XJRPAAUS.js → chunk-5GSDPBTM.js} +24 -4
- package/dist/{chunk-JJBDHUGY.js → chunk-AQWQ7KZX.js} +2 -2
- package/dist/{chunk-UNOJBVD2.js → chunk-H4SPUAKA.js} +83 -5
- package/dist/{chunk-23T2XGSZ.js → chunk-LBTTUQJM.js} +290 -33
- package/dist/{chunk-VGYTNJXN.js → chunk-QUV5XB2V.js} +15 -15
- package/dist/{chunk-ZEMWV6IR.js → chunk-WEUKIPNI.js} +2 -2
- package/dist/commands/mcpCommand.js +1 -1
- package/dist/{create-NGI7IIQ4.js → create-3ABBVYR5.js} +3 -3
- package/dist/index.js +338 -440
- package/dist/{llmMarkdownGenerator-JDYKJUEC.js → llmMarkdownGenerator-IJKJYJ3U.js} +1 -1
- package/dist/{markdownGenerator-QXBC2EW5.js → markdownGenerator-SJT7AXLT.js} +1 -1
- package/dist/{mementoService-X35OMHVC.js → mementoService-GG4ZJ6H2.js} +3 -3
- package/dist/{src-CBU6EAO3.js → src-4IYWG6WR.js} +4 -2
- package/dist/{src-6NIYIWZD.js → src-GRO5NIC3.js} +3 -1
- package/dist/{subtractCredits-RL6JVDMI.js → subtractCredits-C6FJDUOD.js} +3 -3
- package/dist/treeSitterEngine-4SGFQDY3.js +330 -0
- package/package.json +8 -6
package/dist/index.js
CHANGED
|
@@ -5,16 +5,17 @@ import {
|
|
|
5
5
|
getEffectiveApiKey,
|
|
6
6
|
getOpenWeatherKey,
|
|
7
7
|
getSerperKey
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QUV5XB2V.js";
|
|
9
9
|
import {
|
|
10
|
-
ConfigStore
|
|
11
|
-
|
|
10
|
+
ConfigStore,
|
|
11
|
+
logger
|
|
12
|
+
} from "./chunk-LBTTUQJM.js";
|
|
12
13
|
import {
|
|
13
14
|
selectActiveBackgroundAgents,
|
|
14
15
|
useCliStore
|
|
15
16
|
} from "./chunk-TVW4ZESU.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-AQWQ7KZX.js";
|
|
18
|
+
import "./chunk-WEUKIPNI.js";
|
|
18
19
|
import {
|
|
19
20
|
BFLImageService,
|
|
20
21
|
BaseStorage,
|
|
@@ -26,7 +27,7 @@ import {
|
|
|
26
27
|
OpenAIBackend,
|
|
27
28
|
OpenAIImageService,
|
|
28
29
|
XAIImageService
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-H4SPUAKA.js";
|
|
30
31
|
import {
|
|
31
32
|
AiEvents,
|
|
32
33
|
ApiKeyEvents,
|
|
@@ -82,7 +83,7 @@ import {
|
|
|
82
83
|
XAI_IMAGE_MODELS,
|
|
83
84
|
b4mLLMTools,
|
|
84
85
|
getMcpProviderMetadata
|
|
85
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-5GSDPBTM.js";
|
|
86
87
|
import {
|
|
87
88
|
Logger
|
|
88
89
|
} from "./chunk-OCYRD7D6.js";
|
|
@@ -551,8 +552,9 @@ var COMMANDS = [
|
|
|
551
552
|
args: "<name>"
|
|
552
553
|
},
|
|
553
554
|
{
|
|
554
|
-
name: "
|
|
555
|
-
description: "List saved sessions"
|
|
555
|
+
name: "resume",
|
|
556
|
+
description: "List and resume saved sessions",
|
|
557
|
+
aliases: ["sessions"]
|
|
556
558
|
},
|
|
557
559
|
{
|
|
558
560
|
name: "config",
|
|
@@ -1112,11 +1114,11 @@ function InputPrompt({
|
|
|
1112
1114
|
}
|
|
1113
1115
|
};
|
|
1114
1116
|
const getPlaceholder = () => {
|
|
1115
|
-
if (disabled) return "
|
|
1117
|
+
if (disabled) return "";
|
|
1116
1118
|
if (isBashMode) return "Enter shell command to execute...";
|
|
1117
1119
|
return "Type your message, /help for commands, @file to reference, or ! for bash";
|
|
1118
1120
|
};
|
|
1119
|
-
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: isBashMode ? "yellow" : "cyan" }, isBashMode ? "$ " : "> "), /* @__PURE__ */ React5.createElement(
|
|
1121
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: disabled ? "gray" : isBashMode ? "yellow" : "cyan", dimColor: disabled }, isBashMode ? "$ " : "> "), /* @__PURE__ */ React5.createElement(
|
|
1120
1122
|
CustomTextInput,
|
|
1121
1123
|
{
|
|
1122
1124
|
key: inputKey.current,
|
|
@@ -1139,7 +1141,7 @@ import React6 from "react";
|
|
|
1139
1141
|
import { Box as Box5, Text as Text6 } from "ink";
|
|
1140
1142
|
import Spinner from "ink-spinner";
|
|
1141
1143
|
var ThoughtStream = React6.memo(function ThoughtStream2({ isThinking }) {
|
|
1142
|
-
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column"
|
|
1144
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, isThinking && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Thinking...")));
|
|
1143
1145
|
});
|
|
1144
1146
|
|
|
1145
1147
|
// src/components/AgentThinking.tsx
|
|
@@ -1271,9 +1273,30 @@ function PermissionPrompt({
|
|
|
1271
1273
|
setResponded(true);
|
|
1272
1274
|
onResponse(items[selectedIndex].value);
|
|
1273
1275
|
}, [responded, onResponse, items, selectedIndex]);
|
|
1276
|
+
const handleSelectIndex = useCallback(
|
|
1277
|
+
(index) => {
|
|
1278
|
+
if (responded) return;
|
|
1279
|
+
setResponded(true);
|
|
1280
|
+
onResponse(items[index].value);
|
|
1281
|
+
},
|
|
1282
|
+
[responded, onResponse, items]
|
|
1283
|
+
);
|
|
1274
1284
|
useInput3(
|
|
1275
|
-
(
|
|
1285
|
+
(input, key) => {
|
|
1276
1286
|
if (responded) return;
|
|
1287
|
+
const num = parseInt(input, 10);
|
|
1288
|
+
if (num >= 1 && num <= items.length) {
|
|
1289
|
+
handleSelectIndex(num - 1);
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (input.toLowerCase() === "y") {
|
|
1293
|
+
handleSelectIndex(0);
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
if (input.toLowerCase() === "n") {
|
|
1297
|
+
handleSelectIndex(items.length - 1);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1277
1300
|
if (key.upArrow) {
|
|
1278
1301
|
setSelectedIndex((i) => i > 0 ? i - 1 : items.length - 1);
|
|
1279
1302
|
} else if (key.downArrow) {
|
|
@@ -1288,7 +1311,7 @@ function PermissionPrompt({
|
|
|
1288
1311
|
const rawArgsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
|
|
1289
1312
|
const argsString = rawArgsString.length > MAX_ARGS_LENGTH ? rawArgsString.slice(0, MAX_ARGS_LENGTH) + `
|
|
1290
1313
|
... (${rawArgsString.length - MAX_ARGS_LENGTH} more chars)` : rawArgsString;
|
|
1291
|
-
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Tool: "), /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Action: "), /* @__PURE__ */ React10.createElement(Text9, null, toolDescription)), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { bold: true }, "Arguments:"), /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { bold: true }, "Preview:"), /* @__PURE__ */ React10.createElement(Box9, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, items.map((item, index) => /* @__PURE__ */ React10.createElement(Box9, { key: item.value }, /* @__PURE__ */ React10.createElement(Text9, { color: index === selectedIndex ? "cyan" : void 0, bold: index === selectedIndex }, index === selectedIndex ? "\u276F " : "
|
|
1314
|
+
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Tool: "), /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Action: "), /* @__PURE__ */ React10.createElement(Text9, null, toolDescription)), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { bold: true }, "Arguments:"), /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { bold: true }, "Preview:"), /* @__PURE__ */ React10.createElement(Box9, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, items.map((item, index) => /* @__PURE__ */ React10.createElement(Box9, { key: item.value }, /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, index + 1, "."), /* @__PURE__ */ React10.createElement(Text9, { color: index === selectedIndex ? "cyan" : void 0, bold: index === selectedIndex }, index === selectedIndex ? " \u276F " : " ", item.label)))), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Press 1-", items.length, ", y/n, or \u2191\u2193 + Enter")));
|
|
1292
1315
|
}
|
|
1293
1316
|
|
|
1294
1317
|
// src/components/ConfigEditor.tsx
|
|
@@ -1707,33 +1730,21 @@ function truncateValue(value, maxLength) {
|
|
|
1707
1730
|
}
|
|
1708
1731
|
return str.slice(0, maxLength) + "...";
|
|
1709
1732
|
}
|
|
1710
|
-
function getRoleDisplay(role) {
|
|
1711
|
-
switch (role) {
|
|
1712
|
-
case "user":
|
|
1713
|
-
return { color: "cyan", label: "\u{1F464} You" };
|
|
1714
|
-
case "system":
|
|
1715
|
-
return { color: "gray", label: "\u2139\uFE0F System" };
|
|
1716
|
-
default:
|
|
1717
|
-
return { color: "green", label: "\u{1F916} Assistant" };
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
1733
|
var MessageItem = React14.memo(function MessageItem2({ message }) {
|
|
1721
1734
|
const isUser = message.role === "user";
|
|
1722
|
-
|
|
1723
|
-
const roleDisplay = getRoleDisplay(message.role);
|
|
1724
|
-
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", marginBottom: 1 }, !isContinuation && /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { bold: true, color: roleDisplay.color }, roleDisplay.label), isUser && /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), isUser && message.content && /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { backgroundColor: "whiteBright", color: "black" }, " ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " ", "tools used, ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
|
|
1735
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column" }, isUser && message.content && /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { backgroundColor: "whiteBright", color: "black" }, "\u276F ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.filter((s) => ["thought", "action"].includes(s.type)).length > 0 && /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2, flexDirection: "column", marginBottom: 1 }, message.metadata.steps.map((step, idx) => {
|
|
1725
1736
|
if (step.type === "thought") {
|
|
1726
|
-
return /* @__PURE__ */ React14.createElement(Box13, { key: idx,
|
|
1737
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text13, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` ${step.content}`));
|
|
1727
1738
|
}
|
|
1728
1739
|
if (step.type === "action") {
|
|
1729
1740
|
const toolName = step.metadata?.toolName || "unknown";
|
|
1730
1741
|
const toolInput = step.metadata?.toolInput;
|
|
1731
1742
|
const observationStep = message.metadata?.steps?.[idx + 1];
|
|
1732
1743
|
const result = observationStep?.type === "observation" ? observationStep.content : null;
|
|
1733
|
-
return /* @__PURE__ */ React14.createElement(Box13, { key: idx,
|
|
1744
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text13, { color: "yellow" }, "\u{1F527} ", toolName), toolInput && /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` Input: ${truncateValue(toolInput, 100)}`), result && /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` Result: ${truncateValue(result, 200)}`));
|
|
1734
1745
|
}
|
|
1735
1746
|
return null;
|
|
1736
|
-
}).filter(Boolean)), !isUser && message.content !== "..." && /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2,
|
|
1747
|
+
}).filter(Boolean)), !isUser && message.content !== "..." && /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2, marginBottom: 1 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React14.createElement(Text13, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React14.createElement(MarkdownRenderer, { content: message.content })), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
|
|
1737
1748
|
});
|
|
1738
1749
|
|
|
1739
1750
|
// src/utils/processFileReferences.ts
|
|
@@ -2163,7 +2174,7 @@ function SessionSelector({ sessions, currentSession, onSelect, onCancel }) {
|
|
|
2163
2174
|
{
|
|
2164
2175
|
items,
|
|
2165
2176
|
onSelect: handleSelectionSelect,
|
|
2166
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React19.createElement(Box18, null, /* @__PURE__ */ React19.createElement(Text18, { color: isSelected ? "cyan" : void 0 },
|
|
2177
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React19.createElement(Box18, null, /* @__PURE__ */ React19.createElement(Text18, { color: isSelected ? "cyan" : void 0 }, label))
|
|
2167
2178
|
}
|
|
2168
2179
|
), /* @__PURE__ */ React19.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
|
|
2169
2180
|
}
|
|
@@ -2176,7 +2187,7 @@ function SessionSelector({ sessions, currentSession, onSelect, onCancel }) {
|
|
|
2176
2187
|
{
|
|
2177
2188
|
items: confirmationItems,
|
|
2178
2189
|
onSelect: handleConfirmationSelect,
|
|
2179
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React19.createElement(Box18, null, /* @__PURE__ */ React19.createElement(Text18, { color: isSelected ? "cyan" : void 0 },
|
|
2190
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React19.createElement(Box18, null, /* @__PURE__ */ React19.createElement(Text18, { color: isSelected ? "cyan" : void 0 }, label))
|
|
2180
2191
|
}
|
|
2181
2192
|
), /* @__PURE__ */ React19.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to go back")));
|
|
2182
2193
|
}
|
|
@@ -2623,271 +2634,13 @@ var CommandHistoryStore = class {
|
|
|
2623
2634
|
};
|
|
2624
2635
|
|
|
2625
2636
|
// src/storage/CustomCommandStore.ts
|
|
2626
|
-
import fs6 from "fs/promises";
|
|
2627
|
-
import path6 from "path";
|
|
2628
|
-
import os2 from "os";
|
|
2629
|
-
|
|
2630
|
-
// src/utils/commandParser.ts
|
|
2631
|
-
import matter from "gray-matter";
|
|
2632
|
-
import { z } from "zod";
|
|
2633
|
-
|
|
2634
|
-
// src/utils/Logger.ts
|
|
2635
2637
|
import fs5 from "fs/promises";
|
|
2636
2638
|
import path5 from "path";
|
|
2637
2639
|
import os from "os";
|
|
2638
|
-
var Logger2 = class _Logger {
|
|
2639
|
-
constructor() {
|
|
2640
|
-
this.logFilePath = null;
|
|
2641
|
-
this.sessionId = null;
|
|
2642
|
-
this.fileLoggingEnabled = true;
|
|
2643
|
-
this.consoleVerbose = false;
|
|
2644
|
-
}
|
|
2645
|
-
static {
|
|
2646
|
-
this.instance = null;
|
|
2647
|
-
}
|
|
2648
|
-
static getInstance() {
|
|
2649
|
-
if (!_Logger.instance) {
|
|
2650
|
-
_Logger.instance = new _Logger();
|
|
2651
|
-
}
|
|
2652
|
-
return _Logger.instance;
|
|
2653
|
-
}
|
|
2654
|
-
/**
|
|
2655
|
-
* Initialize the logger with a session ID
|
|
2656
|
-
*/
|
|
2657
|
-
async initialize(sessionId) {
|
|
2658
|
-
this.sessionId = sessionId;
|
|
2659
|
-
const debugDir = path5.join(os.homedir(), ".bike4mind", "debug");
|
|
2660
|
-
await fs5.mkdir(debugDir, { recursive: true });
|
|
2661
|
-
this.logFilePath = path5.join(debugDir, `${sessionId}.txt`);
|
|
2662
|
-
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
2663
|
-
}
|
|
2664
|
-
/**
|
|
2665
|
-
* Set whether verbose console logging is enabled
|
|
2666
|
-
*/
|
|
2667
|
-
setVerbose(enabled) {
|
|
2668
|
-
this.consoleVerbose = enabled;
|
|
2669
|
-
}
|
|
2670
|
-
/**
|
|
2671
|
-
* Set whether file logging is enabled
|
|
2672
|
-
*/
|
|
2673
|
-
setFileLoggingEnabled(enabled) {
|
|
2674
|
-
this.fileLoggingEnabled = enabled;
|
|
2675
|
-
}
|
|
2676
|
-
/**
|
|
2677
|
-
* DEBUG level - verbose-only console, always file
|
|
2678
|
-
*/
|
|
2679
|
-
debug(message) {
|
|
2680
|
-
this.writeToFile("DEBUG", message).catch(() => {
|
|
2681
|
-
});
|
|
2682
|
-
if (this.consoleVerbose) {
|
|
2683
|
-
console.log(message);
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
/**
|
|
2687
|
-
* INFO level - always shown to user
|
|
2688
|
-
*/
|
|
2689
|
-
info(message) {
|
|
2690
|
-
this.writeToFile("INFO", message).catch(() => {
|
|
2691
|
-
});
|
|
2692
|
-
console.log(message);
|
|
2693
|
-
}
|
|
2694
|
-
/**
|
|
2695
|
-
* WARN level - always shown to user
|
|
2696
|
-
*/
|
|
2697
|
-
warn(message) {
|
|
2698
|
-
this.writeToFile("WARN", message).catch(() => {
|
|
2699
|
-
});
|
|
2700
|
-
console.warn(message);
|
|
2701
|
-
}
|
|
2702
|
-
/**
|
|
2703
|
-
* ERROR level - always shown to user
|
|
2704
|
-
*/
|
|
2705
|
-
error(message, err) {
|
|
2706
|
-
this.writeToFile("ERROR", message).catch(() => {
|
|
2707
|
-
});
|
|
2708
|
-
if (err) {
|
|
2709
|
-
this.logErrorDetailsToFile(err).catch(() => {
|
|
2710
|
-
});
|
|
2711
|
-
}
|
|
2712
|
-
console.error(message);
|
|
2713
|
-
}
|
|
2714
|
-
/**
|
|
2715
|
-
* Write log entry to file
|
|
2716
|
-
*/
|
|
2717
|
-
async writeToFile(level, message) {
|
|
2718
|
-
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
2719
|
-
return;
|
|
2720
|
-
}
|
|
2721
|
-
try {
|
|
2722
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
2723
|
-
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
2724
|
-
`;
|
|
2725
|
-
await fs5.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
2726
|
-
} catch (error) {
|
|
2727
|
-
console.error("File logging failed:", error);
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
/**
|
|
2731
|
-
* Log error details to file
|
|
2732
|
-
*/
|
|
2733
|
-
async logErrorDetailsToFile(err) {
|
|
2734
|
-
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
2735
|
-
return;
|
|
2736
|
-
}
|
|
2737
|
-
try {
|
|
2738
|
-
if (err && typeof err === "object" && "response" in err && err.response) {
|
|
2739
|
-
const response = err.response;
|
|
2740
|
-
const config = err && typeof err === "object" && "config" in err ? err.config : void 0;
|
|
2741
|
-
await this.writeToFile("ERROR", ` Status: ${response.status} ${response.statusText || ""}`);
|
|
2742
|
-
await this.writeToFile("ERROR", ` URL: ${config?.url || "unknown"}`);
|
|
2743
|
-
await this.writeToFile("ERROR", ` Headers: ${this.safeStringify(response.headers)}`);
|
|
2744
|
-
if (response.data) {
|
|
2745
|
-
const errorText = this.extractErrorMessage(response.data);
|
|
2746
|
-
if (errorText.trim().startsWith("<!DOCTYPE") || errorText.trim().startsWith("<html")) {
|
|
2747
|
-
await this.writeToFile("ERROR", ` Response Type: HTML Error Page`);
|
|
2748
|
-
const parsedError = this.parseHtmlError(errorText);
|
|
2749
|
-
if (parsedError) {
|
|
2750
|
-
await this.writeToFile("ERROR", ` Error Message: ${parsedError}`);
|
|
2751
|
-
}
|
|
2752
|
-
await this.writeToFile("ERROR", ` Raw HTML: ${this.truncate(errorText, 1e3)}`);
|
|
2753
|
-
} else {
|
|
2754
|
-
const preview = this.truncate(errorText, 500);
|
|
2755
|
-
await this.writeToFile("ERROR", ` Response: ${preview}`);
|
|
2756
|
-
}
|
|
2757
|
-
} else {
|
|
2758
|
-
await this.writeToFile("ERROR", ` Response: (no data)`);
|
|
2759
|
-
}
|
|
2760
|
-
}
|
|
2761
|
-
if (err && typeof err === "object" && "stack" in err && typeof err.stack === "string") {
|
|
2762
|
-
const stackLines = err.stack.split("\n").slice(0, 5).join("\n ");
|
|
2763
|
-
await this.writeToFile("ERROR", ` Stack: ${stackLines}`);
|
|
2764
|
-
} else if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
2765
|
-
await this.writeToFile("ERROR", ` Message: ${err.message}`);
|
|
2766
|
-
}
|
|
2767
|
-
} catch (error) {
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
/**
|
|
2771
|
-
* Safely stringify object, handling circular references
|
|
2772
|
-
*/
|
|
2773
|
-
safeStringify(obj) {
|
|
2774
|
-
try {
|
|
2775
|
-
return JSON.stringify(obj);
|
|
2776
|
-
} catch (error) {
|
|
2777
|
-
if (error instanceof Error && error.message.includes("circular")) {
|
|
2778
|
-
try {
|
|
2779
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
2780
|
-
return JSON.stringify(obj, (key, value) => {
|
|
2781
|
-
if (typeof value === "object" && value !== null) {
|
|
2782
|
-
if (seen.has(value)) {
|
|
2783
|
-
return "[Circular]";
|
|
2784
|
-
}
|
|
2785
|
-
seen.add(value);
|
|
2786
|
-
}
|
|
2787
|
-
return value;
|
|
2788
|
-
});
|
|
2789
|
-
} catch {
|
|
2790
|
-
return "[Unable to stringify]";
|
|
2791
|
-
}
|
|
2792
|
-
}
|
|
2793
|
-
return "[Stringify error]";
|
|
2794
|
-
}
|
|
2795
|
-
}
|
|
2796
|
-
/**
|
|
2797
|
-
* Extract readable text from error response data
|
|
2798
|
-
*/
|
|
2799
|
-
extractErrorMessage(data) {
|
|
2800
|
-
if (Buffer.isBuffer(data)) {
|
|
2801
|
-
return data.toString("utf-8");
|
|
2802
|
-
}
|
|
2803
|
-
if (typeof data === "string") {
|
|
2804
|
-
return data;
|
|
2805
|
-
}
|
|
2806
|
-
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) {
|
|
2807
|
-
const chunks = [];
|
|
2808
|
-
for (const chunk of data._readableState.buffer) {
|
|
2809
|
-
if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "Buffer" && "data" in chunk && Array.isArray(chunk.data)) {
|
|
2810
|
-
chunks.push(Buffer.from(chunk.data));
|
|
2811
|
-
} else if (Buffer.isBuffer(chunk)) {
|
|
2812
|
-
chunks.push(chunk);
|
|
2813
|
-
} else if (chunk && typeof chunk === "object" && "data" in chunk) {
|
|
2814
|
-
if (Buffer.isBuffer(chunk.data)) {
|
|
2815
|
-
chunks.push(chunk.data);
|
|
2816
|
-
} else if (Array.isArray(chunk.data)) {
|
|
2817
|
-
chunks.push(Buffer.from(chunk.data));
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
if (chunks.length > 0) {
|
|
2822
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
2825
|
-
return this.safeStringify(data);
|
|
2826
|
-
}
|
|
2827
|
-
/**
|
|
2828
|
-
* Parse HTML error page to extract error message
|
|
2829
|
-
*/
|
|
2830
|
-
parseHtmlError(html) {
|
|
2831
|
-
const titleMatch = html.match(/<title>(.*?)<\/title>/i);
|
|
2832
|
-
const h1Match = html.match(/<h1>(.*?)<\/h1>/i);
|
|
2833
|
-
const bodyMatch = html.match(/<body[^>]*>(.*?)<\/body>/is);
|
|
2834
|
-
if (titleMatch && titleMatch[1] !== "Error") {
|
|
2835
|
-
return titleMatch[1].trim();
|
|
2836
|
-
}
|
|
2837
|
-
if (h1Match) {
|
|
2838
|
-
return h1Match[1].trim();
|
|
2839
|
-
}
|
|
2840
|
-
if (bodyMatch) {
|
|
2841
|
-
const text = bodyMatch[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
2842
|
-
return text.substring(0, 200);
|
|
2843
|
-
}
|
|
2844
|
-
return null;
|
|
2845
|
-
}
|
|
2846
|
-
/**
|
|
2847
|
-
* Truncate string to max length with ellipsis
|
|
2848
|
-
*/
|
|
2849
|
-
truncate(str, maxLength) {
|
|
2850
|
-
if (str.length <= maxLength) {
|
|
2851
|
-
return str;
|
|
2852
|
-
}
|
|
2853
|
-
return str.substring(0, maxLength) + "... [truncated]";
|
|
2854
|
-
}
|
|
2855
|
-
/**
|
|
2856
|
-
* Format bytes to human-readable size
|
|
2857
|
-
*/
|
|
2858
|
-
formatBytes(bytes) {
|
|
2859
|
-
if (bytes === 0) return "0 B";
|
|
2860
|
-
const k = 1024;
|
|
2861
|
-
const sizes = ["B", "KB", "MB", "GB"];
|
|
2862
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
2863
|
-
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
2864
|
-
}
|
|
2865
|
-
/**
|
|
2866
|
-
* Clean up old debug logs (older than 30 days)
|
|
2867
|
-
*/
|
|
2868
|
-
async cleanupOldLogs() {
|
|
2869
|
-
if (!this.fileLoggingEnabled) return;
|
|
2870
|
-
try {
|
|
2871
|
-
const debugDir = path5.join(os.homedir(), ".bike4mind", "debug");
|
|
2872
|
-
const files = await fs5.readdir(debugDir);
|
|
2873
|
-
const now = Date.now();
|
|
2874
|
-
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
2875
|
-
for (const file of files) {
|
|
2876
|
-
const filePath = path5.join(debugDir, file);
|
|
2877
|
-
const stats = await fs5.stat(filePath);
|
|
2878
|
-
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
2879
|
-
await fs5.unlink(filePath);
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2882
|
-
} catch (error) {
|
|
2883
|
-
console.error("Failed to cleanup old logs:", error);
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
};
|
|
2887
|
-
var logger = Logger2.getInstance();
|
|
2888
|
-
logger.setVerbose(process.env.B4M_VERBOSE === "1");
|
|
2889
2640
|
|
|
2890
2641
|
// src/utils/commandParser.ts
|
|
2642
|
+
import matter from "gray-matter";
|
|
2643
|
+
import { z } from "zod";
|
|
2891
2644
|
var flexibleString = z.union([z.string(), z.array(z.string())]).transform((val) => Array.isArray(val) ? val.join(" ") : val).optional();
|
|
2892
2645
|
var flexibleStringArray = z.union([z.string(), z.array(z.string())]).transform((val) => Array.isArray(val) ? val : [val]).optional();
|
|
2893
2646
|
function needsQuoting(value) {
|
|
@@ -3042,17 +2795,17 @@ function extractCommandName(filename) {
|
|
|
3042
2795
|
var CustomCommandStore = class {
|
|
3043
2796
|
constructor(projectRoot) {
|
|
3044
2797
|
this.commands = /* @__PURE__ */ new Map();
|
|
3045
|
-
const home =
|
|
2798
|
+
const home = os.homedir();
|
|
3046
2799
|
const root = projectRoot || process.cwd();
|
|
3047
2800
|
this.globalCommandsDirs = [
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
2801
|
+
path5.join(home, ".bike4mind", "commands"),
|
|
2802
|
+
path5.join(home, ".claude", "commands"),
|
|
2803
|
+
path5.join(home, ".claude", "skills")
|
|
3051
2804
|
];
|
|
3052
2805
|
this.projectCommandsDirs = [
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
2806
|
+
path5.join(root, ".bike4mind", "commands"),
|
|
2807
|
+
path5.join(root, ".claude", "commands"),
|
|
2808
|
+
path5.join(root, ".claude", "skills")
|
|
3056
2809
|
];
|
|
3057
2810
|
}
|
|
3058
2811
|
/**
|
|
@@ -3077,7 +2830,7 @@ var CustomCommandStore = class {
|
|
|
3077
2830
|
*/
|
|
3078
2831
|
async loadCommandsFromDirectory(directory, source) {
|
|
3079
2832
|
try {
|
|
3080
|
-
const stats = await
|
|
2833
|
+
const stats = await fs5.stat(directory);
|
|
3081
2834
|
if (!stats.isDirectory()) {
|
|
3082
2835
|
return;
|
|
3083
2836
|
}
|
|
@@ -3110,9 +2863,9 @@ var CustomCommandStore = class {
|
|
|
3110
2863
|
async findCommandFiles(directory) {
|
|
3111
2864
|
const files = [];
|
|
3112
2865
|
try {
|
|
3113
|
-
const entries = await
|
|
2866
|
+
const entries = await fs5.readdir(directory, { withFileTypes: true });
|
|
3114
2867
|
for (const entry of entries) {
|
|
3115
|
-
const fullPath =
|
|
2868
|
+
const fullPath = path5.join(directory, entry.name);
|
|
3116
2869
|
if (entry.isDirectory()) {
|
|
3117
2870
|
const subFiles = await this.findCommandFiles(fullPath);
|
|
3118
2871
|
files.push(...subFiles);
|
|
@@ -3132,14 +2885,14 @@ var CustomCommandStore = class {
|
|
|
3132
2885
|
* @param source - Source identifier ('global' or 'project')
|
|
3133
2886
|
*/
|
|
3134
2887
|
async loadCommandFile(filePath, source) {
|
|
3135
|
-
const filename =
|
|
2888
|
+
const filename = path5.basename(filePath);
|
|
3136
2889
|
const isSkillFile = filename.toLowerCase() === "skill.md";
|
|
3137
2890
|
const commandName = isSkillFile ? this.extractSkillName(filePath) : extractCommandName(filename);
|
|
3138
2891
|
if (!commandName) {
|
|
3139
2892
|
console.warn(`Invalid command filename: ${filename} (must end with .md and have valid name)`);
|
|
3140
2893
|
return;
|
|
3141
2894
|
}
|
|
3142
|
-
const fileContent = await
|
|
2895
|
+
const fileContent = await fs5.readFile(filePath, "utf-8");
|
|
3143
2896
|
const command = parseCommandFile(fileContent, filePath, commandName, source);
|
|
3144
2897
|
this.commands.set(commandName, command);
|
|
3145
2898
|
}
|
|
@@ -3151,7 +2904,7 @@ var CustomCommandStore = class {
|
|
|
3151
2904
|
* @returns Skill name or null if invalid
|
|
3152
2905
|
*/
|
|
3153
2906
|
extractSkillName(filePath) {
|
|
3154
|
-
const parentDir =
|
|
2907
|
+
const parentDir = path5.basename(path5.dirname(filePath));
|
|
3155
2908
|
return parentDir && parentDir !== "skills" ? parentDir : null;
|
|
3156
2909
|
}
|
|
3157
2910
|
/**
|
|
@@ -3213,15 +2966,15 @@ var CustomCommandStore = class {
|
|
|
3213
2966
|
*/
|
|
3214
2967
|
async createCommandFile(name, isGlobal = false) {
|
|
3215
2968
|
const targetDir = isGlobal ? this.globalCommandsDirs[0] : this.projectCommandsDirs[0];
|
|
3216
|
-
const filePath =
|
|
3217
|
-
const fileExists = await
|
|
2969
|
+
const filePath = path5.join(targetDir, `${name}.md`);
|
|
2970
|
+
const fileExists = await fs5.access(filePath).then(
|
|
3218
2971
|
() => true,
|
|
3219
2972
|
() => false
|
|
3220
2973
|
);
|
|
3221
2974
|
if (fileExists) {
|
|
3222
2975
|
throw new Error(`Command file already exists: ${filePath}`);
|
|
3223
2976
|
}
|
|
3224
|
-
await
|
|
2977
|
+
await fs5.mkdir(targetDir, { recursive: true });
|
|
3225
2978
|
const template = `---
|
|
3226
2979
|
description: ${name} command
|
|
3227
2980
|
argument-hint: [args]
|
|
@@ -3236,7 +2989,7 @@ You can use:
|
|
|
3236
2989
|
- $1, $2, etc. for positional arguments
|
|
3237
2990
|
- @filename for file references
|
|
3238
2991
|
`;
|
|
3239
|
-
await
|
|
2992
|
+
await fs5.writeFile(filePath, template, "utf-8");
|
|
3240
2993
|
return filePath;
|
|
3241
2994
|
}
|
|
3242
2995
|
};
|
|
@@ -3717,18 +3470,23 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
|
|
|
3717
3470
|
async executeToolWithQueueFallback(toolUse) {
|
|
3718
3471
|
const queuedObs = this.observationQueue.find((obs) => obs.toolId === getToolId(toolUse));
|
|
3719
3472
|
if (queuedObs) {
|
|
3720
|
-
const
|
|
3473
|
+
const result = queuedObs.result;
|
|
3721
3474
|
const index = this.observationQueue.indexOf(queuedObs);
|
|
3722
3475
|
this.observationQueue.splice(index, 1);
|
|
3723
|
-
return typeof
|
|
3476
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
3724
3477
|
}
|
|
3725
3478
|
const tool = this.context.tools.find((t) => t.toolSchema.name === toolUse.name);
|
|
3726
3479
|
if (!tool) {
|
|
3727
|
-
|
|
3480
|
+
return `Error: Tool ${toolUse.name} not found in agent context`;
|
|
3481
|
+
}
|
|
3482
|
+
try {
|
|
3483
|
+
const params = this.parseToolArguments(toolUse.arguments);
|
|
3484
|
+
const result = await tool.toolFn(params);
|
|
3485
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
3486
|
+
} catch (error) {
|
|
3487
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3488
|
+
return `Error: ${message}`;
|
|
3728
3489
|
}
|
|
3729
|
-
const params = this.parseToolArguments(toolUse.arguments);
|
|
3730
|
-
const result = await tool.toolFn(params);
|
|
3731
|
-
return typeof result === "string" ? result : JSON.stringify(result);
|
|
3732
3490
|
}
|
|
3733
3491
|
/**
|
|
3734
3492
|
* Build and append tool call/result messages for the conversation history
|
|
@@ -3806,6 +3564,7 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
3806
3564
|
grep_search: "prompt_default",
|
|
3807
3565
|
glob_files: "prompt_default",
|
|
3808
3566
|
get_file_tree: "prompt_default",
|
|
3567
|
+
get_file_structure: "prompt_default",
|
|
3809
3568
|
git_status: "prompt_default",
|
|
3810
3569
|
git_diff: "prompt_default",
|
|
3811
3570
|
git_log: "prompt_default",
|
|
@@ -4380,7 +4139,7 @@ import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
|
4380
4139
|
import OpenAI2 from "openai";
|
|
4381
4140
|
|
|
4382
4141
|
// ../../b4m-core/packages/services/dist/src/importHistoryService/index.js
|
|
4383
|
-
import
|
|
4142
|
+
import fs6, { unlinkSync } from "fs";
|
|
4384
4143
|
import yauzl from "yauzl";
|
|
4385
4144
|
import axios3 from "axios";
|
|
4386
4145
|
|
|
@@ -9328,15 +9087,15 @@ var planetVisibilityTool = {
|
|
|
9328
9087
|
};
|
|
9329
9088
|
|
|
9330
9089
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/fileRead/index.js
|
|
9331
|
-
import { promises as
|
|
9090
|
+
import { promises as fs7 } from "fs";
|
|
9332
9091
|
import { existsSync as existsSync3, statSync as statSync4 } from "fs";
|
|
9333
|
-
import
|
|
9092
|
+
import path6 from "path";
|
|
9334
9093
|
var MAX_FILE_SIZE2 = 10 * 1024 * 1024;
|
|
9335
9094
|
async function readFileContent(params) {
|
|
9336
9095
|
const { path: filePath, encoding = "utf-8", offset = 0, limit } = params;
|
|
9337
|
-
const normalizedPath =
|
|
9338
|
-
const resolvedPath =
|
|
9339
|
-
const cwd =
|
|
9096
|
+
const normalizedPath = path6.normalize(filePath);
|
|
9097
|
+
const resolvedPath = path6.resolve(process.cwd(), normalizedPath);
|
|
9098
|
+
const cwd = path6.resolve(process.cwd());
|
|
9340
9099
|
if (!resolvedPath.startsWith(cwd)) {
|
|
9341
9100
|
throw new Error(`Access denied: Cannot read files outside of current working directory`);
|
|
9342
9101
|
}
|
|
@@ -9354,7 +9113,7 @@ async function readFileContent(params) {
|
|
|
9354
9113
|
if (isBinary && encoding === "utf-8") {
|
|
9355
9114
|
throw new Error(`File appears to be binary. Use encoding 'base64' to read binary files, or specify a different encoding.`);
|
|
9356
9115
|
}
|
|
9357
|
-
const content = await
|
|
9116
|
+
const content = await fs7.readFile(resolvedPath, encoding);
|
|
9358
9117
|
if (typeof content === "string") {
|
|
9359
9118
|
const lines = content.split("\n");
|
|
9360
9119
|
const totalLines = lines.length;
|
|
@@ -9392,7 +9151,7 @@ ${content}`;
|
|
|
9392
9151
|
}
|
|
9393
9152
|
async function checkIfBinary(filePath) {
|
|
9394
9153
|
const buffer = Buffer.alloc(8192);
|
|
9395
|
-
const fd = await
|
|
9154
|
+
const fd = await fs7.open(filePath, "r");
|
|
9396
9155
|
try {
|
|
9397
9156
|
const { bytesRead } = await fd.read(buffer, 0, 8192, 0);
|
|
9398
9157
|
const chunk = buffer.slice(0, bytesRead);
|
|
@@ -9409,7 +9168,7 @@ var fileReadTool = {
|
|
|
9409
9168
|
context.logger.info("\u{1F4C4} FileRead: Reading file", { path: params.path });
|
|
9410
9169
|
try {
|
|
9411
9170
|
const content = await readFileContent(params);
|
|
9412
|
-
const stats = statSync4(
|
|
9171
|
+
const stats = statSync4(path6.resolve(process.cwd(), path6.normalize(params.path)));
|
|
9413
9172
|
context.logger.info("\u2705 FileRead: Success", {
|
|
9414
9173
|
path: params.path,
|
|
9415
9174
|
size: stats.size,
|
|
@@ -9453,25 +9212,25 @@ var fileReadTool = {
|
|
|
9453
9212
|
};
|
|
9454
9213
|
|
|
9455
9214
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/createFile/index.js
|
|
9456
|
-
import { promises as
|
|
9215
|
+
import { promises as fs8 } from "fs";
|
|
9457
9216
|
import { existsSync as existsSync4 } from "fs";
|
|
9458
|
-
import
|
|
9217
|
+
import path7 from "path";
|
|
9459
9218
|
async function createFile(params) {
|
|
9460
9219
|
const { path: filePath, content, createDirectories = true } = params;
|
|
9461
|
-
const normalizedPath =
|
|
9462
|
-
const resolvedPath =
|
|
9463
|
-
const cwd =
|
|
9220
|
+
const normalizedPath = path7.normalize(filePath);
|
|
9221
|
+
const resolvedPath = path7.resolve(process.cwd(), normalizedPath);
|
|
9222
|
+
const cwd = path7.resolve(process.cwd());
|
|
9464
9223
|
if (!resolvedPath.startsWith(cwd)) {
|
|
9465
9224
|
throw new Error(`Access denied: Cannot create files outside of current working directory`);
|
|
9466
9225
|
}
|
|
9467
9226
|
const fileExists = existsSync4(resolvedPath);
|
|
9468
9227
|
const action = fileExists ? "overwritten" : "created";
|
|
9469
9228
|
if (createDirectories) {
|
|
9470
|
-
const dir =
|
|
9471
|
-
await
|
|
9229
|
+
const dir = path7.dirname(resolvedPath);
|
|
9230
|
+
await fs8.mkdir(dir, { recursive: true });
|
|
9472
9231
|
}
|
|
9473
|
-
await
|
|
9474
|
-
const stats = await
|
|
9232
|
+
await fs8.writeFile(resolvedPath, content, "utf-8");
|
|
9233
|
+
const stats = await fs8.stat(resolvedPath);
|
|
9475
9234
|
const lines = content.split("\n").length;
|
|
9476
9235
|
return `File ${action} successfully: ${filePath}
|
|
9477
9236
|
Size: ${stats.size} bytes
|
|
@@ -9482,7 +9241,7 @@ var createFileTool = {
|
|
|
9482
9241
|
implementation: (context) => ({
|
|
9483
9242
|
toolFn: async (value) => {
|
|
9484
9243
|
const params = value;
|
|
9485
|
-
const fileExists = existsSync4(
|
|
9244
|
+
const fileExists = existsSync4(path7.resolve(process.cwd(), path7.normalize(params.path)));
|
|
9486
9245
|
context.logger.info(`\u{1F4DD} CreateFile: ${fileExists ? "Overwriting" : "Creating"} file`, {
|
|
9487
9246
|
path: params.path,
|
|
9488
9247
|
size: params.content.length
|
|
@@ -9524,7 +9283,7 @@ var createFileTool = {
|
|
|
9524
9283
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/globFiles/index.js
|
|
9525
9284
|
import { glob } from "glob";
|
|
9526
9285
|
import { stat } from "fs/promises";
|
|
9527
|
-
import
|
|
9286
|
+
import path8 from "path";
|
|
9528
9287
|
var DEFAULT_IGNORE_PATTERNS2 = [
|
|
9529
9288
|
"**/node_modules/**",
|
|
9530
9289
|
"**/.git/**",
|
|
@@ -9540,7 +9299,7 @@ var DEFAULT_IGNORE_PATTERNS2 = [
|
|
|
9540
9299
|
async function findFiles(params) {
|
|
9541
9300
|
const { pattern, dir_path, case_sensitive = true, respect_git_ignore = true } = params;
|
|
9542
9301
|
const baseCwd = process.cwd();
|
|
9543
|
-
const targetDir = dir_path ?
|
|
9302
|
+
const targetDir = dir_path ? path8.resolve(baseCwd, path8.normalize(dir_path)) : baseCwd;
|
|
9544
9303
|
if (!targetDir.startsWith(baseCwd)) {
|
|
9545
9304
|
throw new Error(`Access denied: Cannot search outside of current working directory`);
|
|
9546
9305
|
}
|
|
@@ -9580,7 +9339,7 @@ async function findFiles(params) {
|
|
|
9580
9339
|
const summary = `Found ${filesWithStats.length} file(s)${truncated ? ` (showing first ${MAX_RESULTS})` : ""} matching: ${pattern}`;
|
|
9581
9340
|
const dirInfo = dir_path ? `
|
|
9582
9341
|
Directory: ${dir_path}` : "";
|
|
9583
|
-
const filesList = results.map((file) =>
|
|
9342
|
+
const filesList = results.map((file) => path8.relative(baseCwd, file.path)).join("\n");
|
|
9584
9343
|
return `${summary}${dirInfo}
|
|
9585
9344
|
|
|
9586
9345
|
${filesList}`;
|
|
@@ -9634,7 +9393,7 @@ var globFilesTool = {
|
|
|
9634
9393
|
|
|
9635
9394
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/grepSearch/index.js
|
|
9636
9395
|
import { stat as stat2 } from "fs/promises";
|
|
9637
|
-
import
|
|
9396
|
+
import path9 from "path";
|
|
9638
9397
|
import { execFile } from "child_process";
|
|
9639
9398
|
import { promisify } from "util";
|
|
9640
9399
|
import { createRequire } from "module";
|
|
@@ -9643,18 +9402,18 @@ var require2 = createRequire(import.meta.url);
|
|
|
9643
9402
|
function getRipgrepPath() {
|
|
9644
9403
|
try {
|
|
9645
9404
|
const ripgrepPath = require2.resolve("@vscode/ripgrep");
|
|
9646
|
-
const ripgrepDir =
|
|
9647
|
-
const rgBinary =
|
|
9405
|
+
const ripgrepDir = path9.dirname(ripgrepPath);
|
|
9406
|
+
const rgBinary = path9.join(ripgrepDir, "..", "bin", "rg" + (process.platform === "win32" ? ".exe" : ""));
|
|
9648
9407
|
return rgBinary;
|
|
9649
9408
|
} catch (error) {
|
|
9650
9409
|
throw new Error("ripgrep is not available. Please install @vscode/ripgrep: pnpm add @vscode/ripgrep --filter @bike4mind/services");
|
|
9651
9410
|
}
|
|
9652
9411
|
}
|
|
9653
9412
|
function isPathWithinWorkspace(targetPath, baseCwd) {
|
|
9654
|
-
const resolvedTarget =
|
|
9655
|
-
const resolvedBase =
|
|
9656
|
-
const relativePath =
|
|
9657
|
-
return !relativePath.startsWith("..") && !
|
|
9413
|
+
const resolvedTarget = path9.resolve(targetPath);
|
|
9414
|
+
const resolvedBase = path9.resolve(baseCwd);
|
|
9415
|
+
const relativePath = path9.relative(resolvedBase, resolvedTarget);
|
|
9416
|
+
return !relativePath.startsWith("..") && !path9.isAbsolute(relativePath);
|
|
9658
9417
|
}
|
|
9659
9418
|
function convertGlobToRipgrepGlobs(globPattern) {
|
|
9660
9419
|
if (!globPattern || globPattern === "**/*") {
|
|
@@ -9670,7 +9429,7 @@ function convertGlobToRipgrepGlobs(globPattern) {
|
|
|
9670
9429
|
async function searchFiles2(params) {
|
|
9671
9430
|
const { pattern, dir_path, include } = params;
|
|
9672
9431
|
const baseCwd = process.cwd();
|
|
9673
|
-
const targetDir = dir_path ?
|
|
9432
|
+
const targetDir = dir_path ? path9.resolve(baseCwd, dir_path) : baseCwd;
|
|
9674
9433
|
if (!isPathWithinWorkspace(targetDir, baseCwd)) {
|
|
9675
9434
|
throw new Error(`Path validation failed: "${dir_path}" resolves outside the allowed workspace directory`);
|
|
9676
9435
|
}
|
|
@@ -9732,7 +9491,7 @@ async function searchFiles2(params) {
|
|
|
9732
9491
|
if (item.type === "match") {
|
|
9733
9492
|
const match = item;
|
|
9734
9493
|
allMatches.push({
|
|
9735
|
-
filePath:
|
|
9494
|
+
filePath: path9.relative(targetDir, match.data.path.text) || path9.basename(match.data.path.text),
|
|
9736
9495
|
lineNumber: match.data.line_number,
|
|
9737
9496
|
line: match.data.lines.text.trimEnd()
|
|
9738
9497
|
// Remove trailing newline
|
|
@@ -9825,14 +9584,14 @@ var grepSearchTool = {
|
|
|
9825
9584
|
};
|
|
9826
9585
|
|
|
9827
9586
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/deleteFile/index.js
|
|
9828
|
-
import { promises as
|
|
9587
|
+
import { promises as fs9 } from "fs";
|
|
9829
9588
|
import { existsSync as existsSync5, statSync as statSync5 } from "fs";
|
|
9830
|
-
import
|
|
9589
|
+
import path10 from "path";
|
|
9831
9590
|
async function deleteFile(params) {
|
|
9832
9591
|
const { path: filePath, recursive = false } = params;
|
|
9833
|
-
const normalizedPath =
|
|
9834
|
-
const resolvedPath =
|
|
9835
|
-
const cwd =
|
|
9592
|
+
const normalizedPath = path10.normalize(filePath);
|
|
9593
|
+
const resolvedPath = path10.resolve(process.cwd(), normalizedPath);
|
|
9594
|
+
const cwd = path10.resolve(process.cwd());
|
|
9836
9595
|
if (!resolvedPath.startsWith(cwd)) {
|
|
9837
9596
|
throw new Error(`Access denied: Cannot delete files outside of current working directory`);
|
|
9838
9597
|
}
|
|
@@ -9846,10 +9605,10 @@ async function deleteFile(params) {
|
|
|
9846
9605
|
throw new Error(`Path is a directory: ${filePath}. Use recursive=true to delete directories and their contents.`);
|
|
9847
9606
|
}
|
|
9848
9607
|
if (isDirectory) {
|
|
9849
|
-
await
|
|
9608
|
+
await fs9.rm(resolvedPath, { recursive: true, force: true });
|
|
9850
9609
|
return `Directory deleted successfully: ${filePath}`;
|
|
9851
9610
|
} else {
|
|
9852
|
-
await
|
|
9611
|
+
await fs9.unlink(resolvedPath);
|
|
9853
9612
|
return `File deleted successfully: ${filePath}
|
|
9854
9613
|
Size: ${size} bytes`;
|
|
9855
9614
|
}
|
|
@@ -9859,7 +9618,7 @@ var deleteFileTool = {
|
|
|
9859
9618
|
implementation: (context) => ({
|
|
9860
9619
|
toolFn: async (value) => {
|
|
9861
9620
|
const params = value;
|
|
9862
|
-
const resolvedPath =
|
|
9621
|
+
const resolvedPath = path10.resolve(process.cwd(), path10.normalize(params.path));
|
|
9863
9622
|
const isDirectory = existsSync5(resolvedPath) && statSync5(resolvedPath).isDirectory();
|
|
9864
9623
|
context.logger.info(`\u{1F5D1}\uFE0F DeleteFile: Deleting ${isDirectory ? "directory" : "file"}`, {
|
|
9865
9624
|
path: params.path,
|
|
@@ -9985,7 +9744,7 @@ var knowledgeBaseSearchTool = {
|
|
|
9985
9744
|
|
|
9986
9745
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
9987
9746
|
import { spawn } from "child_process";
|
|
9988
|
-
import
|
|
9747
|
+
import path11 from "path";
|
|
9989
9748
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
9990
9749
|
var MAX_OUTPUT_SIZE = 100 * 1024;
|
|
9991
9750
|
var DANGEROUS_PATTERNS = [
|
|
@@ -10169,7 +9928,7 @@ async function executeBashCommand(params) {
|
|
|
10169
9928
|
};
|
|
10170
9929
|
}
|
|
10171
9930
|
const baseCwd = process.cwd();
|
|
10172
|
-
const targetCwd = relativeCwd ?
|
|
9931
|
+
const targetCwd = relativeCwd ? path11.resolve(baseCwd, relativeCwd) : baseCwd;
|
|
10173
9932
|
const effectiveTimeout = Math.min(timeout, 5 * 60 * 1e3);
|
|
10174
9933
|
return new Promise((resolve3) => {
|
|
10175
9934
|
let stdout = "";
|
|
@@ -10359,9 +10118,9 @@ BLOCKED OPERATIONS:
|
|
|
10359
10118
|
};
|
|
10360
10119
|
|
|
10361
10120
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editLocalFile/index.js
|
|
10362
|
-
import { promises as
|
|
10121
|
+
import { promises as fs10 } from "fs";
|
|
10363
10122
|
import { existsSync as existsSync6 } from "fs";
|
|
10364
|
-
import
|
|
10123
|
+
import path12 from "path";
|
|
10365
10124
|
import { diffLines as diffLines3 } from "diff";
|
|
10366
10125
|
function generateDiff(original, modified) {
|
|
10367
10126
|
const differences = diffLines3(original, modified);
|
|
@@ -10385,16 +10144,16 @@ function generateDiff(original, modified) {
|
|
|
10385
10144
|
}
|
|
10386
10145
|
async function editLocalFile(params) {
|
|
10387
10146
|
const { path: filePath, old_string, new_string } = params;
|
|
10388
|
-
const normalizedPath =
|
|
10389
|
-
const resolvedPath =
|
|
10390
|
-
const cwd =
|
|
10147
|
+
const normalizedPath = path12.normalize(filePath);
|
|
10148
|
+
const resolvedPath = path12.resolve(process.cwd(), normalizedPath);
|
|
10149
|
+
const cwd = path12.resolve(process.cwd());
|
|
10391
10150
|
if (!resolvedPath.startsWith(cwd)) {
|
|
10392
10151
|
throw new Error(`Access denied: Cannot edit files outside of current working directory`);
|
|
10393
10152
|
}
|
|
10394
10153
|
if (!existsSync6(resolvedPath)) {
|
|
10395
10154
|
throw new Error(`File not found: ${filePath}`);
|
|
10396
10155
|
}
|
|
10397
|
-
const currentContent = await
|
|
10156
|
+
const currentContent = await fs10.readFile(resolvedPath, "utf-8");
|
|
10398
10157
|
if (!currentContent.includes(old_string)) {
|
|
10399
10158
|
const preview = old_string.length > 100 ? old_string.substring(0, 100) + "..." : old_string;
|
|
10400
10159
|
throw new Error(`String to replace not found in file. Make sure the old_string matches exactly (including whitespace and line endings). Searched for: "${preview}"`);
|
|
@@ -10404,7 +10163,7 @@ async function editLocalFile(params) {
|
|
|
10404
10163
|
throw new Error(`Found ${occurrences} occurrences of the string to replace. Please provide a more specific old_string that matches exactly one location.`);
|
|
10405
10164
|
}
|
|
10406
10165
|
const newContent = currentContent.replace(old_string, new_string);
|
|
10407
|
-
await
|
|
10166
|
+
await fs10.writeFile(resolvedPath, newContent, "utf-8");
|
|
10408
10167
|
const diffResult = generateDiff(old_string, new_string);
|
|
10409
10168
|
return `File edited successfully: ${filePath}
|
|
10410
10169
|
Changes: +${diffResult.additions} lines, -${diffResult.deletions} lines
|
|
@@ -10979,7 +10738,9 @@ var QuestStartBodySchema = z139.object({
|
|
|
10979
10738
|
fabFileIds: z139.array(z139.string()).optional()
|
|
10980
10739
|
})).optional(),
|
|
10981
10740
|
/** User's timezone (IANA format, e.g., "America/New_York") */
|
|
10982
|
-
timezone: z139.string().optional()
|
|
10741
|
+
timezone: z139.string().optional(),
|
|
10742
|
+
/** Pre-fetched API key table from invoke phase — avoids redundant DB call in process (#6616 P1-a) */
|
|
10743
|
+
apiKeyTable: z139.record(z139.string(), z139.string().nullable()).optional()
|
|
10983
10744
|
});
|
|
10984
10745
|
|
|
10985
10746
|
// ../../b4m-core/packages/services/dist/src/llm/StatusManager.js
|
|
@@ -12335,8 +12096,8 @@ function getEnvironmentName(configApiConfig) {
|
|
|
12335
12096
|
}
|
|
12336
12097
|
|
|
12337
12098
|
// src/utils/contextLoader.ts
|
|
12338
|
-
import * as
|
|
12339
|
-
import * as
|
|
12099
|
+
import * as fs11 from "fs";
|
|
12100
|
+
import * as path13 from "path";
|
|
12340
12101
|
import { homedir as homedir3 } from "os";
|
|
12341
12102
|
var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
|
|
12342
12103
|
var PROJECT_CONTEXT_FILES = [
|
|
@@ -12357,9 +12118,9 @@ function formatFileSize2(bytes) {
|
|
|
12357
12118
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
12358
12119
|
}
|
|
12359
12120
|
function tryReadContextFile(dir, filename, source) {
|
|
12360
|
-
const filePath =
|
|
12121
|
+
const filePath = path13.join(dir, filename);
|
|
12361
12122
|
try {
|
|
12362
|
-
const stats =
|
|
12123
|
+
const stats = fs11.lstatSync(filePath);
|
|
12363
12124
|
if (stats.isDirectory()) {
|
|
12364
12125
|
return null;
|
|
12365
12126
|
}
|
|
@@ -12373,7 +12134,7 @@ function tryReadContextFile(dir, filename, source) {
|
|
|
12373
12134
|
error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
|
|
12374
12135
|
};
|
|
12375
12136
|
}
|
|
12376
|
-
const content =
|
|
12137
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
12377
12138
|
return {
|
|
12378
12139
|
filename,
|
|
12379
12140
|
content,
|
|
@@ -12425,7 +12186,7 @@ ${project.content}`;
|
|
|
12425
12186
|
}
|
|
12426
12187
|
async function loadContextFiles(projectDir) {
|
|
12427
12188
|
const errors = [];
|
|
12428
|
-
const globalDir =
|
|
12189
|
+
const globalDir = path13.join(homedir3(), ".bike4mind");
|
|
12429
12190
|
const projectDirectory = projectDir || process.cwd();
|
|
12430
12191
|
const [globalResult, projectResult] = await Promise.all([
|
|
12431
12192
|
Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
|
|
@@ -12696,7 +12457,7 @@ function substituteArguments(template, args) {
|
|
|
12696
12457
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
12697
12458
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
12698
12459
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
12699
|
-
import
|
|
12460
|
+
import path14 from "path";
|
|
12700
12461
|
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
12701
12462
|
var MCPClient = class {
|
|
12702
12463
|
// Note: This class handles MCP server communication with repository filtering
|
|
@@ -12734,21 +12495,20 @@ var MCPClient = class {
|
|
|
12734
12495
|
if (this.customCommand && this.customCommand.trim() !== "") {
|
|
12735
12496
|
command = this.customCommand;
|
|
12736
12497
|
args = this.customArgs ?? [];
|
|
12737
|
-
console.log(`[MCP] Using external command for ${this.serverName}: ${command} ${args.join(" ")}`);
|
|
12738
12498
|
} else {
|
|
12739
12499
|
const root = process.env.INIT_CWD || process.cwd();
|
|
12740
12500
|
const candidatePaths = [
|
|
12741
12501
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
12742
|
-
|
|
12502
|
+
path14.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
12743
12503
|
// When running from SST Lambda deployed environment (/var/task)
|
|
12744
|
-
|
|
12504
|
+
path14.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
12745
12505
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
12746
|
-
|
|
12506
|
+
path14.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
12747
12507
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
12748
|
-
|
|
12508
|
+
path14.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
12749
12509
|
// Original paths (backward compatibility)
|
|
12750
|
-
|
|
12751
|
-
|
|
12510
|
+
path14.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
12511
|
+
path14.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
12752
12512
|
];
|
|
12753
12513
|
const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
|
|
12754
12514
|
if (!serverScriptPath) {
|
|
@@ -13563,7 +13323,7 @@ var ServerLlmBackend = class {
|
|
|
13563
13323
|
logger.info("\u26A0\uFE0F Using fallback model list (no CLI-compatible models available)");
|
|
13564
13324
|
return this.getFallbackModels();
|
|
13565
13325
|
}
|
|
13566
|
-
logger.
|
|
13326
|
+
logger.debug(`\u{1F4CB} Loaded ${filteredModels.length} models from server`);
|
|
13567
13327
|
return filteredModels;
|
|
13568
13328
|
} catch (error) {
|
|
13569
13329
|
logger.warn(
|
|
@@ -13801,7 +13561,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
13801
13561
|
// package.json
|
|
13802
13562
|
var package_default = {
|
|
13803
13563
|
name: "@bike4mind/cli",
|
|
13804
|
-
version: "0.2.
|
|
13564
|
+
version: "0.2.29-cache-mcp-tools-schema-and-refactor.18845+131a0f301",
|
|
13805
13565
|
type: "module",
|
|
13806
13566
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
13807
13567
|
license: "UNLICENSED",
|
|
@@ -13896,10 +13656,12 @@ var package_default = {
|
|
|
13896
13656
|
sharp: "^0.34.5",
|
|
13897
13657
|
speakeasy: "^2.0.0",
|
|
13898
13658
|
tiktoken: "^1.0.16",
|
|
13659
|
+
"tree-sitter-wasms": "^0.1.13",
|
|
13899
13660
|
turndown: "^7.2.0",
|
|
13900
13661
|
unpdf: "^0.10.0",
|
|
13901
13662
|
uuid: "^9.0.1",
|
|
13902
13663
|
voyageai: "^0.0.4",
|
|
13664
|
+
"web-tree-sitter": "0.25.10",
|
|
13903
13665
|
xlsx: "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
13904
13666
|
yargs: "^17.7.2",
|
|
13905
13667
|
yauzl: "^3.1.3",
|
|
@@ -13909,10 +13671,10 @@ var package_default = {
|
|
|
13909
13671
|
},
|
|
13910
13672
|
devDependencies: {
|
|
13911
13673
|
"@bike4mind/agents": "0.1.0",
|
|
13912
|
-
"@bike4mind/common": "2.50.
|
|
13913
|
-
"@bike4mind/mcp": "1.29.
|
|
13914
|
-
"@bike4mind/services": "2.48.
|
|
13915
|
-
"@bike4mind/utils": "2.5.
|
|
13674
|
+
"@bike4mind/common": "2.50.1-cache-mcp-tools-schema-and-refactor.18845+131a0f301",
|
|
13675
|
+
"@bike4mind/mcp": "1.29.1-cache-mcp-tools-schema-and-refactor.18845+131a0f301",
|
|
13676
|
+
"@bike4mind/services": "2.48.1-cache-mcp-tools-schema-and-refactor.18845+131a0f301",
|
|
13677
|
+
"@bike4mind/utils": "2.5.1-cache-mcp-tools-schema-and-refactor.18845+131a0f301",
|
|
13916
13678
|
"@types/better-sqlite3": "^7.6.13",
|
|
13917
13679
|
"@types/diff": "^5.0.9",
|
|
13918
13680
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -13929,7 +13691,7 @@ var package_default = {
|
|
|
13929
13691
|
optionalDependencies: {
|
|
13930
13692
|
"@vscode/ripgrep": "^1.17.0"
|
|
13931
13693
|
},
|
|
13932
|
-
gitHead: "
|
|
13694
|
+
gitHead: "131a0f301e2a9170b2d207809ee117065b7bf54d"
|
|
13933
13695
|
};
|
|
13934
13696
|
|
|
13935
13697
|
// src/config/constants.ts
|
|
@@ -14422,9 +14184,9 @@ var SubagentOrchestrator = class {
|
|
|
14422
14184
|
};
|
|
14423
14185
|
|
|
14424
14186
|
// src/agents/AgentStore.ts
|
|
14425
|
-
import
|
|
14426
|
-
import
|
|
14427
|
-
import
|
|
14187
|
+
import fs12 from "fs/promises";
|
|
14188
|
+
import path15 from "path";
|
|
14189
|
+
import os2 from "os";
|
|
14428
14190
|
import matter2 from "gray-matter";
|
|
14429
14191
|
var FULL_MODEL_ID_PREFIXES = [
|
|
14430
14192
|
"claude-",
|
|
@@ -14570,12 +14332,12 @@ var AgentStore = class {
|
|
|
14570
14332
|
constructor(builtinDir, projectRoot) {
|
|
14571
14333
|
this.agents = /* @__PURE__ */ new Map();
|
|
14572
14334
|
const root = projectRoot || process.cwd();
|
|
14573
|
-
const home =
|
|
14335
|
+
const home = os2.homedir();
|
|
14574
14336
|
this.builtinAgentsDir = builtinDir;
|
|
14575
|
-
this.globalB4MAgentsDir =
|
|
14576
|
-
this.globalClaudeAgentsDir =
|
|
14577
|
-
this.projectB4MAgentsDir =
|
|
14578
|
-
this.projectClaudeAgentsDir =
|
|
14337
|
+
this.globalB4MAgentsDir = path15.join(home, ".bike4mind", "agents");
|
|
14338
|
+
this.globalClaudeAgentsDir = path15.join(home, ".claude", "agents");
|
|
14339
|
+
this.projectB4MAgentsDir = path15.join(root, ".bike4mind", "agents");
|
|
14340
|
+
this.projectClaudeAgentsDir = path15.join(root, ".claude", "agents");
|
|
14579
14341
|
}
|
|
14580
14342
|
/**
|
|
14581
14343
|
* Load all agents from all directories
|
|
@@ -14599,7 +14361,7 @@ var AgentStore = class {
|
|
|
14599
14361
|
*/
|
|
14600
14362
|
async loadAgentsFromDirectory(directory, source) {
|
|
14601
14363
|
try {
|
|
14602
|
-
const stats = await
|
|
14364
|
+
const stats = await fs12.stat(directory);
|
|
14603
14365
|
if (!stats.isDirectory()) {
|
|
14604
14366
|
return;
|
|
14605
14367
|
}
|
|
@@ -14627,9 +14389,9 @@ var AgentStore = class {
|
|
|
14627
14389
|
async findAgentFiles(directory) {
|
|
14628
14390
|
const files = [];
|
|
14629
14391
|
try {
|
|
14630
|
-
const entries = await
|
|
14392
|
+
const entries = await fs12.readdir(directory, { withFileTypes: true });
|
|
14631
14393
|
for (const entry of entries) {
|
|
14632
|
-
const fullPath =
|
|
14394
|
+
const fullPath = path15.join(directory, entry.name);
|
|
14633
14395
|
if (entry.isDirectory()) {
|
|
14634
14396
|
const subFiles = await this.findAgentFiles(fullPath);
|
|
14635
14397
|
files.push(...subFiles);
|
|
@@ -14646,10 +14408,10 @@ var AgentStore = class {
|
|
|
14646
14408
|
* Parse a single agent markdown file
|
|
14647
14409
|
*/
|
|
14648
14410
|
async parseAgentFile(filePath, source) {
|
|
14649
|
-
const content = await
|
|
14411
|
+
const content = await fs12.readFile(filePath, "utf-8");
|
|
14650
14412
|
const { data: frontmatter, content: body } = matter2(content);
|
|
14651
14413
|
const parsed = AgentFrontmatterSchema.parse(frontmatter);
|
|
14652
|
-
const name =
|
|
14414
|
+
const name = path15.basename(filePath, ".md");
|
|
14653
14415
|
const modelInput = parsed.model || DEFAULT_AGENT_MODEL;
|
|
14654
14416
|
const resolution = resolveModelAlias(modelInput, name, filePath);
|
|
14655
14417
|
if (!resolution.resolved && resolution.warning) {
|
|
@@ -14729,16 +14491,16 @@ var AgentStore = class {
|
|
|
14729
14491
|
*/
|
|
14730
14492
|
async createAgentFile(name, isGlobal = false, useClaude = true) {
|
|
14731
14493
|
const targetDir = isGlobal ? useClaude ? this.globalClaudeAgentsDir : this.globalB4MAgentsDir : useClaude ? this.projectClaudeAgentsDir : this.projectB4MAgentsDir;
|
|
14732
|
-
const filePath =
|
|
14494
|
+
const filePath = path15.join(targetDir, `${name}.md`);
|
|
14733
14495
|
try {
|
|
14734
|
-
await
|
|
14496
|
+
await fs12.access(filePath);
|
|
14735
14497
|
throw new Error(`Agent file already exists: ${filePath}`);
|
|
14736
14498
|
} catch (error) {
|
|
14737
14499
|
if (error.code !== "ENOENT") {
|
|
14738
14500
|
throw error;
|
|
14739
14501
|
}
|
|
14740
14502
|
}
|
|
14741
|
-
await
|
|
14503
|
+
await fs12.mkdir(targetDir, { recursive: true });
|
|
14742
14504
|
const template = `---
|
|
14743
14505
|
description: ${name} agent description
|
|
14744
14506
|
model: claude-3-5-haiku-20241022
|
|
@@ -14773,7 +14535,7 @@ You are a ${name} specialist. Your job is to [describe primary task].
|
|
|
14773
14535
|
## Output Format
|
|
14774
14536
|
Describe the expected output format here.
|
|
14775
14537
|
`;
|
|
14776
|
-
await
|
|
14538
|
+
await fs12.writeFile(filePath, template, "utf-8");
|
|
14777
14539
|
return filePath;
|
|
14778
14540
|
}
|
|
14779
14541
|
/**
|
|
@@ -15411,7 +15173,7 @@ function createTodoStore(onUpdate) {
|
|
|
15411
15173
|
|
|
15412
15174
|
// src/tools/findDefinitionTool.ts
|
|
15413
15175
|
import { stat as stat3 } from "fs/promises";
|
|
15414
|
-
import
|
|
15176
|
+
import path16 from "path";
|
|
15415
15177
|
import { execFile as execFile2 } from "child_process";
|
|
15416
15178
|
import { promisify as promisify2 } from "util";
|
|
15417
15179
|
import { createRequire as createRequire2 } from "module";
|
|
@@ -15432,8 +15194,8 @@ var ALL_KEYWORDS = Object.values(KIND_KEYWORDS).flat();
|
|
|
15432
15194
|
function getRipgrepPath2() {
|
|
15433
15195
|
try {
|
|
15434
15196
|
const ripgrepPath = require3.resolve("@vscode/ripgrep");
|
|
15435
|
-
const ripgrepDir =
|
|
15436
|
-
return
|
|
15197
|
+
const ripgrepDir = path16.dirname(ripgrepPath);
|
|
15198
|
+
return path16.join(ripgrepDir, "..", "bin", "rg" + (process.platform === "win32" ? ".exe" : ""));
|
|
15437
15199
|
} catch {
|
|
15438
15200
|
throw new Error(
|
|
15439
15201
|
"ripgrep is not available. Please install @vscode/ripgrep: pnpm add @vscode/ripgrep --filter @bike4mind/services"
|
|
@@ -15441,10 +15203,10 @@ function getRipgrepPath2() {
|
|
|
15441
15203
|
}
|
|
15442
15204
|
}
|
|
15443
15205
|
function isPathWithinWorkspace2(targetPath, baseCwd) {
|
|
15444
|
-
const resolvedTarget =
|
|
15445
|
-
const resolvedBase =
|
|
15446
|
-
const relativePath =
|
|
15447
|
-
return !relativePath.startsWith("..") && !
|
|
15206
|
+
const resolvedTarget = path16.resolve(targetPath);
|
|
15207
|
+
const resolvedBase = path16.resolve(baseCwd);
|
|
15208
|
+
const relativePath = path16.relative(resolvedBase, resolvedTarget);
|
|
15209
|
+
return !relativePath.startsWith("..") && !path16.isAbsolute(relativePath);
|
|
15448
15210
|
}
|
|
15449
15211
|
function escapeRegex(str) {
|
|
15450
15212
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -15477,7 +15239,7 @@ async function findDefinitions(params) {
|
|
|
15477
15239
|
throw new Error("symbol_name is required");
|
|
15478
15240
|
}
|
|
15479
15241
|
const baseCwd = process.cwd();
|
|
15480
|
-
const targetDir = search_path ?
|
|
15242
|
+
const targetDir = search_path ? path16.resolve(baseCwd, search_path) : baseCwd;
|
|
15481
15243
|
if (!isPathWithinWorkspace2(targetDir, baseCwd)) {
|
|
15482
15244
|
throw new Error(`Path validation failed: "${search_path}" resolves outside the allowed workspace directory`);
|
|
15483
15245
|
}
|
|
@@ -15532,7 +15294,7 @@ async function findDefinitions(params) {
|
|
|
15532
15294
|
const lineText = match.data.lines.text.trimEnd();
|
|
15533
15295
|
if (isLikelyDefinition(lineText)) {
|
|
15534
15296
|
allMatches.push({
|
|
15535
|
-
filePath:
|
|
15297
|
+
filePath: path16.relative(targetDir, match.data.path.text) || path16.basename(match.data.path.text),
|
|
15536
15298
|
lineNumber: match.data.line_number,
|
|
15537
15299
|
line: lineText
|
|
15538
15300
|
});
|
|
@@ -15609,6 +15371,99 @@ function createFindDefinitionTool() {
|
|
|
15609
15371
|
};
|
|
15610
15372
|
}
|
|
15611
15373
|
|
|
15374
|
+
// src/tools/getFileStructure/index.ts
|
|
15375
|
+
import { existsSync as existsSync9, promises as fs13, statSync as statSync6 } from "fs";
|
|
15376
|
+
import path17 from "path";
|
|
15377
|
+
|
|
15378
|
+
// src/tools/getFileStructure/formatter.ts
|
|
15379
|
+
var SECTIONS = [
|
|
15380
|
+
{ title: "IMPORTS", kind: "import", exportable: false },
|
|
15381
|
+
{ title: "EXPORTS", kind: "export", exportable: false },
|
|
15382
|
+
{ title: "FUNCTIONS", kind: "function", exportable: true },
|
|
15383
|
+
{ title: "CLASSES", kind: "class", exportable: true },
|
|
15384
|
+
{ title: "INTERFACES", kind: "interface", exportable: true },
|
|
15385
|
+
{ title: "TYPES", kind: "type", exportable: true },
|
|
15386
|
+
{ title: "ENUMS", kind: "enum", exportable: true }
|
|
15387
|
+
];
|
|
15388
|
+
function formatStructureOutput(filePath, items, fileSize, lineCount) {
|
|
15389
|
+
const sizeStr = fileSize < 1024 ? `${fileSize} B` : `${(fileSize / 1024).toFixed(1)} KB`;
|
|
15390
|
+
const lines = [`File: ${filePath} (${sizeStr}, ${lineCount} lines)`, ""];
|
|
15391
|
+
for (const section of SECTIONS) {
|
|
15392
|
+
const sectionItems = items.filter((i) => i.kind === section.kind);
|
|
15393
|
+
formatSection(lines, section.title, sectionItems, (item) => {
|
|
15394
|
+
const prefix = section.exportable && item.exported ? "export " : "";
|
|
15395
|
+
return `L${item.line}: ${prefix}${item.name}`;
|
|
15396
|
+
});
|
|
15397
|
+
}
|
|
15398
|
+
return lines.join("\n").trimEnd();
|
|
15399
|
+
}
|
|
15400
|
+
function formatSection(lines, title, items, format) {
|
|
15401
|
+
lines.push(`${title} (${items.length}):`);
|
|
15402
|
+
if (items.length === 0) {
|
|
15403
|
+
lines.push(" (none)");
|
|
15404
|
+
} else {
|
|
15405
|
+
for (const item of items) {
|
|
15406
|
+
lines.push(` ${format(item)}`);
|
|
15407
|
+
}
|
|
15408
|
+
}
|
|
15409
|
+
lines.push("");
|
|
15410
|
+
}
|
|
15411
|
+
|
|
15412
|
+
// src/tools/getFileStructure/index.ts
|
|
15413
|
+
var MAX_FILE_SIZE3 = 10 * 1024 * 1024;
|
|
15414
|
+
function createGetFileStructureTool() {
|
|
15415
|
+
return {
|
|
15416
|
+
toolFn: async (value) => {
|
|
15417
|
+
const params = value;
|
|
15418
|
+
try {
|
|
15419
|
+
const cwd = process.cwd();
|
|
15420
|
+
const resolvedPath = path17.resolve(cwd, params.path);
|
|
15421
|
+
if (!resolvedPath.startsWith(cwd)) {
|
|
15422
|
+
return "Error: Access denied - cannot read files outside of current working directory";
|
|
15423
|
+
}
|
|
15424
|
+
if (!existsSync9(resolvedPath)) {
|
|
15425
|
+
return `Error: File not found: ${params.path}`;
|
|
15426
|
+
}
|
|
15427
|
+
const stats = statSync6(resolvedPath);
|
|
15428
|
+
if (stats.isDirectory()) {
|
|
15429
|
+
return `Error: Path is a directory, not a file: ${params.path}`;
|
|
15430
|
+
}
|
|
15431
|
+
if (stats.size > MAX_FILE_SIZE3) {
|
|
15432
|
+
return `Error: File too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Max: ${MAX_FILE_SIZE3 / 1024 / 1024}MB`;
|
|
15433
|
+
}
|
|
15434
|
+
const ext = path17.extname(resolvedPath).toLowerCase();
|
|
15435
|
+
const { getLanguageForExtension, parseFileStructure, getSupportedLanguages } = await import("./treeSitterEngine-4SGFQDY3.js");
|
|
15436
|
+
const languageId = getLanguageForExtension(ext);
|
|
15437
|
+
if (!languageId) {
|
|
15438
|
+
const supported = getSupportedLanguages();
|
|
15439
|
+
return `Error: Unsupported file type "${ext}". Supported languages: ${supported.join(", ")}`;
|
|
15440
|
+
}
|
|
15441
|
+
const sourceCode = await fs13.readFile(resolvedPath, "utf-8");
|
|
15442
|
+
const lineCount = sourceCode.split("\n").length;
|
|
15443
|
+
const items = await parseFileStructure(sourceCode, languageId);
|
|
15444
|
+
return formatStructureOutput(params.path, items, stats.size, lineCount);
|
|
15445
|
+
} catch (error) {
|
|
15446
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
15447
|
+
return `Error analyzing file structure: ${errorMessage}`;
|
|
15448
|
+
}
|
|
15449
|
+
},
|
|
15450
|
+
toolSchema: {
|
|
15451
|
+
name: "get_file_structure",
|
|
15452
|
+
description: "Extract the high-level structure of a source file (imports, exports, functions, classes, interfaces, types) using AST parsing. Returns a concise outline with line numbers. Much more efficient than file_read when you only need to understand what a file contains or exports. Use this before file_read to decide which parts of a large file to read.",
|
|
15453
|
+
parameters: {
|
|
15454
|
+
type: "object",
|
|
15455
|
+
properties: {
|
|
15456
|
+
path: {
|
|
15457
|
+
type: "string",
|
|
15458
|
+
description: "Path to the source file (relative to cwd or absolute within cwd). Supported: .ts, .tsx, .js, .jsx, .mjs, .cjs, .py"
|
|
15459
|
+
}
|
|
15460
|
+
},
|
|
15461
|
+
required: ["path"]
|
|
15462
|
+
}
|
|
15463
|
+
}
|
|
15464
|
+
};
|
|
15465
|
+
}
|
|
15466
|
+
|
|
15612
15467
|
// src/index.tsx
|
|
15613
15468
|
process.removeAllListeners("warning");
|
|
15614
15469
|
process.on("warning", (warning) => {
|
|
@@ -15725,6 +15580,7 @@ function CliApp() {
|
|
|
15725
15580
|
});
|
|
15726
15581
|
const init = useCallback2(async () => {
|
|
15727
15582
|
try {
|
|
15583
|
+
const startupLog = [];
|
|
15728
15584
|
const config = await state.configStore.load();
|
|
15729
15585
|
const history = await state.commandHistoryStore.load();
|
|
15730
15586
|
setCommandHistory(history);
|
|
@@ -15732,7 +15588,7 @@ function CliApp() {
|
|
|
15732
15588
|
await state.customCommandStore.loadCommands();
|
|
15733
15589
|
const customCommandCount = state.customCommandStore.getCommandCount();
|
|
15734
15590
|
if (customCommandCount > 0) {
|
|
15735
|
-
|
|
15591
|
+
startupLog.push(`\u{1F4DD} Loaded ${customCommandCount} custom command${customCommandCount !== 1 ? "s" : ""}`);
|
|
15736
15592
|
}
|
|
15737
15593
|
} catch (error) {
|
|
15738
15594
|
console.warn("Failed to load custom commands:", error instanceof Error ? error.message : String(error));
|
|
@@ -15753,7 +15609,7 @@ function CliApp() {
|
|
|
15753
15609
|
} else {
|
|
15754
15610
|
isAuthenticated = true;
|
|
15755
15611
|
const daysUntilExpiry = Math.floor((expiresAt.getTime() - Date.now()) / (1e3 * 60 * 60 * 24));
|
|
15756
|
-
|
|
15612
|
+
startupLog.push(`\u2705 Authenticated (expires in ${daysUntilExpiry} day${daysUntilExpiry !== 1 ? "s" : ""})`);
|
|
15757
15613
|
}
|
|
15758
15614
|
}
|
|
15759
15615
|
if (!isAuthenticated) {
|
|
@@ -15867,22 +15723,23 @@ function CliApp() {
|
|
|
15867
15723
|
state.configStore,
|
|
15868
15724
|
apiClient
|
|
15869
15725
|
);
|
|
15870
|
-
|
|
15726
|
+
startupLog.push(`\u{1F6E0}\uFE0F Loaded ${b4mTools2.length} B4M tool(s)`);
|
|
15871
15727
|
const mcpManager = new McpManager(config);
|
|
15872
15728
|
await mcpManager.initialize();
|
|
15873
15729
|
const mcpTools = mcpManager.getTools();
|
|
15874
15730
|
if (mcpTools.length > 0) {
|
|
15875
|
-
const
|
|
15876
|
-
|
|
15731
|
+
const toolCountByServer = mcpManager.getToolCount();
|
|
15732
|
+
const serverSummaries = toolCountByServer.map((s) => `${s.serverName} (${s.count})`).join(", ");
|
|
15733
|
+
startupLog.push(`\u{1F4E1} Loaded ${mcpTools.length} MCP tool(s): ${serverSummaries}`);
|
|
15877
15734
|
} else {
|
|
15878
|
-
|
|
15735
|
+
startupLog.push(`\u{1F4E1} No MCP tools loaded`);
|
|
15879
15736
|
}
|
|
15880
15737
|
const builtinAgentsDir = new URL("./agents/defaults/", import.meta.url).pathname;
|
|
15881
15738
|
const agentProjectDir = state.configStore.getProjectConfigDir();
|
|
15882
15739
|
const agentStore = new AgentStore(builtinAgentsDir, agentProjectDir || process.cwd());
|
|
15883
15740
|
await agentStore.loadAgents();
|
|
15884
15741
|
const agentSummary = agentStore.getSummary();
|
|
15885
|
-
|
|
15742
|
+
startupLog.push(
|
|
15886
15743
|
`\u{1F916} Loaded ${agentSummary.total} agent(s): ${agentSummary.builtin} built-in, ${agentSummary.global} global, ${agentSummary.project} project`
|
|
15887
15744
|
);
|
|
15888
15745
|
const orchestrator = new SubagentOrchestrator({
|
|
@@ -15917,18 +15774,25 @@ function CliApp() {
|
|
|
15917
15774
|
sessionId: newSession.id
|
|
15918
15775
|
}) : null;
|
|
15919
15776
|
const findDefinitionTool = createFindDefinitionTool();
|
|
15920
|
-
const
|
|
15777
|
+
const getFileStructureTool = createGetFileStructureTool();
|
|
15778
|
+
const cliTools = [
|
|
15779
|
+
agentDelegateTool,
|
|
15780
|
+
...backgroundTools,
|
|
15781
|
+
writeTodosTool,
|
|
15782
|
+
findDefinitionTool,
|
|
15783
|
+
getFileStructureTool
|
|
15784
|
+
];
|
|
15921
15785
|
if (skillTool) {
|
|
15922
15786
|
cliTools.push(skillTool);
|
|
15923
15787
|
}
|
|
15924
15788
|
const allTools = [...b4mTools2, ...mcpTools, ...cliTools];
|
|
15925
|
-
|
|
15789
|
+
startupLog.push(`\u{1F4C2} Working directory: ${process.cwd()}`);
|
|
15926
15790
|
const agentNamesList = agentStore.getAgentNames().join(", ");
|
|
15927
|
-
|
|
15791
|
+
startupLog.push(`\u{1F916} Subagent delegation enabled (${agentNamesList}) + background execution`);
|
|
15928
15792
|
if (skillTool) {
|
|
15929
15793
|
const skillCount = state.customCommandStore.getCommandCount();
|
|
15930
15794
|
if (skillCount > 0) {
|
|
15931
|
-
|
|
15795
|
+
startupLog.push(`\u{1F6E0}\uFE0F Skill tool enabled (${skillCount} skills available)`);
|
|
15932
15796
|
}
|
|
15933
15797
|
}
|
|
15934
15798
|
logger.debug(
|
|
@@ -15937,13 +15801,13 @@ function CliApp() {
|
|
|
15937
15801
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
15938
15802
|
const contextResult = await loadContextFiles(projectDir);
|
|
15939
15803
|
if (contextResult.globalContext) {
|
|
15940
|
-
|
|
15804
|
+
startupLog.push(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
|
|
15941
15805
|
}
|
|
15942
15806
|
if (contextResult.projectContext) {
|
|
15943
|
-
|
|
15807
|
+
startupLog.push(`\u{1F4C4} Project context: ${contextResult.projectContext.filename}`);
|
|
15944
15808
|
}
|
|
15945
15809
|
for (const error of contextResult.errors) {
|
|
15946
|
-
|
|
15810
|
+
startupLog.push(`\u26A0\uFE0F Context file error: ${error}`);
|
|
15947
15811
|
}
|
|
15948
15812
|
let contextSection = contextResult.mergedContent ? `
|
|
15949
15813
|
|
|
@@ -16019,8 +15883,36 @@ ${contextResult.mergedContent}` : "";
|
|
|
16019
15883
|
// Store for grouped notification turn tracking
|
|
16020
15884
|
}));
|
|
16021
15885
|
setStoreSession(newSession);
|
|
15886
|
+
const bannerLines = [
|
|
15887
|
+
{ text: "\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557", ansi: "\x1B[36m\x1B[1m" },
|
|
15888
|
+
{ text: "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551", ansi: "\x1B[36m\x1B[1m" },
|
|
15889
|
+
{ text: "\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551", ansi: "\x1B[36m\x1B[1m" },
|
|
15890
|
+
{ text: "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551", ansi: "\x1B[36m\x1B[1m" },
|
|
15891
|
+
{ text: "\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551", ansi: "\x1B[36m\x1B[1m" },
|
|
15892
|
+
{ text: "\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D", ansi: "\x1B[36m\x1B[1m" },
|
|
15893
|
+
{ text: "", ansi: "" },
|
|
15894
|
+
{ text: `v${package_default.version} - AI-Powered CLI`, ansi: "\x1B[2m" },
|
|
15895
|
+
{ text: "/help for more information", ansi: "\x1B[2m" }
|
|
15896
|
+
];
|
|
15897
|
+
const bannerWidth = 30;
|
|
15898
|
+
const termWidth = process.stdout.columns || 80;
|
|
15899
|
+
const rightColWidth = termWidth - bannerWidth - 2;
|
|
15900
|
+
const truncate = (str, max) => {
|
|
15901
|
+
if (str.length > max) return str.slice(0, max - 1) + "\u2026";
|
|
15902
|
+
return str;
|
|
15903
|
+
};
|
|
15904
|
+
const totalLines = Math.max(bannerLines.length, startupLog.length);
|
|
15905
|
+
for (let i = 0; i < totalLines; i++) {
|
|
15906
|
+
const banner = bannerLines[i];
|
|
15907
|
+
const leftText = banner?.text || "";
|
|
15908
|
+
const leftAnsi = banner?.ansi || "";
|
|
15909
|
+
const right = startupLog[i] || "";
|
|
15910
|
+
const coloredLeft = leftText ? `${leftAnsi}${leftText}\x1B[0m` : "";
|
|
15911
|
+
const gap = " ".repeat(bannerWidth - leftText.length + 2);
|
|
15912
|
+
console.log(coloredLeft + gap + truncate(right, rightColWidth));
|
|
15913
|
+
}
|
|
16022
15914
|
setIsInitialized(true);
|
|
16023
|
-
console.log("
|
|
15915
|
+
console.log("");
|
|
16024
15916
|
} catch (error) {
|
|
16025
15917
|
console.error("Initialization error:", error);
|
|
16026
15918
|
setInitError(error instanceof Error ? error.message : "Unknown error");
|
|
@@ -16675,7 +16567,7 @@ Available commands:
|
|
|
16675
16567
|
/whoami - Show current authenticated user
|
|
16676
16568
|
/usage - Show credit usage and balance
|
|
16677
16569
|
/save <name> - Save current session
|
|
16678
|
-
/
|
|
16570
|
+
/resume - List and resume saved sessions
|
|
16679
16571
|
/config - Show configuration
|
|
16680
16572
|
|
|
16681
16573
|
API Configuration:
|
|
@@ -16694,7 +16586,24 @@ Project Configuration:
|
|
|
16694
16586
|
Custom Commands:
|
|
16695
16587
|
/commands - List all custom commands
|
|
16696
16588
|
/commands:new <name> - Create a new custom command
|
|
16697
|
-
/commands:reload - Reload custom commands from disk
|
|
16589
|
+
/commands:reload - Reload custom commands from disk
|
|
16590
|
+
|
|
16591
|
+
Keyboard Shortcuts:
|
|
16592
|
+
Ctrl+C - Press twice to exit
|
|
16593
|
+
Esc - Abort current operation
|
|
16594
|
+
Shift+Tab - Toggle auto-accept edits
|
|
16595
|
+
Ctrl+U - Clear current line
|
|
16596
|
+
Ctrl+K - Clear from cursor to end of line
|
|
16597
|
+
Ctrl+W - Delete word before cursor
|
|
16598
|
+
Ctrl+A - Move cursor to beginning
|
|
16599
|
+
Ctrl+E - Move cursor to end
|
|
16600
|
+
Ctrl+B / \u2190 - Move cursor left
|
|
16601
|
+
Ctrl+F / \u2192 - Move cursor right
|
|
16602
|
+
Ctrl+D - Delete character at cursor
|
|
16603
|
+
Ctrl+L - Clear input
|
|
16604
|
+
\u2191 / \u2193 - Navigate history / autocomplete
|
|
16605
|
+
Tab - Accept autocomplete suggestion
|
|
16606
|
+
Shift+Cmd+Click - Open links in browser${hasCustomCommands ? "\n\n\u{1F4DD} Custom Commands Available:" : ""}${hasCustomCommands ? customCommands.map((cmd) => {
|
|
16698
16607
|
const source = cmd.source === "global" ? "\u{1F3E0}" : "\u{1F4C1}";
|
|
16699
16608
|
const argHint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
|
|
16700
16609
|
return `
|
|
@@ -16724,6 +16633,7 @@ Custom Commands:
|
|
|
16724
16633
|
console.log(`\u2705 Session saved as "${sessionName}"`);
|
|
16725
16634
|
break;
|
|
16726
16635
|
}
|
|
16636
|
+
case "resume":
|
|
16727
16637
|
case "sessions": {
|
|
16728
16638
|
const sessions = await state.sessionStore.list(20);
|
|
16729
16639
|
if (sessions.length === 0) {
|
|
@@ -16734,7 +16644,6 @@ Custom Commands:
|
|
|
16734
16644
|
const handleSessionSelect = async (selectedSession) => {
|
|
16735
16645
|
setState((prev) => ({ ...prev, sessionSelector: null }));
|
|
16736
16646
|
if (!selectedSession) {
|
|
16737
|
-
console.log("\u274C Session selection cancelled");
|
|
16738
16647
|
return;
|
|
16739
16648
|
}
|
|
16740
16649
|
const loadedSession = await state.sessionStore.load(selectedSession.id);
|
|
@@ -17586,17 +17495,6 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
17586
17495
|
}
|
|
17587
17496
|
);
|
|
17588
17497
|
}
|
|
17589
|
-
var BANNER = `
|
|
17590
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557
|
|
17591
|
-
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551
|
|
17592
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551
|
|
17593
|
-
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551
|
|
17594
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551
|
|
17595
|
-
\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
17596
|
-
`;
|
|
17597
|
-
console.log("\x1B[36m\x1B[1m%s\x1B[0m", BANNER);
|
|
17598
|
-
console.log(`\x1B[2m v${package_default.version} - AI-Powered CLI\x1B[0m`);
|
|
17599
|
-
console.log(" /help for more information\n");
|
|
17600
17498
|
var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "development";
|
|
17601
17499
|
if (isDevMode) {
|
|
17602
17500
|
logger.debug("\u{1F527} Running in development mode (using TypeScript source)\n");
|