@bike4mind/cli 0.5.0 → 0.6.1
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.
- package/README.md +98 -5
- package/dist/{ConfigStore-DBUmvCfe.mjs → ConfigStore-Dt6utdSA.mjs} +53 -2
- package/dist/commands/doctorCommand.mjs +19 -19
- package/dist/commands/headlessCommand.mjs +2 -2
- package/dist/commands/mcpCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/index.mjs +292 -10
- package/dist/{tools-V5FJ83BJ.mjs → tools-BUs_OkJc.mjs} +173 -75
- package/dist/{updateChecker-Boy2GLk4.mjs → updateChecker-D-xoVcN3.mjs} +3 -3
- package/package.json +18 -18
package/README.md
CHANGED
|
@@ -384,18 +384,111 @@ tail -f ~/.bike4mind/debug/[session-id].txt
|
|
|
384
384
|
|
|
385
385
|
## Development
|
|
386
386
|
|
|
387
|
+
This section covers the contributor workflow for hacking on the CLI from a checkout of the monorepo. For end-user installation see [Installation](#installation) above.
|
|
388
|
+
|
|
389
|
+
### How the bin resolves source vs. built code
|
|
390
|
+
|
|
391
|
+
`apps/cli/bin/bike4mind-cli.mjs` auto-detects which mode to run in:
|
|
392
|
+
|
|
393
|
+
- If `apps/cli/dist/index.mjs` exists → runs the bundled production build
|
|
394
|
+
- Otherwise → falls back to `tsx` and imports `src/index.tsx` directly
|
|
395
|
+
|
|
396
|
+
This means **you do not need to rebuild the CLI itself between source edits** — `tsx` reads `src/` live on every invocation. The rebuild burden is only on the workspace packages that the CLI imports (see below).
|
|
397
|
+
|
|
398
|
+
### Quick start
|
|
399
|
+
|
|
400
|
+
From the repo root:
|
|
401
|
+
|
|
387
402
|
```bash
|
|
388
|
-
#
|
|
403
|
+
# 1. Install all workspace dependencies
|
|
404
|
+
pnpm install
|
|
405
|
+
|
|
406
|
+
# 2. Build the @bike4mind/* core packages so the CLI can import their dist/ outputs
|
|
407
|
+
pnpm turbo:core:build
|
|
408
|
+
|
|
409
|
+
# 3. Make the `b4m` and `bike4mind` commands point at this checkout
|
|
389
410
|
cd apps/cli
|
|
390
|
-
pnpm
|
|
411
|
+
pnpm link --global
|
|
412
|
+
|
|
413
|
+
# 4. Verify
|
|
414
|
+
which b4m
|
|
415
|
+
b4m --version
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
After step 3, running `b4m` anywhere on your system executes this working tree. Re-run `pnpm link --global` if you move or rename the repo.
|
|
419
|
+
|
|
420
|
+
### Editing CLI source (`apps/cli/src/`)
|
|
421
|
+
|
|
422
|
+
Just run `b4m`. The bin's `tsx` fallback picks up your edits on the next invocation — no build step needed.
|
|
423
|
+
|
|
424
|
+
If you want to test the bundled production path (the same code an end user would run after `npm install -g @bike4mind/cli`):
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
pnpm --filter @bike4mind/cli build
|
|
428
|
+
b4m # now uses dist/index.mjs
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
To drop back into source mode, delete `dist/`:
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
rm -rf apps/cli/dist
|
|
435
|
+
```
|
|
391
436
|
|
|
392
|
-
|
|
393
|
-
pnpm build
|
|
437
|
+
### Editing workspace dependencies (`b4m-core/*`)
|
|
394
438
|
|
|
395
|
-
|
|
439
|
+
The CLI imports `@bike4mind/agents`, `@bike4mind/services`, `@bike4mind/utils`, `@bike4mind/mcp`, and `@bike4mind/common` via pnpm symlinks that resolve to each package's `dist/` (per its `exports` field). Source edits in those packages require a rebuild before `b4m` will see them.
|
|
440
|
+
|
|
441
|
+
Rebuild only the package you touched:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
pnpm --filter @bike4mind/agents build
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Or rebuild the whole core graph (cached, near-instant if only one package changed):
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
pnpm turbo:core:build
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
The next `b4m` invocation picks up the change. The CLI itself does not need to be rebuilt.
|
|
454
|
+
|
|
455
|
+
### Watch mode (optional)
|
|
456
|
+
|
|
457
|
+
Each core package exposes `"dev": "tsdown --watch"`. In a separate terminal:
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
pnpm --filter @bike4mind/agents dev
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
`dist/` rebuilds on save, so the next `b4m` invocation sees changes without a manual `build`.
|
|
464
|
+
|
|
465
|
+
Caveats:
|
|
466
|
+
- This does **not** hot-reload an already-running interactive `b4m` session — you still exit and re-run.
|
|
467
|
+
- Running multiple watchers in parallel (one per package you're touching) hasn't been load-tested in this repo. If watch seems to miss changes or feels unreliable, fall back to manual `pnpm --filter <pkg> build`.
|
|
468
|
+
|
|
469
|
+
### Verification commands
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
# Inside apps/cli
|
|
396
473
|
pnpm typecheck
|
|
474
|
+
pnpm test
|
|
475
|
+
pnpm test:watch
|
|
476
|
+
|
|
477
|
+
# From repo root (cached, recommended)
|
|
478
|
+
pnpm turbo:typecheck
|
|
479
|
+
pnpm turbo:test
|
|
480
|
+
|
|
481
|
+
# Run with debug logs
|
|
482
|
+
b4m --verbose
|
|
397
483
|
```
|
|
398
484
|
|
|
485
|
+
### Common pitfalls
|
|
486
|
+
|
|
487
|
+
- **Don't `pnpm --filter @bike4mind/cli build` after every CLI source edit.** It's wasted work — the `tsx` fallback already runs your source live.
|
|
488
|
+
- **Don't use `npm link`.** This repo is pnpm-only; mixing tools breaks symlink resolution.
|
|
489
|
+
- **A stale `apps/cli/dist/` will mask your source changes.** If `b4m` is showing old behavior, check whether `dist/index.mjs` exists — the bin will prefer it over `src/`. Delete `dist/` to drop back to source mode.
|
|
490
|
+
- **First-run native module errors** (`better-sqlite3`, `sharp`): see [Build Requirements](#build-requirements) above. The postinstall hook handles most cases automatically.
|
|
491
|
+
|
|
399
492
|
## Architecture
|
|
400
493
|
|
|
401
494
|
```
|
|
@@ -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(
|
|
1073
|
+
maxOutputTokens: z.number().default(16e3),
|
|
1066
1074
|
maxGithubApiCalls: z.number().default(20)
|
|
1067
1075
|
}).default({
|
|
1068
1076
|
maxInputTokens: 5e4,
|
|
1069
|
-
maxOutputTokens:
|
|
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 {
|
|
2
|
+
import { a as version, n as compareSemver, r as fetchLatestVersion } from "../updateChecker-D-xoVcN3.mjs";
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
4
|
import { constants, existsSync, promises } from "fs";
|
|
5
5
|
import { homedir } from "os";
|
|
@@ -25,29 +25,29 @@ async function handleDoctorCommand() {
|
|
|
25
25
|
status: "fail",
|
|
26
26
|
message: `${nodeVersion} (>= 18 required, please upgrade)`
|
|
27
27
|
});
|
|
28
|
+
const currentVersion = version;
|
|
28
29
|
const latestVersion = await fetchLatestVersion();
|
|
29
|
-
if (latestVersion)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
if (latestVersion) {
|
|
31
|
+
results.push({
|
|
32
|
+
name: "NPM registry",
|
|
33
|
+
status: "pass",
|
|
34
|
+
message: `Accessible (latest: v${latestVersion})`
|
|
35
|
+
});
|
|
36
|
+
if (compareSemver(latestVersion, currentVersion) > 0) results.push({
|
|
37
|
+
name: "Version",
|
|
38
|
+
status: "warn",
|
|
39
|
+
message: `v${currentVersion} installed, v${latestVersion} available. Run: b4m update`
|
|
40
|
+
});
|
|
41
|
+
else results.push({
|
|
42
|
+
name: "Version",
|
|
43
|
+
status: "pass",
|
|
44
|
+
message: `v${currentVersion} (latest)`
|
|
45
|
+
});
|
|
46
|
+
} else results.push({
|
|
35
47
|
name: "NPM registry",
|
|
36
48
|
status: "fail",
|
|
37
49
|
message: "Not accessible — check your internet connection"
|
|
38
50
|
});
|
|
39
|
-
const currentVersion = version;
|
|
40
|
-
const updateResult = await forceCheckForUpdate(currentVersion);
|
|
41
|
-
if (updateResult) if (updateResult.updateAvailable) results.push({
|
|
42
|
-
name: "Version",
|
|
43
|
-
status: "warn",
|
|
44
|
-
message: `v${currentVersion} installed, v${updateResult.latestVersion} available. Run: b4m update`
|
|
45
|
-
});
|
|
46
|
-
else results.push({
|
|
47
|
-
name: "Version",
|
|
48
|
-
status: "pass",
|
|
49
|
-
message: `v${currentVersion} (latest)`
|
|
50
|
-
});
|
|
51
51
|
try {
|
|
52
52
|
const npmPrefix = execSync("npm config get prefix", {
|
|
53
53
|
encoding: "utf-8",
|
|
@@ -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-
|
|
3
|
-
import { n as logger, t as ConfigStore } from "../ConfigStore-
|
|
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-BUs_OkJc.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 {
|
|
2
|
+
import { a as version, i as forceCheckForUpdate } from "../updateChecker-D-xoVcN3.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-
|
|
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-
|
|
5
|
-
import {
|
|
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-BUs_OkJc.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 { a as version, t as checkForUpdate } from "./updateChecker-D-xoVcN3.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
|
/**
|
|
@@ -5138,7 +5335,8 @@ function CliApp() {
|
|
|
5138
5335
|
console.log("\n🔐 Welcome to B4M CLI! Authentication is required to get started.\n");
|
|
5139
5336
|
setState((prev) => ({
|
|
5140
5337
|
...prev,
|
|
5141
|
-
showLoginFlow: true
|
|
5338
|
+
showLoginFlow: true,
|
|
5339
|
+
config
|
|
5142
5340
|
}));
|
|
5143
5341
|
return;
|
|
5144
5342
|
}
|
|
@@ -5148,7 +5346,8 @@ function CliApp() {
|
|
|
5148
5346
|
await state.configStore.clearAuthTokens();
|
|
5149
5347
|
setState((prev) => ({
|
|
5150
5348
|
...prev,
|
|
5151
|
-
showLoginFlow: true
|
|
5349
|
+
showLoginFlow: true,
|
|
5350
|
+
config
|
|
5152
5351
|
}));
|
|
5153
5352
|
return;
|
|
5154
5353
|
}
|
|
@@ -6426,6 +6625,46 @@ function CliApp() {
|
|
|
6426
6625
|
console.log("");
|
|
6427
6626
|
}
|
|
6428
6627
|
};
|
|
6628
|
+
/**
|
|
6629
|
+
* Generate a structured session handoff via a single LLM call and persist it
|
|
6630
|
+
* onto the session's workflow state. Returns the handoff on success, or null
|
|
6631
|
+
* if generation was skipped (short session) or failed (parse / agent error).
|
|
6632
|
+
*
|
|
6633
|
+
* Failures are best-effort and surfaced as a warning rather than thrown —
|
|
6634
|
+
* the surrounding /save flow must not block on handoff generation.
|
|
6635
|
+
*
|
|
6636
|
+
* Callers are responsible for saving the session afterwards.
|
|
6637
|
+
*/
|
|
6638
|
+
const generateHandoff = async (session) => {
|
|
6639
|
+
if (!state.agent) return null;
|
|
6640
|
+
const prompt = buildHandoffPrompt(session);
|
|
6641
|
+
if (!prompt) return null;
|
|
6642
|
+
console.log("📝 Generating session handoff...");
|
|
6643
|
+
useCliStore.getState().setIsThinking(true);
|
|
6644
|
+
try {
|
|
6645
|
+
const result = await state.agent.run(prompt, { maxIterations: 1 });
|
|
6646
|
+
const handoff = parseHandoffResponse(result.finalAnswer);
|
|
6647
|
+
if (!handoff) {
|
|
6648
|
+
console.warn("⚠️ Handoff generation returned no parseable JSON; skipping.");
|
|
6649
|
+
logger.debug(`Handoff response: ${result.finalAnswer.slice(0, 500)}`);
|
|
6650
|
+
return null;
|
|
6651
|
+
}
|
|
6652
|
+
session.metadata.workflow = {
|
|
6653
|
+
decisions: decisionStoreRef.current.decisions,
|
|
6654
|
+
blockers: blockerStoreRef.current.blockers,
|
|
6655
|
+
handoff,
|
|
6656
|
+
reviewGates: session.metadata.workflow?.reviewGates
|
|
6657
|
+
};
|
|
6658
|
+
return handoff;
|
|
6659
|
+
} catch (err) {
|
|
6660
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
6661
|
+
console.warn(`⚠️ Handoff generation failed: ${reason}`);
|
|
6662
|
+
logger.debug(`Handoff generation error: ${reason}`);
|
|
6663
|
+
return null;
|
|
6664
|
+
} finally {
|
|
6665
|
+
useCliStore.getState().setIsThinking(false);
|
|
6666
|
+
}
|
|
6667
|
+
};
|
|
6429
6668
|
const handleCommand = async (command, args) => {
|
|
6430
6669
|
const customCommand = state.customCommandStore.getCommand(command);
|
|
6431
6670
|
if (customCommand) try {
|
|
@@ -6565,8 +6804,10 @@ Multi-line Input:
|
|
|
6565
6804
|
handoff: state.session.metadata.workflow?.handoff,
|
|
6566
6805
|
reviewGates: state.session.metadata.workflow?.reviewGates
|
|
6567
6806
|
};
|
|
6807
|
+
const handoff = await generateHandoff(state.session);
|
|
6568
6808
|
await state.sessionStore.save(state.session);
|
|
6569
6809
|
console.log(`✅ Session saved as "${sessionName}"`);
|
|
6810
|
+
if (handoff) console.log("🤝 Session handoff generated");
|
|
6570
6811
|
break;
|
|
6571
6812
|
}
|
|
6572
6813
|
case "resume":
|
|
@@ -6592,15 +6833,24 @@ Multi-line Input:
|
|
|
6592
6833
|
await logger.initialize(loadedSession.id);
|
|
6593
6834
|
logger.debug("=== Session Resumed ===");
|
|
6594
6835
|
if (state.checkpointStore) state.checkpointStore.setSessionId(loadedSession.id);
|
|
6836
|
+
const handoff = loadedSession.metadata.workflow?.handoff;
|
|
6837
|
+
const sessionForState = handoff ? {
|
|
6838
|
+
...loadedSession,
|
|
6839
|
+
messages: injectHandoffMessage(loadedSession.messages, handoff)
|
|
6840
|
+
} : loadedSession;
|
|
6595
6841
|
setState((prev) => ({
|
|
6596
6842
|
...prev,
|
|
6597
|
-
session:
|
|
6843
|
+
session: sessionForState
|
|
6598
6844
|
}));
|
|
6599
|
-
setStoreSession(
|
|
6845
|
+
setStoreSession(sessionForState);
|
|
6600
6846
|
useCliStore.getState().clearPendingMessages();
|
|
6601
6847
|
usageCache = null;
|
|
6602
|
-
console.log(`\n✅ Session resumed: "${
|
|
6603
|
-
console.log(`📝 ${
|
|
6848
|
+
console.log(`\n✅ Session resumed: "${sessionForState.name}"`);
|
|
6849
|
+
console.log(`📝 ${sessionForState.messages.length} messages | 🤖 ${sessionForState.model} | 📊 ${sessionForState.metadata.totalTokens.toLocaleString()} tokens\n`);
|
|
6850
|
+
if (handoff) {
|
|
6851
|
+
console.log("🤝 Session handoff:\n");
|
|
6852
|
+
console.log(formatHandoffOutput(handoff));
|
|
6853
|
+
}
|
|
6604
6854
|
};
|
|
6605
6855
|
setState((prev) => ({
|
|
6606
6856
|
...prev,
|
|
@@ -7528,6 +7778,38 @@ Multi-line Input:
|
|
|
7528
7778
|
console.log(formatBlockersOutput(blockerStoreRef.current.blockers));
|
|
7529
7779
|
console.log("");
|
|
7530
7780
|
break;
|
|
7781
|
+
case "handoff": {
|
|
7782
|
+
if (!state.session) {
|
|
7783
|
+
console.log("No active session");
|
|
7784
|
+
break;
|
|
7785
|
+
}
|
|
7786
|
+
const existing = state.session.metadata.workflow?.handoff;
|
|
7787
|
+
const wantsRegen = args[0] === "generate" || args[0] === "regen";
|
|
7788
|
+
if (existing && !wantsRegen) {
|
|
7789
|
+
console.log("\n🤝 Session handoff\n");
|
|
7790
|
+
console.log(formatHandoffOutput(existing));
|
|
7791
|
+
console.log("Run /handoff generate to refresh.\n");
|
|
7792
|
+
break;
|
|
7793
|
+
}
|
|
7794
|
+
if (state.session.messages.length < 4) {
|
|
7795
|
+
console.log(`Not enough messages to generate a handoff (need at least 4)`);
|
|
7796
|
+
break;
|
|
7797
|
+
}
|
|
7798
|
+
if (!state.agent) {
|
|
7799
|
+
console.log("Cannot generate handoff: no active agent");
|
|
7800
|
+
break;
|
|
7801
|
+
}
|
|
7802
|
+
const handoff = await generateHandoff(state.session);
|
|
7803
|
+
if (!handoff) {
|
|
7804
|
+
console.log("❌ Failed to generate handoff");
|
|
7805
|
+
break;
|
|
7806
|
+
}
|
|
7807
|
+
await state.sessionStore.save(state.session);
|
|
7808
|
+
console.log("\n🤝 Session handoff\n");
|
|
7809
|
+
console.log(formatHandoffOutput(handoff));
|
|
7810
|
+
console.log("\n✅ Session saved with refreshed handoff");
|
|
7811
|
+
break;
|
|
7812
|
+
}
|
|
7531
7813
|
case "dirs": {
|
|
7532
7814
|
const additionalDirs = await state.configStore.getAdditionalDirectories();
|
|
7533
7815
|
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-
|
|
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
|
/**
|
|
@@ -2902,7 +2906,7 @@ const TOOL_FILE_READ = "file_read";
|
|
|
2902
2906
|
const TOOL_EDIT_LOCAL_FILE = "edit_local_file";
|
|
2903
2907
|
const TOOL_CREATE_FILE = "create_file";
|
|
2904
2908
|
const TOOL_BASH_EXECUTE = "bash_execute";
|
|
2905
|
-
const TOOL_SUBAGENT_DELEGATE = "
|
|
2909
|
+
const TOOL_SUBAGENT_DELEGATE = "agent_delegate";
|
|
2906
2910
|
const TOOL_WRITE_TODOS = "write_todos";
|
|
2907
2911
|
const TOOL_CREATE_DYNAMIC_AGENT = "create_dynamic_agent";
|
|
2908
2912
|
const EXPLORE_SUBAGENT_TYPE = "explore";
|
|
@@ -3021,7 +3025,7 @@ EXAMPLES:
|
|
|
3021
3025
|
- "how about Japan?" → use weather tool for Japan (applying same question from context)
|
|
3022
3026
|
- "enhance README" → ${TOOL_FILE_READ} → generate → ${TOOL_EDIT_LOCAL_FILE}
|
|
3023
3027
|
- "what packages installed?" → ${TOOL_GLOB_FILES} "**/package.json" → ${TOOL_FILE_READ}
|
|
3024
|
-
- "find all components using React hooks" → ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks",
|
|
3028
|
+
- "find all components using React hooks" → ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks", agent="explore")
|
|
3025
3029
|
|
|
3026
3030
|
Remember: Use context from previous messages to understand follow-up questions.
|
|
3027
3031
|
|
|
@@ -3099,8 +3103,7 @@ var AIImageService = class {
|
|
|
3099
3103
|
}
|
|
3100
3104
|
};
|
|
3101
3105
|
//#endregion
|
|
3102
|
-
//#region ../../b4m-core/
|
|
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-
|
|
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
|
-
|
|
6883
|
-
|
|
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
|
|
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
|
-
|
|
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-
|
|
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;
|
|
@@ -21897,7 +21995,7 @@ Describe the expected output format here.
|
|
|
21897
21995
|
*/
|
|
21898
21996
|
getDirectoryContext() {
|
|
21899
21997
|
if (this.agents.size === 0) return "No sub-agents are currently available.";
|
|
21900
|
-
let context = "Use `
|
|
21998
|
+
let context = "Use `agent_delegate` for complex tasks requiring specialized analysis.\n";
|
|
21901
21999
|
for (const [name, def] of this.agents) context += ` - **${name}**: ${def.description}\n`;
|
|
21902
22000
|
return context;
|
|
21903
22001
|
}
|
|
@@ -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.
|
|
7
|
+
var version = "0.6.1";
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/utils/updateChecker.ts
|
|
10
10
|
/**
|
|
@@ -53,7 +53,7 @@ async function readCache() {
|
|
|
53
53
|
try {
|
|
54
54
|
const data = await promises.readFile(CACHE_FILE, "utf-8");
|
|
55
55
|
const parsed = JSON.parse(data);
|
|
56
|
-
if (parsed && typeof parsed.lastChecked === "string" && typeof parsed.latestVersion === "string") return parsed;
|
|
56
|
+
if (parsed && typeof parsed.lastChecked === "string" && typeof parsed.latestVersion === "string" && typeof parsed.currentVersion === "string") return parsed;
|
|
57
57
|
return null;
|
|
58
58
|
} catch {
|
|
59
59
|
return null;
|
|
@@ -117,4 +117,4 @@ async function forceCheckForUpdate(currentVersion) {
|
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
119
|
//#endregion
|
|
120
|
-
export { version as i,
|
|
120
|
+
export { version as a, forceCheckForUpdate as i, compareSemver as n, fetchLatestVersion as r, checkForUpdate as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
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.
|
|
36
|
-
"@aws-sdk/client-bedrock-runtime": "^3.
|
|
37
|
-
"@aws-sdk/client-cloudwatch": "^3.
|
|
38
|
-
"@aws-sdk/client-lambda": "^3.
|
|
39
|
-
"@aws-sdk/client-s3": "^3.
|
|
40
|
-
"@aws-sdk/client-sqs": "^3.
|
|
41
|
-
"@aws-sdk/client-transcribe": "^3.
|
|
42
|
-
"@aws-sdk/credential-provider-node": "^3.972.
|
|
43
|
-
"@aws-sdk/s3-request-presigner": "^3.
|
|
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.
|
|
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": "^
|
|
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": "^
|
|
81
|
+
"mime-types": "^3.0.2",
|
|
82
82
|
"mongoose": "^8.8.3",
|
|
83
83
|
"ollama": "^0.6.3",
|
|
84
84
|
"open": "^11.0.0",
|
|
@@ -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.
|
|
122
|
-
"@bike4mind/common": "2.
|
|
123
|
-
"@bike4mind/mcp": "1.
|
|
124
|
-
"@bike4mind/services": "2.
|
|
125
|
-
"@bike4mind/utils": "2.
|
|
121
|
+
"@bike4mind/agents": "0.6.3",
|
|
122
|
+
"@bike4mind/common": "2.92.1",
|
|
123
|
+
"@bike4mind/mcp": "1.37.3",
|
|
124
|
+
"@bike4mind/services": "2.79.3",
|
|
125
|
+
"@bike4mind/utils": "2.19.3"
|
|
126
126
|
},
|
|
127
127
|
"optionalDependencies": {
|
|
128
128
|
"@vscode/ripgrep": "^1.17.1"
|