@buildautomaton/cli 0.1.35 → 0.1.37
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/cli.js +409 -112
- package/dist/cli.js.map +4 -4
- package/dist/index.js +403 -106
- package/dist/index.js.map +4 -4
- package/dist/migrations/003_file_index_parent_paths.sql +17 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -974,7 +974,7 @@ var require_command = __commonJS({
|
|
|
974
974
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
975
975
|
var childProcess2 = __require("node:child_process");
|
|
976
976
|
var path43 = __require("node:path");
|
|
977
|
-
var
|
|
977
|
+
var fs41 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1907,10 +1907,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1907
1907
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1908
1908
|
function findFile(baseDir, baseName) {
|
|
1909
1909
|
const localBin = path43.resolve(baseDir, baseName);
|
|
1910
|
-
if (
|
|
1910
|
+
if (fs41.existsSync(localBin)) return localBin;
|
|
1911
1911
|
if (sourceExt.includes(path43.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs41.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
1915
1915
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1916
1916
|
return void 0;
|
|
@@ -1922,7 +1922,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
if (this._scriptPath) {
|
|
1923
1923
|
let resolvedScriptPath;
|
|
1924
1924
|
try {
|
|
1925
|
-
resolvedScriptPath =
|
|
1925
|
+
resolvedScriptPath = fs41.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
@@ -25064,14 +25064,14 @@ var {
|
|
|
25064
25064
|
} = import_index.default;
|
|
25065
25065
|
|
|
25066
25066
|
// src/cli-version.ts
|
|
25067
|
-
var CLI_VERSION = "0.1.
|
|
25067
|
+
var CLI_VERSION = "0.1.37".length > 0 ? "0.1.37" : "0.0.0-dev";
|
|
25068
25068
|
|
|
25069
25069
|
// src/cli/defaults.ts
|
|
25070
25070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25071
25071
|
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25072
25072
|
|
|
25073
25073
|
// src/cli/run-cli-action.ts
|
|
25074
|
-
import * as
|
|
25074
|
+
import * as fs40 from "node:fs";
|
|
25075
25075
|
import * as path42 from "node:path";
|
|
25076
25076
|
|
|
25077
25077
|
// src/cli-log-level.ts
|
|
@@ -26961,6 +26961,7 @@ function recordMigrationAndPruneCheckpointLegacy(db, migration, applied2) {
|
|
|
26961
26961
|
var CHECKPOINT_V1 = "001_cli_sqlite_checkpoint_v1";
|
|
26962
26962
|
var CHECKPOINT_V1_SQL = readCliSqliteMigrationSql("001_cli_sqlite_checkpoint_v1.sql");
|
|
26963
26963
|
var AGENT_CAPABILITIES_SQL = readCliSqliteMigrationSql("002_agent_capabilities.sql");
|
|
26964
|
+
var FILE_INDEX_PARENT_PATHS_SQL = readCliSqliteMigrationSql("003_file_index_parent_paths.sql");
|
|
26964
26965
|
function agentCapabilitiesTableState(db) {
|
|
26965
26966
|
const rows = db.all(
|
|
26966
26967
|
`SELECT name FROM sqlite_master WHERE type='table' AND name IN ('agent_capabilities', 'agent_capability_cache')`
|
|
@@ -26994,6 +26995,18 @@ var CLI_SQLITE_MIGRATIONS = [
|
|
|
26994
26995
|
db.exec(AGENT_CAPABILITIES_SQL);
|
|
26995
26996
|
},
|
|
26996
26997
|
alreadyApplied: (db) => agentCapabilitiesTableState(db) === "current"
|
|
26998
|
+
},
|
|
26999
|
+
{
|
|
27000
|
+
name: "003_file_index_parent_paths",
|
|
27001
|
+
migrate: (db) => {
|
|
27002
|
+
db.exec(FILE_INDEX_PARENT_PATHS_SQL);
|
|
27003
|
+
},
|
|
27004
|
+
alreadyApplied: (db) => {
|
|
27005
|
+
const row = db.get(
|
|
27006
|
+
`SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='file_index_parent_path' LIMIT 1`
|
|
27007
|
+
);
|
|
27008
|
+
return row != null;
|
|
27009
|
+
}
|
|
26997
27010
|
}
|
|
26998
27011
|
];
|
|
26999
27012
|
function migrateCliSqlite(db) {
|
|
@@ -27032,6 +27045,10 @@ var CliSqliteInterrupted = class extends Error {
|
|
|
27032
27045
|
}
|
|
27033
27046
|
};
|
|
27034
27047
|
function applyCliSqliteConcurrencyPragmas(db) {
|
|
27048
|
+
try {
|
|
27049
|
+
db.run("PRAGMA foreign_keys = ON");
|
|
27050
|
+
} catch {
|
|
27051
|
+
}
|
|
27035
27052
|
try {
|
|
27036
27053
|
db.exec("PRAGMA journal_mode = WAL");
|
|
27037
27054
|
} catch {
|
|
@@ -27694,6 +27711,16 @@ function isClaudeCodePermissionMode(value) {
|
|
|
27694
27711
|
return MODE_SET.has(value);
|
|
27695
27712
|
}
|
|
27696
27713
|
|
|
27714
|
+
// ../types/src/codex-permission-mode.ts
|
|
27715
|
+
function isCodexPermissionMode(value) {
|
|
27716
|
+
return value.trim() !== "";
|
|
27717
|
+
}
|
|
27718
|
+
function normalizeCodexPermissionModeInput(raw) {
|
|
27719
|
+
if (typeof raw !== "string") return null;
|
|
27720
|
+
const t = raw.trim();
|
|
27721
|
+
return isCodexPermissionMode(t) ? t : null;
|
|
27722
|
+
}
|
|
27723
|
+
|
|
27697
27724
|
// ../types/src/cli-permission-mode.ts
|
|
27698
27725
|
var CLI_PERMISSION_MODE_DEFAULT = "default";
|
|
27699
27726
|
var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
|
|
@@ -27765,6 +27792,7 @@ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
|
|
|
27765
27792
|
// ../types/src/agent-config.ts
|
|
27766
27793
|
var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
|
|
27767
27794
|
var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
|
|
27795
|
+
var AGENT_CONFIG_CODEX_PERMISSION_MODE_KEY = "codex_permission_mode";
|
|
27768
27796
|
var AGENT_CONFIG_AGENT_MODEL_KEY = "agent_model";
|
|
27769
27797
|
function getClaudePermissionModeFromAgentConfig(config2) {
|
|
27770
27798
|
if (!config2) return null;
|
|
@@ -27777,6 +27805,10 @@ function getCliPermissionModeFromAgentConfig(config2) {
|
|
|
27777
27805
|
if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
|
|
27778
27806
|
return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
|
|
27779
27807
|
}
|
|
27808
|
+
function getCodexPermissionModeFromAgentConfig(config2) {
|
|
27809
|
+
if (!config2) return null;
|
|
27810
|
+
return normalizeCodexPermissionModeInput(config2[AGENT_CONFIG_CODEX_PERMISSION_MODE_KEY]);
|
|
27811
|
+
}
|
|
27780
27812
|
function getAgentModelFromAgentConfig(config2) {
|
|
27781
27813
|
if (!config2) return null;
|
|
27782
27814
|
const cur = config2[AGENT_CONFIG_AGENT_MODEL_KEY];
|
|
@@ -33377,8 +33409,60 @@ async function applyClaudePermissionFromAcpSession(params) {
|
|
|
33377
33409
|
}
|
|
33378
33410
|
}
|
|
33379
33411
|
|
|
33380
|
-
// src/agents/acp/
|
|
33412
|
+
// src/agents/acp/codex-acp-permission-from-session.ts
|
|
33381
33413
|
function flattenSelectOptions2(options) {
|
|
33414
|
+
if (options == null || options.length === 0) return [];
|
|
33415
|
+
const first2 = options[0];
|
|
33416
|
+
if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
|
|
33417
|
+
return options.flatMap(
|
|
33418
|
+
(g) => Array.isArray(g.options) ? g.options : []
|
|
33419
|
+
);
|
|
33420
|
+
}
|
|
33421
|
+
return options;
|
|
33422
|
+
}
|
|
33423
|
+
function pickModeConfigOption2(configOptions) {
|
|
33424
|
+
if (configOptions == null || configOptions.length === 0) return null;
|
|
33425
|
+
const byCategory = configOptions.find((o) => o.category === "mode");
|
|
33426
|
+
if (byCategory) return byCategory;
|
|
33427
|
+
return configOptions.find((o) => o.id === "mode") ?? null;
|
|
33428
|
+
}
|
|
33429
|
+
async function applyCodexPermissionFromAcpSession(params) {
|
|
33430
|
+
const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
|
|
33431
|
+
const desiredMode = getCodexPermissionModeFromAgentConfig(agentConfig);
|
|
33432
|
+
if (desiredMode == null) return;
|
|
33433
|
+
const modeOpt = pickModeConfigOption2(configOptions ?? null);
|
|
33434
|
+
if (modeOpt != null) {
|
|
33435
|
+
const flat = flattenSelectOptions2(modeOpt.options);
|
|
33436
|
+
const allowed = flat.some((o) => o.value === desiredMode);
|
|
33437
|
+
if (allowed && modeOpt.currentValue !== desiredMode) {
|
|
33438
|
+
try {
|
|
33439
|
+
logDebug2(
|
|
33440
|
+
`[Agent] Codex: sending ACP session/set_config_option (mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
33441
|
+
);
|
|
33442
|
+
await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
|
|
33443
|
+
} catch (e) {
|
|
33444
|
+
logDebug2(`[Agent] Codex: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
33445
|
+
}
|
|
33446
|
+
}
|
|
33447
|
+
return;
|
|
33448
|
+
}
|
|
33449
|
+
if (modes?.availableModes?.length) {
|
|
33450
|
+
const allowed = modes.availableModes.some((m) => m.id === desiredMode);
|
|
33451
|
+
if (allowed && desiredMode !== modes.currentModeId) {
|
|
33452
|
+
try {
|
|
33453
|
+
logDebug2(
|
|
33454
|
+
`[Agent] Codex: sending ACP session/set_mode modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
33455
|
+
);
|
|
33456
|
+
await setSessionMode({ sessionId, modeId: desiredMode });
|
|
33457
|
+
} catch (e) {
|
|
33458
|
+
logDebug2(`[Agent] Codex: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
33459
|
+
}
|
|
33460
|
+
}
|
|
33461
|
+
}
|
|
33462
|
+
}
|
|
33463
|
+
|
|
33464
|
+
// src/agents/acp/apply-acp-model-from-agent-session.ts
|
|
33465
|
+
function flattenSelectOptions3(options) {
|
|
33382
33466
|
if (options == null || options.length === 0) return [];
|
|
33383
33467
|
const first2 = options[0];
|
|
33384
33468
|
if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
|
|
@@ -33403,7 +33487,7 @@ async function applyAcpModelFromAcpSession(params) {
|
|
|
33403
33487
|
if (desired == null) return;
|
|
33404
33488
|
const modelOpt = pickModelConfigOption(configOptions ?? null);
|
|
33405
33489
|
if (modelOpt == null) return;
|
|
33406
|
-
const flat =
|
|
33490
|
+
const flat = flattenSelectOptions3(modelOpt.options);
|
|
33407
33491
|
const allowed = flat.some((o) => o.value === desired);
|
|
33408
33492
|
if (!allowed) return;
|
|
33409
33493
|
if (modelOpt.currentValue === desired) return;
|
|
@@ -33483,12 +33567,41 @@ function parseAcpInitAgentCapabilities(initResult) {
|
|
|
33483
33567
|
}
|
|
33484
33568
|
|
|
33485
33569
|
// src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
|
|
33570
|
+
function configOptionsWithModes(configOptions, modes) {
|
|
33571
|
+
const modeState = modes && typeof modes === "object" ? modes : null;
|
|
33572
|
+
if (!modeState?.availableModes?.length) return configOptions;
|
|
33573
|
+
const hasModeConfig = Array.isArray(configOptions) && configOptions.some((raw) => {
|
|
33574
|
+
if (raw == null || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
33575
|
+
const o = raw;
|
|
33576
|
+
return o.category === "mode" || o.id === "mode";
|
|
33577
|
+
});
|
|
33578
|
+
if (hasModeConfig) return configOptions;
|
|
33579
|
+
return [
|
|
33580
|
+
...configOptions ?? [],
|
|
33581
|
+
{
|
|
33582
|
+
id: "mode",
|
|
33583
|
+
name: "Mode",
|
|
33584
|
+
type: "select",
|
|
33585
|
+
category: "mode",
|
|
33586
|
+
currentValue: modeState.currentModeId ?? null,
|
|
33587
|
+
options: modeState.availableModes.map((m) => {
|
|
33588
|
+
const r = m;
|
|
33589
|
+
return {
|
|
33590
|
+
value: m.id,
|
|
33591
|
+
name: m.name ?? m.id,
|
|
33592
|
+
...typeof r.description === "string" && r.description.trim() !== "" ? { description: r.description.trim() } : {}
|
|
33593
|
+
};
|
|
33594
|
+
})
|
|
33595
|
+
}
|
|
33596
|
+
];
|
|
33597
|
+
}
|
|
33486
33598
|
async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
33487
33599
|
const initResult = await transport.initialize(initializeRequest);
|
|
33488
33600
|
const { canResume, canLoad, promptSupportsImage } = parseAcpInitAgentCapabilities(initResult);
|
|
33489
33601
|
ctx.agentPromptImageSupported = promptSupportsImage;
|
|
33490
33602
|
await transport.afterInitialize?.();
|
|
33491
33603
|
const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
|
|
33604
|
+
established.configOptions = configOptionsWithModes(established.configOptions, established.modes);
|
|
33492
33605
|
const sessionId = established.sessionId;
|
|
33493
33606
|
ctx.onAcpSessionEstablished?.({
|
|
33494
33607
|
acpSessionId: sessionId,
|
|
@@ -33511,6 +33624,22 @@ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
|
33511
33624
|
logDebug: ctx.logDebug
|
|
33512
33625
|
});
|
|
33513
33626
|
}
|
|
33627
|
+
if (ctx.backendAgentType === "codex-acp") {
|
|
33628
|
+
const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
|
|
33629
|
+
const configOptionsTyped = established.configOptions;
|
|
33630
|
+
const modesTyped = established.modes;
|
|
33631
|
+
await applyCodexPermissionFromAcpSession({
|
|
33632
|
+
sessionId,
|
|
33633
|
+
agentConfig: cfg,
|
|
33634
|
+
configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
|
|
33635
|
+
modes: modesTyped,
|
|
33636
|
+
setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
|
|
33637
|
+
},
|
|
33638
|
+
setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
|
|
33639
|
+
},
|
|
33640
|
+
logDebug: ctx.logDebug
|
|
33641
|
+
});
|
|
33642
|
+
}
|
|
33514
33643
|
const cfgAll = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
|
|
33515
33644
|
const configOptionsForModel = established.configOptions;
|
|
33516
33645
|
if (transport.setSessionConfigOption) {
|
|
@@ -33883,13 +34012,18 @@ function isCodexAcpCommand(command) {
|
|
|
33883
34012
|
const i = command.indexOf("@zed-industries/codex-acp");
|
|
33884
34013
|
return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
|
|
33885
34014
|
}
|
|
33886
|
-
function buildCodexAcpSpawnCommand(base, _sessionMode) {
|
|
34015
|
+
function buildCodexAcpSpawnCommand(base, _sessionMode, _agentConfig) {
|
|
33887
34016
|
return [...base];
|
|
33888
34017
|
}
|
|
33889
34018
|
async function createCodexAcpClient(options) {
|
|
33890
34019
|
const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
|
|
33891
|
-
const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
|
|
33892
|
-
return createSdkStdioAcpClient({
|
|
34020
|
+
const command = buildCodexAcpSpawnCommand(base, options.sessionMode, options.agentConfig);
|
|
34021
|
+
return createSdkStdioAcpClient({
|
|
34022
|
+
...options,
|
|
34023
|
+
command,
|
|
34024
|
+
/** Codex ACP can ignore `session/cancel`; mirror Claude Code's subprocess fallback. */
|
|
34025
|
+
killSubprocessAfterCancelMs: options.killSubprocessAfterCancelMs ?? 2500
|
|
34026
|
+
});
|
|
33893
34027
|
}
|
|
33894
34028
|
|
|
33895
34029
|
// src/agents/acp/clients/cursor/cursor-acp-client.ts
|
|
@@ -34287,7 +34421,7 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
34287
34421
|
command,
|
|
34288
34422
|
label: preferredAgentType,
|
|
34289
34423
|
createClient: createCodexAcpClient,
|
|
34290
|
-
spawnCommandForSession: (sessionMode,
|
|
34424
|
+
spawnCommandForSession: (sessionMode, agentConfig) => buildCodexAcpSpawnCommand(command, sessionMode, agentConfig)
|
|
34291
34425
|
};
|
|
34292
34426
|
}
|
|
34293
34427
|
if (useKiroAcp(preferredAgentType, command)) {
|
|
@@ -36743,8 +36877,18 @@ import path29 from "node:path";
|
|
|
36743
36877
|
// src/files/index/walk-workspace-tree.ts
|
|
36744
36878
|
import fs25 from "node:fs";
|
|
36745
36879
|
import path28 from "node:path";
|
|
36880
|
+
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
36881
|
+
"node_modules",
|
|
36882
|
+
"bower_components",
|
|
36883
|
+
"vendor",
|
|
36884
|
+
"Pods",
|
|
36885
|
+
"Carthage",
|
|
36886
|
+
"DerivedData",
|
|
36887
|
+
".yarn",
|
|
36888
|
+
".pnpm-store"
|
|
36889
|
+
]);
|
|
36746
36890
|
function shouldSkipWorkspaceWalkEntry(name) {
|
|
36747
|
-
return
|
|
36891
|
+
return DEPENDENCY_INSTALL_DIR_NAMES.has(name);
|
|
36748
36892
|
}
|
|
36749
36893
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
36750
36894
|
let names;
|
|
@@ -36815,14 +36959,26 @@ var FILE_INDEX_INTERRUPT_CHECK_EVERY = 256;
|
|
|
36815
36959
|
function assertNotShutdown() {
|
|
36816
36960
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
36817
36961
|
}
|
|
36962
|
+
function upsertFileIndexParentPath(db, resolved) {
|
|
36963
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36964
|
+
db.run(
|
|
36965
|
+
`INSERT INTO file_index_parent_path (path, path_hash, updated_at)
|
|
36966
|
+
VALUES (?, ?, ?)
|
|
36967
|
+
ON CONFLICT(path) DO UPDATE SET path_hash = excluded.path_hash, updated_at = excluded.updated_at`,
|
|
36968
|
+
[resolved, getCwdHashForFileIndex(resolved), now]
|
|
36969
|
+
);
|
|
36970
|
+
const row = db.get("SELECT id FROM file_index_parent_path WHERE path = ?", [resolved]);
|
|
36971
|
+
if (row == null) throw new Error(`Failed to upsert file index parent path: ${resolved}`);
|
|
36972
|
+
return Number(row.id);
|
|
36973
|
+
}
|
|
36818
36974
|
function persistFileIndexPaths(resolved, paths) {
|
|
36819
36975
|
return withCliSqliteSync((db) => {
|
|
36820
|
-
const h = getCwdHashForFileIndex(resolved);
|
|
36821
36976
|
let pathCount = 0;
|
|
36822
36977
|
db.run("BEGIN IMMEDIATE");
|
|
36823
36978
|
try {
|
|
36824
|
-
|
|
36825
|
-
|
|
36979
|
+
const parentId = upsertFileIndexParentPath(db, resolved);
|
|
36980
|
+
db.run("DELETE FROM file_index_child_path WHERE parent_id = ?", [parentId]);
|
|
36981
|
+
const ins = db.prepare("INSERT INTO file_index_child_path (parent_id, path) VALUES (?, ?)");
|
|
36826
36982
|
try {
|
|
36827
36983
|
let batch = 0;
|
|
36828
36984
|
for (const rel of paths) {
|
|
@@ -36830,7 +36986,7 @@ function persistFileIndexPaths(resolved, paths) {
|
|
|
36830
36986
|
batch = 0;
|
|
36831
36987
|
assertNotShutdown();
|
|
36832
36988
|
}
|
|
36833
|
-
ins.run([
|
|
36989
|
+
ins.run([parentId, rel]);
|
|
36834
36990
|
pathCount += 1;
|
|
36835
36991
|
}
|
|
36836
36992
|
} finally {
|
|
@@ -36872,36 +37028,38 @@ async function buildFileIndexAsync(cwd) {
|
|
|
36872
37028
|
// src/files/index/ensure-file-index.ts
|
|
36873
37029
|
import path30 from "node:path";
|
|
36874
37030
|
|
|
36875
|
-
// src/files/index/file-index-dependency-path.ts
|
|
36876
|
-
function sqliteExprBridgeFileIndexDependencyRank() {
|
|
36877
|
-
return `CASE WHEN lower(path) = 'node_modules' OR lower(path) LIKE 'node_modules/%' OR lower(path) LIKE '%/node_modules/%' OR lower(path) = 'bower_components' OR lower(path) LIKE 'bower_components/%' OR lower(path) LIKE '%/bower_components/%' THEN 1 ELSE 0 END`;
|
|
36878
|
-
}
|
|
36879
|
-
|
|
36880
37031
|
// src/files/index/search-file-index.ts
|
|
36881
37032
|
function escapeLikePattern(fragment) {
|
|
36882
37033
|
return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
36883
37034
|
}
|
|
36884
37035
|
function bridgeFileIndexIsPopulatedWithDb(resolvedCwd, db) {
|
|
36885
|
-
const
|
|
36886
|
-
const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
|
|
37036
|
+
const row = db.get("SELECT 1 as ok FROM file_index_parent_path WHERE path = ? LIMIT 1", [resolvedCwd]);
|
|
36887
37037
|
return row != null;
|
|
36888
37038
|
}
|
|
36889
37039
|
function bridgeFileIndexPathCountWithDb(resolvedCwd, db) {
|
|
36890
|
-
const
|
|
36891
|
-
|
|
37040
|
+
const row = db.get(
|
|
37041
|
+
`SELECT COUNT(*) as c
|
|
37042
|
+
FROM file_index_child_path child
|
|
37043
|
+
JOIN file_index_parent_path parent ON parent.id = child.parent_id
|
|
37044
|
+
WHERE parent.path = ?`,
|
|
37045
|
+
[resolvedCwd]
|
|
37046
|
+
);
|
|
36892
37047
|
const c = row?.c ?? 0;
|
|
36893
37048
|
return Number(c);
|
|
36894
37049
|
}
|
|
36895
37050
|
function searchBridgeFilePathsWithDb(resolvedCwd, query, limit, db) {
|
|
36896
37051
|
const q = query.trim().toLowerCase();
|
|
36897
37052
|
if (!q) return [];
|
|
36898
|
-
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
36899
37053
|
const pattern = `%${escapeLikePattern(q)}%`;
|
|
36900
37054
|
const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
|
|
36901
|
-
const depRank = sqliteExprBridgeFileIndexDependencyRank();
|
|
36902
37055
|
const rows = db.all(
|
|
36903
|
-
`SELECT path
|
|
36904
|
-
|
|
37056
|
+
`SELECT child.path
|
|
37057
|
+
FROM file_index_child_path child
|
|
37058
|
+
JOIN file_index_parent_path parent ON parent.id = child.parent_id
|
|
37059
|
+
WHERE parent.path = ? AND lower(child.path) LIKE ? ESCAPE '\\'
|
|
37060
|
+
ORDER BY child.path
|
|
37061
|
+
LIMIT ?`,
|
|
37062
|
+
[resolvedCwd, pattern, lim]
|
|
36905
37063
|
);
|
|
36906
37064
|
return rows.map((r) => String(r.path));
|
|
36907
37065
|
}
|
|
@@ -36931,9 +37089,7 @@ async function ensureFileIndexAsync(cwd) {
|
|
|
36931
37089
|
var DEBOUNCE_MS = 900;
|
|
36932
37090
|
function shouldIgnoreRelative(rel) {
|
|
36933
37091
|
const n = rel.replace(/\\/g, "/");
|
|
36934
|
-
|
|
36935
|
-
if (n.includes("/.buildautomaton/") || n.startsWith(".buildautomaton/")) return true;
|
|
36936
|
-
return false;
|
|
37092
|
+
return n.split("/").some((segment) => shouldSkipWorkspaceWalkEntry(segment));
|
|
36937
37093
|
}
|
|
36938
37094
|
function attachWatchErrorLog(w) {
|
|
36939
37095
|
w.on("error", (err) => {
|
|
@@ -39318,9 +39474,8 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
39318
39474
|
);
|
|
39319
39475
|
};
|
|
39320
39476
|
|
|
39321
|
-
// src/files/list-dir.ts
|
|
39322
|
-
import
|
|
39323
|
-
import path36 from "node:path";
|
|
39477
|
+
// src/files/list-dir/index.ts
|
|
39478
|
+
import fs34 from "node:fs";
|
|
39324
39479
|
|
|
39325
39480
|
// src/files/ensure-under-cwd.ts
|
|
39326
39481
|
import path35 from "node:path";
|
|
@@ -39333,71 +39488,93 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
39333
39488
|
return resolved;
|
|
39334
39489
|
}
|
|
39335
39490
|
|
|
39336
|
-
// src/files/list-dir.ts
|
|
39491
|
+
// src/files/list-dir/types.ts
|
|
39337
39492
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
39338
|
-
|
|
39339
|
-
|
|
39493
|
+
|
|
39494
|
+
// src/files/list-dir/map-dir-entry.ts
|
|
39495
|
+
import path36 from "node:path";
|
|
39496
|
+
import fs33 from "node:fs";
|
|
39497
|
+
async function mapDirEntry(d, relativePath, resolved) {
|
|
39498
|
+
const entryPath = path36.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
39499
|
+
const fullPath = path36.join(resolved, d.name);
|
|
39500
|
+
let isDir = d.isDirectory();
|
|
39501
|
+
if (d.isSymbolicLink()) {
|
|
39502
|
+
try {
|
|
39503
|
+
const targetStat = await fs33.promises.stat(fullPath);
|
|
39504
|
+
isDir = targetStat.isDirectory();
|
|
39505
|
+
} catch {
|
|
39506
|
+
isDir = false;
|
|
39507
|
+
}
|
|
39508
|
+
}
|
|
39509
|
+
return {
|
|
39510
|
+
name: d.name,
|
|
39511
|
+
path: entryPath,
|
|
39512
|
+
isDir,
|
|
39513
|
+
isSymlink: d.isSymbolicLink()
|
|
39514
|
+
};
|
|
39515
|
+
}
|
|
39516
|
+
|
|
39517
|
+
// src/files/list-dir/sort-entries.ts
|
|
39518
|
+
function sortListEntries(entries) {
|
|
39519
|
+
return entries.sort((a, b) => {
|
|
39520
|
+
if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
|
|
39521
|
+
return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
39522
|
+
});
|
|
39523
|
+
}
|
|
39524
|
+
|
|
39525
|
+
// src/files/list-dir/index.ts
|
|
39526
|
+
async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
39527
|
+
await yieldToEventLoop();
|
|
39528
|
+
const resolved = ensureUnderCwd(relativePath || ".", sessionParentPath);
|
|
39340
39529
|
if (!resolved) {
|
|
39341
39530
|
return { error: "Path is outside working directory" };
|
|
39342
39531
|
}
|
|
39343
39532
|
try {
|
|
39344
|
-
const names = await
|
|
39345
|
-
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
39533
|
+
const names = await fs34.promises.readdir(resolved, { withFileTypes: true });
|
|
39346
39534
|
const entries = [];
|
|
39347
|
-
for (let i = 0; i <
|
|
39535
|
+
for (let i = 0; i < names.length; i++) {
|
|
39348
39536
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
39349
39537
|
await yieldToEventLoop();
|
|
39350
39538
|
}
|
|
39351
|
-
|
|
39352
|
-
const entryPath = path36.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
39353
|
-
const fullPath = path36.join(resolved, d.name);
|
|
39354
|
-
let isDir = d.isDirectory();
|
|
39355
|
-
if (d.isSymbolicLink()) {
|
|
39356
|
-
try {
|
|
39357
|
-
const targetStat = await fs33.promises.stat(fullPath);
|
|
39358
|
-
isDir = targetStat.isDirectory();
|
|
39359
|
-
} catch {
|
|
39360
|
-
isDir = false;
|
|
39361
|
-
}
|
|
39362
|
-
}
|
|
39363
|
-
entries.push({
|
|
39364
|
-
name: d.name,
|
|
39365
|
-
path: entryPath,
|
|
39366
|
-
isDir,
|
|
39367
|
-
isSymlink: d.isSymbolicLink()
|
|
39368
|
-
});
|
|
39539
|
+
entries.push(await mapDirEntry(names[i], relativePath, resolved));
|
|
39369
39540
|
}
|
|
39370
|
-
entries
|
|
39371
|
-
if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
|
|
39372
|
-
return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
39373
|
-
});
|
|
39374
|
-
return { entries };
|
|
39541
|
+
return { entries: sortListEntries(entries) };
|
|
39375
39542
|
} catch (err) {
|
|
39376
39543
|
const message = err instanceof Error ? err.message : String(err);
|
|
39377
39544
|
return { error: message };
|
|
39378
39545
|
}
|
|
39379
39546
|
}
|
|
39380
39547
|
|
|
39381
|
-
// src/files/read-file.ts
|
|
39382
|
-
|
|
39383
|
-
|
|
39384
|
-
|
|
39385
|
-
|
|
39548
|
+
// src/files/read-file/types.ts
|
|
39549
|
+
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
39550
|
+
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
39551
|
+
|
|
39552
|
+
// src/files/read-file/resolve-file-path.ts
|
|
39553
|
+
import fs35 from "node:fs";
|
|
39554
|
+
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
39555
|
+
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
39386
39556
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
39387
39557
|
let real;
|
|
39388
39558
|
try {
|
|
39389
|
-
real =
|
|
39559
|
+
real = await fs35.promises.realpath(resolved);
|
|
39390
39560
|
} catch {
|
|
39391
39561
|
real = resolved;
|
|
39392
39562
|
}
|
|
39393
|
-
|
|
39394
|
-
|
|
39395
|
-
|
|
39563
|
+
try {
|
|
39564
|
+
const stat3 = await fs35.promises.stat(real);
|
|
39565
|
+
if (!stat3.isFile()) return { error: "Not a file" };
|
|
39566
|
+
return real;
|
|
39567
|
+
} catch (err) {
|
|
39568
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
39569
|
+
}
|
|
39396
39570
|
}
|
|
39397
|
-
|
|
39398
|
-
|
|
39399
|
-
|
|
39400
|
-
|
|
39571
|
+
|
|
39572
|
+
// src/files/read-file/read-file-range-async.ts
|
|
39573
|
+
import fs36 from "node:fs";
|
|
39574
|
+
import { StringDecoder } from "node:string_decoder";
|
|
39575
|
+
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
39576
|
+
const fileSize = (await fs36.promises.stat(filePath)).size;
|
|
39577
|
+
const fd = await fs36.promises.open(filePath, "r");
|
|
39401
39578
|
const bufSize = 64 * 1024;
|
|
39402
39579
|
const buf = Buffer.alloc(bufSize);
|
|
39403
39580
|
const decoder = new StringDecoder("utf8");
|
|
@@ -39408,9 +39585,18 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
39408
39585
|
let skipLine0Chars = typeof lineOffsetIn === "number" ? lineOffsetIn : 0;
|
|
39409
39586
|
let line0CharsReturned = 0;
|
|
39410
39587
|
let line0Accum = "";
|
|
39588
|
+
let bytesSinceYield = 0;
|
|
39411
39589
|
try {
|
|
39412
|
-
let
|
|
39413
|
-
while (!done
|
|
39590
|
+
let position = 0;
|
|
39591
|
+
while (!done) {
|
|
39592
|
+
const { bytesRead } = await fd.read(buf, 0, bufSize, position);
|
|
39593
|
+
if (bytesRead === 0) break;
|
|
39594
|
+
position += bytesRead;
|
|
39595
|
+
bytesSinceYield += bytesRead;
|
|
39596
|
+
if (bytesSinceYield >= READ_RANGE_YIELD_EVERY_BYTES) {
|
|
39597
|
+
await yieldToEventLoop();
|
|
39598
|
+
bytesSinceYield = 0;
|
|
39599
|
+
}
|
|
39414
39600
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
39415
39601
|
partial2 = "";
|
|
39416
39602
|
let lineStart = 0;
|
|
@@ -39545,39 +39731,132 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
39545
39731
|
}
|
|
39546
39732
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
39547
39733
|
} finally {
|
|
39548
|
-
|
|
39734
|
+
await fd.close();
|
|
39549
39735
|
}
|
|
39550
39736
|
}
|
|
39551
|
-
|
|
39737
|
+
|
|
39738
|
+
// src/files/read-file/read-file-buffer-full-async.ts
|
|
39739
|
+
import fs37 from "node:fs";
|
|
39740
|
+
var READ_CHUNK_BYTES = 256 * 1024;
|
|
39741
|
+
async function readFileBufferFullAsync(filePath) {
|
|
39742
|
+
const stat3 = await fs37.promises.stat(filePath);
|
|
39743
|
+
const fd = await fs37.promises.open(filePath, "r");
|
|
39744
|
+
const chunks = [];
|
|
39745
|
+
let position = 0;
|
|
39746
|
+
let bytesSinceYield = 0;
|
|
39552
39747
|
try {
|
|
39553
|
-
|
|
39748
|
+
while (position < stat3.size) {
|
|
39749
|
+
const buf = Buffer.alloc(Math.min(READ_CHUNK_BYTES, stat3.size - position));
|
|
39750
|
+
const { bytesRead } = await fd.read(buf, 0, buf.length, position);
|
|
39751
|
+
if (bytesRead === 0) break;
|
|
39752
|
+
chunks.push(buf.subarray(0, bytesRead));
|
|
39753
|
+
position += bytesRead;
|
|
39754
|
+
bytesSinceYield += bytesRead;
|
|
39755
|
+
if (bytesSinceYield >= READ_RANGE_YIELD_EVERY_BYTES) {
|
|
39756
|
+
await yieldToEventLoop();
|
|
39757
|
+
bytesSinceYield = 0;
|
|
39758
|
+
}
|
|
39759
|
+
}
|
|
39760
|
+
} finally {
|
|
39761
|
+
await fd.close();
|
|
39762
|
+
}
|
|
39763
|
+
return { buffer: Buffer.concat(chunks), size: stat3.size };
|
|
39764
|
+
}
|
|
39765
|
+
|
|
39766
|
+
// src/files/read-file/read-file-full-async.ts
|
|
39767
|
+
async function readFileFullAsync(filePath) {
|
|
39768
|
+
const { buffer, size } = await readFileBufferFullAsync(filePath);
|
|
39769
|
+
const raw = buffer.toString("utf8");
|
|
39770
|
+
const lines = raw.split(/\r?\n/);
|
|
39771
|
+
return { content: raw, totalLines: lines.length, size };
|
|
39772
|
+
}
|
|
39773
|
+
|
|
39774
|
+
// src/files/read-file/guess-mime-type.ts
|
|
39775
|
+
var MIME_BY_EXT = {
|
|
39776
|
+
png: "image/png",
|
|
39777
|
+
jpg: "image/jpeg",
|
|
39778
|
+
jpeg: "image/jpeg",
|
|
39779
|
+
gif: "image/gif",
|
|
39780
|
+
bmp: "image/bmp",
|
|
39781
|
+
ico: "image/x-icon",
|
|
39782
|
+
webp: "image/webp",
|
|
39783
|
+
avif: "image/avif",
|
|
39784
|
+
svg: "image/svg+xml",
|
|
39785
|
+
pdf: "application/pdf",
|
|
39786
|
+
json: "application/json",
|
|
39787
|
+
html: "text/html",
|
|
39788
|
+
htm: "text/html",
|
|
39789
|
+
css: "text/css",
|
|
39790
|
+
js: "text/javascript",
|
|
39791
|
+
mjs: "text/javascript",
|
|
39792
|
+
ts: "text/typescript",
|
|
39793
|
+
txt: "text/plain",
|
|
39794
|
+
md: "text/markdown",
|
|
39795
|
+
xml: "application/xml",
|
|
39796
|
+
zip: "application/zip",
|
|
39797
|
+
gz: "application/gzip",
|
|
39798
|
+
wasm: "application/wasm"
|
|
39799
|
+
};
|
|
39800
|
+
function guessMimeType(filePath) {
|
|
39801
|
+
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
|
|
39802
|
+
return MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
39803
|
+
}
|
|
39804
|
+
|
|
39805
|
+
// src/files/read-file/read-file-binary-full-async.ts
|
|
39806
|
+
async function readFileBinaryFullAsync(filePath) {
|
|
39807
|
+
const { buffer, size } = await readFileBufferFullAsync(filePath);
|
|
39808
|
+
return {
|
|
39809
|
+
content: buffer.toString("base64"),
|
|
39810
|
+
size,
|
|
39811
|
+
mimeType: guessMimeType(filePath)
|
|
39812
|
+
};
|
|
39813
|
+
}
|
|
39814
|
+
|
|
39815
|
+
// src/files/read-file/index.ts
|
|
39816
|
+
async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE, sessionParentPath = getBridgeRoot(), encoding = "utf8") {
|
|
39817
|
+
await yieldToEventLoop();
|
|
39818
|
+
try {
|
|
39819
|
+
const result = await resolveFilePathAsync(relativePath, sessionParentPath);
|
|
39554
39820
|
if (typeof result === "object") return result;
|
|
39821
|
+
const resolvedPath = result;
|
|
39555
39822
|
const hasRange = typeof startLine === "number" && typeof endLine === "number";
|
|
39823
|
+
if (encoding === "base64") {
|
|
39824
|
+
if (hasRange) return { error: "base64 encoding requires a full file read (no line range)" };
|
|
39825
|
+
const read2 = await readFileBinaryFullAsync(resolvedPath);
|
|
39826
|
+
return { ...read2, resolvedPath };
|
|
39827
|
+
}
|
|
39556
39828
|
if (hasRange) {
|
|
39557
|
-
return
|
|
39829
|
+
return readFileRangeAsync(resolvedPath, startLine, endLine, lineOffset, lineChunkSize);
|
|
39558
39830
|
}
|
|
39559
|
-
const
|
|
39560
|
-
|
|
39561
|
-
const lines = raw.split(/\r?\n/);
|
|
39562
|
-
return { content: raw, totalLines: lines.length, size: stat3.size };
|
|
39831
|
+
const read = await readFileFullAsync(resolvedPath);
|
|
39832
|
+
return { ...read, resolvedPath };
|
|
39563
39833
|
} catch (err) {
|
|
39564
39834
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
39565
39835
|
}
|
|
39566
39836
|
}
|
|
39567
|
-
|
|
39568
|
-
|
|
39569
|
-
|
|
39837
|
+
|
|
39838
|
+
// src/files/resolve-file-browser-session-parent.ts
|
|
39839
|
+
function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
39840
|
+
const sid = sessionId?.trim();
|
|
39841
|
+
if (sid) {
|
|
39842
|
+
sessionWorktreeManager.ensureRepoCheckoutPathsForSession(sid);
|
|
39843
|
+
const worktreeRoot = sessionWorktreeManager.getSessionWorktreeRootForSession(sid);
|
|
39844
|
+
if (worktreeRoot) return worktreeRoot;
|
|
39845
|
+
}
|
|
39846
|
+
return getBridgeRoot();
|
|
39570
39847
|
}
|
|
39571
39848
|
|
|
39572
39849
|
// src/files/handle-file-browser-search.ts
|
|
39573
39850
|
import path37 from "node:path";
|
|
39574
39851
|
var SEARCH_LIMIT = 100;
|
|
39575
|
-
function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
39852
|
+
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
39576
39853
|
void (async () => {
|
|
39577
39854
|
await yieldToEventLoop();
|
|
39578
39855
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
39579
|
-
const
|
|
39580
|
-
|
|
39856
|
+
const sessionParentPath = path37.resolve(
|
|
39857
|
+
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
39858
|
+
);
|
|
39859
|
+
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
39581
39860
|
const payload2 = {
|
|
39582
39861
|
type: "file_browser_search_response",
|
|
39583
39862
|
id: msg.id,
|
|
@@ -39587,7 +39866,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
39587
39866
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
39588
39867
|
return;
|
|
39589
39868
|
}
|
|
39590
|
-
const results = await searchBridgeFilePathsAsync(
|
|
39869
|
+
const results = await searchBridgeFilePathsAsync(sessionParentPath, q, SEARCH_LIMIT);
|
|
39591
39870
|
const payload = {
|
|
39592
39871
|
type: "file_browser_search_response",
|
|
39593
39872
|
id: msg.id,
|
|
@@ -39597,9 +39876,9 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
39597
39876
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
|
|
39598
39877
|
})();
|
|
39599
39878
|
}
|
|
39600
|
-
function triggerFileIndexBuild() {
|
|
39879
|
+
function triggerFileIndexBuild(sessionParentPath = getBridgeRoot()) {
|
|
39601
39880
|
setImmediate(() => {
|
|
39602
|
-
void ensureFileIndexAsync(
|
|
39881
|
+
void ensureFileIndexAsync(sessionParentPath).catch((e) => {
|
|
39603
39882
|
console.error("[file-index] Background build failed:", e);
|
|
39604
39883
|
});
|
|
39605
39884
|
});
|
|
@@ -39609,18 +39888,19 @@ function triggerFileIndexBuild() {
|
|
|
39609
39888
|
function sendFileBrowserMessage(socket, e2ee, payload) {
|
|
39610
39889
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
|
|
39611
39890
|
}
|
|
39612
|
-
function handleFileBrowserRequest(msg, socket, e2ee) {
|
|
39891
|
+
function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
39613
39892
|
void (async () => {
|
|
39614
39893
|
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
39615
39894
|
const op = msg.op === "read" ? "read" : "list";
|
|
39895
|
+
const sessionParentPath = sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
39616
39896
|
if (op === "list") {
|
|
39617
|
-
const result = await listDirAsync(reqPath);
|
|
39897
|
+
const result = await listDirAsync(reqPath, sessionParentPath);
|
|
39618
39898
|
if ("error" in result) {
|
|
39619
39899
|
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
39620
39900
|
} else {
|
|
39621
39901
|
sendFileBrowserMessage(socket, e2ee, { type: "file_browser_response", id: msg.id, entries: result.entries });
|
|
39622
39902
|
if (reqPath === "." || reqPath === "") {
|
|
39623
|
-
triggerFileIndexBuild();
|
|
39903
|
+
triggerFileIndexBuild(sessionParentPath);
|
|
39624
39904
|
}
|
|
39625
39905
|
}
|
|
39626
39906
|
} else {
|
|
@@ -39628,7 +39908,16 @@ function handleFileBrowserRequest(msg, socket, e2ee) {
|
|
|
39628
39908
|
const endLine = typeof msg.endLine === "number" ? msg.endLine : void 0;
|
|
39629
39909
|
const lineOffset = typeof msg.lineOffset === "number" ? msg.lineOffset : void 0;
|
|
39630
39910
|
const lineChunkSize = typeof msg.lineChunkSize === "number" ? msg.lineChunkSize : void 0;
|
|
39631
|
-
const
|
|
39911
|
+
const encoding = msg.encoding === "base64" ? "base64" : "utf8";
|
|
39912
|
+
const result = await readFileAsync(
|
|
39913
|
+
reqPath,
|
|
39914
|
+
startLine,
|
|
39915
|
+
endLine,
|
|
39916
|
+
lineOffset,
|
|
39917
|
+
lineChunkSize,
|
|
39918
|
+
sessionParentPath,
|
|
39919
|
+
encoding
|
|
39920
|
+
);
|
|
39632
39921
|
if ("error" in result) {
|
|
39633
39922
|
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
39634
39923
|
} else {
|
|
@@ -39640,6 +39929,8 @@ function handleFileBrowserRequest(msg, socket, e2ee) {
|
|
|
39640
39929
|
size: result.size
|
|
39641
39930
|
};
|
|
39642
39931
|
if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
|
|
39932
|
+
if (result.mimeType != null) payload.mimeType = result.mimeType;
|
|
39933
|
+
if (result.resolvedPath != null) payload.resolvedPath = result.resolvedPath;
|
|
39643
39934
|
sendFileBrowserMessage(socket, e2ee, payload);
|
|
39644
39935
|
}
|
|
39645
39936
|
}
|
|
@@ -39647,21 +39938,27 @@ function handleFileBrowserRequest(msg, socket, e2ee) {
|
|
|
39647
39938
|
}
|
|
39648
39939
|
|
|
39649
39940
|
// src/routing/handlers/file-browser-messages.ts
|
|
39650
|
-
function handleFileBrowserRequestMessage(msg, { getWs, e2ee }) {
|
|
39941
|
+
function handleFileBrowserRequestMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
39651
39942
|
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
39652
39943
|
const socket = getWs();
|
|
39653
39944
|
if (!socket) return;
|
|
39654
39945
|
handleFileBrowserRequest(
|
|
39655
39946
|
msg,
|
|
39656
39947
|
socket,
|
|
39657
|
-
e2ee
|
|
39948
|
+
e2ee,
|
|
39949
|
+
sessionWorktreeManager
|
|
39658
39950
|
);
|
|
39659
39951
|
}
|
|
39660
|
-
function handleFileBrowserSearchMessage(msg, { getWs, e2ee }) {
|
|
39952
|
+
function handleFileBrowserSearchMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
39661
39953
|
if (typeof msg.id !== "string") return;
|
|
39662
39954
|
const socket = getWs();
|
|
39663
39955
|
if (!socket) return;
|
|
39664
|
-
handleFileBrowserSearch(
|
|
39956
|
+
handleFileBrowserSearch(
|
|
39957
|
+
msg,
|
|
39958
|
+
socket,
|
|
39959
|
+
e2ee,
|
|
39960
|
+
sessionWorktreeManager
|
|
39961
|
+
);
|
|
39665
39962
|
}
|
|
39666
39963
|
|
|
39667
39964
|
// src/routing/handlers/skill-layout-request.ts
|
|
@@ -39675,7 +39972,7 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
39675
39972
|
}
|
|
39676
39973
|
|
|
39677
39974
|
// src/skills/install-remote-skills.ts
|
|
39678
|
-
import
|
|
39975
|
+
import fs38 from "node:fs";
|
|
39679
39976
|
import path38 from "node:path";
|
|
39680
39977
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
39681
39978
|
const installed2 = [];
|
|
@@ -39691,11 +39988,11 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
39691
39988
|
for (const f of item.files) {
|
|
39692
39989
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
39693
39990
|
const dest = path38.join(skillDir, f.path);
|
|
39694
|
-
|
|
39991
|
+
fs38.mkdirSync(path38.dirname(dest), { recursive: true });
|
|
39695
39992
|
if (f.text !== void 0) {
|
|
39696
|
-
|
|
39993
|
+
fs38.writeFileSync(dest, f.text, "utf8");
|
|
39697
39994
|
} else if (f.base64) {
|
|
39698
|
-
|
|
39995
|
+
fs38.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
39699
39996
|
}
|
|
39700
39997
|
}
|
|
39701
39998
|
installed2.push({
|
|
@@ -39853,7 +40150,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
39853
40150
|
};
|
|
39854
40151
|
|
|
39855
40152
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
39856
|
-
import * as
|
|
40153
|
+
import * as fs39 from "node:fs";
|
|
39857
40154
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
39858
40155
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
39859
40156
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -39866,7 +40163,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
39866
40163
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
39867
40164
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
39868
40165
|
try {
|
|
39869
|
-
await
|
|
40166
|
+
await fs39.promises.access(file2, fs39.constants.F_OK);
|
|
39870
40167
|
} catch {
|
|
39871
40168
|
sendWsMessage(s, {
|
|
39872
40169
|
type: "revert_turn_snapshot_result",
|
|
@@ -40882,7 +41179,7 @@ async function runCliAction(program2, opts) {
|
|
|
40882
41179
|
if (bridgeRootOpt) {
|
|
40883
41180
|
const resolvedBridgeRoot = path42.resolve(process.cwd(), bridgeRootOpt);
|
|
40884
41181
|
try {
|
|
40885
|
-
const st =
|
|
41182
|
+
const st = fs40.statSync(resolvedBridgeRoot);
|
|
40886
41183
|
if (!st.isDirectory()) {
|
|
40887
41184
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
40888
41185
|
process.exit(1);
|