@bike4mind/cli 0.6.1 → 0.8.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.
@@ -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-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";
@@ -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
@@ -2911,6 +3023,84 @@ const TOOL_WRITE_TODOS = "write_todos";
2911
3023
  const TOOL_CREATE_DYNAMIC_AGENT = "create_dynamic_agent";
2912
3024
  const EXPLORE_SUBAGENT_TYPE = "explore";
2913
3025
  /**
3026
+ * Plan-mode section: tells the model that write tools are blocked and where to put the plan.
3027
+ * Appended dynamically when the user cycles into plan mode via Shift+Tab.
3028
+ *
3029
+ * The phased workflow (understand → clarify → design → present) mirrors Claude Code's
3030
+ * plan-mode prompting: research before designing, ask the user before assuming, and only
3031
+ * write the plan after ambiguities are resolved.
3032
+ */
3033
+ function buildPlanModePromptSection(planModeFilePath) {
3034
+ return `
3035
+
3036
+ ## PLAN MODE ACTIVE
3037
+
3038
+ The user has cycled into plan mode (Shift+Tab). Plan mode restricts WRITING, not READING. You still have a complete read toolkit — use it.
3039
+
3040
+ **Tools available in plan mode (use these aggressively):**
3041
+ - \`grep_search\` — find symbols, strings, patterns across files
3042
+ - \`glob_files\` — list files by pattern (use this instead of \`ls\` / \`find\`)
3043
+ - \`file_read\` — read file contents
3044
+ - \`find_definition\` — locate where a symbol is defined
3045
+ - \`get_file_structure\` — AST overview of a file
3046
+ - \`agent_delegate\` — delegate to read-only subagents (e.g. 'explore', 'plan')
3047
+ - \`ask_user_question\` — ask the user clarifying questions
3048
+ - \`current_datetime\`, \`math_evaluate\`, \`web_search\`, \`web_fetch\` — also fine
3049
+
3050
+ **Tools blocked in plan mode:**
3051
+ - \`bash_execute\`, \`edit_local_file\`, \`create_file\`, \`delete_file\` — and any other tool that mutates state.
3052
+ - Exception: \`create_file\` / \`edit_local_file\` targeting paths under \`${planModeFilePath.replace(/\/plan-[^/]+\.md$/, "/")}\` are allowed (that's where you write the plan).
3053
+
3054
+ **Forbidden responses:**
3055
+ - ❌ "I can't explore the directory because plan mode blocks shell commands."
3056
+ - ❌ "I'd need to run bash to check this."
3057
+ - ❌ Any variant of "plan mode prevents me from researching."
3058
+ - ✅ Instead: use \`glob_files\`, \`grep_search\`, \`file_read\`, or delegate to the \`explore\` subagent. Bash is not the only way to investigate code.
3059
+
3060
+ Ground every claim in files you have actually read. Do not write pseudocode in chat as a substitute for reading the real code.
3061
+
3062
+ Follow this phased workflow. Do not skip phases.
3063
+
3064
+ ### Phase 1 — Understand
3065
+ - Read the relevant code before forming opinions. Use grep_search / glob_files / file_read directly for narrow lookups.
3066
+ - For broad or uncertain scope, delegate to the 'explore' subagent via agent_delegate so the main context stays focused.
3067
+ - Identify what already exists vs. what needs to be built. Reuse existing functions and patterns rather than proposing new ones.
3068
+
3069
+ ### Phase 2 — Clarify (REQUIRED if anything is ambiguous)
3070
+ - 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**.
3071
+ - Ask about: trade-offs the user should pick between, scope (which files / how broad), behavior on edge cases, naming, dependencies you would add.
3072
+ - 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.
3073
+ - If the request is fully unambiguous, skip this phase. Do not invent questions.
3074
+
3075
+ ### Phase 3 — Design
3076
+ - For complex tasks, delegate to the 'plan' subagent via agent_delegate to get a structured implementation plan, then critique its output.
3077
+ - For simple tasks, design directly.
3078
+
3079
+ ### Phase 4 — Write the plan
3080
+ 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:
3081
+
3082
+ \`\`\`markdown
3083
+ ## Context
3084
+ Why this change is being made — the problem, what prompted it, the intended outcome.
3085
+
3086
+ ## Approach
3087
+ The chosen approach in 1-3 sentences. Mention rejected alternatives only if non-obvious.
3088
+
3089
+ ## Files to change
3090
+ - path/to/file.ts — what changes and why
3091
+ - path/to/other.ts — what changes and why
3092
+
3093
+ ## Reused existing code
3094
+ - function/module path — how it will be reused
3095
+
3096
+ ## Verification
3097
+ How to confirm the change works end-to-end (commands, tests, manual steps).
3098
+ \`\`\`
3099
+
3100
+ ### Phase 5 — Hand off
3101
+ 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.`;
3102
+ }
3103
+ /**
2914
3104
  * Build the CLI system prompt with optional project context
2915
3105
  * @param contextSection - Optional project-specific context to append (legacy string) or config object
2916
3106
  * @param config - Configuration object for building context sections (when first param is string)
@@ -2922,6 +3112,7 @@ function buildCoreSystemPrompt(contextSection, config) {
2922
3112
  let dynamicAgentSection = "";
2923
3113
  let directoriesSection = "";
2924
3114
  let featureModulesSection = "";
3115
+ let planModeSection = "";
2925
3116
  if (typeof contextSection === "string") {
2926
3117
  projectContextSection = contextSection;
2927
3118
  if (config) {
@@ -2929,6 +3120,7 @@ function buildCoreSystemPrompt(contextSection, config) {
2929
3120
  if (config.agentStore) agentDirectoryContext = config.agentStore.getDirectoryContext();
2930
3121
  if (config.enableDynamicAgentCreation) dynamicAgentSection = buildDynamicAgentPromptSection();
2931
3122
  if (config.featureModulePrompts) featureModulesSection = config.featureModulePrompts;
3123
+ if (config.planModeFilePath) planModeSection = buildPlanModePromptSection(config.planModeFilePath);
2932
3124
  }
2933
3125
  } else if (contextSection && typeof contextSection === "object") {
2934
3126
  config = contextSection;
@@ -2938,6 +3130,7 @@ function buildCoreSystemPrompt(contextSection, config) {
2938
3130
  if (config.enableDynamicAgentCreation) dynamicAgentSection = buildDynamicAgentPromptSection();
2939
3131
  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.`;
2940
3132
  if (config.featureModulePrompts) featureModulesSection = config.featureModulePrompts;
3133
+ if (config.planModeFilePath) planModeSection = buildPlanModePromptSection(config.planModeFilePath);
2941
3134
  }
2942
3135
  return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
2943
3136
 
@@ -3030,7 +3223,7 @@ EXAMPLES:
3030
3223
  Remember: Use context from previous messages to understand follow-up questions.
3031
3224
 
3032
3225
  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.
3226
+ 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
3227
 
3035
3228
  - 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
3229
 
@@ -3038,7 +3231,40 @@ You have tools for tracking decisions and blockers during your work. These creat
3038
3231
 
3039
3232
  - resolve_blocker: When a blocker is cleared, record how it was resolved. Use the blocker ID from the track_blocker output.
3040
3233
 
3041
- These tools are lightweight — use them naturally as part of your work, not as a ceremony.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}`;
3234
+ - 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.
3235
+
3236
+ These tools are lightweight — use them naturally as part of your work, not as a ceremony.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}${planModeSection}`;
3237
+ }
3238
+ /**
3239
+ * Build the minimal-variant system prompt. Reuses the project context,
3240
+ * skills, additional-directories, and feature-module sections from
3241
+ * `buildCoreSystemPrompt` — those carry user-specific information the
3242
+ * model needs and are independent of the behavioral scaffolding.
3243
+ */
3244
+ function buildMinimalSystemPrompt(config = {}) {
3245
+ let projectContextSection = "";
3246
+ let skillsSection = "";
3247
+ let directoriesSection = "";
3248
+ let featureModulesSection = "";
3249
+ let planModeSection = "";
3250
+ if (config.contextContent) projectContextSection = `\n\n## Project Context\n\nFollow these project-specific instructions:\n\n${config.contextContent}`;
3251
+ if (config.enableSkillTool !== false && config.customCommands && config.customCommands.length > 0) skillsSection = buildSkillsPromptSection(config.customCommands);
3252
+ 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.`;
3253
+ if (config.featureModulePrompts) featureModulesSection = config.featureModulePrompts;
3254
+ if (config.planModeFilePath) planModeSection = buildPlanModePromptSection(config.planModeFilePath);
3255
+ 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.
3256
+
3257
+ Guidelines:
3258
+ - Be concise in your responses.
3259
+ - Show file paths clearly when working with files.
3260
+ - 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}`;
3261
+ }
3262
+ /**
3263
+ * Pick a system prompt by variant. The dispatch point for the
3264
+ * production CLI's `promptVariant` preference flag.
3265
+ */
3266
+ function buildSystemPrompt(variant, config = {}) {
3267
+ return variant === "minimal" ? buildMinimalSystemPrompt(config) : buildCoreSystemPrompt(config);
3042
3268
  }
3043
3269
  /**
3044
3270
  * Build the dynamic agent creation prompt section
@@ -3091,6 +3317,41 @@ You have access to the '${TOOL_CREATE_DYNAMIC_AGENT}' tool, which lets you creat
3091
3317
  thoroughness: "quick"`;
3092
3318
  }
3093
3319
  //#endregion
3320
+ //#region src/utils/planMode.ts
3321
+ const PLAN_MODE_DIR = ".b4m-cli/plans";
3322
+ const PATH_TOOLS = new Set([
3323
+ "create_file",
3324
+ "edit_local_file",
3325
+ "delete_file"
3326
+ ]);
3327
+ /**
3328
+ * Directory plan-mode artifacts are written to (under the working directory).
3329
+ * Writes to paths under this directory are permitted while plan mode is active.
3330
+ */
3331
+ function getPlanModeFileDir(cwd = process.cwd()) {
3332
+ return path.resolve(cwd, PLAN_MODE_DIR);
3333
+ }
3334
+ /**
3335
+ * Default plan file for the current session. Sessions can override this if needed.
3336
+ */
3337
+ function getPlanModeFilePath(sessionId, cwd = process.cwd()) {
3338
+ const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
3339
+ return path.join(getPlanModeFileDir(cwd), `plan-${safeId}.md`);
3340
+ }
3341
+ /**
3342
+ * Whether a write/edit/delete tool call targets a path inside the plan-mode directory.
3343
+ * Used to allow incremental plan-file writes while plan mode blocks other writes.
3344
+ */
3345
+ function isWriteTargetingPlanFile(toolName, args, cwd = process.cwd()) {
3346
+ if (!PATH_TOOLS.has(toolName)) return false;
3347
+ const argPath = args?.path;
3348
+ if (typeof argPath !== "string" || argPath.length === 0) return false;
3349
+ const resolved = path.resolve(cwd, argPath);
3350
+ const planDir = getPlanModeFileDir(cwd);
3351
+ const rel = path.relative(planDir, resolved);
3352
+ return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
3353
+ }
3354
+ //#endregion
3094
3355
  //#region ../../b4m-core/utils/dist/imageGeneration/AIImageService.mjs
3095
3356
  /**
3096
3357
  * Abstract class for AI Image Service
@@ -5580,7 +5841,7 @@ z.object({
5580
5841
  * @see https://platform.openai.com/docs/guides/function-calling
5581
5842
  */
5582
5843
  const MAX_GOAL_LENGTH = 1e3;
5583
- const MAX_DESCRIPTION_LENGTH = 2e3;
5844
+ const MAX_DESCRIPTION_LENGTH$1 = 2e3;
5584
5845
  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;
5585
5846
  /**
5586
5847
  * Invokes the image processor Lambda to convert and resize images
@@ -15061,7 +15322,8 @@ updateUserSchema.extend({
15061
15322
  note: z.string(),
15062
15323
  userName: z.string()
15063
15324
  })).optional(),
15064
- numReferralsAvailable: z.number().optional()
15325
+ numReferralsAvailable: z.number().optional(),
15326
+ disputePending: z.boolean().optional()
15065
15327
  });
15066
15328
  z.object({
15067
15329
  username: z.string(),
@@ -15764,7 +16026,7 @@ z.object({
15764
16026
  const questSchema = z.object({
15765
16027
  id: z.string(),
15766
16028
  title: z.string().min(1).max(255),
15767
- description: z.string().max(MAX_DESCRIPTION_LENGTH),
16029
+ description: z.string().max(MAX_DESCRIPTION_LENGTH$1),
15768
16030
  status: z.enum([
15769
16031
  "not_started",
15770
16032
  "in_progress",
@@ -15787,7 +16049,7 @@ const questResourceSchema = z.object({
15787
16049
  });
15788
16050
  z.object({
15789
16051
  title: z.string().min(1).max(255),
15790
- description: z.string().max(MAX_DESCRIPTION_LENGTH).optional(),
16052
+ description: z.string().max(MAX_DESCRIPTION_LENGTH$1).optional(),
15791
16053
  goal: z.string().min(1).max(MAX_GOAL_LENGTH),
15792
16054
  complexity: z.enum([
15793
16055
  "beginner",
@@ -18827,9 +19089,18 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
18827
19089
  });
18828
19090
  return result;
18829
19091
  }
19092
+ const { useCliStore } = await import("./store-44C_Fvdb.mjs");
19093
+ const interactionMode = useCliStore.getState().interactionMode;
19094
+ if (interactionMode === "plan" && !isReadOnlyTool(toolName) && !isWriteTargetingPlanFile(toolName, args)) {
19095
+ 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.`;
19096
+ agentContext.observationQueue.push({
19097
+ toolName,
19098
+ result
19099
+ });
19100
+ return result;
19101
+ }
18830
19102
  if (!permissionManager.needsPermission(toolName, { isSandboxed })) return executeAndRecord();
18831
- const { useCliStore } = await import("./store-B_ILRSdP.mjs");
18832
- if (useCliStore.getState().autoAcceptEdits) return executeAndRecord();
19103
+ if (interactionMode === "auto-accept") return executeAndRecord();
18833
19104
  const response = await showPermissionPrompt(toolName, effectiveArgs, await generateToolPreview(toolName, args, isSandboxed));
18834
19105
  if (response.action === "deny") throw new PermissionDeniedError(toolName, args);
18835
19106
  if (response.action === "allow-session") permissionManager.trustToolForSession(toolName);
@@ -23620,7 +23891,7 @@ function createGetFileStructureTool() {
23620
23891
  * Validate log_decision parameters
23621
23892
  * @throws Error if validation fails
23622
23893
  */
23623
- function validateParams(args) {
23894
+ function validateParams$1(args) {
23624
23895
  const params = args;
23625
23896
  if (typeof params.summary !== "string" || params.summary.trim() === "") throw new Error("log_decision: summary must be a non-empty string");
23626
23897
  if (typeof params.rationale !== "string" || params.rationale.trim() === "") throw new Error("log_decision: rationale must be a non-empty string");
@@ -23660,7 +23931,7 @@ function formatDecisionsOutput(decisions) {
23660
23931
  function createDecisionLogTool(store) {
23661
23932
  return {
23662
23933
  toolFn: async (args) => {
23663
- const params = validateParams(args);
23934
+ const params = validateParams$1(args);
23664
23935
  const decision = {
23665
23936
  id: v4(),
23666
23937
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -23845,4 +24116,146 @@ function createBlockerStore(onUpdate) {
23845
24116
  };
23846
24117
  }
23847
24118
  //#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 };
24119
+ //#region src/tools/reviewGateTool.ts
24120
+ const MAX_DESCRIPTION_LENGTH = 2e3;
24121
+ const MAX_RECOMMENDATION_LENGTH = 1e3;
24122
+ const MAX_OPTION_LENGTH = 500;
24123
+ const MAX_OPTIONS_COUNT = 10;
24124
+ /**
24125
+ * Validate request_review_gate parameters
24126
+ * @throws Error if validation fails
24127
+ */
24128
+ function validateParams(args) {
24129
+ const params = args;
24130
+ if (typeof params.description !== "string" || params.description.trim() === "") throw new Error("request_review_gate: description must be a non-empty string");
24131
+ if (params.description.length > MAX_DESCRIPTION_LENGTH) throw new Error(`request_review_gate: description must be ${MAX_DESCRIPTION_LENGTH} characters or fewer`);
24132
+ if (params.options !== void 0) {
24133
+ if (!Array.isArray(params.options)) throw new Error("request_review_gate: options must be an array of strings");
24134
+ if (params.options.length > MAX_OPTIONS_COUNT) throw new Error(`request_review_gate: options must contain ${MAX_OPTIONS_COUNT} entries or fewer`);
24135
+ for (const opt of params.options) {
24136
+ if (typeof opt !== "string") throw new Error("request_review_gate: each option must be a string");
24137
+ if (opt.length > MAX_OPTION_LENGTH) throw new Error(`request_review_gate: each option must be ${MAX_OPTION_LENGTH} characters or fewer`);
24138
+ }
24139
+ }
24140
+ if (params.recommendation !== void 0) {
24141
+ if (typeof params.recommendation !== "string") throw new Error("request_review_gate: recommendation must be a string");
24142
+ if (params.recommendation.length > MAX_RECOMMENDATION_LENGTH) throw new Error(`request_review_gate: recommendation must be ${MAX_RECOMMENDATION_LENGTH} characters or fewer`);
24143
+ }
24144
+ const options = params.options?.map((o) => o.trim()).filter((o) => o.length > 0);
24145
+ return {
24146
+ description: params.description.trim(),
24147
+ options: options && options.length > 0 ? options : void 0,
24148
+ recommendation: typeof params.recommendation === "string" ? params.recommendation.trim() : void 0
24149
+ };
24150
+ }
24151
+ /**
24152
+ * Format review gates for display output
24153
+ */
24154
+ function formatReviewGatesOutput(gates) {
24155
+ if (gates.length === 0) return "No review gates recorded in this session.";
24156
+ return gates.map((gate, index) => {
24157
+ const lines = [`${index + 1}. **${gate.description}**`, ` Status: ${gate.status}`];
24158
+ if (gate.recommendation) lines.push(` Recommendation: ${gate.recommendation}`);
24159
+ if (gate.options && gate.options.length > 0) {
24160
+ lines.push(" Options:");
24161
+ for (const opt of gate.options) lines.push(` • ${opt}`);
24162
+ }
24163
+ if (gate.userNote) lines.push(` Note: ${gate.userNote}`);
24164
+ const requested = new Date(gate.timestamp).toLocaleTimeString();
24165
+ lines.push(` Requested at: ${requested}`);
24166
+ if (gate.resolvedAt) {
24167
+ const resolved = new Date(gate.resolvedAt).toLocaleTimeString();
24168
+ lines.push(` Resolved at: ${resolved}`);
24169
+ }
24170
+ return lines.join("\n");
24171
+ }).join("\n\n");
24172
+ }
24173
+ /**
24174
+ * Create the request_review_gate tool.
24175
+ *
24176
+ * Pauses agent execution and prompts the user for explicit approval at a
24177
+ * significant decision point. The agent halts until the user responds.
24178
+ *
24179
+ * Decisions are persisted in the session's workflow state (`reviewGates`)
24180
+ * for audit trail and cross-session continuity.
24181
+ */
24182
+ function createReviewGateTool(store, requestReviewFn) {
24183
+ return {
24184
+ toolFn: async (args) => {
24185
+ const params = validateParams(args);
24186
+ const id = v4();
24187
+ const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
24188
+ const response = await requestReviewFn({
24189
+ id,
24190
+ description: params.description,
24191
+ options: params.options,
24192
+ recommendation: params.recommendation
24193
+ });
24194
+ const trimmedNote = response.note?.trim();
24195
+ const entry = {
24196
+ id,
24197
+ timestamp: requestedAt,
24198
+ description: params.description,
24199
+ status: response.decision,
24200
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
24201
+ userNote: trimmedNote && trimmedNote.length > 0 ? trimmedNote : void 0,
24202
+ options: params.options,
24203
+ recommendation: params.recommendation
24204
+ };
24205
+ store.reviewGates.push(entry);
24206
+ if (store.onUpdate) store.onUpdate(store.reviewGates);
24207
+ const verdict = response.decision === "approved" ? "APPROVED" : "REJECTED";
24208
+ const noteText = entry.userNote ? `\nUser note: ${entry.userNote}` : "";
24209
+ return `Review gate ${verdict} [${id.slice(0, 8)}]: ${params.description}${noteText}`;
24210
+ },
24211
+ toolSchema: {
24212
+ name: "request_review_gate",
24213
+ description: `Pause execution and request explicit human approval at a significant decision point.
24214
+
24215
+ Review gates protect meaning. Stop before crossing decisions that affect interpretation, evidence, cost, credentials, platform, or public commitment.
24216
+
24217
+ **When to use:**
24218
+ - Synthesizing findings before narrowing research scope
24219
+ - Hard-to-reverse decisions (refactors, architectural pivots, dependency swaps)
24220
+ - Decisions affecting cost, credentials, or external commitments
24221
+ - Major direction changes after exploration
24222
+
24223
+ **When NOT to use:**
24224
+ - Routine operations (reading files, running tests, listing directories)
24225
+ - Operations already covered by the standard permission system (file edits, bash commands)
24226
+ - Trivial choices that wouldn't matter to someone resuming this work
24227
+
24228
+ 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.`,
24229
+ parameters: {
24230
+ type: "object",
24231
+ properties: {
24232
+ description: {
24233
+ type: "string",
24234
+ description: "Clear explanation of what the user is being asked to approve, including relevant context"
24235
+ },
24236
+ options: {
24237
+ type: "array",
24238
+ items: { type: "string" },
24239
+ description: "Optional list of alternatives the user can choose between"
24240
+ },
24241
+ recommendation: {
24242
+ type: "string",
24243
+ description: "Optional recommendation from the AI on the preferred path and why"
24244
+ }
24245
+ },
24246
+ required: ["description"]
24247
+ }
24248
+ }
24249
+ };
24250
+ }
24251
+ /**
24252
+ * Create a new empty ReviewGateStore
24253
+ */
24254
+ function createReviewGateStore(onUpdate) {
24255
+ return {
24256
+ reviewGates: [],
24257
+ onUpdate
24258
+ };
24259
+ }
24260
+ //#endregion
24261
+ 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 };