@bike4mind/cli 0.2.29-feat-cli-websocket-streaming.18842 → 0.2.29-feat-session-permission.18877

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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-KPOK6V6E.js";
4
+ } from "./chunk-5GSDPBTM.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/artifactExtractor.js
7
7
  var ARTIFACT_TAG_REGEX = /<artifact\s+(.*?)>([\s\S]*?)<\/artifact>/gi;
@@ -1012,29 +1012,6 @@ var VoiceSessionSendTranscriptAction = z10.object({
1012
1012
  conversationItemId: z10.string(),
1013
1013
  timestamp: z10.coerce.date().optional()
1014
1014
  });
1015
- var CliCompletionRequestAction = z10.object({
1016
- action: z10.literal("cli_completion_request"),
1017
- accessToken: z10.string(),
1018
- requestId: z10.string().uuid(),
1019
- model: z10.string(),
1020
- messages: z10.array(z10.object({
1021
- role: z10.enum(["user", "assistant", "system"]),
1022
- content: z10.union([z10.string(), z10.array(z10.unknown())])
1023
- })),
1024
- options: z10.object({
1025
- temperature: z10.number().optional(),
1026
- maxTokens: z10.number().optional(),
1027
- stream: z10.boolean().optional(),
1028
- tools: z10.array(z10.unknown()).optional()
1029
- }).optional()
1030
- });
1031
- var CliToolRequestAction = z10.object({
1032
- action: z10.literal("cli_tool_request"),
1033
- accessToken: z10.string(),
1034
- requestId: z10.string().uuid(),
1035
- toolName: z10.string(),
1036
- input: z10.record(z10.unknown())
1037
- });
1038
1015
  var VoiceSessionEndedAction = z10.object({
1039
1016
  action: z10.literal("voice_session_ended"),
1040
1017
  userId: z10.string(),
@@ -1281,36 +1258,6 @@ var ResearchModeStreamAction = z10.object({
1281
1258
  completionInfo: z10.any().optional()
1282
1259
  }).optional()
1283
1260
  });
1284
- var CliCompletionChunkAction = z10.object({
1285
- action: z10.literal("cli_completion_chunk"),
1286
- requestId: z10.string(),
1287
- chunk: z10.object({
1288
- type: z10.enum(["content", "tool_use"]),
1289
- text: z10.string(),
1290
- tools: z10.array(z10.unknown()).optional(),
1291
- usage: z10.object({
1292
- inputTokens: z10.number().optional(),
1293
- outputTokens: z10.number().optional()
1294
- }).optional(),
1295
- thinking: z10.array(z10.unknown()).optional()
1296
- })
1297
- });
1298
- var CliCompletionDoneAction = z10.object({
1299
- action: z10.literal("cli_completion_done"),
1300
- requestId: z10.string()
1301
- });
1302
- var CliCompletionErrorAction = z10.object({
1303
- action: z10.literal("cli_completion_error"),
1304
- requestId: z10.string(),
1305
- error: z10.string()
1306
- });
1307
- var CliToolResponseAction = z10.object({
1308
- action: z10.literal("cli_tool_response"),
1309
- requestId: z10.string(),
1310
- success: z10.boolean(),
1311
- content: z10.unknown().optional(),
1312
- error: z10.string().optional()
1313
- });
1314
1261
  var SessionCreatedAction = shareableDocumentSchema.extend({
1315
1262
  action: z10.literal("session.created"),
1316
1263
  id: z10.string(),
@@ -1345,9 +1292,7 @@ var MessageDataToServer = z10.discriminatedUnion("action", [
1345
1292
  DataUnsubscribeRequestAction,
1346
1293
  HeartbeatAction,
1347
1294
  VoiceSessionSendTranscriptAction,
1348
- VoiceSessionEndedAction,
1349
- CliCompletionRequestAction,
1350
- CliToolRequestAction
1295
+ VoiceSessionEndedAction
1351
1296
  ]);
1352
1297
  var MessageDataToClient = z10.discriminatedUnion("action", [
1353
1298
  DataSubscriptionUpdateAction,
@@ -1369,11 +1314,7 @@ var MessageDataToClient = z10.discriminatedUnion("action", [
1369
1314
  SpiderProgressUpdateAction,
1370
1315
  SpiderCompleteAction,
1371
1316
  SpiderErrorAction,
1372
- SessionCreatedAction,
1373
- CliCompletionChunkAction,
1374
- CliCompletionDoneAction,
1375
- CliCompletionErrorAction,
1376
- CliToolResponseAction
1317
+ SessionCreatedAction
1377
1318
  ]);
1378
1319
 
1379
1320
  // ../../b4m-core/packages/common/dist/src/schemas/cliCompletions.js
@@ -7985,8 +7926,6 @@ export {
7985
7926
  DataUnsubscribeRequestAction,
7986
7927
  HeartbeatAction,
7987
7928
  VoiceSessionSendTranscriptAction,
7988
- CliCompletionRequestAction,
7989
- CliToolRequestAction,
7990
7929
  VoiceSessionEndedAction,
7991
7930
  DataSubscriptionUpdateAction,
7992
7931
  LLMStatusUpdateAction,
@@ -8007,10 +7946,6 @@ export {
8007
7946
  UpdateResearchTaskStatusAction,
8008
7947
  ImportHistoryJobProgressUpdateAction,
8009
7948
  ResearchModeStreamAction,
8010
- CliCompletionChunkAction,
8011
- CliCompletionDoneAction,
8012
- CliCompletionErrorAction,
8013
- CliToolResponseAction,
8014
7949
  SessionCreatedAction,
8015
7950
  MessageDataToServer,
8016
7951
  MessageDataToClient,
@@ -6,12 +6,12 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-TY6Z2UV2.js";
9
+ } from "./chunk-S7BPPS33.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
13
13
  isSupportedEmbeddingModel
14
- } from "./chunk-KPOK6V6E.js";
14
+ } from "./chunk-5GSDPBTM.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
17
17
  import { z } from "zod";
@@ -7,11 +7,11 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-TY6Z2UV2.js";
10
+ } from "./chunk-S7BPPS33.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
14
- } from "./chunk-KPOK6V6E.js";
14
+ } from "./chunk-5GSDPBTM.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/fabFileService/create.js
17
17
  import { z } from "zod";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-TY6Z2UV2.js";
5
+ } from "./chunk-S7BPPS33.js";
6
6
  import {
7
7
  CompletionApiUsageTransaction,
8
8
  GenericCreditDeductTransaction,
@@ -12,7 +12,7 @@ import {
12
12
  TextGenerationUsageTransaction,
13
13
  TransferCreditTransaction,
14
14
  VideoGenerationUsageTransaction
15
- } from "./chunk-KPOK6V6E.js";
15
+ } from "./chunk-5GSDPBTM.js";
16
16
 
17
17
  // ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
18
18
  import { z } from "zod";
@@ -15,7 +15,7 @@ import {
15
15
  dayjsConfig_default,
16
16
  extractSnippetMeta,
17
17
  settingsMap
18
- } from "./chunk-KPOK6V6E.js";
18
+ } from "./chunk-5GSDPBTM.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-OCYRD7D6.js";
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-EC2VEDD2.js";
6
- import "./chunk-TY6Z2UV2.js";
7
- import "./chunk-KPOK6V6E.js";
5
+ } from "./chunk-ELTTBWAQ.js";
6
+ import "./chunk-S7BPPS33.js";
7
+ import "./chunk-5GSDPBTM.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  createFabFile,
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  getEffectiveApiKey,
6
6
  getOpenWeatherKey,
7
7
  getSerperKey
8
- } from "./chunk-QQL3OBKL.js";
8
+ } from "./chunk-BCOGDPUB.js";
9
9
  import {
10
10
  ConfigStore,
11
11
  logger
@@ -14,8 +14,8 @@ import {
14
14
  selectActiveBackgroundAgents,
15
15
  useCliStore
16
16
  } from "./chunk-TVW4ZESU.js";
17
- import "./chunk-BXCARBUQ.js";
18
- import "./chunk-EC2VEDD2.js";
17
+ import "./chunk-PKKJ44C5.js";
18
+ import "./chunk-ELTTBWAQ.js";
19
19
  import {
20
20
  BFLImageService,
21
21
  BaseStorage,
@@ -27,7 +27,7 @@ import {
27
27
  OpenAIBackend,
28
28
  OpenAIImageService,
29
29
  XAIImageService
30
- } from "./chunk-TY6Z2UV2.js";
30
+ } from "./chunk-S7BPPS33.js";
31
31
  import {
32
32
  AiEvents,
33
33
  ApiKeyEvents,
@@ -83,7 +83,7 @@ import {
83
83
  XAI_IMAGE_MODELS,
84
84
  b4mLLMTools,
85
85
  getMcpProviderMetadata
86
- } from "./chunk-KPOK6V6E.js";
86
+ } from "./chunk-5GSDPBTM.js";
87
87
  import {
88
88
  Logger
89
89
  } from "./chunk-OCYRD7D6.js";
@@ -93,7 +93,7 @@ import React21, { useState as useState9, useEffect as useEffect6, useCallback as
93
93
  import { render, Box as Box20, Text as Text20, useApp, useInput as useInput9 } from "ink";
94
94
  import { execSync } from "child_process";
95
95
  import { randomBytes as randomBytes5 } from "crypto";
96
- import { v4 as uuidv413 } from "uuid";
96
+ import { v4 as uuidv411 } from "uuid";
97
97
 
98
98
  // src/components/App.tsx
99
99
  import React15, { useState as useState5, useEffect as useEffect4 } from "react";
@@ -1260,10 +1260,12 @@ function PermissionPrompt({
1260
1260
  }) {
1261
1261
  const items = canBeTrusted ? [
1262
1262
  { label: "\u2713 Allow once", value: "allow-once" },
1263
+ { label: "\u2713 Allow for this session", value: "allow-session" },
1263
1264
  { label: "\u2713 Always allow (trust this tool)", value: "allow-always" },
1264
1265
  { label: "\u2717 Deny", value: "deny" }
1265
1266
  ] : [
1266
1267
  { label: "\u2713 Allow once", value: "allow-once" },
1268
+ { label: "\u2713 Allow for this session", value: "allow-session" },
1267
1269
  { label: "\u2717 Deny", value: "deny" }
1268
1270
  ];
1269
1271
  const [selectedIndex, setSelectedIndex] = useState3(0);
@@ -3587,6 +3589,50 @@ function isReadOnlyTool(toolName, customCategories) {
3587
3589
  return getToolCategory(toolName, customCategories) !== "prompt_always";
3588
3590
  }
3589
3591
 
3592
+ // src/core/skillsPrompt.ts
3593
+ function getSkillDisplayName(cmd) {
3594
+ return cmd.displayName || cmd.name;
3595
+ }
3596
+ function formatSkillEntry(cmd) {
3597
+ const displayName = getSkillDisplayName(cmd);
3598
+ const argHint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
3599
+ const nameDisplay = cmd.displayName && cmd.displayName !== cmd.name ? `**${displayName}** (\`${cmd.name}\`)` : `**${cmd.name}**`;
3600
+ return `- ${nameDisplay}${argHint}: ${cmd.description}
3601
+ `;
3602
+ }
3603
+ function formatSkillGroup(heading, commands) {
3604
+ if (commands.length === 0) {
3605
+ return "";
3606
+ }
3607
+ return `
3608
+ ### ${heading}
3609
+ ${commands.map(formatSkillEntry).join("")}`;
3610
+ }
3611
+ function filterAIVisibleSkills(commands) {
3612
+ return commands.filter((cmd) => !cmd.disableModelInvocation);
3613
+ }
3614
+ function filterSkillsByAllowedList(commands, allowedSkills) {
3615
+ if (!allowedSkills || allowedSkills.length === 0) {
3616
+ return commands;
3617
+ }
3618
+ return commands.filter((cmd) => allowedSkills.includes(cmd.name));
3619
+ }
3620
+ function buildSkillsPromptSection(commands, allowedSkills) {
3621
+ const filteredByAllowed = filterSkillsByAllowedList(commands, allowedSkills);
3622
+ const visibleCommands = filterAIVisibleSkills(filteredByAllowed);
3623
+ if (visibleCommands.length === 0) {
3624
+ return "";
3625
+ }
3626
+ const projectSkills = visibleCommands.filter((c) => c.source === "project");
3627
+ const globalSkills = visibleCommands.filter((c) => c.source === "global");
3628
+ return `
3629
+
3630
+ ## Available Skills
3631
+
3632
+ Use the \`skill\` tool to invoke these. Example: skill({ skill: "commit" })
3633
+ ` + formatSkillGroup("Project Skills", projectSkills) + formatSkillGroup("Global Skills", globalSkills);
3634
+ }
3635
+
3590
3636
  // src/core/prompts.ts
3591
3637
  var TOOL_GREP_SEARCH = "grep_search";
3592
3638
  var TOOL_GLOB_FILES = "glob_files";
@@ -3597,7 +3643,38 @@ var TOOL_BASH_EXECUTE = "bash_execute";
3597
3643
  var TOOL_SUBAGENT_DELEGATE = "subagent_delegate";
3598
3644
  var TOOL_WRITE_TODOS = "write_todos";
3599
3645
  var EXPLORE_SUBAGENT_TYPE = "explore";
3600
- function buildCoreSystemPrompt(contextSection = "") {
3646
+ function buildCoreSystemPrompt(contextSection, config) {
3647
+ let projectContextSection = "";
3648
+ let agentDirectoryContext = "";
3649
+ let skillsSection = "";
3650
+ if (typeof contextSection === "string") {
3651
+ projectContextSection = contextSection;
3652
+ if (config) {
3653
+ if (config.enableSkillTool !== false && config.customCommands && config.customCommands.length > 0) {
3654
+ skillsSection = buildSkillsPromptSection(config.customCommands);
3655
+ }
3656
+ if (config.agentStore) {
3657
+ agentDirectoryContext = config.agentStore.getDirectoryContext();
3658
+ }
3659
+ }
3660
+ } else if (contextSection && typeof contextSection === "object") {
3661
+ config = contextSection;
3662
+ if (config.contextContent) {
3663
+ projectContextSection = `
3664
+
3665
+ ## Project Context
3666
+
3667
+ Follow these project-specific instructions:
3668
+
3669
+ ${config.contextContent}`;
3670
+ }
3671
+ if (config.enableSkillTool !== false && config.customCommands && config.customCommands.length > 0) {
3672
+ skillsSection = buildSkillsPromptSection(config.customCommands);
3673
+ }
3674
+ if (config.agentStore) {
3675
+ agentDirectoryContext = config.agentStore.getDirectoryContext();
3676
+ }
3677
+ }
3601
3678
  return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
3602
3679
 
3603
3680
  CORE BEHAVIOR:
@@ -3627,12 +3704,8 @@ When requested to perform tasks like fixing bugs, adding features, refactoring,
3627
3704
 
3628
3705
  SUBAGENT DELEGATION:
3629
3706
  - You have access to specialized subagents via the ${TOOL_SUBAGENT_DELEGATE} tool
3630
- - Use subagents for focused exploration, planning, or review tasks:
3631
- * explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
3632
- * plan: Break down complex tasks into actionable steps
3633
- * review: Analyze code quality and identify issues
3707
+ - ${agentDirectoryContext ? `${agentDirectoryContext}` : ""}
3634
3708
  - Subagents keep the main conversation clean and run faster with optimized models
3635
- - Delegate when you need to search extensively or analyze code structure
3636
3709
 
3637
3710
  CODE SEARCH BEST PRACTICES:
3638
3711
  When searching code, follow this hierarchy for speed and efficiency:
@@ -3689,7 +3762,7 @@ EXAMPLES:
3689
3762
  - "what packages installed?" \u2192 ${TOOL_GLOB_FILES} "**/package.json" \u2192 ${TOOL_FILE_READ}
3690
3763
  - "find all components using React hooks" \u2192 ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks", type="explore")
3691
3764
 
3692
- Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
3765
+ Remember: Use context from previous messages to understand follow-up questions.${projectContextSection}${skillsSection}`;
3693
3766
  }
3694
3767
 
3695
3768
  // ../../b4m-core/packages/services/dist/src/referService/generateCodes.js
@@ -11438,10 +11511,6 @@ var ServerToolExecutor = class {
11438
11511
  };
11439
11512
 
11440
11513
  // src/llm/ToolRouter.ts
11441
- var wsToolExecutor = null;
11442
- function setWebSocketToolExecutor(executor) {
11443
- wsToolExecutor = executor;
11444
- }
11445
11514
  var SERVER_TOOLS = ["weather_info", "web_search", "web_fetch"];
11446
11515
  var LOCAL_TOOLS = [
11447
11516
  "file_read",
@@ -11464,15 +11533,7 @@ function isLocalTool(toolName) {
11464
11533
  }
11465
11534
  async function executeTool(toolName, input, apiClient, localToolFn) {
11466
11535
  if (isServerTool(toolName)) {
11467
- if (wsToolExecutor) {
11468
- logger.debug(`[ToolRouter] Routing ${toolName} to server via WebSocket`);
11469
- const result = await wsToolExecutor.execute(toolName, input);
11470
- if (!result.success) {
11471
- return `Error executing ${toolName}: ${result.error || "Tool execution failed"}`;
11472
- }
11473
- return typeof result.content === "string" ? result.content : JSON.stringify(result.content ?? "");
11474
- }
11475
- logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
11536
+ logger.debug(`[ToolRouter] Routing ${toolName} to server`);
11476
11537
  const executor = new ServerToolExecutor(apiClient);
11477
11538
  return await executor.executeTool(toolName, input);
11478
11539
  } else if (isLocalTool(toolName)) {
@@ -11776,6 +11837,9 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
11776
11837
  if (response.action === "deny") {
11777
11838
  throw new PermissionDeniedError(toolName, args);
11778
11839
  }
11840
+ if (response.action === "allow-session") {
11841
+ permissionManager.trustToolForSession(toolName);
11842
+ }
11779
11843
  if (response.action === "allow-always") {
11780
11844
  const canTrust = permissionManager.trustTool(toolName);
11781
11845
  if (canTrust) {
@@ -11980,6 +12044,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
11980
12044
  var PermissionManager = class {
11981
12045
  constructor(trustedTools = [], customCategories, deniedTools) {
11982
12046
  this.trustedTools = /* @__PURE__ */ new Set();
12047
+ this.sessionTrustedTools = /* @__PURE__ */ new Set();
11983
12048
  this.deniedTools = /* @__PURE__ */ new Set();
11984
12049
  this.trustedTools = new Set(trustedTools);
11985
12050
  this.customCategories = new Map(Object.entries(customCategories || {}));
@@ -12005,6 +12070,9 @@ var PermissionManager = class {
12005
12070
  if (category === "auto_approve") {
12006
12071
  return false;
12007
12072
  }
12073
+ if (this.sessionTrustedTools.has(toolName)) {
12074
+ return false;
12075
+ }
12008
12076
  if (category === "prompt_always") {
12009
12077
  return true;
12010
12078
  }
@@ -12072,6 +12140,29 @@ var PermissionManager = class {
12072
12140
  getDeniedTools() {
12073
12141
  return Array.from(this.deniedTools).sort();
12074
12142
  }
12143
+ /**
12144
+ * Trust a tool for the current session only (in-memory, no persistence)
12145
+ * Works for all tool categories including prompt_always, but NOT project-denied tools
12146
+ */
12147
+ trustToolForSession(toolName) {
12148
+ if (this.deniedTools.has(toolName)) {
12149
+ return false;
12150
+ }
12151
+ this.sessionTrustedTools.add(toolName);
12152
+ return true;
12153
+ }
12154
+ /**
12155
+ * Check if a tool is trusted for the current session
12156
+ */
12157
+ isSessionTrusted(toolName) {
12158
+ return this.sessionTrustedTools.has(toolName);
12159
+ }
12160
+ /**
12161
+ * Clear all session-scoped trust (called on exit or session reset)
12162
+ */
12163
+ clearSessionTrust() {
12164
+ this.sessionTrustedTools.clear();
12165
+ }
12075
12166
  /**
12076
12167
  * Clear all trusted tools
12077
12168
  */
@@ -13402,168 +13493,6 @@ var ServerLlmBackend = class {
13402
13493
  }
13403
13494
  };
13404
13495
 
13405
- // src/llm/WebSocketLlmBackend.ts
13406
- import { v4 as uuidv411 } from "uuid";
13407
- function stripThinkingBlocks2(text) {
13408
- return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
13409
- }
13410
- var WebSocketLlmBackend = class {
13411
- constructor(options) {
13412
- this.wsManager = options.wsManager;
13413
- this.apiClient = options.apiClient;
13414
- this.currentModel = options.model;
13415
- this.tokenGetter = options.tokenGetter;
13416
- }
13417
- /**
13418
- * Make LLM completion request via WebSocket.
13419
- * Collects all streamed chunks, then calls callback once at completion
13420
- * with the full accumulated content.
13421
- */
13422
- async complete(model, messages, options, callback) {
13423
- logger.debug(`[WebSocketLlmBackend] Starting complete() with model: ${model}`);
13424
- if (options.abortSignal?.aborted) {
13425
- logger.debug("[WebSocketLlmBackend] Request aborted before start");
13426
- return;
13427
- }
13428
- if (!this.wsManager.isConnected) {
13429
- throw new Error("WebSocket is not connected");
13430
- }
13431
- const requestId = uuidv411();
13432
- const token = await this.tokenGetter();
13433
- if (!token) {
13434
- throw new Error("No access token available");
13435
- }
13436
- return new Promise((resolve3, reject) => {
13437
- const isVerbose = process.env.B4M_VERBOSE === "1";
13438
- const isUltraVerbose = process.env.B4M_DEBUG_STREAM === "1";
13439
- const streamLogger = new StreamLogger(logger, "WebSocketLlmBackend", isVerbose, isUltraVerbose);
13440
- streamLogger.streamStart();
13441
- let eventCount = 0;
13442
- let accumulatedText = "";
13443
- let lastUsageInfo = {};
13444
- let toolsUsed = [];
13445
- let thinkingBlocks = [];
13446
- let settled = false;
13447
- const settle = (action) => {
13448
- if (settled) return;
13449
- settled = true;
13450
- this.wsManager.offRequest(requestId);
13451
- action();
13452
- };
13453
- const settleResolve = () => settle(() => resolve3());
13454
- const settleReject = (err) => settle(() => reject(err));
13455
- if (options.abortSignal) {
13456
- if (options.abortSignal.aborted) {
13457
- settleResolve();
13458
- return;
13459
- }
13460
- options.abortSignal.addEventListener(
13461
- "abort",
13462
- () => {
13463
- logger.debug("[WebSocketLlmBackend] Abort signal received");
13464
- settleResolve();
13465
- },
13466
- { once: true }
13467
- );
13468
- }
13469
- const updateUsage = (usage) => {
13470
- if (usage) {
13471
- lastUsageInfo = { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens };
13472
- }
13473
- };
13474
- this.wsManager.onRequest(requestId, (message) => {
13475
- if (options.abortSignal?.aborted) return;
13476
- const action = message.action;
13477
- if (action === "cli_completion_chunk") {
13478
- eventCount++;
13479
- const chunk = message.chunk;
13480
- streamLogger.onEvent(eventCount, JSON.stringify(chunk));
13481
- const textChunk = chunk.text || "";
13482
- if (textChunk) accumulatedText += textChunk;
13483
- updateUsage(chunk.usage);
13484
- if (chunk.type === "content") {
13485
- streamLogger.onContent(eventCount, textChunk, accumulatedText);
13486
- } else if (chunk.type === "tool_use") {
13487
- streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${chunk.tools?.length}`);
13488
- if (chunk.tools && chunk.tools.length > 0) toolsUsed = chunk.tools;
13489
- if (chunk.thinking && chunk.thinking.length > 0) thinkingBlocks = chunk.thinking;
13490
- }
13491
- } else if (action === "cli_completion_done") {
13492
- streamLogger.streamComplete(accumulatedText);
13493
- const cleanedText = stripThinkingBlocks2(accumulatedText);
13494
- if (!cleanedText && toolsUsed.length === 0) {
13495
- settleResolve();
13496
- return;
13497
- }
13498
- const info = {
13499
- ...lastUsageInfo,
13500
- ...toolsUsed.length > 0 && { toolsUsed },
13501
- ...thinkingBlocks.length > 0 && { thinking: thinkingBlocks }
13502
- };
13503
- callback([cleanedText], info).then(() => settleResolve()).catch((err) => settleReject(err));
13504
- } else if (action === "cli_completion_error") {
13505
- const errorMsg = message.error || "Server error";
13506
- streamLogger.onCriticalEvent(eventCount, "ERROR", errorMsg);
13507
- settleReject(new Error(errorMsg));
13508
- }
13509
- });
13510
- try {
13511
- this.wsManager.send({
13512
- action: "cli_completion_request",
13513
- accessToken: token,
13514
- requestId,
13515
- model,
13516
- messages,
13517
- options: {
13518
- temperature: options.temperature,
13519
- maxTokens: options.maxTokens,
13520
- stream: true,
13521
- tools: options.tools || []
13522
- }
13523
- });
13524
- } catch (err) {
13525
- settleReject(err instanceof Error ? err : new Error(String(err)));
13526
- }
13527
- });
13528
- }
13529
- /**
13530
- * Get available models from server (REST call, not streaming).
13531
- * Delegates to ApiClient -- same as ServerLlmBackend.
13532
- */
13533
- async getModelInfo() {
13534
- try {
13535
- logger.debug("[WebSocketLlmBackend] Fetching models from /api/models");
13536
- const response = await this.apiClient.get("/api/models");
13537
- if (!response || typeof response !== "object" || !Array.isArray(response.models)) {
13538
- logger.warn("[WebSocketLlmBackend] Invalid API response format, using fallback models");
13539
- return this.getFallbackModels();
13540
- }
13541
- const filteredModels = response.models.filter(
13542
- (model) => model.type === "text" && model.supportsTools === true
13543
- );
13544
- if (filteredModels.length === 0) {
13545
- logger.warn("[WebSocketLlmBackend] No CLI-compatible models found, using fallback");
13546
- return this.getFallbackModels();
13547
- }
13548
- logger.debug(`[WebSocketLlmBackend] Loaded ${filteredModels.length} models`);
13549
- return filteredModels;
13550
- } catch (error) {
13551
- logger.warn(
13552
- `[WebSocketLlmBackend] Failed to fetch models: ${error instanceof Error ? error.message : String(error)}`
13553
- );
13554
- return this.getFallbackModels();
13555
- }
13556
- }
13557
- getFallbackModels() {
13558
- return [
13559
- { id: "claude-sonnet-4-5-20250929", name: "Claude 4.5 Sonnet" },
13560
- { id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku" },
13561
- { id: "gpt-4o", name: "GPT-4o" },
13562
- { id: "gpt-4o-mini", name: "GPT-4o Mini" }
13563
- ];
13564
- }
13565
- };
13566
-
13567
13496
  // src/llm/NotifyingLlmBackend.ts
13568
13497
  var NotifyingLlmBackend = class {
13569
13498
  constructor(inner, backgroundManager) {
@@ -13598,214 +13527,6 @@ Please acknowledge these background agent results and incorporate them into your
13598
13527
  }
13599
13528
  };
13600
13529
 
13601
- // src/ws/WebSocketConnectionManager.ts
13602
- var WebSocketConnectionManager = class {
13603
- constructor(wsUrl, getToken) {
13604
- this.ws = null;
13605
- this.heartbeatInterval = null;
13606
- this.reconnectAttempts = 0;
13607
- this.maxReconnectDelay = 3e4;
13608
- this.handlers = /* @__PURE__ */ new Map();
13609
- this.connected = false;
13610
- this.connecting = false;
13611
- this.closed = false;
13612
- this.wsUrl = wsUrl;
13613
- this.getToken = getToken;
13614
- }
13615
- /**
13616
- * Connect to the WebSocket server.
13617
- * Resolves when connection is established, rejects on failure.
13618
- */
13619
- async connect() {
13620
- if (this.connected || this.connecting) return;
13621
- this.connecting = true;
13622
- const token = await this.getToken();
13623
- if (!token) {
13624
- this.connecting = false;
13625
- throw new Error("No access token available for WebSocket connection");
13626
- }
13627
- return new Promise((resolve3, reject) => {
13628
- const url = `${this.wsUrl}?token=${token}`;
13629
- logger.debug(`[WS] Connecting to ${this.wsUrl}...`);
13630
- this.ws = new WebSocket(url);
13631
- this.ws.onopen = () => {
13632
- logger.debug("[WS] Connected");
13633
- this.connected = true;
13634
- this.connecting = false;
13635
- this.reconnectAttempts = 0;
13636
- this.startHeartbeat();
13637
- resolve3();
13638
- };
13639
- this.ws.onmessage = (event) => {
13640
- try {
13641
- const data = typeof event.data === "string" ? event.data : event.data.toString();
13642
- const message = JSON.parse(data);
13643
- const requestId = message.requestId;
13644
- if (requestId && this.handlers.has(requestId)) {
13645
- this.handlers.get(requestId)(message);
13646
- } else {
13647
- logger.debug(`[WS] Unhandled message: ${message.action || "unknown"}`);
13648
- }
13649
- } catch (err) {
13650
- logger.debug(`[WS] Failed to parse message: ${err}`);
13651
- }
13652
- };
13653
- this.ws.onclose = () => {
13654
- logger.debug("[WS] Connection closed");
13655
- this.cleanup();
13656
- if (!this.closed) {
13657
- this.scheduleReconnect();
13658
- }
13659
- };
13660
- this.ws.onerror = (err) => {
13661
- logger.debug(`[WS] Error: ${err}`);
13662
- if (this.connecting) {
13663
- this.connecting = false;
13664
- this.connected = false;
13665
- reject(new Error("WebSocket connection failed"));
13666
- }
13667
- };
13668
- });
13669
- }
13670
- /** Whether the connection is currently established */
13671
- get isConnected() {
13672
- return this.connected;
13673
- }
13674
- /**
13675
- * Send a JSON message over the WebSocket connection.
13676
- */
13677
- send(data) {
13678
- if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
13679
- throw new Error("WebSocket is not connected");
13680
- }
13681
- this.ws.send(JSON.stringify(data));
13682
- }
13683
- /**
13684
- * Register a handler for messages matching a specific requestId.
13685
- */
13686
- onRequest(requestId, handler) {
13687
- this.handlers.set(requestId, handler);
13688
- }
13689
- /**
13690
- * Remove a handler for a specific requestId.
13691
- */
13692
- offRequest(requestId) {
13693
- this.handlers.delete(requestId);
13694
- }
13695
- /**
13696
- * Close the connection and stop all heartbeat/reconnect logic.
13697
- */
13698
- disconnect() {
13699
- this.closed = true;
13700
- this.cleanup();
13701
- if (this.ws) {
13702
- this.ws.close();
13703
- this.ws = null;
13704
- }
13705
- this.handlers.clear();
13706
- }
13707
- startHeartbeat() {
13708
- this.stopHeartbeat();
13709
- this.heartbeatInterval = setInterval(
13710
- () => {
13711
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
13712
- this.ws.send(JSON.stringify({ action: "heartbeat" }));
13713
- logger.debug("[WS] Heartbeat sent");
13714
- }
13715
- },
13716
- 5 * 60 * 1e3
13717
- );
13718
- }
13719
- stopHeartbeat() {
13720
- if (this.heartbeatInterval) {
13721
- clearInterval(this.heartbeatInterval);
13722
- this.heartbeatInterval = null;
13723
- }
13724
- }
13725
- cleanup() {
13726
- this.connected = false;
13727
- this.connecting = false;
13728
- this.stopHeartbeat();
13729
- }
13730
- scheduleReconnect() {
13731
- if (this.closed) return;
13732
- this.reconnectAttempts++;
13733
- const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
13734
- logger.debug(`[WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
13735
- setTimeout(async () => {
13736
- if (this.closed) return;
13737
- try {
13738
- await this.connect();
13739
- } catch {
13740
- logger.debug("[WS] Reconnection failed");
13741
- }
13742
- }, delay);
13743
- }
13744
- };
13745
-
13746
- // src/ws/WebSocketToolExecutor.ts
13747
- import { v4 as uuidv412 } from "uuid";
13748
- var WebSocketToolExecutor = class {
13749
- constructor(wsManager, tokenGetter) {
13750
- this.wsManager = wsManager;
13751
- this.tokenGetter = tokenGetter;
13752
- }
13753
- /**
13754
- * Execute a server-side tool via WebSocket.
13755
- * Returns the tool result or throws on error.
13756
- */
13757
- async execute(toolName, input, abortSignal) {
13758
- if (!this.wsManager.isConnected) {
13759
- throw new Error("WebSocket is not connected");
13760
- }
13761
- const token = await this.tokenGetter();
13762
- if (!token) {
13763
- throw new Error("No access token available");
13764
- }
13765
- const requestId = uuidv412();
13766
- return new Promise((resolve3, reject) => {
13767
- let settled = false;
13768
- const settle = (action) => {
13769
- if (settled) return;
13770
- settled = true;
13771
- this.wsManager.offRequest(requestId);
13772
- action();
13773
- };
13774
- const settleResolve = (result) => settle(() => resolve3(result));
13775
- const settleReject = (err) => settle(() => reject(err));
13776
- if (abortSignal) {
13777
- if (abortSignal.aborted) {
13778
- settleReject(new Error("Tool execution aborted"));
13779
- return;
13780
- }
13781
- abortSignal.addEventListener("abort", () => settleReject(new Error("Tool execution aborted")), {
13782
- once: true
13783
- });
13784
- }
13785
- this.wsManager.onRequest(requestId, (message) => {
13786
- if (message.action === "cli_tool_response") {
13787
- settleResolve({
13788
- success: message.success,
13789
- content: message.content,
13790
- error: message.error
13791
- });
13792
- }
13793
- });
13794
- try {
13795
- this.wsManager.send({
13796
- action: "cli_tool_request",
13797
- accessToken: token,
13798
- requestId,
13799
- toolName,
13800
- input
13801
- });
13802
- } catch (err) {
13803
- settleReject(err instanceof Error ? err : new Error(String(err)));
13804
- }
13805
- });
13806
- }
13807
- };
13808
-
13809
13530
  // src/auth/ApiClient.ts
13810
13531
  import axios11 from "axios";
13811
13532
  var ApiClient = class {
@@ -13943,7 +13664,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
13943
13664
  // package.json
13944
13665
  var package_default = {
13945
13666
  name: "@bike4mind/cli",
13946
- version: "0.2.29-feat-cli-websocket-streaming.18842+8ba59c222",
13667
+ version: "0.2.29-feat-session-permission.18877+9b858652a",
13947
13668
  type: "module",
13948
13669
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
13949
13670
  license: "UNLICENSED",
@@ -14053,10 +13774,10 @@ var package_default = {
14053
13774
  },
14054
13775
  devDependencies: {
14055
13776
  "@bike4mind/agents": "0.1.0",
14056
- "@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18842+8ba59c222",
14057
- "@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18842+8ba59c222",
14058
- "@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18842+8ba59c222",
14059
- "@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18842+8ba59c222",
13777
+ "@bike4mind/common": "2.50.1-feat-session-permission.18877+9b858652a",
13778
+ "@bike4mind/mcp": "1.29.1-feat-session-permission.18877+9b858652a",
13779
+ "@bike4mind/services": "2.48.1-feat-session-permission.18877+9b858652a",
13780
+ "@bike4mind/utils": "2.5.1-feat-session-permission.18877+9b858652a",
14060
13781
  "@types/better-sqlite3": "^7.6.13",
14061
13782
  "@types/diff": "^5.0.9",
14062
13783
  "@types/jsonwebtoken": "^9.0.4",
@@ -14073,7 +13794,7 @@ var package_default = {
14073
13794
  optionalDependencies: {
14074
13795
  "@vscode/ripgrep": "^1.17.0"
14075
13796
  },
14076
- gitHead: "8ba59c22293ec8857baaba3c7c6d96db1fbb4b15"
13797
+ gitHead: "9b858652ae9c40dab415fd8fab4515a2f0d312be"
14077
13798
  };
14078
13799
 
14079
13800
  // src/config/constants.ts
@@ -14310,50 +14031,6 @@ ${expandedBody}
14310
14031
  };
14311
14032
  }
14312
14033
 
14313
- // src/core/skillsPrompt.ts
14314
- function getSkillDisplayName(cmd) {
14315
- return cmd.displayName || cmd.name;
14316
- }
14317
- function formatSkillEntry(cmd) {
14318
- const displayName = getSkillDisplayName(cmd);
14319
- const argHint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
14320
- const nameDisplay = cmd.displayName && cmd.displayName !== cmd.name ? `**${displayName}** (\`${cmd.name}\`)` : `**${cmd.name}**`;
14321
- return `- ${nameDisplay}${argHint}: ${cmd.description}
14322
- `;
14323
- }
14324
- function formatSkillGroup(heading, commands) {
14325
- if (commands.length === 0) {
14326
- return "";
14327
- }
14328
- return `
14329
- ### ${heading}
14330
- ${commands.map(formatSkillEntry).join("")}`;
14331
- }
14332
- function filterAIVisibleSkills(commands) {
14333
- return commands.filter((cmd) => !cmd.disableModelInvocation);
14334
- }
14335
- function filterSkillsByAllowedList(commands, allowedSkills) {
14336
- if (!allowedSkills || allowedSkills.length === 0) {
14337
- return commands;
14338
- }
14339
- return commands.filter((cmd) => allowedSkills.includes(cmd.name));
14340
- }
14341
- function buildSkillsPromptSection(commands, allowedSkills) {
14342
- const filteredByAllowed = filterSkillsByAllowedList(commands, allowedSkills);
14343
- const visibleCommands = filterAIVisibleSkills(filteredByAllowed);
14344
- if (visibleCommands.length === 0) {
14345
- return "";
14346
- }
14347
- const projectSkills = visibleCommands.filter((c) => c.source === "project");
14348
- const globalSkills = visibleCommands.filter((c) => c.source === "global");
14349
- return `
14350
-
14351
- ## Available Skills
14352
-
14353
- Use the \`skill\` tool to invoke these. Example: skill({ skill: "commit" })
14354
- ` + formatSkillGroup("Project Skills", projectSkills) + formatSkillGroup("Global Skills", globalSkills);
14355
- }
14356
-
14357
14034
  // src/agents/SubagentOrchestrator.ts
14358
14035
  var SubagentOrchestrator = class {
14359
14036
  constructor(deps) {
@@ -14934,6 +14611,21 @@ Describe the expected output format here.
14934
14611
  }
14935
14612
  return { builtin, global, project, total: this.agents.size };
14936
14613
  }
14614
+ /**
14615
+ * Generates a markdown "Phone Book" of available agents and their schemas.
14616
+ * This MUST be injected into the System Prompt of the parent agent.
14617
+ */
14618
+ getDirectoryContext() {
14619
+ if (this.agents.size === 0) {
14620
+ return "No sub-agents are currently available.";
14621
+ }
14622
+ let context = "Use `subagent_delegate` for complex tasks requiring specialized analysis.\n";
14623
+ for (const [name, def] of this.agents) {
14624
+ context += ` - **${name}**: ${def.description}
14625
+ `;
14626
+ }
14627
+ return context;
14628
+ }
14937
14629
  };
14938
14630
 
14939
14631
  // src/agents/delegateTool.ts
@@ -15881,8 +15573,7 @@ function CliApp() {
15881
15573
  agentStore: null,
15882
15574
  abortController: null,
15883
15575
  contextContent: "",
15884
- backgroundManager: null,
15885
- wsManager: null
15576
+ backgroundManager: null
15886
15577
  });
15887
15578
  const [isInitialized, setIsInitialized] = useState9(false);
15888
15579
  const [initError, setInitError] = useState9(null);
@@ -15910,10 +15601,6 @@ function CliApp() {
15910
15601
  })
15911
15602
  );
15912
15603
  }
15913
- if (state.wsManager) {
15914
- state.wsManager.disconnect();
15915
- setWebSocketToolExecutor(null);
15916
- }
15917
15604
  if (state.agent) {
15918
15605
  state.agent.removeAllListeners();
15919
15606
  }
@@ -15932,7 +15619,7 @@ function CliApp() {
15932
15619
  setTimeout(() => {
15933
15620
  process.exit(0);
15934
15621
  }, 100);
15935
- }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
15622
+ }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
15936
15623
  useInput9((input, key) => {
15937
15624
  if (key.escape) {
15938
15625
  if (state.abortController) {
@@ -16002,7 +15689,7 @@ function CliApp() {
16002
15689
  if (!isAuthenticated) {
16003
15690
  console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
16004
15691
  const minimalSession = {
16005
- id: uuidv413(),
15692
+ id: uuidv411(),
16006
15693
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
16007
15694
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
16008
15695
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16030,41 +15717,10 @@ function CliApp() {
16030
15717
  console.log(`\u{1F30D} API Environment: ${envName} (${apiBaseURL})`);
16031
15718
  }
16032
15719
  const apiClient = new ApiClient(apiBaseURL, state.configStore);
16033
- const tokenGetter = async () => {
16034
- const tokens = await state.configStore.getAuthTokens();
16035
- return tokens?.accessToken ?? null;
16036
- };
16037
- let wsManager = null;
16038
- let llm;
16039
- try {
16040
- const serverConfig = await apiClient.get("/api/settings/serverConfig");
16041
- const wsUrl = serverConfig?.websocketUrl;
16042
- if (wsUrl) {
16043
- wsManager = new WebSocketConnectionManager(wsUrl, tokenGetter);
16044
- await wsManager.connect();
16045
- const wsToolExecutor2 = new WebSocketToolExecutor(wsManager, tokenGetter);
16046
- setWebSocketToolExecutor(wsToolExecutor2);
16047
- llm = new WebSocketLlmBackend({
16048
- wsManager,
16049
- apiClient,
16050
- model: config.defaultModel,
16051
- tokenGetter
16052
- });
16053
- logger.debug("\u{1F50C} Using WebSocket transport (bypasses CloudFront timeout)");
16054
- } else {
16055
- throw new Error("No websocketUrl in server config");
16056
- }
16057
- } catch (wsError) {
16058
- logger.debug(
16059
- `[WS] WebSocket unavailable, using SSE fallback: ${wsError instanceof Error ? wsError.message : String(wsError)}`
16060
- );
16061
- wsManager = null;
16062
- setWebSocketToolExecutor(null);
16063
- llm = new ServerLlmBackend({
16064
- apiClient,
16065
- model: config.defaultModel
16066
- });
16067
- }
15720
+ const llm = new ServerLlmBackend({
15721
+ apiClient,
15722
+ model: config.defaultModel
15723
+ });
16068
15724
  const models = await llm.getModelInfo();
16069
15725
  if (models.length === 0) {
16070
15726
  throw new Error("No models available from server.");
@@ -16077,7 +15733,7 @@ function CliApp() {
16077
15733
  }
16078
15734
  llm.currentModel = modelInfo.id;
16079
15735
  const newSession = {
16080
- id: uuidv413(),
15736
+ id: uuidv411(),
16081
15737
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
16082
15738
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
16083
15739
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16227,18 +15883,12 @@ function CliApp() {
16227
15883
  for (const error of contextResult.errors) {
16228
15884
  startupLog.push(`\u26A0\uFE0F Context file error: ${error}`);
16229
15885
  }
16230
- let contextSection = contextResult.mergedContent ? `
16231
-
16232
- ## Project Context
16233
-
16234
- Follow these project-specific instructions:
16235
-
16236
- ${contextResult.mergedContent}` : "";
16237
- if (enableSkillTool) {
16238
- const commands = state.customCommandStore.getAllCommands();
16239
- contextSection += buildSkillsPromptSection(commands);
16240
- }
16241
- const cliSystemPrompt = buildCoreSystemPrompt(contextSection);
15886
+ const cliSystemPrompt = buildCoreSystemPrompt({
15887
+ contextContent: contextResult.mergedContent,
15888
+ agentStore,
15889
+ customCommands: state.customCommandStore.getAllCommands(),
15890
+ enableSkillTool
15891
+ });
16242
15892
  const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
16243
15893
  const agent = new ReActAgent({
16244
15894
  userId: config.userId,
@@ -16297,10 +15947,8 @@ ${contextResult.mergedContent}` : "";
16297
15947
  // Store agent store for agent management commands
16298
15948
  contextContent: contextResult.mergedContent,
16299
15949
  // Store raw context for compact instructions
16300
- backgroundManager,
15950
+ backgroundManager
16301
15951
  // Store for grouped notification turn tracking
16302
- wsManager
16303
- // WebSocket connection manager (null if using SSE fallback)
16304
15952
  }));
16305
15953
  setStoreSession(newSession);
16306
15954
  const bannerLines = [
@@ -16395,13 +16043,13 @@ ${contextResult.mergedContent}` : "";
16395
16043
  messageContent = multimodalMessage.content;
16396
16044
  }
16397
16045
  const userMessage = {
16398
- id: uuidv413(),
16046
+ id: uuidv411(),
16399
16047
  role: "user",
16400
16048
  content: userMessageContent,
16401
16049
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
16402
16050
  };
16403
16051
  const pendingAssistantMessage = {
16404
- id: uuidv413(),
16052
+ id: uuidv411(),
16405
16053
  role: "assistant",
16406
16054
  content: "...",
16407
16055
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16570,7 +16218,12 @@ ${contextResult.mergedContent}` : "";
16570
16218
  const tokenCounter2 = getTokenCounter();
16571
16219
  const contextWindow = tokenCounter2.getContextWindow(activeSession.model, state.availableModels);
16572
16220
  const threshold = contextWindow * 0.8;
16573
- const systemPrompt = buildCoreSystemPrompt(state.contextContent || "");
16221
+ const systemPrompt = buildCoreSystemPrompt({
16222
+ contextContent: state.contextContent,
16223
+ agentStore: state.agentStore || void 0,
16224
+ customCommands: state.customCommandStore.getAllCommands(),
16225
+ enableSkillTool: config?.preferences.enableSkillTool !== false
16226
+ });
16574
16227
  const contextUsage = tokenCounter2.countSessionTokens(activeSession, systemPrompt);
16575
16228
  if (contextUsage.totalTokens >= threshold) {
16576
16229
  console.log("\n\u26A0\uFE0F Context window 80% full. Auto-compacting...\n");
@@ -16607,13 +16260,13 @@ ${contextResult.mergedContent}` : "";
16607
16260
  userMessageContent = message;
16608
16261
  }
16609
16262
  const userMessage = {
16610
- id: uuidv413(),
16263
+ id: uuidv411(),
16611
16264
  role: "user",
16612
16265
  content: userMessageContent,
16613
16266
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
16614
16267
  };
16615
16268
  const pendingAssistantMessage = {
16616
- id: uuidv413(),
16269
+ id: uuidv411(),
16617
16270
  role: "assistant",
16618
16271
  content: "...",
16619
16272
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16691,7 +16344,7 @@ ${contextResult.mergedContent}` : "";
16691
16344
  const currentSession = useCliStore.getState().session;
16692
16345
  if (currentSession) {
16693
16346
  const cancelMessage = {
16694
- id: uuidv413(),
16347
+ id: uuidv411(),
16695
16348
  role: "assistant",
16696
16349
  content: "\u26A0\uFE0F Operation cancelled by user",
16697
16350
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16736,7 +16389,7 @@ ${contextResult.mergedContent}` : "";
16736
16389
  setState((prev) => ({ ...prev, abortController }));
16737
16390
  try {
16738
16391
  const pendingAssistantMessage = {
16739
- id: uuidv413(),
16392
+ id: uuidv411(),
16740
16393
  role: "assistant",
16741
16394
  content: "...",
16742
16395
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16764,7 +16417,7 @@ ${contextResult.mergedContent}` : "";
16764
16417
  const currentSession = useCliStore.getState().session;
16765
16418
  if (!currentSession) return;
16766
16419
  const continuationMessage = {
16767
- id: uuidv413(),
16420
+ id: uuidv411(),
16768
16421
  role: "assistant",
16769
16422
  content: "---\n\n**Background Agent Results:**\n\n" + result.finalAnswer,
16770
16423
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16823,13 +16476,13 @@ ${contextResult.mergedContent}` : "";
16823
16476
  isError = true;
16824
16477
  }
16825
16478
  const userMessage = {
16826
- id: uuidv413(),
16479
+ id: uuidv411(),
16827
16480
  role: "user",
16828
16481
  content: `$ ${command}`,
16829
16482
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
16830
16483
  };
16831
16484
  const assistantMessage = {
16832
- id: uuidv413(),
16485
+ id: uuidv411(),
16833
16486
  role: "assistant",
16834
16487
  content: isError ? `\u274C Error:
16835
16488
  ${output}` : output.trim() || "(no output)",
@@ -17298,7 +16951,7 @@ Keyboard Shortcuts:
17298
16951
  console.clear();
17299
16952
  const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
17300
16953
  const newSession = {
17301
- id: uuidv413(),
16954
+ id: uuidv411(),
17302
16955
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
17303
16956
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
17304
16957
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -17488,15 +17141,21 @@ No usage data available for the last ${USAGE_DAYS} days.`);
17488
17141
  }
17489
17142
  const tokenCounter2 = getTokenCounter();
17490
17143
  const contextWindow = tokenCounter2.getContextWindow(state.session.model, state.availableModels);
17491
- const corePromptTokens = tokenCounter2.countTokens(buildCoreSystemPrompt(""));
17144
+ const corePromptTokens = tokenCounter2.countTokens(buildCoreSystemPrompt());
17492
17145
  const projectContextTokens = state.contextContent ? tokenCounter2.countTokens(state.contextContent) : 0;
17493
17146
  const commands = state.customCommandStore.getAllCommands();
17494
17147
  const skillsSection = buildSkillsPromptSection(commands);
17495
17148
  const skillsTokens = skillsSection ? tokenCounter2.countTokens(skillsSection) : 0;
17149
+ const agentDirectoryTokens = state.agentStore ? tokenCounter2.countTokens(state.agentStore.getDirectoryContext()) : 0;
17496
17150
  const mcpTools = state.mcpManager?.getTools() || [];
17497
17151
  const mcpToolsTokens = tokenCounter2.countToolSchemaTokens(mcpTools);
17498
17152
  const mcpToolCount = state.mcpManager?.getToolCount() || [];
17499
- const systemPrompt = buildCoreSystemPrompt(state.contextContent || "");
17153
+ const systemPrompt = buildCoreSystemPrompt({
17154
+ contextContent: state.contextContent,
17155
+ agentStore: state.agentStore || void 0,
17156
+ customCommands: commands,
17157
+ enableSkillTool: state.config?.preferences.enableSkillTool !== false
17158
+ });
17500
17159
  const usage = tokenCounter2.countSessionTokens(state.session, systemPrompt);
17501
17160
  const totalWithTools = usage.totalTokens + mcpToolsTokens;
17502
17161
  const usagePercent = totalWithTools / contextWindow * 100;
@@ -17515,6 +17174,10 @@ No usage data available for the last ${USAGE_DAYS} days.`);
17515
17174
  if (commands.length > 0) {
17516
17175
  console.log(` Skills Section: ${skillsTokens.toLocaleString()} tokens (${commands.length} skills)`);
17517
17176
  }
17177
+ if (agentDirectoryTokens > 0) {
17178
+ const agentCount = state.agentStore?.getAgentCount() || 0;
17179
+ console.log(` Agent Directory: ${agentDirectoryTokens.toLocaleString()} tokens (${agentCount} agents)`);
17180
+ }
17518
17181
  if (mcpTools.length > 0) {
17519
17182
  console.log("\nMCP Tools:");
17520
17183
  console.log(` Total: ${mcpToolsTokens.toLocaleString()} tokens (${mcpTools.length} tools)`);
@@ -17793,9 +17456,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
17793
17456
  return { ...prev, config: updatedConfig };
17794
17457
  });
17795
17458
  if (modelChanged && state.agent) {
17796
- const backend = state.agent.context.llm;
17797
- if (backend) {
17798
- backend.currentModel = updatedConfig.defaultModel;
17459
+ const llm = state.agent.context.llm;
17460
+ if (llm) {
17461
+ llm.currentModel = updatedConfig.defaultModel;
17799
17462
  }
17800
17463
  }
17801
17464
  };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-KPOK6V6E.js";
4
+ } from "./chunk-5GSDPBTM.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/llmMarkdownGenerator.js
7
7
  var DEFAULT_OPTIONS = {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-KPOK6V6E.js";
4
+ } from "./chunk-5GSDPBTM.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/markdownGenerator.js
7
7
  var DEFAULT_OPTIONS = {
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  findMostSimilarMemento,
4
4
  getRelevantMementos
5
- } from "./chunk-QQL3OBKL.js";
6
- import "./chunk-TY6Z2UV2.js";
7
- import "./chunk-KPOK6V6E.js";
5
+ } from "./chunk-BCOGDPUB.js";
6
+ import "./chunk-S7BPPS33.js";
7
+ import "./chunk-5GSDPBTM.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  findMostSimilarMemento,
@@ -134,8 +134,8 @@ import {
134
134
  validateMermaidSyntax,
135
135
  warmUpSettingsCache,
136
136
  withRetry
137
- } from "./chunk-TY6Z2UV2.js";
138
- import "./chunk-KPOK6V6E.js";
137
+ } from "./chunk-S7BPPS33.js";
138
+ import "./chunk-5GSDPBTM.js";
139
139
  import {
140
140
  Logger,
141
141
  NotificationDeduplicator,
@@ -41,12 +41,6 @@ import {
41
41
  ChatModels,
42
42
  CitableSourceSchema,
43
43
  ClaudeArtifactMimeTypes,
44
- CliCompletionChunkAction,
45
- CliCompletionDoneAction,
46
- CliCompletionErrorAction,
47
- CliCompletionRequestAction,
48
- CliToolRequestAction,
49
- CliToolResponseAction,
50
44
  CollectionType,
51
45
  CompletionApiUsageTransaction,
52
46
  CompletionRequestSchema,
@@ -346,7 +340,7 @@ import {
346
340
  validateReactArtifactV2,
347
341
  validateSvgArtifactV2,
348
342
  wikiMarkupToAdf
349
- } from "./chunk-KPOK6V6E.js";
343
+ } from "./chunk-5GSDPBTM.js";
350
344
  export {
351
345
  ALL_IMAGE_MODELS,
352
346
  ALL_IMAGE_SIZES,
@@ -390,12 +384,6 @@ export {
390
384
  ChatModels,
391
385
  CitableSourceSchema,
392
386
  ClaudeArtifactMimeTypes,
393
- CliCompletionChunkAction,
394
- CliCompletionDoneAction,
395
- CliCompletionErrorAction,
396
- CliCompletionRequestAction,
397
- CliToolRequestAction,
398
- CliToolResponseAction,
399
387
  CollectionType,
400
388
  CompletionApiUsageTransaction,
401
389
  CompletionRequestSchema,
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  SubtractCreditsSchema,
4
4
  subtractCredits
5
- } from "./chunk-BXCARBUQ.js";
6
- import "./chunk-TY6Z2UV2.js";
7
- import "./chunk-KPOK6V6E.js";
5
+ } from "./chunk-PKKJ44C5.js";
6
+ import "./chunk-S7BPPS33.js";
7
+ import "./chunk-5GSDPBTM.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  SubtractCreditsSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.29-feat-cli-websocket-streaming.18842+8ba59c222",
3
+ "version": "0.2.29-feat-session-permission.18877+9b858652a",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -110,10 +110,10 @@
110
110
  },
111
111
  "devDependencies": {
112
112
  "@bike4mind/agents": "0.1.0",
113
- "@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18842+8ba59c222",
114
- "@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18842+8ba59c222",
115
- "@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18842+8ba59c222",
116
- "@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18842+8ba59c222",
113
+ "@bike4mind/common": "2.50.1-feat-session-permission.18877+9b858652a",
114
+ "@bike4mind/mcp": "1.29.1-feat-session-permission.18877+9b858652a",
115
+ "@bike4mind/services": "2.48.1-feat-session-permission.18877+9b858652a",
116
+ "@bike4mind/utils": "2.5.1-feat-session-permission.18877+9b858652a",
117
117
  "@types/better-sqlite3": "^7.6.13",
118
118
  "@types/diff": "^5.0.9",
119
119
  "@types/jsonwebtoken": "^9.0.4",
@@ -130,5 +130,5 @@
130
130
  "optionalDependencies": {
131
131
  "@vscode/ripgrep": "^1.17.0"
132
132
  },
133
- "gitHead": "8ba59c22293ec8857baaba3c7c6d96db1fbb4b15"
133
+ "gitHead": "9b858652ae9c40dab415fd8fab4515a2f0d312be"
134
134
  }