@bike4mind/cli 0.6.1 → 0.7.0

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.
@@ -8829,7 +8829,14 @@ const CliConfigSchema = z.object({
8829
8829
  maxIterations: z.number().nullable().prefault(10),
8830
8830
  enableSkillTool: z.boolean().optional().prefault(true),
8831
8831
  enableDynamicAgentCreation: z.boolean().optional().prefault(false),
8832
- enableCoordinatorMode: z.boolean().optional().prefault(false)
8832
+ enableCoordinatorMode: z.boolean().optional().prefault(false),
8833
+ /**
8834
+ * System-prompt variant. 'current' uses the elaborate behavioral-scaffolding
8835
+ * prompt; 'minimal' uses a pi-style short prompt. See apps/cli/src/core/prompts.ts.
8836
+ * Defaults to 'current' for backward compatibility; switch via /config or by
8837
+ * editing the config file directly.
8838
+ */
8839
+ promptVariant: z.enum(["current", "minimal"]).optional().prefault("current")
8833
8840
  }),
8834
8841
  tools: z.object({
8835
8842
  enabled: z.array(z.string()),
@@ -8862,7 +8869,8 @@ const ProjectConfigSchema = z.object({
8862
8869
  exportFormat: z.enum(["markdown", "json"]).optional(),
8863
8870
  enableSkillTool: z.boolean().optional(),
8864
8871
  enableDynamicAgentCreation: z.boolean().optional(),
8865
- enableCoordinatorMode: z.boolean().optional()
8872
+ enableCoordinatorMode: z.boolean().optional(),
8873
+ promptVariant: z.enum(["current", "minimal"]).optional()
8866
8874
  }).optional(),
8867
8875
  sandbox: PartialSandboxConfigSchema,
8868
8876
  additionalDirectories: z.array(z.string()).optional()
@@ -8912,7 +8920,8 @@ const DEFAULT_CONFIG = {
8912
8920
  maxIterations: 10,
8913
8921
  enableSkillTool: true,
8914
8922
  enableDynamicAgentCreation: false,
8915
- enableCoordinatorMode: false
8923
+ enableCoordinatorMode: false,
8924
+ promptVariant: "current"
8916
8925
  },
8917
8926
  tools: {
8918
8927
  enabled: [],
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as version, n as compareSemver, r as fetchLatestVersion } from "../updateChecker-D-xoVcN3.mjs";
2
+ import { a as version, n as compareSemver, r as fetchLatestVersion } from "../updateChecker-Dn-Ri8zw.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 { A as getApiUrl, C as WebSocketLlmBackend, G as isReadOnlyTool, J as CheckpointStore, K as ReActAgent, M as PermissionManager, N as generateCliTools, S as FallbackLlmBackend, T as McpManager, U as buildCoreSystemPrompt, V as setWebSocketToolExecutor, X as SessionStore, _ as createSkillTool, b as WebSocketToolExecutor, c as createFindDefinitionTool, d as createCoordinateTaskTool, f as createBackgroundAgentTools, g as SubagentOrchestrator, h as AgentStore, k as loadContextFiles, l as createTodoStore, m as createAgentDelegateTool, p as BackgroundAgentManager, q as CustomCommandStore, s as createGetFileStructureTool, u as createWriteTodosTool, w as ServerLlmBackend, x as WebSocketConnectionManager, y as ApiClient } from "../tools-BUs_OkJc.mjs";
3
- import { n as logger, t as ConfigStore } from "../ConfigStore-Dt6utdSA.mjs";
2
+ import { $ as SessionStore, C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as PermissionManager, I as generateCliTools, J as isReadOnlyTool, K as buildSystemPrompt, M as loadContextFiles, N as getApiUrl, O as McpManager, S as ApiClient, T as FallbackLlmBackend, W as setWebSocketToolExecutor, X as CustomCommandStore, Y as ReActAgent, Z as CheckpointStore, _ as createAgentDelegateTool, b as createSkillTool, d as createFindDefinitionTool, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, m as createCoordinateTaskTool, p as createWriteTodosTool, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, y as SubagentOrchestrator } from "../tools-DY-JzNoY.mjs";
3
+ import { n as logger, t as ConfigStore } from "../ConfigStore-Bu_plzvP.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";
@@ -193,7 +193,7 @@ async function handleHeadlessCommand(options) {
193
193
  ...mcpTools,
194
194
  ...cliTools
195
195
  ];
196
- const systemPrompt = buildCoreSystemPrompt({
196
+ const systemPrompt = buildSystemPrompt(config.preferences.promptVariant ?? "current", {
197
197
  contextContent: contextResult.mergedContent,
198
198
  agentStore,
199
199
  customCommands: customCommandStore.getAllCommands(),
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-Dt6utdSA.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-Bu_plzvP.mjs";
3
3
  //#region src/commands/mcpCommand.ts
4
4
  /**
5
5
  * External MCP commands (b4m mcp list, b4m mcp add, etc.)
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as version, i as forceCheckForUpdate } from "../updateChecker-D-xoVcN3.mjs";
2
+ import { a as version, i as forceCheckForUpdate } from "../updateChecker-Dn-Ri8zw.mjs";
3
3
  import { execSync } from "child_process";
4
4
  //#region src/commands/updateCommand.ts
5
5
  /**
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-B7-LLvvx.mjs";
3
- import { $ as processFileReferences, A as getApiUrl, B as registerFeatureModuleTools, C as WebSocketLlmBackend, D as formatStep, E as substituteArguments, F as DEFAULT_AGENT_MODEL, G as isReadOnlyTool, H as OllamaBackend, I as DEFAULT_MAX_ITERATIONS, J as CheckpointStore, K as ReActAgent, L as DEFAULT_RETRY_CONFIG, M as PermissionManager, N as generateCliTools, O as extractCompactInstructions, P as ALWAYS_DENIED_FOR_AGENTS, Q as hasFileReferences, R as DEFAULT_THOROUGHNESS, S as FallbackLlmBackend, T as McpManager, U as buildCoreSystemPrompt, V as setWebSocketToolExecutor, W as buildSkillsPromptSection, X as SessionStore, Y as CommandHistoryStore, Z as OAuthClient, _ as createSkillTool, a as createDecisionStore, b as WebSocketToolExecutor, c as createFindDefinitionTool, d as createCoordinateTaskTool, et as searchCommands, f as createBackgroundAgentTools, g as SubagentOrchestrator, h as AgentStore, i as createDecisionLogTool, it as warmFileCache, j as getEnvironmentName, k as loadContextFiles, l as createTodoStore, m as createAgentDelegateTool, n as createBlockerTools, nt as formatFileSize, o as formatDecisionsOutput, p as BackgroundAgentManager, q as CustomCommandStore, r as formatBlockersOutput, rt as searchFiles, s as createGetFileStructureTool, t as createBlockerStore, tt as mergeCommands, u as createWriteTodosTool, v as parseAgentConfig, w as ServerLlmBackend, x as WebSocketConnectionManager, y as ApiClient, z as clearFeatureModuleTools } from "./tools-BUs_OkJc.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-Dt6utdSA.mjs";
5
- import { a as version, t as checkForUpdate } from "./updateChecker-D-xoVcN3.mjs";
2
+ import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-FkY4K-0M.mjs";
3
+ import { $ as SessionStore, 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 isReadOnlyTool, K as buildSystemPrompt, L as ALWAYS_DENIED_FOR_AGENTS, M as loadContextFiles, N as getApiUrl, O as McpManager, P as getEnvironmentName, Q as CommandHistoryStore, R as DEFAULT_AGENT_MODEL, S as ApiClient, T as FallbackLlmBackend, U as registerFeatureModuleTools, V as DEFAULT_THOROUGHNESS, W as setWebSocketToolExecutor, X as CustomCommandStore, Y as ReActAgent, Z as CheckpointStore, _ as createAgentDelegateTool, a as createBlockerTools, at as formatFileSize, b as createSkillTool, c as createDecisionStore, d as createFindDefinitionTool, et as OAuthClient, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, i as createBlockerStore, it as mergeCommands, j as extractCompactInstructions, k as substituteArguments, l as formatDecisionsOutput, m as createCoordinateTaskTool, n as createReviewGateTool, nt as processFileReferences, o as formatBlockersOutput, ot as searchFiles, p as createWriteTodosTool, q as buildSkillsPromptSection, r as formatReviewGatesOutput, rt as searchCommands, s as createDecisionLogTool, st as warmFileCache, t as createReviewGateStore, tt as hasFileReferences, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, x as parseAgentConfig, y as SubagentOrchestrator, z as DEFAULT_MAX_ITERATIONS } from "./tools-DY-JzNoY.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-Bu_plzvP.mjs";
5
+ import { a as version, t as checkForUpdate } from "./updateChecker-Dn-Ri8zw.mjs";
6
6
  import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
7
7
  import { Box, Static, Text, render, useApp, useInput } from "ink";
8
8
  import { execSync } from "child_process";
@@ -1274,6 +1274,138 @@ function UserQuestionPrompt({ payload, onResponse }) {
1274
1274
  })), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, isOnOther ? "Type your answer, Enter to submit, or arrow keys to go back" : isMulti ? "Press 1-" + options.length + ", Space to toggle, Enter to confirm" : "Press 1-" + options.length + ", or arrow keys + Enter")));
1275
1275
  }
1276
1276
  //#endregion
1277
+ //#region src/components/ReviewGatePrompt.tsx
1278
+ const ITEMS = [
1279
+ {
1280
+ label: "✓ Approve",
1281
+ decision: "approved",
1282
+ withNote: false
1283
+ },
1284
+ {
1285
+ label: "✓ Approve with note...",
1286
+ decision: "approved",
1287
+ withNote: true
1288
+ },
1289
+ {
1290
+ label: "✗ Reject",
1291
+ decision: "rejected",
1292
+ withNote: false
1293
+ },
1294
+ {
1295
+ label: "✗ Reject with note...",
1296
+ decision: "rejected",
1297
+ withNote: true
1298
+ }
1299
+ ];
1300
+ /**
1301
+ * Review gate prompt component.
1302
+ *
1303
+ * Pauses the agent and asks the user to explicitly approve or reject a
1304
+ * significant decision. An optional free-text note can be attached to either
1305
+ * decision via the dedicated "...with note..." actions.
1306
+ *
1307
+ * Keyboard:
1308
+ * - 1–4: shortcut for each action
1309
+ * - y: Approve (no note); n: Reject (no note)
1310
+ * - ↑/↓: navigate; Enter: confirm selection
1311
+ * - When a "with note..." action is selected, an inline text input appears.
1312
+ * Type the note and press Enter to submit. Use ↑/↓ to switch to a no-note
1313
+ * action without losing the typed note.
1314
+ */
1315
+ function ReviewGatePrompt({ description, options, recommendation, onResponse }) {
1316
+ const [selectedIndex, setSelectedIndex] = useState(0);
1317
+ const [note, setNote] = useState("");
1318
+ const [responded, setResponded] = useState(false);
1319
+ const submit = useCallback((item, noteText) => {
1320
+ if (responded) return;
1321
+ setResponded(true);
1322
+ const trimmed = noteText.trim();
1323
+ onResponse({
1324
+ decision: item.decision,
1325
+ note: trimmed.length > 0 ? trimmed : void 0
1326
+ });
1327
+ }, [responded, onResponse]);
1328
+ const selectedItem = ITEMS[selectedIndex];
1329
+ const noteMode = selectedItem.withNote;
1330
+ const handleConfirm = useCallback(() => {
1331
+ if (selectedItem.withNote && note.trim().length === 0) return;
1332
+ submit(selectedItem, note);
1333
+ }, [
1334
+ selectedItem,
1335
+ note,
1336
+ submit
1337
+ ]);
1338
+ useInput((input, key) => {
1339
+ if (responded) return;
1340
+ if (key.upArrow) {
1341
+ setSelectedIndex((i) => i > 0 ? i - 1 : ITEMS.length - 1);
1342
+ return;
1343
+ }
1344
+ if (key.downArrow) {
1345
+ setSelectedIndex((i) => i < ITEMS.length - 1 ? i + 1 : 0);
1346
+ return;
1347
+ }
1348
+ if (noteMode) return;
1349
+ const num = parseInt(input, 10);
1350
+ if (num >= 1 && num <= ITEMS.length) {
1351
+ const item = ITEMS[num - 1];
1352
+ setSelectedIndex(num - 1);
1353
+ if (!item.withNote) submit(item, "");
1354
+ return;
1355
+ }
1356
+ if (input.toLowerCase() === "y") {
1357
+ submit(ITEMS[0], "");
1358
+ return;
1359
+ }
1360
+ if (input.toLowerCase() === "n") {
1361
+ submit(ITEMS[2], "");
1362
+ return;
1363
+ }
1364
+ if (key.return) handleConfirm();
1365
+ }, { isActive: !responded });
1366
+ if (responded) return null;
1367
+ return /* @__PURE__ */ React.createElement(Box, {
1368
+ flexDirection: "column",
1369
+ borderStyle: "bold",
1370
+ borderColor: "magenta",
1371
+ padding: 1,
1372
+ marginY: 1
1373
+ }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, {
1374
+ bold: true,
1375
+ color: "magenta"
1376
+ }, "🛑 Review Gate")), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, null, description)), recommendation && /* @__PURE__ */ React.createElement(Box, {
1377
+ marginTop: 1,
1378
+ flexDirection: "column"
1379
+ }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Recommendation:"), /* @__PURE__ */ React.createElement(Box, { paddingLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, recommendation))), options && options.length > 0 && /* @__PURE__ */ React.createElement(Box, {
1380
+ marginTop: 1,
1381
+ flexDirection: "column"
1382
+ }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Options:"), /* @__PURE__ */ React.createElement(Box, {
1383
+ paddingLeft: 2,
1384
+ flexDirection: "column"
1385
+ }, options.map((opt, idx) => /* @__PURE__ */ React.createElement(Text, {
1386
+ key: idx,
1387
+ dimColor: true
1388
+ }, "• ", opt)))), /* @__PURE__ */ React.createElement(Box, {
1389
+ marginTop: 1,
1390
+ flexDirection: "column"
1391
+ }, ITEMS.map((item, index) => {
1392
+ const isHighlighted = index === selectedIndex;
1393
+ const color = item.decision === "approved" ? "green" : "red";
1394
+ return /* @__PURE__ */ React.createElement(Box, { key: item.label }, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, index + 1, "."), /* @__PURE__ */ React.createElement(Text, {
1395
+ color: isHighlighted ? color : void 0,
1396
+ bold: isHighlighted
1397
+ }, isHighlighted ? " ❯ " : " ", item.label));
1398
+ })), noteMode && /* @__PURE__ */ React.createElement(Box, {
1399
+ marginTop: 1,
1400
+ flexDirection: "column"
1401
+ }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Note:"), /* @__PURE__ */ React.createElement(Box, { paddingLeft: 2 }, /* @__PURE__ */ React.createElement(TextInput, {
1402
+ value: note,
1403
+ onChange: setNote,
1404
+ onSubmit: handleConfirm,
1405
+ 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")));
1407
+ }
1408
+ //#endregion
1277
1409
  //#region src/components/ConfigEditor.tsx
1278
1410
  /**
1279
1411
  * Max iterations options: 10, 20, 30, 40, 50, Infinite (null)
@@ -1886,7 +2018,7 @@ const MessageItem = React.memo(function MessageItem({ message }) {
1886
2018
  });
1887
2019
  //#endregion
1888
2020
  //#region src/components/App.tsx
1889
- function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPermissionResponse, onUserQuestionResponse, onImageDetected, commandHistory = [], commands = [], config, availableModels = [], onSaveConfig, prefillInput, onPrefillConsumed, mcpManager }) {
2021
+ function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPermissionResponse, onUserQuestionResponse, onReviewGateResponse, onImageDetected, commandHistory = [], commands = [], config, availableModels = [], onSaveConfig, prefillInput, onPrefillConsumed, mcpManager }) {
1890
2022
  const messages = useCliStore((state) => state.session?.messages || []);
1891
2023
  const pendingMessages = useCliStore((state) => state.pendingMessages);
1892
2024
  const sessionName = useCliStore((state) => state.session?.name || "New Session");
@@ -1896,6 +2028,7 @@ function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPe
1896
2028
  const isThinking = useCliStore((state) => state.isThinking);
1897
2029
  const permissionPrompt = useCliStore((state) => state.permissionPrompt);
1898
2030
  const userQuestionPrompt = useCliStore((state) => state.userQuestionPrompt);
2031
+ const reviewGatePrompt = useCliStore((state) => state.reviewGatePrompt);
1899
2032
  const showConfigEditor = useCliStore((state) => state.showConfigEditor);
1900
2033
  const setShowConfigEditor = useCliStore((state) => state.setShowConfigEditor);
1901
2034
  const showMcpViewer = useCliStore((state) => state.showMcpViewer);
@@ -1988,7 +2121,16 @@ function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPe
1988
2121
  }, /* @__PURE__ */ React.createElement(UserQuestionPrompt, {
1989
2122
  payload: userQuestionPrompt.payload,
1990
2123
  onResponse: (response) => onUserQuestionResponse(response, userQuestionPrompt.id)
1991
- })), !permissionPrompt && !userQuestionPrompt && /* @__PURE__ */ React.createElement(AgentThinking, null), /* @__PURE__ */ React.createElement(BackgroundAgentStatus, null), /* @__PURE__ */ React.createElement(CompletedGroupNotification, null), exitRequested && /* @__PURE__ */ React.createElement(Box, {
2124
+ })), reviewGatePrompt && /* @__PURE__ */ React.createElement(Box, {
2125
+ key: reviewGatePrompt.id,
2126
+ flexDirection: "column",
2127
+ paddingX: 1
2128
+ }, /* @__PURE__ */ React.createElement(ReviewGatePrompt, {
2129
+ description: reviewGatePrompt.description,
2130
+ options: reviewGatePrompt.options,
2131
+ recommendation: reviewGatePrompt.recommendation,
2132
+ onResponse: (response) => onReviewGateResponse(response, reviewGatePrompt.id)
2133
+ })), !permissionPrompt && !userQuestionPrompt && !reviewGatePrompt && /* @__PURE__ */ React.createElement(AgentThinking, null), /* @__PURE__ */ React.createElement(BackgroundAgentStatus, null), /* @__PURE__ */ React.createElement(CompletedGroupNotification, null), exitRequested && /* @__PURE__ */ React.createElement(Box, {
1992
2134
  paddingX: 1,
1993
2135
  marginBottom: 1
1994
2136
  }, /* @__PURE__ */ React.createElement(Text, {
@@ -2002,7 +2144,7 @@ function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPe
2002
2144
  onSubmit: handleSubmit,
2003
2145
  onBashCommand,
2004
2146
  onImageDetected,
2005
- disabled: isThinking || !!permissionPrompt || !!userQuestionPrompt,
2147
+ disabled: isThinking || !!permissionPrompt || !!userQuestionPrompt || !!reviewGatePrompt,
2006
2148
  history: commandHistory,
2007
2149
  commands,
2008
2150
  prefillInput,
@@ -2469,7 +2611,7 @@ function buildCompactionPrompt(messages, options = {}) {
2469
2611
  function createCompactedSession(originalSession, summary, preservedMessages) {
2470
2612
  const summaryMessage = {
2471
2613
  id: v4(),
2472
- role: "system",
2614
+ role: "user",
2473
2615
  content: `[Previous conversation summary]\n\n${summary}`,
2474
2616
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2475
2617
  };
@@ -5235,10 +5377,13 @@ function CliApp() {
5235
5377
  const imageStoreInitPromise = useRef(null);
5236
5378
  const decisionStoreRef = useRef(createDecisionStore());
5237
5379
  const blockerStoreRef = useRef(createBlockerStore());
5380
+ const reviewGateStoreRef = useRef(createReviewGateStore());
5238
5381
  const setStoreSession = useCliStore((state) => state.setSession);
5239
5382
  const enqueuePermissionPrompt = useCliStore((state) => state.enqueuePermissionPrompt);
5240
5383
  const enqueueUserQuestionPrompt = useCliStore((state) => state.enqueueUserQuestionPrompt);
5241
5384
  const dequeueUserQuestionPrompt = useCliStore((state) => state.dequeueUserQuestionPrompt);
5385
+ const enqueueReviewGatePrompt = useCliStore((state) => state.enqueueReviewGatePrompt);
5386
+ const dequeueReviewGatePrompt = useCliStore((state) => state.dequeueReviewGatePrompt);
5242
5387
  const setShowConfigEditor = useCliStore((state) => state.setShowConfigEditor);
5243
5388
  const setShowMcpViewer = useCliStore((state) => state.setShowMcpViewer);
5244
5389
  const setExitRequested = useCliStore((state) => state.setExitRequested);
@@ -5628,6 +5773,22 @@ function CliApp() {
5628
5773
  });
5629
5774
  });
5630
5775
  };
5776
+ const reviewGateFn = (params) => {
5777
+ return new Promise((resolve) => {
5778
+ enqueueReviewGatePrompt({
5779
+ id: params.id,
5780
+ description: params.description,
5781
+ options: params.options,
5782
+ recommendation: params.recommendation,
5783
+ resolve
5784
+ });
5785
+ bridgePresence.emitEvent({
5786
+ type: "status",
5787
+ status: "awaiting_input",
5788
+ text: `Review gate: ${params.description}`.slice(0, 240)
5789
+ });
5790
+ });
5791
+ };
5631
5792
  const agentContext = {
5632
5793
  currentAgent: null,
5633
5794
  observationQueue: []
@@ -5681,12 +5842,15 @@ function CliApp() {
5681
5842
  const writeTodosTool = createWriteTodosTool(createTodoStore());
5682
5843
  const decisionLogTool = createDecisionLogTool(decisionStoreRef.current);
5683
5844
  const blockerTools = createBlockerTools(blockerStoreRef.current);
5845
+ const reviewGateTool = createReviewGateTool(reviewGateStoreRef.current, reviewGateFn);
5684
5846
  if (newSession.metadata.workflow) {
5685
5847
  decisionStoreRef.current.decisions = [...newSession.metadata.workflow.decisions];
5686
5848
  blockerStoreRef.current.blockers = [...newSession.metadata.workflow.blockers];
5849
+ reviewGateStoreRef.current.reviewGates = [...newSession.metadata.workflow.reviewGates ?? []];
5687
5850
  } else {
5688
5851
  decisionStoreRef.current.decisions = [];
5689
5852
  blockerStoreRef.current.blockers = [];
5853
+ reviewGateStoreRef.current.reviewGates = [];
5690
5854
  }
5691
5855
  const enableSkillTool = config.preferences.enableSkillTool !== false;
5692
5856
  const skillTool = enableSkillTool ? createSkillTool({
@@ -5707,6 +5871,7 @@ function CliApp() {
5707
5871
  writeTodosTool,
5708
5872
  decisionLogTool,
5709
5873
  ...blockerTools,
5874
+ reviewGateTool,
5710
5875
  findDefinitionTool,
5711
5876
  getFileStructureTool
5712
5877
  ];
@@ -5741,7 +5906,7 @@ function CliApp() {
5741
5906
  if (contextResult.projectContext) startupLog.push(`📄 Project context: ${contextResult.projectContext.filename}`);
5742
5907
  for (const error of contextResult.errors) startupLog.push(`⚠️ Context file error: ${error}`);
5743
5908
  const featureModulePrompts = featureRegistry.getSystemPromptSections();
5744
- const cliSystemPrompt = buildCoreSystemPrompt({
5909
+ const cliSystemPrompt = buildSystemPrompt(config.preferences.promptVariant ?? "current", {
5745
5910
  contextContent: contextResult.mergedContent,
5746
5911
  agentStore,
5747
5912
  customCommands: state.customCommandStore.getAllCommands(),
@@ -5980,6 +6145,14 @@ function CliApp() {
5980
6145
  });
5981
6146
  return;
5982
6147
  }
6148
+ if (s.reviewGatePrompt) {
6149
+ bridgePresence.emitEvent({
6150
+ type: "status",
6151
+ status: "awaiting_input",
6152
+ text: `Review gate: ${s.reviewGatePrompt.description}`.slice(0, 240)
6153
+ });
6154
+ return;
6155
+ }
5983
6156
  const abort = abortControllerRef.current;
5984
6157
  if (!abort || abort.signal.aborted) return;
5985
6158
  bridgePresence.emitEvent({
@@ -6137,11 +6310,11 @@ function CliApp() {
6137
6310
  totalTokens: currentSession.metadata.totalTokens + result.completionInfo.totalTokens,
6138
6311
  totalCredits: (currentSession.metadata.totalCredits || 0) + (result.completionInfo.totalCredits || 0),
6139
6312
  toolCallCount: currentSession.metadata.toolCallCount + successfulToolCalls,
6140
- workflow: decisionStoreRef.current.decisions.length > 0 || blockerStoreRef.current.blockers.length > 0 ? {
6313
+ workflow: decisionStoreRef.current.decisions.length > 0 || blockerStoreRef.current.blockers.length > 0 || reviewGateStoreRef.current.reviewGates.length > 0 ? {
6141
6314
  decisions: decisionStoreRef.current.decisions,
6142
6315
  blockers: blockerStoreRef.current.blockers,
6143
6316
  handoff: currentSession.metadata.workflow?.handoff,
6144
- reviewGates: currentSession.metadata.workflow?.reviewGates
6317
+ reviewGates: reviewGateStoreRef.current.reviewGates
6145
6318
  } : currentSession.metadata.workflow
6146
6319
  }
6147
6320
  };
@@ -6255,7 +6428,7 @@ function CliApp() {
6255
6428
  if (config?.preferences.autoCompact !== false && activeSession.messages.length >= 6) {
6256
6429
  const tokenCounter = getTokenCounter();
6257
6430
  const threshold = tokenCounter.getContextWindow(activeSession.model, state.availableModels) * .8;
6258
- const systemPrompt = buildCoreSystemPrompt({
6431
+ const systemPrompt = buildSystemPrompt(config?.preferences.promptVariant ?? "current", {
6259
6432
  contextContent: state.contextContent,
6260
6433
  agentStore: state.agentStore || void 0,
6261
6434
  customCommands: state.customCommandStore.getAllCommands(),
@@ -6653,7 +6826,7 @@ function CliApp() {
6653
6826
  decisions: decisionStoreRef.current.decisions,
6654
6827
  blockers: blockerStoreRef.current.blockers,
6655
6828
  handoff,
6656
- reviewGates: session.metadata.workflow?.reviewGates
6829
+ reviewGates: reviewGateStoreRef.current.reviewGates
6657
6830
  };
6658
6831
  return handoff;
6659
6832
  } catch (err) {
@@ -6798,11 +6971,11 @@ Multi-line Input:
6798
6971
  }
6799
6972
  const sessionName = args.join(" ") || state.session.name;
6800
6973
  state.session.name = sessionName;
6801
- if (decisionStoreRef.current.decisions.length > 0 || blockerStoreRef.current.blockers.length > 0) state.session.metadata.workflow = {
6974
+ if (decisionStoreRef.current.decisions.length > 0 || blockerStoreRef.current.blockers.length > 0 || reviewGateStoreRef.current.reviewGates.length > 0) state.session.metadata.workflow = {
6802
6975
  decisions: decisionStoreRef.current.decisions,
6803
6976
  blockers: blockerStoreRef.current.blockers,
6804
6977
  handoff: state.session.metadata.workflow?.handoff,
6805
- reviewGates: state.session.metadata.workflow?.reviewGates
6978
+ reviewGates: reviewGateStoreRef.current.reviewGates
6806
6979
  };
6807
6980
  const handoff = await generateHandoff(state.session);
6808
6981
  await state.sessionStore.save(state.session);
@@ -7077,6 +7250,7 @@ Multi-line Input:
7077
7250
  logger.debug("=== New Session Started via /clear ===");
7078
7251
  decisionStoreRef.current.decisions = [];
7079
7252
  blockerStoreRef.current.blockers = [];
7253
+ reviewGateStoreRef.current.reviewGates = [];
7080
7254
  if (state.checkpointStore) state.checkpointStore.setSessionId(newSession.id);
7081
7255
  setState((prev) => ({
7082
7256
  ...prev,
@@ -7309,7 +7483,8 @@ Multi-line Input:
7309
7483
  }
7310
7484
  const tokenCounter = getTokenCounter();
7311
7485
  const contextWindow = tokenCounter.getContextWindow(state.session.model, state.availableModels);
7312
- const corePromptTokens = tokenCounter.countTokens(buildCoreSystemPrompt());
7486
+ const variantForCount = state.config?.preferences.promptVariant ?? "current";
7487
+ const corePromptTokens = tokenCounter.countTokens(buildSystemPrompt(variantForCount));
7313
7488
  const projectContextTokens = state.contextContent ? tokenCounter.countTokens(state.contextContent) : 0;
7314
7489
  const commands = state.customCommandStore.getAllCommands();
7315
7490
  const skillsSection = buildSkillsPromptSection(commands);
@@ -7318,7 +7493,7 @@ Multi-line Input:
7318
7493
  const mcpTools = state.mcpManager?.getTools() || [];
7319
7494
  const mcpToolsTokens = tokenCounter.countToolSchemaTokens(mcpTools);
7320
7495
  const mcpToolCount = state.mcpManager?.getToolCount() || [];
7321
- const systemPrompt = buildCoreSystemPrompt({
7496
+ const systemPrompt = buildSystemPrompt(variantForCount, {
7322
7497
  contextContent: state.contextContent,
7323
7498
  agentStore: state.agentStore || void 0,
7324
7499
  customCommands: commands,
@@ -7778,6 +7953,11 @@ Multi-line Input:
7778
7953
  console.log(formatBlockersOutput(blockerStoreRef.current.blockers));
7779
7954
  console.log("");
7780
7955
  break;
7956
+ case "review-gates":
7957
+ console.log("\n🛑 Review Gates\n");
7958
+ console.log(formatReviewGatesOutput(reviewGateStoreRef.current.reviewGates));
7959
+ console.log("");
7960
+ break;
7781
7961
  case "handoff": {
7782
7962
  if (!state.session) {
7783
7963
  console.log("No active session");
@@ -7891,7 +8071,7 @@ Multi-line Input:
7891
8071
  const newFeatureTools = newFeatureRegistry.getAllTools();
7892
8072
  agentContext.tools = [...baseTools, ...newFeatureTools];
7893
8073
  const newFeaturePrompts = newFeatureRegistry.getSystemPromptSections();
7894
- agentContext.systemPrompt = buildCoreSystemPrompt({
8074
+ agentContext.systemPrompt = buildSystemPrompt(updatedConfig.preferences.promptVariant ?? "current", {
7895
8075
  contextContent: state.contextContent,
7896
8076
  agentStore: state.agentStore || void 0,
7897
8077
  customCommands: state.customCommandStore.getAllCommands(),
@@ -8040,6 +8220,13 @@ Multi-line Input:
8040
8220
  currentPrompt.resolve(response);
8041
8221
  dequeueUserQuestionPrompt();
8042
8222
  emitNextAwaitingStatus();
8223
+ },
8224
+ onReviewGateResponse: (response, promptId) => {
8225
+ const currentPrompt = useCliStore.getState().reviewGatePrompt;
8226
+ if (currentPrompt?.id !== promptId) return;
8227
+ currentPrompt.resolve(response);
8228
+ dequeueReviewGatePrompt();
8229
+ emitNextAwaitingStatus();
8043
8230
  }
8044
8231
  });
8045
8232
  }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { n as useCliStore } from "./store-FkY4K-0M.mjs";
3
+ export { useCliStore };
@@ -105,6 +105,19 @@ const useCliStore = create((set) => ({
105
105
  userQuestionQueue: rest
106
106
  };
107
107
  }),
108
+ reviewGatePrompt: null,
109
+ reviewGateQueue: [],
110
+ enqueueReviewGatePrompt: (prompt) => set((state) => {
111
+ if (!state.reviewGatePrompt) return { reviewGatePrompt: prompt };
112
+ return { reviewGateQueue: [...state.reviewGateQueue, prompt] };
113
+ }),
114
+ dequeueReviewGatePrompt: () => set((state) => {
115
+ const [next, ...rest] = state.reviewGateQueue;
116
+ return {
117
+ reviewGatePrompt: next ?? null,
118
+ reviewGateQueue: rest
119
+ };
120
+ }),
108
121
  showConfigEditor: false,
109
122
  setShowConfigEditor: (show) => set({ showConfigEditor: show }),
110
123
  showMcpViewer: false,
@@ -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-Dt6utdSA.mjs";
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-Bu_plzvP.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";
@@ -1906,11 +1906,17 @@ var ReActAgent = class extends EventEmitter {
1906
1906
  iterations = 0;
1907
1907
  /** Whether runIteration() has been initialized (messages built, state reset) */
1908
1908
  iterationInitialized = false;
1909
+ /**
1910
+ * Length of the initial messages array (system + previousMessages + user query)
1911
+ * before any ReAct iteration messages are appended. Used by trimConversationHistory
1912
+ * to protect the conversation prefix from being mistaken for iteration nudges.
1913
+ */
1914
+ initialMessageCount = 0;
1909
1915
  constructor(context) {
1910
1916
  super();
1911
1917
  this.context = {
1912
1918
  ...context,
1913
- maxIterations: context.maxIterations ?? 5,
1919
+ maxIterations: context.maxIterations ?? 50,
1914
1920
  maxTokens: context.maxTokens ?? 4096,
1915
1921
  temperature: context.temperature ?? .7
1916
1922
  };
@@ -1933,11 +1939,13 @@ var ReActAgent = class extends EventEmitter {
1933
1939
  this.toolCallCount = 0;
1934
1940
  this.confidenceLog = [];
1935
1941
  this.iterationConfidences = [];
1936
- const maxIterations = options.maxIterations ?? this.context.maxIterations ?? 5;
1942
+ const maxIterations = options.maxIterations ?? this.context.maxIterations ?? 50;
1937
1943
  const temperature = options.temperature ?? this.context.temperature ?? .7;
1938
1944
  const maxTokens = options.maxTokens ?? this.context.maxTokens ?? 4096;
1945
+ const maxTotalTokens = options.maxTotalTokens ?? this.context.maxTotalTokens;
1939
1946
  const maxHistoryIterations = options.maxHistoryIterations ?? 4;
1940
1947
  let iterations = 0;
1948
+ let reachedMaxTotalTokens = false;
1941
1949
  try {
1942
1950
  const messages = [
1943
1951
  {
@@ -1951,6 +1959,7 @@ var ReActAgent = class extends EventEmitter {
1951
1959
  }
1952
1960
  ];
1953
1961
  this.messages = messages;
1962
+ this.initialMessageCount = messages.length;
1954
1963
  messages.forEach((msg, i) => {
1955
1964
  const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
1956
1965
  this.context.logger.debug(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
@@ -1987,7 +1996,7 @@ var ReActAgent = class extends EventEmitter {
1987
1996
  const processedToolIds = /* @__PURE__ */ new Set();
1988
1997
  let hadToolCalls = false;
1989
1998
  if (maxHistoryIterations > 0 && iterations > 1) {
1990
- trimConversationHistory(messages, maxHistoryIterations);
1999
+ trimConversationHistory(messages, maxHistoryIterations, this.initialMessageCount);
1991
2000
  trimSteps(this.steps, maxHistoryIterations);
1992
2001
  }
1993
2002
  const cacheStrategy = options.enableCaching ? {
@@ -2119,6 +2128,18 @@ var ReActAgent = class extends EventEmitter {
2119
2128
  role: "user",
2120
2129
  content: `Based on the tool results above, please provide a complete answer. If I asked for multiple things, make sure to address all of them.`
2121
2130
  });
2131
+ if (maxTotalTokens !== void 0 && this.totalTokens >= maxTotalTokens && !iterationComplete) {
2132
+ reachedMaxTotalTokens = true;
2133
+ finalAnswer = currentText.trim() || `I stopped after reaching the cumulative token ceiling (${this.totalTokens}/${maxTotalTokens}) without arriving at a final answer.`;
2134
+ const finalStep = {
2135
+ type: "final_answer",
2136
+ content: finalAnswer,
2137
+ metadata: { timestamp: Date.now() }
2138
+ };
2139
+ this.steps.push(finalStep);
2140
+ this.emit("final_answer", finalStep);
2141
+ break;
2142
+ }
2122
2143
  if (iterations >= maxIterations) {
2123
2144
  reachedMaxIterations = true;
2124
2145
  finalAnswer = currentText.trim() || `I reached the maximum number of iterations (${iterations}/${maxIterations}) without arriving at a final answer.`;
@@ -2147,6 +2168,7 @@ var ReActAgent = class extends EventEmitter {
2147
2168
  iterations,
2148
2169
  toolCalls: this.toolCallCount,
2149
2170
  reachedMaxIterations,
2171
+ reachedMaxTotalTokens: reachedMaxTotalTokens || void 0,
2150
2172
  averageConfidence: avgConfidence,
2151
2173
  minConfidence,
2152
2174
  confidenceLog: this.confidenceLog.length > 0 ? this.confidenceLog : void 0
@@ -2265,7 +2287,8 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2265
2287
  totalCredits: this.totalCredits,
2266
2288
  toolCallCount: this.toolCallCount,
2267
2289
  confidenceLog: structuredClone(this.confidenceLog),
2268
- iterationConfidences: [...this.iterationConfidences]
2290
+ iterationConfidences: [...this.iterationConfidences],
2291
+ initialMessageCount: this.initialMessageCount
2269
2292
  };
2270
2293
  }
2271
2294
  /**
@@ -2290,6 +2313,7 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2290
2313
  this.toolCallCount = checkpoint.toolCallCount;
2291
2314
  this.confidenceLog = structuredClone(checkpoint.confidenceLog);
2292
2315
  this.iterationConfidences = [...checkpoint.iterationConfidences];
2316
+ this.initialMessageCount = checkpoint.initialMessageCount ?? this.messages.length;
2293
2317
  this.observationQueue = [];
2294
2318
  this.iterationInitialized = true;
2295
2319
  }
@@ -2325,9 +2349,10 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2325
2349
  * regressing the battle-tested run() path in this PR.
2326
2350
  */
2327
2351
  async runIteration(query, options = {}) {
2328
- const maxIterations = options.maxIterations ?? this.context.maxIterations ?? 5;
2352
+ const maxIterations = options.maxIterations ?? this.context.maxIterations ?? 50;
2329
2353
  const temperature = options.temperature ?? this.context.temperature ?? .7;
2330
2354
  const maxTokens = options.maxTokens ?? this.context.maxTokens ?? 4096;
2355
+ const maxTotalTokens = options.maxTotalTokens ?? this.context.maxTotalTokens;
2331
2356
  if (!this.iterationInitialized) {
2332
2357
  if (!query) throw new Error("query is required on the first call to runIteration(). Pass the user query, or call fromCheckpoint() first to resume.");
2333
2358
  this.steps = [];
@@ -2352,6 +2377,7 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2352
2377
  content: query
2353
2378
  }
2354
2379
  ];
2380
+ this.initialMessageCount = this.messages.length;
2355
2381
  this.iterationInitialized = true;
2356
2382
  }
2357
2383
  if (this.iterations >= maxIterations) {
@@ -2393,7 +2419,7 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2393
2419
  this.context.logger.debug(`[ReActAgent] Starting iteration ${this.iterations}/${maxIterations}`);
2394
2420
  const maxHistoryIterations = options.maxHistoryIterations ?? 4;
2395
2421
  if (maxHistoryIterations > 0 && this.iterations > 1) {
2396
- trimConversationHistory(this.messages, maxHistoryIterations);
2422
+ trimConversationHistory(this.messages, maxHistoryIterations, this.initialMessageCount);
2397
2423
  trimSteps(this.steps, maxHistoryIterations);
2398
2424
  }
2399
2425
  let iterationComplete = false;
@@ -2540,6 +2566,25 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2540
2566
  role: "user",
2541
2567
  content: "Based on the tool results above, please provide a complete answer. If I asked for multiple things, make sure to address all of them."
2542
2568
  });
2569
+ if (!iterationComplete && maxTotalTokens !== void 0 && this.totalTokens >= maxTotalTokens) {
2570
+ finalAnswer = currentText.trim() || `I stopped after reaching the cumulative token ceiling (${this.totalTokens}/${maxTotalTokens}) without arriving at a final answer.`;
2571
+ const ceilingStep = {
2572
+ type: "final_answer",
2573
+ content: finalAnswer,
2574
+ metadata: { timestamp: Date.now() }
2575
+ };
2576
+ this.steps.push(ceilingStep);
2577
+ iterationSteps.push(ceilingStep);
2578
+ this.emit("final_answer", ceilingStep);
2579
+ return {
2580
+ step: ceilingStep,
2581
+ allSteps: iterationSteps,
2582
+ isComplete: true,
2583
+ reachedMaxIterations: false,
2584
+ reachedMaxTotalTokens: true,
2585
+ checkpoint: this.toCheckpoint()
2586
+ };
2587
+ }
2543
2588
  if (!iterationComplete && this.iterations >= maxIterations) {
2544
2589
  finalAnswer = currentText.trim() || `I reached the maximum number of iterations (${this.iterations}/${maxIterations}) without arriving at a final answer.`;
2545
2590
  const maxStep = {
@@ -2671,10 +2716,19 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2671
2716
  return .7;
2672
2717
  }
2673
2718
  /**
2674
- * Parse tool arguments, handling both string and object forms
2719
+ * Parse tool arguments, handling both string and object forms.
2720
+ *
2721
+ * Recovers from common malformed-JSON patterns models emit before failing:
2722
+ * - Trailing commas before `]` or `}` (frequent across providers)
2723
+ * - Markdown code fences wrapping the JSON (`` ```json ... ``` ``)
2724
+ *
2725
+ * If recovery succeeds, logs at debug level so provider-specific patterns
2726
+ * can be tracked. If recovery fails, re-throws the original parse error
2727
+ * so the failure mode stays visible.
2675
2728
  */
2676
2729
  parseToolArguments(args) {
2677
- return typeof args === "string" ? JSON.parse(args) : args;
2730
+ if (typeof args !== "string") return args;
2731
+ return parseToolArgsLenient(args, this.context.logger);
2678
2732
  }
2679
2733
  /**
2680
2734
  * Execute a tool and return the result as a string.
@@ -2715,6 +2769,64 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
2715
2769
  }
2716
2770
  };
2717
2771
  /**
2772
+ * Parse JSON tool arguments with recovery for common LLM mistakes.
2773
+ *
2774
+ * Strategy: try standard parse first (the happy path, no allocation). On
2775
+ * failure, attempt targeted fixes one at a time and retry. Each recovery
2776
+ * step is conservative — it only handles patterns that have a low risk of
2777
+ * silently corrupting valid input.
2778
+ *
2779
+ * Exported for direct use and unit testing.
2780
+ */
2781
+ function parseToolArgsLenient(args, logger) {
2782
+ try {
2783
+ return JSON.parse(args);
2784
+ } catch (originalError) {
2785
+ const recoveries = [
2786
+ {
2787
+ name: "strip-code-fence",
2788
+ transform: stripCodeFence
2789
+ },
2790
+ {
2791
+ name: "strip-trailing-commas",
2792
+ transform: stripTrailingCommas
2793
+ },
2794
+ {
2795
+ name: "strip-code-fence+strip-trailing-commas",
2796
+ transform: (s) => stripTrailingCommas(stripCodeFence(s))
2797
+ }
2798
+ ];
2799
+ for (const { name, transform } of recoveries) {
2800
+ const candidate = transform(args);
2801
+ if (candidate === args) continue;
2802
+ try {
2803
+ const result = JSON.parse(candidate);
2804
+ logger?.debug?.(`[ReActAgent] Recovered malformed tool args via ${name}`);
2805
+ return result;
2806
+ } catch {}
2807
+ }
2808
+ throw originalError;
2809
+ }
2810
+ }
2811
+ /**
2812
+ * Remove a wrapping markdown code fence, e.g. `` ```json\n{...}\n``` ``.
2813
+ * Preserves input if no recognizable fence is found.
2814
+ */
2815
+ function stripCodeFence(input) {
2816
+ const fenceMatch = input.trim().match(/^```(?:json|JSON)?\s*\n?([\s\S]*?)\n?```$/);
2817
+ return fenceMatch ? fenceMatch[1].trim() : input;
2818
+ }
2819
+ /**
2820
+ * Strip commas that immediately precede `}` or `]` (with optional whitespace).
2821
+ * Conservative: doesn't touch commas inside strings because the regex only
2822
+ * matches commas followed by whitespace and a closing bracket.
2823
+ *
2824
+ * Preserves input if no trailing-comma pattern is found.
2825
+ */
2826
+ function stripTrailingCommas(input) {
2827
+ return input.replace(/,(\s*[}\]])/g, "$1");
2828
+ }
2829
+ /**
2718
2830
  * Trim the steps array to keep only the last N iterations worth of steps.
2719
2831
  *
2720
2832
  * Each iteration produces 1-5 steps (thought, action(s), observation(s), final_answer).
@@ -2731,27 +2843,27 @@ function trimSteps(steps, maxIterations) {
2731
2843
  }
2732
2844
  }
2733
2845
  /**
2734
- * Trim conversation history to keep only the initial messages (system + user query)
2735
- * plus the last N iterations of assistant/tool/user messages.
2846
+ * Trim conversation history to keep the protected prefix (system + previousMessages
2847
+ * + current user query) plus the last N iterations of assistant/tool/user messages.
2736
2848
  *
2737
2849
  * Each ReAct iteration adds ~3-5 messages (assistant with tool calls, tool results,
2738
2850
  * user nudge). Keeping all iterations causes input tokens to grow quadratically.
2739
2851
  * Trimming to the last N iterations keeps the agent grounded in recent context
2740
2852
  * while dramatically reducing token accumulation.
2853
+ *
2854
+ * @param protectedPrefixCount - Length of the initial messages array before any
2855
+ * ReAct iteration messages were appended. Required when previousMessages is
2856
+ * used, otherwise prior-turn user messages get mistaken for iteration nudges
2857
+ * and trimmed away (including, eventually, the current user query itself).
2741
2858
  */
2742
- function trimConversationHistory(messages, maxIterations) {
2743
- let dynamicStart = 0;
2744
- for (let i = 0; i < messages.length; i++) if (messages[i].role === "user") {
2745
- dynamicStart = i + 1;
2746
- break;
2747
- }
2859
+ function trimConversationHistory(messages, maxIterations, protectedPrefixCount) {
2860
+ const dynamicStart = protectedPrefixCount;
2748
2861
  const dynamicMessages = messages.slice(dynamicStart);
2749
2862
  if (dynamicMessages.length === 0) return;
2750
2863
  const nudgeIndices = [];
2751
2864
  for (let i = 0; i < dynamicMessages.length; i++) if (dynamicMessages[i].role === "user" && typeof dynamicMessages[i].content === "string") nudgeIndices.push(i);
2752
2865
  if (nudgeIndices.length <= maxIterations) return;
2753
- const cutoffNudgeIndex = nudgeIndices[nudgeIndices.length - maxIterations];
2754
- const keepFrom = dynamicStart + cutoffNudgeIndex;
2866
+ const keepFrom = dynamicStart + nudgeIndices[nudgeIndices.length - maxIterations];
2755
2867
  messages.splice(dynamicStart, keepFrom - dynamicStart);
2756
2868
  }
2757
2869
  //#endregion
@@ -3030,7 +3142,7 @@ EXAMPLES:
3030
3142
  Remember: Use context from previous messages to understand follow-up questions.
3031
3143
 
3032
3144
  DURABLE WORKFLOW TRACKING:
3033
- You have tools for tracking decisions and blockers during your work. These create an audit trail that persists across sessions, enabling anyone to understand why things were done and what's still outstanding.
3145
+ You have tools for tracking decisions, blockers, and human review gates during your work. These create an audit trail that persists across sessions, enabling anyone to understand why things were done and what's still outstanding.
3034
3146
 
3035
3147
  - log_decision: When you make a significant decision (architecture choice, scope narrowing, interpretation of ambiguous requirements, trade-off between alternatives), log it with rationale. Do NOT log trivial decisions. Log decisions that would matter if someone needed to understand WHY you did something or if they needed to resume this work.
3036
3148
 
@@ -3038,9 +3150,40 @@ You have tools for tracking decisions and blockers during your work. These creat
3038
3150
 
3039
3151
  - resolve_blocker: When a blocker is cleared, record how it was resolved. Use the blocker ID from the track_blocker output.
3040
3152
 
3153
+ - 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
+
3041
3155
  These tools are lightweight — use them naturally as part of your work, not as a ceremony.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}`;
3042
3156
  }
3043
3157
  /**
3158
+ * Build the minimal-variant system prompt. Reuses the project context,
3159
+ * skills, additional-directories, and feature-module sections from
3160
+ * `buildCoreSystemPrompt` — those carry user-specific information the
3161
+ * model needs and are independent of the behavioral scaffolding.
3162
+ */
3163
+ function buildMinimalSystemPrompt(config = {}) {
3164
+ let projectContextSection = "";
3165
+ let skillsSection = "";
3166
+ let directoriesSection = "";
3167
+ let featureModulesSection = "";
3168
+ if (config.contextContent) projectContextSection = `\n\n## Project Context\n\nFollow these project-specific instructions:\n\n${config.contextContent}`;
3169
+ if (config.enableSkillTool !== false && config.customCommands && config.customCommands.length > 0) skillsSection = buildSkillsPromptSection(config.customCommands);
3170
+ 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
+ if (config.featureModulePrompts) featureModulesSection = config.featureModulePrompts;
3172
+ 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
+
3174
+ Guidelines:
3175
+ - Be concise in your responses.
3176
+ - 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}`;
3178
+ }
3179
+ /**
3180
+ * Pick a system prompt by variant. The dispatch point for the
3181
+ * production CLI's `promptVariant` preference flag.
3182
+ */
3183
+ function buildSystemPrompt(variant, config = {}) {
3184
+ return variant === "minimal" ? buildMinimalSystemPrompt(config) : buildCoreSystemPrompt(config);
3185
+ }
3186
+ /**
3044
3187
  * Build the dynamic agent creation prompt section
3045
3188
  * Injected into the system prompt when enableDynamicAgentCreation is true
3046
3189
  */
@@ -18828,7 +18971,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
18828
18971
  return result;
18829
18972
  }
18830
18973
  if (!permissionManager.needsPermission(toolName, { isSandboxed })) return executeAndRecord();
18831
- const { useCliStore } = await import("./store-B_ILRSdP.mjs");
18974
+ const { useCliStore } = await import("./store-D2zh6DFz.mjs");
18832
18975
  if (useCliStore.getState().autoAcceptEdits) return executeAndRecord();
18833
18976
  const response = await showPermissionPrompt(toolName, effectiveArgs, await generateToolPreview(toolName, args, isSandboxed));
18834
18977
  if (response.action === "deny") throw new PermissionDeniedError(toolName, args);
@@ -23620,7 +23763,7 @@ function createGetFileStructureTool() {
23620
23763
  * Validate log_decision parameters
23621
23764
  * @throws Error if validation fails
23622
23765
  */
23623
- function validateParams(args) {
23766
+ function validateParams$1(args) {
23624
23767
  const params = args;
23625
23768
  if (typeof params.summary !== "string" || params.summary.trim() === "") throw new Error("log_decision: summary must be a non-empty string");
23626
23769
  if (typeof params.rationale !== "string" || params.rationale.trim() === "") throw new Error("log_decision: rationale must be a non-empty string");
@@ -23660,7 +23803,7 @@ function formatDecisionsOutput(decisions) {
23660
23803
  function createDecisionLogTool(store) {
23661
23804
  return {
23662
23805
  toolFn: async (args) => {
23663
- const params = validateParams(args);
23806
+ const params = validateParams$1(args);
23664
23807
  const decision = {
23665
23808
  id: v4(),
23666
23809
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -23845,4 +23988,127 @@ function createBlockerStore(onUpdate) {
23845
23988
  };
23846
23989
  }
23847
23990
  //#endregion
23848
- export { processFileReferences as $, getApiUrl as A, registerFeatureModuleTools as B, WebSocketLlmBackend as C, formatStep as D, substituteArguments as E, DEFAULT_AGENT_MODEL as F, isReadOnlyTool as G, OllamaBackend as H, DEFAULT_MAX_ITERATIONS as I, CheckpointStore as J, ReActAgent as K, DEFAULT_RETRY_CONFIG as L, PermissionManager as M, generateCliTools as N, extractCompactInstructions as O, ALWAYS_DENIED_FOR_AGENTS as P, hasFileReferences as Q, DEFAULT_THOROUGHNESS as R, FallbackLlmBackend as S, McpManager as T, buildCoreSystemPrompt as U, setWebSocketToolExecutor as V, buildSkillsPromptSection as W, SessionStore as X, CommandHistoryStore as Y, OAuthClient as Z, createSkillTool as _, createDecisionStore as a, WebSocketToolExecutor as b, createFindDefinitionTool as c, createCoordinateTaskTool as d, searchCommands as et, createBackgroundAgentTools as f, SubagentOrchestrator as g, AgentStore as h, createDecisionLogTool as i, warmFileCache as it, getEnvironmentName as j, loadContextFiles as k, createTodoStore as l, createAgentDelegateTool as m, createBlockerTools as n, formatFileSize$1 as nt, formatDecisionsOutput as o, BackgroundAgentManager as p, CustomCommandStore as q, formatBlockersOutput as r, searchFiles as rt, createGetFileStructureTool as s, createBlockerStore as t, mergeCommands as tt, createWriteTodosTool as u, parseAgentConfig as v, ServerLlmBackend as w, WebSocketConnectionManager as x, ApiClient as y, clearFeatureModuleTools as z };
23991
+ //#region src/tools/reviewGateTool.ts
23992
+ /**
23993
+ * Validate request_review_gate parameters
23994
+ * @throws Error if validation fails
23995
+ */
23996
+ function validateParams(args) {
23997
+ const params = args;
23998
+ if (typeof params.description !== "string" || params.description.trim() === "") throw new Error("request_review_gate: description must be a non-empty string");
23999
+ if (params.options !== void 0) {
24000
+ if (!Array.isArray(params.options)) throw new Error("request_review_gate: options must be an array of strings");
24001
+ for (const opt of params.options) if (typeof opt !== "string") throw new Error("request_review_gate: each option must be a string");
24002
+ }
24003
+ if (params.recommendation !== void 0 && typeof params.recommendation !== "string") throw new Error("request_review_gate: recommendation must be a string");
24004
+ const options = params.options?.map((o) => o.trim()).filter((o) => o.length > 0);
24005
+ return {
24006
+ description: params.description.trim(),
24007
+ options: options && options.length > 0 ? options : void 0,
24008
+ recommendation: typeof params.recommendation === "string" ? params.recommendation.trim() : void 0
24009
+ };
24010
+ }
24011
+ /**
24012
+ * Format review gates for display output
24013
+ */
24014
+ function formatReviewGatesOutput(gates) {
24015
+ if (gates.length === 0) return "No review gates recorded in this session.";
24016
+ return gates.map((gate, index) => {
24017
+ const lines = [`${index + 1}. **${gate.description}**`, ` Status: ${gate.status}`];
24018
+ if (gate.userNote) lines.push(` Note: ${gate.userNote}`);
24019
+ const requested = new Date(gate.timestamp).toLocaleTimeString();
24020
+ lines.push(` Requested at: ${requested}`);
24021
+ if (gate.resolvedAt) {
24022
+ const resolved = new Date(gate.resolvedAt).toLocaleTimeString();
24023
+ lines.push(` Resolved at: ${resolved}`);
24024
+ }
24025
+ return lines.join("\n");
24026
+ }).join("\n\n");
24027
+ }
24028
+ /**
24029
+ * Create the request_review_gate tool.
24030
+ *
24031
+ * Pauses agent execution and prompts the user for explicit approval at a
24032
+ * significant decision point. The agent halts until the user responds.
24033
+ *
24034
+ * Decisions are persisted in the session's workflow state (`reviewGates`)
24035
+ * for audit trail and cross-session continuity.
24036
+ */
24037
+ function createReviewGateTool(store, requestReviewFn) {
24038
+ return {
24039
+ toolFn: async (args) => {
24040
+ const params = validateParams(args);
24041
+ const id = v4();
24042
+ const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
24043
+ const response = await requestReviewFn({
24044
+ id,
24045
+ description: params.description,
24046
+ options: params.options,
24047
+ recommendation: params.recommendation
24048
+ });
24049
+ const trimmedNote = response.note?.trim();
24050
+ const entry = {
24051
+ id,
24052
+ timestamp: requestedAt,
24053
+ description: params.description,
24054
+ status: response.decision,
24055
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
24056
+ userNote: trimmedNote && trimmedNote.length > 0 ? trimmedNote : void 0
24057
+ };
24058
+ store.reviewGates.push(entry);
24059
+ if (store.onUpdate) store.onUpdate(store.reviewGates);
24060
+ const verdict = response.decision === "approved" ? "APPROVED" : "REJECTED";
24061
+ const noteText = entry.userNote ? `\nUser note: ${entry.userNote}` : "";
24062
+ return `Review gate ${verdict} [${id.slice(0, 8)}]: ${params.description}${noteText}`;
24063
+ },
24064
+ toolSchema: {
24065
+ name: "request_review_gate",
24066
+ description: `Pause execution and request explicit human approval at a significant decision point.
24067
+
24068
+ Review gates protect meaning. Stop before crossing decisions that affect interpretation, evidence, cost, credentials, platform, or public commitment.
24069
+
24070
+ **When to use:**
24071
+ - Synthesizing findings before narrowing research scope
24072
+ - Hard-to-reverse decisions (refactors, architectural pivots, dependency swaps)
24073
+ - Decisions affecting cost, credentials, or external commitments
24074
+ - Major direction changes after exploration
24075
+
24076
+ **When NOT to use:**
24077
+ - Routine operations (reading files, running tests, listing directories)
24078
+ - Operations already covered by the standard permission system (file edits, bash commands)
24079
+ - Trivial choices that wouldn't matter to someone resuming this work
24080
+
24081
+ The agent will pause until the user explicitly approves or rejects. The user may attach an optional note to their decision (e.g., to redirect or clarify scope). Treat a rejection as a hard stop — re-plan rather than retry.`,
24082
+ parameters: {
24083
+ type: "object",
24084
+ properties: {
24085
+ description: {
24086
+ type: "string",
24087
+ description: "Clear explanation of what the user is being asked to approve, including relevant context"
24088
+ },
24089
+ options: {
24090
+ type: "array",
24091
+ items: { type: "string" },
24092
+ description: "Optional list of alternatives the user can choose between"
24093
+ },
24094
+ recommendation: {
24095
+ type: "string",
24096
+ description: "Optional recommendation from the AI on the preferred path and why"
24097
+ }
24098
+ },
24099
+ required: ["description"]
24100
+ }
24101
+ }
24102
+ };
24103
+ }
24104
+ /**
24105
+ * Create a new empty ReviewGateStore
24106
+ */
24107
+ function createReviewGateStore(onUpdate) {
24108
+ return {
24109
+ reviewGates: [],
24110
+ onUpdate
24111
+ };
24112
+ }
24113
+ //#endregion
24114
+ export { SessionStore 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, isReadOnlyTool as J, buildSystemPrompt as K, ALWAYS_DENIED_FOR_AGENTS as L, loadContextFiles as M, getApiUrl as N, McpManager as O, getEnvironmentName as P, CommandHistoryStore as Q, DEFAULT_AGENT_MODEL as R, ApiClient as S, FallbackLlmBackend as T, registerFeatureModuleTools as U, DEFAULT_THOROUGHNESS as V, setWebSocketToolExecutor as W, CustomCommandStore as X, ReActAgent as Y, CheckpointStore as Z, createAgentDelegateTool as _, createBlockerTools as a, formatFileSize$1 as at, createSkillTool as b, createDecisionStore as c, createFindDefinitionTool as d, OAuthClient as et, createTodoStore as f, BackgroundAgentManager as g, createBackgroundAgentTools as h, createBlockerStore as i, mergeCommands as it, extractCompactInstructions as j, substituteArguments as k, formatDecisionsOutput as l, createCoordinateTaskTool as m, createReviewGateTool as n, processFileReferences as nt, formatBlockersOutput as o, searchFiles as ot, createWriteTodosTool as p, buildSkillsPromptSection as q, formatReviewGatesOutput as r, searchCommands as rt, createDecisionLogTool as s, warmFileCache as st, createReviewGateStore as t, hasFileReferences as tt, createGetFileStructureTool as u, AgentStore as v, WebSocketConnectionManager as w, parseAgentConfig as x, SubagentOrchestrator as y, DEFAULT_MAX_ITERATIONS as z };
@@ -4,7 +4,7 @@ import { homedir } from "os";
4
4
  import path from "path";
5
5
  import axios from "axios";
6
6
  //#region package.json
7
- var version = "0.6.1";
7
+ var version = "0.7.0";
8
8
  //#endregion
9
9
  //#region src/utils/updateChecker.ts
10
10
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
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.6.3",
121
+ "@bike4mind/agents": "0.7.0",
122
122
  "@bike4mind/common": "2.92.1",
123
- "@bike4mind/mcp": "1.37.3",
124
- "@bike4mind/services": "2.79.3",
125
- "@bike4mind/utils": "2.19.3"
123
+ "@bike4mind/services": "2.79.4",
124
+ "@bike4mind/utils": "2.19.3",
125
+ "@bike4mind/mcp": "1.37.3"
126
126
  },
127
127
  "optionalDependencies": {
128
128
  "@vscode/ripgrep": "^1.17.1"
@@ -134,6 +134,7 @@
134
134
  "test": "vitest run",
135
135
  "test:watch": "vitest",
136
136
  "start": "node dist/index.mjs",
137
+ "eval:run": "tsx src/evals/cli.ts",
137
138
  "postinstall": "node -e \"try { require('better-sqlite3') } catch(e) { if(e.message.includes('bindings')) { console.log('\\n⚠️ Rebuilding better-sqlite3 native bindings...'); require('child_process').execSync('pnpm rebuild better-sqlite3', {stdio:'inherit'}) } }\""
138
139
  }
139
140
  }
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import { n as useCliStore } from "./store-B7-LLvvx.mjs";
3
- export { useCliStore };