@bike4mind/cli 0.2.75 → 0.2.76-chore-upgrade-mathjs-v15.22376

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.
@@ -340,7 +340,8 @@ const b4mLLMTools = z.enum([
340
340
  "quantum_formulate",
341
341
  "navigate_view",
342
342
  "generate_jupyter_notebook",
343
- "excel_generation"
343
+ "excel_generation",
344
+ "fmp_financial_data"
344
345
  ]);
345
346
  b4mLLMTools.options.map((tool) => tool);
346
347
  /**
@@ -1853,6 +1854,24 @@ const TavernQuestUpdateAction = z.object({
1853
1854
  expiresAt: z.string().optional()
1854
1855
  }))
1855
1856
  });
1857
+ /** Server → Client: real-time stock portfolio update for the Stock Corner */
1858
+ const TavernStockUpdateAction = z.object({
1859
+ action: z.literal("tavern_stock_update"),
1860
+ portfolios: z.array(z.object({
1861
+ agentId: z.string(),
1862
+ agentName: z.string(),
1863
+ cashBalance: z.number(),
1864
+ holdings: z.array(z.object({
1865
+ symbol: z.string(),
1866
+ shares: z.number(),
1867
+ avgCostBasis: z.number(),
1868
+ currentPrice: z.number(),
1869
+ currentValue: z.number(),
1870
+ unrealizedPnL: z.number()
1871
+ })),
1872
+ totalValue: z.number()
1873
+ }))
1874
+ });
1856
1875
  const SessionCreatedAction = shareableDocumentSchema.extend({
1857
1876
  action: z.literal("session.created"),
1858
1877
  id: z.string(),
@@ -1938,6 +1957,7 @@ z.discriminatedUnion("action", [
1938
1957
  TavernSceneBroadcastAction,
1939
1958
  TavernHeartbeatLogAction,
1940
1959
  TavernQuestUpdateAction,
1960
+ TavernStockUpdateAction,
1941
1961
  JupyterNotebookProgressAction,
1942
1962
  DataLakeBatchProgressAction
1943
1963
  ]);
@@ -2774,6 +2794,8 @@ z.enum([
2774
2794
  "OpenWeatherKey",
2775
2795
  "SerperKey",
2776
2796
  "WolframAlphaKey",
2797
+ "FmpApiKey",
2798
+ "EnableFmpFinancialData",
2777
2799
  "VectorThreshold",
2778
2800
  "bflApiKey",
2779
2801
  "EnableMCPServer",
@@ -3525,13 +3547,20 @@ const API_SERVICE_GROUPS = {
3525
3547
  name: "Search & Compute",
3526
3548
  description: "Search and computational API integration settings",
3527
3549
  icon: "Search",
3528
- settings: [{
3529
- key: "SerperKey",
3530
- order: 1
3531
- }, {
3532
- key: "WolframAlphaKey",
3533
- order: 2
3534
- }]
3550
+ settings: [
3551
+ {
3552
+ key: "SerperKey",
3553
+ order: 1
3554
+ },
3555
+ {
3556
+ key: "WolframAlphaKey",
3557
+ order: 2
3558
+ },
3559
+ {
3560
+ key: "FmpApiKey",
3561
+ order: 3
3562
+ }
3563
+ ]
3535
3564
  },
3536
3565
  CALENDAR: {
3537
3566
  id: "calendarAPIService",
@@ -3706,6 +3735,10 @@ const API_SERVICE_GROUPS = {
3706
3735
  {
3707
3736
  key: "EnableQuantumCanvasser",
3708
3737
  order: 21
3738
+ },
3739
+ {
3740
+ key: "EnableFmpFinancialData",
3741
+ order: 22
3709
3742
  }
3710
3743
  ]
3711
3744
  },
@@ -4457,6 +4490,23 @@ makeStringSetting({
4457
4490
  group: API_SERVICE_GROUPS.SEARCH.id,
4458
4491
  order: 2,
4459
4492
  isSensitive: true
4493
+ }), makeStringSetting({
4494
+ key: "FmpApiKey",
4495
+ name: "Financial Modeling Prep API Key",
4496
+ defaultValue: "",
4497
+ description: "API key for Financial Modeling Prep (stock quotes, company data, financial statements). Get one at financialmodelingprep.com.",
4498
+ category: "Tools",
4499
+ group: API_SERVICE_GROUPS.SEARCH.id,
4500
+ order: 3,
4501
+ isSensitive: true
4502
+ }), makeBooleanSetting({
4503
+ key: "EnableFmpFinancialData",
4504
+ name: "Enable Financial Data Tool",
4505
+ defaultValue: false,
4506
+ description: "Whether to enable the FMP Financial Data tool for stock quotes, company profiles, and financial statements in chat. Requires FmpApiKey to be set.",
4507
+ category: "Experimental",
4508
+ group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
4509
+ order: 13
4460
4510
  }), makeNumberSetting({
4461
4511
  key: "VectorThreshold",
4462
4512
  name: "Vector Threshold",
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as version, n as fetchLatestVersion, r as forceCheckForUpdate } from "../updateChecker-BnMv6QdE.mjs";
2
+ import { i as version, n as fetchLatestVersion, r as forceCheckForUpdate } from "../updateChecker-DMit6mGB.mjs";
3
3
  import { execSync } from "child_process";
4
4
  import { constants, existsSync, promises } from "fs";
5
5
  import { homedir } from "os";
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { B as CustomCommandStore, C as getApiUrl, E as generateCliTools, I as buildCoreSystemPrompt, P as setWebSocketToolExecutor, R as isReadOnlyTool, S as loadContextFiles, T as PermissionManager, U as SessionStore, V as CheckpointStore, _ as ServerLlmBackend, a as createBackgroundAgentTools, c as AgentStore, f as ApiClient, g as WebSocketLlmBackend, h as FallbackLlmBackend, i as createWriteTodosTool, l as SubagentOrchestrator, m as WebSocketConnectionManager, n as createFindDefinitionTool, o as BackgroundAgentManager, p as WebSocketToolExecutor, r as createTodoStore, s as createAgentDelegateTool, t as createGetFileStructureTool, u as createSkillTool, v as McpManager, z as ReActAgent } from "../tools-DM5Ig7rw.mjs";
3
- import { n as logger, t as ConfigStore } from "../ConfigStore-BZgsqS-3.mjs";
2
+ import { B as CustomCommandStore, C as getApiUrl, E as generateCliTools, I as buildCoreSystemPrompt, P as setWebSocketToolExecutor, R as isReadOnlyTool, S as loadContextFiles, T as PermissionManager, U as SessionStore, V as CheckpointStore, _ as ServerLlmBackend, a as createBackgroundAgentTools, c as AgentStore, f as ApiClient, g as WebSocketLlmBackend, h as FallbackLlmBackend, i as createWriteTodosTool, l as SubagentOrchestrator, m as WebSocketConnectionManager, n as createFindDefinitionTool, o as BackgroundAgentManager, p as WebSocketToolExecutor, r as createTodoStore, s as createAgentDelegateTool, t as createGetFileStructureTool, u as createSkillTool, v as McpManager, z as ReActAgent } from "../tools-w4bUHLiY.mjs";
3
+ import { n as logger, t as ConfigStore } from "../ConfigStore-D-dq6dND.mjs";
4
4
  import { t as DEFAULT_SANDBOX_CONFIG } from "../types-DBEjF9YS.mjs";
5
5
  import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-C1B4t20N.mjs";
6
6
  import { t as SandboxOrchestrator } from "../SandboxOrchestrator-BEW3rqYi.mjs";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-BZgsqS-3.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-D-dq6dND.mjs";
3
3
  //#region src/commands/mcpCommand.ts
4
4
  /**
5
5
  * External MCP commands (b4m mcp list, b4m mcp add, etc.)
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as version, r as forceCheckForUpdate } from "../updateChecker-BnMv6QdE.mjs";
2
+ import { i as version, r as forceCheckForUpdate } from "../updateChecker-DMit6mGB.mjs";
3
3
  import { execSync } from "child_process";
4
4
  //#region src/commands/updateCommand.ts
5
5
  /**
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-Dw1nZX2Y.mjs";
3
- import { A as DEFAULT_RETRY_CONFIG, B as CustomCommandStore, C as getApiUrl, D as ALWAYS_DENIED_FOR_AGENTS, E as generateCliTools, F as OllamaBackend, G as hasFileReferences, H as CommandHistoryStore, I as buildCoreSystemPrompt, J as mergeCommands, K as processFileReferences, L as buildSkillsPromptSection, M as clearFeatureModuleTools, N as registerFeatureModuleTools, O as DEFAULT_AGENT_MODEL, P as setWebSocketToolExecutor, R as isReadOnlyTool, S as loadContextFiles, T as PermissionManager, U as SessionStore, V as CheckpointStore, W as OAuthClient, X as searchFiles, Y as formatFileSize, Z as warmFileCache, _ as ServerLlmBackend, a as createBackgroundAgentTools, b as formatStep, c as AgentStore, d as parseAgentConfig, f as ApiClient, g as WebSocketLlmBackend, h as FallbackLlmBackend, i as createWriteTodosTool, j as DEFAULT_THOROUGHNESS, k as DEFAULT_MAX_ITERATIONS, l as SubagentOrchestrator, m as WebSocketConnectionManager, n as createFindDefinitionTool, o as BackgroundAgentManager, p as WebSocketToolExecutor, q as searchCommands, r as createTodoStore, s as createAgentDelegateTool, t as createGetFileStructureTool, u as createSkillTool, v as McpManager, w as getEnvironmentName, x as extractCompactInstructions, y as substituteArguments, z as ReActAgent } from "./tools-DM5Ig7rw.mjs";
4
- import { Dt as validateJupyterKernelName, Ot as validateNotebookPath$1, g as ChatModels, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-BZgsqS-3.mjs";
5
- import { i as version, t as checkForUpdate } from "./updateChecker-BnMv6QdE.mjs";
3
+ import { A as DEFAULT_RETRY_CONFIG, B as CustomCommandStore, C as getApiUrl, D as ALWAYS_DENIED_FOR_AGENTS, E as generateCliTools, F as OllamaBackend, G as hasFileReferences, H as CommandHistoryStore, I as buildCoreSystemPrompt, J as mergeCommands, K as processFileReferences, L as buildSkillsPromptSection, M as clearFeatureModuleTools, N as registerFeatureModuleTools, O as DEFAULT_AGENT_MODEL, P as setWebSocketToolExecutor, R as isReadOnlyTool, S as loadContextFiles, T as PermissionManager, U as SessionStore, V as CheckpointStore, W as OAuthClient, X as searchFiles, Y as formatFileSize, Z as warmFileCache, _ as ServerLlmBackend, a as createBackgroundAgentTools, b as formatStep, c as AgentStore, d as parseAgentConfig, f as ApiClient, g as WebSocketLlmBackend, h as FallbackLlmBackend, i as createWriteTodosTool, j as DEFAULT_THOROUGHNESS, k as DEFAULT_MAX_ITERATIONS, l as SubagentOrchestrator, m as WebSocketConnectionManager, n as createFindDefinitionTool, o as BackgroundAgentManager, p as WebSocketToolExecutor, q as searchCommands, r as createTodoStore, s as createAgentDelegateTool, t as createGetFileStructureTool, u as createSkillTool, v as McpManager, w as getEnvironmentName, x as extractCompactInstructions, y as substituteArguments, z as ReActAgent } from "./tools-w4bUHLiY.mjs";
4
+ import { Dt as validateJupyterKernelName, Ot as validateNotebookPath$1, g as ChatModels, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-D-dq6dND.mjs";
5
+ import { i as version, t as checkForUpdate } from "./updateChecker-DMit6mGB.mjs";
6
6
  import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
7
7
  import { Box, Static, Text, render, useApp, useInput } from "ink";
8
8
  import { execSync } from "child_process";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as RegInviteEvents, A as ImageGenerationUsageTransaction, B as OpenAIEmbeddingModel, C as FileEvents, Ct as getViewById, D as GenericCreditAddTransaction, E as GenerateImageToolCallSchema, Et as sanitizeTelemetryError, F as KnowledgeType, G as ProjectEvents, H as Permission, I as LLMEvents, J as QuestMasterParamsSchema, K as PromptMetaZodSchema, L as MiscEvents, M as InboxEvents, N as InviteEvents, O as GenericCreditDeductTransaction, P as InviteType, Q as RechartsChartTypeList, R as ModalEvents, S as FeedbackEvents, St as getMcpProviderMetadata, T as GEMINI_IMAGE_MODELS, Tt as resolveNavigationIntents, U as PermissionDeniedError, V as OpenAIImageGenerationInput, W as ProfileEvents, X as RealtimeVoiceUsageTransaction, Y as REASONING_SUPPORTED_MODELS, Z as ReceivedCreditTransaction, _ as CompletionApiUsageTransaction, _t as VoyageAIEmbeddingModel, a as ApiKeyEvents, at as SpeechToTextModels, b as FIXED_TEMPERATURE_MODELS, bt as getAccessibleDataLakes, c as AppFileEvents, ct as TagType, d as BFL_IMAGE_MODELS, dt as ToolUsageTransaction, et as ResearchModeParamsSchema, f as BFL_SAFETY_TOLERANCE, ft as TransferCreditTransaction, g as ChatModels, gt as VideoModels, h as ChatCompletionCreateInputSchema, ht as VideoGenerationUsageTransaction, i as AiEvents, it as SessionEvents, j as ImageModels, k as ImageEditUsageTransaction, kt as CollectionType, l as ArtifactTypeSchema, lt as TaskScheduleHandler, mt as VIDEO_SIZE_CONSTRAINTS, n as logger, nt as ResearchTaskPeriodicFrequencyType, o as ApiKeyScope, ot as SubscriptionCreditTransaction, p as BedrockEmbeddingModel, pt as UiNavigationEvents, q as PurchaseTransaction, r as ALERT_THRESHOLDS, rt as ResearchTaskType, s as ApiKeyType, st as SupportedFabFileMimeTypes, t as ConfigStore, tt as ResearchTaskExecutionType, u as AuthEvents, ut as TextGenerationUsageTransaction, v as DashboardParamsSchema, vt as XAI_IMAGE_MODELS, w as FriendshipEvents, wt as isGPTImageModel, x as FavoriteDocumentType, xt as getDataLakeTags, y as ElabsEvents, yt as b4mLLMTools, z as ModelBackend } from "./ConfigStore-BZgsqS-3.mjs";
2
+ import { $ as RegInviteEvents, A as ImageGenerationUsageTransaction, B as OpenAIEmbeddingModel, C as FileEvents, Ct as getViewById, D as GenericCreditAddTransaction, E as GenerateImageToolCallSchema, Et as sanitizeTelemetryError, F as KnowledgeType, G as ProjectEvents, H as Permission, I as LLMEvents, J as QuestMasterParamsSchema, K as PromptMetaZodSchema, L as MiscEvents, M as InboxEvents, N as InviteEvents, O as GenericCreditDeductTransaction, P as InviteType, Q as RechartsChartTypeList, R as ModalEvents, S as FeedbackEvents, St as getMcpProviderMetadata, T as GEMINI_IMAGE_MODELS, Tt as resolveNavigationIntents, U as PermissionDeniedError, V as OpenAIImageGenerationInput, W as ProfileEvents, X as RealtimeVoiceUsageTransaction, Y as REASONING_SUPPORTED_MODELS, Z as ReceivedCreditTransaction, _ as CompletionApiUsageTransaction, _t as VoyageAIEmbeddingModel, a as ApiKeyEvents, at as SpeechToTextModels, b as FIXED_TEMPERATURE_MODELS, bt as getAccessibleDataLakes, c as AppFileEvents, ct as TagType, d as BFL_IMAGE_MODELS, dt as ToolUsageTransaction, et as ResearchModeParamsSchema, f as BFL_SAFETY_TOLERANCE, ft as TransferCreditTransaction, g as ChatModels, gt as VideoModels, h as ChatCompletionCreateInputSchema, ht as VideoGenerationUsageTransaction, i as AiEvents, it as SessionEvents, j as ImageModels, k as ImageEditUsageTransaction, kt as CollectionType, l as ArtifactTypeSchema, lt as TaskScheduleHandler, mt as VIDEO_SIZE_CONSTRAINTS, n as logger, nt as ResearchTaskPeriodicFrequencyType, o as ApiKeyScope, ot as SubscriptionCreditTransaction, p as BedrockEmbeddingModel, pt as UiNavigationEvents, q as PurchaseTransaction, r as ALERT_THRESHOLDS, rt as ResearchTaskType, s as ApiKeyType, st as SupportedFabFileMimeTypes, t as ConfigStore, tt as ResearchTaskExecutionType, u as AuthEvents, ut as TextGenerationUsageTransaction, v as DashboardParamsSchema, vt as XAI_IMAGE_MODELS, w as FriendshipEvents, wt as isGPTImageModel, x as FavoriteDocumentType, xt as getDataLakeTags, y as ElabsEvents, yt as b4mLLMTools, z as ModelBackend } from "./ConfigStore-D-dq6dND.mjs";
3
3
  import { n as isPathAllowed, t as assertPathAllowed } from "./pathValidation-CIytuhr3-Dt5dntLx.mjs";
4
4
  import { execFile, execFileSync, spawn } from "child_process";
5
5
  import { createHash, randomBytes } from "crypto";
@@ -135,13 +135,13 @@ function formatFileSize$1(bytes) {
135
135
  }
136
136
  let cachedFiles = null;
137
137
  let cacheTimestamp = 0;
138
- const CACHE_TTL_MS = 3e4;
138
+ const CACHE_TTL_MS$1 = 3e4;
139
139
  /**
140
140
  * Get cached file list or refresh if stale
141
141
  */
142
142
  function getCachedFiles(projectRoot = process.cwd()) {
143
143
  const now = Date.now();
144
- if (!cachedFiles || now - cacheTimestamp > CACHE_TTL_MS) {
144
+ if (!cachedFiles || now - cacheTimestamp > CACHE_TTL_MS$1) {
145
145
  const normalizedBase = path$1.resolve(projectRoot);
146
146
  cachedFiles = crawlDirectory(normalizedBase, 10, 2e4, loadIgnoreRules(normalizedBase));
147
147
  cacheTimestamp = now;
@@ -153,7 +153,7 @@ function getCachedFiles(projectRoot = process.cwd()) {
153
153
  * Call this early (e.g., when InputPrompt mounts) to prevent lag on first @ usage
154
154
  */
155
155
  function warmFileCache() {
156
- if (!cachedFiles || Date.now() - cacheTimestamp > CACHE_TTL_MS) setImmediate(() => {
156
+ if (!cachedFiles || Date.now() - cacheTimestamp > CACHE_TTL_MS$1) setImmediate(() => {
157
157
  getCachedFiles();
158
158
  });
159
159
  }
@@ -5912,7 +5912,7 @@ z.object({
5912
5912
  userId: z.string()
5913
5913
  });
5914
5914
  //#endregion
5915
- //#region ../../b4m-core/services/dist/getEffective-DdXITYE5.mjs
5915
+ //#region ../../b4m-core/services/dist/getEffective-_iTNLa4a.mjs
5916
5916
  const getApiKeySchema = z.object({
5917
5917
  type: z.enum(ApiKeyType),
5918
5918
  nullIfMissing: z.boolean().optional(),
@@ -5948,6 +5948,10 @@ const getWolframAlphaKey = async (adapters) => {
5948
5948
  const { db } = adapters;
5949
5949
  return (await db.adminSettings.findBySettingName("WolframAlphaKey"))?.settingValue;
5950
5950
  };
5951
+ const getFmpApiKey = async (adapters) => {
5952
+ const { db } = adapters;
5953
+ return (await db.adminSettings.findBySettingName("FmpApiKey"))?.settingValue;
5954
+ };
5951
5955
  const getEffectiveApiKey = async (userId, params, adapters) => {
5952
5956
  const { db } = adapters;
5953
5957
  let key = (await getApiKey(userId, params, adapters))?.apiKey;
@@ -8134,7 +8138,7 @@ No markdown, no explanation, no code blocks — just the raw JSON object.`;
8134
8138
  "Minimize: sum(error^2)"
8135
8139
  ].join("\n");
8136
8140
  //#endregion
8137
- //#region ../../b4m-core/services/dist/tools-HKRu6bpe.mjs
8141
+ //#region ../../b4m-core/services/dist/tools-BNR-uSzM.mjs
8138
8142
  async function performDeepResearch(context, params, config) {
8139
8143
  const maxDepth = config.maxDepth || 7;
8140
8144
  const duration = config.duration || 4.5;
@@ -8721,7 +8725,7 @@ const imageGenerationTool = {
8721
8725
  })
8722
8726
  };
8723
8727
  const MAX_QUERY_LENGTH = 500;
8724
- const MAX_RESPONSE_SIZE = 5e4;
8728
+ const MAX_RESPONSE_SIZE$1 = 5e4;
8725
8729
  /**
8726
8730
  * Validates query parameters and returns an error message if invalid
8727
8731
  */
@@ -8775,7 +8779,7 @@ Try breaking compound queries into simpler steps, or send a concrete computation
8775
8779
  return `Wolfram Alpha error: ${response.statusText}`;
8776
8780
  }
8777
8781
  const result = await response.text();
8778
- const maxSize = Math.min(params.maxchars || MAX_RESPONSE_SIZE, MAX_RESPONSE_SIZE);
8782
+ const maxSize = Math.min(params.maxchars || MAX_RESPONSE_SIZE$1, MAX_RESPONSE_SIZE$1);
8779
8783
  const truncatedResult = result.slice(0, maxSize);
8780
8784
  logger?.log("✅ Wolfram Alpha: Query successful, response length:", truncatedResult.length);
8781
8785
  return truncatedResult || "No results from Wolfram Alpha.";
@@ -8840,6 +8844,7 @@ async function evaluateMath(params) {
8840
8844
  console.log("🔢 Math Tool: Starting evaluation of expression:", params.expression);
8841
8845
  try {
8842
8846
  let expression = params.expression.trim();
8847
+ expression = expression.replace(/\/\*[\s\S]*?\*\//g, "");
8843
8848
  expression = expression.replace(/\/\/[^\n]*/g, "");
8844
8849
  expression = expression.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).join("\n").replace(/;\s*$/, "");
8845
8850
  if (expression.includes(";")) {
@@ -12672,6 +12677,332 @@ function sanitizeFilename(filename) {
12672
12677
  if (!name) name = "spreadsheet";
12673
12678
  return name;
12674
12679
  }
12680
+ const excelGenerationTool = {
12681
+ name: "excel_generation",
12682
+ implementation: (context) => ({
12683
+ toolFn: async (value) => {
12684
+ const parseResult = ExcelGenerationParamsSchema.safeParse(value);
12685
+ if (!parseResult.success) {
12686
+ const errors = parseResult.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join("; ");
12687
+ throw new Error(`Invalid parameters: ${errors}`);
12688
+ }
12689
+ const params = parseResult.data;
12690
+ await context.statusUpdate({}, "Generating Excel file...");
12691
+ try {
12692
+ const buffer = await generateExcel(params);
12693
+ const sanitizedName = sanitizeFilename(params.filename);
12694
+ const filename = `${sanitizedName}-${v4().slice(0, 8)}.xlsx`;
12695
+ await context.imageGenerateStorage.upload(buffer, filename, {
12696
+ ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
12697
+ ContentDisposition: `attachment; filename="${sanitizedName}.xlsx"`
12698
+ });
12699
+ await context.onFinish?.("excel_generation", [filename]);
12700
+ await context.statusUpdate({ images: [filename] });
12701
+ return `Successfully generated Excel file: ${sanitizedName}.xlsx`;
12702
+ } catch (error) {
12703
+ context.logger.error("Excel generation failed:", error);
12704
+ throw new Error(`Failed to generate Excel file: ${error instanceof Error ? error.message : "Unknown error"}`);
12705
+ }
12706
+ },
12707
+ toolSchema: {
12708
+ name: "excel_generation",
12709
+ description: `Generate Excel (.xlsx) files with formatting. Supports: multiple sheets, formulas (SUM, AVERAGE, IF, etc.), styling (bold, colors, borders), number formats, merged cells, frozen panes. Limits: max ${LIMITS.MAX_SHEETS} sheets, ${LIMITS.MAX_CELLS_PER_SHEET} cells/sheet, rows 1-${LIMITS.MAX_ROW}, cols 1-${LIMITS.MAX_COL}.`,
12710
+ parameters: {
12711
+ type: "object",
12712
+ properties: {
12713
+ filename: {
12714
+ type: "string",
12715
+ description: "Name for the Excel file (without .xlsx extension)"
12716
+ },
12717
+ sheets: {
12718
+ type: "array",
12719
+ description: "Array of sheet definitions",
12720
+ items: {
12721
+ type: "object",
12722
+ properties: {
12723
+ name: {
12724
+ type: "string",
12725
+ description: "Sheet name (max 31 characters)"
12726
+ },
12727
+ data: {
12728
+ type: "array",
12729
+ description: "Cell data array",
12730
+ items: {
12731
+ type: "object",
12732
+ properties: {
12733
+ row: {
12734
+ type: "number",
12735
+ description: "1-indexed row number"
12736
+ },
12737
+ col: {
12738
+ type: "number",
12739
+ description: "1-indexed column number"
12740
+ },
12741
+ value: { description: "Cell value (string, number, boolean, or null)" },
12742
+ formula: {
12743
+ type: "string",
12744
+ description: "Excel formula (e.g., =SUM(A1:A10))"
12745
+ },
12746
+ style: {
12747
+ type: "object",
12748
+ description: "Cell styling options",
12749
+ properties: {
12750
+ bold: { type: "boolean" },
12751
+ italic: { type: "boolean" },
12752
+ fontSize: { type: "number" },
12753
+ fontColor: {
12754
+ type: "string",
12755
+ description: "Hex color (e.g., #FF0000)"
12756
+ },
12757
+ backgroundColor: {
12758
+ type: "string",
12759
+ description: "Hex color"
12760
+ },
12761
+ horizontalAlignment: {
12762
+ type: "string",
12763
+ enum: [
12764
+ "left",
12765
+ "center",
12766
+ "right"
12767
+ ]
12768
+ },
12769
+ verticalAlignment: {
12770
+ type: "string",
12771
+ enum: [
12772
+ "top",
12773
+ "middle",
12774
+ "bottom"
12775
+ ]
12776
+ },
12777
+ numberFormat: {
12778
+ type: "string",
12779
+ description: "Excel number format (e.g., #,##0.00, 0%, yyyy-mm-dd)"
12780
+ },
12781
+ border: {
12782
+ type: "object",
12783
+ properties: {
12784
+ top: { type: "boolean" },
12785
+ bottom: { type: "boolean" },
12786
+ left: { type: "boolean" },
12787
+ right: { type: "boolean" }
12788
+ }
12789
+ }
12790
+ }
12791
+ }
12792
+ },
12793
+ required: ["row", "col"]
12794
+ }
12795
+ },
12796
+ columnWidths: {
12797
+ type: "array",
12798
+ description: "Column width settings",
12799
+ items: {
12800
+ type: "object",
12801
+ properties: {
12802
+ col: { type: "number" },
12803
+ width: { type: "number" }
12804
+ },
12805
+ required: ["col", "width"]
12806
+ }
12807
+ },
12808
+ rowHeights: {
12809
+ type: "array",
12810
+ description: "Row height settings",
12811
+ items: {
12812
+ type: "object",
12813
+ properties: {
12814
+ row: { type: "number" },
12815
+ height: { type: "number" }
12816
+ },
12817
+ required: ["row", "height"]
12818
+ }
12819
+ },
12820
+ mergedCells: {
12821
+ type: "array",
12822
+ description: "Merged cell regions",
12823
+ items: {
12824
+ type: "object",
12825
+ properties: {
12826
+ startRow: { type: "number" },
12827
+ startCol: { type: "number" },
12828
+ endRow: { type: "number" },
12829
+ endCol: { type: "number" }
12830
+ },
12831
+ required: [
12832
+ "startRow",
12833
+ "startCol",
12834
+ "endRow",
12835
+ "endCol"
12836
+ ]
12837
+ }
12838
+ },
12839
+ freezePane: {
12840
+ type: "object",
12841
+ description: "Freeze pane settings. Both row and col default to 1 (no freeze) if omitted.",
12842
+ properties: {
12843
+ row: {
12844
+ type: "number",
12845
+ description: "Freeze rows above this row (default: 1, meaning no row freeze)"
12846
+ },
12847
+ col: {
12848
+ type: "number",
12849
+ description: "Freeze columns to the left of this column (default: 1, meaning no column freeze)"
12850
+ }
12851
+ }
12852
+ }
12853
+ },
12854
+ required: ["name", "data"]
12855
+ }
12856
+ }
12857
+ },
12858
+ required: ["filename", "sheets"]
12859
+ }
12860
+ }
12861
+ })
12862
+ };
12863
+ /**
12864
+ * Shared FMP (Financial Modeling Prep) API service.
12865
+ *
12866
+ * Provides stock quotes, company profiles, financial statements, and
12867
+ * historical price data with an in-memory cache (60 s TTL) to respect
12868
+ * FMP rate limits. All functions accept an explicit `apiKey` so both
12869
+ * the LLM tool (via apiKeyService) and the tavern (via systemSecretsManager)
12870
+ * can share this code.
12871
+ *
12872
+ * NOTE: apps/client/server/tavern/fmpService.ts has a parallel copy for
12873
+ * the tavern Lambda context. Keep cache/fetch logic in sync when fixing
12874
+ * bugs in either copy.
12875
+ */
12876
+ const FMP_BASE = "https://financialmodelingprep.com/api/v3";
12877
+ const CACHE_TTL_MS = 6e4;
12878
+ const REQUEST_TIMEOUT_MS = 15e3;
12879
+ const MAX_RESPONSE_SIZE = 1e5;
12880
+ const MAX_CACHE_SIZE = 500;
12881
+ const cache = /* @__PURE__ */ new Map();
12882
+ function getCached(key) {
12883
+ const entry = cache.get(key);
12884
+ if (!entry) return void 0;
12885
+ if (Date.now() > entry.expiresAt) {
12886
+ cache.delete(key);
12887
+ return;
12888
+ }
12889
+ return entry.data;
12890
+ }
12891
+ function setCache(key, data) {
12892
+ if (cache.size >= MAX_CACHE_SIZE) {
12893
+ const firstKey = cache.keys().next().value;
12894
+ if (firstKey) cache.delete(firstKey);
12895
+ }
12896
+ cache.set(key, {
12897
+ data,
12898
+ expiresAt: Date.now() + CACHE_TTL_MS
12899
+ });
12900
+ }
12901
+ async function fmpFetch(apiKey, path, params) {
12902
+ const cacheKey = `${path}?${JSON.stringify(params ?? {})}`;
12903
+ const cached = getCached(cacheKey);
12904
+ if (cached !== void 0) return cached;
12905
+ const url = new URL(`${FMP_BASE}${path}`);
12906
+ url.searchParams.set("apikey", apiKey);
12907
+ if (params) for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
12908
+ const controller = new AbortController();
12909
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
12910
+ try {
12911
+ const res = await fetch(url.toString(), { signal: controller.signal });
12912
+ clearTimeout(timeoutId);
12913
+ if (!res.ok) return null;
12914
+ const text = await res.text();
12915
+ if (text.length > MAX_RESPONSE_SIZE) return null;
12916
+ const data = JSON.parse(text);
12917
+ setCache(cacheKey, data);
12918
+ return data;
12919
+ } catch {
12920
+ clearTimeout(timeoutId);
12921
+ return null;
12922
+ }
12923
+ }
12924
+ /** Full quote for a single ticker. */
12925
+ async function getStockQuote(apiKey, symbol) {
12926
+ return (await fmpFetch(apiKey, `/quote/${encodeURIComponent(symbol.toUpperCase())}`))?.[0] ?? null;
12927
+ }
12928
+ /** Search for tickers by company name or symbol. Filters to major US exchanges. */
12929
+ async function searchStocks(apiKey, query) {
12930
+ return await fmpFetch(apiKey, "/search", {
12931
+ query,
12932
+ limit: "10",
12933
+ exchange: "NASDAQ,NYSE"
12934
+ }) ?? [];
12935
+ }
12936
+ /** Company profile / overview. */
12937
+ async function getCompanyProfile(apiKey, symbol) {
12938
+ return (await fmpFetch(apiKey, `/profile/${encodeURIComponent(symbol.toUpperCase())}`))?.[0] ?? null;
12939
+ }
12940
+ /** Historical daily prices. */
12941
+ async function getHistoricalPrices(apiKey, symbol, from, to) {
12942
+ const params = {};
12943
+ if (from) params.from = from;
12944
+ if (to) params.to = to;
12945
+ return (await fmpFetch(apiKey, `/historical-price-full/${encodeURIComponent(symbol.toUpperCase())}`, params))?.historical ?? [];
12946
+ }
12947
+ /** Income statement (annual or quarterly). */
12948
+ async function getIncomeStatement(apiKey, symbol, period = "annual") {
12949
+ return await fmpFetch(apiKey, `/income-statement/${encodeURIComponent(symbol.toUpperCase())}`, {
12950
+ period,
12951
+ limit: "4"
12952
+ }) ?? [];
12953
+ }
12954
+ /** Balance sheet (annual or quarterly). */
12955
+ async function getBalanceSheet(apiKey, symbol, period = "annual") {
12956
+ return await fmpFetch(apiKey, `/balance-sheet-statement/${encodeURIComponent(symbol.toUpperCase())}`, {
12957
+ period,
12958
+ limit: "4"
12959
+ }) ?? [];
12960
+ }
12961
+ const NOT_CONFIGURED_MSG = "Financial Modeling Prep is not configured. Please contact your administrator to set up the FmpApiKey in admin settings.";
12962
+ async function executeFmpAction(adapters, params) {
12963
+ const apiKey = await getFmpApiKey(adapters);
12964
+ if (!apiKey) return NOT_CONFIGURED_MSG;
12965
+ const { action } = params;
12966
+ switch (action) {
12967
+ case "quote": {
12968
+ if (!params.symbol) return "Error: symbol is required for quote action.";
12969
+ const quote = await getStockQuote(apiKey, params.symbol);
12970
+ if (!quote) return `No quote data found for symbol "${params.symbol}". Verify the ticker is correct.`;
12971
+ return JSON.stringify(quote, null, 2);
12972
+ }
12973
+ case "search": {
12974
+ if (!params.query) return "Error: query is required for search action.";
12975
+ const results = await searchStocks(apiKey, params.query);
12976
+ if (results.length === 0) return `No results found for "${params.query}".`;
12977
+ return JSON.stringify(results, null, 2);
12978
+ }
12979
+ case "profile": {
12980
+ if (!params.symbol) return "Error: symbol is required for profile action.";
12981
+ const profile = await getCompanyProfile(apiKey, params.symbol);
12982
+ if (!profile) return `No company profile found for symbol "${params.symbol}".`;
12983
+ return JSON.stringify(profile, null, 2);
12984
+ }
12985
+ case "history": {
12986
+ if (!params.symbol) return "Error: symbol is required for history action.";
12987
+ const prices = await getHistoricalPrices(apiKey, params.symbol, params.from, params.to);
12988
+ if (prices.length === 0) return `No historical prices found for "${params.symbol}".`;
12989
+ return JSON.stringify(prices, null, 2);
12990
+ }
12991
+ case "income_statement": {
12992
+ if (!params.symbol) return "Error: symbol is required for income_statement action.";
12993
+ const statements = await getIncomeStatement(apiKey, params.symbol, params.period);
12994
+ if (statements.length === 0) return `No income statements found for "${params.symbol}".`;
12995
+ return JSON.stringify(statements, null, 2);
12996
+ }
12997
+ case "balance_sheet": {
12998
+ if (!params.symbol) return "Error: symbol is required for balance_sheet action.";
12999
+ const sheets = await getBalanceSheet(apiKey, params.symbol, params.period);
13000
+ if (sheets.length === 0) return `No balance sheet data found for "${params.symbol}".`;
13001
+ return JSON.stringify(sheets, null, 2);
13002
+ }
13003
+ default: return `Unknown action "${action}". Valid actions: quote, search, profile, history, income_statement, balance_sheet.`;
13004
+ }
13005
+ }
12675
13006
  const b4mTools = {
12676
13007
  dice_roll: diceRollTool,
12677
13008
  weather_info: weatherTool,
@@ -12701,185 +13032,69 @@ const b4mTools = {
12701
13032
  quantum_formulate: quantumFormulateTool,
12702
13033
  navigate_view: navigateViewTool,
12703
13034
  generate_jupyter_notebook: jupyterNotebookTool,
12704
- excel_generation: {
12705
- name: "excel_generation",
13035
+ excel_generation: excelGenerationTool,
13036
+ fmp_financial_data: {
13037
+ name: "fmp_financial_data",
12706
13038
  implementation: (context) => ({
12707
13039
  toolFn: async (value) => {
12708
- const parseResult = ExcelGenerationParamsSchema.safeParse(value);
12709
- if (!parseResult.success) {
12710
- const errors = parseResult.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join("; ");
12711
- throw new Error(`Invalid parameters: ${errors}`);
12712
- }
12713
- const params = parseResult.data;
12714
- await context.statusUpdate({}, "Generating Excel file...");
12715
- try {
12716
- const buffer = await generateExcel(params);
12717
- const sanitizedName = sanitizeFilename(params.filename);
12718
- const filename = `${sanitizedName}-${v4().slice(0, 8)}.xlsx`;
12719
- await context.imageGenerateStorage.upload(buffer, filename, {
12720
- ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
12721
- ContentDisposition: `attachment; filename="${sanitizedName}.xlsx"`
12722
- });
12723
- await context.onFinish?.("excel_generation", [filename]);
12724
- await context.statusUpdate({ images: [filename] });
12725
- return `Successfully generated Excel file: ${sanitizedName}.xlsx`;
12726
- } catch (error) {
12727
- context.logger.error("Excel generation failed:", error);
12728
- throw new Error(`Failed to generate Excel file: ${error instanceof Error ? error.message : "Unknown error"}`);
12729
- }
13040
+ const params = value;
13041
+ return executeFmpAction({ db: context.db }, params);
12730
13042
  },
12731
13043
  toolSchema: {
12732
- name: "excel_generation",
12733
- description: `Generate Excel (.xlsx) files with formatting. Supports: multiple sheets, formulas (SUM, AVERAGE, IF, etc.), styling (bold, colors, borders), number formats, merged cells, frozen panes. Limits: max ${LIMITS.MAX_SHEETS} sheets, ${LIMITS.MAX_CELLS_PER_SHEET} cells/sheet, rows 1-${LIMITS.MAX_ROW}, cols 1-${LIMITS.MAX_COL}.`,
13044
+ name: "fmp_financial_data",
13045
+ description: `Query Financial Modeling Prep for real-time stock market and financial data.
13046
+
13047
+ USE FOR:
13048
+ - Stock quotes: Current price, change, volume, market cap, P/E ratio (action=quote)
13049
+ - Ticker search: Find stock symbols by company name (action=search)
13050
+ - Company profiles: Industry, sector, CEO, description, employees (action=profile)
13051
+ - Price history: Daily OHLCV data for charting and analysis (action=history)
13052
+ - Income statements: Revenue, net income, EPS — annual or quarterly (action=income_statement)
13053
+ - Balance sheets: Assets, liabilities, equity — annual or quarterly (action=balance_sheet)
13054
+
13055
+ DO NOT USE FOR:
13056
+ - Cryptocurrency prices (FMP focuses on equities)
13057
+ - Real-time intraday tick data
13058
+ - Options or futures data
13059
+ - General financial advice or predictions`,
12734
13060
  parameters: {
12735
13061
  type: "object",
12736
13062
  properties: {
12737
- filename: {
13063
+ action: {
12738
13064
  type: "string",
12739
- description: "Name for the Excel file (without .xlsx extension)"
13065
+ enum: [
13066
+ "quote",
13067
+ "search",
13068
+ "profile",
13069
+ "history",
13070
+ "income_statement",
13071
+ "balance_sheet"
13072
+ ],
13073
+ description: "The type of financial data to retrieve"
12740
13074
  },
12741
- sheets: {
12742
- type: "array",
12743
- description: "Array of sheet definitions",
12744
- items: {
12745
- type: "object",
12746
- properties: {
12747
- name: {
12748
- type: "string",
12749
- description: "Sheet name (max 31 characters)"
12750
- },
12751
- data: {
12752
- type: "array",
12753
- description: "Cell data array",
12754
- items: {
12755
- type: "object",
12756
- properties: {
12757
- row: {
12758
- type: "number",
12759
- description: "1-indexed row number"
12760
- },
12761
- col: {
12762
- type: "number",
12763
- description: "1-indexed column number"
12764
- },
12765
- value: { description: "Cell value (string, number, boolean, or null)" },
12766
- formula: {
12767
- type: "string",
12768
- description: "Excel formula (e.g., =SUM(A1:A10))"
12769
- },
12770
- style: {
12771
- type: "object",
12772
- description: "Cell styling options",
12773
- properties: {
12774
- bold: { type: "boolean" },
12775
- italic: { type: "boolean" },
12776
- fontSize: { type: "number" },
12777
- fontColor: {
12778
- type: "string",
12779
- description: "Hex color (e.g., #FF0000)"
12780
- },
12781
- backgroundColor: {
12782
- type: "string",
12783
- description: "Hex color"
12784
- },
12785
- horizontalAlignment: {
12786
- type: "string",
12787
- enum: [
12788
- "left",
12789
- "center",
12790
- "right"
12791
- ]
12792
- },
12793
- verticalAlignment: {
12794
- type: "string",
12795
- enum: [
12796
- "top",
12797
- "middle",
12798
- "bottom"
12799
- ]
12800
- },
12801
- numberFormat: {
12802
- type: "string",
12803
- description: "Excel number format (e.g., #,##0.00, 0%, yyyy-mm-dd)"
12804
- },
12805
- border: {
12806
- type: "object",
12807
- properties: {
12808
- top: { type: "boolean" },
12809
- bottom: { type: "boolean" },
12810
- left: { type: "boolean" },
12811
- right: { type: "boolean" }
12812
- }
12813
- }
12814
- }
12815
- }
12816
- },
12817
- required: ["row", "col"]
12818
- }
12819
- },
12820
- columnWidths: {
12821
- type: "array",
12822
- description: "Column width settings",
12823
- items: {
12824
- type: "object",
12825
- properties: {
12826
- col: { type: "number" },
12827
- width: { type: "number" }
12828
- },
12829
- required: ["col", "width"]
12830
- }
12831
- },
12832
- rowHeights: {
12833
- type: "array",
12834
- description: "Row height settings",
12835
- items: {
12836
- type: "object",
12837
- properties: {
12838
- row: { type: "number" },
12839
- height: { type: "number" }
12840
- },
12841
- required: ["row", "height"]
12842
- }
12843
- },
12844
- mergedCells: {
12845
- type: "array",
12846
- description: "Merged cell regions",
12847
- items: {
12848
- type: "object",
12849
- properties: {
12850
- startRow: { type: "number" },
12851
- startCol: { type: "number" },
12852
- endRow: { type: "number" },
12853
- endCol: { type: "number" }
12854
- },
12855
- required: [
12856
- "startRow",
12857
- "startCol",
12858
- "endRow",
12859
- "endCol"
12860
- ]
12861
- }
12862
- },
12863
- freezePane: {
12864
- type: "object",
12865
- description: "Freeze pane settings. Both row and col default to 1 (no freeze) if omitted.",
12866
- properties: {
12867
- row: {
12868
- type: "number",
12869
- description: "Freeze rows above this row (default: 1, meaning no row freeze)"
12870
- },
12871
- col: {
12872
- type: "number",
12873
- description: "Freeze columns to the left of this column (default: 1, meaning no column freeze)"
12874
- }
12875
- }
12876
- }
12877
- },
12878
- required: ["name", "data"]
12879
- }
13075
+ symbol: {
13076
+ type: "string",
13077
+ description: "Stock ticker symbol (e.g., AAPL, MSFT, GOOGL). Required for all actions except search."
13078
+ },
13079
+ query: {
13080
+ type: "string",
13081
+ description: "Search query to find stock tickers by company name. Required for action=search."
13082
+ },
13083
+ from: {
13084
+ type: "string",
13085
+ description: "Start date in YYYY-MM-DD format (for action=history). Defaults to 1 year ago."
13086
+ },
13087
+ to: {
13088
+ type: "string",
13089
+ description: "End date in YYYY-MM-DD format (for action=history). Defaults to today."
13090
+ },
13091
+ period: {
13092
+ type: "string",
13093
+ enum: ["annual", "quarter"],
13094
+ description: "Reporting period for financial statements. Defaults to annual."
12880
13095
  }
12881
13096
  },
12882
- required: ["filename", "sheets"]
13097
+ required: ["action"]
12883
13098
  }
12884
13099
  }
12885
13100
  })
@@ -13157,9 +13372,20 @@ z.object({
13157
13372
  riskAssessment: z.string(),
13158
13373
  affectedFiles: z.array(z.object({
13159
13374
  filePath: z.string(),
13160
- before: z.string().min(1),
13161
- after: z.string()
13162
- })).max(10)
13375
+ before: z.string(),
13376
+ after: z.string(),
13377
+ kind: z.enum([
13378
+ "insert",
13379
+ "replace",
13380
+ "create"
13381
+ ]).default("replace")
13382
+ }).superRefine((file, ctx) => {
13383
+ if (file.kind !== "create" && file.before.length === 0) ctx.addIssue({
13384
+ code: z.ZodIssueCode.custom,
13385
+ path: ["before"],
13386
+ message: `"before" is required for kind="${file.kind}" hunks`
13387
+ });
13388
+ })).max(15)
13163
13389
  });
13164
13390
  z.object({
13165
13391
  count: z.number().optional(),
@@ -4,7 +4,7 @@ import { homedir } from "os";
4
4
  import path from "path";
5
5
  import axios from "axios";
6
6
  //#region package.json
7
- var version = "0.2.75";
7
+ var version = "0.2.76-chore-upgrade-mathjs-v15.22376+4415940ec";
8
8
  //#endregion
9
9
  //#region src/utils/updateChecker.ts
10
10
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.75",
3
+ "version": "0.2.76-chore-upgrade-mathjs-v15.22376+4415940ec",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -86,7 +86,7 @@
86
86
  "lodash": "^4.17.21",
87
87
  "mammoth": "^1.12.0",
88
88
  "marked": "^15.0.11",
89
- "mathjs": "^14.2.0",
89
+ "mathjs": "^15.2.0",
90
90
  "mime-types": "^2.1.35",
91
91
  "mongoose": "^8.8.3",
92
92
  "ollama": "^0.6.3",
@@ -115,11 +115,11 @@
115
115
  "zustand": "^4.5.4"
116
116
  },
117
117
  "devDependencies": {
118
- "@bike4mind/agents": "0.4.12",
119
- "@bike4mind/common": "2.83.0",
120
- "@bike4mind/mcp": "1.34.0",
121
- "@bike4mind/services": "2.73.2",
122
- "@bike4mind/utils": "2.16.13",
118
+ "@bike4mind/agents": "0.4.13-chore-upgrade-mathjs-v15.22376+4415940ec",
119
+ "@bike4mind/common": "2.83.1-chore-upgrade-mathjs-v15.22376+4415940ec",
120
+ "@bike4mind/mcp": "1.34.1-chore-upgrade-mathjs-v15.22376+4415940ec",
121
+ "@bike4mind/services": "2.73.3-chore-upgrade-mathjs-v15.22376+4415940ec",
122
+ "@bike4mind/utils": "2.16.14-chore-upgrade-mathjs-v15.22376+4415940ec",
123
123
  "@types/better-sqlite3": "^7.6.13",
124
124
  "@types/jsonwebtoken": "^9.0.4",
125
125
  "@types/node": "^22.9.0",
@@ -136,5 +136,5 @@
136
136
  "optionalDependencies": {
137
137
  "@vscode/ripgrep": "^1.17.1"
138
138
  },
139
- "gitHead": "7db08e15f07372a907de0a4d874589f19d8335bf"
139
+ "gitHead": "4415940ec6d370522204f264b89d1a9e299b8926"
140
140
  }