@bike4mind/cli 1.0.0 → 1.1.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/dist/{AgentHistoryStore-CrRb8cMt.mjs → AgentHistoryStore-kT9eNMRO.mjs} +2007 -1122
- package/dist/{ApiClient-EUTyn5yu.mjs → ApiClient-BOWpVvTq.mjs} +2 -2
- package/dist/{ConfigStore-DHNgFdOu.mjs → ConfigStore-DdHHCH2t.mjs} +1435 -248
- package/dist/{SandboxOrchestrator-BFPVpmB5.mjs → SandboxOrchestrator-BbMDgjzr.mjs} +1 -1
- package/dist/{SandboxOrchestrator-C8uleDn2.mjs → SandboxOrchestrator-CIegJrCj.mjs} +1 -1
- package/dist/{buildAgent-CJrkEG0M.mjs → buildAgent-B_kArQ_Y.mjs} +18 -9
- package/dist/commands/acpCommand.mjs +34 -13
- package/dist/commands/apiCommand.mjs +1 -1
- package/dist/commands/doctorCommand.mjs +1 -1
- package/dist/commands/envCommand.mjs +1 -1
- package/dist/commands/headlessCommand.mjs +73 -33
- package/dist/commands/mcpCommand.mjs +8 -13
- package/dist/commands/pluginCommand.mjs +9 -15
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/{createFile-DPv180yF-BnWFIxey.mjs → createFile-B8bur5Rb-CVzCarEA.mjs} +2 -2
- package/dist/{deleteFile-BdjUwUQF-B3XOJmg3.mjs → deleteFile-9B3gW_Nb-DG2sovIl.mjs} +2 -2
- package/dist/{globFiles-DjfDGaUK-CNR8pMRC.mjs → globFiles-CwJ8qmYo-BR5b2KvO.mjs} +3 -2
- package/dist/{grepSearch-BaYUfIYs-n0XKoGnL.mjs → grepSearch-BgoOOwGe-DtlV8Gn-.mjs} +3 -3
- package/dist/index.mjs +212 -47
- package/dist/{package-7a45-Svr.mjs → package-Bqg2LSnH.mjs} +1 -1
- package/dist/{pathValidation-D8tjkQXE-1HwvsuYT.mjs → pathValidation-BRqf4HFX-CHwtwp3O.mjs} +7 -3
- package/dist/{serve-CavAHPdQ.mjs → serve-DO9Edl5S.mjs} +2 -2
- package/dist/types-CdIKgWWe.mjs +3 -0
- package/dist/{types-LyRNHOiS.mjs → types-F61_hxmG.mjs} +2 -0
- package/package.json +28 -28
- package/dist/types-CqscS34o.mjs +0 -3
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as CustomCommandStore, A as createAgentDelegateTool, B as ALWAYS_DENIED_FOR_AGENTS, C as createTodoStore, D as createCoordinateTaskTool, E as parseAgentConfig, F as PermissionManager, H as DEFAULT_MAX_ITERATIONS, J as setWebSocketToolExecutor, K as clearFeatureModuleTools, L as wrapTools, M as substituteArguments, O as createResumeAgentTool, P as findIterationBoundary, Q as RemoteSkillSource, R as getProcessHooks, S as createFindDefinitionTool, T as createSkillTool, U as DEFAULT_RETRY_CONFIG, V as DEFAULT_AGENT_MODEL, W as DEFAULT_THOROUGHNESS, X as buildSystemPrompt, Y as getPlanModeFilePath, Z as buildSkillsPromptSection, _ as createDecisionLogTool, at as mergeCommands, b as createGetFileStructureTool, ct as warmFileCache, d as createReviewGateStore, dt as MAX_PASTE_SIZE, et as CheckpointStore, f as createReviewGateTool, g as formatBlockersOutput, h as createBlockerTools, it as searchCommands, j as FallbackLlmBackend, k as createBackgroundAgentTools, l as isTransientNetworkError, lt as COMPACTION_SUMMARY_MARKER, m as createBlockerStore, nt as hasFileReferences, ot as formatFileSize, p as formatReviewGatesOutput, q as registerFeatureModuleTools, rt as processFileReferences, st as searchFiles, tt as SessionStore, v as createDecisionStore, w as createWriteTodosTool, x as createWorkItemTools, y as formatDecisionsOutput } from "./AgentHistoryStore-kT9eNMRO.mjs";
|
|
3
3
|
import { a as selectLiveSubagentTokens, i as selectLiveSubagentCredits, n as selectActiveBackgroundShells, o as useCliStore, r as selectCompletedBackgroundShells, t as selectActiveBackgroundAgents } from "./store-CvjTpQPs.mjs";
|
|
4
4
|
import { r as isFeatureEnabled, t as PluginStore } from "./PluginStore-DwvOJ-G3.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { D as ChatModels, E as CREDIT_DEDUCT_TRANSACTION_TYPES, Ot as isEarlyStop, c as ApiEndpointUnconfiguredError, cn as actorColorIndex, d as getEnvironmentName, dn as selfClaimedActorKindSchema, et as REVIEW_GATE_STATUS_VALUES, f as parseApiUrl, l as LOCAL_DEV_URL, ln as actorKindMarker, m as resolveApiEndpoint, n as logger, p as requireApiUrl, r as extractCompactInstructions, s as isReadOnlyTool, sn as ACTOR_COLOR_SLOTS, t as ConfigStore, tt as SUBQUEST_STATUS_VALUES, u as getCreditsUrl, un as actorKindSchema } from "./ConfigStore-DdHHCH2t.mjs";
|
|
6
6
|
import { t as getShellSessionManager } from "./ShellSessionManager-6o8KZzl1-vrbPAUTq.mjs";
|
|
7
|
-
import { n as OAuthClient, t as ApiClient } from "./ApiClient-
|
|
7
|
+
import { n as OAuthClient, t as ApiClient } from "./ApiClient-BOWpVvTq.mjs";
|
|
8
8
|
import { i as getTokenCounter, n as ConversationContext, r as reconstructTurnBlocks, t as WorkItemsClient } from "./WorkItemsClient-Cow6nXx7.mjs";
|
|
9
|
-
import { a as createToolSearchTool, i as buildLlmBackend, n as buildSupportingStores, o as deferredToolRegistry, r as buildSandbox, s as NotifyingLlmBackend, t as buildAgent } from "./buildAgent-
|
|
10
|
-
import { t as version } from "./package-
|
|
9
|
+
import { a as createToolSearchTool, i as buildLlmBackend, n as buildSupportingStores, o as deferredToolRegistry, r as buildSandbox, s as NotifyingLlmBackend, t as buildAgent } from "./buildAgent-B_kArQ_Y.mjs";
|
|
10
|
+
import { t as version } from "./package-Bqg2LSnH.mjs";
|
|
11
11
|
import { r as checkForUpdate } from "./updateChecker-CQW8bxo6.mjs";
|
|
12
12
|
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
13
13
|
import { Box, Static, Text, render, useApp, useInput, usePaste, useStdout } from "ink";
|
|
@@ -1083,9 +1083,19 @@ function CompletedGroupNotification() {
|
|
|
1083
1083
|
}
|
|
1084
1084
|
//#endregion
|
|
1085
1085
|
//#region src/components/PermissionPrompt.tsx
|
|
1086
|
+
/**
|
|
1087
|
+
* Escape terminal control characters (carriage return, ESC/ANSI, other C0
|
|
1088
|
+
* controls, DEL) into a visible `\xHH` form. The preview is model-authored;
|
|
1089
|
+
* rendering it raw would let a `\r` or ESC sequence rewrite what the user sees,
|
|
1090
|
+
* so the approved text could differ from what actually runs. Tab and newline are
|
|
1091
|
+
* left intact (newline is already the line delimiter).
|
|
1092
|
+
*/
|
|
1093
|
+
function escapeTerminalControlChars(text) {
|
|
1094
|
+
return text.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, (ch) => `\\x${ch.charCodeAt(0).toString(16).padStart(2, "0")}`);
|
|
1095
|
+
}
|
|
1086
1096
|
/** Render a diff/preview string, color-coding each line by its prefix (see per-branch comments below). */
|
|
1087
1097
|
function renderDiffPreview(preview) {
|
|
1088
|
-
return preview.split("\n").map((line, index) => {
|
|
1098
|
+
return escapeTerminalControlChars(preview).split("\n").map((line, index) => {
|
|
1089
1099
|
if (line.startsWith("🛑")) return /* @__PURE__ */ React.createElement(Text, {
|
|
1090
1100
|
key: index,
|
|
1091
1101
|
bold: true,
|
|
@@ -2656,6 +2666,40 @@ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
|
2656
2666
|
}), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Use ↑↓ arrows to navigate, Enter to select, Ctrl+C to cancel")));
|
|
2657
2667
|
}
|
|
2658
2668
|
//#endregion
|
|
2669
|
+
//#region src/components/FolderTrustPrompt.tsx
|
|
2670
|
+
/**
|
|
2671
|
+
* One-time startup prompt shown when the current project root ships repo-committed
|
|
2672
|
+
* b4m files (config, .mcp.json, agents, skills, commands) but has not been
|
|
2673
|
+
* trusted. Until trusted, those files are inert - no config merge, no MCP spawn,
|
|
2674
|
+
* no agent/skill/command load. "Trust this folder" persists the decision; "Not
|
|
2675
|
+
* now" keeps the project untrusted for this session (re-prompts next launch).
|
|
2676
|
+
*
|
|
2677
|
+
* "Not now" is listed first so it is the preselected default: Enter-through on a
|
|
2678
|
+
* freshly cloned repo must not grant trust.
|
|
2679
|
+
*/
|
|
2680
|
+
function FolderTrustPrompt({ projectRoot, onSelect }) {
|
|
2681
|
+
return /* @__PURE__ */ React.createElement(Box, {
|
|
2682
|
+
flexDirection: "column",
|
|
2683
|
+
marginY: 1
|
|
2684
|
+
}, /* @__PURE__ */ React.createElement(Box, {
|
|
2685
|
+
marginBottom: 1,
|
|
2686
|
+
flexDirection: "column"
|
|
2687
|
+
}, /* @__PURE__ */ React.createElement(Text, {
|
|
2688
|
+
bold: true,
|
|
2689
|
+
color: "yellow"
|
|
2690
|
+
}, "This project ships Bike4Mind config that can run code."), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, projectRoot), /* @__PURE__ */ React.createElement(Text, null, "Repo-committed config, MCP servers, agents and skills stay inert until you trust this folder. Only trust folders you would run code from.")), /* @__PURE__ */ React.createElement(SelectInput, {
|
|
2691
|
+
items: [{
|
|
2692
|
+
label: "Not now - keep repo config inert this session",
|
|
2693
|
+
value: "not-now"
|
|
2694
|
+
}, {
|
|
2695
|
+
label: "Trust this folder - load its config, agents, skills and MCP servers",
|
|
2696
|
+
value: "trust"
|
|
2697
|
+
}],
|
|
2698
|
+
onSelect: (item) => onSelect(item.value),
|
|
2699
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: isSelected ? "cyan" : void 0 }, isSelected ? "❯ " : " ", label))
|
|
2700
|
+
}), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Use ↑↓ arrows to navigate, Enter to select. You can change this later with /trust folder.")));
|
|
2701
|
+
}
|
|
2702
|
+
//#endregion
|
|
2659
2703
|
//#region src/components/RewindSelector.tsx
|
|
2660
2704
|
function RewindSelector({ messages, onSelect, onCancel }) {
|
|
2661
2705
|
const [step, setStep] = useState("selection");
|
|
@@ -2882,6 +2926,22 @@ function EnvironmentPicker({ onSelect }) {
|
|
|
2882
2926
|
}
|
|
2883
2927
|
//#endregion
|
|
2884
2928
|
//#region src/components/LoginFlow.tsx
|
|
2929
|
+
/**
|
|
2930
|
+
* Only https URLs (and http on localhost for dev) may be handed to the OS opener.
|
|
2931
|
+
* The device-flow response is server-controlled, so a hostile/compromised server
|
|
2932
|
+
* could return `file:///...`, `javascript:...` or similar and have the OS launch
|
|
2933
|
+
* it. Reject anything that isn't a plain web URL.
|
|
2934
|
+
*/
|
|
2935
|
+
function isBrowserOpenableUrl(raw) {
|
|
2936
|
+
let url;
|
|
2937
|
+
try {
|
|
2938
|
+
url = new URL(raw);
|
|
2939
|
+
} catch {
|
|
2940
|
+
return false;
|
|
2941
|
+
}
|
|
2942
|
+
if (url.protocol === "https:") return true;
|
|
2943
|
+
return url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1");
|
|
2944
|
+
}
|
|
2885
2945
|
function extractErrorMessage(err) {
|
|
2886
2946
|
if (axios.isAxiosError(err)) {
|
|
2887
2947
|
if (err.response?.data) {
|
|
@@ -2939,9 +2999,10 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
2939
2999
|
onError
|
|
2940
3000
|
]);
|
|
2941
3001
|
useEffect(() => {
|
|
2942
|
-
if (deviceFlow && status === "waiting") open(deviceFlow.verification_uri_complete).catch((err) => {
|
|
3002
|
+
if (deviceFlow && status === "waiting") if (isBrowserOpenableUrl(deviceFlow.verification_uri_complete)) open(deviceFlow.verification_uri_complete).catch((err) => {
|
|
2943
3003
|
console.error("Failed to auto-open browser:", err);
|
|
2944
3004
|
});
|
|
3005
|
+
else console.error("Refusing to auto-open untrusted verification URL:", deviceFlow.verification_uri_complete);
|
|
2945
3006
|
}, [deviceFlow, status]);
|
|
2946
3007
|
if (status === "initiating") return /* @__PURE__ */ React.createElement(Box, {
|
|
2947
3008
|
flexDirection: "column",
|
|
@@ -3087,6 +3148,35 @@ var CommandHistoryStore = class {
|
|
|
3087
3148
|
}
|
|
3088
3149
|
};
|
|
3089
3150
|
//#endregion
|
|
3151
|
+
//#region src/storage/buildGlobalConfigPatch.ts
|
|
3152
|
+
/**
|
|
3153
|
+
* Compute the minimal global-config patch for a /config editor save: only the
|
|
3154
|
+
* editor-owned fields (defaultModel, preferences, features) that the user
|
|
3155
|
+
* actually changed vs the current effective (merged) config. Unchanged fields
|
|
3156
|
+
* are omitted, so a repo-injected value the user never touched is never
|
|
3157
|
+
* laundered into the global layer by a save() that spreads the merged config.
|
|
3158
|
+
*
|
|
3159
|
+
* defaultModel and preferences diff per key. features stays whole-object when
|
|
3160
|
+
* anything changed, on purpose: ConfigStore.save() feeds config.features to
|
|
3161
|
+
* mergeFeatures as the caller's COMPLETE desired set (absence of a key means
|
|
3162
|
+
* "removed"), so a per-key diff would make save() delete untouched keys. That
|
|
3163
|
+
* whole-object features path is only latently launderable today (no repo layer
|
|
3164
|
+
* populates features); tightening it needs a coordinated change to save()'s
|
|
3165
|
+
* concurrent-writer merge and is tracked separately.
|
|
3166
|
+
*/
|
|
3167
|
+
function buildGlobalConfigPatch(prev, next) {
|
|
3168
|
+
const patch = {};
|
|
3169
|
+
if (next.defaultModel !== prev?.defaultModel) patch.defaultModel = next.defaultModel;
|
|
3170
|
+
const changedPreferences = {};
|
|
3171
|
+
for (const [key, value] of Object.entries(next.preferences)) {
|
|
3172
|
+
const prevValue = (prev?.preferences)?.[key];
|
|
3173
|
+
if (JSON.stringify(value) !== JSON.stringify(prevValue)) changedPreferences[key] = value;
|
|
3174
|
+
}
|
|
3175
|
+
if (Object.keys(changedPreferences).length > 0) patch.preferences = changedPreferences;
|
|
3176
|
+
if (JSON.stringify(next.features ?? {}) !== JSON.stringify(prev?.features ?? {})) patch.features = next.features;
|
|
3177
|
+
return patch;
|
|
3178
|
+
}
|
|
3179
|
+
//#endregion
|
|
3090
3180
|
//#region src/utils/formatStep.ts
|
|
3091
3181
|
const MAX_INPUT_LENGTH = 500;
|
|
3092
3182
|
/**
|
|
@@ -7069,7 +7159,9 @@ API Configuration:
|
|
|
7069
7159
|
Tool Permissions:
|
|
7070
7160
|
/trust <tool-name> - Trust a tool (won't ask permission again)
|
|
7071
7161
|
/untrust <tool-name> - Remove tool from trusted list
|
|
7072
|
-
/
|
|
7162
|
+
/trust folder - Trust this project (load its repo config, agents, skills, MCP)
|
|
7163
|
+
/untrust folder - Revoke trust for this project (repo config goes inert)
|
|
7164
|
+
/trusted - Show folder-trust status and list all trusted tools
|
|
7073
7165
|
|
|
7074
7166
|
Project Configuration:
|
|
7075
7167
|
/project-config - Show merged project configuration
|
|
@@ -7131,8 +7223,16 @@ Multi-line Input:
|
|
|
7131
7223
|
{
|
|
7132
7224
|
name: "trusted",
|
|
7133
7225
|
run: (_args, ctx) => {
|
|
7226
|
+
const projectRoot = ctx.configStore.getProjectRealPath();
|
|
7227
|
+
console.log("\n📁 Folder Trust:\n");
|
|
7228
|
+
if (!projectRoot) console.log(" No project root discovered.");
|
|
7229
|
+
else {
|
|
7230
|
+
const isTrusted = ctx.configStore.isProjectTrusted();
|
|
7231
|
+
console.log(` ${isTrusted ? "✅ Trusted" : "⛔ Not trusted"}: ${projectRoot}`);
|
|
7232
|
+
if (!isTrusted) console.log(" Repo config/agents/skills/MCP stay inert. Trust with /trust folder.");
|
|
7233
|
+
}
|
|
7134
7234
|
if (!ctx.permissionManager) {
|
|
7135
|
-
console.log("
|
|
7235
|
+
console.log("\nPermission manager not initialized\n");
|
|
7136
7236
|
return;
|
|
7137
7237
|
}
|
|
7138
7238
|
const trustedTools = ctx.permissionManager.getTrustedTools();
|
|
@@ -7753,6 +7853,7 @@ function CliApp() {
|
|
|
7753
7853
|
permissionManager: null,
|
|
7754
7854
|
permissionPrompt: null,
|
|
7755
7855
|
trustLocationSelector: null,
|
|
7856
|
+
folderTrustPrompt: null,
|
|
7756
7857
|
rewindSelector: null,
|
|
7757
7858
|
sessionSelector: null,
|
|
7758
7859
|
orchestrator: null,
|
|
@@ -7771,6 +7872,7 @@ function CliApp() {
|
|
|
7771
7872
|
const [initError, setInitError] = useState(null);
|
|
7772
7873
|
const [commandHistory, setCommandHistory] = useState([]);
|
|
7773
7874
|
const imageStoreInitPromise = useRef(null);
|
|
7875
|
+
const folderTrustResolvedRef = useRef(false);
|
|
7774
7876
|
const todoStoreRef = useRef(createTodoStore());
|
|
7775
7877
|
const decisionStoreRef = useRef(createDecisionStore());
|
|
7776
7878
|
const blockerStoreRef = useRef(createBlockerStore());
|
|
@@ -7877,11 +7979,21 @@ function CliApp() {
|
|
|
7877
7979
|
try {
|
|
7878
7980
|
const startupLog = [];
|
|
7879
7981
|
const config = await state.configStore.load();
|
|
7982
|
+
if (!folderTrustResolvedRef.current && !state.configStore.isProjectTrusted() && state.configStore.projectHasB4mFiles() && Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY)) {
|
|
7983
|
+
folderTrustResolvedRef.current = true;
|
|
7984
|
+
setState((prev) => ({
|
|
7985
|
+
...prev,
|
|
7986
|
+
folderTrustPrompt: { projectRoot: state.configStore.getProjectRealPath() ?? process.cwd() },
|
|
7987
|
+
config
|
|
7988
|
+
}));
|
|
7989
|
+
return;
|
|
7990
|
+
}
|
|
7880
7991
|
const configDirs = await state.configStore.getAdditionalDirectories();
|
|
7881
7992
|
const flagDirs = process.env.B4M_ADDITIONAL_DIRS ? JSON.parse(process.env.B4M_ADDITIONAL_DIRS) : [];
|
|
7882
7993
|
const additionalDirectories = [.../* @__PURE__ */ new Set([...configDirs, ...flagDirs])];
|
|
7883
7994
|
const history = await state.commandHistoryStore.load();
|
|
7884
7995
|
setCommandHistory(history);
|
|
7996
|
+
state.customCommandStore.setProjectTrusted(state.configStore.isProjectTrusted());
|
|
7885
7997
|
try {
|
|
7886
7998
|
await state.customCommandStore.loadCommands();
|
|
7887
7999
|
} catch (error) {
|
|
@@ -8108,14 +8220,26 @@ function CliApp() {
|
|
|
8108
8220
|
blockerStoreRef.current.blockers = [];
|
|
8109
8221
|
reviewGateStoreRef.current.reviewGates = [];
|
|
8110
8222
|
}
|
|
8223
|
+
const cliWrapDeps = {
|
|
8224
|
+
permissionManager,
|
|
8225
|
+
showPermissionPrompt: promptFn,
|
|
8226
|
+
agentContext,
|
|
8227
|
+
configStore: state.configStore,
|
|
8228
|
+
apiClient,
|
|
8229
|
+
sandboxOrchestrator: sandboxOrchestrator ?? void 0,
|
|
8230
|
+
allowedDirectories: additionalDirectories
|
|
8231
|
+
};
|
|
8111
8232
|
const enableSkillTool = config.preferences.enableSkillTool !== false;
|
|
8112
|
-
const skillTool = enableSkillTool ? createSkillTool({
|
|
8233
|
+
const skillTool = enableSkillTool ? wrapTools([createSkillTool({
|
|
8113
8234
|
customCommandStore: state.customCommandStore,
|
|
8114
8235
|
subagentOrchestrator: orchestrator,
|
|
8115
|
-
sessionId: newSession.id
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8236
|
+
sessionId: newSession.id,
|
|
8237
|
+
permissionManager,
|
|
8238
|
+
promptFn,
|
|
8239
|
+
allowedDirectories: additionalDirectories
|
|
8240
|
+
})], cliWrapDeps)[0] : null;
|
|
8241
|
+
const findDefinitionTool = wrapTools([createFindDefinitionTool(additionalDirectories)], cliWrapDeps)[0];
|
|
8242
|
+
const getFileStructureTool = wrapTools([createGetFileStructureTool(additionalDirectories)], cliWrapDeps)[0];
|
|
8119
8243
|
const workItemTools = config.preferences.enableWorkItemTools ? createWorkItemTools(new WorkItemsClient(apiClient)) : [];
|
|
8120
8244
|
const cliTools = [
|
|
8121
8245
|
agentDelegateTool,
|
|
@@ -9142,6 +9266,18 @@ function CliApp() {
|
|
|
9142
9266
|
break;
|
|
9143
9267
|
}
|
|
9144
9268
|
case "trust": {
|
|
9269
|
+
if (args[0] === "folder") {
|
|
9270
|
+
const root = state.configStore.getProjectRealPath() ?? process.cwd();
|
|
9271
|
+
if (!await state.configStore.trustProject()) {
|
|
9272
|
+
console.log("\n⚠️ No project folder to trust here (no resolvable project root).\n");
|
|
9273
|
+
return;
|
|
9274
|
+
}
|
|
9275
|
+
state.customCommandStore.setProjectTrusted(true);
|
|
9276
|
+
await state.customCommandStore.reloadCommands().catch(() => {});
|
|
9277
|
+
console.log(`\n✅ Trusted project folder: ${root}`);
|
|
9278
|
+
console.log("Project skills are now loaded. Restart b4m to load repo agents and MCP servers.\n");
|
|
9279
|
+
return;
|
|
9280
|
+
}
|
|
9145
9281
|
if (!state.permissionManager) {
|
|
9146
9282
|
console.log("Permission manager not initialized");
|
|
9147
9283
|
return;
|
|
@@ -9177,6 +9313,11 @@ function CliApp() {
|
|
|
9177
9313
|
console.log("❌ No project found. Use \"global\" to save to ~/.bike4mind/config.json");
|
|
9178
9314
|
return;
|
|
9179
9315
|
}
|
|
9316
|
+
if (!state.configStore.isProjectTrusted()) {
|
|
9317
|
+
console.log("❌ This folder is not trusted, so a project-local trust would not take effect.");
|
|
9318
|
+
console.log(` Run /trust folder first, or choose "global" to trust '${toolToTrust}' everywhere.`);
|
|
9319
|
+
return;
|
|
9320
|
+
}
|
|
9180
9321
|
try {
|
|
9181
9322
|
await state.configStore.initProjectConfig();
|
|
9182
9323
|
const existingLocal = await state.configStore.loadRawProjectLocalConfig() || {};
|
|
@@ -9197,6 +9338,11 @@ function CliApp() {
|
|
|
9197
9338
|
console.log("❌ No project found. Use \"global\" to save to ~/.bike4mind/config.json");
|
|
9198
9339
|
return;
|
|
9199
9340
|
}
|
|
9341
|
+
if (!state.configStore.isProjectTrusted()) {
|
|
9342
|
+
console.log("❌ This folder is not trusted, so a team-project trust would not take effect.");
|
|
9343
|
+
console.log(` Run /trust folder first, or choose "global" to trust '${toolToTrust}' everywhere.`);
|
|
9344
|
+
return;
|
|
9345
|
+
}
|
|
9200
9346
|
try {
|
|
9201
9347
|
const existingProject = await state.configStore.loadRawProjectConfig() || {};
|
|
9202
9348
|
const updatedProject = {
|
|
@@ -9235,6 +9381,15 @@ function CliApp() {
|
|
|
9235
9381
|
break;
|
|
9236
9382
|
}
|
|
9237
9383
|
case "untrust": {
|
|
9384
|
+
if (args[0] === "folder") {
|
|
9385
|
+
const root = state.configStore.getProjectRealPath() ?? process.cwd();
|
|
9386
|
+
await state.configStore.untrustProject();
|
|
9387
|
+
state.customCommandStore.setProjectTrusted(false);
|
|
9388
|
+
await state.customCommandStore.reloadCommands().catch(() => {});
|
|
9389
|
+
console.log(`\n✅ Untrusted project folder: ${root}`);
|
|
9390
|
+
console.log("Repo config stays inert. Restart b4m to fully unload repo agents and MCP servers.\n");
|
|
9391
|
+
return;
|
|
9392
|
+
}
|
|
9238
9393
|
if (!state.permissionManager) {
|
|
9239
9394
|
console.log("Permission manager not initialized");
|
|
9240
9395
|
return;
|
|
@@ -9568,6 +9723,7 @@ function CliApp() {
|
|
|
9568
9723
|
console.log("\n📁 Project Configuration:\n");
|
|
9569
9724
|
if (projectDir) {
|
|
9570
9725
|
console.log(`Project Directory: ${projectDir}/.bike4mind/`);
|
|
9726
|
+
if (!state.configStore.isProjectTrusted()) console.log("⚠️ Folder not trusted - team/local config below is NOT applied. Run /trust folder.");
|
|
9571
9727
|
console.log("");
|
|
9572
9728
|
const projectConfig = await state.configStore.loadRawProjectConfig();
|
|
9573
9729
|
const localConfig = await state.configStore.loadRawProjectLocalConfig();
|
|
@@ -9769,7 +9925,7 @@ function CliApp() {
|
|
|
9769
9925
|
}
|
|
9770
9926
|
break;
|
|
9771
9927
|
}
|
|
9772
|
-
case "sandbox:enable":
|
|
9928
|
+
case "sandbox:enable":
|
|
9773
9929
|
if (!state.sandboxOrchestrator) {
|
|
9774
9930
|
console.log("Sandbox not initialized");
|
|
9775
9931
|
break;
|
|
@@ -9785,15 +9941,10 @@ function CliApp() {
|
|
|
9785
9941
|
const pm = state.sandboxOrchestrator.getProxyManager();
|
|
9786
9942
|
if (pm?.isRunning()) console.log(`🌐 Network proxy started on port ${pm.getPort()}`);
|
|
9787
9943
|
}
|
|
9788
|
-
|
|
9789
|
-
await state.configStore.save({
|
|
9790
|
-
...config,
|
|
9791
|
-
sandbox: { ...state.sandboxOrchestrator.getConfig() }
|
|
9792
|
-
});
|
|
9944
|
+
await state.configStore.saveSandboxConfig(state.sandboxOrchestrator.getConfig());
|
|
9793
9945
|
console.log("Sandbox enabled (auto-allow mode)");
|
|
9794
9946
|
break;
|
|
9795
|
-
|
|
9796
|
-
case "sandbox:disable": {
|
|
9947
|
+
case "sandbox:disable":
|
|
9797
9948
|
if (!state.sandboxOrchestrator) {
|
|
9798
9949
|
console.log("Sandbox not initialized");
|
|
9799
9950
|
break;
|
|
@@ -9801,14 +9952,9 @@ function CliApp() {
|
|
|
9801
9952
|
await state.sandboxOrchestrator.stopProxy();
|
|
9802
9953
|
state.sandboxOrchestrator.setMode("disabled");
|
|
9803
9954
|
state.permissionManager?.setSandboxState("disabled", false);
|
|
9804
|
-
|
|
9805
|
-
await state.configStore.save({
|
|
9806
|
-
...disableConfig,
|
|
9807
|
-
sandbox: { ...state.sandboxOrchestrator.getConfig() }
|
|
9808
|
-
});
|
|
9955
|
+
await state.configStore.saveSandboxConfig(state.sandboxOrchestrator.getConfig());
|
|
9809
9956
|
console.log("Sandbox disabled");
|
|
9810
9957
|
break;
|
|
9811
|
-
}
|
|
9812
9958
|
case "sandbox:mode": {
|
|
9813
9959
|
if (!state.sandboxOrchestrator) {
|
|
9814
9960
|
console.log("Sandbox not initialized");
|
|
@@ -9825,11 +9971,7 @@ function CliApp() {
|
|
|
9825
9971
|
}
|
|
9826
9972
|
state.sandboxOrchestrator.setMode(modeArg);
|
|
9827
9973
|
state.permissionManager?.setSandboxState(modeArg, state.sandboxOrchestrator.isActive());
|
|
9828
|
-
|
|
9829
|
-
await state.configStore.save({
|
|
9830
|
-
...modeConfig,
|
|
9831
|
-
sandbox: { ...state.sandboxOrchestrator.getConfig() }
|
|
9832
|
-
});
|
|
9974
|
+
await state.configStore.saveSandboxConfig(state.sandboxOrchestrator.getConfig());
|
|
9833
9975
|
console.log(`Sandbox mode set to: ${modeArg}`);
|
|
9834
9976
|
break;
|
|
9835
9977
|
}
|
|
@@ -9851,16 +9993,12 @@ function CliApp() {
|
|
|
9851
9993
|
proxyMgr.addAllowedDomain(domain);
|
|
9852
9994
|
console.log(` Added: ${domain}`);
|
|
9853
9995
|
}
|
|
9854
|
-
const trustDomainConfig = await state.configStore.get();
|
|
9855
9996
|
const currentSandboxConfig = state.sandboxOrchestrator.getConfig();
|
|
9856
|
-
await state.configStore.
|
|
9857
|
-
...
|
|
9858
|
-
|
|
9859
|
-
...currentSandboxConfig,
|
|
9860
|
-
|
|
9861
|
-
...currentSandboxConfig.network,
|
|
9862
|
-
allowedDomains: proxyMgr.getAllowedDomains()
|
|
9863
|
-
}
|
|
9997
|
+
await state.configStore.saveSandboxConfig({
|
|
9998
|
+
...currentSandboxConfig,
|
|
9999
|
+
network: {
|
|
10000
|
+
...currentSandboxConfig.network,
|
|
10001
|
+
allowedDomains: proxyMgr.getAllowedDomains()
|
|
9864
10002
|
}
|
|
9865
10003
|
});
|
|
9866
10004
|
console.log(`Trusted ${args.length} domain(s)`);
|
|
@@ -10039,7 +10177,8 @@ function CliApp() {
|
|
|
10039
10177
|
* Handle saving config from the interactive editor
|
|
10040
10178
|
*/
|
|
10041
10179
|
const handleSaveConfig = async (updatedConfig, options) => {
|
|
10042
|
-
|
|
10180
|
+
const patch = buildGlobalConfigPatch(state.config, updatedConfig);
|
|
10181
|
+
await state.configStore.save(patch);
|
|
10043
10182
|
const modelChanged = state.config?.defaultModel !== updatedConfig.defaultModel;
|
|
10044
10183
|
const featuresChanged = JSON.stringify(state.config?.features ?? {}) !== JSON.stringify(updatedConfig.features ?? {});
|
|
10045
10184
|
let newFeatureRegistry = state.featureRegistry;
|
|
@@ -10127,10 +10266,14 @@ function CliApp() {
|
|
|
10127
10266
|
isBusy: () => useCliStore.getState().isThinking,
|
|
10128
10267
|
saveModel: async (modelId) => {
|
|
10129
10268
|
if (!state.config) throw new Error("no CLI config is loaded");
|
|
10130
|
-
await
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10269
|
+
await state.configStore.save({ defaultModel: modelId });
|
|
10270
|
+
setState((prev) => prev.config ? {
|
|
10271
|
+
...prev,
|
|
10272
|
+
config: {
|
|
10273
|
+
...prev.config,
|
|
10274
|
+
defaultModel: modelId
|
|
10275
|
+
}
|
|
10276
|
+
} : prev);
|
|
10134
10277
|
},
|
|
10135
10278
|
applyToSession: applyModelToSession,
|
|
10136
10279
|
log: (message) => console.log(message),
|
|
@@ -10155,6 +10298,28 @@ function CliApp() {
|
|
|
10155
10298
|
}
|
|
10156
10299
|
});
|
|
10157
10300
|
}
|
|
10301
|
+
if (state.folderTrustPrompt) return /* @__PURE__ */ React.createElement(FolderTrustPrompt, {
|
|
10302
|
+
projectRoot: state.folderTrustPrompt.projectRoot,
|
|
10303
|
+
onSelect: (choice) => {
|
|
10304
|
+
(async () => {
|
|
10305
|
+
try {
|
|
10306
|
+
if (choice === "trust") {
|
|
10307
|
+
await state.configStore.trustProject();
|
|
10308
|
+
console.log("\n✅ Folder trusted. Loading its config, agents, skills and MCP servers.\n");
|
|
10309
|
+
} else console.log("\nℹ️ Project config stays inert this session. Use /trust folder to trust it later.\n");
|
|
10310
|
+
} finally {
|
|
10311
|
+
setState((prev) => ({
|
|
10312
|
+
...prev,
|
|
10313
|
+
folderTrustPrompt: null
|
|
10314
|
+
}));
|
|
10315
|
+
init().catch((err) => {
|
|
10316
|
+
console.error("\n❌ Initialization failed:", err instanceof Error ? err.message : String(err), "\n");
|
|
10317
|
+
exit();
|
|
10318
|
+
});
|
|
10319
|
+
}
|
|
10320
|
+
})();
|
|
10321
|
+
}
|
|
10322
|
+
});
|
|
10158
10323
|
const currentSession = useCliStore.getState().session;
|
|
10159
10324
|
if (state.rewindSelector && currentSession) return /* @__PURE__ */ React.createElement(RewindSelector, {
|
|
10160
10325
|
messages: currentSession.messages,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { realpathSync } from "fs";
|
|
2
|
+
import { readlinkSync, realpathSync } from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
//#region ../../b4m-core/services/dist/pathValidation-
|
|
4
|
+
//#region ../../b4m-core/services/dist/pathValidation-BRqf4HFX.mjs
|
|
5
5
|
/**
|
|
6
6
|
* Resolves a path to its canonical form, following symlinks.
|
|
7
7
|
* If the path doesn't exist (e.g., file being created), resolves the
|
|
@@ -10,7 +10,11 @@ import path from "path";
|
|
|
10
10
|
function resolveRealPath(filePath) {
|
|
11
11
|
try {
|
|
12
12
|
return realpathSync(filePath);
|
|
13
|
-
} catch {
|
|
13
|
+
} catch (err) {
|
|
14
|
+
if (err?.code === "ENOENT") try {
|
|
15
|
+
const linkTarget = readlinkSync(filePath);
|
|
16
|
+
return resolveRealPath(path.isAbsolute(linkTarget) ? linkTarget : path.resolve(path.dirname(filePath), linkTarget));
|
|
17
|
+
} catch {}
|
|
14
18
|
const parentDir = path.dirname(filePath);
|
|
15
19
|
const basename = path.basename(filePath);
|
|
16
20
|
if (parentDir === filePath) return filePath;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { t as ApiClient } from "./ApiClient-
|
|
2
|
+
import { J as PROMPT_TEXT_MAX, _ as AGENT_QUEST_MCP_URI, f as parseApiUrl, g as AGENT_QUEST_MANIFEST, h as AGENT_QUEST_ID, n as logger, p as requireApiUrl, t as ConfigStore } from "./ConfigStore-DdHHCH2t.mjs";
|
|
3
|
+
import { t as ApiClient } from "./ApiClient-BOWpVvTq.mjs";
|
|
4
4
|
import { z as z$1 } from "zod";
|
|
5
5
|
import { isAxiosError } from "axios";
|
|
6
6
|
import { Writable } from "node:stream";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"mcpName": "io.github.bike4mind/bike4mind",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
@@ -56,57 +56,57 @@
|
|
|
56
56
|
"@smithy/node-http-handler": "^4.9.3",
|
|
57
57
|
"async-mutex": "^0.5.0",
|
|
58
58
|
"axios": "1.18.0",
|
|
59
|
-
"bcryptjs": "^3.0.
|
|
60
|
-
"better-sqlite3": "^13.0.
|
|
59
|
+
"bcryptjs": "^3.0.3",
|
|
60
|
+
"better-sqlite3": "^13.0.3",
|
|
61
61
|
"cheerio": "1.2.0",
|
|
62
|
-
"chess.js": "^1.
|
|
62
|
+
"chess.js": "^1.4.0",
|
|
63
63
|
"cli-highlight": "^2.1.11",
|
|
64
|
-
"csv-parse": "^7.0.
|
|
65
|
-
"dayjs": "^1.11.
|
|
64
|
+
"csv-parse": "^7.0.2",
|
|
65
|
+
"dayjs": "^1.11.23",
|
|
66
66
|
"diff": "^9.0.0",
|
|
67
67
|
"dotenv": "^17.4.2",
|
|
68
68
|
"eventsource-parser": "^3.1.0",
|
|
69
69
|
"fdir": "^6.5.0",
|
|
70
|
-
"file-type": "^22.0
|
|
71
|
-
"fuse.js": "^7.
|
|
70
|
+
"file-type": "^22.1.0",
|
|
71
|
+
"fuse.js": "^7.5.0",
|
|
72
72
|
"fzf": "^0.5.2",
|
|
73
73
|
"glob": "^13.0.6",
|
|
74
74
|
"gray-matter": "^4.0.3",
|
|
75
|
-
"ignore": "^7.0.
|
|
76
|
-
"ink": "^7.1.
|
|
75
|
+
"ignore": "^7.0.9",
|
|
76
|
+
"ink": "^7.1.1",
|
|
77
77
|
"ink-select-input": "^6.2.0",
|
|
78
78
|
"ink-spinner": "^5.0.0",
|
|
79
79
|
"ink-text-input": "^6.0.0",
|
|
80
80
|
"jsonwebtoken": "^9.0.3",
|
|
81
|
-
"jszip": "^3.10.
|
|
81
|
+
"jszip": "^3.10.2",
|
|
82
82
|
"lodash": "^4.18.1",
|
|
83
|
-
"mammoth": "^1.12.
|
|
83
|
+
"mammoth": "^1.12.3",
|
|
84
84
|
"marked": "^15.0.11",
|
|
85
85
|
"mathjs": "^15.2.0",
|
|
86
86
|
"mime-types": "^3.0.2",
|
|
87
87
|
"mongoose": "^8.24.1",
|
|
88
88
|
"ollama": "^0.6.3",
|
|
89
|
-
"open": "^11.0.
|
|
89
|
+
"open": "^11.0.4",
|
|
90
90
|
"openai": "^6.46.0",
|
|
91
|
-
"p-limit": "^7.3.
|
|
92
|
-
"picomatch": "^4.0.
|
|
91
|
+
"p-limit": "^7.3.2",
|
|
92
|
+
"picomatch": "^4.0.7",
|
|
93
93
|
"qrcode": "^1.5.4",
|
|
94
94
|
"react": "^19.2.7",
|
|
95
|
-
"sharp": "^0.35.
|
|
95
|
+
"sharp": "^0.35.4",
|
|
96
96
|
"shell-quote": "^1.10.0",
|
|
97
97
|
"speakeasy": "^2.0.0",
|
|
98
98
|
"tiktoken": "^1.0.22",
|
|
99
|
-
"tldts": "^7.4.
|
|
99
|
+
"tldts": "^7.4.13",
|
|
100
100
|
"tree-sitter-wasms": "^0.1.13",
|
|
101
101
|
"turndown": "^7.2.4",
|
|
102
102
|
"undici": "^7.29.0",
|
|
103
103
|
"unpdf": "^1.6.2",
|
|
104
|
-
"uuid": "^14.0.
|
|
104
|
+
"uuid": "^14.0.2",
|
|
105
105
|
"voyageai": "^0.4.0",
|
|
106
106
|
"web-tree-sitter": "0.25.10",
|
|
107
|
-
"ws": "^8.21.
|
|
107
|
+
"ws": "^8.21.3",
|
|
108
108
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
109
|
-
"yargs": "^18.
|
|
109
|
+
"yargs": "^18.1.0",
|
|
110
110
|
"yauzl": "^3.4.0",
|
|
111
111
|
"zod": "^4.4.3",
|
|
112
112
|
"zod-validation-error": "^5.0.0",
|
|
@@ -126,15 +126,15 @@
|
|
|
126
126
|
"tsx": "^4.23.0",
|
|
127
127
|
"typescript": "^5.9.3",
|
|
128
128
|
"vitest": "^4.1.10",
|
|
129
|
-
"@bike4mind/agents": "
|
|
130
|
-
"@bike4mind/common": "
|
|
131
|
-
"@bike4mind/fab-pipeline": "
|
|
129
|
+
"@bike4mind/agents": "0.0.0-snapshot-changeset-release-main-20260922072433",
|
|
130
|
+
"@bike4mind/common": "0.0.0-snapshot-changeset-release-main-20260922072433",
|
|
131
|
+
"@bike4mind/fab-pipeline": "0.0.0-snapshot-changeset-release-main-20260922072433",
|
|
132
132
|
"@bike4mind/hearth": "0.3.0",
|
|
133
|
-
"@bike4mind/llm-adapters": "0.
|
|
134
|
-
"@bike4mind/mcp": "
|
|
135
|
-
"@bike4mind/observability": "0.2.
|
|
136
|
-
"@bike4mind/services": "
|
|
137
|
-
"@bike4mind/utils": "
|
|
133
|
+
"@bike4mind/llm-adapters": "0.0.0-snapshot-changeset-release-main-20260922072433",
|
|
134
|
+
"@bike4mind/mcp": "0.0.0-snapshot-changeset-release-main-20260922072433",
|
|
135
|
+
"@bike4mind/observability": "0.2.1",
|
|
136
|
+
"@bike4mind/services": "0.0.0-snapshot-changeset-release-main-20260922072433",
|
|
137
|
+
"@bike4mind/utils": "0.0.0-snapshot-changeset-release-main-20260922072433"
|
|
138
138
|
},
|
|
139
139
|
"optionalDependencies": {
|
|
140
140
|
"@vscode/ripgrep": "^1.18.0"
|
package/dist/types-CqscS34o.mjs
DELETED