@bike4mind/cli 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1027,6 +1027,8 @@ const SreRepoConfigSchema = z.object({
1027
1027
  maxFixesPerDay: z.number().min(0).default(5),
1028
1028
  /** Max revision attempts before escalating to human */
1029
1029
  maxRevisions: z.number().int().min(0).max(10).default(2),
1030
+ /** Max CI retry attempts before permanently failing (typecheck/apply-fix failures) */
1031
+ maxCiRetries: z.number().int().min(0).max(3).default(1),
1030
1032
  /** Log actions without dispatching */
1031
1033
  dryRun: z.boolean().default(false),
1032
1034
  /** Comma-separated GitHub usernames to request as PR reviewers */
@@ -1035,6 +1037,12 @@ const SreRepoConfigSchema = z.object({
1035
1037
  defaultBranch: z.string().default(""),
1036
1038
  /** Build command for the workflow */
1037
1039
  buildCommand: z.string().default(""),
1040
+ /**
1041
+ * Repository-specific instructions for the Diagnostician (max 2,000 chars).
1042
+ * For critical constraints that would cause broken fixes if unknown — e.g., "never modify X",
1043
+ * "all DB calls must go through Y wrapper". Not for general coding conventions (use CLAUDE.md).
1044
+ */
1045
+ sreInstructions: z.string().max(2e3).default(""),
1038
1046
  /** Files the Surgeon can modify (glob patterns). Base patterns always merged in. */
1039
1047
  allowedFilePatterns: z.array(z.string()).default([]),
1040
1048
  /** Files never auto-fixed (glob patterns) */
@@ -1062,11 +1070,11 @@ const SreRepoConfigSchema = z.object({
1062
1070
  /** Token budget per analysis */
1063
1071
  tokenBudget: z.object({
1064
1072
  maxInputTokens: z.number().default(5e4),
1065
- maxOutputTokens: z.number().default(8e3),
1073
+ maxOutputTokens: z.number().default(16e3),
1066
1074
  maxGithubApiCalls: z.number().default(20)
1067
1075
  }).default({
1068
1076
  maxInputTokens: 5e4,
1069
- maxOutputTokens: 8e3,
1077
+ maxOutputTokens: 16e3,
1070
1078
  maxGithubApiCalls: 20
1071
1079
  }),
1072
1080
  /** Error sources */
@@ -6280,6 +6288,49 @@ let FriendshipEvents = /* @__PURE__ */ function(FriendshipEvents) {
6280
6288
  FriendshipEvents["FRIENDSHIP_CANCEL"] = "Friendship Cancelled";
6281
6289
  return FriendshipEvents;
6282
6290
  }({});
6291
+ /**
6292
+ * Overwatch Analytics Event Schema
6293
+ *
6294
+ * Cross-product event schema for the Overwatch marketing command center.
6295
+ * Products (VibesWire, B4M, StocksAndVibes, K2Kanji) emit these events
6296
+ * to a shared SQS queue. Overwatch consumes them and rolls up DAU/WAU/MAU.
6297
+ *
6298
+ * Unlike the B4M-internal IBaseEvent analytics events, this schema is
6299
+ * designed for cross-product use with Zod validation at both emission
6300
+ * and consumption boundaries.
6301
+ */
6302
+ const OverwatchUtmSchema = z.object({
6303
+ source: z.string().max(128).optional(),
6304
+ medium: z.string().max(128).optional(),
6305
+ campaign: z.string().max(128).optional(),
6306
+ content: z.string().max(128).optional()
6307
+ });
6308
+ z.object({
6309
+ /** UUID for deduplication (SQS is at-least-once) */
6310
+ eventId: z.string().uuid(),
6311
+ /** Schema version for forward compatibility */
6312
+ schemaVersion: z.number().int().positive(),
6313
+ /** Product identifier: 'vibeswire', 'bike4mind', 'stocksandvibes', 'k2kanji', etc. */
6314
+ productId: z.string().min(1).max(64),
6315
+ /** Product's internal user ID */
6316
+ userId: z.string().min(1).max(256),
6317
+ /** Session identifier for retention/funnel analysis */
6318
+ sessionId: z.string().min(1).max(256),
6319
+ /** Event type: 'session_start', 'signup', 'feature_used', etc. */
6320
+ event: z.string().min(1).max(128),
6321
+ /** ISO 8601 timestamp */
6322
+ timestamp: z.string().datetime(),
6323
+ /** Where the user came from */
6324
+ referrer: z.string().url().refine((url) => /^https?:\/\//i.test(url), "referrer must be an http or https URL").max(2048).optional(),
6325
+ /** UTM attribution parameters */
6326
+ utm: OverwatchUtmSchema.optional(),
6327
+ /** Event-specific key-value data. Flat values only, max 1KB serialized. */
6328
+ metadata: z.record(z.string(), z.union([
6329
+ z.string(),
6330
+ z.number(),
6331
+ z.boolean()
6332
+ ])).refine((v) => JSON.stringify(v).length <= 1024, "metadata must be ≤ 1KB serialized").optional()
6333
+ });
6283
6334
  const InternalTeamMemberSchema = z.object({
6284
6335
  name: z.string().min(1, "Name is required"),
6285
6336
  phone: z.string().min(1, "Phone is required"),
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as version, n as fetchLatestVersion, r as forceCheckForUpdate } from "../updateChecker-Boy2GLk4.mjs";
2
+ import { i as version, n as fetchLatestVersion, r as forceCheckForUpdate } from "../updateChecker-DZXWZfKF.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 { A as getApiUrl, C as WebSocketLlmBackend, G as isReadOnlyTool, J as CheckpointStore, K as ReActAgent, M as PermissionManager, N as generateCliTools, S as FallbackLlmBackend, T as McpManager, U as buildCoreSystemPrompt, V as setWebSocketToolExecutor, X as SessionStore, _ as createSkillTool, b as WebSocketToolExecutor, c as createFindDefinitionTool, d as createCoordinateTaskTool, f as createBackgroundAgentTools, g as SubagentOrchestrator, h as AgentStore, k as loadContextFiles, l as createTodoStore, m as createAgentDelegateTool, p as BackgroundAgentManager, q as CustomCommandStore, s as createGetFileStructureTool, u as createWriteTodosTool, w as ServerLlmBackend, x as WebSocketConnectionManager, y as ApiClient } from "../tools-V5FJ83BJ.mjs";
3
- import { n as logger, t as ConfigStore } from "../ConfigStore-DBUmvCfe.mjs";
2
+ import { A as getApiUrl, C as WebSocketLlmBackend, G as isReadOnlyTool, J as CheckpointStore, K as ReActAgent, M as PermissionManager, N as generateCliTools, S as FallbackLlmBackend, T as McpManager, U as buildCoreSystemPrompt, V as setWebSocketToolExecutor, X as SessionStore, _ as createSkillTool, b as WebSocketToolExecutor, c as createFindDefinitionTool, d as createCoordinateTaskTool, f as createBackgroundAgentTools, g as SubagentOrchestrator, h as AgentStore, k as loadContextFiles, l as createTodoStore, m as createAgentDelegateTool, p as BackgroundAgentManager, q as CustomCommandStore, s as createGetFileStructureTool, u as createWriteTodosTool, w as ServerLlmBackend, x as WebSocketConnectionManager, y as ApiClient } from "../tools-dIVxi-6-.mjs";
3
+ import { n as logger, t as ConfigStore } from "../ConfigStore-Dt6utdSA.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-DBUmvCfe.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-Dt6utdSA.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-Boy2GLk4.mjs";
2
+ import { i as version, r as forceCheckForUpdate } from "../updateChecker-DZXWZfKF.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-B7-LLvvx.mjs";
3
- import { $ as processFileReferences, A as getApiUrl, B as registerFeatureModuleTools, C as WebSocketLlmBackend, D as formatStep, E as substituteArguments, F as DEFAULT_AGENT_MODEL, G as isReadOnlyTool, H as OllamaBackend, I as DEFAULT_MAX_ITERATIONS, J as CheckpointStore, K as ReActAgent, L as DEFAULT_RETRY_CONFIG, M as PermissionManager, N as generateCliTools, O as extractCompactInstructions, P as ALWAYS_DENIED_FOR_AGENTS, Q as hasFileReferences, R as DEFAULT_THOROUGHNESS, S as FallbackLlmBackend, T as McpManager, U as buildCoreSystemPrompt, V as setWebSocketToolExecutor, W as buildSkillsPromptSection, X as SessionStore, Y as CommandHistoryStore, Z as OAuthClient, _ as createSkillTool, a as createDecisionStore, b as WebSocketToolExecutor, c as createFindDefinitionTool, d as createCoordinateTaskTool, et as searchCommands, f as createBackgroundAgentTools, g as SubagentOrchestrator, h as AgentStore, i as createDecisionLogTool, it as warmFileCache, j as getEnvironmentName, k as loadContextFiles, l as createTodoStore, m as createAgentDelegateTool, n as createBlockerTools, nt as formatFileSize, o as formatDecisionsOutput, p as BackgroundAgentManager, q as CustomCommandStore, r as formatBlockersOutput, rt as searchFiles, s as createGetFileStructureTool, t as createBlockerStore, tt as mergeCommands, u as createWriteTodosTool, v as parseAgentConfig, w as ServerLlmBackend, x as WebSocketConnectionManager, y as ApiClient, z as clearFeatureModuleTools } from "./tools-V5FJ83BJ.mjs";
4
- import { Mt as validateNotebookPath$1, g as ChatModels, jt as validateJupyterKernelName, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-DBUmvCfe.mjs";
5
- import { i as version, t as checkForUpdate } from "./updateChecker-Boy2GLk4.mjs";
3
+ import { $ as processFileReferences, A as getApiUrl, B as registerFeatureModuleTools, C as WebSocketLlmBackend, D as formatStep, E as substituteArguments, F as DEFAULT_AGENT_MODEL, G as isReadOnlyTool, H as OllamaBackend, I as DEFAULT_MAX_ITERATIONS, J as CheckpointStore, K as ReActAgent, L as DEFAULT_RETRY_CONFIG, M as PermissionManager, N as generateCliTools, O as extractCompactInstructions, P as ALWAYS_DENIED_FOR_AGENTS, Q as hasFileReferences, R as DEFAULT_THOROUGHNESS, S as FallbackLlmBackend, T as McpManager, U as buildCoreSystemPrompt, V as setWebSocketToolExecutor, W as buildSkillsPromptSection, X as SessionStore, Y as CommandHistoryStore, Z as OAuthClient, _ as createSkillTool, a as createDecisionStore, b as WebSocketToolExecutor, c as createFindDefinitionTool, d as createCoordinateTaskTool, et as searchCommands, f as createBackgroundAgentTools, g as SubagentOrchestrator, h as AgentStore, i as createDecisionLogTool, it as warmFileCache, j as getEnvironmentName, k as loadContextFiles, l as createTodoStore, m as createAgentDelegateTool, n as createBlockerTools, nt as formatFileSize, o as formatDecisionsOutput, p as BackgroundAgentManager, q as CustomCommandStore, r as formatBlockersOutput, rt as searchFiles, s as createGetFileStructureTool, t as createBlockerStore, tt as mergeCommands, u as createWriteTodosTool, v as parseAgentConfig, w as ServerLlmBackend, x as WebSocketConnectionManager, y as ApiClient, z as clearFeatureModuleTools } from "./tools-dIVxi-6-.mjs";
4
+ import { Mt as validateNotebookPath$1, g as ChatModels, jt as validateJupyterKernelName, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-Dt6utdSA.mjs";
5
+ import { i as version, t as checkForUpdate } from "./updateChecker-DZXWZfKF.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";
@@ -2484,10 +2484,207 @@ function createCompactedSession(originalSession, summary, preservedMessages) {
2484
2484
  totalTokens: 0,
2485
2485
  totalCost: 0,
2486
2486
  toolCallCount: 0,
2487
- compactedFrom: originalSession.id
2487
+ compactedFrom: originalSession.id,
2488
+ ...originalSession.metadata.workflow ? { workflow: originalSession.metadata.workflow } : {}
2488
2489
  }
2489
2490
  };
2490
2491
  }
2492
+ /**
2493
+ * Prefix tag used to mark a system message as an injected handoff. Kept as a
2494
+ * single source of truth so the dedup-on-resume check and the system-message
2495
+ * builder cannot drift out of sync.
2496
+ */
2497
+ const HANDOFF_MARKER = "[Session handoff from previous session]";
2498
+ const MAX_MESSAGE_CHARS = 2e3;
2499
+ /**
2500
+ * Cap on the number of conversation messages included in the handoff prompt.
2501
+ * Prevents unbounded prompt growth on long sessions; the most recent messages
2502
+ * are kept since they best reflect the session's current state. Decisions and
2503
+ * blockers from workflow state are still included in full above the excerpt.
2504
+ */
2505
+ const MAX_CONVERSATION_MESSAGES = 50;
2506
+ const ROLE_LABELS = {
2507
+ user: "User",
2508
+ assistant: "Assistant",
2509
+ system: "System"
2510
+ };
2511
+ /**
2512
+ * Build a prompt instructing the LLM to produce a structured session handoff
2513
+ * as JSON. Incorporates decisions and blockers from the existing workflow state
2514
+ * so the handoff reflects durable state, not just chat history.
2515
+ *
2516
+ * Any previously-injected handoff message (from a prior /resume) is filtered
2517
+ * out — the LLM should produce a fresh handoff from the actual conversation,
2518
+ * not echo back a prior handoff sitting at the top of the message list.
2519
+ *
2520
+ * Returns an empty string for short sessions — callers should skip generation.
2521
+ */
2522
+ function buildHandoffPrompt(session) {
2523
+ if (session.messages.length < 4) return "";
2524
+ const filtered = session.messages.filter((m) => !isInjectedHandoff(m));
2525
+ const conversation = filtered.length > MAX_CONVERSATION_MESSAGES ? filtered.slice(-MAX_CONVERSATION_MESSAGES) : filtered;
2526
+ let prompt = `You are generating a structured session handoff so the next session (or another agent) can pick up seamlessly without re-reading the full chat history.
2527
+
2528
+ Output a single JSON object — no prose, no markdown fences — with exactly these fields:
2529
+
2530
+ {
2531
+ "summary": "2-4 sentence overview of what this session accomplished and where it ended",
2532
+ "keyFindings": ["concise factual discoveries — e.g. 'auth bug is in middleware.ts:42, caused by missing token refresh'"],
2533
+ "nextSteps": ["concrete actions the next session should take, in priority order"],
2534
+ "pendingDecisions": ["open questions or trade-offs awaiting a decision"],
2535
+ "blockers": ["anything preventing progress — wait conditions, missing inputs, broken upstream"]
2536
+ }
2537
+
2538
+ Rules:
2539
+ - Each list item is a single line, no nested structure.
2540
+ - Empty lists are fine — use [] when nothing applies.
2541
+ - Be specific: cite filenames, function names, error messages where relevant.
2542
+ - Do not invent context. Only include items grounded in the conversation or workflow state below.
2543
+
2544
+ `;
2545
+ prompt += appendWorkflowContext(session.metadata.workflow);
2546
+ prompt += `CONVERSATION:\n\n`;
2547
+ for (const msg of conversation) {
2548
+ const role = ROLE_LABELS[msg.role] || "System";
2549
+ const content = msg.content.length > MAX_MESSAGE_CHARS ? msg.content.slice(0, MAX_MESSAGE_CHARS) + "...[truncated]" : msg.content;
2550
+ prompt += `**${role}:** ${content}\n\n`;
2551
+ }
2552
+ prompt += `\nReturn only the JSON object.`;
2553
+ return prompt;
2554
+ }
2555
+ function appendWorkflowContext(workflow) {
2556
+ if (!workflow) return "";
2557
+ const sections = [];
2558
+ if (workflow.decisions.length > 0) {
2559
+ const lines = workflow.decisions.map((d) => `- ${d.summary} (rationale: ${d.rationale})`);
2560
+ sections.push(`LOGGED DECISIONS:\n${lines.join("\n")}`);
2561
+ }
2562
+ const openBlockers = workflow.blockers.filter((b) => b.status === "open");
2563
+ if (openBlockers.length > 0) {
2564
+ const lines = openBlockers.map((b) => `- ${b.description}`);
2565
+ sections.push(`OPEN BLOCKERS:\n${lines.join("\n")}`);
2566
+ }
2567
+ return sections.length > 0 ? `${sections.join("\n\n")}\n\n` : "";
2568
+ }
2569
+ /**
2570
+ * Parse a raw LLM response into a SessionHandoff.
2571
+ *
2572
+ * Tolerates fenced code blocks (```json ... ```) and surrounding prose by
2573
+ * extracting the first balanced JSON object. Returns null if no valid handoff
2574
+ * can be parsed — callers decide how to surface that to the user.
2575
+ */
2576
+ function parseHandoffResponse(response) {
2577
+ const json = extractJsonObject(response);
2578
+ if (!json) return null;
2579
+ let parsed;
2580
+ try {
2581
+ parsed = JSON.parse(json);
2582
+ } catch {
2583
+ return null;
2584
+ }
2585
+ if (!parsed || typeof parsed !== "object") return null;
2586
+ const obj = parsed;
2587
+ const summary = typeof obj.summary === "string" ? obj.summary.trim() : "";
2588
+ if (!summary) return null;
2589
+ return {
2590
+ summary,
2591
+ keyFindings: toStringArray(obj.keyFindings),
2592
+ nextSteps: toStringArray(obj.nextSteps),
2593
+ pendingDecisions: toStringArray(obj.pendingDecisions),
2594
+ blockers: toStringArray(obj.blockers),
2595
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
2596
+ };
2597
+ }
2598
+ function toStringArray(value) {
2599
+ if (!Array.isArray(value)) return [];
2600
+ return value.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim());
2601
+ }
2602
+ function extractJsonObject(text) {
2603
+ const trimmed = text.trim();
2604
+ if (!trimmed) return null;
2605
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
2606
+ const candidate = fenced ? fenced[1].trim() : trimmed;
2607
+ const start = candidate.indexOf("{");
2608
+ if (start === -1) return null;
2609
+ let depth = 0;
2610
+ let inString = false;
2611
+ let escaped = false;
2612
+ for (let i = start; i < candidate.length; i++) {
2613
+ const ch = candidate[i];
2614
+ if (escaped) {
2615
+ escaped = false;
2616
+ continue;
2617
+ }
2618
+ if (ch === "\\" && inString) {
2619
+ escaped = true;
2620
+ continue;
2621
+ }
2622
+ if (ch === "\"") {
2623
+ inString = !inString;
2624
+ continue;
2625
+ }
2626
+ if (inString) continue;
2627
+ if (ch === "{") depth++;
2628
+ else if (ch === "}") {
2629
+ depth--;
2630
+ if (depth === 0) return candidate.slice(start, i + 1);
2631
+ }
2632
+ }
2633
+ return null;
2634
+ }
2635
+ /**
2636
+ * Render a SessionHandoff for terminal display, including the generation
2637
+ * timestamp so the user knows how fresh the context is.
2638
+ */
2639
+ function formatHandoffOutput(handoff) {
2640
+ return formatHandoff(handoff, { includeTimestamp: true });
2641
+ }
2642
+ /**
2643
+ * Build the system message that injects handoff context into a resumed
2644
+ * session. Excludes the timestamp so the message text is stable across
2645
+ * regenerations — important for keeping LLM prompt caches warm.
2646
+ */
2647
+ function buildHandoffSystemMessage(handoff) {
2648
+ return `${HANDOFF_MARKER}\n\n${formatHandoff(handoff, { includeTimestamp: false })}`;
2649
+ }
2650
+ function formatHandoff(handoff, options) {
2651
+ const lines = [handoff.summary, ""];
2652
+ appendSection(lines, "Key findings", handoff.keyFindings);
2653
+ appendSection(lines, "Next steps", handoff.nextSteps);
2654
+ appendSection(lines, "Pending decisions", handoff.pendingDecisions);
2655
+ appendSection(lines, "Blockers", handoff.blockers);
2656
+ if (options.includeTimestamp) lines.push(`Generated: ${handoff.generatedAt}`);
2657
+ else if (lines[lines.length - 1] === "") lines.pop();
2658
+ return lines.join("\n");
2659
+ }
2660
+ function appendSection(lines, heading, items) {
2661
+ if (items.length === 0) return;
2662
+ lines.push(`${heading}:`);
2663
+ for (const item of items) lines.push(` - ${item}`);
2664
+ lines.push("");
2665
+ }
2666
+ /**
2667
+ * True when a message is a previously-injected handoff system message.
2668
+ * Used to deduplicate handoff injections across save/resume cycles.
2669
+ */
2670
+ function isInjectedHandoff(message) {
2671
+ return message.role === "system" && message.content.startsWith("[Session handoff from previous session]");
2672
+ }
2673
+ /**
2674
+ * Return a new message list with the handoff prepended as a system message.
2675
+ * Any previously-injected handoff anywhere in the list is removed so the
2676
+ * message list stays stable across repeated save/resume cycles. We scan the
2677
+ * whole list rather than just index 0 because compaction can prepend a
2678
+ * summary system message, pushing the prior handoff to a later index.
2679
+ */
2680
+ function injectHandoffMessage(messages, handoff) {
2681
+ return [{
2682
+ id: v4(),
2683
+ role: "system",
2684
+ content: buildHandoffSystemMessage(handoff),
2685
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2686
+ }, ...messages.filter((m) => !isInjectedHandoff(m))];
2687
+ }
2491
2688
  //#endregion
2492
2689
  //#region src/utils/imageRenderer.ts
2493
2690
  /**
@@ -6426,6 +6623,46 @@ function CliApp() {
6426
6623
  console.log("");
6427
6624
  }
6428
6625
  };
6626
+ /**
6627
+ * Generate a structured session handoff via a single LLM call and persist it
6628
+ * onto the session's workflow state. Returns the handoff on success, or null
6629
+ * if generation was skipped (short session) or failed (parse / agent error).
6630
+ *
6631
+ * Failures are best-effort and surfaced as a warning rather than thrown —
6632
+ * the surrounding /save flow must not block on handoff generation.
6633
+ *
6634
+ * Callers are responsible for saving the session afterwards.
6635
+ */
6636
+ const generateHandoff = async (session) => {
6637
+ if (!state.agent) return null;
6638
+ const prompt = buildHandoffPrompt(session);
6639
+ if (!prompt) return null;
6640
+ console.log("📝 Generating session handoff...");
6641
+ useCliStore.getState().setIsThinking(true);
6642
+ try {
6643
+ const result = await state.agent.run(prompt, { maxIterations: 1 });
6644
+ const handoff = parseHandoffResponse(result.finalAnswer);
6645
+ if (!handoff) {
6646
+ console.warn("⚠️ Handoff generation returned no parseable JSON; skipping.");
6647
+ logger.debug(`Handoff response: ${result.finalAnswer.slice(0, 500)}`);
6648
+ return null;
6649
+ }
6650
+ session.metadata.workflow = {
6651
+ decisions: decisionStoreRef.current.decisions,
6652
+ blockers: blockerStoreRef.current.blockers,
6653
+ handoff,
6654
+ reviewGates: session.metadata.workflow?.reviewGates
6655
+ };
6656
+ return handoff;
6657
+ } catch (err) {
6658
+ const reason = err instanceof Error ? err.message : String(err);
6659
+ console.warn(`⚠️ Handoff generation failed: ${reason}`);
6660
+ logger.debug(`Handoff generation error: ${reason}`);
6661
+ return null;
6662
+ } finally {
6663
+ useCliStore.getState().setIsThinking(false);
6664
+ }
6665
+ };
6429
6666
  const handleCommand = async (command, args) => {
6430
6667
  const customCommand = state.customCommandStore.getCommand(command);
6431
6668
  if (customCommand) try {
@@ -6565,8 +6802,10 @@ Multi-line Input:
6565
6802
  handoff: state.session.metadata.workflow?.handoff,
6566
6803
  reviewGates: state.session.metadata.workflow?.reviewGates
6567
6804
  };
6805
+ const handoff = await generateHandoff(state.session);
6568
6806
  await state.sessionStore.save(state.session);
6569
6807
  console.log(`✅ Session saved as "${sessionName}"`);
6808
+ if (handoff) console.log("🤝 Session handoff generated");
6570
6809
  break;
6571
6810
  }
6572
6811
  case "resume":
@@ -6592,15 +6831,24 @@ Multi-line Input:
6592
6831
  await logger.initialize(loadedSession.id);
6593
6832
  logger.debug("=== Session Resumed ===");
6594
6833
  if (state.checkpointStore) state.checkpointStore.setSessionId(loadedSession.id);
6834
+ const handoff = loadedSession.metadata.workflow?.handoff;
6835
+ const sessionForState = handoff ? {
6836
+ ...loadedSession,
6837
+ messages: injectHandoffMessage(loadedSession.messages, handoff)
6838
+ } : loadedSession;
6595
6839
  setState((prev) => ({
6596
6840
  ...prev,
6597
- session: loadedSession
6841
+ session: sessionForState
6598
6842
  }));
6599
- setStoreSession(loadedSession);
6843
+ setStoreSession(sessionForState);
6600
6844
  useCliStore.getState().clearPendingMessages();
6601
6845
  usageCache = null;
6602
- console.log(`\n✅ Session resumed: "${loadedSession.name}"`);
6603
- console.log(`📝 ${loadedSession.messages.length} messages | 🤖 ${loadedSession.model} | 📊 ${loadedSession.metadata.totalTokens.toLocaleString()} tokens\n`);
6846
+ console.log(`\n✅ Session resumed: "${sessionForState.name}"`);
6847
+ console.log(`📝 ${sessionForState.messages.length} messages | 🤖 ${sessionForState.model} | 📊 ${sessionForState.metadata.totalTokens.toLocaleString()} tokens\n`);
6848
+ if (handoff) {
6849
+ console.log("🤝 Session handoff:\n");
6850
+ console.log(formatHandoffOutput(handoff));
6851
+ }
6604
6852
  };
6605
6853
  setState((prev) => ({
6606
6854
  ...prev,
@@ -7528,6 +7776,38 @@ Multi-line Input:
7528
7776
  console.log(formatBlockersOutput(blockerStoreRef.current.blockers));
7529
7777
  console.log("");
7530
7778
  break;
7779
+ case "handoff": {
7780
+ if (!state.session) {
7781
+ console.log("No active session");
7782
+ break;
7783
+ }
7784
+ const existing = state.session.metadata.workflow?.handoff;
7785
+ const wantsRegen = args[0] === "generate" || args[0] === "regen";
7786
+ if (existing && !wantsRegen) {
7787
+ console.log("\n🤝 Session handoff\n");
7788
+ console.log(formatHandoffOutput(existing));
7789
+ console.log("Run /handoff generate to refresh.\n");
7790
+ break;
7791
+ }
7792
+ if (state.session.messages.length < 4) {
7793
+ console.log(`Not enough messages to generate a handoff (need at least 4)`);
7794
+ break;
7795
+ }
7796
+ if (!state.agent) {
7797
+ console.log("Cannot generate handoff: no active agent");
7798
+ break;
7799
+ }
7800
+ const handoff = await generateHandoff(state.session);
7801
+ if (!handoff) {
7802
+ console.log("❌ Failed to generate handoff");
7803
+ break;
7804
+ }
7805
+ await state.sessionStore.save(state.session);
7806
+ console.log("\n🤝 Session handoff\n");
7807
+ console.log(formatHandoffOutput(handoff));
7808
+ console.log("\n✅ Session saved with refreshed handoff");
7809
+ break;
7810
+ }
7531
7811
  case "dirs": {
7532
7812
  const additionalDirs = await state.configStore.getAdditionalDirectories();
7533
7813
  const cwd = process.cwd();
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as RechartsChartTypeList, A as ImageGenerationUsageTransaction, At as secureParameters, B as NotFoundError, C as FileEvents, Ct as getMcpProviderMetadata, D as GenericCreditAddTransaction, Dt as obfuscateApiKey, E as GenerateImageToolCallSchema, Et as isGPTImageModel, F as KnowledgeType, G as ProfileEvents, H as OpenAIImageGenerationInput, I as LLMEvents, J as PurchaseTransaction, K as ProjectEvents, L as MiscEvents, M as InboxEvents, N as InviteEvents, Nt as CollectionType, O as GenericCreditDeductTransaction, Ot as resolveNavigationIntents, P as InviteType, Q as ReceivedCreditTransaction, R as ModalEvents, S as FeedbackEvents, St as getDataLakeTags, T as GEMINI_IMAGE_MODELS, Tt as isGPTImage2Model, U as Permission, V as OpenAIEmbeddingModel, W as PermissionDeniedError, X as REASONING_SUPPORTED_MODELS, Y as QuestMasterParamsSchema, Z as RealtimeVoiceUsageTransaction, _ as CompletionApiUsageTransaction, _t as VideoModels, a as ApiKeyEvents, at as SessionEvents, b as FIXED_TEMPERATURE_MODELS, bt as b4mLLMTools, c as AppFileEvents, ct as SupportedFabFileMimeTypes, d as BFL_IMAGE_MODELS, dt as TextGenerationUsageTransaction, et as RegInviteEvents, f as BFL_SAFETY_TOLERANCE, ft as ToolUsageTransaction, g as ChatModels, gt as VideoGenerationUsageTransaction, h as ChatCompletionCreateInputSchema, ht as VIDEO_SIZE_CONSTRAINTS, i as AiEvents, it as ResearchTaskType, j as ImageModels, k as ImageEditUsageTransaction, kt as sanitizeTelemetryError, l as ArtifactTypeSchema, lt as TagType, mt as UiNavigationEvents, n as logger, nt as ResearchTaskExecutionType, o as ApiKeyScope, ot as SpeechToTextModels, p as BedrockEmbeddingModel, pt as TransferCreditTransaction, q as PromptMetaZodSchema, r as ALERT_THRESHOLDS, rt as ResearchTaskPeriodicFrequencyType, s as ApiKeyType, st as SubscriptionCreditTransaction, t as ConfigStore, tt as ResearchModeParamsSchema, u as AuthEvents, ut as TaskScheduleHandler, v as DashboardParamsSchema, vt as VoyageAIEmbeddingModel, w as FriendshipEvents, wt as getViewById, x as FavoriteDocumentType, xt as getAccessibleDataLakes, y as ElabsEvents, yt as XAI_IMAGE_MODELS, z as ModelBackend } from "./ConfigStore-DBUmvCfe.mjs";
2
+ import { $ as RechartsChartTypeList, A as ImageGenerationUsageTransaction, At as secureParameters, B as NotFoundError, C as FileEvents, Ct as getMcpProviderMetadata, D as GenericCreditAddTransaction, Dt as obfuscateApiKey, E as GenerateImageToolCallSchema, Et as isGPTImageModel, F as KnowledgeType, G as ProfileEvents, H as OpenAIImageGenerationInput, I as LLMEvents, J as PurchaseTransaction, K as ProjectEvents, L as MiscEvents, M as InboxEvents, N as InviteEvents, Nt as CollectionType, O as GenericCreditDeductTransaction, Ot as resolveNavigationIntents, P as InviteType, Q as ReceivedCreditTransaction, R as ModalEvents, S as FeedbackEvents, St as getDataLakeTags, T as GEMINI_IMAGE_MODELS, Tt as isGPTImage2Model, U as Permission, V as OpenAIEmbeddingModel, W as PermissionDeniedError, X as REASONING_SUPPORTED_MODELS, Y as QuestMasterParamsSchema, Z as RealtimeVoiceUsageTransaction, _ as CompletionApiUsageTransaction, _t as VideoModels, a as ApiKeyEvents, at as SessionEvents, b as FIXED_TEMPERATURE_MODELS, bt as b4mLLMTools, c as AppFileEvents, ct as SupportedFabFileMimeTypes, d as BFL_IMAGE_MODELS, dt as TextGenerationUsageTransaction, et as RegInviteEvents, f as BFL_SAFETY_TOLERANCE, ft as ToolUsageTransaction, g as ChatModels, gt as VideoGenerationUsageTransaction, h as ChatCompletionCreateInputSchema, ht as VIDEO_SIZE_CONSTRAINTS, i as AiEvents, it as ResearchTaskType, j as ImageModels, k as ImageEditUsageTransaction, kt as sanitizeTelemetryError, l as ArtifactTypeSchema, lt as TagType, mt as UiNavigationEvents, n as logger, nt as ResearchTaskExecutionType, o as ApiKeyScope, ot as SpeechToTextModels, p as BedrockEmbeddingModel, pt as TransferCreditTransaction, q as PromptMetaZodSchema, r as ALERT_THRESHOLDS, rt as ResearchTaskPeriodicFrequencyType, s as ApiKeyType, st as SubscriptionCreditTransaction, t as ConfigStore, tt as ResearchModeParamsSchema, u as AuthEvents, ut as TaskScheduleHandler, v as DashboardParamsSchema, vt as VoyageAIEmbeddingModel, w as FriendshipEvents, wt as getViewById, x as FavoriteDocumentType, xt as getAccessibleDataLakes, y as ElabsEvents, yt as XAI_IMAGE_MODELS, z as ModelBackend } from "./ConfigStore-Dt6utdSA.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";
@@ -530,6 +530,10 @@ const COMMANDS = [
530
530
  {
531
531
  name: "blockers",
532
532
  description: "Show tracked blockers for current session"
533
+ },
534
+ {
535
+ name: "handoff",
536
+ description: "Show or generate the session handoff for cross-session continuity"
533
537
  }
534
538
  ];
535
539
  /**
@@ -3099,8 +3103,7 @@ var AIImageService = class {
3099
3103
  }
3100
3104
  };
3101
3105
  //#endregion
3102
- //#region ../../b4m-core/utils/dist/index.mjs
3103
- var BaseStorage = class {};
3106
+ //#region ../../b4m-core/observability/dist/index.mjs
3104
3107
  var Logger = class Logger {
3105
3108
  static globalInstance = new Logger();
3106
3109
  metadata = {};
@@ -3304,6 +3307,9 @@ var Logger = class Logger {
3304
3307
  blue: `\x1b[34m${args.join(" ")}\x1b[0m`
3305
3308
  });
3306
3309
  };
3310
+ //#endregion
3311
+ //#region ../../b4m-core/utils/dist/index.mjs
3312
+ var BaseStorage = class {};
3307
3313
  dotenv.config();
3308
3314
  /**
3309
3315
  * Execute an array of async tasks either in parallel (with concurrency limiting)
@@ -4760,6 +4766,8 @@ var OpenAIBackend = class {
4760
4766
  ...options
4761
4767
  };
4762
4768
  const toolCallCount = options._internal?.toolCallCount ?? 0;
4769
+ const accumInputTokens = options._internal?.accumInputTokens ?? 0;
4770
+ const accumOutputTokens = options._internal?.accumOutputTokens ?? 0;
4763
4771
  if (toolCallCount >= 10 && options.tools?.length) {
4764
4772
  this.logger.warn(`⚠️ Max tool calls limit (10) reached. Disabling tools to prevent infinite loops.`);
4765
4773
  await this.complete(model, messages, {
@@ -4942,7 +4950,9 @@ var OpenAIBackend = class {
4942
4950
  tools: anyMcpTool ? options.tools : void 0,
4943
4951
  _internal: {
4944
4952
  ...options._internal,
4945
- toolCallCount: toolCallCount + 1
4953
+ toolCallCount: toolCallCount + 1,
4954
+ accumInputTokens: accumInputTokens + (response.usage?.prompt_tokens || 0),
4955
+ accumOutputTokens: accumOutputTokens + (response.usage?.completion_tokens || 0)
4946
4956
  }
4947
4957
  }, recursiveCallback, toolsUsed);
4948
4958
  if (anyArtifactWasStreamed && recursiveBuffer) {
@@ -4953,8 +4963,8 @@ var OpenAIBackend = class {
4953
4963
  } else {
4954
4964
  this.logger.debug(`[Tool Execution] executeTools=false, passing tool calls to callback`);
4955
4965
  await callback([null], {
4956
- inputTokens: response.usage?.prompt_tokens || 0,
4957
- outputTokens: response.usage?.completion_tokens || 0,
4966
+ inputTokens: accumInputTokens + (response.usage?.prompt_tokens || 0),
4967
+ outputTokens: accumOutputTokens + (response.usage?.completion_tokens || 0),
4958
4968
  toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0
4959
4969
  });
4960
4970
  return;
@@ -4968,8 +4978,8 @@ var OpenAIBackend = class {
4968
4978
  if (cacheStats) logCacheStats(this.logger, cacheStats, { streaming: false });
4969
4979
  }
4970
4980
  await callback(streamedText, {
4971
- inputTokens: response.usage?.prompt_tokens || 0,
4972
- outputTokens: response.usage?.completion_tokens || 0,
4981
+ inputTokens: accumInputTokens + (response.usage?.prompt_tokens || 0),
4982
+ outputTokens: accumOutputTokens + (response.usage?.completion_tokens || 0),
4973
4983
  toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0,
4974
4984
  cacheStats
4975
4985
  });
@@ -5008,8 +5018,8 @@ var OpenAIBackend = class {
5008
5018
  if (c.delta.content) streamedText[c.index] = (streamedText[c.index] || "") + c.delta.content;
5009
5019
  });
5010
5020
  await callback(streamedText, {
5011
- inputTokens,
5012
- outputTokens,
5021
+ inputTokens: accumInputTokens + inputTokens,
5022
+ outputTokens: accumOutputTokens + outputTokens,
5013
5023
  toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0
5014
5024
  });
5015
5025
  }
@@ -5114,8 +5124,8 @@ var OpenAIBackend = class {
5114
5124
  thisToolHadArtifact = true;
5115
5125
  anyArtifactWasStreamed = true;
5116
5126
  await callback(results, {
5117
- inputTokens,
5118
- outputTokens,
5127
+ inputTokens: accumInputTokens + inputTokens,
5128
+ outputTokens: accumOutputTokens + outputTokens,
5119
5129
  toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0,
5120
5130
  cacheStats
5121
5131
  });
@@ -5138,7 +5148,9 @@ var OpenAIBackend = class {
5138
5148
  tools: anyMcpTool ? options.tools : void 0,
5139
5149
  _internal: {
5140
5150
  ...options._internal,
5141
- toolCallCount: toolCallCount + 1
5151
+ toolCallCount: toolCallCount + 1,
5152
+ accumInputTokens: accumInputTokens + inputTokens,
5153
+ accumOutputTokens: accumOutputTokens + outputTokens
5142
5154
  }
5143
5155
  }, async (results, meta) => {
5144
5156
  for (const r of results) if (r != null) recursiveBuffer += r;
@@ -5151,14 +5163,16 @@ var OpenAIBackend = class {
5151
5163
  tools: anyMcpTool ? options.tools : void 0,
5152
5164
  _internal: {
5153
5165
  ...options._internal,
5154
- toolCallCount: toolCallCount + 1
5166
+ toolCallCount: toolCallCount + 1,
5167
+ accumInputTokens: accumInputTokens + inputTokens,
5168
+ accumOutputTokens: accumOutputTokens + outputTokens
5155
5169
  }
5156
5170
  }, callback, toolsUsed);
5157
5171
  } else {
5158
5172
  this.logger.debug(`[Tool Execution] executeTools=false, passing tool calls to callback`);
5159
5173
  await callback([null], {
5160
- inputTokens,
5161
- outputTokens,
5174
+ inputTokens: accumInputTokens + inputTokens,
5175
+ outputTokens: accumOutputTokens + outputTokens,
5162
5176
  toolsUsed: toolsUsed.length > 0 ? toolsUsed : void 0,
5163
5177
  cacheStats
5164
5178
  });
@@ -6859,17 +6873,49 @@ const webFetchTool = {
6859
6873
  })
6860
6874
  };
6861
6875
  //#endregion
6862
- //#region ../../b4m-core/services/dist/jsonSanitize-NGoqEfny.mjs
6876
+ //#region ../../b4m-core/services/dist/jsonSanitize-DPYPbara.mjs
6863
6877
  /**
6864
6878
  * Sanitize a JSON string by escaping control characters inside string literals.
6865
6879
  * LLMs sometimes return JSON with unescaped newlines/tabs inside string values,
6866
6880
  * which causes JSON.parse to fail with "Bad control character in string literal".
6867
6881
  *
6868
6882
  * Covers all U+0000–U+001F control characters per JSON RFC 8259.
6883
+ *
6884
+ * Also applies a lookahead heuristic to escape unescaped double-quotes inside
6885
+ * string values — the most common LLM JSON failure mode (e.g., code snippets
6886
+ * containing logger.error("msg") inside a JSON string).
6887
+ *
6888
+ * Returns the sanitized string and the number of quotes repaired.
6889
+ * If the JSON is already valid, it is returned unchanged (zero repairs).
6869
6890
  */
6870
6891
  function sanitizeJsonString(jsonStr) {
6892
+ const { result } = sanitizeJsonStringWithMeta(jsonStr);
6893
+ return result;
6894
+ }
6895
+ function sanitizeJsonStringWithMeta(jsonStr, options) {
6896
+ try {
6897
+ JSON.parse(jsonStr);
6898
+ return {
6899
+ result: jsonStr,
6900
+ repairedQuotes: 0
6901
+ };
6902
+ } catch {}
6871
6903
  let result = "";
6872
6904
  let inString = false;
6905
+ /**
6906
+ * Tracks whether we are in a key position (true) or value position (false).
6907
+ * Starts as true — the first string in valid JSON must be a key.
6908
+ * Flips to false after a key-closing quote + colon pair.
6909
+ * Flips back to true after a value-closing quote (or structural char) + comma/`{`/`[`.
6910
+ *
6911
+ * This is used to disambiguate `:` after a `"` inside a string:
6912
+ * - In key position: `"` + `:` → structural (closes the key, colon follows)
6913
+ * - In value position: `"` + `:` → embedded (e.g., `"status": it was null"`)
6914
+ */
6915
+ let inKey = true;
6916
+ /** Tracks nested structure context for truncation repair. */
6917
+ const structureStack = [];
6918
+ let repairedQuotes = 0;
6873
6919
  let i = 0;
6874
6920
  while (i < jsonStr.length) {
6875
6921
  const char = jsonStr[i];
@@ -6879,8 +6925,25 @@ function sanitizeJsonString(jsonStr) {
6879
6925
  continue;
6880
6926
  }
6881
6927
  if (char === "\"") {
6882
- inString = !inString;
6883
- result += char;
6928
+ if (!inString) {
6929
+ inString = true;
6930
+ result += char;
6931
+ i++;
6932
+ continue;
6933
+ }
6934
+ let j = i + 1;
6935
+ while (j < jsonStr.length && (jsonStr[j] === " " || jsonStr[j] === " " || jsonStr[j] === "\r" || jsonStr[j] === "\n")) j++;
6936
+ const nextNonWs = j < jsonStr.length ? jsonStr[j] : "";
6937
+ if (nextNonWs === "," || nextNonWs === "}" || nextNonWs === "]" || nextNonWs === "" || nextNonWs === ":" && inKey) {
6938
+ inString = false;
6939
+ result += char;
6940
+ i++;
6941
+ if (nextNonWs === ":") inKey = false;
6942
+ else if (nextNonWs === "," || nextNonWs === "}" || nextNonWs === "]") inKey = true;
6943
+ continue;
6944
+ }
6945
+ result += "\\\"";
6946
+ repairedQuotes++;
6884
6947
  i++;
6885
6948
  continue;
6886
6949
  }
@@ -6907,10 +6970,45 @@ function sanitizeJsonString(jsonStr) {
6907
6970
  break;
6908
6971
  }
6909
6972
  else result += char;
6910
- } else result += char;
6973
+ } else {
6974
+ result += char;
6975
+ if (char === "{") {
6976
+ structureStack.push("{");
6977
+ inKey = true;
6978
+ } else if (char === "[") {
6979
+ structureStack.push("[");
6980
+ inKey = false;
6981
+ } else if (char === "}" || char === "]") {
6982
+ if (structureStack.length > 0) structureStack.pop();
6983
+ inKey = (structureStack.length > 0 ? structureStack[structureStack.length - 1] : null) !== "[";
6984
+ } else if (char === ",") {
6985
+ if ((structureStack.length > 0 ? structureStack[structureStack.length - 1] : null) === "{") inKey = true;
6986
+ }
6987
+ }
6911
6988
  i++;
6912
6989
  }
6913
- return result;
6990
+ if (inString) {
6991
+ if (options?.attemptTruncationRepair && structureStack.length > 0) {
6992
+ const closing = [...structureStack].reverse().map((c) => c === "{" ? "}" : "]").join("");
6993
+ const salvage = result + "\"" + closing;
6994
+ try {
6995
+ JSON.parse(salvage);
6996
+ return {
6997
+ result: salvage,
6998
+ repairedQuotes,
6999
+ truncationRepaired: true
7000
+ };
7001
+ } catch {}
7002
+ }
7003
+ return {
7004
+ result: jsonStr,
7005
+ repairedQuotes: 0
7006
+ };
7007
+ }
7008
+ return {
7009
+ result,
7010
+ repairedQuotes
7011
+ };
6914
7012
  }
6915
7013
  //#endregion
6916
7014
  //#region ../../b4m-core/quantum/dist/index.mjs
@@ -8758,7 +8856,7 @@ No markdown, no explanation, no code blocks — just the raw JSON object.`;
8758
8856
  "Minimize: sum(error^2)"
8759
8857
  ].join("\n");
8760
8858
  //#endregion
8761
- //#region ../../b4m-core/services/dist/tools-s4H4po60.mjs
8859
+ //#region ../../b4m-core/services/dist/tools-B55E_Q3K.mjs
8762
8860
  async function performDeepResearch(context, params, config) {
8763
8861
  const maxDepth = config.maxDepth || 7;
8764
8862
  const duration = config.duration || 4.5;
@@ -15798,56 +15896,6 @@ z.object({
15798
15896
  embargoDetected: z.boolean().prefault(false),
15799
15897
  suggestedTags: z.array(z.string()).prefault([])
15800
15898
  });
15801
- z.object({
15802
- userId: z.string(),
15803
- sessionId: z.string(),
15804
- questId: z.string(),
15805
- message: z.string().min(1, "Message cannot be empty"),
15806
- messageFileIds: z.array(z.string()),
15807
- historyCount: z.number(),
15808
- fabFileIds: z.array(z.string()),
15809
- params: ChatCompletionCreateInputSchema,
15810
- dashboardParams: DashboardParamsSchema.optional(),
15811
- enableQuestMaster: z.boolean().optional(),
15812
- enableMementos: z.boolean().optional(),
15813
- enableArtifacts: z.boolean().optional(),
15814
- enableAgents: z.boolean().optional(),
15815
- enableLattice: z.boolean().optional(),
15816
- promptMeta: PromptMetaZodSchema,
15817
- tools: z.array(z.union([b4mLLMTools, z.string()])).optional(),
15818
- mcpServers: z.array(z.string()).optional(),
15819
- projectId: z.string().optional(),
15820
- organizationId: z.string().nullable().optional(),
15821
- questMaster: QuestMasterParamsSchema.optional(),
15822
- toolPromptId: z.string().optional(),
15823
- researchMode: ResearchModeParamsSchema.optional(),
15824
- fallbackModel: z.string().optional(),
15825
- embeddingModel: z.string().optional(),
15826
- queryComplexity: z.string(),
15827
- imageConfig: GenerateImageToolCallSchema.optional(),
15828
- deepResearchConfig: z.object({
15829
- maxDepth: z.number().optional(),
15830
- duration: z.number().optional(),
15831
- searchers: z.array(z.any()).optional()
15832
- }).optional(),
15833
- extraContextMessages: z.array(z.object({
15834
- role: z.enum([
15835
- "user",
15836
- "assistant",
15837
- "system",
15838
- "function",
15839
- "tool"
15840
- ]),
15841
- content: z.union([z.string(), z.array(z.any())]),
15842
- fabFileIds: z.array(z.string()).optional()
15843
- })).optional(),
15844
- /** User's timezone (IANA format, e.g., "America/New_York") */
15845
- timezone: z.string().optional(),
15846
- /** Persona-based sub-agent filter — only these agent names are available for delegation */
15847
- allowedAgents: z.array(z.string()).optional(),
15848
- /** When true, Quest Processor injects Slack-specific tool configs (help, notebooks, curated files) */
15849
- enableSlackTools: z.boolean().optional()
15850
- });
15851
15899
  /**
15852
15900
  * Regex patterns for extracting GitHub entities from text
15853
15901
  */
@@ -16345,6 +16393,56 @@ var CombinedExtractor = class {
16345
16393
  }
16346
16394
  };
16347
16395
  new CombinedExtractor();
16396
+ z.object({
16397
+ userId: z.string(),
16398
+ sessionId: z.string(),
16399
+ questId: z.string(),
16400
+ message: z.string().min(1, "Message cannot be empty"),
16401
+ messageFileIds: z.array(z.string()),
16402
+ historyCount: z.number(),
16403
+ fabFileIds: z.array(z.string()),
16404
+ params: ChatCompletionCreateInputSchema,
16405
+ dashboardParams: DashboardParamsSchema.optional(),
16406
+ enableQuestMaster: z.boolean().optional(),
16407
+ enableMementos: z.boolean().optional(),
16408
+ enableArtifacts: z.boolean().optional(),
16409
+ enableAgents: z.boolean().optional(),
16410
+ enableLattice: z.boolean().optional(),
16411
+ promptMeta: PromptMetaZodSchema,
16412
+ tools: z.array(z.union([b4mLLMTools, z.string()])).optional(),
16413
+ mcpServers: z.array(z.string()).optional(),
16414
+ projectId: z.string().optional(),
16415
+ organizationId: z.string().nullable().optional(),
16416
+ questMaster: QuestMasterParamsSchema.optional(),
16417
+ toolPromptId: z.string().optional(),
16418
+ researchMode: ResearchModeParamsSchema.optional(),
16419
+ fallbackModel: z.string().optional(),
16420
+ embeddingModel: z.string().optional(),
16421
+ queryComplexity: z.string(),
16422
+ imageConfig: GenerateImageToolCallSchema.optional(),
16423
+ deepResearchConfig: z.object({
16424
+ maxDepth: z.number().optional(),
16425
+ duration: z.number().optional(),
16426
+ searchers: z.array(z.any()).optional()
16427
+ }).optional(),
16428
+ extraContextMessages: z.array(z.object({
16429
+ role: z.enum([
16430
+ "user",
16431
+ "assistant",
16432
+ "system",
16433
+ "function",
16434
+ "tool"
16435
+ ]),
16436
+ content: z.union([z.string(), z.array(z.any())]),
16437
+ fabFileIds: z.array(z.string()).optional()
16438
+ })).optional(),
16439
+ /** User's timezone (IANA format, e.g., "America/New_York") */
16440
+ timezone: z.string().optional(),
16441
+ /** Persona-based sub-agent filter — only these agent names are available for delegation */
16442
+ allowedAgents: z.array(z.string()).optional(),
16443
+ /** When true, Quest Processor injects Slack-specific tool configs (help, notebooks, curated files) */
16444
+ enableSlackTools: z.boolean().optional()
16445
+ });
16348
16446
  (class AnomalyAlertService {
16349
16447
  static {
16350
16448
  this.MAX_CACHE_ENTRIES = 1e3;
@@ -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.5.0";
7
+ var version = "0.6.0";
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.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -32,15 +32,15 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@anthropic-ai/sdk": "^0.79.0",
35
- "@aws-sdk/client-apigatewaymanagementapi": "^3.1026.0",
36
- "@aws-sdk/client-bedrock-runtime": "^3.1026.0",
37
- "@aws-sdk/client-cloudwatch": "^3.1026.0",
38
- "@aws-sdk/client-lambda": "^3.1026.0",
39
- "@aws-sdk/client-s3": "^3.1026.0",
40
- "@aws-sdk/client-sqs": "^3.1026.0",
41
- "@aws-sdk/client-transcribe": "^3.1026.0",
42
- "@aws-sdk/credential-provider-node": "^3.972.30",
43
- "@aws-sdk/s3-request-presigner": "^3.1026.0",
35
+ "@aws-sdk/client-apigatewaymanagementapi": "^3.1041.0",
36
+ "@aws-sdk/client-bedrock-runtime": "^3.1041.0",
37
+ "@aws-sdk/client-cloudwatch": "^3.1041.0",
38
+ "@aws-sdk/client-lambda": "^3.1041.0",
39
+ "@aws-sdk/client-s3": "^3.1041.0",
40
+ "@aws-sdk/client-sqs": "^3.1041.0",
41
+ "@aws-sdk/client-transcribe": "^3.1041.0",
42
+ "@aws-sdk/credential-provider-node": "^3.972.39",
43
+ "@aws-sdk/s3-request-presigner": "^3.1041.0",
44
44
  "@casl/ability": "^6.8.1",
45
45
  "@google/genai": "^1.46.0",
46
46
  "@joplin/turndown-plugin-gfm": "^1.0.64",
@@ -48,7 +48,7 @@
48
48
  "@modelcontextprotocol/sdk": "1.27.1",
49
49
  "@octokit/rest": "^22.0.1",
50
50
  "@opensearch-project/opensearch": "2.11.0",
51
- "@smithy/node-http-handler": "^4.5.2",
51
+ "@smithy/node-http-handler": "^4.6.1",
52
52
  "async-mutex": "^0.5.0",
53
53
  "axios": "1.15.1",
54
54
  "bcryptjs": "^3.0.2",
@@ -63,7 +63,7 @@
63
63
  "eventsource-parser": "^3.0.8",
64
64
  "exceljs": "^4.4.0",
65
65
  "fdir": "^6.5.0",
66
- "file-type": "^18.7.0",
66
+ "file-type": "^22.0.1",
67
67
  "fuse.js": "^7.3.0",
68
68
  "fzf": "^0.5.2",
69
69
  "glob": "^13.0.6",
@@ -78,7 +78,7 @@
78
78
  "mammoth": "^1.12.0",
79
79
  "marked": "^15.0.11",
80
80
  "mathjs": "^15.2.0",
81
- "mime-types": "^2.1.35",
81
+ "mime-types": "^3.0.2",
82
82
  "mongoose": "^8.8.3",
83
83
  "ollama": "^0.6.3",
84
84
  "open": "^11.0.0",
@@ -103,7 +103,7 @@
103
103
  "yauzl": "^3.3.0",
104
104
  "zod": "^4.3.6",
105
105
  "zod-validation-error": "^5.0.0",
106
- "zustand": "^4.5.4"
106
+ "zustand": "^5.0.13"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@types/better-sqlite3": "^7.6.13",
@@ -118,11 +118,11 @@
118
118
  "tsx": "^4.21.0",
119
119
  "typescript": "^5.9.3",
120
120
  "vitest": "^4.1.2",
121
- "@bike4mind/agents": "0.5.3",
122
- "@bike4mind/common": "2.89.0",
123
- "@bike4mind/mcp": "1.36.0",
124
- "@bike4mind/services": "2.77.0",
125
- "@bike4mind/utils": "2.18.10"
121
+ "@bike4mind/agents": "0.0.0-changeset-release-main-20260505221459",
122
+ "@bike4mind/common": "0.0.0-changeset-release-main-20260505221459",
123
+ "@bike4mind/mcp": "0.0.0-changeset-release-main-20260505221459",
124
+ "@bike4mind/services": "0.0.0-changeset-release-main-20260505221459",
125
+ "@bike4mind/utils": "0.0.0-changeset-release-main-20260505221459"
126
126
  },
127
127
  "optionalDependencies": {
128
128
  "@vscode/ripgrep": "^1.17.1"