@bike4mind/cli 2.1.0 → 3.0.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.
Files changed (30) hide show
  1. package/README.md +1 -1
  2. package/dist/{AgentHistoryStore-DdYKfx7C.mjs → AgentHistoryStore-DVxv1kSO.mjs} +7905 -7029
  3. package/dist/{ConfigStore-BygzEI6H.mjs → ConfigStore-51UaP9pJ.mjs} +10645 -6760
  4. package/dist/{ImageStore-kVo-oHoS.mjs → ImageStore-DuI3tgwQ.mjs} +8 -6
  5. package/dist/SandboxRuntimeAdapter-Bt1wPpld.mjs +2 -0
  6. package/dist/{WorkItemsClient-ClBC49y0.mjs → WorkItemsClient-BMY0Qq1s.mjs} +27 -2
  7. package/dist/{buildAgent-B7cMwRAy.mjs → buildAgent-CrSRKYU_.mjs} +75 -43
  8. package/dist/commands/acpCommand.mjs +26 -35
  9. package/dist/commands/apiCommand.mjs +1 -1
  10. package/dist/commands/doctorCommand.mjs +3 -3
  11. package/dist/commands/envCommand.mjs +1 -1
  12. package/dist/commands/headlessCommand.mjs +15 -24
  13. package/dist/commands/mcpCommand.mjs +3 -3
  14. package/dist/commands/pluginCommand.mjs +2 -2
  15. package/dist/commands/updateCommand.mjs +5 -15
  16. package/dist/dist-BsG2Hlp-.mjs +739 -0
  17. package/dist/index.mjs +602 -324
  18. package/dist/{package-CRNnNXxq.mjs → package-DEsNSP54.mjs} +1 -1
  19. package/dist/{serve-DM7ld3-o.mjs → serve-BaHzVbcm.mjs} +300 -154
  20. package/dist/store-BkMur6uk.mjs +2 -0
  21. package/dist/{store-CvjTpQPs.mjs → store-BxmPEI3v.mjs} +10 -0
  22. package/dist/types-I45lMh7Q.mjs +2 -0
  23. package/dist/{updateChecker-CQW8bxo6.mjs → updateChecker-CCLVVdH0.mjs} +36 -13
  24. package/package.json +24 -23
  25. package/dist/ApiClient-dIB3YQc2.mjs +0 -316
  26. package/dist/SandboxRuntimeAdapter-BmHELLuM.mjs +0 -3
  27. package/dist/store-BG3e54c8.mjs +0 -3
  28. package/dist/types-CdIKgWWe.mjs +0 -3
  29. package/dist/{bashExecute-CrdPpBqk-DCATrE-D.mjs → bashExecute-CrdPpBqk-CgK1gZa2.mjs} +1 -1
  30. package/dist/{grepSearch-BgoOOwGe-DtlV8Gn-.mjs → grepSearch-BgoOOwGe-B388GxRD.mjs} +2 -2
@@ -139,12 +139,14 @@ var ImageStore = class ImageStore {
139
139
  const maxDimension = 2048;
140
140
  let width = metadata.width;
141
141
  let height = metadata.height;
142
- if (width > maxDimension || height > maxDimension) if (width > height) {
143
- height = Math.round(height * maxDimension / width);
144
- width = maxDimension;
145
- } else {
146
- width = Math.round(width * maxDimension / height);
147
- height = maxDimension;
142
+ if (width > maxDimension || height > maxDimension) {
143
+ if (width > height) {
144
+ height = Math.round(height * maxDimension / width);
145
+ width = maxDimension;
146
+ } else {
147
+ width = Math.round(width * maxDimension / height);
148
+ height = maxDimension;
149
+ }
148
150
  }
149
151
  image = image.resize(width, height);
150
152
  let quality = 85;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export { t as createSandboxRuntime, n as detectPlatform, r as expandPath, i as isBinaryAvailable } from "./SandboxRuntimeAdapter-BgLUVTJL.mjs";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { bt as tokenEstimateMultiplier } from "./ConfigStore-BygzEI6H.mjs";
2
+ import { kt as tokenEstimateMultiplier } from "./ConfigStore-51UaP9pJ.mjs";
3
3
  import { v4 } from "uuid";
4
4
  import { get_encoding } from "tiktoken";
5
5
  //#region ../../b4m-core/utils/dist/calibratedTokenizer.mjs
@@ -17,6 +17,8 @@ function scaleTokenEstimate(count, multiplier) {
17
17
  //#region src/utils/tokenCounter.ts
18
18
  const DEFAULT_CONTEXT_WINDOW = 2e5;
19
19
  const IMAGE_BLOCK_TOKEN_ESTIMATE = 1600;
20
+ const TOKEN_CACHE_MIN_CHARS = 256;
21
+ const DEFAULT_TOKEN_CACHE_MAX_CHARS = 4e6;
20
22
  /**
21
23
  * Token counting utility for context window management.
22
24
  * Uses tiktoken (cl100k_base encoding), the encoding GPT-4 reports. Claude's tokenizers spend more
@@ -24,8 +26,11 @@ const IMAGE_BLOCK_TOKEN_ESTIMATE = 1600;
24
26
  * context window (see tokenEstimateMultiplier in @bike4mind/common).
25
27
  */
26
28
  var TokenCounter = class {
27
- constructor() {
29
+ constructor(cacheMaxChars = DEFAULT_TOKEN_CACHE_MAX_CHARS) {
30
+ this.cacheMaxChars = cacheMaxChars;
28
31
  this.encoder = null;
32
+ this.countCache = /* @__PURE__ */ new Map();
33
+ this.cachedChars = 0;
29
34
  }
30
35
  getEncoder() {
31
36
  if (!this.encoder) this.encoder = get_encoding("cl100k_base");
@@ -45,6 +50,24 @@ var TokenCounter = class {
45
50
  * Count tokens in a text string
46
51
  */
47
52
  countTokens(text) {
53
+ if (text.length < TOKEN_CACHE_MIN_CHARS || text.length > this.cacheMaxChars) return this.encode(text);
54
+ const cached = this.countCache.get(text);
55
+ if (cached !== void 0) {
56
+ this.countCache.delete(text);
57
+ this.countCache.set(text, cached);
58
+ return cached;
59
+ }
60
+ const count = this.encode(text);
61
+ this.countCache.set(text, count);
62
+ this.cachedChars += text.length;
63
+ for (const [oldest] of this.countCache) {
64
+ if (this.cachedChars <= this.cacheMaxChars) break;
65
+ this.countCache.delete(oldest);
66
+ this.cachedChars -= oldest.length;
67
+ }
68
+ return count;
69
+ }
70
+ encode(text) {
48
71
  return this.getEncoder().encode_ordinary(text).length;
49
72
  }
50
73
  /**
@@ -99,6 +122,8 @@ var TokenCounter = class {
99
122
  * Free encoder resources when done
100
123
  */
101
124
  dispose() {
125
+ this.countCache.clear();
126
+ this.cachedChars = 0;
102
127
  if (this.encoder) {
103
128
  this.encoder.free();
104
129
  this.encoder = null;
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { I as generateCliTools, J as setWebSocketToolExecutor, L as wrapTools, N as ReActAgent, X as buildSystemPrompt, Y as getPlanModeFilePath, a as loadProjectContext, c as createSseBackend, i as buildProjectAgentStore, it as Logger, l as ServerLlmBackend, n as BackgroundAgentManager, o as McpManager, r as SubagentOrchestrator, t as AgentHistoryStore } from "./AgentHistoryStore-DdYKfx7C.mjs";
3
- import { $ as escapeThinkMarkers, A as ChatModels, C as ARTIFACT_REMOVED_PLACEHOLDER, L as MODEL_INFO_FIELD_GROUP_OF, O as CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS, Q as createThinkMarkerEscaper, S as ARTIFACT_DELIVERED_PLACEHOLDER, W as PermissionDeniedError, _t as stripDeliveredArtifactBlocks, at as hasDeliverablePinnedArtifact, et as filterToolArtifactMarkup, lt as isUserInitiatedAbort, n as logger, rt as getQuestErrorCode, vt as stripToolArtifactMarkup, z as ModelBackend } from "./ConfigStore-BygzEI6H.mjs";
2
+ import { J as getPlanModeFilePath, L as generateCliTools, N as ReActAgent, R as wrapTools, Y as buildSystemPrompt, a as loadProjectContext, c as createSseBackend, i as buildProjectAgentStore, l as ServerLlmBackend, lt as Logger, n as BackgroundAgentManager, o as McpManager, q as setWebSocketToolExecutor, r as SubagentOrchestrator, t as AgentHistoryStore } from "./AgentHistoryStore-DVxv1kSO.mjs";
3
+ import { D as ARTIFACT_REMOVED_PLACEHOLDER, Dt as stripToolArtifactMarkup, E as ARTIFACT_DELIVERED_PLACEHOLDER, Et as stripDeliveredArtifactBlocks, F as ChatModels, G as ModelBackend, I as CompletionReasoningEffortSchema, N as CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS, U as MODEL_INFO_FIELD_GROUP_OF, X as PermissionDeniedError, _ as logger, ct as escapeThinkMarkers, ft as getQuestErrorCode, lt as filterToolArtifactMarkup, mt as hasDeliverablePinnedArtifact, st as createThinkMarkerEscaper, vt as isUserInitiatedAbort } from "./ConfigStore-51UaP9pJ.mjs";
4
4
  import "crypto";
5
5
  import { v4 } from "uuid";
6
6
  import { z as z$1 } from "zod";
@@ -20,6 +20,7 @@ import WebSocket from "ws";
20
20
  * A tool failure that must end the turn rather than be fed back to the model as a
21
21
  * recoverable observation: a declined tool (PermissionDeniedError) or an out-of-credits
22
22
  * error (tagged via `getQuestErrorCode`), neither of which any retry can satisfy.
23
+ * Also exempts these from the services tool failure guard (toolFailureGuard.ts).
23
24
  */
24
25
  function isTerminalToolError(error) {
25
26
  return error instanceof PermissionDeniedError || getQuestErrorCode(error) !== void 0;
@@ -260,6 +261,8 @@ const stripToolDependentMessages = (messages) => messages.filter((message) => !m
260
261
  * WHOLE request with `ValidationException: A maximum of 4 blocks with cache_control may be
261
262
  * provided`, which is non-retryable - so an over-budget request loses the turn outright,
262
263
  * after the user has already waited for it.
264
+ * See https://docs.claude.com/en/docs/build-with-claude/prompt-caching (tools, system and messages
265
+ * all count toward the same four).
263
266
  */
264
267
  const MAX_CACHE_CONTROL_BLOCKS = 4;
265
268
  /**
@@ -278,18 +281,44 @@ function hasMarker(block) {
278
281
  * shareable-prefix breakpoint) - so this adapter's budget is whatever they left, not the full four.
279
282
  */
280
283
  function censusMarkers(params) {
281
- const tools = Array.isArray(params.tools) ? params.tools.filter(hasMarker).length : 0;
282
- const system = Array.isArray(params.system) ? params.system.filter(hasMarker).length : 0;
283
- let messages = 0;
284
- if (Array.isArray(params.messages)) for (const message of params.messages) {
284
+ const { tools, system, messages } = markerSites(params);
285
+ return {
286
+ tools: tools.length,
287
+ system: system.length,
288
+ messages: messages.length,
289
+ total: tools.length + system.length + messages.length
290
+ };
291
+ }
292
+ function markerSites(params) {
293
+ const sitesIn = (region, value) => Array.isArray(value) ? value.flatMap((block, index) => hasMarker(block) ? [{
294
+ region,
295
+ index
296
+ }] : []) : [];
297
+ const messages = [];
298
+ if (Array.isArray(params.messages)) params.messages.forEach((message, messageIndex) => {
285
299
  const content = message?.content;
286
- if (Array.isArray(content)) messages += content.filter(hasMarker).length;
287
- }
300
+ if (!Array.isArray(content)) return;
301
+ content.forEach((block, index) => {
302
+ const inner = block?.content;
303
+ if (Array.isArray(inner)) inner.forEach((innerBlock, nested) => {
304
+ if (hasMarker(innerBlock)) messages.push({
305
+ region: "messages",
306
+ index,
307
+ message: messageIndex,
308
+ nested
309
+ });
310
+ });
311
+ if (hasMarker(block)) messages.push({
312
+ region: "messages",
313
+ index,
314
+ message: messageIndex
315
+ });
316
+ });
317
+ });
288
318
  return {
289
- tools,
290
- system,
291
- messages,
292
- total: tools + system + messages
319
+ tools: sitesIn("tools", params.tools),
320
+ system: sitesIn("system", params.system),
321
+ messages
293
322
  };
294
323
  }
295
324
  /**
@@ -388,14 +417,14 @@ var AnthropicCachingAdapter = class {
388
417
  else console.info(message, JSON.stringify(census));
389
418
  } else if (logger) logger.debug("[PromptCache] cache_control census", census);
390
419
  if (outbound.total > MAX_CACHE_CONTROL_BLOCKS) {
391
- const message = `[PromptCache] request exceeds the ${MAX_CACHE_CONTROL_BLOCKS}-block cache_control limit on arrival (${outbound.total}); the provider will reject it`;
420
+ const message = `[PromptCache] request exceeds the ${MAX_CACHE_CONTROL_BLOCKS}-block cache_control limit on arrival (${outbound.total}); capCacheControlMarkers will strip the excess before send`;
392
421
  const detail = {
393
422
  inbound,
394
423
  outbound,
395
424
  limit: MAX_CACHE_CONTROL_BLOCKS
396
425
  };
397
- if (logger) logger.error(message, detail);
398
- else console.error(message, JSON.stringify(detail));
426
+ if (logger) logger.warn(message, detail);
427
+ else console.warn(message, JSON.stringify(detail));
399
428
  } else if (dropped.length > 0) {
400
429
  const message = `[PromptCache] cache_control budget exhausted (limit ${MAX_CACHE_CONTROL_BLOCKS}); skipped breakpoints: ${dropped.join(", ")}`;
401
430
  const detail = {
@@ -496,6 +525,29 @@ var GeminiCachingAdapter = class {
496
525
  }
497
526
  };
498
527
  /**
528
+ * Cached prompt tokens from a raw provider usage object, across every spelling in use:
529
+ * OpenAI Chat Completions nests them under `prompt_tokens_details`, the OpenAI
530
+ * Responses API under `input_tokens_details`, Moonshot publishes a flat
531
+ * `cached_tokens` alongside the OpenAI-shaped nesting, and DeepSeek its own flat
532
+ * `prompt_cache_hit_tokens`. Reading only one spelling silently bills every cache
533
+ * hit on the other transports at the full input rate.
534
+ *
535
+ * DeepSeek's own spelling leads, because it is the number its invoice is computed
536
+ * from; the OpenAI-shaped ones it also sends are the fallback for a proxy that
537
+ * forwards only those.
538
+ */
539
+ function cachedTokensFromUsage(usage) {
540
+ if (!usage) return 0;
541
+ const candidates = [
542
+ usage.prompt_cache_hit_tokens,
543
+ usage.cached_tokens,
544
+ usage.prompt_tokens_details?.cached_tokens,
545
+ usage.input_tokens_details?.cached_tokens
546
+ ];
547
+ for (const value of candidates) if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
548
+ return 0;
549
+ }
550
+ /**
499
551
  * xAI Grok-specific caching adapter
500
552
  * Caching is automatic with optional conversation ID for cache affinity
501
553
  */
@@ -512,7 +564,7 @@ var XAICachingAdapter = class {
512
564
  const usage = response.usage;
513
565
  if (!usage) return void 0;
514
566
  const totalInputTokens = usage.prompt_tokens || 0;
515
- const cachedTokens = usage.cached_prompt_tokens || 0;
567
+ const cachedTokens = cachedTokensFromUsage(usage);
516
568
  const cacheHitRate = totalInputTokens > 0 ? cachedTokens / totalInputTokens * 100 : 0;
517
569
  const costSavingsPercent = cacheHitRate * .65;
518
570
  const estimatedLatencyReduction = cacheHitRate * .7;
@@ -570,29 +622,6 @@ var KimiCachingAdapter = class {
570
622
  }
571
623
  };
572
624
  /**
573
- * Cached prompt tokens from a raw provider usage object, across every spelling in use:
574
- * OpenAI Chat Completions nests them under `prompt_tokens_details`, the OpenAI
575
- * Responses API under `input_tokens_details`, Moonshot publishes a flat
576
- * `cached_tokens` alongside the OpenAI-shaped nesting, and DeepSeek its own flat
577
- * `prompt_cache_hit_tokens`. Reading only one spelling silently bills every cache
578
- * hit on the other transports at the full input rate.
579
- *
580
- * DeepSeek's own spelling leads, because it is the number its invoice is computed
581
- * from; the OpenAI-shaped ones it also sends are the fallback for a proxy that
582
- * forwards only those.
583
- */
584
- function cachedTokensFromUsage(usage) {
585
- if (!usage) return 0;
586
- const candidates = [
587
- usage.prompt_cache_hit_tokens,
588
- usage.cached_tokens,
589
- usage.prompt_tokens_details?.cached_tokens,
590
- usage.input_tokens_details?.cached_tokens
591
- ];
592
- for (const value of candidates) if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
593
- return 0;
594
- }
595
- /**
596
625
  * DeepSeek context caching. Automatic, like Moonshot's and xAI's: no parameter,
597
626
  * no header, no explicit cache-creation call. The adapter exists only to read
598
627
  * the counters back out.
@@ -634,7 +663,8 @@ var NoOpCachingAdapter = class {
634
663
  extractCacheStats() {}
635
664
  };
636
665
  ModelBackend.Anthropic, new AnthropicCachingAdapter(), ModelBackend.OpenAI, new OpenAICachingAdapter(), ModelBackend.Gemini, new GeminiCachingAdapter(), ModelBackend.Bedrock, new AnthropicCachingAdapter(), ModelBackend.XAI, new XAICachingAdapter(), ModelBackend.Kimi, new KimiCachingAdapter(), ModelBackend.DeepSeek, new DeepSeekCachingAdapter(), ModelBackend.Ollama, new NoOpCachingAdapter(), ModelBackend.BFL, new NoOpCachingAdapter(), ModelBackend.VoyageAI, new NoOpCachingAdapter(), ModelBackend.AWS, new NoOpCachingAdapter(), ModelBackend.LocalImage, new NoOpCachingAdapter();
637
- ChatModels.KIMI_K2_THINKING_BEDROCK, ChatModels.KIMI_K2_5_BEDROCK, ChatModels.DEEPSEEK_R1_BEDROCK, ChatModels.DEEPSEEK_FLASH, ChatModels.DEEPSEEK_V4_PRO;
666
+ ChatModels.KIMI_K2_THINKING_BEDROCK, ChatModels.KIMI_K2_5_BEDROCK, ChatModels.DEEPSEEK_R1_BEDROCK, ChatModels.DEEPSEEK_FLASH, ChatModels.DEEPSEEK_V4_PRO, ChatModels.KIMI_K3;
667
+ ChatModels.CLAUDE_4_7_OPUS, ChatModels.CLAUDE_4_7_OPUS_BEDROCK, ChatModels.CLAUDE_4_8_OPUS, ChatModels.CLAUDE_4_8_OPUS_BEDROCK, ChatModels.CLAUDE_5_SONNET, ChatModels.CLAUDE_5_SONNET_BEDROCK, ChatModels.CLAUDE_5_OPUS, ChatModels.CLAUDE_5_OPUS_BEDROCK, ChatModels.CLAUDE_5_5_HAIKU, ChatModels.CLAUDE_5_5_HAIKU_BEDROCK, ChatModels.CLAUDE_5_5_SONNET_BEDROCK;
638
668
  new Logger();
639
669
  ChatModels.CLAUDE_4_5_SONNET, ChatModels.CLAUDE_4_1_OPUS, ChatModels.CLAUDE_4_5_HAIKU, ChatModels.CLAUDE_4_5_OPUS, ChatModels.CLAUDE_4_6_SONNET, ChatModels.CLAUDE_4_6_OPUS;
640
670
  ChatModels.CLAUDE_4_5_SONNET_BEDROCK, ChatModels.CLAUDE_4_5_HAIKU_BEDROCK, ChatModels.CLAUDE_4_5_OPUS_BEDROCK, ChatModels.CLAUDE_4_6_SONNET_BEDROCK, ChatModels.CLAUDE_4_6_OPUS_BEDROCK;
@@ -1316,9 +1346,10 @@ var OllamaBackend = class OllamaBackend {
1316
1346
  const texts = [];
1317
1347
  const images = [];
1318
1348
  for (const block of msg.content) if (block.type === "text" && typeof block.text === "string") texts.push(block.text);
1319
- else if (block.type === "image") if (block.source.type === "base64") images.push(block.source.data);
1320
- else this._logger.debug("[OllamaBackend] Dropping non-base64 image block; Ollama requires inline base64.");
1321
- else if (block.type === "image_url") {
1349
+ else if (block.type === "image") {
1350
+ if (block.source.type === "base64") images.push(block.source.data);
1351
+ else this._logger.debug("[OllamaBackend] Dropping non-base64 image block; Ollama requires inline base64.");
1352
+ } else if (block.type === "image_url") {
1322
1353
  const dataUrl = block.image_url.url.match(/^data:[^,]*;base64,(.+)$/s);
1323
1354
  if (dataUrl) images.push(dataUrl[1]);
1324
1355
  else this._logger.debug("[OllamaBackend] Dropping non-data image_url; Ollama requires inline base64.");
@@ -1355,6 +1386,7 @@ ModelBackend.Bedrock, ModelBackend.AWS, ModelBackend.OpenAI, ModelBackend.Anthro
1355
1386
  Object.values(ModelBackend);
1356
1387
  Object.entries(MODEL_INFO_FIELD_GROUP_OF);
1357
1388
  ModelBackend.Anthropic, ModelBackend.Gemini, ModelBackend.XAI, ModelBackend.Ollama, ModelBackend.BFL, ModelBackend.LocalImage, ModelBackend.AWS;
1389
+ CompletionReasoningEffortSchema.options;
1358
1390
  ModelBackend.Ollama, ModelBackend.LocalImage;
1359
1391
  //#endregion
1360
1392
  //#region src/llm/NotifyingLlmBackend.ts
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, J as setWebSocketToolExecutor, L as wrapTools, O as createResumeAgentTool, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, b as createGetFileStructureTool, et as CheckpointStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, s as buildSandbox, tt as SessionStore, w as createWriteTodosTool } from "../AgentHistoryStore-DdYKfx7C.mjs";
3
- import { _ as requireApiUrl, d as isReadOnlyTool, n as logger, t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
4
- import { a as deferredToolRegistry, i as createToolSearchTool, n as buildSupportingStores, o as NotifyingLlmBackend, r as buildLlmBackend, t as buildAgent } from "../buildAgent-B7cMwRAy.mjs";
5
- import { t as ApiClient } from "../ApiClient-dIB3YQc2.mjs";
2
+ import { A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, I as buildCliToolList, O as createResumeAgentTool, Q as CustomCommandStore, S as createFindDefinitionTool, T as createSkillTool, Z as RemoteSkillSource, b as createGetFileStructureTool, j as FallbackLlmBackend, k as createBackgroundAgentTools, nt as SessionStore, q as setWebSocketToolExecutor, s as buildSandbox, tt as CheckpointStore, w as createWriteTodosTool } from "../AgentHistoryStore-DVxv1kSO.mjs";
3
+ import { _ as logger, o as isReadOnlyTool, t as ConfigStore, u as requireApiUrl } from "../ConfigStore-51UaP9pJ.mjs";
4
+ import { a as deferredToolRegistry, i as createToolSearchTool, n as buildSupportingStores, o as NotifyingLlmBackend, r as buildLlmBackend, t as buildAgent } from "../buildAgent-CrSRKYU_.mjs";
5
+ import { a as ApiClient } from "../dist-BsG2Hlp-.mjs";
6
6
  import { randomUUID } from "crypto";
7
7
  import { existsSync, realpathSync, statSync } from "fs";
8
8
  import { isAbsolute } from "path";
@@ -604,10 +604,7 @@ var AcpServer = class {
604
604
  checkpointStore
605
605
  });
606
606
  const additionalDirectories = await this.resolveAdditionalDirectories();
607
- const agentContext = {
608
- currentAgent: null,
609
- observationQueue: []
610
- };
607
+ const agentContext = { currentAgent: null };
611
608
  const { agentStore, contextResult, loadedB4mTools, orchestrator, backgroundManager, historyStore, mcpManager } = await buildSupportingStores({
612
609
  config,
613
610
  llm,
@@ -629,6 +626,11 @@ var AcpServer = class {
629
626
  });
630
627
  const llmWithFallback = config.fallbackModels && config.fallbackModels.length > 0 ? new FallbackLlmBackend(llm, config.fallbackModels, (from, to, error) => logger.debug(`[acp] Model "${from}" failed (${error.message}); falling back to "${to}"`)) : llm;
631
628
  const notifyingLlm = new NotifyingLlmBackend(llmWithFallback, backgroundManager);
629
+ const agentToolsRef = { current: null };
630
+ const toolSearchTool = deferredToolRegistry.size() > 0 ? createToolSearchTool(() => {
631
+ if (!agentToolsRef.current) throw new Error("tool_search invoked before agent context was wired");
632
+ return agentToolsRef.current;
633
+ }) : null;
632
634
  const cliTools = this.buildCliTools({
633
635
  config,
634
636
  orchestrator,
@@ -640,18 +642,10 @@ var AcpServer = class {
640
642
  agentContext,
641
643
  apiClient,
642
644
  sandboxOrchestrator: sandboxOrchestrator ?? void 0,
643
- allowedDirectories: additionalDirectories
645
+ allowedDirectories: additionalDirectories,
646
+ toolSearchTool
644
647
  });
645
- const agentToolsRef = { current: null };
646
- const toolSearchTool = deferredToolRegistry.size() > 0 ? createToolSearchTool(() => {
647
- if (!agentToolsRef.current) throw new Error("tool_search invoked before agent context was wired");
648
- return agentToolsRef.current;
649
- }) : null;
650
- const allTools = [
651
- ...loadedB4mTools,
652
- ...toolSearchTool ? [toolSearchTool] : [],
653
- ...cliTools
654
- ];
648
+ const allTools = [...loadedB4mTools, ...cliTools];
655
649
  const { agent, buildPromptForMode } = buildAgent({
656
650
  config,
657
651
  modelId: modelInfo.id,
@@ -684,7 +678,7 @@ var AcpServer = class {
684
678
  };
685
679
  }
686
680
  buildCliTools(input) {
687
- const { config, orchestrator, agentStore, backgroundManager, historyStore, sessionId, permissionManager, agentContext, apiClient, sandboxOrchestrator, allowedDirectories } = input;
681
+ const { config, orchestrator, agentStore, backgroundManager, historyStore, sessionId, permissionManager, agentContext, apiClient, sandboxOrchestrator, allowedDirectories, toolSearchTool } = input;
688
682
  const cliWrapDeps = {
689
683
  permissionManager,
690
684
  showPermissionPrompt: this.promptFn,
@@ -694,10 +688,15 @@ var AcpServer = class {
694
688
  sandboxOrchestrator,
695
689
  allowedDirectories
696
690
  };
697
- const wrappedSecurityTools = wrapTools([
698
- createFindDefinitionTool(allowedDirectories),
699
- createGetFileStructureTool(allowedDirectories),
700
- ...config.preferences.enableSkillTool !== false ? [createSkillTool({
691
+ return buildCliToolList({
692
+ toolSearchTool,
693
+ agentDelegateTool: createAgentDelegateTool(orchestrator, agentStore, sessionId, backgroundManager),
694
+ backgroundTools: createBackgroundAgentTools(backgroundManager),
695
+ resumeAgentTool: createResumeAgentTool(orchestrator, historyStore, backgroundManager),
696
+ writeTodosTool: createWriteTodosTool(createTodoStore()),
697
+ findDefinitionTool: createFindDefinitionTool(allowedDirectories),
698
+ getFileStructureTool: createGetFileStructureTool(allowedDirectories),
699
+ skillTool: config.preferences.enableSkillTool !== false ? createSkillTool({
701
700
  customCommandStore: this.customCommandStore,
702
701
  subagentOrchestrator: orchestrator,
703
702
  sessionId,
@@ -706,17 +705,9 @@ var AcpServer = class {
706
705
  promptFn: this.promptFn
707
706
  },
708
707
  allowedDirectories
709
- })] : []
710
- ], cliWrapDeps);
711
- const tools = [
712
- createAgentDelegateTool(orchestrator, agentStore, sessionId, backgroundManager),
713
- ...createBackgroundAgentTools(backgroundManager),
714
- createResumeAgentTool(orchestrator, historyStore, backgroundManager),
715
- createWriteTodosTool(createTodoStore()),
716
- ...wrappedSecurityTools
717
- ];
718
- if (config.preferences.enableCoordinatorMode === true) tools.push(createCoordinateTaskTool(orchestrator, agentStore, sessionId));
719
- return tools;
708
+ }) : null,
709
+ coordinateTaskTool: config.preferences.enableCoordinatorMode === true ? createCoordinateTaskTool(orchestrator, agentStore, sessionId) : null
710
+ }, cliWrapDeps);
720
711
  }
721
712
  async loadCustomCommands() {
722
713
  this.customCommandStore.setProjectTrusted(this.configStore.isProjectTrusted());
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { g as parseApiUrl, t as ConfigStore, v as resolveApiEndpoint } from "../ConfigStore-BygzEI6H.mjs";
2
+ import { d as resolveApiEndpoint, g as parseApiUrl, t as ConfigStore } from "../ConfigStore-51UaP9pJ.mjs";
3
3
  //#region src/commands/apiCommand.ts
4
4
  /**
5
5
  * External API config command (--api-url / --reset-api)
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { t as version } from "../package-CRNnNXxq.mjs";
3
- import { a as fetchLatestVersion, c as isNpmPrefixWritable, i as compareSemver } from "../updateChecker-CQW8bxo6.mjs";
2
+ import { t as version } from "../package-DEsNSP54.mjs";
3
+ import { c as isNpmPrefixWritable, i as fetchLatestVersion, r as compareSemver } from "../updateChecker-CCLVVdH0.mjs";
4
4
  import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
5
- import { execSync } from "child_process";
6
5
  import { existsSync } from "fs";
7
6
  import { homedir } from "os";
8
7
  import path from "path";
8
+ import { execSync } from "child_process";
9
9
  //#region src/commands/doctorCommand.ts
10
10
  /**
11
11
  * External doctor command (b4m doctor)
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-51UaP9pJ.mjs";
3
3
  //#region src/commands/envCommand.ts
4
4
  /**
5
5
  * Environment switching for the `--dev` / `--prod` launch flags.
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, G as classifyCommandRisk, I as generateCliTools, J as setWebSocketToolExecutor, L as wrapTools, N as ReActAgent, O as createResumeAgentTool, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, X as buildSystemPrompt, a as loadProjectContext, b as createGetFileStructureTool, c as createSseBackend, et as CheckpointStore, i as buildProjectAgentStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, n as BackgroundAgentManager, o as McpManager, r as SubagentOrchestrator, s as buildSandbox, t as AgentHistoryStore, tt as SessionStore, w as createWriteTodosTool, x as createWorkItemTools, z as SHELL_LIKE_TOOL_COMMAND_FIELDS } from "../AgentHistoryStore-DdYKfx7C.mjs";
3
- import { _ as requireApiUrl, d as isReadOnlyTool, n as logger, t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
4
- import { r as reconstructTurnBlocks, t as WorkItemsClient } from "../WorkItemsClient-ClBC49y0.mjs";
5
- import { t as ApiClient } from "../ApiClient-dIB3YQc2.mjs";
2
+ import { A as createAgentDelegateTool, B as SHELL_LIKE_TOOL_COMMAND_FIELDS, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, I as buildCliToolList, K as classifyCommandRisk, L as generateCliTools, N as ReActAgent, O as createResumeAgentTool, Q as CustomCommandStore, R as wrapTools, S as createFindDefinitionTool, T as createSkillTool, Y as buildSystemPrompt, Z as RemoteSkillSource, a as loadProjectContext, b as createGetFileStructureTool, c as createSseBackend, i as buildProjectAgentStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, n as BackgroundAgentManager, nt as SessionStore, o as McpManager, q as setWebSocketToolExecutor, r as SubagentOrchestrator, s as buildSandbox, t as AgentHistoryStore, tt as CheckpointStore, w as createWriteTodosTool, x as createWorkItemTools } from "../AgentHistoryStore-DVxv1kSO.mjs";
3
+ import { _ as logger, o as isReadOnlyTool, t as ConfigStore, u as requireApiUrl } from "../ConfigStore-51UaP9pJ.mjs";
4
+ import { r as reconstructTurnBlocks, t as WorkItemsClient } from "../WorkItemsClient-BMY0Qq1s.mjs";
5
+ import { a as ApiClient } from "../dist-BsG2Hlp-.mjs";
6
6
  import { randomBytes } from "crypto";
7
7
  import { v4 } from "uuid";
8
8
  import { readFile } from "fs/promises";
@@ -360,10 +360,7 @@ async function handleHeadlessCommand(options) {
360
360
  checkpointStore,
361
361
  log: headlessSandboxLog
362
362
  });
363
- const agentContext = {
364
- currentAgent: null,
365
- observationQueue: []
366
- };
363
+ const agentContext = { currentAgent: null };
367
364
  const { tools: b4mTools } = await generateCliTools(config.userId, llm, modelInfo.id, permissionManager, promptFn, agentContext, configStore, apiClient, void 0, userQuestionFn, checkpointStore, sandboxOrchestrator, additionalDirectories);
368
365
  const mcpManager = new McpManager(config);
369
366
  const builtinAgentsDir = new URL("../agents/defaults/", import.meta.url).pathname;
@@ -407,11 +404,9 @@ async function handleHeadlessCommand(options) {
407
404
  const resumeAgentTool = createResumeAgentTool(orchestrator, historyStore, backgroundManager);
408
405
  const todoStore = createTodoStore();
409
406
  const writeTodosTool = createWriteTodosTool(todoStore);
410
- const findDefinitionTool = wrapTools([createFindDefinitionTool(additionalDirectories)], cliWrapDeps)[0];
411
- const getFileStructureTool = wrapTools([createGetFileStructureTool(additionalDirectories)], cliWrapDeps)[0];
412
407
  const workItemTools = config.preferences.enableWorkItemTools ? createWorkItemTools(new WorkItemsClient(apiClient)) : [];
413
408
  const enableSkillTool = config.preferences.enableSkillTool !== false;
414
- const skillTool = enableSkillTool ? wrapTools([createSkillTool({
409
+ const skillTool = enableSkillTool ? createSkillTool({
415
410
  customCommandStore,
416
411
  subagentOrchestrator: orchestrator,
417
412
  sessionId: session.id,
@@ -420,21 +415,18 @@ async function handleHeadlessCommand(options) {
420
415
  promptFn
421
416
  },
422
417
  allowedDirectories: additionalDirectories
423
- })], cliWrapDeps)[0] : null;
424
- const cliTools = [
418
+ }) : null;
419
+ const cliTools = buildCliToolList({
425
420
  agentDelegateTool,
426
- ...backgroundTools,
421
+ backgroundTools,
427
422
  resumeAgentTool,
428
423
  writeTodosTool,
429
- findDefinitionTool,
430
- getFileStructureTool,
431
- ...workItemTools
432
- ];
433
- if (skillTool) cliTools.push(skillTool);
434
- if (config.preferences.enableCoordinatorMode === true) {
435
- const coordinateTaskTool = createCoordinateTaskTool(orchestrator, agentStore, session.id);
436
- cliTools.push(coordinateTaskTool);
437
- }
424
+ findDefinitionTool: createFindDefinitionTool(additionalDirectories),
425
+ getFileStructureTool: createGetFileStructureTool(additionalDirectories),
426
+ workItemTools,
427
+ skillTool,
428
+ coordinateTaskTool: config.preferences.enableCoordinatorMode === true ? createCoordinateTaskTool(orchestrator, agentStore, session.id) : null
429
+ }, cliWrapDeps);
438
430
  const allTools = [
439
431
  ...b4mTools,
440
432
  ...mcpTools,
@@ -461,7 +453,6 @@ async function handleHeadlessCommand(options) {
461
453
  systemPrompt
462
454
  });
463
455
  agentContext.currentAgent = agent;
464
- agent.observationQueue = agentContext.observationQueue;
465
456
  if (streaming) {
466
457
  agent.on("thought", (step) => {
467
458
  emit({
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
3
- import { t as version } from "../package-CRNnNXxq.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-51UaP9pJ.mjs";
3
+ import { t as version } from "../package-DEsNSP54.mjs";
4
4
  //#region src/commands/mcpCommand.ts
5
5
  /**
6
6
  * External MCP commands (b4m mcp list, b4m mcp add, etc.)
@@ -70,7 +70,7 @@ async function handleMcpCommand(subcommand, argv) {
70
70
  await handleDisable(config, argv.name, configStore);
71
71
  break;
72
72
  case "serve": {
73
- const { handleMcpServeCommand } = await import("../serve-DM7ld3-o.mjs");
73
+ const { handleMcpServeCommand } = await import("../serve-BaHzVbcm.mjs");
74
74
  await handleMcpServeCommand({
75
75
  http: Boolean(argv.http),
76
76
  port: typeof argv.port === "number" ? argv.port : void 0,
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ import { t as ConfigStore } from "../ConfigStore-51UaP9pJ.mjs";
2
3
  import { n as getDefaultPluginsDir, r as isFeatureEnabled, t as PluginStore } from "../PluginStore-DwvOJ-G3.mjs";
3
- import { t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
4
- import { execFileSync } from "child_process";
5
4
  import { promises } from "fs";
6
5
  import path from "path";
6
+ import { execFileSync } from "child_process";
7
7
  //#region src/commands/pluginCommand.ts
8
8
  /**
9
9
  * External plugin commands (b4m plugin list, b4m plugin add, b4m plugin remove).
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { t as version } from "../package-CRNnNXxq.mjs";
3
- import { c as isNpmPrefixWritable, l as setAutoUpdatePreference, n as REEXEC_GUARD_ENV, o as forceCheckForUpdate, r as checkForUpdate, s as getAutoUpdatePreference, t as INSTALL_CMD, u as shouldAttemptAutoUpdate } from "../updateChecker-CQW8bxo6.mjs";
2
+ import { t as version } from "../package-DEsNSP54.mjs";
3
+ import { a as forceCheckForUpdate, c as isNpmPrefixWritable, d as shouldAttemptAutoUpdate, l as readCachedUpdate, n as REEXEC_GUARD_ENV, o as getAutoUpdatePreference, t as INSTALL_CMD, u as setAutoUpdatePreference } from "../updateChecker-CCLVVdH0.mjs";
4
4
  import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
5
5
  import { execSync, spawnSync } from "child_process";
6
6
  import { createInterface } from "readline";
@@ -106,8 +106,8 @@ function installAndReexec(currentVersion, latestVersion) {
106
106
  * Skip (ask again next launch) / Never (persist `never`).
107
107
  *
108
108
  * It is a safe no-op (returns without installing) when: already re-exec'd this
109
- * launch, disabled via `B4M_AUTO_UPDATE=0`, not attached to a TTY, no update is
110
- * available, the prefix needs sudo (notify banner informs instead), or the
109
+ * launch, disabled via `B4M_AUTO_UPDATE=0`, not attached to a TTY, the last
110
+ * cached check found no update, the prefix needs sudo (notify banner informs instead), or the
111
111
  * user declines the prompt. Any install/network failure is swallowed so the
112
112
  * user is never blocked from launching the current version.
113
113
  */
@@ -117,17 +117,7 @@ async function maybeAutoUpdateOnLaunch() {
117
117
  const preference = await getAutoUpdatePreference();
118
118
  if (preference === "never") return;
119
119
  const currentVersion = version;
120
- let result;
121
- let timeoutHandle;
122
- try {
123
- result = await Promise.race([checkForUpdate(currentVersion), new Promise((resolve) => {
124
- timeoutHandle = setTimeout(() => resolve(null), 3e3);
125
- })]);
126
- } catch {
127
- return;
128
- } finally {
129
- if (timeoutHandle) clearTimeout(timeoutHandle);
130
- }
120
+ const result = await readCachedUpdate(currentVersion);
131
121
  if (!result?.updateAvailable) return;
132
122
  if (!await isNpmPrefixWritable()) return;
133
123
  if (preference === "ask") {