@bike4mind/cli 3.2.0 → 3.3.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 { Mt as tokenEstimateMultiplier } from "./ConfigStore-v0wgf0_j.mjs";
2
+ import { Pt as tokenEstimateMultiplier } from "./ConfigStore-DUATzLxB.mjs";
3
3
  import { v4 } from "uuid";
4
4
  import { get_encoding } from "tiktoken";
5
5
  //#region ../../b4m-core/utils/dist/calibratedTokenizer.mjs
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { F as generateCliTools, G as setWebSocketToolExecutor, J as DeferredToolRegistry, U as wrapTools, V as buildSystemPrompt, Y as ReActAgent, a as loadProjectContext, c as createSseBackend, i as buildProjectAgentStore, l as ServerLlmBackend, n as BackgroundAgentManager, o as McpManager, q as getPlanModeFilePath, r as SubagentOrchestrator, t as AgentHistoryStore, ut as Logger } from "./AgentHistoryStore-BWko6txx.mjs";
3
- import { $ as PermissionDeniedError, At as stripToolArtifactMarkup, F as CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS, J as ModelBackend, K as MODEL_INFO_FIELD_GROUP_OF, L as ChatModels, O as ARTIFACT_DELIVERED_PLACEHOLDER, R as CompletionReasoningEffortSchema, _t as hasDeliverablePinnedArtifact, dt as escapeThinkMarkers, ft as filterToolArtifactMarkup, ht as getQuestErrorCode, k as ARTIFACT_REMOVED_PLACEHOLDER, kt as stripDeliveredArtifactBlocks, ut as createThinkMarkerEscaper, xt as isUserInitiatedAbort, y as logger } from "./ConfigStore-v0wgf0_j.mjs";
2
+ import { F as generateCliTools, G as setWebSocketToolExecutor, J as DeferredToolRegistry, U as wrapTools, V as buildSystemPrompt, Y as ReActAgent, a as loadProjectContext, c as createSseBackend, i as buildProjectAgentStore, l as ServerLlmBackend, n as BackgroundAgentManager, o as McpManager, q as getPlanModeFilePath, r as SubagentOrchestrator, t as AgentHistoryStore, ut as Logger } from "./AgentHistoryStore-CLidbOHG.mjs";
3
+ import { A as ARTIFACT_REMOVED_PLACEHOLDER, Ct as isUserInitiatedAbort, I as CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS, Mt as stripToolArtifactMarkup, R as ChatModels, Y as ModelBackend, _t as getQuestErrorCode, b as logger, et as PermissionDeniedError, ft as createThinkMarkerEscaper, jt as stripDeliveredArtifactBlocks, k as ARTIFACT_DELIVERED_PLACEHOLDER, mt as filterToolArtifactMarkup, pt as escapeThinkMarkers, q as MODEL_INFO_FIELD_GROUP_OF, yt as hasDeliverablePinnedArtifact, z as CompletionReasoningEffortSchema } from "./ConfigStore-DUATzLxB.mjs";
4
4
  import "crypto";
5
5
  import { v4 } from "uuid";
6
6
  import "axios";
@@ -366,7 +366,8 @@ var AnthropicCachingAdapter = class {
366
366
  const messagesParam = modifiedParams.messages;
367
367
  if (strategy.cacheConversationHistory && Array.isArray(messagesParam) && messagesParam.length > 0) {
368
368
  const messages = [...messagesParam];
369
- const anchorIndex = messages.length - 1 - (strategy.historyCacheExcludeTrailingCount ?? 0);
369
+ let anchorIndex = messages.length - 1 - (strategy.historyCacheExcludeTrailingCount ?? 0);
370
+ while (anchorIndex >= 0 && messages[anchorIndex].role === "system") anchorIndex--;
370
371
  if (anchorIndex >= 0) {
371
372
  const anchorMsg = messages[anchorIndex];
372
373
  const msgContent = anchorMsg.content;
@@ -669,6 +670,7 @@ var NoOpCachingAdapter = class {
669
670
  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();
670
671
  ChatModels.KIMI_K2_THINKING_BEDROCK, ChatModels.KIMI_K2_5_BEDROCK, ChatModels.DEEPSEEK_R1_BEDROCK, ChatModels.DEEPSEEK_FLASH, ChatModels.DEEPSEEK_V4_PRO, ChatModels.KIMI_K3;
671
672
  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;
673
+ ChatModels.CLAUDE_5_SONNET, ChatModels.CLAUDE_5_SONNET_BEDROCK, ChatModels.CLAUDE_5_5_SONNET_BEDROCK, ChatModels.CLAUDE_FABLE_5, ChatModels.CLAUDE_FABLE_5_BEDROCK, ChatModels.CLAUDE_FABLE_5_1_BEDROCK, ChatModels.CLAUDE_5_OPUS, ChatModels.CLAUDE_5_OPUS_BEDROCK, ChatModels.CLAUDE_5_5_OPUS, ChatModels.CLAUDE_5_5_OPUS_BEDROCK, ChatModels.CLAUDE_5_5_HAIKU, ChatModels.CLAUDE_5_5_HAIKU_BEDROCK;
672
674
  new Logger();
673
675
  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;
674
676
  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;
@@ -757,6 +759,19 @@ ChatModels.KIMI_K2_7_CODE, ChatModels.KIMI_K2_7_CODE_HIGHSPEED, ChatModels.KIMI_
757
759
  ChatModels.KIMI_K2_7_CODE, ChatModels.KIMI_K2_7_CODE_HIGHSPEED;
758
760
  ChatModels.KIMI_K2_7_CODE, ChatModels.KIMI_K2_7_CODE_HIGHSPEED, ChatModels.KIMI_K2_6;
759
761
  ChatModels.KIMI_K3, ChatModels.KIMI_K2_7_CODE, ChatModels.KIMI_K2_7_CODE_HIGHSPEED, ChatModels.KIMI_K2_6, ChatModels.KIMI_K2_5;
762
+ /**
763
+ * Ollama's native /api/chat requires tool-call arguments as an object and rejects a JSON string
764
+ * with a 400. Unparseable or non-object input is kept under `_raw` rather than dropped.
765
+ */
766
+ function toOllamaToolArguments(args) {
767
+ if (args !== null && typeof args === "object" && !Array.isArray(args)) return args;
768
+ if (typeof args !== "string" || args.trim() === "") return {};
769
+ try {
770
+ const parsed = JSON.parse(args);
771
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
772
+ } catch {}
773
+ return { _raw: args };
774
+ }
760
775
  var OllamaBackend = class OllamaBackend {
761
776
  _host;
762
777
  _api;
@@ -1298,18 +1313,12 @@ var OllamaBackend = class OllamaBackend {
1298
1313
  };
1299
1314
  }
1300
1315
  pushToolMessages(messages, tool, result, _thinkingBlocks) {
1301
- let argumentsObj;
1302
- try {
1303
- argumentsObj = JSON.parse(tool.parameters);
1304
- } catch {
1305
- argumentsObj = { _raw: tool.parameters };
1306
- }
1307
1316
  messages.push({
1308
1317
  content: "",
1309
1318
  role: "assistant",
1310
1319
  tool_calls: [{ function: {
1311
1320
  name: tool.name,
1312
- arguments: argumentsObj
1321
+ arguments: toOllamaToolArguments(tool.parameters)
1313
1322
  } }]
1314
1323
  });
1315
1324
  messages.push({
@@ -1361,7 +1370,13 @@ var OllamaBackend = class OllamaBackend {
1361
1370
  mapped.content = texts.join("\n");
1362
1371
  if (images.length > 0) mapped.images = images;
1363
1372
  } else mapped.content = msg.content != null ? String(msg.content) : "";
1364
- if (Array.isArray(raw.tool_calls)) mapped.tool_calls = raw.tool_calls;
1373
+ if (Array.isArray(raw.tool_calls)) mapped.tool_calls = raw.tool_calls.map((call) => ({
1374
+ ...call,
1375
+ function: {
1376
+ ...call.function,
1377
+ arguments: toOllamaToolArguments(call.function?.arguments)
1378
+ }
1379
+ }));
1365
1380
  if (typeof raw.tool_name === "string") mapped.tool_name = raw.tool_name;
1366
1381
  return mapped;
1367
1382
  });
@@ -1383,7 +1398,7 @@ ChatModels.O1_PREVIEW, ChatModels.O1_MINI, ChatModels.O1, ChatModels.O3_MINI, Ch
1383
1398
  ChatModels.GPT5, ChatModels.GPT5_MINI, ChatModels.GPT5_NANO, ChatModels.GPT5_CHAT_LATEST;
1384
1399
  ChatModels.GPT5_1, ChatModels.GPT5_1_CHAT_LATEST;
1385
1400
  ChatModels.GPT5_2, ChatModels.GPT5_2_CHAT_LATEST;
1386
- ChatModels.GPT5_4, ChatModels.GPT5_4_MINI, ChatModels.GPT5_4_NANO;
1401
+ ChatModels.GPT5_4, ChatModels.GPT5_4_MINI, ChatModels.GPT5_4_MINI_2026_03_17, ChatModels.GPT5_4_NANO;
1387
1402
  ChatModels.GPT5_5;
1388
1403
  ChatModels.GPT5_6_SOL, ChatModels.GPT5_6_LUNA, ChatModels.GPT5_6_TERRA;
1389
1404
  ModelBackend.Bedrock, ModelBackend.AWS, ModelBackend.OpenAI, ModelBackend.Anthropic, ModelBackend.Gemini, ModelBackend.Ollama, ModelBackend.BFL, ModelBackend.XAI, ModelBackend.Kimi, ModelBackend.DeepSeek, ModelBackend.LocalImage, ModelBackend.VoyageAI;
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, G as setWebSocketToolExecutor, N as PermissionManager, O as createResumeAgentTool, P as buildCliToolList, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, X as createToolSearchTool, b as createGetFileStructureTool, j as FallbackLlmBackend, k as createBackgroundAgentTools, nt as CheckpointStore, rt as SessionStore, s as buildSandbox, w as createWriteTodosTool } from "../AgentHistoryStore-BWko6txx.mjs";
3
- import { f as requireApiUrl, i as ToolCatalog, t as ConfigStore, y as logger } from "../ConfigStore-v0wgf0_j.mjs";
4
- import { a as NotifyingLlmBackend, i as deferredToolRegistry, n as buildSupportingStores, r as buildLlmBackend, t as buildAgent } from "../buildAgent-BZnmDQIr.mjs";
5
- import { a as ApiClient } from "../dist-5DDaX8tB.mjs";
2
+ import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, G as setWebSocketToolExecutor, N as PermissionManager, O as createResumeAgentTool, P as buildCliToolList, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, X as createToolSearchTool, b as createGetFileStructureTool, j as FallbackLlmBackend, k as createBackgroundAgentTools, nt as CheckpointStore, rt as SessionStore, s as buildSandbox, w as createWriteTodosTool } from "../AgentHistoryStore-CLidbOHG.mjs";
3
+ import { b as logger, i as ToolCatalog, p as requireApiUrl, t as ConfigStore } from "../ConfigStore-DUATzLxB.mjs";
4
+ import { a as NotifyingLlmBackend, i as deferredToolRegistry, n as buildSupportingStores, r as buildLlmBackend, t as buildAgent } from "../buildAgent-DyZWK0LW.mjs";
5
+ import { a as ApiClient } from "../dist-DPP7UmK9.mjs";
6
6
  import { randomUUID } from "crypto";
7
7
  import { existsSync, realpathSync, statSync } from "fs";
8
8
  import { isAbsolute } from "path";
@@ -92,18 +92,19 @@ function truncate(text, max) {
92
92
  const PERMISSION_OPTION_ALLOW_ONCE = "allow-once";
93
93
  const PERMISSION_OPTION_ALLOW_ALWAYS = "allow-always";
94
94
  const PERMISSION_OPTION_REJECT = "deny";
95
- function buildPermissionOptions() {
95
+ function buildPermissionOptions(options = {}) {
96
+ const { allowAlways = true } = options;
96
97
  return [
97
98
  {
98
99
  optionId: PERMISSION_OPTION_ALLOW_ONCE,
99
100
  name: "Allow once",
100
101
  kind: "allow_once"
101
102
  },
102
- {
103
+ ...allowAlways ? [{
103
104
  optionId: PERMISSION_OPTION_ALLOW_ALWAYS,
104
105
  name: "Always allow",
105
106
  kind: "allow_always"
106
- },
107
+ }] : [],
107
108
  {
108
109
  optionId: PERMISSION_OPTION_REJECT,
109
110
  name: "Reject",
@@ -271,12 +272,13 @@ var AcpServer = class {
271
272
  this.stackPromise = null;
272
273
  this.stack = null;
273
274
  this.activeTurn = null;
274
- this.promptFn = async (toolName, args, preview) => {
275
+ this.promptFn = async (toolName, args, preview, kind) => {
276
+ const isSandboxEscalation = kind === "sandbox-escalation";
275
277
  const turn = this.activeTurn;
276
278
  if (!turn) return { action: "deny" };
277
279
  const toolCall = {
278
280
  toolCallId: `perm-${randomUUID()}`,
279
- title: toolCallTitle(toolName, args),
281
+ title: `${isSandboxEscalation ? "Run outside sandbox: " : ""}${toolCallTitle(toolName, args)}`,
280
282
  kind: toolKind(toolName),
281
283
  status: "pending",
282
284
  rawInput: args,
@@ -294,13 +296,15 @@ var AcpServer = class {
294
296
  turn.signal.addEventListener("abort", onClose);
295
297
  this.connectionSignal.addEventListener("abort", onClose);
296
298
  try {
297
- return { action: await Promise.race([turn.client.request(methods.client.session.requestPermission, {
299
+ const action = await Promise.race([turn.client.request(methods.client.session.requestPermission, {
298
300
  sessionId: turn.sessionId,
299
301
  toolCall,
300
- options: buildPermissionOptions()
302
+ options: buildPermissionOptions({ allowAlways: !isSandboxEscalation })
301
303
  }, { cancellationSignal: decisionController.signal }).then((res) => permissionResponseFromOutcome(res?.outcome)).catch(() => "deny"), new Promise((resolve) => {
302
304
  decisionController.signal.addEventListener("abort", () => resolve("deny"), { once: true });
303
- })]) };
305
+ })]);
306
+ if (isSandboxEscalation && action === "allow-always") return { action: "deny" };
307
+ return { action };
304
308
  } finally {
305
309
  clearTimeout(timer);
306
310
  turn.signal.removeEventListener("abort", onClose);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { p as resolveApiEndpoint, t as ConfigStore, v as parseApiUrl } from "../ConfigStore-v0wgf0_j.mjs";
2
+ import { m as resolveApiEndpoint, t as ConfigStore, y as parseApiUrl } from "../ConfigStore-DUATzLxB.mjs";
3
3
  //#region src/commands/apiCommand.ts
4
4
  /**
5
5
  * External API config command (--api-url / --reset-api)
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as version } from "../package-COr17yKT.mjs";
2
+ import { t as version } from "../package-DYPVrada.mjs";
3
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
5
  import { existsSync } from "fs";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-v0wgf0_j.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-DUATzLxB.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 generateCliTools, G as setWebSocketToolExecutor, K as classifyCommandRisk, N as PermissionManager, O as createResumeAgentTool, P as buildCliToolList, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, U as wrapTools, V as buildSystemPrompt, Y as ReActAgent, a as loadProjectContext, b as createGetFileStructureTool, c as createSseBackend, i as buildProjectAgentStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, n as BackgroundAgentManager, nt as CheckpointStore, o as McpManager, r as SubagentOrchestrator, rt as SessionStore, s as buildSandbox, t as AgentHistoryStore, w as createWriteTodosTool, x as createWorkItemTools } from "../AgentHistoryStore-BWko6txx.mjs";
3
- import { a as commandTextOf, f as requireApiUrl, i as ToolCatalog, s as toolCategory, t as ConfigStore, y as logger } from "../ConfigStore-v0wgf0_j.mjs";
4
- import { r as reconstructTurnBlocks, t as WorkItemsClient } from "../WorkItemsClient-BZL44N12.mjs";
5
- import { a as ApiClient } from "../dist-5DDaX8tB.mjs";
2
+ import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as generateCliTools, G as setWebSocketToolExecutor, K as classifyCommandRisk, N as PermissionManager, O as createResumeAgentTool, P as buildCliToolList, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, U as wrapTools, V as buildSystemPrompt, Y as ReActAgent, a as loadProjectContext, b as createGetFileStructureTool, c as createSseBackend, i as buildProjectAgentStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, n as BackgroundAgentManager, nt as CheckpointStore, o as McpManager, r as SubagentOrchestrator, rt as SessionStore, s as buildSandbox, t as AgentHistoryStore, w as createWriteTodosTool, x as createWorkItemTools } from "../AgentHistoryStore-CLidbOHG.mjs";
3
+ import { a as commandTextOf, b as logger, c as toolCategory, i as ToolCatalog, p as requireApiUrl, t as ConfigStore } from "../ConfigStore-DUATzLxB.mjs";
4
+ import { r as reconstructTurnBlocks, t as WorkItemsClient } from "../WorkItemsClient-BSoOblGp.mjs";
5
+ import { a as ApiClient } from "../dist-DPP7UmK9.mjs";
6
6
  import { randomBytes } from "crypto";
7
7
  import { v4 } from "uuid";
8
8
  import { readFile } from "fs/promises";
@@ -24,7 +24,7 @@ import { readFile } from "fs/promises";
24
24
  * field or a new event type (backward-compatible). Consumers should reject a
25
25
  * MAJOR they do not understand.
26
26
  */
27
- const HEADLESS_SCHEMA_VERSION = "1.0.0";
27
+ const HEADLESS_SCHEMA_VERSION = "1.1.0";
28
28
  /** Serialize an event with the protocol envelope stamped on. Exposed for tests. */
29
29
  function stampEvent(runId, event) {
30
30
  return {
@@ -172,9 +172,21 @@ function evaluatePermissionPolicy(policy, toolName, riskLevel) {
172
172
  reason: `policy default (${policy.defaultAction})`
173
173
  };
174
174
  }
175
+ /** The permission_request event for a gated tool call; `kind` tells a consumer what is being asked. */
176
+ function buildPermissionRequestEvent(toolName, risk, kind = "tool") {
177
+ return {
178
+ type: "permission_request",
179
+ toolName,
180
+ risk,
181
+ kind
182
+ };
183
+ }
175
184
  /**
176
185
  * Resolve a headless permission decision from the fixed precedence ladder:
177
186
  * --dangerously-skip-permissions -> allow-once (explicit blanket override)
187
+ * a sandbox-escalation request -> deny (running outside the OS sandbox is its own
188
+ * decision; no policy allow-list or risk threshold
189
+ * approves it)
178
190
  * a directory-grant request -> deny (widening the filesystem allow-list is
179
191
  * its own decision; headless has no human to
180
192
  * grant it, so fail closed - never inherit the
@@ -184,11 +196,15 @@ function evaluatePermissionPolicy(policy, toolName, riskLevel) {
184
196
  * Extracted from the headless prompt closure so the ladder is unit-testable.
185
197
  */
186
198
  function resolveHeadlessPermissionDecision(params) {
187
- const { dangerouslySkipPermissions, isDirectoryGrant, toolName, riskLevel, permissionPolicy } = params;
199
+ const { dangerouslySkipPermissions, isDirectoryGrant, isSandboxEscalation, toolName, riskLevel, permissionPolicy } = params;
188
200
  if (dangerouslySkipPermissions) return {
189
201
  action: "allow-once",
190
202
  reason: "dangerously-skip-permissions"
191
203
  };
204
+ if (isSandboxEscalation) return {
205
+ action: "deny",
206
+ reason: "running outside the sandbox not approved in headless mode"
207
+ };
192
208
  if (isDirectoryGrant) return {
193
209
  action: "deny",
194
210
  reason: "directory access not granted in headless mode"
@@ -206,6 +222,39 @@ function resolveHeadlessPermissionDecision(params) {
206
222
  };
207
223
  }
208
224
  //#endregion
225
+ //#region src/commands/headlessPermissionPrompt.ts
226
+ /**
227
+ * The headless permission prompt. Every gated tool surfaces a structured permission_request +
228
+ * permission_decision pair on the stream (so decisions are never silent), then resolves the
229
+ * decision from resolveHeadlessPermissionDecision's precedence ladder.
230
+ */
231
+ function createHeadlessPromptFn(deps) {
232
+ const { catalog, dangerouslySkipPermissions, permissionPolicy, emit, warn } = deps;
233
+ return (toolName, args, _preview, kind) => {
234
+ const risk = classifyToolRisk(catalog.resolve(toolName), args);
235
+ emit?.(buildPermissionRequestEvent(toolName, risk, kind));
236
+ const decision = resolveHeadlessPermissionDecision({
237
+ dangerouslySkipPermissions,
238
+ isDirectoryGrant: kind === "directory-grant",
239
+ isSandboxEscalation: kind === "sandbox-escalation",
240
+ toolName,
241
+ riskLevel: risk.level,
242
+ permissionPolicy
243
+ });
244
+ if (emit) emit({
245
+ type: "permission_decision",
246
+ toolName,
247
+ action: decision.action,
248
+ reason: decision.reason,
249
+ risk: risk.level,
250
+ kind: kind ?? "tool"
251
+ });
252
+ else if (decision.action === "deny") warn(kind === "sandbox-escalation" ? `Warning: Tool "${toolName}" was denied by the OS sandbox, and retrying it outside the sandbox needs approval that headless mode cannot grant. Use --dangerously-skip-permissions to allow it.\n` : `Warning: Tool "${toolName}" requires permission and was denied (${decision.reason}). Grant it via --permission-policy, or --dangerously-skip-permissions to allow all tools.\n`);
253
+ if (decision.action === "allow-once") logger.debug(`[headless] Auto-allowing tool: ${toolName}`);
254
+ return Promise.resolve({ action: decision.action });
255
+ };
256
+ }
257
+ //#endregion
209
258
  //#region src/commands/headlessCommand.ts
210
259
  /**
211
260
  * Headless/programmatic mode command (b4m -p "query")
@@ -323,31 +372,13 @@ async function handleHeadlessCommand(options) {
323
372
  const permissionManager = new PermissionManager(new ToolCatalog(), config.trustedTools ?? [], config.tools.disabled);
324
373
  const emit = createHeadlessEmitter(runId, (line) => process.stdout.write(line));
325
374
  const streaming = outputFormat === "stream-json";
326
- const promptFn = (toolName, args, _preview, kind) => {
327
- const risk = classifyToolRisk(permissionManager.catalog.resolve(toolName), args);
328
- if (streaming) emit({
329
- type: "permission_request",
330
- toolName,
331
- risk
332
- });
333
- const decision = resolveHeadlessPermissionDecision({
334
- dangerouslySkipPermissions,
335
- isDirectoryGrant: kind === "directory-grant",
336
- toolName,
337
- riskLevel: risk.level,
338
- permissionPolicy
339
- });
340
- if (streaming) emit({
341
- type: "permission_decision",
342
- toolName,
343
- action: decision.action,
344
- reason: decision.reason,
345
- risk: risk.level
346
- });
347
- else if (decision.action === "deny") process.stderr.write(`Warning: Tool "${toolName}" requires permission and was denied (${decision.reason}). Grant it via --permission-policy, or --dangerously-skip-permissions to allow all tools.\n`);
348
- if (decision.action === "allow-once") logger.debug(`[headless] Auto-allowing tool: ${toolName}`);
349
- return Promise.resolve({ action: decision.action });
350
- };
375
+ const promptFn = createHeadlessPromptFn({
376
+ catalog: permissionManager.catalog,
377
+ dangerouslySkipPermissions,
378
+ permissionPolicy,
379
+ emit: streaming ? emit : null,
380
+ warn: (message) => process.stderr.write(message)
381
+ });
351
382
  const userQuestionFn = (_payload) => {
352
383
  process.stderr.write("Warning: Agent requested user input; headless mode cannot respond interactively. Answering with empty response.\n");
353
384
  return Promise.resolve({ answers: [] });
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-v0wgf0_j.mjs";
3
- import { t as version } from "../package-COr17yKT.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-DUATzLxB.mjs";
3
+ import { t as version } from "../package-DYPVrada.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-D6Eu3oXv.mjs");
73
+ const { handleMcpServeCommand } = await import("../serve-w6v3rZiR.mjs");
74
74
  await handleMcpServeCommand({
75
75
  http: Boolean(argv.http),
76
76
  port: typeof argv.port === "number" ? argv.port : void 0,
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-v0wgf0_j.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-DUATzLxB.mjs";
3
3
  import { n as getDefaultPluginsDir, r as isFeatureEnabled, t as PluginStore } from "../PluginStore-DwvOJ-G3.mjs";
4
4
  import { promises } from "fs";
5
5
  import path from "path";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as version } from "../package-COr17yKT.mjs";
2
+ import { t as version } from "../package-DYPVrada.mjs";
3
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";
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { h as DeviceFlowClient, m as AuthenticatedApiClient, t as ConfigStore, y as logger } from "./ConfigStore-v0wgf0_j.mjs";
3
- import { t as version } from "./package-COr17yKT.mjs";
2
+ import { b as logger, g as DeviceFlowClient, h as AuthenticatedApiClient, t as ConfigStore } from "./ConfigStore-DUATzLxB.mjs";
3
+ import { t as version } from "./package-DYPVrada.mjs";
4
4
  import { isAxiosError } from "axios";
5
5
  import { Readable } from "node:stream";
6
6
  import { createParser } from "eventsource-parser";
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { $ as CustomCommandStore, A as createAgentDelegateTool, B as DEFAULT_THOROUGHNESS, C as createTodoStore, D as createCoordinateTaskTool, E as parseAgentConfig, G as setWebSocketToolExecutor, H as buildSkillsPromptSection, I as ALWAYS_DENIED_FOR_AGENTS, L as DEFAULT_AGENT_MODEL, M as substituteArguments, N as PermissionManager, O as createResumeAgentTool, P as buildCliToolList, Q as RemoteSkillSource, R as DEFAULT_MAX_ITERATIONS, S as createFindDefinitionTool, T as createSkillTool, V as buildSystemPrompt, W as getProcessHooks, X as createToolSearchTool, Z as findIterationBoundary, _ as createDecisionLogTool, at as mergeCommands, b as createGetFileStructureTool, ct as searchFiles, d as createReviewGateStore, dt as COMPACTION_SUMMARY_MARKER, et as processFileReferences, f as createReviewGateTool, g as formatBlockersOutput, h as createBlockerTools, it as searchCommands, j as FallbackLlmBackend, k as createBackgroundAgentTools, lt as warmFileCache, m as createBlockerStore, nt as CheckpointStore, ot as rewireReservedNames, p as formatReviewGatesOutput, pt as MAX_PASTE_SIZE, q as getPlanModeFilePath, rt as SessionStore, s as buildSandbox, st as formatFileSize, tt as hasFileReferences, u as isConnectionDrop, v as createDecisionStore, w as createWriteTodosTool, x as createWorkItemTools, y as formatDecisionsOutput, z as DEFAULT_RETRY_CONFIG } from "./AgentHistoryStore-BWko6txx.mjs";
2
+ import { $ as CustomCommandStore, A as createAgentDelegateTool, B as DEFAULT_THOROUGHNESS, C as createTodoStore, D as createCoordinateTaskTool, E as parseAgentConfig, G as setWebSocketToolExecutor, H as buildSkillsPromptSection, I as ALWAYS_DENIED_FOR_AGENTS, L as DEFAULT_AGENT_MODEL, M as substituteArguments, N as PermissionManager, O as createResumeAgentTool, P as buildCliToolList, Q as RemoteSkillSource, R as DEFAULT_MAX_ITERATIONS, S as createFindDefinitionTool, T as createSkillTool, V as buildSystemPrompt, W as getProcessHooks, X as createToolSearchTool, Z as findIterationBoundary, _ as createDecisionLogTool, at as mergeCommands, b as createGetFileStructureTool, ct as searchFiles, d as createReviewGateStore, dt as COMPACTION_SUMMARY_MARKER, et as processFileReferences, f as createReviewGateTool, g as formatBlockersOutput, h as createBlockerTools, it as searchCommands, j as FallbackLlmBackend, k as createBackgroundAgentTools, lt as warmFileCache, m as createBlockerStore, nt as CheckpointStore, ot as rewireReservedNames, p as formatReviewGatesOutput, pt as MAX_PASTE_SIZE, q as getPlanModeFilePath, rt as SessionStore, s as buildSandbox, st as formatFileSize, tt as hasFileReferences, u as isConnectionDrop, v as createDecisionStore, w as createWriteTodosTool, x as createWorkItemTools, y as formatDecisionsOutput, z as DEFAULT_RETRY_CONFIG } from "./AgentHistoryStore-CLidbOHG.mjs";
3
3
  import { a as selectLiveSubagentTokens, i as selectLiveSubagentCredits, n as selectActiveBackgroundShells, o as useCliStore, r as selectCompletedBackgroundShells, t as selectActiveBackgroundAgents } from "./store-BxmPEI3v.mjs";
4
- import { Bt as actorKindMarker, Ht as delegationPayloadSchema, I as CREDIT_DEDUCT_TRANSACTION_TYPES, L as ChatModels, Lt as ACTOR_COLOR_SLOTS, Mt as tokenEstimateMultiplier, Rt as DELEGATION_PAYLOAD_SCHEMA_NAME, Ut as selfClaimedActorKindSchema, Vt as actorKindSchema, b as SESSION_ID_PATTERN, d as getEnvironmentName, et as REVIEW_GATE_STATUS_VALUES, f as requireApiUrl, g as LOCAL_DEV_URL, i as ToolCatalog, l as ApiEndpointUnconfiguredError, n as extractCompactInstructions, p as resolveApiEndpoint, rt as SUBQUEST_STATUS_VALUES, t as ConfigStore, u as getCreditsUrl, v as parseApiUrl, vt as isEarlyStop, x as isValidSessionId, y as logger, zt as actorColorIndex } from "./ConfigStore-v0wgf0_j.mjs";
4
+ import { Bt as DELEGATION_PAYLOAD_SCHEMA_NAME, Gt as selfClaimedActorKindSchema, Ht as actorKindMarker, L as CREDIT_DEDUCT_TRANSACTION_TYPES, Pt as tokenEstimateMultiplier, R as ChatModels, S as isValidSessionId, Ut as actorKindSchema, Vt as actorColorIndex, Wt as delegationPayloadSchema, _ as LOCAL_DEV_URL, b as logger, bt as isEarlyStop, d as getCreditsUrl, f as getEnvironmentName, i as ToolCatalog, it as SUBQUEST_STATUS_VALUES, m as resolveApiEndpoint, n as extractCompactInstructions, p as requireApiUrl, t as ConfigStore, tt as REVIEW_GATE_STATUS_VALUES, u as ApiEndpointUnconfiguredError, x as SESSION_ID_PATTERN, y as parseApiUrl, zt as ACTOR_COLOR_SLOTS } from "./ConfigStore-DUATzLxB.mjs";
5
5
  import { r as isFeatureEnabled, t as PluginStore } from "./PluginStore-DwvOJ-G3.mjs";
6
- import { i as getTokenCounter, n as ConversationContext, r as reconstructTurnBlocks, t as WorkItemsClient } from "./WorkItemsClient-BZL44N12.mjs";
7
- import { a as NotifyingLlmBackend, i as deferredToolRegistry, n as buildSupportingStores, r as buildLlmBackend, t as buildAgent } from "./buildAgent-BZnmDQIr.mjs";
6
+ import { i as getTokenCounter, n as ConversationContext, r as reconstructTurnBlocks, t as WorkItemsClient } from "./WorkItemsClient-BSoOblGp.mjs";
7
+ import { a as NotifyingLlmBackend, i as deferredToolRegistry, n as buildSupportingStores, r as buildLlmBackend, t as buildAgent } from "./buildAgent-DyZWK0LW.mjs";
8
8
  import { t as getShellSessionManager } from "./ShellSessionManager-6o8KZzl1-vrbPAUTq.mjs";
9
- import { a as ApiClient, s as OAuthClient } from "./dist-5DDaX8tB.mjs";
10
- import { t as version } from "./package-COr17yKT.mjs";
9
+ import { a as ApiClient, s as OAuthClient } from "./dist-DPP7UmK9.mjs";
10
+ import { t as version } from "./package-DYPVrada.mjs";
11
11
  import { s as getStartupUpdateStatus } from "./updateChecker-CCLVVdH0.mjs";
12
12
  import React, { useCallback, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
13
13
  import { Box, Static, Text, measureElement, render, useApp, useInput, usePaste, useStdout } from "ink";
@@ -1145,9 +1145,23 @@ const TOOLS_WITH_HIDDEN_ARGS$1 = /* @__PURE__ */ new Set(["edit_local_file", "ba
1145
1145
  * Displays when a tool needs permission before execution.
1146
1146
  * Waits indefinitely for user response (like Claude Code).
1147
1147
  */
1148
- function PermissionPrompt({ toolName, toolDescription, args, preview, canBeTrusted, onResponse }) {
1148
+ function PermissionPrompt({ toolName, toolDescription, args, preview, canBeTrusted, kind, onResponse }) {
1149
+ const isSandboxEscalation = kind === "sandbox-escalation";
1149
1150
  const hideArgs = TOOLS_WITH_HIDDEN_ARGS$1.has(toolName);
1150
- const items = canBeTrusted ? [
1151
+ const items = isSandboxEscalation ? [
1152
+ {
1153
+ label: "✓ Retry once without sandbox",
1154
+ value: "allow-once"
1155
+ },
1156
+ {
1157
+ label: "✓ Allow this command unsandboxed for the session",
1158
+ value: "allow-session"
1159
+ },
1160
+ {
1161
+ label: "✗ Deny",
1162
+ value: "deny"
1163
+ }
1164
+ ] : canBeTrusted ? [
1151
1165
  {
1152
1166
  label: "✓ Allow once",
1153
1167
  value: "allow-once"
@@ -1251,7 +1265,7 @@ function PermissionPrompt({ toolName, toolDescription, args, preview, canBeTrust
1251
1265
  borderColor: "gray",
1252
1266
  paddingX: 1,
1253
1267
  flexDirection: "column"
1254
- }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, {
1268
+ }, renderDiffPreview(preview))), !canBeTrusted && !isSandboxEscalation && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, {
1255
1269
  color: "red",
1256
1270
  dimColor: true
1257
1271
  }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React.createElement(Box, {
@@ -2834,6 +2848,7 @@ function App({ onMessage, onBackgroundCompletion, onCommand, onBashCommand, onPe
2834
2848
  args: permissionPrompt.args,
2835
2849
  preview: permissionPrompt.preview,
2836
2850
  canBeTrusted: permissionPrompt.canBeTrusted,
2851
+ kind: permissionPrompt.kind,
2837
2852
  onResponse: (response) => onPermissionResponse(response, permissionPrompt.id)
2838
2853
  })), userQuestionPrompt && /* @__PURE__ */ React.createElement(Box, {
2839
2854
  key: userQuestionPrompt.id,
@@ -9225,7 +9240,7 @@ function CliApp() {
9225
9240
  checkpointStore
9226
9241
  });
9227
9242
  let permissionPromptCounter = 0;
9228
- const promptFn = (toolName, args, preview) => {
9243
+ const promptFn = (toolName, args, preview, kind) => {
9229
9244
  return new Promise((resolve) => {
9230
9245
  getProcessHooks()?.fireNotificationPermissionPrompt(toolName);
9231
9246
  const canBeTrusted = permissionManager.canBeTrusted(toolName);
@@ -9236,6 +9251,7 @@ function CliApp() {
9236
9251
  args,
9237
9252
  preview,
9238
9253
  canBeTrusted,
9254
+ kind,
9239
9255
  resolve
9240
9256
  };
9241
9257
  setState((prev) => ({
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  //#region package.json
3
- var version = "3.2.0";
3
+ var version = "3.3.0";
4
4
  //#endregion
5
5
  export { version as t };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { B as DEFAULT_TTS_PROVIDER, D as AGENT_QUEST_MCP_URI, E as AGENT_QUEST_MANIFEST, Ft as ttsResponseTooLargeSchema, H as GENERATED_IMAGE_EXTENSION_RE, M as BRIEFCASE_CATALOG_QUERIES, Nt as ttsBase64ResponseSchema, P as BriefcasePromptIdSchema, Pt as ttsRequestSchema, Q as PROMPT_TEXT_MAX, St as joinReplySlots, T as AGENT_QUEST_ID, Tt as replacePromptVariables, U as ImageModels, W as ImagePromptResolutionSchema, _ as NotAuthenticatedError, at as VisibilitySchema, f as requireApiUrl, j as ArtifactTypeSchema, jt as supportedVoiceGenerationVendor, lt as buildPromptContext, pt as generatedAudioResponseSchema, t as ConfigStore, v as parseApiUrl, wt as questReplyText, y as logger, z as CreateArtifactRequestSchema } from "./ConfigStore-v0wgf0_j.mjs";
3
- import { a as ApiClient, i as parseRetryAfterSeconds, o as isProviderKeyFailure, r as createClient, t as B4mApiError } from "./dist-5DDaX8tB.mjs";
2
+ import { $ as PROMPT_TEXT_MAX, B as CreateArtifactRequestSchema, D as AGENT_QUEST_MANIFEST, Dt as replacePromptVariables, E as AGENT_QUEST_ID, Et as questReplyText, F as BriefcasePromptIdSchema, Ft as ttsBase64ResponseSchema, G as ImagePromptResolutionSchema, It as ttsRequestSchema, Lt as ttsResponseTooLargeSchema, M as ArtifactTypeSchema, N as BRIEFCASE_CATALOG_QUERIES, Nt as supportedVoiceGenerationVendor, O as AGENT_QUEST_MCP_URI, U as GENERATED_IMAGE_EXTENSION_RE, V as DEFAULT_TTS_PROVIDER, W as ImageModels, b as logger, dt as buildPromptContext, ht as generatedAudioResponseSchema, p as requireApiUrl, st as VisibilitySchema, t as ConfigStore, v as NotAuthenticatedError, wt as joinReplySlots, y as parseApiUrl } from "./ConfigStore-DUATzLxB.mjs";
3
+ import { a as ApiClient, i as parseRetryAfterSeconds, o as isProviderKeyFailure, r as createClient, t as B4mApiError } from "./dist-DPP7UmK9.mjs";
4
4
  import { z as z$1 } from "zod";
5
5
  import { isAxiosError } from "axios";
6
6
  import { createHash, randomUUID } from "node:crypto";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "mcpName": "io.github.Bike4Mind/bike4mind",
5
5
  "type": "module",
6
6
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
@@ -124,17 +124,17 @@
124
124
  "tsx": "^4.23.0",
125
125
  "typescript": "^5.9.3",
126
126
  "vitest": "^4.1.11",
127
- "@bike4mind/agents": "0.0.0-snapshot-gh-readonly-queue-main-pr-5009-e421f9aab9-20261019120015",
128
- "@bike4mind/common": "0.0.0-snapshot-gh-readonly-queue-main-pr-5009-e421f9aab9-20261019120015",
129
- "@bike4mind/client-auth": "0.2.0",
130
- "@bike4mind/fab-pipeline": "0.0.0-snapshot-gh-readonly-queue-main-pr-5009-e421f9aab9-20261019120015",
127
+ "@bike4mind/agents": "1.2.8",
128
+ "@bike4mind/client-auth": "0.2.1",
129
+ "@bike4mind/common": "18.0.0",
130
+ "@bike4mind/fab-pipeline": "2.1.8",
131
131
  "@bike4mind/hearth": "0.3.1",
132
- "@bike4mind/mcp": "0.0.0-snapshot-gh-readonly-queue-main-pr-5009-e421f9aab9-20261019120015",
132
+ "@bike4mind/llm-adapters": "1.5.0",
133
+ "@bike4mind/mcp": "2.1.8",
133
134
  "@bike4mind/observability": "0.2.3",
134
- "@bike4mind/sdk": "1.1.0",
135
- "@bike4mind/llm-adapters": "0.0.0-snapshot-gh-readonly-queue-main-pr-5009-e421f9aab9-20261019120015",
136
- "@bike4mind/utils": "0.0.0-snapshot-gh-readonly-queue-main-pr-5009-e421f9aab9-20261019120015",
137
- "@bike4mind/services": "0.0.0-snapshot-gh-readonly-queue-main-pr-5009-e421f9aab9-20261019120015"
135
+ "@bike4mind/sdk": "1.2.0",
136
+ "@bike4mind/services": "19.2.0",
137
+ "@bike4mind/utils": "8.1.3"
138
138
  },
139
139
  "optionalDependencies": {
140
140
  "@vscode/ripgrep": "^1.18.0"