@bike4mind/cli 0.10.3 → 0.12.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.
- package/README.md +29 -0
- package/bin/bike4mind-cli.mjs +57 -0
- package/dist/{ConfigStore-tjtx9TU6.mjs → ConfigStore-CtBZ2p4M.mjs} +359 -2
- package/dist/commands/apiCommand.mjs +1 -1
- package/dist/commands/doctorCommand.mjs +2 -1
- package/dist/commands/envCommand.mjs +25 -0
- package/dist/commands/headlessCommand.mjs +2 -2
- package/dist/commands/mcpCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +2 -1
- package/dist/index.mjs +41 -9
- package/dist/package-8UMmdI7b.mjs +5 -0
- package/dist/{tools-DyWEu4_d.mjs → tools-BuaOUcTS.mjs} +132 -31
- package/dist/{updateChecker-CS84T-KX.mjs → updateChecker-D67NPlS5.mjs} +1 -4
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -74,6 +74,8 @@ b4m [options]
|
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
**Available flags:**
|
|
77
|
+
- `--dev` - Point the CLI at the local dev server (`http://localhost:3001`) and remember it
|
|
78
|
+
- `--prod` - Point the CLI at Bike4Mind production and remember it
|
|
77
79
|
- `--verbose`, `-v` - Show debug logs in console (useful for troubleshooting)
|
|
78
80
|
- `--help`, `-h` - Show help information
|
|
79
81
|
- `--version`, `-V` - Show CLI version
|
|
@@ -90,6 +92,28 @@ b4m --version
|
|
|
90
92
|
b4m --help
|
|
91
93
|
```
|
|
92
94
|
|
|
95
|
+
### Switching environments (`--dev` / `--prod`)
|
|
96
|
+
|
|
97
|
+
Flip which backend the CLI talks to without editing config by hand:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
b4m --dev # local dev server (http://localhost:3001)
|
|
101
|
+
b4m --prod # Bike4Mind production
|
|
102
|
+
b4m # reuses whichever environment you last selected (sticky)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The choice is persisted to `~/.bike4mind/config.json`, so a bare `b4m` always
|
|
106
|
+
reopens the environment you last chose. Both single- and double-dash forms work
|
|
107
|
+
(`-dev`/`--dev`, `-prod`/`--prod`); `--local` is an alias for `--dev`.
|
|
108
|
+
|
|
109
|
+
Auth tokens are cached **per environment**, so switching back and forth does not
|
|
110
|
+
force a re-login — each environment remembers its own session. The first time you
|
|
111
|
+
visit a new environment you'll be prompted to `/login`. The active environment is
|
|
112
|
+
shown in the startup banner (`🌍 API Environment: …`).
|
|
113
|
+
|
|
114
|
+
> For a one-off custom/self-hosted URL, use the in-session `/set-api <url>` command
|
|
115
|
+
> (see [API Configuration](#api-configuration) below).
|
|
116
|
+
|
|
93
117
|
## Commands
|
|
94
118
|
|
|
95
119
|
While in interactive mode:
|
|
@@ -137,6 +161,11 @@ Authentication tokens are securely stored in your config file with restricted pe
|
|
|
137
161
|
|
|
138
162
|
By default, the CLI connects to the main Bike4Mind service at `https://app.bike4mind.com`.
|
|
139
163
|
|
|
164
|
+
**Quick switch between local dev and production:** use the `b4m --dev` / `b4m --prod`
|
|
165
|
+
launch flags (see [Switching environments](#switching-environments---dev----prod)).
|
|
166
|
+
They persist your choice and cache auth per-environment. The `/set-api`, `/reset-api`,
|
|
167
|
+
and `/api-info` commands below operate on the same setting from inside a session.
|
|
168
|
+
|
|
140
169
|
**For Self-Hosted Instances:**
|
|
141
170
|
|
|
142
171
|
If your organization runs a self-hosted Bike4Mind instance, connect to it using:
|
package/bin/bike4mind-cli.mjs
CHANGED
|
@@ -33,8 +33,43 @@ const require = createRequire(import.meta.url);
|
|
|
33
33
|
// whichever package.json it discovers first, which is not necessarily ours.
|
|
34
34
|
const { version: cliVersion } = require('../package.json');
|
|
35
35
|
|
|
36
|
+
// --- API environment flags (--dev / --prod) ---
|
|
37
|
+
// Intercept these BEFORE yargs parses argv. They're accepted with either a
|
|
38
|
+
// single or double dash (e.g. `b4m -prod` and `b4m --prod` both work), but
|
|
39
|
+
// single-dash multi-char tokens would otherwise be split into clustered short
|
|
40
|
+
// flags by yargs (`-prod` → `-p -r -o -d`, colliding with -p/--prompt). We pull
|
|
41
|
+
// them out here, record the target, and strip them so yargs sees a clean argv.
|
|
42
|
+
const ENV_FLAG_MAP = {
|
|
43
|
+
'--dev': 'dev', '-dev': 'dev', '--local': 'dev', '-local': 'dev',
|
|
44
|
+
'--prod': 'prod', '-prod': 'prod', '--production': 'prod', '-production': 'prod',
|
|
45
|
+
};
|
|
46
|
+
let envTarget = null;
|
|
47
|
+
{
|
|
48
|
+
const cleaned = [];
|
|
49
|
+
for (const token of process.argv.slice(2)) {
|
|
50
|
+
if (Object.prototype.hasOwnProperty.call(ENV_FLAG_MAP, token)) {
|
|
51
|
+
envTarget = ENV_FLAG_MAP[token]; // last one wins
|
|
52
|
+
} else {
|
|
53
|
+
cleaned.push(token);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Rebuild argv without the env tokens so yargs doesn't choke on them.
|
|
57
|
+
process.argv = [process.argv[0], process.argv[1], ...cleaned];
|
|
58
|
+
}
|
|
59
|
+
|
|
36
60
|
// Parse CLI arguments
|
|
37
61
|
const argv = await yargs(hideBin(process.argv))
|
|
62
|
+
// --dev / --prod are declared here ONLY so they appear in `--help`. The actual
|
|
63
|
+
// handling is the pre-yargs argv interception above — these yargs-side values
|
|
64
|
+
// (`argv.dev` / `argv.prod`) are never read.
|
|
65
|
+
.option('dev', {
|
|
66
|
+
type: 'boolean',
|
|
67
|
+
description: 'Point the CLI at the local dev server (http://localhost:3001) and remember it',
|
|
68
|
+
})
|
|
69
|
+
.option('prod', {
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
description: 'Point the CLI at Bike4Mind production and remember it',
|
|
72
|
+
})
|
|
38
73
|
.option('verbose', {
|
|
39
74
|
alias: 'v',
|
|
40
75
|
type: 'boolean',
|
|
@@ -204,6 +239,28 @@ if (argv['reset-api'] || argv['api-url'] !== undefined) {
|
|
|
204
239
|
}
|
|
205
240
|
}
|
|
206
241
|
|
|
242
|
+
// Apply --dev / --prod environment switch before anything connects to a server.
|
|
243
|
+
// This persists the choice (sticky: a bare `b4m` reuses the last selection) and
|
|
244
|
+
// swaps in that environment's cached auth token.
|
|
245
|
+
if (envTarget) {
|
|
246
|
+
try {
|
|
247
|
+
let applyEnvironmentFlag;
|
|
248
|
+
|
|
249
|
+
if (isDev) {
|
|
250
|
+
const { register } = require('tsx/esm/api');
|
|
251
|
+
register();
|
|
252
|
+
({ applyEnvironmentFlag } = await import('../src/commands/envCommand.ts'));
|
|
253
|
+
} else {
|
|
254
|
+
({ applyEnvironmentFlag } = await import('../dist/commands/envCommand.mjs'));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
await applyEnvironmentFlag(envTarget);
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error('Failed to switch API environment:', error.message);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
207
264
|
// Handle headless mode (-p / --prompt flag)
|
|
208
265
|
// Must be done after isDev detection to use correct import path
|
|
209
266
|
if (argv.prompt !== undefined) {
|
|
@@ -987,6 +987,13 @@ let CreditHolderType = /* @__PURE__ */ function(CreditHolderType) {
|
|
|
987
987
|
CreditHolderType["Agent"] = "Agent";
|
|
988
988
|
return CreditHolderType;
|
|
989
989
|
}({});
|
|
990
|
+
const COMPLETION_SOURCES = [
|
|
991
|
+
"web",
|
|
992
|
+
"cli",
|
|
993
|
+
"api",
|
|
994
|
+
"agent",
|
|
995
|
+
"system"
|
|
996
|
+
];
|
|
990
997
|
let CreditPurchaseStatus = /* @__PURE__ */ function(CreditPurchaseStatus) {
|
|
991
998
|
CreditPurchaseStatus["Completed"] = "completed";
|
|
992
999
|
CreditPurchaseStatus["Pending"] = "pending";
|
|
@@ -1003,6 +1010,12 @@ const BaseCreditTransaction = z.object({
|
|
|
1003
1010
|
credits: z.number(),
|
|
1004
1011
|
description: z.string().optional(),
|
|
1005
1012
|
metadata: z.record(z.string(), z.any()).optional(),
|
|
1013
|
+
/**
|
|
1014
|
+
* Where this transaction originated — used to break down usage in reports.
|
|
1015
|
+
* Optional because legacy rows (and non-completion transactions like
|
|
1016
|
+
* purchases/refunds) may not have it set. See CompletionSource in analytics.ts.
|
|
1017
|
+
*/
|
|
1018
|
+
source: z.enum(COMPLETION_SOURCES).optional(),
|
|
1006
1019
|
createdAt: z.date(),
|
|
1007
1020
|
updatedAt: z.date()
|
|
1008
1021
|
});
|
|
@@ -2584,7 +2597,8 @@ const AgentStepSchema = z.object({
|
|
|
2584
2597
|
});
|
|
2585
2598
|
const ExecutionStartedAction = z.object({
|
|
2586
2599
|
action: z.literal("execution_started"),
|
|
2587
|
-
executionId: z.string()
|
|
2600
|
+
executionId: z.string(),
|
|
2601
|
+
questId: z.string().optional()
|
|
2588
2602
|
});
|
|
2589
2603
|
const IterationStepAction = z.object({
|
|
2590
2604
|
action: z.literal("iteration_step"),
|
|
@@ -3644,6 +3658,8 @@ z.enum([
|
|
|
3644
3658
|
"EnableLatticeDefault",
|
|
3645
3659
|
"EnableDataLakes",
|
|
3646
3660
|
"EnableDataLakesDefault",
|
|
3661
|
+
"EnableBriefcase",
|
|
3662
|
+
"EnableBriefcaseDefault",
|
|
3647
3663
|
"RapidReplySettings",
|
|
3648
3664
|
"EnableResearchEngine",
|
|
3649
3665
|
"EnableResearchEngineDefault",
|
|
@@ -4615,6 +4631,14 @@ const API_SERVICE_GROUPS = {
|
|
|
4615
4631
|
key: "EnableArtifactsDefault",
|
|
4616
4632
|
order: 21
|
|
4617
4633
|
},
|
|
4634
|
+
{
|
|
4635
|
+
key: "EnableBriefcase",
|
|
4636
|
+
order: 25
|
|
4637
|
+
},
|
|
4638
|
+
{
|
|
4639
|
+
key: "EnableBriefcaseDefault",
|
|
4640
|
+
order: 26
|
|
4641
|
+
},
|
|
4618
4642
|
{
|
|
4619
4643
|
key: "EnableBmPi",
|
|
4620
4644
|
order: 30
|
|
@@ -5035,6 +5059,25 @@ const settingsMap = {
|
|
|
5035
5059
|
order: 89,
|
|
5036
5060
|
dependsOn: "EnableDataLakes"
|
|
5037
5061
|
}),
|
|
5062
|
+
EnableBriefcase: makeBooleanSetting({
|
|
5063
|
+
key: "EnableBriefcase",
|
|
5064
|
+
name: "Enable Briefcase",
|
|
5065
|
+
defaultValue: false,
|
|
5066
|
+
description: "Server-side gate for the Briefcase capability (one-click AI prompt catalog). Off by default — turn on to expose the briefcase APIs and launcher panel.",
|
|
5067
|
+
category: "Experimental",
|
|
5068
|
+
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
|
|
5069
|
+
order: 86
|
|
5070
|
+
}),
|
|
5071
|
+
EnableBriefcaseDefault: makeBooleanSetting({
|
|
5072
|
+
key: "EnableBriefcaseDefault",
|
|
5073
|
+
name: "Briefcase: On by default for users",
|
|
5074
|
+
defaultValue: false,
|
|
5075
|
+
description: "When enabled, Briefcase is active for users who have never explicitly toggled it.",
|
|
5076
|
+
category: "Experimental",
|
|
5077
|
+
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
|
|
5078
|
+
order: 87,
|
|
5079
|
+
dependsOn: "EnableBriefcase"
|
|
5080
|
+
}),
|
|
5038
5081
|
EnableQuestMaster: makeBooleanSetting({
|
|
5039
5082
|
key: "EnableQuestMaster",
|
|
5040
5083
|
name: "Enable Quest Master",
|
|
@@ -7755,6 +7798,55 @@ z$1.object({
|
|
|
7755
7798
|
skip: z$1.array(z$1.string())
|
|
7756
7799
|
})
|
|
7757
7800
|
});
|
|
7801
|
+
z.enum([
|
|
7802
|
+
"inject",
|
|
7803
|
+
"auto-fire",
|
|
7804
|
+
"hidden"
|
|
7805
|
+
]);
|
|
7806
|
+
/**
|
|
7807
|
+
* Modes acceptable at AUTHORING time. 'hidden' is intentionally excluded until
|
|
7808
|
+
* the host has true hidden-send support — accepting it would persist a value
|
|
7809
|
+
* that silently behaves as 'auto-fire' (a surprising downgrade). It stays in
|
|
7810
|
+
* ExecutionModeSchema/the stored enum for forward-compat.
|
|
7811
|
+
*/
|
|
7812
|
+
const AuthorableExecutionModeSchema = z.enum(["inject", "auto-fire"]);
|
|
7813
|
+
/**
|
|
7814
|
+
* Tools a prompt may require — constrained to the host's closed tool set, MINUS
|
|
7815
|
+
* integration-gated tools that act on the caller's own credentials/account. A
|
|
7816
|
+
* shared system prompt must not be able to inject e.g. blog-publishing into a
|
|
7817
|
+
* non-author's session via requiredTools. (Per-user entitlement of the remaining
|
|
7818
|
+
* tools is still the chat pipeline's responsibility — see follow-up note in the
|
|
7819
|
+
* briefcase blueprint; this allowlist is the storage-layer floor.)
|
|
7820
|
+
*/
|
|
7821
|
+
const BRIEFCASE_DISALLOWED_TOOLS = [
|
|
7822
|
+
"blog_publish",
|
|
7823
|
+
"blog_edit",
|
|
7824
|
+
"blog_draft"
|
|
7825
|
+
];
|
|
7826
|
+
const BriefcaseRequiredToolsSchema = z.array(b4mLLMTools.refine((t) => !BRIEFCASE_DISALLOWED_TOOLS.includes(t), "This tool is not permitted in a briefcase prompt")).max(16);
|
|
7827
|
+
z.string().regex(/^[a-f0-9]{24}$/i, "Invalid prompt id");
|
|
7828
|
+
const PROMPT_TEXT_MAX = 16e3;
|
|
7829
|
+
const TAGS_MAX = 20;
|
|
7830
|
+
z.object({
|
|
7831
|
+
type: z.string().min(1).max(100),
|
|
7832
|
+
name: z.string().min(1).max(200),
|
|
7833
|
+
description: z.string().max(500).optional(),
|
|
7834
|
+
promptText: z.string().min(1).max(PROMPT_TEXT_MAX),
|
|
7835
|
+
tags: z.array(z.string().min(1).max(50)).max(TAGS_MAX).optional(),
|
|
7836
|
+
executionMode: AuthorableExecutionModeSchema.optional(),
|
|
7837
|
+
requiredTools: BriefcaseRequiredToolsSchema.optional()
|
|
7838
|
+
}).partial();
|
|
7839
|
+
/**
|
|
7840
|
+
* One catalog sub-query. Exactly one selector is used, in precedence order:
|
|
7841
|
+
* `personal` (resolved to the caller server-side) > `tags` > `type`.
|
|
7842
|
+
*/
|
|
7843
|
+
const PromptBatchQuerySchema = z.object({
|
|
7844
|
+
key: z.string().min(1).max(100),
|
|
7845
|
+
tags: z.array(z.string().min(1).max(50)).max(TAGS_MAX).optional(),
|
|
7846
|
+
type: z.string().max(100).optional(),
|
|
7847
|
+
personal: z.boolean().optional()
|
|
7848
|
+
});
|
|
7849
|
+
z.object({ queries: z.array(PromptBatchQuerySchema).min(1).max(32).refine((qs) => new Set(qs.map((q) => q.key)).size === qs.length, { message: "Batch query keys must be unique" }) });
|
|
7758
7850
|
const DATA_LAKES = [{
|
|
7759
7851
|
id: "ionq-sales",
|
|
7760
7852
|
name: "IonQ Sales Intelligence",
|
|
@@ -8197,6 +8289,175 @@ BaseArtifactSchema.extend({
|
|
|
8197
8289
|
lastExecutionTime: z.number().optional()
|
|
8198
8290
|
})
|
|
8199
8291
|
});
|
|
8292
|
+
/**
|
|
8293
|
+
* Published-artifact schemas — the B4M instantiation of the `artifact-publishing`
|
|
8294
|
+
* blueprint (MillionOnMars/blueprints, extracted from Polaris Publish v1).
|
|
8295
|
+
*
|
|
8296
|
+
* The blueprint expresses scope/visibility as open string vocabularies; B4M
|
|
8297
|
+
* binds them to its own enums:
|
|
8298
|
+
* scope tier ∈ { user, project, organization }
|
|
8299
|
+
* visibility ∈ { private, project, organization, public } (ordered ladder)
|
|
8300
|
+
*
|
|
8301
|
+
* Unlike Polaris (bundles only), B4M publishes three SOURCE kinds through one
|
|
8302
|
+
* record: a rich HTML `bundle`, a chat `reply`, or a `fabfile`. The `source`
|
|
8303
|
+
* discriminator records provenance; `bundle` artifacts get the full
|
|
8304
|
+
* upload→validate→serve pipeline, while `reply`/`fabfile` are server-rendered
|
|
8305
|
+
* viewer pages.
|
|
8306
|
+
*/
|
|
8307
|
+
const PublishScopeTierSchema = z.enum([
|
|
8308
|
+
"user",
|
|
8309
|
+
"project",
|
|
8310
|
+
"organization"
|
|
8311
|
+
]);
|
|
8312
|
+
const PublishSourceKindSchema = z.enum([
|
|
8313
|
+
"bundle",
|
|
8314
|
+
"reply",
|
|
8315
|
+
"fabfile"
|
|
8316
|
+
]);
|
|
8317
|
+
const PublishSourceSchema = z.object({
|
|
8318
|
+
kind: PublishSourceKindSchema,
|
|
8319
|
+
/** Set when kind === 'bundle' and the bundle was generated from a B4M artifact. */
|
|
8320
|
+
artifactId: z.string().optional(),
|
|
8321
|
+
/** Set when kind === 'reply'. */
|
|
8322
|
+
sessionId: z.string().optional(),
|
|
8323
|
+
messageId: z.string().optional(),
|
|
8324
|
+
/** Set when kind === 'fabfile'. */
|
|
8325
|
+
fabFileId: z.string().optional()
|
|
8326
|
+
});
|
|
8327
|
+
const ArtifactFileSchema = z.object({
|
|
8328
|
+
path: z.string(),
|
|
8329
|
+
size: z.int().nonnegative(),
|
|
8330
|
+
mimeType: z.string(),
|
|
8331
|
+
sha256: z.string()
|
|
8332
|
+
});
|
|
8333
|
+
const ArtifactVersionMetaSchema = z.object({
|
|
8334
|
+
publishedAt: z.date(),
|
|
8335
|
+
publishedBy: z.string(),
|
|
8336
|
+
size: z.object({
|
|
8337
|
+
totalBytes: z.int().nonnegative(),
|
|
8338
|
+
fileCount: z.int().nonnegative()
|
|
8339
|
+
}),
|
|
8340
|
+
sha256Index: z.string()
|
|
8341
|
+
});
|
|
8342
|
+
/** Reserved slugs — must include every tier URL token so a slug can't shadow routing. */
|
|
8343
|
+
const RESERVED_SLUGS = [
|
|
8344
|
+
"api",
|
|
8345
|
+
"admin",
|
|
8346
|
+
"static",
|
|
8347
|
+
"p",
|
|
8348
|
+
"u",
|
|
8349
|
+
"o",
|
|
8350
|
+
"pj",
|
|
8351
|
+
"r",
|
|
8352
|
+
"f",
|
|
8353
|
+
"a",
|
|
8354
|
+
"_next",
|
|
8355
|
+
"health"
|
|
8356
|
+
];
|
|
8357
|
+
const SlugSchema = z.string().min(3).max(64).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "slug must be lowercase kebab-case").refine((s) => !RESERVED_SLUGS.includes(s), { message: "slug is reserved" });
|
|
8358
|
+
const PUBLISH_LIMITS = {
|
|
8359
|
+
maxFiles: 50,
|
|
8360
|
+
maxBundleBytes: 50 * 1024 * 1024,
|
|
8361
|
+
maxFileBytes: 10 * 1024 * 1024
|
|
8362
|
+
};
|
|
8363
|
+
z.object({
|
|
8364
|
+
/** Short opaque id for short URLs (`/p/r/{publicId}`, `/p/f/{publicId}`) and lookups. */
|
|
8365
|
+
publicId: z.string(),
|
|
8366
|
+
tier: PublishScopeTierSchema,
|
|
8367
|
+
scopeId: z.string(),
|
|
8368
|
+
slug: SlugSchema,
|
|
8369
|
+
title: z.string().min(1).max(200),
|
|
8370
|
+
description: z.string().max(1e3).optional(),
|
|
8371
|
+
visibility: VisibilitySchema.prefault("private"),
|
|
8372
|
+
/** Group id a viewer must belong to when gated cross-scope. */
|
|
8373
|
+
gatedToGroupId: z.string().optional(),
|
|
8374
|
+
ownerId: z.string(),
|
|
8375
|
+
lastPublishedBy: z.string().optional(),
|
|
8376
|
+
source: PublishSourceSchema,
|
|
8377
|
+
/** Canonical blob prefix '{tier}/{scopeId}/{slug}/'. Empty for non-bundle sources. */
|
|
8378
|
+
storageKeyPrefix: z.string(),
|
|
8379
|
+
size: z.object({
|
|
8380
|
+
totalBytes: z.int().nonnegative(),
|
|
8381
|
+
fileCount: z.int().nonnegative()
|
|
8382
|
+
}),
|
|
8383
|
+
sha256Index: z.string().optional(),
|
|
8384
|
+
manifest: z.array(ArtifactFileSchema).prefault([]),
|
|
8385
|
+
declaredApiEndpoints: z.array(z.string()).prefault([]),
|
|
8386
|
+
/** Rendered body snapshot for reply/fabfile viewer pages (markdown or text). */
|
|
8387
|
+
renderedBody: z.string().optional(),
|
|
8388
|
+
publishedAt: z.date(),
|
|
8389
|
+
previousVersionMeta: ArtifactVersionMetaSchema.optional(),
|
|
8390
|
+
viewCount: z.int().nonnegative().prefault(0),
|
|
8391
|
+
createdAt: z.date(),
|
|
8392
|
+
updatedAt: z.date(),
|
|
8393
|
+
deletedAt: z.date().nullish(),
|
|
8394
|
+
deletedBy: z.string().nullish()
|
|
8395
|
+
});
|
|
8396
|
+
const ValidationViolationTypeSchema = z.enum([
|
|
8397
|
+
"csp_violation",
|
|
8398
|
+
"forbidden_pattern",
|
|
8399
|
+
"forbidden_iframe",
|
|
8400
|
+
"invalid_asset_url",
|
|
8401
|
+
"missing_index",
|
|
8402
|
+
"size_exceeded",
|
|
8403
|
+
"invalid_mime_type",
|
|
8404
|
+
"invalid_path"
|
|
8405
|
+
]);
|
|
8406
|
+
z.object({
|
|
8407
|
+
type: ValidationViolationTypeSchema,
|
|
8408
|
+
message: z.string(),
|
|
8409
|
+
file: z.string().optional(),
|
|
8410
|
+
line: z.int().optional()
|
|
8411
|
+
});
|
|
8412
|
+
const FileDescriptorSchema = z.object({
|
|
8413
|
+
path: z.string(),
|
|
8414
|
+
size: z.int().nonnegative(),
|
|
8415
|
+
mimeType: z.string()
|
|
8416
|
+
});
|
|
8417
|
+
z.object({
|
|
8418
|
+
tier: PublishScopeTierSchema,
|
|
8419
|
+
scopeId: z.string(),
|
|
8420
|
+
slug: SlugSchema,
|
|
8421
|
+
title: z.string().min(1).max(200),
|
|
8422
|
+
description: z.string().max(1e3).optional(),
|
|
8423
|
+
visibility: VisibilitySchema.optional(),
|
|
8424
|
+
gatedToGroupId: z.string().optional(),
|
|
8425
|
+
source: PublishSourceSchema.optional(),
|
|
8426
|
+
files: z.array(FileDescriptorSchema).min(1).max(PUBLISH_LIMITS.maxFiles)
|
|
8427
|
+
});
|
|
8428
|
+
z.object({
|
|
8429
|
+
draftId: z.uuid(),
|
|
8430
|
+
uploadUrls: z.array(z.object({
|
|
8431
|
+
path: z.string(),
|
|
8432
|
+
url: z.string(),
|
|
8433
|
+
expiresAt: z.string()
|
|
8434
|
+
}))
|
|
8435
|
+
});
|
|
8436
|
+
z.object({ draftId: z.uuid() });
|
|
8437
|
+
z.object({
|
|
8438
|
+
sessionId: z.string(),
|
|
8439
|
+
messageId: z.string(),
|
|
8440
|
+
title: z.string().min(1).max(200).optional(),
|
|
8441
|
+
visibility: VisibilitySchema.optional(),
|
|
8442
|
+
tier: PublishScopeTierSchema.prefault("user"),
|
|
8443
|
+
scopeId: z.string().optional()
|
|
8444
|
+
});
|
|
8445
|
+
z.object({
|
|
8446
|
+
fabFileId: z.string(),
|
|
8447
|
+
title: z.string().min(1).max(200).optional(),
|
|
8448
|
+
visibility: VisibilitySchema.optional(),
|
|
8449
|
+
tier: PublishScopeTierSchema.prefault("user"),
|
|
8450
|
+
scopeId: z.string().optional()
|
|
8451
|
+
});
|
|
8452
|
+
z.object({
|
|
8453
|
+
publicId: z.string(),
|
|
8454
|
+
url: z.string(),
|
|
8455
|
+
tier: PublishScopeTierSchema,
|
|
8456
|
+
scopeId: z.string(),
|
|
8457
|
+
slug: z.string(),
|
|
8458
|
+
visibility: VisibilitySchema,
|
|
8459
|
+
publishedAt: z.string()
|
|
8460
|
+
});
|
|
8200
8461
|
const QuestStatusSchema = z.enum([
|
|
8201
8462
|
"pending",
|
|
8202
8463
|
"in-progress",
|
|
@@ -9385,6 +9646,29 @@ dayjs.extend(timezone);
|
|
|
9385
9646
|
dayjs.extend(relativeTime);
|
|
9386
9647
|
dayjs.extend(localizedFormat);
|
|
9387
9648
|
var dayjsConfig_default = dayjs;
|
|
9649
|
+
//#endregion
|
|
9650
|
+
//#region src/utils/apiUrl.ts
|
|
9651
|
+
/** Bike4Mind production service (used when no customUrl is configured). */
|
|
9652
|
+
const BIKE4MIND_URL = "https://app.bike4mind.com";
|
|
9653
|
+
/** Local development server the `--dev` flag points the CLI at. */
|
|
9654
|
+
const LOCAL_DEV_URL = "http://localhost:3001";
|
|
9655
|
+
/**
|
|
9656
|
+
* Resolve API URL based on configuration
|
|
9657
|
+
* Returns custom URL if set, otherwise Bike4Mind main service
|
|
9658
|
+
*/
|
|
9659
|
+
function getApiUrl(configApiConfig) {
|
|
9660
|
+
if (configApiConfig?.customUrl) return configApiConfig.customUrl;
|
|
9661
|
+
return BIKE4MIND_URL;
|
|
9662
|
+
}
|
|
9663
|
+
/**
|
|
9664
|
+
* Get human-readable API type name
|
|
9665
|
+
*/
|
|
9666
|
+
function getEnvironmentName(configApiConfig) {
|
|
9667
|
+
const url = configApiConfig?.customUrl;
|
|
9668
|
+
if (!url) return "Production";
|
|
9669
|
+
if (/^https?:\/\/(localhost|127\.0\.0\.1)(:|\/|$)/i.test(url)) return "Local Dev";
|
|
9670
|
+
return "Self-Hosted";
|
|
9671
|
+
}
|
|
9388
9672
|
const logger = class Logger {
|
|
9389
9673
|
static {
|
|
9390
9674
|
this.instance = null;
|
|
@@ -9726,6 +10010,7 @@ const CliConfigSchema = z.object({
|
|
|
9726
10010
|
version: z.string(),
|
|
9727
10011
|
userId: z.string(),
|
|
9728
10012
|
auth: AuthTokensSchema.optional(),
|
|
10013
|
+
authByEnv: z.record(z.string(), AuthTokensSchema).optional(),
|
|
9729
10014
|
defaultModel: z.string(),
|
|
9730
10015
|
apiConfig: ApiConfigSchema.optional(),
|
|
9731
10016
|
toolApiKeys: z.object({
|
|
@@ -10017,6 +10302,26 @@ function mergeConfigs(global, project, local) {
|
|
|
10017
10302
|
return merged;
|
|
10018
10303
|
}
|
|
10019
10304
|
/**
|
|
10305
|
+
* Normalize an API URL for use as an `authByEnv` cache key.
|
|
10306
|
+
*
|
|
10307
|
+
* Without normalization, `/set-api https://x.com` and `/set-api https://x.com/`
|
|
10308
|
+
* (or `HTTPS://X.com`) would create separate cache entries, defeating the
|
|
10309
|
+
* per-environment token reuse on a later `--dev` / `--prod` switch.
|
|
10310
|
+
*/
|
|
10311
|
+
function normalizeEnvKey(url) {
|
|
10312
|
+
return url.toLowerCase().replace(/\/+$/, "");
|
|
10313
|
+
}
|
|
10314
|
+
/**
|
|
10315
|
+
* Treat an auth token as "authenticated" only when it has an `expiresAt` in
|
|
10316
|
+
* the future. The startup flow auto-refreshes expired tokens anyway, but
|
|
10317
|
+
* without this check the launch banner would briefly claim a saved login is
|
|
10318
|
+
* being reused when it's actually about to trigger a re-auth.
|
|
10319
|
+
*/
|
|
10320
|
+
function hasValidAuth(auth) {
|
|
10321
|
+
if (!auth) return false;
|
|
10322
|
+
return new Date(auth.expiresAt) > /* @__PURE__ */ new Date();
|
|
10323
|
+
}
|
|
10324
|
+
/**
|
|
10020
10325
|
* Manages CLI configuration stored as JSON
|
|
10021
10326
|
*/
|
|
10022
10327
|
var ConfigStore = class {
|
|
@@ -10284,6 +10589,58 @@ var ConfigStore = class {
|
|
|
10284
10589
|
await this.save(config);
|
|
10285
10590
|
}
|
|
10286
10591
|
/**
|
|
10592
|
+
* Switch the active API environment, caching auth tokens per-environment so
|
|
10593
|
+
* flipping between `--dev` and `--prod` doesn't force a re-login each time you
|
|
10594
|
+
* return to an environment you've already authenticated.
|
|
10595
|
+
*
|
|
10596
|
+
* Targets:
|
|
10597
|
+
* - 'prod' → Bike4Mind production (clears customUrl)
|
|
10598
|
+
* - 'dev' → local dev server (http://localhost:3001)
|
|
10599
|
+
* - { customUrl: '…' } → arbitrary self-hosted URL
|
|
10600
|
+
*
|
|
10601
|
+
* Mutates the cached config in place and persists via `save()` (no argument)
|
|
10602
|
+
* so the write bypasses save()'s field-merge — `save(config)` would otherwise
|
|
10603
|
+
* preserve the previous `auth` and defeat the per-env swap.
|
|
10604
|
+
*/
|
|
10605
|
+
async switchApiEnvironment(target) {
|
|
10606
|
+
const config = await this.load();
|
|
10607
|
+
const prevKey = normalizeEnvKey(config.apiConfig?.customUrl || "https://app.bike4mind.com");
|
|
10608
|
+
let newUrl;
|
|
10609
|
+
let newApiConfig;
|
|
10610
|
+
if (target === "prod") {
|
|
10611
|
+
newUrl = BIKE4MIND_URL;
|
|
10612
|
+
newApiConfig = void 0;
|
|
10613
|
+
} else if (target === "dev") {
|
|
10614
|
+
newUrl = LOCAL_DEV_URL;
|
|
10615
|
+
newApiConfig = { customUrl: LOCAL_DEV_URL };
|
|
10616
|
+
} else {
|
|
10617
|
+
newUrl = target.customUrl;
|
|
10618
|
+
newApiConfig = { customUrl: target.customUrl };
|
|
10619
|
+
}
|
|
10620
|
+
const newKey = normalizeEnvKey(newUrl);
|
|
10621
|
+
const envName = getEnvironmentName(newApiConfig);
|
|
10622
|
+
if (prevKey === newKey) return {
|
|
10623
|
+
url: newUrl,
|
|
10624
|
+
envName,
|
|
10625
|
+
changed: false,
|
|
10626
|
+
authenticated: hasValidAuth(config.auth)
|
|
10627
|
+
};
|
|
10628
|
+
const authByEnv = { ...config.authByEnv || {} };
|
|
10629
|
+
if (config.auth) authByEnv[prevKey] = config.auth;
|
|
10630
|
+
else delete authByEnv[prevKey];
|
|
10631
|
+
const restored = authByEnv[newKey];
|
|
10632
|
+
config.apiConfig = newApiConfig;
|
|
10633
|
+
config.authByEnv = authByEnv;
|
|
10634
|
+
config.auth = restored;
|
|
10635
|
+
await this.save();
|
|
10636
|
+
return {
|
|
10637
|
+
url: newUrl,
|
|
10638
|
+
envName,
|
|
10639
|
+
changed: true,
|
|
10640
|
+
authenticated: hasValidAuth(restored)
|
|
10641
|
+
};
|
|
10642
|
+
}
|
|
10643
|
+
/**
|
|
10287
10644
|
* Get project config directory (if any)
|
|
10288
10645
|
*/
|
|
10289
10646
|
getProjectConfigDir() {
|
|
@@ -10398,4 +10755,4 @@ var ConfigStore = class {
|
|
|
10398
10755
|
}
|
|
10399
10756
|
};
|
|
10400
10757
|
//#endregion
|
|
10401
|
-
export {
|
|
10758
|
+
export { ProjectEvents as $, GenerateImageToolCallSchema as A, dayjsConfig_default as At, InviteEvents as B, sanitizeTelemetryError as Bt, ElabsEvents as C, UnauthorizedError as Ct, ForbiddenError as D, VideoModels as Dt, FileEvents as E, VideoGenerationUsageTransaction as Et, ImageEditUsageTransaction as F, isGPTImage2Model as Ft, ModalEvents as G, buildRateLimitLogEntry as Gt, KnowledgeType as H, settingsMap as Ht, ImageGenerationUsageTransaction as I, isGPTImageModel as It, OpenAIEmbeddingModel as J, parseRateLimitHeaders as Jt, ModelBackend as K, extractSnippetMeta as Kt, ImageModels as L, isZodError as Lt, GenericCreditDeductTransaction as M, getDataLakeTags as Mt, HTTPError as N, getMcpProviderMetadata as Nt, FriendshipEvents as O, XAI_IMAGE_MODELS as Ot, HttpStatus as P, getViewById as Pt, ProfileEvents as Q, InboxEvents as R, obfuscateApiKey as Rt, DashboardParamsSchema as S, UiNavigationEvents as St, FeedbackEvents as T, VIDEO_SIZE_CONSTRAINTS as Tt, LLMEvents as U, validateJupyterKernelName as Ut, InviteType as V, secureParameters as Vt, MiscEvents as W, validateNotebookPath as Wt, Permission as X, OpenAIImageGenerationInput as Y, CollectionType as Yt, PermissionDeniedError as Z, ChatCompletionCreateInputSchema as _, TaskScheduleHandler as _t, ALERT_THRESHOLDS as a, ReceivedCreditTransaction as at, CompletionApiUsageTransaction as b, ToolUsageTransaction as bt, ApiKeyScope as c, ResearchModeParamsSchema as ct, ArtifactTypeSchema as d, ResearchTaskType as dt, PromptIntentSchema as et, AuthEvents as f, SessionEvents as ft, CREDIT_DEDUCT_TRANSACTION_TYPES as g, TagType as gt, BadRequestError as h, SupportedFabFileMimeTypes as ht, getEnvironmentName as i, RealtimeVoiceUsageTransaction as it, GenericCreditAddTransaction as j, getAccessibleDataLakes as jt, GEMINI_IMAGE_MODELS as k, b4mLLMTools as kt, ApiKeyType as l, ResearchTaskExecutionType as lt, BFL_SAFETY_TOLERANCE as m, SubscriptionCreditTransaction as mt, logger as n, PurchaseTransaction as nt, AiEvents as o, RechartsChartTypeList as ot, BFL_IMAGE_MODELS as p, SpeechToTextUsageTransaction as pt, NotFoundError as q, isNearLimit as qt, getApiUrl as r, QuestMasterParamsSchema as rt, ApiKeyEvents as s, RegInviteEvents as st, ConfigStore as t, PromptMetaZodSchema as tt, AppFileEvents as u, ResearchTaskPeriodicFrequencyType as ut, ChatModels as v, TextGenerationUsageTransaction as vt, FavoriteDocumentType as w, UnprocessableEntityError as wt, CorruptedFileError as x, TransferCreditTransaction as xt, ClaudeArtifactMimeTypes as y, TooManyRequestsError as yt, InternalServerError as z, resolveNavigationIntents as zt };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { t as version } from "../package-8UMmdI7b.mjs";
|
|
3
|
+
import { n as compareSemver, r as fetchLatestVersion } from "../updateChecker-D67NPlS5.mjs";
|
|
3
4
|
import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
|
|
4
5
|
import { execSync } from "child_process";
|
|
5
6
|
import { constants, existsSync, promises } from "fs";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as ConfigStore } from "../ConfigStore-CtBZ2p4M.mjs";
|
|
3
|
+
//#region src/commands/envCommand.ts
|
|
4
|
+
/**
|
|
5
|
+
* Environment switching for the `--dev` / `--prod` launch flags.
|
|
6
|
+
*
|
|
7
|
+
* Flipping the target persists the choice to ~/.bike4mind/config.json, so a
|
|
8
|
+
* bare `b4m` always reuses whichever environment you last selected. Auth tokens
|
|
9
|
+
* are cached per-environment, so flipping back and forth doesn't force a
|
|
10
|
+
* re-login (see ConfigStore.switchApiEnvironment).
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Apply a `--dev` / `--prod` launch flag: switch the persisted API environment
|
|
14
|
+
* and print a concise banner describing the result. Runs before the app boots.
|
|
15
|
+
*/
|
|
16
|
+
async function applyEnvironmentFlag(target) {
|
|
17
|
+
const result = await new ConfigStore().switchApiEnvironment(target);
|
|
18
|
+
if (result.changed) console.log(`🔀 Switched API environment → ${result.envName} (${result.url})`);
|
|
19
|
+
else console.log(`🌍 Already on ${result.envName} (${result.url})`);
|
|
20
|
+
if (result.authenticated) console.log(" ✅ Reusing your saved login for this environment.");
|
|
21
|
+
else console.log(" 🔓 Not logged in here yet — run /login once the CLI starts.");
|
|
22
|
+
console.log("");
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { applyEnvironmentFlag };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as logger, t as ConfigStore } from "../ConfigStore-
|
|
2
|
+
import { C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as generateCliTools, G as buildSystemPrompt, J as ReActAgent, N as loadContextFiles, P as PermissionManager, Q as SessionStore, S as ApiClient, T as FallbackLlmBackend, U as setWebSocketToolExecutor, X as CheckpointStore, Y as CustomCommandStore, _ as createAgentDelegateTool, b as createSkillTool, d as createFindDefinitionTool, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, k as McpManager, m as createCoordinateTaskTool, p as createWriteTodosTool, q as isReadOnlyTool, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, y as SubagentOrchestrator } from "../tools-BuaOUcTS.mjs";
|
|
3
|
+
import { n as logger, r as getApiUrl, t as ConfigStore } from "../ConfigStore-CtBZ2p4M.mjs";
|
|
4
4
|
import { t as DEFAULT_SANDBOX_CONFIG } from "../types-LyRNHOiS.mjs";
|
|
5
5
|
import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-ChGlxSGQ.mjs";
|
|
6
6
|
import { t as SandboxOrchestrator } from "../SandboxOrchestrator-BoINxbX4.mjs";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { t as version } from "../package-8UMmdI7b.mjs";
|
|
3
|
+
import { i as forceCheckForUpdate } from "../updateChecker-D67NPlS5.mjs";
|
|
3
4
|
import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
|
|
4
5
|
import { execSync } from "child_process";
|
|
5
6
|
//#region src/commands/updateCommand.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as OAuthClient, A as substituteArguments, B as DEFAULT_THOROUGHNESS, C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as generateCliTools, G as buildSystemPrompt, H as registerFeatureModuleTools, I as ALWAYS_DENIED_FOR_AGENTS, J as ReActAgent, K as buildSkillsPromptSection, L as DEFAULT_AGENT_MODEL, M as extractCompactInstructions, N as loadContextFiles, O as isTransientNetworkError, P as PermissionManager, Q as SessionStore, R as DEFAULT_MAX_ITERATIONS, S as ApiClient, T as FallbackLlmBackend, U as setWebSocketToolExecutor, V as clearFeatureModuleTools, W as getPlanModeFilePath, X as CheckpointStore, Y as CustomCommandStore, Z as CommandHistoryStore, _ as createAgentDelegateTool, a as createBlockerTools, at as searchFiles, b as createSkillTool, c as createDecisionStore, d as createFindDefinitionTool, et as hasFileReferences, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, i as createBlockerStore, it as formatFileSize, j as formatStep, k as McpManager, l as formatDecisionsOutput, m as createCoordinateTaskTool, n as createReviewGateTool, nt as searchCommands, o as formatBlockersOutput, ot as warmFileCache, p as createWriteTodosTool, q as isReadOnlyTool, r as formatReviewGatesOutput, rt as mergeCommands, s as createDecisionLogTool, t as createReviewGateStore, tt as processFileReferences, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, x as parseAgentConfig, y as SubagentOrchestrator, z as DEFAULT_RETRY_CONFIG } from "./tools-BuaOUcTS.mjs";
|
|
3
3
|
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-DV5s-qni.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { Ut as validateJupyterKernelName, Wt as validateNotebookPath$1, g as CREDIT_DEDUCT_TRANSACTION_TYPES, i as getEnvironmentName, n as logger, r as getApiUrl, t as ConfigStore, v as ChatModels } from "./ConfigStore-CtBZ2p4M.mjs";
|
|
5
|
+
import { t as version } from "./package-8UMmdI7b.mjs";
|
|
6
|
+
import { t as checkForUpdate } from "./updateChecker-D67NPlS5.mjs";
|
|
6
7
|
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
7
8
|
import { Box, Static, Text, render, useApp, useInput, usePaste, useStdout } from "ink";
|
|
8
9
|
import { execSync } from "child_process";
|
|
@@ -5440,6 +5441,7 @@ var BridgePresence = class {
|
|
|
5440
5441
|
*/
|
|
5441
5442
|
async start(opts) {
|
|
5442
5443
|
if (this.started) return this.instanceId !== null;
|
|
5444
|
+
this.stopped = false;
|
|
5443
5445
|
this.started = true;
|
|
5444
5446
|
const config = await readBridgeConfig();
|
|
5445
5447
|
if (!config) {
|
|
@@ -5503,9 +5505,19 @@ var BridgePresence = class {
|
|
|
5503
5505
|
this.emitQueue = this.emitQueue.then(task, task);
|
|
5504
5506
|
return this.emitQueue;
|
|
5505
5507
|
}
|
|
5506
|
-
/**
|
|
5508
|
+
/**
|
|
5509
|
+
* Tear down the tavern presence cleanly. Halts the announce-retry and
|
|
5510
|
+
* command-WS reconnect loops, closes the socket, and best-effort signals
|
|
5511
|
+
* disconnect to the bridge.
|
|
5512
|
+
*
|
|
5513
|
+
* After this resolves the instance is fully reset, so a later `start()`
|
|
5514
|
+
* re-announces — the same singleton can be toggled off (Tavern feature
|
|
5515
|
+
* disabled at runtime) and back on without restarting the CLI. The
|
|
5516
|
+
* `stopped` latch is left true here purely so any straggler retry callback
|
|
5517
|
+
* already queued short-circuits; `start()` clears it.
|
|
5518
|
+
*/
|
|
5507
5519
|
async stop(reason = "cli_exit") {
|
|
5508
|
-
if (this.stopped) return;
|
|
5520
|
+
if (this.stopped || !this.started) return;
|
|
5509
5521
|
this.stopped = true;
|
|
5510
5522
|
if (this.reconnectTimer) {
|
|
5511
5523
|
clearTimeout(this.reconnectTimer);
|
|
@@ -5525,6 +5537,16 @@ var BridgePresence = class {
|
|
|
5525
5537
|
instanceId: this.instanceId,
|
|
5526
5538
|
reason
|
|
5527
5539
|
}).catch(() => {});
|
|
5540
|
+
this.started = false;
|
|
5541
|
+
this.instanceId = null;
|
|
5542
|
+
this.config = null;
|
|
5543
|
+
this.startOpts = null;
|
|
5544
|
+
this.pendingWorkspaceName = null;
|
|
5545
|
+
this.pendingCapabilities = null;
|
|
5546
|
+
this.pendingSource = null;
|
|
5547
|
+
this.announceAttempts = 0;
|
|
5548
|
+
this.reconnectAttempts = 0;
|
|
5549
|
+
this.emitQueue = Promise.resolve();
|
|
5528
5550
|
}
|
|
5529
5551
|
async announce(body) {
|
|
5530
5552
|
try {
|
|
@@ -5863,7 +5885,7 @@ function CliApp() {
|
|
|
5863
5885
|
startupLog.push(`✅ Authenticated (expires in ${daysUntilExpiry} day${daysUntilExpiry !== 1 ? "s" : ""})`);
|
|
5864
5886
|
const apiBaseURL = getApiUrl(config.apiConfig);
|
|
5865
5887
|
const envName = getEnvironmentName(config.apiConfig);
|
|
5866
|
-
|
|
5888
|
+
startupLog.unshift(`🌍 API Environment: ${envName} (${apiBaseURL})`);
|
|
5867
5889
|
const apiClient = new ApiClient(apiBaseURL, state.configStore);
|
|
5868
5890
|
const tokenGetter = async () => {
|
|
5869
5891
|
return (await state.configStore.getAuthTokens())?.accessToken ?? null;
|
|
@@ -6498,8 +6520,13 @@ function CliApp() {
|
|
|
6498
6520
|
status: "running"
|
|
6499
6521
|
});
|
|
6500
6522
|
};
|
|
6523
|
+
const tavernPresenceEnabled = state.config?.features?.tavern ?? false;
|
|
6501
6524
|
useEffect(() => {
|
|
6502
6525
|
if (!isInitialized) return;
|
|
6526
|
+
if (!tavernPresenceEnabled) {
|
|
6527
|
+
bridgePresence.stop("tavern_disabled");
|
|
6528
|
+
return;
|
|
6529
|
+
}
|
|
6503
6530
|
let cancelled = false;
|
|
6504
6531
|
bridgePresence.setCallbacks({
|
|
6505
6532
|
onSendPrompt: (text) => handleMessageRef.current?.(text),
|
|
@@ -6523,7 +6550,7 @@ function CliApp() {
|
|
|
6523
6550
|
return () => {
|
|
6524
6551
|
cancelled = true;
|
|
6525
6552
|
};
|
|
6526
|
-
}, [isInitialized]);
|
|
6553
|
+
}, [isInitialized, tavernPresenceEnabled]);
|
|
6527
6554
|
/**
|
|
6528
6555
|
* Handle custom command execution with proper display
|
|
6529
6556
|
* Shows concise user message but sends full template to agent
|
|
@@ -6927,8 +6954,13 @@ function CliApp() {
|
|
|
6927
6954
|
return;
|
|
6928
6955
|
}
|
|
6929
6956
|
}
|
|
6930
|
-
const
|
|
6931
|
-
|
|
6957
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
6958
|
+
if (error instanceof Error && isTransientNetworkError(error)) {
|
|
6959
|
+
console.error("\n❌ The connection to the server dropped mid-response. Type \"continue\" to resume.\n");
|
|
6960
|
+
logger.debug(`Full error details: ${error.stack || error.message}`);
|
|
6961
|
+
return;
|
|
6962
|
+
}
|
|
6963
|
+
console.error(`\n❌ ${rawMessage}\n`);
|
|
6932
6964
|
logger.debug(`Full error details: ${error instanceof Error ? error.stack || error.message : String(error)}`);
|
|
6933
6965
|
} finally {
|
|
6934
6966
|
const wasAborted = abortController.signal.aborted;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as ProjectEvents, A as GenerateImageToolCallSchema, At as dayjsConfig_default, B as InviteEvents, Bt as sanitizeTelemetryError, C as ElabsEvents, Ct as UnauthorizedError, D as ForbiddenError, Dt as VideoModels, E as FileEvents, Et as VideoGenerationUsageTransaction, F as ImageEditUsageTransaction, Ft as isGPTImage2Model, G as ModalEvents, Gt as buildRateLimitLogEntry, H as KnowledgeType, Ht as settingsMap, I as ImageGenerationUsageTransaction, It as isGPTImageModel, J as OpenAIEmbeddingModel, Jt as parseRateLimitHeaders, K as ModelBackend, Kt as extractSnippetMeta, L as ImageModels, Lt as isZodError, M as GenericCreditDeductTransaction, Mt as getDataLakeTags, N as HTTPError, Nt as getMcpProviderMetadata, O as FriendshipEvents, Ot as XAI_IMAGE_MODELS, P as HttpStatus, Pt as getViewById, Q as ProfileEvents, R as InboxEvents, Rt as obfuscateApiKey, S as DashboardParamsSchema, St as UiNavigationEvents, T as FeedbackEvents, Tt as VIDEO_SIZE_CONSTRAINTS, U as LLMEvents, V as InviteType, Vt as secureParameters, W as MiscEvents, X as Permission, Y as OpenAIImageGenerationInput, Yt as CollectionType, Z as PermissionDeniedError, _ as ChatCompletionCreateInputSchema, _t as TaskScheduleHandler, a as ALERT_THRESHOLDS, at as ReceivedCreditTransaction, b as CompletionApiUsageTransaction, bt as ToolUsageTransaction, c as ApiKeyScope, ct as ResearchModeParamsSchema, d as ArtifactTypeSchema, dt as ResearchTaskType, et as PromptIntentSchema, f as AuthEvents, ft as SessionEvents, gt as TagType, h as BadRequestError, ht as SupportedFabFileMimeTypes, it as RealtimeVoiceUsageTransaction, j as GenericCreditAddTransaction, jt as getAccessibleDataLakes, k as GEMINI_IMAGE_MODELS, kt as b4mLLMTools, l as ApiKeyType, lt as ResearchTaskExecutionType, m as BFL_SAFETY_TOLERANCE, mt as SubscriptionCreditTransaction, n as logger, nt as PurchaseTransaction, o as AiEvents, ot as RechartsChartTypeList, p as BFL_IMAGE_MODELS, pt as SpeechToTextUsageTransaction, q as NotFoundError, qt as isNearLimit, rt as QuestMasterParamsSchema, s as ApiKeyEvents, st as RegInviteEvents, t as ConfigStore, tt as PromptMetaZodSchema, u as AppFileEvents, ut as ResearchTaskPeriodicFrequencyType, v as ChatModels, vt as TextGenerationUsageTransaction, w as FavoriteDocumentType, wt as UnprocessableEntityError, x as CorruptedFileError, xt as TransferCreditTransaction, y as ClaudeArtifactMimeTypes, yt as TooManyRequestsError, z as InternalServerError, zt as resolveNavigationIntents } from "./ConfigStore-CtBZ2p4M.mjs";
|
|
3
3
|
import { a as isUserLockedOut, c as userCanDisableMFA, d as userRequiresMFA, f as verifyBackupCode, i as getLockoutTimeRemaining, l as userEligibleForMFA, n as generateBackupCodes, o as recordFailedAttempt, p as verifyTOTPToken, r as generateTOTPSetup, s as shouldResetFailedAttempts, t as clearFailedAttempts, u as userHasMFAConfigured } from "./utils-PpNti-tY.mjs";
|
|
4
4
|
import { n as isPathAllowed, t as assertPathAllowed } from "./pathValidation-D8tjkQXE-1HwvsuYT.mjs";
|
|
5
|
+
import { t as version } from "./package-8UMmdI7b.mjs";
|
|
5
6
|
import { execFile, execFileSync, spawn } from "child_process";
|
|
6
7
|
import crypto, { createHash, randomBytes } from "crypto";
|
|
7
8
|
import { existsSync, promises, readFileSync, readdirSync, rmSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -22289,7 +22290,7 @@ var CliLogger = class extends Logger {
|
|
|
22289
22290
|
* 5. Route to server or execute locally via ToolRouter
|
|
22290
22291
|
* 6. Record observation in agent's step history
|
|
22291
22292
|
*/
|
|
22292
|
-
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, sandboxOrchestrator) {
|
|
22293
|
+
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, sandboxOrchestrator, allowedDirectories) {
|
|
22293
22294
|
const originalFn = tool.toolFn;
|
|
22294
22295
|
const toolName = tool.toolSchema.name;
|
|
22295
22296
|
return {
|
|
@@ -22328,10 +22329,18 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
22328
22329
|
* offer retry on sandbox failure, and record observation.
|
|
22329
22330
|
*/
|
|
22330
22331
|
async function executeAndRecord() {
|
|
22331
|
-
let result
|
|
22332
|
+
let result;
|
|
22333
|
+
try {
|
|
22334
|
+
result = await executeTool(toolName, effectiveArgs, apiClient, originalFn);
|
|
22335
|
+
} catch (err) {
|
|
22336
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
22337
|
+
if (!isPathAccessDenial(msg)) throw err;
|
|
22338
|
+
result = msg;
|
|
22339
|
+
}
|
|
22332
22340
|
cleanupSandboxFiles(effectiveArgs?._sandboxCleanup);
|
|
22333
22341
|
await captureViolations(isSandboxed, result, args?.command, sandboxOrchestrator);
|
|
22334
22342
|
result = await retrySandboxFailure(isSandboxed, result, toolName, args, apiClient, originalFn, showPermissionPrompt);
|
|
22343
|
+
result = await retryPathAccessDenial(result, toolName, effectiveArgs, allowedDirectories, configStore, apiClient, originalFn, showPermissionPrompt);
|
|
22335
22344
|
agentContext.observationQueue.push({
|
|
22336
22345
|
toolName,
|
|
22337
22346
|
result
|
|
@@ -22376,6 +22385,64 @@ async function retrySandboxFailure(isSandboxed, result, toolName, originalArgs,
|
|
|
22376
22385
|
return result;
|
|
22377
22386
|
}
|
|
22378
22387
|
/**
|
|
22388
|
+
* Matches the three shapes of filesystem allow-list denial emitted by core:
|
|
22389
|
+
* - file tools: `Access denied: Cannot <op> files outside allowed directories.`
|
|
22390
|
+
* - glob_files: `Access denied: Cannot search outside allowed directories.` (no "files")
|
|
22391
|
+
* - grep_search: `Path validation failed: "<p>" resolves outside allowed directories.`
|
|
22392
|
+
* The `files` token is optional so glob_files' wording is covered too.
|
|
22393
|
+
*/
|
|
22394
|
+
const PATH_ACCESS_DENIAL_RE = /Access denied: Cannot \w+ (?:files )?outside allowed directories|Path validation failed: .* resolves outside allowed directories/;
|
|
22395
|
+
function isPathAccessDenial(text) {
|
|
22396
|
+
return PATH_ACCESS_DENIAL_RE.test(text);
|
|
22397
|
+
}
|
|
22398
|
+
/**
|
|
22399
|
+
* Derive the directory to grant so the blocked operation can succeed on retry.
|
|
22400
|
+
* File tools (`file_read`, `create_file`, `edit_local_file`, `delete_file`)
|
|
22401
|
+
* target a file → grant its containing directory. `grep_search` / `glob_files`
|
|
22402
|
+
* target a directory → grant it directly. Returns an absolute path, or null if
|
|
22403
|
+
* no path argument is present.
|
|
22404
|
+
*/
|
|
22405
|
+
function deriveGrantDirectory(toolName, args) {
|
|
22406
|
+
const raw = args?.path ?? args?.dir_path;
|
|
22407
|
+
if (typeof raw !== "string" || raw.length === 0) return null;
|
|
22408
|
+
const resolved = path.isAbsolute(raw) ? raw : path.resolve(process.cwd(), raw);
|
|
22409
|
+
return new Set(["grep_search", "glob_files"]).has(toolName) ? resolved : path.dirname(resolved);
|
|
22410
|
+
}
|
|
22411
|
+
/**
|
|
22412
|
+
* If a tool result indicates the operation was blocked by the filesystem
|
|
22413
|
+
* allow-list, prompt the user to grant access to the relevant directory.
|
|
22414
|
+
* On approval the directory is pushed onto the live allow-list (so the very
|
|
22415
|
+
* next core tool call sees it — same array reference held by the tool
|
|
22416
|
+
* context), persisted to config on "Always allow", and the tool is retried.
|
|
22417
|
+
*
|
|
22418
|
+
* This is the runtime, on-demand equivalent of `/add-dir`: instead of failing
|
|
22419
|
+
* hard when the agent reaches outside the workspace, it asks — like Claude
|
|
22420
|
+
* Code does — and continues once the user says yes.
|
|
22421
|
+
*/
|
|
22422
|
+
async function retryPathAccessDenial(result, toolName, args, allowedDirectories, configStore, apiClient, originalFn, showPermissionPrompt) {
|
|
22423
|
+
if (!allowedDirectories || !isPathAccessDenial(result)) return result;
|
|
22424
|
+
const grantDir = deriveGrantDirectory(toolName, args);
|
|
22425
|
+
if (!grantDir) return result;
|
|
22426
|
+
if (allowedDirectories.includes(grantDir)) return result;
|
|
22427
|
+
const response = await showPermissionPrompt(toolName, args, `🔒 DIRECTORY ACCESS — "${toolName}" needs a path outside the current workspace.\n\n- Grant access to this directory:\n ${grantDir}\n- "Allow for this session" grants access until the CLI exits.\n- "Always allow" also saves it to your config so it persists across sessions.`);
|
|
22428
|
+
if (response.action === "deny") return result;
|
|
22429
|
+
const oneShot = response.action === "allow-once";
|
|
22430
|
+
allowedDirectories.push(grantDir);
|
|
22431
|
+
if (response.action === "allow-always") try {
|
|
22432
|
+
await configStore.addDirectory(grantDir);
|
|
22433
|
+
} catch {}
|
|
22434
|
+
try {
|
|
22435
|
+
return await executeTool(toolName, args, apiClient, originalFn);
|
|
22436
|
+
} catch (err) {
|
|
22437
|
+
return err instanceof Error ? err.message : String(err);
|
|
22438
|
+
} finally {
|
|
22439
|
+
if (oneShot) {
|
|
22440
|
+
const idx = allowedDirectories.lastIndexOf(grantDir);
|
|
22441
|
+
if (idx !== -1) allowedDirectories.splice(idx, 1);
|
|
22442
|
+
}
|
|
22443
|
+
}
|
|
22444
|
+
}
|
|
22445
|
+
/**
|
|
22379
22446
|
* Clean up temporary sandbox files (e.g., Seatbelt profiles).
|
|
22380
22447
|
* Fails silently — cleanup is best-effort.
|
|
22381
22448
|
*/
|
|
@@ -22604,12 +22671,14 @@ async function generateCliTools(userId, llm, model, permissionManager, showPermi
|
|
|
22604
22671
|
"web_fetch"
|
|
22605
22672
|
].filter((name) => name in b4mTools).map((name) => [name, b4mTools[name]]));
|
|
22606
22673
|
const cliOnlyTools = await getCliOnlyTools();
|
|
22607
|
-
const
|
|
22674
|
+
const tools_to_generate = {
|
|
22608
22675
|
...filteredB4mTools,
|
|
22609
22676
|
...cliOnlyTools
|
|
22610
|
-
}
|
|
22677
|
+
};
|
|
22678
|
+
const liveAllowedDirectories = allowedDirectories ?? [];
|
|
22679
|
+
const toolsMap = generateTools(userId, user, logger, dbAdapters, storage, storage, statusUpdate, onStart, onFinish, llm, {}, model, void 0, tools_to_generate, liveAllowedDirectories);
|
|
22611
22680
|
let tools = Object.entries(toolsMap).map(([_, tool]) => {
|
|
22612
|
-
return wrapToolWithCheckpointing(wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, sandboxOrchestrator), checkpointStore ?? null);
|
|
22681
|
+
return wrapToolWithCheckpointing(wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, sandboxOrchestrator, liveAllowedDirectories), checkpointStore ?? null);
|
|
22613
22682
|
});
|
|
22614
22683
|
if (toolFilter) {
|
|
22615
22684
|
const { allowedTools, deniedTools } = toolFilter;
|
|
@@ -22778,24 +22847,6 @@ var PermissionManager = class {
|
|
|
22778
22847
|
};
|
|
22779
22848
|
}
|
|
22780
22849
|
};
|
|
22781
|
-
//#endregion
|
|
22782
|
-
//#region src/utils/apiUrl.ts
|
|
22783
|
-
const BIKE4MIND_URL = "https://app.bike4mind.com";
|
|
22784
|
-
/**
|
|
22785
|
-
* Resolve API URL based on configuration
|
|
22786
|
-
* Returns custom URL if set, otherwise Bike4Mind main service
|
|
22787
|
-
*/
|
|
22788
|
-
function getApiUrl(configApiConfig) {
|
|
22789
|
-
if (configApiConfig?.customUrl) return configApiConfig.customUrl;
|
|
22790
|
-
return BIKE4MIND_URL;
|
|
22791
|
-
}
|
|
22792
|
-
/**
|
|
22793
|
-
* Get human-readable API type name
|
|
22794
|
-
*/
|
|
22795
|
-
function getEnvironmentName(configApiConfig) {
|
|
22796
|
-
if (configApiConfig?.customUrl) return "Self-Hosted";
|
|
22797
|
-
return "Bike4Mind";
|
|
22798
|
-
}
|
|
22799
22850
|
const PROJECT_CONTEXT_FILES = [
|
|
22800
22851
|
"CLAUDE.local.md",
|
|
22801
22852
|
"CLAUDE.md",
|
|
@@ -23629,6 +23680,35 @@ var StreamAccumulator = class {
|
|
|
23629
23680
|
//#endregion
|
|
23630
23681
|
//#region src/llm/ServerLlmBackend.ts
|
|
23631
23682
|
/**
|
|
23683
|
+
* Connection-level failures that should be retried rather than surfaced to the
|
|
23684
|
+
* user. Mirrors the canonical retryable-error list in `@bike4mind/llm-adapters`
|
|
23685
|
+
* (retry.ts, issues #6936 / #6892): the most common offender is a TLS socket
|
|
23686
|
+
* close mid-stream, which Node surfaces as `Error: aborted` thrown from
|
|
23687
|
+
* `node:_http_client` `socketCloseListener`. This happens when the SSE
|
|
23688
|
+
* connection sits idle during a long extended-thinking step and an intermediary
|
|
23689
|
+
* (or the socket itself) times out the idle connection.
|
|
23690
|
+
*
|
|
23691
|
+
* Crucially this is NOT a user cancel — those are detected separately via
|
|
23692
|
+
* `options.abortSignal` before this classifier is consulted. Matching is on the
|
|
23693
|
+
* lowercased message so we catch the various wordings undici/Node emit.
|
|
23694
|
+
*/
|
|
23695
|
+
const TRANSIENT_NETWORK_ERROR_PATTERNS = [
|
|
23696
|
+
"aborted",
|
|
23697
|
+
"socket closed",
|
|
23698
|
+
"socket hang up",
|
|
23699
|
+
"connection closed",
|
|
23700
|
+
"econnreset",
|
|
23701
|
+
"etimedout",
|
|
23702
|
+
"terminated",
|
|
23703
|
+
"network error",
|
|
23704
|
+
"fetch failed",
|
|
23705
|
+
"und_err_socket"
|
|
23706
|
+
];
|
|
23707
|
+
function isTransientNetworkError(error) {
|
|
23708
|
+
const message = error.message?.toLowerCase() ?? "";
|
|
23709
|
+
return TRANSIENT_NETWORK_ERROR_PATTERNS.some((pattern) => message.includes(pattern));
|
|
23710
|
+
}
|
|
23711
|
+
/**
|
|
23632
23712
|
* Server-side LLM backend that proxies requests through Bike4Mind API
|
|
23633
23713
|
* Uses Server-Sent Events (SSE) for streaming responses
|
|
23634
23714
|
* API keys remain secure on server - never exposed to CLI
|
|
@@ -23653,19 +23733,35 @@ var ServerLlmBackend = class ServerLlmBackend {
|
|
|
23653
23733
|
*/
|
|
23654
23734
|
async complete(model, messages, options, callback) {
|
|
23655
23735
|
let lastError;
|
|
23736
|
+
let delivered = false;
|
|
23737
|
+
const trackingCallback = (text, info) => {
|
|
23738
|
+
delivered = true;
|
|
23739
|
+
return callback(text, info);
|
|
23740
|
+
};
|
|
23656
23741
|
for (let attempt = 0; attempt <= ServerLlmBackend.MAX_STREAM_RETRIES; attempt++) {
|
|
23657
23742
|
if (attempt > 0) logger.warn(`[ServerLlmBackend] Retrying stream (attempt ${attempt + 1}/${ServerLlmBackend.MAX_STREAM_RETRIES + 1})...`);
|
|
23658
23743
|
try {
|
|
23659
|
-
await this.completeOnce(model, messages, options,
|
|
23744
|
+
await this.completeOnce(model, messages, options, trackingCallback);
|
|
23660
23745
|
return;
|
|
23661
23746
|
} catch (error) {
|
|
23662
23747
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
23663
|
-
|
|
23664
|
-
|
|
23665
|
-
|
|
23666
|
-
|
|
23748
|
+
if (options.abortSignal?.aborted) throw lastError;
|
|
23749
|
+
if (delivered) {
|
|
23750
|
+
if (isTransientNetworkError(lastError)) {
|
|
23751
|
+
logger.warn(`[ServerLlmBackend] Ignoring post-delivery transient stream error: ${lastError.message}`);
|
|
23752
|
+
return;
|
|
23753
|
+
}
|
|
23754
|
+
throw lastError;
|
|
23755
|
+
}
|
|
23756
|
+
if (!(lastError.message.includes("Stream ended prematurely") || isTransientNetworkError(lastError))) throw lastError;
|
|
23757
|
+
logger.warn(`[ServerLlmBackend] Transient stream failure (attempt ${attempt + 1}/${ServerLlmBackend.MAX_STREAM_RETRIES + 1}): ${lastError.message}`);
|
|
23758
|
+
if (attempt < ServerLlmBackend.MAX_STREAM_RETRIES) await new Promise((resolve) => setTimeout(resolve, 500 * (attempt + 1)));
|
|
23667
23759
|
}
|
|
23668
23760
|
}
|
|
23761
|
+
if (lastError && isTransientNetworkError(lastError) && !options.abortSignal?.aborted) {
|
|
23762
|
+
logger.error("[ServerLlmBackend] Stream failed after all retries due to a network drop", lastError);
|
|
23763
|
+
throw new Error("The connection to the Bike4Mind server dropped mid-response (likely a network timeout during a long thinking step). It was retried automatically but kept failing — type \"continue\" to resume.");
|
|
23764
|
+
}
|
|
23669
23765
|
throw lastError ?? /* @__PURE__ */ new Error("Stream failed after all retry attempts");
|
|
23670
23766
|
}
|
|
23671
23767
|
/**
|
|
@@ -24436,6 +24532,7 @@ var WebSocketToolExecutor = class {
|
|
|
24436
24532
|
};
|
|
24437
24533
|
//#endregion
|
|
24438
24534
|
//#region src/auth/ApiClient.ts
|
|
24535
|
+
const USER_AGENT = `b4m-cli/${version}`;
|
|
24439
24536
|
/**
|
|
24440
24537
|
* Authenticated API client for B4M services
|
|
24441
24538
|
* Automatically injects access tokens from ConfigStore
|
|
@@ -24446,7 +24543,11 @@ var ApiClient = class {
|
|
|
24446
24543
|
this.oauthClient = new OAuthClient(baseURL);
|
|
24447
24544
|
this.client = axios.create({
|
|
24448
24545
|
baseURL,
|
|
24449
|
-
headers: {
|
|
24546
|
+
headers: {
|
|
24547
|
+
"Content-Type": "application/json",
|
|
24548
|
+
"User-Agent": USER_AGENT,
|
|
24549
|
+
"X-B4M-Client": USER_AGENT
|
|
24550
|
+
}
|
|
24450
24551
|
});
|
|
24451
24552
|
this.client.interceptors.request.use(async (config) => {
|
|
24452
24553
|
const tokens = await this.configStore.getAuthTokens();
|
|
@@ -27518,4 +27619,4 @@ function createReviewGateStore(onUpdate) {
|
|
|
27518
27619
|
};
|
|
27519
27620
|
}
|
|
27520
27621
|
//#endregion
|
|
27521
|
-
export {
|
|
27622
|
+
export { OAuthClient as $, substituteArguments as A, DEFAULT_THOROUGHNESS as B, WebSocketToolExecutor as C, ServerLlmBackend as D, WebSocketLlmBackend as E, generateCliTools as F, buildSystemPrompt as G, registerFeatureModuleTools as H, ALWAYS_DENIED_FOR_AGENTS as I, ReActAgent as J, buildSkillsPromptSection as K, DEFAULT_AGENT_MODEL as L, extractCompactInstructions as M, loadContextFiles as N, isTransientNetworkError as O, PermissionManager as P, SessionStore as Q, DEFAULT_MAX_ITERATIONS as R, ApiClient as S, FallbackLlmBackend as T, setWebSocketToolExecutor as U, clearFeatureModuleTools as V, getPlanModeFilePath as W, CheckpointStore as X, CustomCommandStore as Y, CommandHistoryStore as Z, createAgentDelegateTool as _, createBlockerTools as a, searchFiles as at, createSkillTool as b, createDecisionStore as c, createFindDefinitionTool as d, hasFileReferences as et, createTodoStore as f, BackgroundAgentManager as g, createBackgroundAgentTools as h, createBlockerStore as i, formatFileSize$1 as it, formatStep as j, McpManager as k, formatDecisionsOutput as l, createCoordinateTaskTool as m, createReviewGateTool as n, searchCommands as nt, formatBlockersOutput as o, warmFileCache as ot, createWriteTodosTool as p, isReadOnlyTool as q, formatReviewGatesOutput as r, mergeCommands as rt, createDecisionLogTool as s, createReviewGateStore as t, processFileReferences as tt, createGetFileStructureTool as u, AgentStore as v, WebSocketConnectionManager as w, parseAgentConfig as x, SubagentOrchestrator as y, DEFAULT_RETRY_CONFIG as z };
|
|
@@ -3,9 +3,6 @@ import { promises } from "fs";
|
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import axios from "axios";
|
|
6
|
-
//#region package.json
|
|
7
|
-
var version = "0.10.3";
|
|
8
|
-
//#endregion
|
|
9
6
|
//#region src/utils/updateChecker.ts
|
|
10
7
|
/**
|
|
11
8
|
* Update checker utility for B4M CLI
|
|
@@ -117,4 +114,4 @@ async function forceCheckForUpdate(currentVersion) {
|
|
|
117
114
|
};
|
|
118
115
|
}
|
|
119
116
|
//#endregion
|
|
120
|
-
export {
|
|
117
|
+
export { 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.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"zod": "^4.4.3",
|
|
108
108
|
"zod-validation-error": "^5.0.0",
|
|
109
109
|
"zustand": "^5.0.13",
|
|
110
|
-
"@bike4mind/fab-pipeline": "0.2.
|
|
111
|
-
"@bike4mind/llm-adapters": "0.3.
|
|
110
|
+
"@bike4mind/fab-pipeline": "0.2.8",
|
|
111
|
+
"@bike4mind/llm-adapters": "0.3.3",
|
|
112
112
|
"@bike4mind/observability": "0.1.0"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
@@ -124,11 +124,11 @@
|
|
|
124
124
|
"tsx": "^4.22.3",
|
|
125
125
|
"typescript": "^5.9.3",
|
|
126
126
|
"vitest": "^4.1.7",
|
|
127
|
-
"@bike4mind/agents": "0.11.
|
|
128
|
-
"@bike4mind/common": "2.
|
|
129
|
-
"@bike4mind/mcp": "1.37.
|
|
130
|
-
"@bike4mind/services": "2.
|
|
131
|
-
"@bike4mind/utils": "2.23.
|
|
127
|
+
"@bike4mind/agents": "0.11.7",
|
|
128
|
+
"@bike4mind/common": "2.106.0",
|
|
129
|
+
"@bike4mind/mcp": "1.37.21",
|
|
130
|
+
"@bike4mind/services": "2.92.1",
|
|
131
|
+
"@bike4mind/utils": "2.23.9"
|
|
132
132
|
},
|
|
133
133
|
"optionalDependencies": {
|
|
134
134
|
"@vscode/ripgrep": "^1.18.0"
|