@bike4mind/cli 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ConfigStore-Bu_plzvP.mjs → ConfigStore-Bj1IOvWn.mjs} +20 -2
- package/dist/commands/doctorCommand.mjs +1 -1
- package/dist/commands/headlessCommand.mjs +2 -2
- package/dist/commands/mcpCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/index.mjs +94 -31
- package/dist/store-44C_Fvdb.mjs +3 -0
- package/dist/{store-FkY4K-0M.mjs → store-B0ImnWR4.mjs} +11 -2
- package/dist/{tools-DY-JzNoY.mjs → tools-DDoiKdgk.mjs} +169 -13
- package/dist/{updateChecker-Dn-Ri8zw.mjs → updateChecker-BVKr0OXs.mjs} +1 -1
- package/package.json +6 -6
- package/dist/store-D2zh6DFz.mjs +0 -3
|
@@ -862,9 +862,27 @@ const GenericCreditDeductTransaction = BaseCreditTransaction.extend({
|
|
|
862
862
|
*/
|
|
863
863
|
userId: z.string().optional(),
|
|
864
864
|
/**
|
|
865
|
-
*
|
|
865
|
+
* Reason/source for the transaction. Use GenericDeductReasons for new callers.
|
|
866
866
|
*/
|
|
867
|
-
reason: z.
|
|
867
|
+
reason: z.enum([
|
|
868
|
+
"dispute_clawback",
|
|
869
|
+
"refund_clawback",
|
|
870
|
+
"payment_failed_clawback",
|
|
871
|
+
"notebook_curation",
|
|
872
|
+
"manual",
|
|
873
|
+
"admin_adjustment",
|
|
874
|
+
"refund_adjustment"
|
|
875
|
+
]).optional(),
|
|
876
|
+
/**
|
|
877
|
+
* Stripe dispute ID — set for dispute clawback transactions.
|
|
878
|
+
* Used for idempotency (unique sparse index prevents duplicate clawbacks).
|
|
879
|
+
*/
|
|
880
|
+
stripeDisputeId: z.string().optional(),
|
|
881
|
+
/**
|
|
882
|
+
* Stripe refund ID — set for refund clawback transactions.
|
|
883
|
+
* Used for idempotency (unique sparse index prevents duplicate clawbacks).
|
|
884
|
+
*/
|
|
885
|
+
stripeRefundId: z.string().optional()
|
|
868
886
|
});
|
|
869
887
|
const TextGenerationUsageTransaction = BaseCreditTransaction.extend({
|
|
870
888
|
type: z.literal("text_generation_usage"),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as version, n as compareSemver, r as fetchLatestVersion } from "../updateChecker-
|
|
2
|
+
import { a as version, n as compareSemver, r as fetchLatestVersion } from "../updateChecker-BVKr0OXs.mjs";
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
4
|
import { constants, existsSync, promises } from "fs";
|
|
5
5
|
import { homedir } from "os";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as logger, t as ConfigStore } from "../ConfigStore-
|
|
2
|
+
import { C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as PermissionManager, I as generateCliTools, M as loadContextFiles, N as getApiUrl, O as McpManager, Q as CheckpointStore, S as ApiClient, T as FallbackLlmBackend, W as setWebSocketToolExecutor, X as ReActAgent, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createAgentDelegateTool, b as createSkillTool, d as createFindDefinitionTool, et as SessionStore, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, m as createCoordinateTaskTool, p as createWriteTodosTool, q as buildSystemPrompt, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, y as SubagentOrchestrator } from "../tools-DDoiKdgk.mjs";
|
|
3
|
+
import { n as logger, t as ConfigStore } from "../ConfigStore-Bj1IOvWn.mjs";
|
|
4
4
|
import { t as DEFAULT_SANDBOX_CONFIG } from "../types-DBEjF9YS.mjs";
|
|
5
5
|
import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-C1B4t20N.mjs";
|
|
6
6
|
import { t as SandboxOrchestrator } from "../SandboxOrchestrator-BEW3rqYi.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as version, i as forceCheckForUpdate } from "../updateChecker-
|
|
2
|
+
import { a as version, i as forceCheckForUpdate } from "../updateChecker-BVKr0OXs.mjs";
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
4
|
//#region src/commands/updateCommand.ts
|
|
5
5
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-
|
|
3
|
-
import { $ as
|
|
4
|
-
import { Mt as validateNotebookPath$1, g as ChatModels, jt as validateJupyterKernelName, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-
|
|
5
|
-
import { a as version, t as checkForUpdate } from "./updateChecker-
|
|
2
|
+
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-B0ImnWR4.mjs";
|
|
3
|
+
import { $ as CommandHistoryStore, A as formatStep, B as DEFAULT_RETRY_CONFIG, C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as PermissionManager, G as OllamaBackend, H as clearFeatureModuleTools, I as generateCliTools, J as buildSkillsPromptSection, K as getPlanModeFilePath, L as ALWAYS_DENIED_FOR_AGENTS, M as loadContextFiles, N as getApiUrl, O as McpManager, P as getEnvironmentName, Q as CheckpointStore, R as DEFAULT_AGENT_MODEL, S as ApiClient, T as FallbackLlmBackend, U as registerFeatureModuleTools, V as DEFAULT_THOROUGHNESS, W as setWebSocketToolExecutor, X as ReActAgent, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createAgentDelegateTool, a as createBlockerTools, at as mergeCommands, b as createSkillTool, c as createDecisionStore, ct as warmFileCache, d as createFindDefinitionTool, et as SessionStore, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, i as createBlockerStore, it as searchCommands, j as extractCompactInstructions, k as substituteArguments, l as formatDecisionsOutput, m as createCoordinateTaskTool, n as createReviewGateTool, nt as hasFileReferences, o as formatBlockersOutput, ot as formatFileSize, p as createWriteTodosTool, q as buildSystemPrompt, r as formatReviewGatesOutput, rt as processFileReferences, s as createDecisionLogTool, st as searchFiles, t as createReviewGateStore, tt as OAuthClient, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, x as parseAgentConfig, y as SubagentOrchestrator, z as DEFAULT_MAX_ITERATIONS } from "./tools-DDoiKdgk.mjs";
|
|
4
|
+
import { Mt as validateNotebookPath$1, g as ChatModels, jt as validateJupyterKernelName, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-Bj1IOvWn.mjs";
|
|
5
|
+
import { a as version, t as checkForUpdate } from "./updateChecker-BVKr0OXs.mjs";
|
|
6
6
|
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
7
|
-
import { Box, Static, Text, render, useApp, useInput } from "ink";
|
|
7
|
+
import { Box, Static, Text, render, useApp, useInput, usePaste } from "ink";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
9
|
import { randomBytes, randomUUID } from "crypto";
|
|
10
10
|
import { existsSync, promises, readFileSync, statSync } from "fs";
|
|
@@ -25,16 +25,19 @@ import { get_encoding } from "tiktoken";
|
|
|
25
25
|
import WsWebSocket from "ws";
|
|
26
26
|
//#region src/components/StatusBar.tsx
|
|
27
27
|
const StatusBar = React.memo(function StatusBar({ sessionName, model, tokenUsage, creditsUsage }) {
|
|
28
|
-
const
|
|
28
|
+
const interactionMode = useCliStore((state) => state.interactionMode);
|
|
29
29
|
return /* @__PURE__ */ React.createElement(Box, {
|
|
30
30
|
flexDirection: "row",
|
|
31
31
|
justifyContent: "space-between",
|
|
32
32
|
width: "100%",
|
|
33
33
|
paddingX: 1
|
|
34
|
-
}, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, sessionName), /* @__PURE__ */ React.createElement(Box, { gap: 2 },
|
|
34
|
+
}, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, sessionName), /* @__PURE__ */ React.createElement(Box, { gap: 2 }, interactionMode === "auto-accept" && /* @__PURE__ */ React.createElement(Text, {
|
|
35
35
|
color: "green",
|
|
36
36
|
bold: true
|
|
37
|
-
}, "AUTO ACCEPT: Edits"),
|
|
37
|
+
}, "AUTO ACCEPT: Edits"), interactionMode === "plan" && /* @__PURE__ */ React.createElement(Text, {
|
|
38
|
+
color: "yellow",
|
|
39
|
+
bold: true
|
|
40
|
+
}, "PLAN MODE"), tokenUsage > 0 && /* @__PURE__ */ React.createElement(Text, { dimColor: true }, tokenUsage.toLocaleString(), " tokens"), creditsUsage !== void 0 && creditsUsage > 0 && /* @__PURE__ */ React.createElement(Text, { dimColor: true }, creditsUsage.toLocaleString(), " ", creditsUsage === 1 ? "credit" : "credits"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, model)));
|
|
38
41
|
});
|
|
39
42
|
/**
|
|
40
43
|
* Maximum paste size in characters (~500KB) to prevent memory issues
|
|
@@ -74,6 +77,20 @@ function CustomTextInput({ value, onChange, onSubmit, onPaste, pasteIndicator, p
|
|
|
74
77
|
while (pos < text.length && /\s/.test(text[pos])) pos++;
|
|
75
78
|
return pos;
|
|
76
79
|
};
|
|
80
|
+
usePaste((text) => {
|
|
81
|
+
const normalized = (text.length > 5e5 ? text.slice(0, MAX_PASTE_SIZE) : text).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
82
|
+
if (normalized.split("\n").length >= 5 && onPaste) {
|
|
83
|
+
onPaste(normalized);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (pasteIndicator) {
|
|
87
|
+
emitChange(normalized);
|
|
88
|
+
setCursorOffset(normalized.length);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
emitChange(value.slice(0, cursorOffset) + normalized + value.slice(cursorOffset));
|
|
92
|
+
setCursorOffset(cursorOffset + normalized.length);
|
|
93
|
+
}, { isActive: !disabled });
|
|
77
94
|
useInput((input, key) => {
|
|
78
95
|
if (key.return && !key.meta && !key.shift) {
|
|
79
96
|
if (value.length > 0 && value[cursorOffset - 1] === "\\") {
|
|
@@ -98,7 +115,7 @@ function CustomTextInput({ value, onChange, onSubmit, onPaste, pasteIndicator, p
|
|
|
98
115
|
setCursorOffset(findNextWordBoundary(value, cursorOffset));
|
|
99
116
|
return;
|
|
100
117
|
}
|
|
101
|
-
if (key.backspace
|
|
118
|
+
if (key.backspace) {
|
|
102
119
|
const beforeCursor = value.slice(0, cursorOffset);
|
|
103
120
|
const afterCursor = value.slice(cursorOffset);
|
|
104
121
|
const newPos = findPreviousWordBoundary(beforeCursor, beforeCursor.length);
|
|
@@ -106,6 +123,13 @@ function CustomTextInput({ value, onChange, onSubmit, onPaste, pasteIndicator, p
|
|
|
106
123
|
setCursorOffset(newPos);
|
|
107
124
|
return;
|
|
108
125
|
}
|
|
126
|
+
if (key.delete) {
|
|
127
|
+
const beforeCursor = value.slice(0, cursorOffset);
|
|
128
|
+
const afterCursor = value.slice(cursorOffset);
|
|
129
|
+
const newPos = findNextWordBoundary(afterCursor, 0);
|
|
130
|
+
emitChange(beforeCursor + afterCursor.slice(newPos));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
109
133
|
} else {
|
|
110
134
|
if (key.leftArrow) {
|
|
111
135
|
setCursorOffset(0);
|
|
@@ -115,11 +139,15 @@ function CustomTextInput({ value, onChange, onSubmit, onPaste, pasteIndicator, p
|
|
|
115
139
|
setCursorOffset(value.length);
|
|
116
140
|
return;
|
|
117
141
|
}
|
|
118
|
-
if (key.backspace
|
|
142
|
+
if (key.backspace) {
|
|
119
143
|
emitChange(value.slice(cursorOffset));
|
|
120
144
|
setCursorOffset(0);
|
|
121
145
|
return;
|
|
122
146
|
}
|
|
147
|
+
if (key.delete) {
|
|
148
|
+
emitChange(value.slice(0, cursorOffset));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
123
151
|
}
|
|
124
152
|
if (key.home) {
|
|
125
153
|
setCursorOffset(0);
|
|
@@ -188,7 +216,7 @@ function CustomTextInput({ value, onChange, onSubmit, onPaste, pasteIndicator, p
|
|
|
188
216
|
}
|
|
189
217
|
return;
|
|
190
218
|
}
|
|
191
|
-
if (key.backspace
|
|
219
|
+
if (key.backspace) {
|
|
192
220
|
if (pasteIndicator) {
|
|
193
221
|
emitChange("");
|
|
194
222
|
setCursorOffset(0);
|
|
@@ -200,6 +228,15 @@ function CustomTextInput({ value, onChange, onSubmit, onPaste, pasteIndicator, p
|
|
|
200
228
|
}
|
|
201
229
|
return;
|
|
202
230
|
}
|
|
231
|
+
if (key.delete) {
|
|
232
|
+
if (pasteIndicator) {
|
|
233
|
+
emitChange("");
|
|
234
|
+
setCursorOffset(0);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (cursorOffset < value.length) emitChange(value.slice(0, cursorOffset) + value.slice(cursorOffset + 1));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
203
240
|
if (key.leftArrow && !key.meta && !key.ctrl) {
|
|
204
241
|
setCursorOffset(Math.max(0, cursorOffset - 1));
|
|
205
242
|
return;
|
|
@@ -721,10 +758,9 @@ function InputPrompt({ onSubmit, onBashCommand, onImageDetected, disabled = fals
|
|
|
721
758
|
setFileAutocomplete(null);
|
|
722
759
|
};
|
|
723
760
|
const handlePaste = (content) => {
|
|
724
|
-
const
|
|
725
|
-
const lineCount = truncated.split("\n").length;
|
|
761
|
+
const lineCount = content.split("\n").length;
|
|
726
762
|
const prefix = value.trim();
|
|
727
|
-
setPastedContent(prefix ? `${prefix}\n${
|
|
763
|
+
setPastedContent(prefix ? `${prefix}\n${content}` : content, lineCount);
|
|
728
764
|
};
|
|
729
765
|
const handleChange = async (newValue) => {
|
|
730
766
|
if (pastedContent) clearPaste();
|
|
@@ -1403,7 +1439,7 @@ function ReviewGatePrompt({ description, options, recommendation, onResponse })
|
|
|
1403
1439
|
onChange: setNote,
|
|
1404
1440
|
onSubmit: handleConfirm,
|
|
1405
1441
|
placeholder: "Type a note and press Enter…"
|
|
1406
|
-
}))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, noteMode ? "Type note + Enter to submit, ↑↓ to switch action" : "Press 1-4, y/n, or ↑↓ + Enter")));
|
|
1442
|
+
}))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, noteMode ? note.trim().length === 0 ? "Note required — type a note + Enter to submit, ↑↓ to switch action" : "Type note + Enter to submit, ↑↓ to switch action" : "Press 1-4, y/n, or ↑↓ + Enter")));
|
|
1407
1443
|
}
|
|
1408
1444
|
//#endregion
|
|
1409
1445
|
//#region src/components/ConfigEditor.tsx
|
|
@@ -1856,21 +1892,22 @@ function McpViewer({ config, mcpManager, onClose }) {
|
|
|
1856
1892
|
}
|
|
1857
1893
|
//#endregion
|
|
1858
1894
|
//#region src/components/MarkdownRenderer.tsx
|
|
1859
|
-
function MarkdownRenderer({ content }) {
|
|
1895
|
+
function MarkdownRenderer({ content, columns: columnsProp }) {
|
|
1896
|
+
const columns = columnsProp ?? process.stdout.columns ?? 80;
|
|
1860
1897
|
const tokens = marked.lexer(content);
|
|
1861
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, tokens.map((token, idx) => renderToken(token, idx)));
|
|
1898
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, tokens.map((token, idx) => renderToken(token, idx, columns)));
|
|
1862
1899
|
}
|
|
1863
|
-
function renderToken(token, idx) {
|
|
1900
|
+
function renderToken(token, idx, columns) {
|
|
1864
1901
|
switch (token.type) {
|
|
1865
1902
|
case "heading": return renderHeading(token, idx);
|
|
1866
1903
|
case "code": return renderCodeBlock(token, idx);
|
|
1867
1904
|
case "paragraph": return renderParagraph(token, idx);
|
|
1868
1905
|
case "list": return renderList(token, idx);
|
|
1869
|
-
case "blockquote": return renderBlockquote(token, idx);
|
|
1906
|
+
case "blockquote": return renderBlockquote(token, idx, columns);
|
|
1870
1907
|
case "hr": return /* @__PURE__ */ React.createElement(Text, {
|
|
1871
1908
|
key: idx,
|
|
1872
1909
|
dimColor: true
|
|
1873
|
-
}, "─".repeat(
|
|
1910
|
+
}, "─".repeat(Math.max(1, columns - 4)));
|
|
1874
1911
|
case "space": return null;
|
|
1875
1912
|
default:
|
|
1876
1913
|
if ("text" in token) return /* @__PURE__ */ React.createElement(Text, { key: idx }, token.text);
|
|
@@ -1929,14 +1966,14 @@ function renderListItem(item, idx, ordered, number) {
|
|
|
1929
1966
|
paddingLeft: 2
|
|
1930
1967
|
}, /* @__PURE__ */ React.createElement(Text, null, bullet, " ", parseInlineText(item.text)));
|
|
1931
1968
|
}
|
|
1932
|
-
function renderBlockquote(token, idx) {
|
|
1969
|
+
function renderBlockquote(token, idx, columns) {
|
|
1933
1970
|
return /* @__PURE__ */ React.createElement(Box, {
|
|
1934
1971
|
key: idx,
|
|
1935
1972
|
paddingLeft: 2,
|
|
1936
1973
|
borderStyle: "single",
|
|
1937
1974
|
borderLeft: true,
|
|
1938
1975
|
borderColor: "gray"
|
|
1939
|
-
}, token.tokens.map((t, i) => renderToken(t, i)));
|
|
1976
|
+
}, token.tokens.map((t, i) => renderToken(t, i, columns)));
|
|
1940
1977
|
}
|
|
1941
1978
|
/**
|
|
1942
1979
|
* Parse inline markdown formatting (bold, italic, code, links)
|
|
@@ -2048,9 +2085,9 @@ function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPe
|
|
|
2048
2085
|
setPendingBackgroundTrigger,
|
|
2049
2086
|
onBackgroundCompletion
|
|
2050
2087
|
]);
|
|
2051
|
-
const
|
|
2088
|
+
const cycleInteractionMode = useCliStore((state) => state.cycleInteractionMode);
|
|
2052
2089
|
useInput((_input, key) => {
|
|
2053
|
-
if (key.tab && key.shift)
|
|
2090
|
+
if (key.tab && key.shift) cycleInteractionMode();
|
|
2054
2091
|
});
|
|
2055
2092
|
const [isBashMode, setIsBashMode] = useState(false);
|
|
2056
2093
|
const handleSubmit = React.useCallback(async (input) => {
|
|
@@ -5906,15 +5943,18 @@ function CliApp() {
|
|
|
5906
5943
|
if (contextResult.projectContext) startupLog.push(`📄 Project context: ${contextResult.projectContext.filename}`);
|
|
5907
5944
|
for (const error of contextResult.errors) startupLog.push(`⚠️ Context file error: ${error}`);
|
|
5908
5945
|
const featureModulePrompts = featureRegistry.getSystemPromptSections();
|
|
5909
|
-
const
|
|
5946
|
+
const promptVariant = config.preferences.promptVariant ?? "current";
|
|
5947
|
+
const buildPromptForMode = (mode) => buildSystemPrompt(promptVariant, {
|
|
5910
5948
|
contextContent: contextResult.mergedContent,
|
|
5911
5949
|
agentStore,
|
|
5912
5950
|
customCommands: state.customCommandStore.getAllCommands(),
|
|
5913
5951
|
enableSkillTool,
|
|
5914
5952
|
enableDynamicAgentCreation: config.preferences.enableDynamicAgentCreation === true,
|
|
5915
5953
|
additionalDirectories,
|
|
5916
|
-
featureModulePrompts: featureModulePrompts || void 0
|
|
5954
|
+
featureModulePrompts: featureModulePrompts || void 0,
|
|
5955
|
+
planModeFilePath: mode === "plan" ? getPlanModeFilePath(newSession.id) : void 0
|
|
5917
5956
|
});
|
|
5957
|
+
const cliSystemPrompt = buildPromptForMode(useCliStore.getState().interactionMode);
|
|
5918
5958
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
5919
5959
|
const agent = new ReActAgent({
|
|
5920
5960
|
userId: config.userId,
|
|
@@ -5928,6 +5968,14 @@ function CliApp() {
|
|
|
5928
5968
|
systemPrompt: cliSystemPrompt
|
|
5929
5969
|
});
|
|
5930
5970
|
agentContext.currentAgent = agent;
|
|
5971
|
+
const agentInternalContext = agent.context;
|
|
5972
|
+
let lastInteractionMode = useCliStore.getState().interactionMode;
|
|
5973
|
+
useCliStore.subscribe((s) => {
|
|
5974
|
+
if (s.interactionMode === lastInteractionMode) return;
|
|
5975
|
+
lastInteractionMode = s.interactionMode;
|
|
5976
|
+
if (agentContext.currentAgent !== agent) return;
|
|
5977
|
+
agentInternalContext.systemPrompt = buildPromptForMode(s.interactionMode);
|
|
5978
|
+
});
|
|
5931
5979
|
agent.observationQueue = agentContext.observationQueue;
|
|
5932
5980
|
const stepHandler = (step) => {
|
|
5933
5981
|
const { pendingMessages, updatePendingMessage } = useCliStore.getState();
|
|
@@ -7250,7 +7298,6 @@ Multi-line Input:
|
|
|
7250
7298
|
logger.debug("=== New Session Started via /clear ===");
|
|
7251
7299
|
decisionStoreRef.current.decisions = [];
|
|
7252
7300
|
blockerStoreRef.current.blockers = [];
|
|
7253
|
-
reviewGateStoreRef.current.reviewGates = [];
|
|
7254
7301
|
if (state.checkpointStore) state.checkpointStore.setSessionId(newSession.id);
|
|
7255
7302
|
setState((prev) => ({
|
|
7256
7303
|
...prev,
|
|
@@ -7258,6 +7305,17 @@ Multi-line Input:
|
|
|
7258
7305
|
}));
|
|
7259
7306
|
setStoreSession(newSession);
|
|
7260
7307
|
useCliStore.getState().clearPendingMessages();
|
|
7308
|
+
const staleGate = useCliStore.getState().reviewGatePrompt;
|
|
7309
|
+
if (staleGate) {
|
|
7310
|
+
dequeueReviewGatePrompt();
|
|
7311
|
+
staleGate.resolve({
|
|
7312
|
+
decision: "rejected",
|
|
7313
|
+
note: "Session cleared."
|
|
7314
|
+
});
|
|
7315
|
+
}
|
|
7316
|
+
queueMicrotask(() => {
|
|
7317
|
+
reviewGateStoreRef.current.reviewGates = [];
|
|
7318
|
+
});
|
|
7261
7319
|
usageCache = null;
|
|
7262
7320
|
console.log("New session started.");
|
|
7263
7321
|
console.log(`\n📝 Session: ${newSession.name} | 🤖 Model: ${newSession.model} | 📊 Tokens: 0\n`);
|
|
@@ -8071,6 +8129,7 @@ Multi-line Input:
|
|
|
8071
8129
|
const newFeatureTools = newFeatureRegistry.getAllTools();
|
|
8072
8130
|
agentContext.tools = [...baseTools, ...newFeatureTools];
|
|
8073
8131
|
const newFeaturePrompts = newFeatureRegistry.getSystemPromptSections();
|
|
8132
|
+
const planFilePathForRebuild = useCliStore.getState().interactionMode === "plan" && state.session ? getPlanModeFilePath(state.session.id) : void 0;
|
|
8074
8133
|
agentContext.systemPrompt = buildSystemPrompt(updatedConfig.preferences.promptVariant ?? "current", {
|
|
8075
8134
|
contextContent: state.contextContent,
|
|
8076
8135
|
agentStore: state.agentStore || void 0,
|
|
@@ -8078,7 +8137,8 @@ Multi-line Input:
|
|
|
8078
8137
|
enableSkillTool: updatedConfig.preferences.enableSkillTool !== false,
|
|
8079
8138
|
enableDynamicAgentCreation: updatedConfig.preferences.enableDynamicAgentCreation === true,
|
|
8080
8139
|
additionalDirectories: state.additionalDirectories,
|
|
8081
|
-
featureModulePrompts: newFeaturePrompts || void 0
|
|
8140
|
+
featureModulePrompts: newFeaturePrompts || void 0,
|
|
8141
|
+
planModeFilePath: planFilePathForRebuild
|
|
8082
8142
|
});
|
|
8083
8143
|
const moduleNames = newFeatureRegistry.getModuleNames();
|
|
8084
8144
|
if (moduleNames.length > 0) console.error(`\n\x1b[36m🏰 Feature modules hot-reloaded: ${moduleNames.join(", ")}\x1b[0m`);
|
|
@@ -8217,15 +8277,15 @@ Multi-line Input:
|
|
|
8217
8277
|
onUserQuestionResponse: (response, promptId) => {
|
|
8218
8278
|
const currentPrompt = useCliStore.getState().userQuestionPrompt;
|
|
8219
8279
|
if (currentPrompt?.id !== promptId) return;
|
|
8220
|
-
currentPrompt.resolve(response);
|
|
8221
8280
|
dequeueUserQuestionPrompt();
|
|
8281
|
+
currentPrompt.resolve(response);
|
|
8222
8282
|
emitNextAwaitingStatus();
|
|
8223
8283
|
},
|
|
8224
8284
|
onReviewGateResponse: (response, promptId) => {
|
|
8225
8285
|
const currentPrompt = useCliStore.getState().reviewGatePrompt;
|
|
8226
8286
|
if (currentPrompt?.id !== promptId) return;
|
|
8227
|
-
currentPrompt.resolve(response);
|
|
8228
8287
|
dequeueReviewGatePrompt();
|
|
8288
|
+
currentPrompt.resolve(response);
|
|
8229
8289
|
emitNextAwaitingStatus();
|
|
8230
8290
|
}
|
|
8231
8291
|
});
|
|
@@ -8236,6 +8296,9 @@ try {
|
|
|
8236
8296
|
} catch {}
|
|
8237
8297
|
if (import.meta.url.includes("/src/") || process.env.NODE_ENV === "development") logger.debug("🔧 Running in development mode (using TypeScript source)\n");
|
|
8238
8298
|
warmFileCache();
|
|
8239
|
-
render(/* @__PURE__ */ React.createElement(CliApp, null), {
|
|
8299
|
+
render(/* @__PURE__ */ React.createElement(CliApp, null), {
|
|
8300
|
+
exitOnCtrlC: false,
|
|
8301
|
+
alternateScreen: true
|
|
8302
|
+
});
|
|
8240
8303
|
//#endregion
|
|
8241
8304
|
export {};
|
|
@@ -3,6 +3,14 @@ import { create } from "zustand";
|
|
|
3
3
|
//#region src/store/index.ts
|
|
4
4
|
/** Active job statuses (jobs still in progress) */
|
|
5
5
|
const ACTIVE_STATUSES = new Set(["running", "queued"]);
|
|
6
|
+
const INTERACTION_MODE_CYCLE = [
|
|
7
|
+
"normal",
|
|
8
|
+
"auto-accept",
|
|
9
|
+
"plan"
|
|
10
|
+
];
|
|
11
|
+
function nextInteractionMode(current) {
|
|
12
|
+
return INTERACTION_MODE_CYCLE[(INTERACTION_MODE_CYCLE.indexOf(current) + 1) % INTERACTION_MODE_CYCLE.length];
|
|
13
|
+
}
|
|
6
14
|
/** Check if a job status is active (running or queued) */
|
|
7
15
|
function isActiveStatus(status) {
|
|
8
16
|
return ACTIVE_STATUSES.has(status);
|
|
@@ -122,8 +130,9 @@ const useCliStore = create((set) => ({
|
|
|
122
130
|
setShowConfigEditor: (show) => set({ showConfigEditor: show }),
|
|
123
131
|
showMcpViewer: false,
|
|
124
132
|
setShowMcpViewer: (show) => set({ showMcpViewer: show }),
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
interactionMode: "normal",
|
|
134
|
+
cycleInteractionMode: () => set((state) => ({ interactionMode: nextInteractionMode(state.interactionMode) })),
|
|
135
|
+
setInteractionMode: (mode) => set({ interactionMode: mode }),
|
|
127
136
|
exitRequested: false,
|
|
128
137
|
setExitRequested: (requested) => set({ exitRequested: requested }),
|
|
129
138
|
backgroundAgents: [],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as RechartsChartTypeList, A as ImageGenerationUsageTransaction, At as secureParameters, B as NotFoundError, C as FileEvents, Ct as getMcpProviderMetadata, D as GenericCreditAddTransaction, Dt as obfuscateApiKey, E as GenerateImageToolCallSchema, Et as isGPTImageModel, F as KnowledgeType, G as ProfileEvents, H as OpenAIImageGenerationInput, I as LLMEvents, J as PurchaseTransaction, K as ProjectEvents, L as MiscEvents, M as InboxEvents, N as InviteEvents, Nt as CollectionType, O as GenericCreditDeductTransaction, Ot as resolveNavigationIntents, P as InviteType, Q as ReceivedCreditTransaction, R as ModalEvents, S as FeedbackEvents, St as getDataLakeTags, T as GEMINI_IMAGE_MODELS, Tt as isGPTImage2Model, U as Permission, V as OpenAIEmbeddingModel, W as PermissionDeniedError, X as REASONING_SUPPORTED_MODELS, Y as QuestMasterParamsSchema, Z as RealtimeVoiceUsageTransaction, _ as CompletionApiUsageTransaction, _t as VideoModels, a as ApiKeyEvents, at as SessionEvents, b as FIXED_TEMPERATURE_MODELS, bt as b4mLLMTools, c as AppFileEvents, ct as SupportedFabFileMimeTypes, d as BFL_IMAGE_MODELS, dt as TextGenerationUsageTransaction, et as RegInviteEvents, f as BFL_SAFETY_TOLERANCE, ft as ToolUsageTransaction, g as ChatModels, gt as VideoGenerationUsageTransaction, h as ChatCompletionCreateInputSchema, ht as VIDEO_SIZE_CONSTRAINTS, i as AiEvents, it as ResearchTaskType, j as ImageModels, k as ImageEditUsageTransaction, kt as sanitizeTelemetryError, l as ArtifactTypeSchema, lt as TagType, mt as UiNavigationEvents, n as logger, nt as ResearchTaskExecutionType, o as ApiKeyScope, ot as SpeechToTextModels, p as BedrockEmbeddingModel, pt as TransferCreditTransaction, q as PromptMetaZodSchema, r as ALERT_THRESHOLDS, rt as ResearchTaskPeriodicFrequencyType, s as ApiKeyType, st as SubscriptionCreditTransaction, t as ConfigStore, tt as ResearchModeParamsSchema, u as AuthEvents, ut as TaskScheduleHandler, v as DashboardParamsSchema, vt as VoyageAIEmbeddingModel, w as FriendshipEvents, wt as getViewById, x as FavoriteDocumentType, xt as getAccessibleDataLakes, y as ElabsEvents, yt as XAI_IMAGE_MODELS, z as ModelBackend } from "./ConfigStore-
|
|
2
|
+
import { $ as RechartsChartTypeList, A as ImageGenerationUsageTransaction, At as secureParameters, B as NotFoundError, C as FileEvents, Ct as getMcpProviderMetadata, D as GenericCreditAddTransaction, Dt as obfuscateApiKey, E as GenerateImageToolCallSchema, Et as isGPTImageModel, F as KnowledgeType, G as ProfileEvents, H as OpenAIImageGenerationInput, I as LLMEvents, J as PurchaseTransaction, K as ProjectEvents, L as MiscEvents, M as InboxEvents, N as InviteEvents, Nt as CollectionType, O as GenericCreditDeductTransaction, Ot as resolveNavigationIntents, P as InviteType, Q as ReceivedCreditTransaction, R as ModalEvents, S as FeedbackEvents, St as getDataLakeTags, T as GEMINI_IMAGE_MODELS, Tt as isGPTImage2Model, U as Permission, V as OpenAIEmbeddingModel, W as PermissionDeniedError, X as REASONING_SUPPORTED_MODELS, Y as QuestMasterParamsSchema, Z as RealtimeVoiceUsageTransaction, _ as CompletionApiUsageTransaction, _t as VideoModels, a as ApiKeyEvents, at as SessionEvents, b as FIXED_TEMPERATURE_MODELS, bt as b4mLLMTools, c as AppFileEvents, ct as SupportedFabFileMimeTypes, d as BFL_IMAGE_MODELS, dt as TextGenerationUsageTransaction, et as RegInviteEvents, f as BFL_SAFETY_TOLERANCE, ft as ToolUsageTransaction, g as ChatModels, gt as VideoGenerationUsageTransaction, h as ChatCompletionCreateInputSchema, ht as VIDEO_SIZE_CONSTRAINTS, i as AiEvents, it as ResearchTaskType, j as ImageModels, k as ImageEditUsageTransaction, kt as sanitizeTelemetryError, l as ArtifactTypeSchema, lt as TagType, mt as UiNavigationEvents, n as logger, nt as ResearchTaskExecutionType, o as ApiKeyScope, ot as SpeechToTextModels, p as BedrockEmbeddingModel, pt as TransferCreditTransaction, q as PromptMetaZodSchema, r as ALERT_THRESHOLDS, rt as ResearchTaskPeriodicFrequencyType, s as ApiKeyType, st as SubscriptionCreditTransaction, t as ConfigStore, tt as ResearchModeParamsSchema, u as AuthEvents, ut as TaskScheduleHandler, v as DashboardParamsSchema, vt as VoyageAIEmbeddingModel, w as FriendshipEvents, wt as getViewById, x as FavoriteDocumentType, xt as getAccessibleDataLakes, y as ElabsEvents, yt as XAI_IMAGE_MODELS, z as ModelBackend } from "./ConfigStore-Bj1IOvWn.mjs";
|
|
3
3
|
import { n as isPathAllowed, t as assertPathAllowed } from "./pathValidation-CIytuhr3-Dt5dntLx.mjs";
|
|
4
4
|
import { execFile, execFileSync, spawn } from "child_process";
|
|
5
5
|
import { createHash, randomBytes } from "crypto";
|
|
@@ -2268,6 +2268,15 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
|
|
|
2268
2268
|
return this.toolCallCount;
|
|
2269
2269
|
}
|
|
2270
2270
|
/**
|
|
2271
|
+
* Get current iteration count.
|
|
2272
|
+
* Cheap accessor for hot paths (e.g., per-step event listeners) — prefer this
|
|
2273
|
+
* over `toCheckpoint().iteration`, which deep-clones messages, steps, and
|
|
2274
|
+
* confidence log on every call.
|
|
2275
|
+
*/
|
|
2276
|
+
getIteration() {
|
|
2277
|
+
return this.iterations;
|
|
2278
|
+
}
|
|
2279
|
+
/**
|
|
2271
2280
|
* Serialize the agent's current execution state for persistence.
|
|
2272
2281
|
*
|
|
2273
2282
|
* Call this after each iteration to create a durable checkpoint that can
|
|
@@ -3023,6 +3032,84 @@ const TOOL_WRITE_TODOS = "write_todos";
|
|
|
3023
3032
|
const TOOL_CREATE_DYNAMIC_AGENT = "create_dynamic_agent";
|
|
3024
3033
|
const EXPLORE_SUBAGENT_TYPE = "explore";
|
|
3025
3034
|
/**
|
|
3035
|
+
* Plan-mode section: tells the model that write tools are blocked and where to put the plan.
|
|
3036
|
+
* Appended dynamically when the user cycles into plan mode via Shift+Tab.
|
|
3037
|
+
*
|
|
3038
|
+
* The phased workflow (understand → clarify → design → present) mirrors Claude Code's
|
|
3039
|
+
* plan-mode prompting: research before designing, ask the user before assuming, and only
|
|
3040
|
+
* write the plan after ambiguities are resolved.
|
|
3041
|
+
*/
|
|
3042
|
+
function buildPlanModePromptSection(planModeFilePath) {
|
|
3043
|
+
return `
|
|
3044
|
+
|
|
3045
|
+
## PLAN MODE ACTIVE
|
|
3046
|
+
|
|
3047
|
+
The user has cycled into plan mode (Shift+Tab). Plan mode restricts WRITING, not READING. You still have a complete read toolkit — use it.
|
|
3048
|
+
|
|
3049
|
+
**Tools available in plan mode (use these aggressively):**
|
|
3050
|
+
- \`grep_search\` — find symbols, strings, patterns across files
|
|
3051
|
+
- \`glob_files\` — list files by pattern (use this instead of \`ls\` / \`find\`)
|
|
3052
|
+
- \`file_read\` — read file contents
|
|
3053
|
+
- \`find_definition\` — locate where a symbol is defined
|
|
3054
|
+
- \`get_file_structure\` — AST overview of a file
|
|
3055
|
+
- \`agent_delegate\` — delegate to read-only subagents (e.g. 'explore', 'plan')
|
|
3056
|
+
- \`ask_user_question\` — ask the user clarifying questions
|
|
3057
|
+
- \`current_datetime\`, \`math_evaluate\`, \`web_search\`, \`web_fetch\` — also fine
|
|
3058
|
+
|
|
3059
|
+
**Tools blocked in plan mode:**
|
|
3060
|
+
- \`bash_execute\`, \`edit_local_file\`, \`create_file\`, \`delete_file\` — and any other tool that mutates state.
|
|
3061
|
+
- Exception: \`create_file\` / \`edit_local_file\` targeting paths under \`${planModeFilePath.replace(/\/plan-[^/]+\.md$/, "/")}\` are allowed (that's where you write the plan).
|
|
3062
|
+
|
|
3063
|
+
**Forbidden responses:**
|
|
3064
|
+
- ❌ "I can't explore the directory because plan mode blocks shell commands."
|
|
3065
|
+
- ❌ "I'd need to run bash to check this."
|
|
3066
|
+
- ❌ Any variant of "plan mode prevents me from researching."
|
|
3067
|
+
- ✅ Instead: use \`glob_files\`, \`grep_search\`, \`file_read\`, or delegate to the \`explore\` subagent. Bash is not the only way to investigate code.
|
|
3068
|
+
|
|
3069
|
+
Ground every claim in files you have actually read. Do not write pseudocode in chat as a substitute for reading the real code.
|
|
3070
|
+
|
|
3071
|
+
Follow this phased workflow. Do not skip phases.
|
|
3072
|
+
|
|
3073
|
+
### Phase 1 — Understand
|
|
3074
|
+
- Read the relevant code before forming opinions. Use grep_search / glob_files / file_read directly for narrow lookups.
|
|
3075
|
+
- For broad or uncertain scope, delegate to the 'explore' subagent via agent_delegate so the main context stays focused.
|
|
3076
|
+
- Identify what already exists vs. what needs to be built. Reuse existing functions and patterns rather than proposing new ones.
|
|
3077
|
+
|
|
3078
|
+
### Phase 2 — Clarify (REQUIRED if anything is ambiguous)
|
|
3079
|
+
- If requirements are unclear, if there are multiple reasonable approaches, or if you would otherwise be guessing about user intent, **call the ask_user_question tool BEFORE writing the plan**.
|
|
3080
|
+
- Ask about: trade-offs the user should pick between, scope (which files / how broad), behavior on edge cases, naming, dependencies you would add.
|
|
3081
|
+
- Do NOT ask "is the plan ready?" or "should I proceed?" — those are decided by the user pressing Shift+Tab. Only ask substantive design questions.
|
|
3082
|
+
- If the request is fully unambiguous, skip this phase. Do not invent questions.
|
|
3083
|
+
|
|
3084
|
+
### Phase 3 — Design
|
|
3085
|
+
- For complex tasks, delegate to the 'plan' subagent via agent_delegate to get a structured implementation plan, then critique its output.
|
|
3086
|
+
- For simple tasks, design directly.
|
|
3087
|
+
|
|
3088
|
+
### Phase 4 — Write the plan
|
|
3089
|
+
Write the plan to \`${planModeFilePath}\` (writes to this path are permitted in plan mode). Build it incrementally — append sections as you research, do not wait until the end. Structure it as:
|
|
3090
|
+
|
|
3091
|
+
\`\`\`markdown
|
|
3092
|
+
## Context
|
|
3093
|
+
Why this change is being made — the problem, what prompted it, the intended outcome.
|
|
3094
|
+
|
|
3095
|
+
## Approach
|
|
3096
|
+
The chosen approach in 1-3 sentences. Mention rejected alternatives only if non-obvious.
|
|
3097
|
+
|
|
3098
|
+
## Files to change
|
|
3099
|
+
- path/to/file.ts — what changes and why
|
|
3100
|
+
- path/to/other.ts — what changes and why
|
|
3101
|
+
|
|
3102
|
+
## Reused existing code
|
|
3103
|
+
- function/module path — how it will be reused
|
|
3104
|
+
|
|
3105
|
+
## Verification
|
|
3106
|
+
How to confirm the change works end-to-end (commands, tests, manual steps).
|
|
3107
|
+
\`\`\`
|
|
3108
|
+
|
|
3109
|
+
### Phase 5 — Hand off
|
|
3110
|
+
Tell the user the plan is ready and where it lives (\`${planModeFilePath}\`). Summarize in 1-2 sentences. Do not ask for approval — the user will press Shift+Tab to exit plan mode and authorize execution.`;
|
|
3111
|
+
}
|
|
3112
|
+
/**
|
|
3026
3113
|
* Build the CLI system prompt with optional project context
|
|
3027
3114
|
* @param contextSection - Optional project-specific context to append (legacy string) or config object
|
|
3028
3115
|
* @param config - Configuration object for building context sections (when first param is string)
|
|
@@ -3034,6 +3121,7 @@ function buildCoreSystemPrompt(contextSection, config) {
|
|
|
3034
3121
|
let dynamicAgentSection = "";
|
|
3035
3122
|
let directoriesSection = "";
|
|
3036
3123
|
let featureModulesSection = "";
|
|
3124
|
+
let planModeSection = "";
|
|
3037
3125
|
if (typeof contextSection === "string") {
|
|
3038
3126
|
projectContextSection = contextSection;
|
|
3039
3127
|
if (config) {
|
|
@@ -3041,6 +3129,7 @@ function buildCoreSystemPrompt(contextSection, config) {
|
|
|
3041
3129
|
if (config.agentStore) agentDirectoryContext = config.agentStore.getDirectoryContext();
|
|
3042
3130
|
if (config.enableDynamicAgentCreation) dynamicAgentSection = buildDynamicAgentPromptSection();
|
|
3043
3131
|
if (config.featureModulePrompts) featureModulesSection = config.featureModulePrompts;
|
|
3132
|
+
if (config.planModeFilePath) planModeSection = buildPlanModePromptSection(config.planModeFilePath);
|
|
3044
3133
|
}
|
|
3045
3134
|
} else if (contextSection && typeof contextSection === "object") {
|
|
3046
3135
|
config = contextSection;
|
|
@@ -3050,6 +3139,7 @@ function buildCoreSystemPrompt(contextSection, config) {
|
|
|
3050
3139
|
if (config.enableDynamicAgentCreation) dynamicAgentSection = buildDynamicAgentPromptSection();
|
|
3051
3140
|
if (config.additionalDirectories && config.additionalDirectories.length > 0) directoriesSection = `\n\n## Additional Allowed Directories\n\nIn addition to the working directory (${process.cwd()}), you have read/write access to these directories:\n${config.additionalDirectories.map((d) => `- ${d}`).join("\n")}\n\nTo access files in additional directories, pass the full path to the 'dir_path' parameter of file tools:\n- ${TOOL_GREP_SEARCH}(pattern="...", dir_path="/path/to/additional/dir")\n- ${TOOL_GLOB_FILES}(pattern="**/*.ts", dir_path="/path/to/additional/dir")\n- ${TOOL_FILE_READ}(path="/path/to/additional/dir/file.ts")\n\nWhen the user asks about content in an additional directory, search there first using the dir_path parameter.`;
|
|
3052
3141
|
if (config.featureModulePrompts) featureModulesSection = config.featureModulePrompts;
|
|
3142
|
+
if (config.planModeFilePath) planModeSection = buildPlanModePromptSection(config.planModeFilePath);
|
|
3053
3143
|
}
|
|
3054
3144
|
return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
|
|
3055
3145
|
|
|
@@ -3152,7 +3242,7 @@ You have tools for tracking decisions, blockers, and human review gates during y
|
|
|
3152
3242
|
|
|
3153
3243
|
- request_review_gate: Pause for explicit human approval before crossing a significant decision point — one that affects interpretation, evidence, cost, credentials, platform, or public commitment (e.g., narrowing research scope after synthesis, hard-to-reverse refactors, architectural pivots, dependency swaps). Do NOT use for routine operations or actions already covered by the standard permission system (file edits, bash commands). Treat a rejection as a hard stop — re-plan, do not retry.
|
|
3154
3244
|
|
|
3155
|
-
These tools are lightweight — use them naturally as part of your work, not as a ceremony.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}`;
|
|
3245
|
+
These tools are lightweight — use them naturally as part of your work, not as a ceremony.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}${planModeSection}`;
|
|
3156
3246
|
}
|
|
3157
3247
|
/**
|
|
3158
3248
|
* Build the minimal-variant system prompt. Reuses the project context,
|
|
@@ -3165,16 +3255,18 @@ function buildMinimalSystemPrompt(config = {}) {
|
|
|
3165
3255
|
let skillsSection = "";
|
|
3166
3256
|
let directoriesSection = "";
|
|
3167
3257
|
let featureModulesSection = "";
|
|
3258
|
+
let planModeSection = "";
|
|
3168
3259
|
if (config.contextContent) projectContextSection = `\n\n## Project Context\n\nFollow these project-specific instructions:\n\n${config.contextContent}`;
|
|
3169
3260
|
if (config.enableSkillTool !== false && config.customCommands && config.customCommands.length > 0) skillsSection = buildSkillsPromptSection(config.customCommands);
|
|
3170
3261
|
if (config.additionalDirectories && config.additionalDirectories.length > 0) directoriesSection = `\n\n## Additional Allowed Directories\n\nIn addition to the working directory (${process.cwd()}), you have read/write access to these directories:\n${config.additionalDirectories.map((d) => `- ${d}`).join("\n")}\n\nPass full paths to file tools' \`dir_path\` parameter to access these directories.`;
|
|
3171
3262
|
if (config.featureModulePrompts) featureModulesSection = config.featureModulePrompts;
|
|
3263
|
+
if (config.planModeFilePath) planModeSection = buildPlanModePromptSection(config.planModeFilePath);
|
|
3172
3264
|
return `You are an expert coding assistant. You help users by reading files, executing commands, editing code, and writing new files using the tools available to you.
|
|
3173
3265
|
|
|
3174
3266
|
Guidelines:
|
|
3175
3267
|
- Be concise in your responses.
|
|
3176
3268
|
- Show file paths clearly when working with files.
|
|
3177
|
-
- When the task is done, give the user a direct answer — no recap of steps already visible in the tool history.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}`;
|
|
3269
|
+
- When the task is done, give the user a direct answer — no recap of steps already visible in the tool history.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}${planModeSection}`;
|
|
3178
3270
|
}
|
|
3179
3271
|
/**
|
|
3180
3272
|
* Pick a system prompt by variant. The dispatch point for the
|
|
@@ -3234,6 +3326,41 @@ You have access to the '${TOOL_CREATE_DYNAMIC_AGENT}' tool, which lets you creat
|
|
|
3234
3326
|
thoroughness: "quick"`;
|
|
3235
3327
|
}
|
|
3236
3328
|
//#endregion
|
|
3329
|
+
//#region src/utils/planMode.ts
|
|
3330
|
+
const PLAN_MODE_DIR = ".b4m-cli/plans";
|
|
3331
|
+
const PATH_TOOLS = new Set([
|
|
3332
|
+
"create_file",
|
|
3333
|
+
"edit_local_file",
|
|
3334
|
+
"delete_file"
|
|
3335
|
+
]);
|
|
3336
|
+
/**
|
|
3337
|
+
* Directory plan-mode artifacts are written to (under the working directory).
|
|
3338
|
+
* Writes to paths under this directory are permitted while plan mode is active.
|
|
3339
|
+
*/
|
|
3340
|
+
function getPlanModeFileDir(cwd = process.cwd()) {
|
|
3341
|
+
return path.resolve(cwd, PLAN_MODE_DIR);
|
|
3342
|
+
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Default plan file for the current session. Sessions can override this if needed.
|
|
3345
|
+
*/
|
|
3346
|
+
function getPlanModeFilePath(sessionId, cwd = process.cwd()) {
|
|
3347
|
+
const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3348
|
+
return path.join(getPlanModeFileDir(cwd), `plan-${safeId}.md`);
|
|
3349
|
+
}
|
|
3350
|
+
/**
|
|
3351
|
+
* Whether a write/edit/delete tool call targets a path inside the plan-mode directory.
|
|
3352
|
+
* Used to allow incremental plan-file writes while plan mode blocks other writes.
|
|
3353
|
+
*/
|
|
3354
|
+
function isWriteTargetingPlanFile(toolName, args, cwd = process.cwd()) {
|
|
3355
|
+
if (!PATH_TOOLS.has(toolName)) return false;
|
|
3356
|
+
const argPath = args?.path;
|
|
3357
|
+
if (typeof argPath !== "string" || argPath.length === 0) return false;
|
|
3358
|
+
const resolved = path.resolve(cwd, argPath);
|
|
3359
|
+
const planDir = getPlanModeFileDir(cwd);
|
|
3360
|
+
const rel = path.relative(planDir, resolved);
|
|
3361
|
+
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
3362
|
+
}
|
|
3363
|
+
//#endregion
|
|
3237
3364
|
//#region ../../b4m-core/utils/dist/imageGeneration/AIImageService.mjs
|
|
3238
3365
|
/**
|
|
3239
3366
|
* Abstract class for AI Image Service
|
|
@@ -5723,7 +5850,7 @@ z.object({
|
|
|
5723
5850
|
* @see https://platform.openai.com/docs/guides/function-calling
|
|
5724
5851
|
*/
|
|
5725
5852
|
const MAX_GOAL_LENGTH = 1e3;
|
|
5726
|
-
const MAX_DESCRIPTION_LENGTH = 2e3;
|
|
5853
|
+
const MAX_DESCRIPTION_LENGTH$1 = 2e3;
|
|
5727
5854
|
ChatModels.GPT5, ChatModels.GPT5_MINI, ChatModels.GPT5_NANO, ChatModels.GPT5_1, ChatModels.GPT5_2, ChatModels.GPT5_4, ChatModels.GPT5_4_MINI, ChatModels.GPT5_4_NANO, ChatModels.GPT5_5;
|
|
5728
5855
|
/**
|
|
5729
5856
|
* Invokes the image processor Lambda to convert and resize images
|
|
@@ -15204,7 +15331,8 @@ updateUserSchema.extend({
|
|
|
15204
15331
|
note: z.string(),
|
|
15205
15332
|
userName: z.string()
|
|
15206
15333
|
})).optional(),
|
|
15207
|
-
numReferralsAvailable: z.number().optional()
|
|
15334
|
+
numReferralsAvailable: z.number().optional(),
|
|
15335
|
+
disputePending: z.boolean().optional()
|
|
15208
15336
|
});
|
|
15209
15337
|
z.object({
|
|
15210
15338
|
username: z.string(),
|
|
@@ -15907,7 +16035,7 @@ z.object({
|
|
|
15907
16035
|
const questSchema = z.object({
|
|
15908
16036
|
id: z.string(),
|
|
15909
16037
|
title: z.string().min(1).max(255),
|
|
15910
|
-
description: z.string().max(MAX_DESCRIPTION_LENGTH),
|
|
16038
|
+
description: z.string().max(MAX_DESCRIPTION_LENGTH$1),
|
|
15911
16039
|
status: z.enum([
|
|
15912
16040
|
"not_started",
|
|
15913
16041
|
"in_progress",
|
|
@@ -15930,7 +16058,7 @@ const questResourceSchema = z.object({
|
|
|
15930
16058
|
});
|
|
15931
16059
|
z.object({
|
|
15932
16060
|
title: z.string().min(1).max(255),
|
|
15933
|
-
description: z.string().max(MAX_DESCRIPTION_LENGTH).optional(),
|
|
16061
|
+
description: z.string().max(MAX_DESCRIPTION_LENGTH$1).optional(),
|
|
15934
16062
|
goal: z.string().min(1).max(MAX_GOAL_LENGTH),
|
|
15935
16063
|
complexity: z.enum([
|
|
15936
16064
|
"beginner",
|
|
@@ -18970,9 +19098,18 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
18970
19098
|
});
|
|
18971
19099
|
return result;
|
|
18972
19100
|
}
|
|
19101
|
+
const { useCliStore } = await import("./store-44C_Fvdb.mjs");
|
|
19102
|
+
const interactionMode = useCliStore.getState().interactionMode;
|
|
19103
|
+
if (interactionMode === "plan" && !isReadOnlyTool(toolName) && !isWriteTargetingPlanFile(toolName, args)) {
|
|
19104
|
+
const result = `Tool "${toolName}" is blocked while plan mode is active. Plan mode is read-only — research the codebase, then write your plan to a file under ${getPlanModeFileDir()}/. The user will press Shift+Tab to exit plan mode and authorize execution.`;
|
|
19105
|
+
agentContext.observationQueue.push({
|
|
19106
|
+
toolName,
|
|
19107
|
+
result
|
|
19108
|
+
});
|
|
19109
|
+
return result;
|
|
19110
|
+
}
|
|
18973
19111
|
if (!permissionManager.needsPermission(toolName, { isSandboxed })) return executeAndRecord();
|
|
18974
|
-
|
|
18975
|
-
if (useCliStore.getState().autoAcceptEdits) return executeAndRecord();
|
|
19112
|
+
if (interactionMode === "auto-accept") return executeAndRecord();
|
|
18976
19113
|
const response = await showPermissionPrompt(toolName, effectiveArgs, await generateToolPreview(toolName, args, isSandboxed));
|
|
18977
19114
|
if (response.action === "deny") throw new PermissionDeniedError(toolName, args);
|
|
18978
19115
|
if (response.action === "allow-session") permissionManager.trustToolForSession(toolName);
|
|
@@ -23989,6 +24126,10 @@ function createBlockerStore(onUpdate) {
|
|
|
23989
24126
|
}
|
|
23990
24127
|
//#endregion
|
|
23991
24128
|
//#region src/tools/reviewGateTool.ts
|
|
24129
|
+
const MAX_DESCRIPTION_LENGTH = 2e3;
|
|
24130
|
+
const MAX_RECOMMENDATION_LENGTH = 1e3;
|
|
24131
|
+
const MAX_OPTION_LENGTH = 500;
|
|
24132
|
+
const MAX_OPTIONS_COUNT = 10;
|
|
23992
24133
|
/**
|
|
23993
24134
|
* Validate request_review_gate parameters
|
|
23994
24135
|
* @throws Error if validation fails
|
|
@@ -23996,11 +24137,19 @@ function createBlockerStore(onUpdate) {
|
|
|
23996
24137
|
function validateParams(args) {
|
|
23997
24138
|
const params = args;
|
|
23998
24139
|
if (typeof params.description !== "string" || params.description.trim() === "") throw new Error("request_review_gate: description must be a non-empty string");
|
|
24140
|
+
if (params.description.length > MAX_DESCRIPTION_LENGTH) throw new Error(`request_review_gate: description must be ${MAX_DESCRIPTION_LENGTH} characters or fewer`);
|
|
23999
24141
|
if (params.options !== void 0) {
|
|
24000
24142
|
if (!Array.isArray(params.options)) throw new Error("request_review_gate: options must be an array of strings");
|
|
24001
|
-
|
|
24143
|
+
if (params.options.length > MAX_OPTIONS_COUNT) throw new Error(`request_review_gate: options must contain ${MAX_OPTIONS_COUNT} entries or fewer`);
|
|
24144
|
+
for (const opt of params.options) {
|
|
24145
|
+
if (typeof opt !== "string") throw new Error("request_review_gate: each option must be a string");
|
|
24146
|
+
if (opt.length > MAX_OPTION_LENGTH) throw new Error(`request_review_gate: each option must be ${MAX_OPTION_LENGTH} characters or fewer`);
|
|
24147
|
+
}
|
|
24148
|
+
}
|
|
24149
|
+
if (params.recommendation !== void 0) {
|
|
24150
|
+
if (typeof params.recommendation !== "string") throw new Error("request_review_gate: recommendation must be a string");
|
|
24151
|
+
if (params.recommendation.length > MAX_RECOMMENDATION_LENGTH) throw new Error(`request_review_gate: recommendation must be ${MAX_RECOMMENDATION_LENGTH} characters or fewer`);
|
|
24002
24152
|
}
|
|
24003
|
-
if (params.recommendation !== void 0 && typeof params.recommendation !== "string") throw new Error("request_review_gate: recommendation must be a string");
|
|
24004
24153
|
const options = params.options?.map((o) => o.trim()).filter((o) => o.length > 0);
|
|
24005
24154
|
return {
|
|
24006
24155
|
description: params.description.trim(),
|
|
@@ -24015,6 +24164,11 @@ function formatReviewGatesOutput(gates) {
|
|
|
24015
24164
|
if (gates.length === 0) return "No review gates recorded in this session.";
|
|
24016
24165
|
return gates.map((gate, index) => {
|
|
24017
24166
|
const lines = [`${index + 1}. **${gate.description}**`, ` Status: ${gate.status}`];
|
|
24167
|
+
if (gate.recommendation) lines.push(` Recommendation: ${gate.recommendation}`);
|
|
24168
|
+
if (gate.options && gate.options.length > 0) {
|
|
24169
|
+
lines.push(" Options:");
|
|
24170
|
+
for (const opt of gate.options) lines.push(` • ${opt}`);
|
|
24171
|
+
}
|
|
24018
24172
|
if (gate.userNote) lines.push(` Note: ${gate.userNote}`);
|
|
24019
24173
|
const requested = new Date(gate.timestamp).toLocaleTimeString();
|
|
24020
24174
|
lines.push(` Requested at: ${requested}`);
|
|
@@ -24053,7 +24207,9 @@ function createReviewGateTool(store, requestReviewFn) {
|
|
|
24053
24207
|
description: params.description,
|
|
24054
24208
|
status: response.decision,
|
|
24055
24209
|
resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24056
|
-
userNote: trimmedNote && trimmedNote.length > 0 ? trimmedNote : void 0
|
|
24210
|
+
userNote: trimmedNote && trimmedNote.length > 0 ? trimmedNote : void 0,
|
|
24211
|
+
options: params.options,
|
|
24212
|
+
recommendation: params.recommendation
|
|
24057
24213
|
};
|
|
24058
24214
|
store.reviewGates.push(entry);
|
|
24059
24215
|
if (store.onUpdate) store.onUpdate(store.reviewGates);
|
|
@@ -24111,4 +24267,4 @@ function createReviewGateStore(onUpdate) {
|
|
|
24111
24267
|
};
|
|
24112
24268
|
}
|
|
24113
24269
|
//#endregion
|
|
24114
|
-
export {
|
|
24270
|
+
export { CommandHistoryStore as $, formatStep as A, DEFAULT_RETRY_CONFIG as B, WebSocketToolExecutor as C, ServerLlmBackend as D, WebSocketLlmBackend as E, PermissionManager as F, OllamaBackend as G, clearFeatureModuleTools as H, generateCliTools as I, buildSkillsPromptSection as J, getPlanModeFilePath as K, ALWAYS_DENIED_FOR_AGENTS as L, loadContextFiles as M, getApiUrl as N, McpManager as O, getEnvironmentName as P, CheckpointStore as Q, DEFAULT_AGENT_MODEL as R, ApiClient as S, FallbackLlmBackend as T, registerFeatureModuleTools as U, DEFAULT_THOROUGHNESS as V, setWebSocketToolExecutor as W, ReActAgent as X, isReadOnlyTool as Y, CustomCommandStore as Z, createAgentDelegateTool as _, createBlockerTools as a, mergeCommands as at, createSkillTool as b, createDecisionStore as c, warmFileCache as ct, createFindDefinitionTool as d, SessionStore as et, createTodoStore as f, BackgroundAgentManager as g, createBackgroundAgentTools as h, createBlockerStore as i, searchCommands as it, extractCompactInstructions as j, substituteArguments as k, formatDecisionsOutput as l, createCoordinateTaskTool as m, createReviewGateTool as n, hasFileReferences as nt, formatBlockersOutput as o, formatFileSize$1 as ot, createWriteTodosTool as p, buildSystemPrompt as q, formatReviewGatesOutput as r, processFileReferences as rt, createDecisionLogTool as s, searchFiles as st, createReviewGateStore as t, OAuthClient as tt, createGetFileStructureTool as u, AgentStore as v, WebSocketConnectionManager as w, parseAgentConfig as x, SubagentOrchestrator as y, DEFAULT_MAX_ITERATIONS as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -118,11 +118,11 @@
|
|
|
118
118
|
"tsx": "^4.21.0",
|
|
119
119
|
"typescript": "^5.9.3",
|
|
120
120
|
"vitest": "^4.1.2",
|
|
121
|
-
"@bike4mind/agents": "0.
|
|
122
|
-
"@bike4mind/common": "2.92.
|
|
123
|
-
"@bike4mind/
|
|
124
|
-
"@bike4mind/utils": "2.19.
|
|
125
|
-
"@bike4mind/
|
|
121
|
+
"@bike4mind/agents": "0.8.0",
|
|
122
|
+
"@bike4mind/common": "2.92.2",
|
|
123
|
+
"@bike4mind/mcp": "1.37.4",
|
|
124
|
+
"@bike4mind/utils": "2.19.4",
|
|
125
|
+
"@bike4mind/services": "2.80.0"
|
|
126
126
|
},
|
|
127
127
|
"optionalDependencies": {
|
|
128
128
|
"@vscode/ripgrep": "^1.17.1"
|
package/dist/store-D2zh6DFz.mjs
DELETED