@bike4mind/cli 0.2.55 → 0.2.56-feat-cli-tavern-integration.21361

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.
@@ -397,6 +397,9 @@ var CliConfigSchema = z.object({
397
397
  disabled: z.array(z.string()),
398
398
  config: z.record(z.string(), z.any())
399
399
  }),
400
+ features: z.object({
401
+ tavern: z.boolean().optional()
402
+ }).optional().prefault({}),
400
403
  trustedTools: z.array(z.string()).optional().prefault([]),
401
404
  sandbox: SandboxConfigSchema.optional(),
402
405
  additionalDirectories: z.array(z.string()).optional().prefault([])
@@ -23,7 +23,7 @@ import {
23
23
  import {
24
24
  ConfigStore,
25
25
  logger
26
- } from "./chunk-524RAWPN.js";
26
+ } from "./chunk-JV4GPGBC.js";
27
27
  import {
28
28
  ALERT_THRESHOLDS,
29
29
  AiEvents,
@@ -2381,6 +2381,7 @@ function buildCoreSystemPrompt(contextSection, config) {
2381
2381
  let skillsSection = "";
2382
2382
  let dynamicAgentSection = "";
2383
2383
  let directoriesSection = "";
2384
+ let featureModulesSection = "";
2384
2385
  if (typeof contextSection === "string") {
2385
2386
  projectContextSection = contextSection;
2386
2387
  if (config) {
@@ -2393,6 +2394,9 @@ function buildCoreSystemPrompt(contextSection, config) {
2393
2394
  if (config.enableDynamicAgentCreation) {
2394
2395
  dynamicAgentSection = buildDynamicAgentPromptSection();
2395
2396
  }
2397
+ if (config.featureModulePrompts) {
2398
+ featureModulesSection = config.featureModulePrompts;
2399
+ }
2396
2400
  }
2397
2401
  } else if (contextSection && typeof contextSection === "object") {
2398
2402
  config = contextSection;
@@ -2429,6 +2433,9 @@ To access files in additional directories, pass the full path to the 'dir_path'
2429
2433
 
2430
2434
  When the user asks about content in an additional directory, search there first using the dir_path parameter.`;
2431
2435
  }
2436
+ if (config.featureModulePrompts) {
2437
+ featureModulesSection = config.featureModulePrompts;
2438
+ }
2432
2439
  }
2433
2440
  return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
2434
2441
 
@@ -2518,7 +2525,7 @@ EXAMPLES:
2518
2525
  - "what packages installed?" \u2192 ${TOOL_GLOB_FILES} "**/package.json" \u2192 ${TOOL_FILE_READ}
2519
2526
  - "find all components using React hooks" \u2192 ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks", type="explore")
2520
2527
 
2521
- Remember: Use context from previous messages to understand follow-up questions.${directoriesSection}${projectContextSection}${skillsSection}`;
2528
+ Remember: Use context from previous messages to understand follow-up questions.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}`;
2522
2529
  }
2523
2530
  function buildDynamicAgentPromptSection() {
2524
2531
  return `
@@ -2610,6 +2617,18 @@ var ServerToolExecutor = class {
2610
2617
 
2611
2618
  // src/llm/ToolRouter.ts
2612
2619
  var wsToolExecutor = null;
2620
+ var featureModuleTools = /* @__PURE__ */ new Set();
2621
+ function registerFeatureModuleTools(toolNames) {
2622
+ for (const name of toolNames) {
2623
+ featureModuleTools.add(name);
2624
+ }
2625
+ }
2626
+ function clearFeatureModuleTools() {
2627
+ featureModuleTools.clear();
2628
+ }
2629
+ function isFeatureModuleTool(toolName) {
2630
+ return featureModuleTools.has(toolName);
2631
+ }
2613
2632
  function setWebSocketToolExecutor(executor) {
2614
2633
  wsToolExecutor = executor;
2615
2634
  }
@@ -2647,7 +2666,7 @@ async function executeTool(toolName, input, apiClient, localToolFn) {
2647
2666
  logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
2648
2667
  const executor = new ServerToolExecutor(apiClient);
2649
2668
  return await executor.executeTool(toolName, input);
2650
- } else if (isLocalTool(toolName)) {
2669
+ } else if (isLocalTool(toolName) || isFeatureModuleTool(toolName)) {
2651
2670
  logger.debug(`[ToolRouter] Executing ${toolName} locally`);
2652
2671
  if (!localToolFn) {
2653
2672
  throw new Error(`Local tool ${toolName} has no implementation`);
@@ -15423,7 +15442,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
15423
15442
  if (!permissionManager.needsPermission(toolName, { isSandboxed })) {
15424
15443
  return executeAndRecord();
15425
15444
  }
15426
- const { useCliStore } = await import("./store-X5LEOSGZ.js");
15445
+ const { useCliStore } = await import("./store-CAB6BV3P.js");
15427
15446
  if (useCliStore.getState().autoAcceptEdits) {
15428
15447
  return executeAndRecord();
15429
15448
  }
@@ -19656,6 +19675,8 @@ export {
19656
19675
  isReadOnlyTool,
19657
19676
  buildSkillsPromptSection,
19658
19677
  buildCoreSystemPrompt,
19678
+ registerFeatureModuleTools,
19679
+ clearFeatureModuleTools,
19659
19680
  setWebSocketToolExecutor,
19660
19681
  ALWAYS_DENIED_FOR_AGENTS,
19661
19682
  DEFAULT_MAX_ITERATIONS,
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@bike4mind/cli",
6
- version: "0.2.55",
6
+ version: "0.2.56-feat-cli-tavern-integration.21361+2f1552bbd",
7
7
  type: "module",
8
8
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
9
9
  license: "UNLICENSED",
@@ -73,6 +73,7 @@ var package_default = {
73
73
  diff: "^8.0.2",
74
74
  dotenv: "^17.0.0",
75
75
  "eventsource-parser": "^3.0.6",
76
+ exceljs: "^4.4.0",
76
77
  fdir: "^6.5.0",
77
78
  "file-type": "^18.7.0",
78
79
  "fuse.js": "^7.1.0",
@@ -117,11 +118,11 @@ var package_default = {
117
118
  zustand: "^4.5.4"
118
119
  },
119
120
  devDependencies: {
120
- "@bike4mind/agents": "0.2.1",
121
- "@bike4mind/common": "2.70.1",
122
- "@bike4mind/mcp": "1.33.15",
123
- "@bike4mind/services": "2.64.3",
124
- "@bike4mind/utils": "2.15.9",
121
+ "@bike4mind/agents": "0.2.2-feat-cli-tavern-integration.21361+2f1552bbd",
122
+ "@bike4mind/common": "2.70.2-feat-cli-tavern-integration.21361+2f1552bbd",
123
+ "@bike4mind/mcp": "1.33.16-feat-cli-tavern-integration.21361+2f1552bbd",
124
+ "@bike4mind/services": "2.64.4-feat-cli-tavern-integration.21361+2f1552bbd",
125
+ "@bike4mind/utils": "2.15.10-feat-cli-tavern-integration.21361+2f1552bbd",
125
126
  "@types/better-sqlite3": "^7.6.13",
126
127
  "@types/jsonwebtoken": "^9.0.4",
127
128
  "@types/node": "^22.9.0",
@@ -138,7 +139,7 @@ var package_default = {
138
139
  optionalDependencies: {
139
140
  "@vscode/ripgrep": "^1.17.1"
140
141
  },
141
- gitHead: "dfc4dccb344f081dd2c87bc16fb2d27f70c02844"
142
+ gitHead: "2f1552bbd1fd89923637cbcf2a6e40b729437a2d"
142
143
  };
143
144
 
144
145
  // src/utils/updateChecker.ts
@@ -128,7 +128,14 @@ var useCliStore = create((set) => ({
128
128
  clearCompletedGroupNotifications: () => set({ completedGroupNotifications: [] }),
129
129
  // Pending background trigger
130
130
  pendingBackgroundTrigger: false,
131
- setPendingBackgroundTrigger: (pending) => set({ pendingBackgroundTrigger: pending })
131
+ setPendingBackgroundTrigger: (pending) => set({ pendingBackgroundTrigger: pending }),
132
+ // Tavern activity log (capped at 200 entries)
133
+ tavernActivityLog: [],
134
+ addTavernLogEntry: (entry) => set((state) => {
135
+ const log = [...state.tavernActivityLog, entry];
136
+ return { tavernActivityLog: log.length > 200 ? log.slice(-200) : log };
137
+ }),
138
+ clearTavernActivityLog: () => set({ tavernActivityLog: [] })
132
139
  }));
133
140
  var selectActiveBackgroundAgents = (state) => state.backgroundAgents.filter((j) => isActiveStatus(j.status));
134
141
  var selectCompletedBackgroundAgents = (state) => state.backgroundAgents.filter((j) => !isActiveStatus(j.status));
@@ -3,7 +3,7 @@ import {
3
3
  fetchLatestVersion,
4
4
  forceCheckForUpdate,
5
5
  package_default
6
- } from "../chunk-25UR2PLZ.js";
6
+ } from "../chunk-SDMU65DA.js";
7
7
 
8
8
  // src/commands/doctorCommand.ts
9
9
  import { execSync } from "child_process";
@@ -36,7 +36,7 @@ import {
36
36
  isReadOnlyTool,
37
37
  loadContextFiles,
38
38
  setWebSocketToolExecutor
39
- } from "../chunk-SA2GRZGG.js";
39
+ } from "../chunk-PJ3VATSD.js";
40
40
  import "../chunk-BDQBOLYG.js";
41
41
  import "../chunk-XACIOJZ7.js";
42
42
  import "../chunk-GQGOWACU.js";
@@ -48,7 +48,7 @@ import "../chunk-BPFEGDC7.js";
48
48
  import {
49
49
  ConfigStore,
50
50
  logger
51
- } from "../chunk-524RAWPN.js";
51
+ } from "../chunk-JV4GPGBC.js";
52
52
  import "../chunk-I5ZF2OVL.js";
53
53
  import {
54
54
  DEFAULT_SANDBOX_CONFIG
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigStore
4
- } from "../chunk-524RAWPN.js";
4
+ } from "../chunk-JV4GPGBC.js";
5
5
  import "../chunk-I5ZF2OVL.js";
6
6
  import "../chunk-4BIBE3J7.js";
7
7
 
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  forceCheckForUpdate,
4
4
  package_default
5
- } from "../chunk-25UR2PLZ.js";
5
+ } from "../chunk-SDMU65DA.js";
6
6
 
7
7
  // src/commands/updateCommand.ts
8
8
  import { execSync } from "child_process";
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  WebSocketToolExecutor,
23
23
  buildCoreSystemPrompt,
24
24
  buildSkillsPromptSection,
25
+ clearFeatureModuleTools,
25
26
  createAgentDelegateTool,
26
27
  createBackgroundAgentTools,
27
28
  createFindDefinitionTool,
@@ -41,12 +42,13 @@ import {
41
42
  mergeCommands,
42
43
  parseAgentConfig,
43
44
  processFileReferences,
45
+ registerFeatureModuleTools,
44
46
  searchCommands,
45
47
  searchFiles,
46
48
  setWebSocketToolExecutor,
47
49
  substituteArguments,
48
50
  warmFileCache
49
- } from "./chunk-SA2GRZGG.js";
51
+ } from "./chunk-PJ3VATSD.js";
50
52
  import "./chunk-BDQBOLYG.js";
51
53
  import "./chunk-XACIOJZ7.js";
52
54
  import "./chunk-GQGOWACU.js";
@@ -60,15 +62,15 @@ import "./chunk-BPFEGDC7.js";
60
62
  import {
61
63
  ConfigStore,
62
64
  logger
63
- } from "./chunk-524RAWPN.js";
65
+ } from "./chunk-JV4GPGBC.js";
64
66
  import {
65
67
  checkForUpdate,
66
68
  package_default
67
- } from "./chunk-25UR2PLZ.js";
69
+ } from "./chunk-SDMU65DA.js";
68
70
  import {
69
71
  selectActiveBackgroundAgents,
70
72
  useCliStore
71
- } from "./chunk-G2LYCVZJ.js";
73
+ } from "./chunk-Y4WOJJM3.js";
72
74
  import {
73
75
  CREDIT_DEDUCT_TRANSACTION_TYPES,
74
76
  ChatModels
@@ -1420,6 +1422,19 @@ function buildConfigItems(availableModels) {
1420
1422
  enableDynamicAgentCreation: value
1421
1423
  }
1422
1424
  })
1425
+ },
1426
+ {
1427
+ key: "featuresTavern",
1428
+ label: "Tavern",
1429
+ type: "boolean",
1430
+ getValue: (config) => config.features?.tavern ?? false,
1431
+ setValue: (config, value) => ({
1432
+ ...config,
1433
+ features: {
1434
+ ...config.features,
1435
+ tavern: value
1436
+ }
1437
+ })
1423
1438
  }
1424
1439
  );
1425
1440
  return items;
@@ -1431,8 +1446,15 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
1431
1446
  const [isSaving, setIsSaving] = useState7(false);
1432
1447
  const configItems = useMemo3(() => buildConfigItems(availableModels), [availableModels]);
1433
1448
  const hasChanges = useMemo3(() => {
1434
- return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
1435
- }, [config.preferences, editedConfig.preferences, config.defaultModel, editedConfig.defaultModel]);
1449
+ return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel || JSON.stringify(config.features) !== JSON.stringify(editedConfig.features);
1450
+ }, [
1451
+ config.preferences,
1452
+ editedConfig.preferences,
1453
+ config.defaultModel,
1454
+ editedConfig.defaultModel,
1455
+ config.features,
1456
+ editedConfig.features
1457
+ ]);
1436
1458
  const handleSaveAndClose = async () => {
1437
1459
  if (hasChanges) {
1438
1460
  try {
@@ -2681,6 +2703,599 @@ Unlike agent_delegate (which uses pre-defined agents), this tool lets you compos
2681
2703
  };
2682
2704
  }
2683
2705
 
2706
+ // src/features/FeatureModuleRegistry.ts
2707
+ var FeatureModuleRegistry = class {
2708
+ constructor() {
2709
+ this.modules = [];
2710
+ }
2711
+ /** Register a feature module */
2712
+ register(module) {
2713
+ if (this.modules.some((m) => m.name === module.name)) {
2714
+ throw new Error(`Feature module '${module.name}' is already registered`);
2715
+ }
2716
+ this.modules.push(module);
2717
+ }
2718
+ /** Collect all tools from all registered modules */
2719
+ getAllTools() {
2720
+ return this.modules.flatMap((m) => m.getTools());
2721
+ }
2722
+ /** Get all tool names from all registered modules */
2723
+ getAllToolNames() {
2724
+ return this.getAllTools().map((t) => t.toolSchema.name);
2725
+ }
2726
+ /** Build combined system prompt section from all modules */
2727
+ getSystemPromptSections() {
2728
+ const sections = this.modules.map((m) => m.getSystemPromptSection()).filter((s) => s.length > 0);
2729
+ return sections.length > 0 ? "\n\n" + sections.join("\n\n") : "";
2730
+ }
2731
+ /** Register all WS handlers from all modules */
2732
+ registerAllWsHandlers(wsManager) {
2733
+ for (const module of this.modules) {
2734
+ module.registerWsHandlers?.(wsManager);
2735
+ }
2736
+ }
2737
+ /** Cleanup all modules */
2738
+ disposeAll() {
2739
+ for (const module of this.modules) {
2740
+ module.dispose?.();
2741
+ }
2742
+ }
2743
+ /** Get names of all registered modules */
2744
+ getModuleNames() {
2745
+ return this.modules.map((m) => m.name);
2746
+ }
2747
+ /** Check if any modules are registered */
2748
+ get hasModules() {
2749
+ return this.modules.length > 0;
2750
+ }
2751
+ };
2752
+
2753
+ // src/features/tavern/TavernService.ts
2754
+ var TavernService = class {
2755
+ constructor(apiClient) {
2756
+ this.apiClient = apiClient;
2757
+ }
2758
+ async listAgents() {
2759
+ return this.apiClient.get("/api/agents?limit=100");
2760
+ }
2761
+ async mentionAgent(agentName, message, config) {
2762
+ return this.apiClient.post("/api/tavern/mention", {
2763
+ agentName,
2764
+ message,
2765
+ config
2766
+ });
2767
+ }
2768
+ async listQuests() {
2769
+ return this.apiClient.get("/api/tavern/quests");
2770
+ }
2771
+ async postQuest(request) {
2772
+ return this.apiClient.post("/api/tavern/quests", request);
2773
+ }
2774
+ async deleteQuest(questId) {
2775
+ await this.apiClient.delete(`/api/tavern/quests`, { data: { questId } });
2776
+ }
2777
+ async getAgentNotebook(agentId, limit = 50) {
2778
+ return this.apiClient.get(`/api/tavern/agent-notebook?agentId=${agentId}&limit=${limit}`);
2779
+ }
2780
+ async listGates() {
2781
+ return this.apiClient.get("/api/tavern/gates");
2782
+ }
2783
+ async resolveGate(gateId, resolution) {
2784
+ return this.apiClient.post("/api/tavern/gate-resolve", {
2785
+ gateId,
2786
+ resolution
2787
+ });
2788
+ }
2789
+ async toggleHeartbeats(enabled) {
2790
+ return this.apiClient.post("/api/tavern/toggle-heartbeats", { enabled });
2791
+ }
2792
+ async triggerHeartbeat(config) {
2793
+ return this.apiClient.post("/api/tavern/trigger-heartbeat", { config });
2794
+ }
2795
+ async abortHeartbeats() {
2796
+ await this.apiClient.post("/api/tavern/abort-heartbeats", { abort: true });
2797
+ }
2798
+ };
2799
+
2800
+ // src/features/tavern/types.ts
2801
+ import { z } from "zod";
2802
+ var HeartbeatLogEntrySchema = z.object({
2803
+ id: z.string(),
2804
+ agentId: z.string(),
2805
+ agentName: z.string(),
2806
+ action: z.enum([
2807
+ "idle",
2808
+ "speech",
2809
+ "thought",
2810
+ "memory",
2811
+ "move",
2812
+ "reply",
2813
+ "post_quest",
2814
+ "claim_quest",
2815
+ "complete_quest",
2816
+ "tool_use",
2817
+ "email",
2818
+ "move_decoration",
2819
+ "gate_paused",
2820
+ "gate_timed",
2821
+ "gate_proceed",
2822
+ "yolo_override",
2823
+ "intent",
2824
+ "report",
2825
+ "credits"
2826
+ ]),
2827
+ text: z.string().optional(),
2828
+ toolOutput: z.string().optional(),
2829
+ targetAgentName: z.string().optional(),
2830
+ threadId: z.string().optional(),
2831
+ timestamp: z.string(),
2832
+ burstId: z.string().optional(),
2833
+ stepIndex: z.number().optional(),
2834
+ totalSteps: z.number().optional(),
2835
+ confidence: z.number().optional(),
2836
+ confidenceSource: z.string().optional(),
2837
+ creditsUsed: z.number().optional()
2838
+ });
2839
+ var AgentSummarySchema = z.object({
2840
+ _id: z.string(),
2841
+ name: z.string(),
2842
+ description: z.string().optional(),
2843
+ heartbeatConfig: z.object({
2844
+ enabled: z.boolean().optional()
2845
+ }).optional()
2846
+ });
2847
+ var AgentListResponseSchema = z.object({
2848
+ data: z.array(AgentSummarySchema),
2849
+ total: z.number().optional()
2850
+ });
2851
+ var MentionRequestSchema = z.object({
2852
+ agentName: z.string().optional(),
2853
+ message: z.string(),
2854
+ config: z.record(z.string(), z.unknown()).optional()
2855
+ });
2856
+ var DirectedMentionResponseSchema = z.object({
2857
+ success: z.boolean(),
2858
+ agentName: z.string(),
2859
+ agentId: z.string(),
2860
+ warning: z.string().optional()
2861
+ });
2862
+ var AmbientMentionResponseSchema = z.object({
2863
+ success: z.boolean(),
2864
+ mode: z.literal("ambient"),
2865
+ agentCount: z.number(),
2866
+ results: z.array(
2867
+ z.object({
2868
+ agentName: z.string(),
2869
+ status: z.string()
2870
+ })
2871
+ )
2872
+ });
2873
+ var MentionResponseSchema = z.union([DirectedMentionResponseSchema, AmbientMentionResponseSchema]);
2874
+ var TavernQuestSchema = z.object({
2875
+ _id: z.string(),
2876
+ title: z.string(),
2877
+ description: z.string().optional(),
2878
+ status: z.string(),
2879
+ postedBy: z.string(),
2880
+ claimedBy: z.string().optional(),
2881
+ difficulty: z.string().optional(),
2882
+ createdAt: z.string().optional(),
2883
+ updatedAt: z.string().optional()
2884
+ });
2885
+ var QuestListResponseSchema = z.object({
2886
+ quests: z.array(TavernQuestSchema)
2887
+ });
2888
+ var CreateQuestRequestSchema = z.object({
2889
+ title: z.string(),
2890
+ description: z.string().optional(),
2891
+ agentId: z.string(),
2892
+ agentName: z.string(),
2893
+ difficulty: z.enum(["easy", "medium", "hard", "epic"]).optional()
2894
+ });
2895
+ var QuestResponseSchema = z.object({
2896
+ quest: TavernQuestSchema
2897
+ });
2898
+ var NotebookEntrySchema = z.object({
2899
+ _id: z.string(),
2900
+ title: z.string().optional(),
2901
+ content: z.string().optional(),
2902
+ createdAt: z.string().optional()
2903
+ });
2904
+ var NotebookResponseSchema = z.object({
2905
+ sessionId: z.string().nullable(),
2906
+ entries: z.array(NotebookEntrySchema)
2907
+ });
2908
+ var TimedGateSchema = z.object({
2909
+ gateId: z.string(),
2910
+ agentId: z.string(),
2911
+ agentName: z.string(),
2912
+ userId: z.string(),
2913
+ confidence: z.number(),
2914
+ reason: z.string(),
2915
+ createdAt: z.number(),
2916
+ expiresAt: z.number(),
2917
+ delayMs: z.number(),
2918
+ status: z.enum(["pending", "approved", "rejected", "expired", "auto_proceeded"]),
2919
+ resolvedBy: z.enum(["human", "timer"]).optional(),
2920
+ resolvedAt: z.number().optional(),
2921
+ burstId: z.string(),
2922
+ iteration: z.number()
2923
+ });
2924
+ var GateListResponseSchema = z.object({
2925
+ gates: z.array(TimedGateSchema)
2926
+ });
2927
+ var GateResolveRequestSchema = z.object({
2928
+ gateId: z.string(),
2929
+ resolution: z.enum(["approve", "reject"])
2930
+ });
2931
+ var GateResolveResponseSchema = z.object({
2932
+ success: z.boolean(),
2933
+ gate: TimedGateSchema
2934
+ });
2935
+ var HeartbeatToggleResponseSchema = z.object({
2936
+ success: z.boolean(),
2937
+ enabled: z.boolean(),
2938
+ agentCount: z.number()
2939
+ });
2940
+ var TriggerHeartbeatResponseSchema = z.object({
2941
+ triggered: z.number(),
2942
+ results: z.array(
2943
+ z.object({
2944
+ agentId: z.string(),
2945
+ agentName: z.string(),
2946
+ status: z.string(),
2947
+ error: z.string().optional()
2948
+ })
2949
+ )
2950
+ });
2951
+
2952
+ // src/features/tavern/TavernActivityStream.ts
2953
+ var TavernActivityStream = class {
2954
+ constructor(onLogEntry) {
2955
+ this.onLogEntry = onLogEntry;
2956
+ this.wsManager = null;
2957
+ }
2958
+ /** Register the WS handler for tavern_heartbeat_log events */
2959
+ registerHandlers(wsManager) {
2960
+ this.wsManager = wsManager;
2961
+ wsManager.onAction("tavern_heartbeat_log", (message) => {
2962
+ const parsed = message;
2963
+ if (!parsed.entry) return;
2964
+ const result = HeartbeatLogEntrySchema.safeParse(parsed.entry);
2965
+ if (result.success) {
2966
+ this.onLogEntry(result.data);
2967
+ }
2968
+ });
2969
+ }
2970
+ /** Unsubscribe from WS events */
2971
+ dispose() {
2972
+ if (this.wsManager) {
2973
+ this.wsManager.offAction("tavern_heartbeat_log");
2974
+ this.wsManager = null;
2975
+ }
2976
+ }
2977
+ };
2978
+
2979
+ // src/features/tavern/tavernTools.ts
2980
+ function createTavernTools(service) {
2981
+ return [
2982
+ createListAgentsTool(service),
2983
+ createMentionTool(service),
2984
+ createListQuestsTool(service),
2985
+ createPostQuestTool(service),
2986
+ createDeleteQuestTool(service),
2987
+ createReadNotebookTool(service),
2988
+ createListGatesTool(service),
2989
+ createResolveGateTool(service),
2990
+ createToggleHeartbeatsTool(service),
2991
+ createTriggerHeartbeatTool(service),
2992
+ createAbortHeartbeatsTool(service)
2993
+ ];
2994
+ }
2995
+ function createListAgentsTool(service) {
2996
+ return {
2997
+ toolSchema: {
2998
+ name: "tavern_list_agents",
2999
+ description: "List all Tavern agents with their IDs, names, descriptions, and heartbeat status. Use this FIRST to discover agent IDs before using tools that require an agent_id (like tavern_read_notebook or tavern_post_quest).",
3000
+ parameters: {
3001
+ type: "object",
3002
+ properties: {}
3003
+ }
3004
+ },
3005
+ toolFn: async () => {
3006
+ const result = await service.listAgents();
3007
+ return JSON.stringify(result);
3008
+ }
3009
+ };
3010
+ }
3011
+ function createMentionTool(service) {
3012
+ return {
3013
+ toolSchema: {
3014
+ name: "tavern_mention",
3015
+ description: "Send a message to a specific Tavern agent by name, or broadcast an ambient message to all agents if no agent_name is provided. Use this to talk to agents, ask them questions, give them instructions, or announce something to the whole tavern.",
3016
+ parameters: {
3017
+ type: "object",
3018
+ properties: {
3019
+ agent_name: {
3020
+ type: "string",
3021
+ description: "Name of the agent to mention (omit for ambient broadcast to all agents)"
3022
+ },
3023
+ message: {
3024
+ type: "string",
3025
+ description: "The message to send to the agent(s)"
3026
+ }
3027
+ },
3028
+ required: ["message"]
3029
+ }
3030
+ },
3031
+ toolFn: async (params) => {
3032
+ const { agent_name, message } = params;
3033
+ const result = await service.mentionAgent(agent_name, message);
3034
+ return JSON.stringify(result);
3035
+ }
3036
+ };
3037
+ }
3038
+ function createListQuestsTool(service) {
3039
+ return {
3040
+ toolSchema: {
3041
+ name: "tavern_list_quests",
3042
+ description: "List all quests on the Tavern quest board. Shows quest title, status, who posted it, and who claimed it.",
3043
+ parameters: {
3044
+ type: "object",
3045
+ properties: {}
3046
+ }
3047
+ },
3048
+ toolFn: async () => {
3049
+ const result = await service.listQuests();
3050
+ return JSON.stringify(result);
3051
+ }
3052
+ };
3053
+ }
3054
+ function createPostQuestTool(service) {
3055
+ return {
3056
+ toolSchema: {
3057
+ name: "tavern_post_quest",
3058
+ description: "Post a new quest to the Tavern quest board for agents to discover and claim.",
3059
+ parameters: {
3060
+ type: "object",
3061
+ properties: {
3062
+ title: {
3063
+ type: "string",
3064
+ description: "Quest title"
3065
+ },
3066
+ description: {
3067
+ type: "string",
3068
+ description: "Detailed quest description"
3069
+ },
3070
+ agent_id: {
3071
+ type: "string",
3072
+ description: "ID of the agent posting the quest"
3073
+ },
3074
+ agent_name: {
3075
+ type: "string",
3076
+ description: "Name of the agent posting the quest"
3077
+ },
3078
+ difficulty: {
3079
+ type: "string",
3080
+ description: "Quest difficulty level",
3081
+ enum: ["easy", "medium", "hard", "epic"]
3082
+ }
3083
+ },
3084
+ required: ["title", "agent_id", "agent_name"]
3085
+ }
3086
+ },
3087
+ toolFn: async (params) => {
3088
+ const raw = params;
3089
+ const request = CreateQuestRequestSchema.parse({
3090
+ title: raw.title,
3091
+ description: raw.description,
3092
+ agentId: raw.agent_id,
3093
+ agentName: raw.agent_name,
3094
+ difficulty: raw.difficulty
3095
+ });
3096
+ const result = await service.postQuest(request);
3097
+ return JSON.stringify(result);
3098
+ }
3099
+ };
3100
+ }
3101
+ function createDeleteQuestTool(service) {
3102
+ return {
3103
+ toolSchema: {
3104
+ name: "tavern_delete_quest",
3105
+ description: "Remove a quest from the Tavern quest board by its ID.",
3106
+ parameters: {
3107
+ type: "object",
3108
+ properties: {
3109
+ quest_id: {
3110
+ type: "string",
3111
+ description: "The ID of the quest to delete"
3112
+ }
3113
+ },
3114
+ required: ["quest_id"]
3115
+ }
3116
+ },
3117
+ toolFn: async (params) => {
3118
+ const { quest_id } = params;
3119
+ await service.deleteQuest(quest_id);
3120
+ return JSON.stringify({ success: true });
3121
+ }
3122
+ };
3123
+ }
3124
+ function createReadNotebookTool(service) {
3125
+ return {
3126
+ toolSchema: {
3127
+ name: "tavern_read_notebook",
3128
+ description: `Read a Tavern agent's activity notebook/history. Shows their recent actions, thoughts, conversations, and quest progress. IMPORTANT: agent_id must be a MongoDB ObjectId (e.g. "6540b58d1f703ade3ea1e82b"), NOT the agent name. Use tavern_list_agents first to get the correct ID.`,
3129
+ parameters: {
3130
+ type: "object",
3131
+ properties: {
3132
+ agent_id: {
3133
+ type: "string",
3134
+ description: "The MongoDB ObjectId of the agent (get this from tavern_list_agents, NOT the agent name)"
3135
+ },
3136
+ limit: {
3137
+ type: "number",
3138
+ description: "Maximum number of entries to return (default: 50)"
3139
+ }
3140
+ },
3141
+ required: ["agent_id"]
3142
+ }
3143
+ },
3144
+ toolFn: async (params) => {
3145
+ const { agent_id, limit } = params;
3146
+ const result = await service.getAgentNotebook(agent_id, limit);
3147
+ return JSON.stringify(result);
3148
+ }
3149
+ };
3150
+ }
3151
+ function createListGatesTool(service) {
3152
+ return {
3153
+ toolSchema: {
3154
+ name: "tavern_list_gates",
3155
+ description: "List all pending confidence gates in the Tavern. Gates are pause points where agents need human approval to proceed with low-confidence actions.",
3156
+ parameters: {
3157
+ type: "object",
3158
+ properties: {}
3159
+ }
3160
+ },
3161
+ toolFn: async () => {
3162
+ const result = await service.listGates();
3163
+ return JSON.stringify(result);
3164
+ }
3165
+ };
3166
+ }
3167
+ function createResolveGateTool(service) {
3168
+ return {
3169
+ toolSchema: {
3170
+ name: "tavern_resolve_gate",
3171
+ description: "Approve or reject a pending confidence gate. This lets an agent proceed or stops its current action.",
3172
+ parameters: {
3173
+ type: "object",
3174
+ properties: {
3175
+ gate_id: {
3176
+ type: "string",
3177
+ description: "The ID of the gate to resolve"
3178
+ },
3179
+ resolution: {
3180
+ type: "string",
3181
+ description: "Whether to approve or reject the gate",
3182
+ enum: ["approve", "reject"]
3183
+ }
3184
+ },
3185
+ required: ["gate_id", "resolution"]
3186
+ }
3187
+ },
3188
+ toolFn: async (params) => {
3189
+ const { gate_id, resolution } = params;
3190
+ const result = await service.resolveGate(gate_id, resolution);
3191
+ return JSON.stringify(result);
3192
+ }
3193
+ };
3194
+ }
3195
+ function createToggleHeartbeatsTool(service) {
3196
+ return {
3197
+ toolSchema: {
3198
+ name: "tavern_toggle_heartbeats",
3199
+ description: "Enable or disable background heartbeats for all Tavern agents. When enabled, agents autonomously think, act, and interact on a schedule.",
3200
+ parameters: {
3201
+ type: "object",
3202
+ properties: {
3203
+ enabled: {
3204
+ type: "boolean",
3205
+ description: "true to enable heartbeats, false to disable"
3206
+ }
3207
+ },
3208
+ required: ["enabled"]
3209
+ }
3210
+ },
3211
+ toolFn: async (params) => {
3212
+ const { enabled } = params;
3213
+ const result = await service.toggleHeartbeats(enabled);
3214
+ return JSON.stringify(result);
3215
+ }
3216
+ };
3217
+ }
3218
+ function createTriggerHeartbeatTool(service) {
3219
+ return {
3220
+ toolSchema: {
3221
+ name: "tavern_trigger_heartbeat",
3222
+ description: "Manually trigger a heartbeat cycle for all Tavern agents. Useful for testing or forcing immediate agent activity.",
3223
+ parameters: {
3224
+ type: "object",
3225
+ properties: {
3226
+ config: {
3227
+ type: "object",
3228
+ description: "Optional configuration overrides for the heartbeat (e.g. preferredModelId, costMode)",
3229
+ additionalProperties: true
3230
+ }
3231
+ }
3232
+ }
3233
+ },
3234
+ toolFn: async (params) => {
3235
+ const { config } = params ?? {};
3236
+ const result = await service.triggerHeartbeat(config);
3237
+ return JSON.stringify(result);
3238
+ }
3239
+ };
3240
+ }
3241
+ function createAbortHeartbeatsTool(service) {
3242
+ return {
3243
+ toolSchema: {
3244
+ name: "tavern_abort_heartbeats",
3245
+ description: "Emergency stop \u2014 abort all in-flight Tavern agent heartbeats immediately.",
3246
+ parameters: {
3247
+ type: "object",
3248
+ properties: {}
3249
+ }
3250
+ },
3251
+ toolFn: async () => {
3252
+ await service.abortHeartbeats();
3253
+ return JSON.stringify({ success: true, message: "All in-flight heartbeats aborted" });
3254
+ }
3255
+ };
3256
+ }
3257
+
3258
+ // src/features/tavern/TavernModule.ts
3259
+ var TavernModule = class {
3260
+ constructor(apiClient, onLogEntry) {
3261
+ this.name = "tavern";
3262
+ this.description = "Interact with autonomous AI agents in the B4M Tavern";
3263
+ this.service = new TavernService(apiClient);
3264
+ this.activityStream = new TavernActivityStream(onLogEntry);
3265
+ }
3266
+ getTools() {
3267
+ return createTavernTools(this.service);
3268
+ }
3269
+ getSystemPromptSection() {
3270
+ return `## Tavern Integration
3271
+ You can interact with autonomous AI agents in the B4M Tavern using tavern_* tools.
3272
+
3273
+ IMPORTANT: Many tools require agent IDs (MongoDB ObjectIds like "6540b58d1f703ade3ea1e82b"). Always use tavern_list_agents FIRST to discover agent names and their IDs before using tools that need an agent_id.
3274
+
3275
+ Available actions:
3276
+ - **tavern_list_agents**: List all agents with their IDs, names, and status \u2014 USE THIS FIRST
3277
+ - **tavern_mention**: Talk to a specific agent by name or broadcast to all agents
3278
+ - **tavern_list_quests**: View the quest board
3279
+ - **tavern_post_quest**: Post a new quest for agents to claim
3280
+ - **tavern_delete_quest**: Remove a quest from the board
3281
+ - **tavern_read_notebook**: Read an agent's activity history (requires agent ID from tavern_list_agents)
3282
+ - **tavern_list_gates**: See pending confidence gates awaiting human approval
3283
+ - **tavern_resolve_gate**: Approve or reject a confidence gate
3284
+ - **tavern_toggle_heartbeats**: Enable/disable agent background heartbeats
3285
+ - **tavern_trigger_heartbeat**: Manually trigger a heartbeat cycle
3286
+ - **tavern_abort_heartbeats**: Emergency stop all in-flight heartbeats
3287
+
3288
+ When the user mentions talking to agents, checking the quest board, or managing the tavern, use these tools.
3289
+ Agents have personalities, moods, quests, and memories \u2014 they are autonomous entities, not chatbots.`;
3290
+ }
3291
+ registerWsHandlers(wsManager) {
3292
+ this.activityStream.registerHandlers(wsManager);
3293
+ }
3294
+ dispose() {
3295
+ this.activityStream.dispose();
3296
+ }
3297
+ };
3298
+
2684
3299
  // src/index.tsx
2685
3300
  process.removeAllListeners("warning");
2686
3301
  process.on("warning", (warning) => {
@@ -2720,7 +3335,8 @@ function CliApp() {
2720
3335
  sandboxOrchestrator: null,
2721
3336
  wsManager: null,
2722
3337
  checkpointStore: null,
2723
- additionalDirectories: []
3338
+ additionalDirectories: [],
3339
+ featureRegistry: null
2724
3340
  });
2725
3341
  const [isInitialized, setIsInitialized] = useState12(false);
2726
3342
  const [initError, setInitError] = useState12(null);
@@ -2750,6 +3366,9 @@ function CliApp() {
2750
3366
  })
2751
3367
  );
2752
3368
  }
3369
+ if (state.featureRegistry) {
3370
+ state.featureRegistry.disposeAll();
3371
+ }
2753
3372
  if (state.wsManager) {
2754
3373
  state.wsManager.disconnect();
2755
3374
  setWebSocketToolExecutor(null);
@@ -2772,7 +3391,15 @@ function CliApp() {
2772
3391
  setTimeout(() => {
2773
3392
  process.exit(0);
2774
3393
  }, 100);
2775
- }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
3394
+ }, [
3395
+ state.session,
3396
+ state.sessionStore,
3397
+ state.mcpManager,
3398
+ state.agent,
3399
+ state.imageStore,
3400
+ state.wsManager,
3401
+ state.featureRegistry
3402
+ ]);
2776
3403
  useInput10((input, key) => {
2777
3404
  if (key.escape) {
2778
3405
  const store = useCliStore.getState();
@@ -3199,6 +3826,21 @@ Pull a model: ollama pull qwen3.5`
3199
3826
  }) : null;
3200
3827
  const findDefinitionTool = createFindDefinitionTool();
3201
3828
  const getFileStructureTool = createGetFileStructureTool();
3829
+ const featureRegistry = new FeatureModuleRegistry();
3830
+ if (config.features?.tavern) {
3831
+ featureRegistry.register(
3832
+ new TavernModule(apiClient, (entry) => {
3833
+ useCliStore.getState().addTavernLogEntry(entry);
3834
+ })
3835
+ );
3836
+ }
3837
+ const featureModuleToolNames = featureRegistry.getAllToolNames();
3838
+ if (featureModuleToolNames.length > 0) {
3839
+ registerFeatureModuleTools(featureModuleToolNames);
3840
+ }
3841
+ if (wsManager && featureRegistry.hasModules) {
3842
+ featureRegistry.registerAllWsHandlers(wsManager);
3843
+ }
3202
3844
  const cliTools = [
3203
3845
  agentDelegateTool,
3204
3846
  ...backgroundTools,
@@ -3212,7 +3854,8 @@ Pull a model: ollama pull qwen3.5`
3212
3854
  if (dynamicAgentTool) {
3213
3855
  cliTools.push(dynamicAgentTool);
3214
3856
  }
3215
- const allTools = [...b4mTools, ...mcpTools, ...cliTools];
3857
+ const featureTools = featureRegistry.getAllTools();
3858
+ const allTools = [...b4mTools, ...mcpTools, ...cliTools, ...featureTools];
3216
3859
  startupLog.push(`\u{1F4C2} Working directory: ${process.cwd()}`);
3217
3860
  if (additionalDirectories.length > 0) {
3218
3861
  startupLog.push(`\u{1F4C1} Additional directories: ${additionalDirectories.length}`);
@@ -3228,8 +3871,12 @@ Pull a model: ollama pull qwen3.5`
3228
3871
  if (dynamicAgentTool) {
3229
3872
  startupLog.push(`\u{1F9EA} Dynamic agent creation enabled (experimental)`);
3230
3873
  }
3874
+ if (featureRegistry.hasModules) {
3875
+ const moduleNames = featureRegistry.getModuleNames().join(", ");
3876
+ startupLog.push(`\u{1F3F0} Feature modules: ${moduleNames} (${featureTools.length} tools)`);
3877
+ }
3231
3878
  logger.debug(
3232
- `Total tools available to agent: ${allTools.length} (${b4mTools.length} B4M + ${mcpTools.length} MCP + ${cliTools.length} CLI)`
3879
+ `Total tools available to agent: ${allTools.length} (${b4mTools.length} B4M + ${mcpTools.length} MCP + ${cliTools.length} CLI + ${featureTools.length} feature)`
3233
3880
  );
3234
3881
  if (contextResult.globalContext) {
3235
3882
  startupLog.push(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
@@ -3240,13 +3887,15 @@ Pull a model: ollama pull qwen3.5`
3240
3887
  for (const error of contextResult.errors) {
3241
3888
  startupLog.push(`\u26A0\uFE0F Context file error: ${error}`);
3242
3889
  }
3890
+ const featureModulePrompts = featureRegistry.getSystemPromptSections();
3243
3891
  const cliSystemPrompt = buildCoreSystemPrompt({
3244
3892
  contextContent: contextResult.mergedContent,
3245
3893
  agentStore,
3246
3894
  customCommands: state.customCommandStore.getAllCommands(),
3247
3895
  enableSkillTool,
3248
3896
  enableDynamicAgentCreation: config.preferences.enableDynamicAgentCreation === true,
3249
- additionalDirectories
3897
+ additionalDirectories,
3898
+ featureModulePrompts: featureModulePrompts || void 0
3250
3899
  });
3251
3900
  const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
3252
3901
  const agent = new ReActAgent({
@@ -3314,8 +3963,10 @@ Pull a model: ollama pull qwen3.5`
3314
3963
  // WebSocket connection manager (null if using SSE fallback)
3315
3964
  checkpointStore,
3316
3965
  // File change checkpointing for undo/restore
3317
- additionalDirectories
3966
+ additionalDirectories,
3318
3967
  // Store additional directories for file access
3968
+ featureRegistry
3969
+ // Feature module registry for opt-in modules
3319
3970
  }));
3320
3971
  setStoreSession(newSession);
3321
3972
  const bannerLines = [
@@ -3592,7 +4243,8 @@ Pull a model: ollama pull qwen3.5`
3592
4243
  agentStore: state.agentStore || void 0,
3593
4244
  customCommands: state.customCommandStore.getAllCommands(),
3594
4245
  enableSkillTool: config?.preferences.enableSkillTool !== false,
3595
- additionalDirectories: state.additionalDirectories
4246
+ additionalDirectories: state.additionalDirectories,
4247
+ featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
3596
4248
  });
3597
4249
  const contextUsage = tokenCounter2.countSessionTokens(activeSession, systemPrompt);
3598
4250
  if (contextUsage.totalTokens >= threshold) {
@@ -4647,7 +5299,8 @@ No usage data available for the last ${USAGE_DAYS} days.`);
4647
5299
  agentStore: state.agentStore || void 0,
4648
5300
  customCommands: commands,
4649
5301
  enableSkillTool: state.config?.preferences.enableSkillTool !== false,
4650
- additionalDirectories: state.additionalDirectories
5302
+ additionalDirectories: state.additionalDirectories,
5303
+ featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
4651
5304
  });
4652
5305
  const usage = tokenCounter2.countSessionTokens(state.session, systemPrompt);
4653
5306
  const totalWithTools = usage.totalTokens + mcpToolsTokens;
@@ -5203,7 +5856,56 @@ Allowed domains (${domains.length}):`);
5203
5856
  const handleSaveConfig = async (updatedConfig) => {
5204
5857
  await state.configStore.save(updatedConfig);
5205
5858
  const modelChanged = state.config?.defaultModel !== updatedConfig.defaultModel;
5859
+ const featuresChanged = JSON.stringify(state.config?.features ?? {}) !== JSON.stringify(updatedConfig.features ?? {});
5860
+ let newFeatureRegistry = state.featureRegistry;
5861
+ if (featuresChanged && state.agent) {
5862
+ state.featureRegistry?.disposeAll();
5863
+ clearFeatureModuleTools();
5864
+ newFeatureRegistry = new FeatureModuleRegistry();
5865
+ const apiClient = new ApiClient(getApiUrl(updatedConfig.apiConfig), state.configStore);
5866
+ if (updatedConfig.features?.tavern) {
5867
+ newFeatureRegistry.register(
5868
+ new TavernModule(apiClient, (entry) => {
5869
+ useCliStore.getState().addTavernLogEntry(entry);
5870
+ })
5871
+ );
5872
+ }
5873
+ const newToolNames = newFeatureRegistry.getAllToolNames();
5874
+ if (newToolNames.length > 0) {
5875
+ registerFeatureModuleTools(newToolNames);
5876
+ }
5877
+ if (state.wsManager && newFeatureRegistry.hasModules) {
5878
+ newFeatureRegistry.registerAllWsHandlers(state.wsManager);
5879
+ }
5880
+ const agentContext = state.agent.context;
5881
+ const oldFeatureToolNames = new Set(state.featureRegistry?.getAllToolNames() ?? []);
5882
+ const baseTools = agentContext.tools.filter((t) => !oldFeatureToolNames.has(t.toolSchema.name));
5883
+ const newFeatureTools = newFeatureRegistry.getAllTools();
5884
+ agentContext.tools = [...baseTools, ...newFeatureTools];
5885
+ const newFeaturePrompts = newFeatureRegistry.getSystemPromptSections();
5886
+ agentContext.systemPrompt = buildCoreSystemPrompt({
5887
+ contextContent: state.contextContent,
5888
+ agentStore: state.agentStore || void 0,
5889
+ customCommands: state.customCommandStore.getAllCommands(),
5890
+ enableSkillTool: updatedConfig.preferences.enableSkillTool !== false,
5891
+ enableDynamicAgentCreation: updatedConfig.preferences.enableDynamicAgentCreation === true,
5892
+ additionalDirectories: state.additionalDirectories,
5893
+ featureModulePrompts: newFeaturePrompts || void 0
5894
+ });
5895
+ const moduleNames = newFeatureRegistry.getModuleNames();
5896
+ if (moduleNames.length > 0) {
5897
+ console.error(`
5898
+ \x1B[36m\u{1F3F0} Feature modules hot-reloaded: ${moduleNames.join(", ")}\x1B[0m`);
5899
+ } else {
5900
+ console.error(`
5901
+ \x1B[36m\u{1F3F0} Feature modules disabled\x1B[0m`);
5902
+ }
5903
+ }
5206
5904
  setState((prev) => {
5905
+ const updates = { config: updatedConfig };
5906
+ if (featuresChanged) {
5907
+ updates.featureRegistry = newFeatureRegistry;
5908
+ }
5207
5909
  if (modelChanged && prev.session) {
5208
5910
  const updatedSession = {
5209
5911
  ...prev.session,
@@ -5214,9 +5916,9 @@ Allowed domains (${domains.length}):`);
5214
5916
  if (prev.agent) {
5215
5917
  prev.agent.context.model = updatedConfig.defaultModel;
5216
5918
  }
5217
- return { ...prev, config: updatedConfig, session: updatedSession };
5919
+ return { ...prev, ...updates, session: updatedSession };
5218
5920
  }
5219
- return { ...prev, config: updatedConfig };
5921
+ return { ...prev, ...updates };
5220
5922
  });
5221
5923
  if (modelChanged && state.agent) {
5222
5924
  const backend = state.agent.context.llm;
@@ -3,7 +3,7 @@ import {
3
3
  selectActiveBackgroundAgents,
4
4
  selectCompletedBackgroundAgents,
5
5
  useCliStore
6
- } from "./chunk-G2LYCVZJ.js";
6
+ } from "./chunk-Y4WOJJM3.js";
7
7
  export {
8
8
  selectActiveBackgroundAgents,
9
9
  selectCompletedBackgroundAgents,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.55",
3
+ "version": "0.2.56-feat-cli-tavern-integration.21361+2f1552bbd",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -70,6 +70,7 @@
70
70
  "diff": "^8.0.2",
71
71
  "dotenv": "^17.0.0",
72
72
  "eventsource-parser": "^3.0.6",
73
+ "exceljs": "^4.4.0",
73
74
  "fdir": "^6.5.0",
74
75
  "file-type": "^18.7.0",
75
76
  "fuse.js": "^7.1.0",
@@ -114,11 +115,11 @@
114
115
  "zustand": "^4.5.4"
115
116
  },
116
117
  "devDependencies": {
117
- "@bike4mind/agents": "0.2.1",
118
- "@bike4mind/common": "2.70.1",
119
- "@bike4mind/mcp": "1.33.15",
120
- "@bike4mind/services": "2.64.3",
121
- "@bike4mind/utils": "2.15.9",
118
+ "@bike4mind/agents": "0.2.2-feat-cli-tavern-integration.21361+2f1552bbd",
119
+ "@bike4mind/common": "2.70.2-feat-cli-tavern-integration.21361+2f1552bbd",
120
+ "@bike4mind/mcp": "1.33.16-feat-cli-tavern-integration.21361+2f1552bbd",
121
+ "@bike4mind/services": "2.64.4-feat-cli-tavern-integration.21361+2f1552bbd",
122
+ "@bike4mind/utils": "2.15.10-feat-cli-tavern-integration.21361+2f1552bbd",
122
123
  "@types/better-sqlite3": "^7.6.13",
123
124
  "@types/jsonwebtoken": "^9.0.4",
124
125
  "@types/node": "^22.9.0",
@@ -135,5 +136,5 @@
135
136
  "optionalDependencies": {
136
137
  "@vscode/ripgrep": "^1.17.1"
137
138
  },
138
- "gitHead": "dfc4dccb344f081dd2c87bc16fb2d27f70c02844"
139
+ "gitHead": "2f1552bbd1fd89923637cbcf2a6e40b729437a2d"
139
140
  }