@buildautomaton/cli 0.1.69 → 0.1.71
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 +784 -511
- package/dist/cli.js.map +4 -4
- package/dist/index.js +872 -599
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7720,14 +7720,14 @@ var init_access = __esm({
|
|
|
7720
7720
|
|
|
7721
7721
|
// src/sqlite/read-migration-sql.ts
|
|
7722
7722
|
import { existsSync, readFileSync } from "node:fs";
|
|
7723
|
-
import { dirname, join as
|
|
7723
|
+
import { dirname, join as join3 } from "node:path";
|
|
7724
7724
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7725
7725
|
function readMigrationSql(filename, ...searchSubdirs) {
|
|
7726
7726
|
const moduleDir = dirname(fileURLToPath2(import.meta.url));
|
|
7727
7727
|
const candidates = searchSubdirs.flatMap((sub) => [
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7728
|
+
join3(moduleDir, sub, filename),
|
|
7729
|
+
join3(moduleDir, "..", sub, filename),
|
|
7730
|
+
join3(moduleDir, "..", "..", "dist", sub, filename)
|
|
7731
7731
|
]);
|
|
7732
7732
|
const resolved = candidates.find((path84) => existsSync(path84));
|
|
7733
7733
|
if (!resolved) {
|
|
@@ -10608,26 +10608,26 @@ var init_member_access = __esm({
|
|
|
10608
10608
|
|
|
10609
10609
|
// src/code-nav/tree-sitter-assets-dir.ts
|
|
10610
10610
|
import { existsSync as existsSync2 } from "node:fs";
|
|
10611
|
-
import { dirname as dirname2, join as
|
|
10611
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
10612
10612
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
10613
10613
|
function repoNodeModulesDir(fromDir) {
|
|
10614
|
-
return
|
|
10614
|
+
return join4(fromDir, "..", "..", "..", "node_modules");
|
|
10615
10615
|
}
|
|
10616
10616
|
function firstDirWithWebTreeSitterWasm(candidates) {
|
|
10617
10617
|
for (const dir of candidates) {
|
|
10618
|
-
if (existsSync2(
|
|
10618
|
+
if (existsSync2(join4(dir, "web-tree-sitter.wasm"))) return dir;
|
|
10619
10619
|
}
|
|
10620
10620
|
return null;
|
|
10621
10621
|
}
|
|
10622
10622
|
function getTreeSitterAssetsDir() {
|
|
10623
10623
|
const moduleDir = dirname2(fileURLToPath3(import.meta.url));
|
|
10624
10624
|
const fromModule = firstDirWithWebTreeSitterWasm([
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10625
|
+
join4(moduleDir, "tree-sitter"),
|
|
10626
|
+
join4(moduleDir, "..", "tree-sitter"),
|
|
10627
|
+
join4(moduleDir, "..", "..", "dist", "tree-sitter")
|
|
10628
10628
|
]);
|
|
10629
10629
|
if (fromModule) return fromModule;
|
|
10630
|
-
const fromNodeModules = firstDirWithWebTreeSitterWasm([
|
|
10630
|
+
const fromNodeModules = firstDirWithWebTreeSitterWasm([join4(repoNodeModulesDir(moduleDir), "web-tree-sitter")]);
|
|
10631
10631
|
if (fromNodeModules) return fromNodeModules;
|
|
10632
10632
|
throw new Error(
|
|
10633
10633
|
"Missing web-tree-sitter.wasm. Run `pnpm build` in packages/cli to copy tree-sitter assets into dist/tree-sitter."
|
|
@@ -10641,7 +10641,7 @@ var init_tree_sitter_assets_dir = __esm({
|
|
|
10641
10641
|
|
|
10642
10642
|
// src/code-nav/parser/tree-sitter-runtime.ts
|
|
10643
10643
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
10644
|
-
import { dirname as dirname3, join as
|
|
10644
|
+
import { dirname as dirname3, join as join5 } from "node:path";
|
|
10645
10645
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
10646
10646
|
import { Parser, Language, Query, LANGUAGE_VERSION, MIN_COMPATIBLE_VERSION } from "web-tree-sitter";
|
|
10647
10647
|
function withTreeSitterRuntimeLock(fn) {
|
|
@@ -10656,7 +10656,7 @@ async function ensureParserInit() {
|
|
|
10656
10656
|
if (!initPromise2) {
|
|
10657
10657
|
const assetsDir = getTreeSitterAssetsDir();
|
|
10658
10658
|
initPromise2 = Parser.init({
|
|
10659
|
-
locateFile: (scriptName) =>
|
|
10659
|
+
locateFile: (scriptName) => join5(assetsDir, scriptName)
|
|
10660
10660
|
}).catch((e) => {
|
|
10661
10661
|
initPromise2 = null;
|
|
10662
10662
|
throw e;
|
|
@@ -10666,9 +10666,9 @@ async function ensureParserInit() {
|
|
|
10666
10666
|
}
|
|
10667
10667
|
function resolveWasmPath(assetsDir, wasmFile) {
|
|
10668
10668
|
const candidates = [
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10669
|
+
join5(assetsDir, wasmFile),
|
|
10670
|
+
join5(assetsDir, "..", "..", "dist", "tree-sitter", wasmFile),
|
|
10671
|
+
join5(assetsDir, "..", "..", "..", "node_modules", wasmFile.replace(".wasm", ""), wasmFile)
|
|
10672
10672
|
];
|
|
10673
10673
|
const hit = candidates.find((p) => existsSync3(p));
|
|
10674
10674
|
if (!hit) throw new Error(`Missing tree-sitter wasm: ${wasmFile}`);
|
|
@@ -10677,10 +10677,10 @@ function resolveWasmPath(assetsDir, wasmFile) {
|
|
|
10677
10677
|
function resolveTagsPath(assetsDir, tagsQueryFile) {
|
|
10678
10678
|
const pkgName = tagsQueryFile.split("/")[0] ?? "";
|
|
10679
10679
|
const candidates = [
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10680
|
+
join5(CODE_NAV_QUERIES_ROOT, tagsQueryFile),
|
|
10681
|
+
join5(assetsDir, tagsQueryFile),
|
|
10682
|
+
join5(assetsDir, "..", "..", "dist", "tree-sitter", tagsQueryFile),
|
|
10683
|
+
join5(assetsDir, "..", "..", "..", "node_modules", pkgName, "queries", "tags.scm")
|
|
10684
10684
|
];
|
|
10685
10685
|
const hit = candidates.find((p) => existsSync3(p));
|
|
10686
10686
|
if (!hit) throw new Error(`Missing tags query: ${tagsQueryFile}`);
|
|
@@ -10718,7 +10718,7 @@ var init_tree_sitter_runtime = __esm({
|
|
|
10718
10718
|
loadedByKey = /* @__PURE__ */ new Map();
|
|
10719
10719
|
failedLanguageKeys = /* @__PURE__ */ new Set();
|
|
10720
10720
|
runtimeChain = Promise.resolve();
|
|
10721
|
-
CODE_NAV_QUERIES_ROOT =
|
|
10721
|
+
CODE_NAV_QUERIES_ROOT = join5(dirname3(fileURLToPath4(import.meta.url)), "..", "queries");
|
|
10722
10722
|
}
|
|
10723
10723
|
});
|
|
10724
10724
|
|
|
@@ -12289,7 +12289,7 @@ var init_in_process_bridge = __esm({
|
|
|
12289
12289
|
});
|
|
12290
12290
|
|
|
12291
12291
|
// src/code-nav/symbol-index/worker/lifecycle/state.ts
|
|
12292
|
-
import { dirname as dirname4, join as
|
|
12292
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
12293
12293
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
12294
12294
|
function getWorker() {
|
|
12295
12295
|
return worker;
|
|
@@ -12308,7 +12308,7 @@ function shouldUseInProcessWorker() {
|
|
|
12308
12308
|
}
|
|
12309
12309
|
function resolveWorkerScriptPath() {
|
|
12310
12310
|
const moduleDir = dirname4(fileURLToPath5(import.meta.url));
|
|
12311
|
-
return
|
|
12311
|
+
return join6(moduleDir, "..", "worker.js");
|
|
12312
12312
|
}
|
|
12313
12313
|
function resetLifecycleStateForTests() {
|
|
12314
12314
|
terminatePromise = null;
|
|
@@ -31064,7 +31064,7 @@ var {
|
|
|
31064
31064
|
} = import_index.default;
|
|
31065
31065
|
|
|
31066
31066
|
// src/cli-version.ts
|
|
31067
|
-
var CLI_VERSION = "0.1.
|
|
31067
|
+
var CLI_VERSION = "0.1.71".length > 0 ? "0.1.71" : "0.0.0-dev";
|
|
31068
31068
|
|
|
31069
31069
|
// src/cli/defaults.ts
|
|
31070
31070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
@@ -32816,6 +32816,46 @@ function runPendingAuth(options) {
|
|
|
32816
32816
|
// src/run-bridge-connected.ts
|
|
32817
32817
|
init_log();
|
|
32818
32818
|
|
|
32819
|
+
// src/agents/acp/clients/bridge-agent-path.ts
|
|
32820
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
32821
|
+
import { homedir } from "node:os";
|
|
32822
|
+
import { join as join2 } from "node:path";
|
|
32823
|
+
function getBridgeAgentPathEntries(home = process.env.HOME ?? homedir()) {
|
|
32824
|
+
const entries = [
|
|
32825
|
+
join2(home, ".local", "bin"),
|
|
32826
|
+
join2(home, ".npm-global", "bin"),
|
|
32827
|
+
"/usr/local/bin"
|
|
32828
|
+
];
|
|
32829
|
+
const prefix = process.env.NPM_CONFIG_PREFIX;
|
|
32830
|
+
if (prefix) entries.push(join2(prefix, "bin"));
|
|
32831
|
+
try {
|
|
32832
|
+
const npmBin = execFileSync2("npm", ["bin", "-g"], { encoding: "utf8", timeout: 2e3 }).trim();
|
|
32833
|
+
if (npmBin) entries.push(npmBin);
|
|
32834
|
+
} catch {
|
|
32835
|
+
}
|
|
32836
|
+
return entries;
|
|
32837
|
+
}
|
|
32838
|
+
function augmentPath(pathValue, extra) {
|
|
32839
|
+
const current = pathValue ?? "";
|
|
32840
|
+
const parts = current.split(":").filter(Boolean);
|
|
32841
|
+
const seen = new Set(parts);
|
|
32842
|
+
const prefix = [];
|
|
32843
|
+
for (const entry of extra) {
|
|
32844
|
+
if (!entry || seen.has(entry)) continue;
|
|
32845
|
+
seen.add(entry);
|
|
32846
|
+
prefix.push(entry);
|
|
32847
|
+
}
|
|
32848
|
+
if (prefix.length === 0) return current;
|
|
32849
|
+
return current ? `${prefix.join(":")}:${current}` : prefix.join(":");
|
|
32850
|
+
}
|
|
32851
|
+
function ensureBridgeAgentPathInProcessEnv() {
|
|
32852
|
+
const extra = getBridgeAgentPathEntries();
|
|
32853
|
+
process.env.PATH = augmentPath(process.env.PATH, extra);
|
|
32854
|
+
}
|
|
32855
|
+
function bridgeAgentPathEnv(base = process.env) {
|
|
32856
|
+
return { ...base, PATH: augmentPath(base.PATH, getBridgeAgentPathEntries()) };
|
|
32857
|
+
}
|
|
32858
|
+
|
|
32819
32859
|
// src/files/watch-file-index.ts
|
|
32820
32860
|
import path25 from "node:path";
|
|
32821
32861
|
|
|
@@ -34902,6 +34942,18 @@ function getAgentModelFromAgentConfig(config2) {
|
|
|
34902
34942
|
return t !== "" ? t : null;
|
|
34903
34943
|
}
|
|
34904
34944
|
|
|
34945
|
+
// ../types/src/overview/heatmap/constants.ts
|
|
34946
|
+
var HOUR_MS = 36e5;
|
|
34947
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
34948
|
+
|
|
34949
|
+
// ../types/src/bridges/agents/types.ts
|
|
34950
|
+
var INSTALLABLE_BRIDGE_AGENTS = [
|
|
34951
|
+
{ value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
|
|
34952
|
+
{ value: "codex-acp", label: "Codex", tokenLabel: "OpenAI API key", tokenEnvVar: "OPENAI_API_KEY" },
|
|
34953
|
+
{ value: "cursor-cli", label: "Cursor CLI agent", tokenLabel: "Cursor API key", tokenEnvVar: "CURSOR_API_KEY" },
|
|
34954
|
+
{ value: "opencode", label: "OpenCode agent", tokenLabel: "Provider API key", tokenEnvVar: "OPENCODE_API_KEY" }
|
|
34955
|
+
];
|
|
34956
|
+
|
|
34905
34957
|
// src/paths/session-layout-paths.ts
|
|
34906
34958
|
import * as path26 from "node:path";
|
|
34907
34959
|
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
@@ -34958,7 +35010,10 @@ async function execFileShutdownAware(file2, args, timeoutMs) {
|
|
|
34958
35010
|
async function isCommandOnPath(command, timeoutMs = COMMAND_ON_PATH_PROBE_TIMEOUT_MS) {
|
|
34959
35011
|
if (isCliImmediateShutdownRequested()) return false;
|
|
34960
35012
|
try {
|
|
34961
|
-
await
|
|
35013
|
+
await execFileAsync5("which", [command], {
|
|
35014
|
+
timeout: timeoutMs,
|
|
35015
|
+
env: bridgeAgentPathEnv()
|
|
35016
|
+
});
|
|
34962
35017
|
return true;
|
|
34963
35018
|
} catch {
|
|
34964
35019
|
return false;
|
|
@@ -36673,15 +36728,15 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
36673
36728
|
}
|
|
36674
36729
|
|
|
36675
36730
|
// src/agents/acp/session-file-change-path-kind.ts
|
|
36676
|
-
import { execFileSync as
|
|
36731
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
36677
36732
|
import { existsSync as existsSync4, statSync } from "node:fs";
|
|
36678
36733
|
|
|
36679
36734
|
// src/git/get-git-repo-root-sync.ts
|
|
36680
|
-
import { execFileSync as
|
|
36735
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
36681
36736
|
import * as path28 from "node:path";
|
|
36682
36737
|
function getGitRepoRootSync(startDir) {
|
|
36683
36738
|
try {
|
|
36684
|
-
const out =
|
|
36739
|
+
const out = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
|
|
36685
36740
|
cwd: path28.resolve(startDir),
|
|
36686
36741
|
encoding: "utf8",
|
|
36687
36742
|
stdio: ["ignore", "pipe", "ignore"],
|
|
@@ -36694,7 +36749,7 @@ function getGitRepoRootSync(startDir) {
|
|
|
36694
36749
|
}
|
|
36695
36750
|
|
|
36696
36751
|
// src/agents/acp/workspace-files.ts
|
|
36697
|
-
import { execFileSync as
|
|
36752
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
36698
36753
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
36699
36754
|
import * as path29 from "node:path";
|
|
36700
36755
|
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
@@ -36755,7 +36810,7 @@ function readGitHeadBlob(sessionParentPath, displayPath) {
|
|
|
36755
36810
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
36756
36811
|
const execCwd = gitRoot ?? sessionParentPath;
|
|
36757
36812
|
try {
|
|
36758
|
-
return
|
|
36813
|
+
return execFileSync4("git", ["show", `HEAD:${displayPath}`], {
|
|
36759
36814
|
cwd: execCwd,
|
|
36760
36815
|
encoding: "utf8",
|
|
36761
36816
|
maxBuffer: 50 * 1024 * 1024
|
|
@@ -36771,7 +36826,7 @@ function gitHeadPathObjectType(sessionParentPath, displayPath) {
|
|
|
36771
36826
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
36772
36827
|
if (!gitRoot) return null;
|
|
36773
36828
|
try {
|
|
36774
|
-
return
|
|
36829
|
+
return execFileSync5("git", ["cat-file", "-t", `HEAD:${displayPath}`], {
|
|
36775
36830
|
cwd: gitRoot,
|
|
36776
36831
|
encoding: "utf8"
|
|
36777
36832
|
}).trim();
|
|
@@ -37626,11 +37681,11 @@ init_cli_process_interrupt();
|
|
|
37626
37681
|
var BRIDGE_MCP_SERVER_NAME2 = "buildautomaton-bridge";
|
|
37627
37682
|
|
|
37628
37683
|
// src/mcp/resolve-bridge-mcp-server-path.ts
|
|
37629
|
-
import { dirname as dirname7, join as
|
|
37684
|
+
import { dirname as dirname7, join as join7 } from "node:path";
|
|
37630
37685
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
37631
37686
|
function resolveBridgeMcpServerScriptPath() {
|
|
37632
37687
|
const cliDir = dirname7(fileURLToPath7(import.meta.url));
|
|
37633
|
-
return
|
|
37688
|
+
return join7(cliDir, "bridge-mcp-server.js");
|
|
37634
37689
|
}
|
|
37635
37690
|
|
|
37636
37691
|
// src/mcp/build-acp-mcp-servers.ts
|
|
@@ -51489,6 +51544,7 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
|
|
|
51489
51544
|
"code_nav",
|
|
51490
51545
|
"skill_layout_request",
|
|
51491
51546
|
"install_skills",
|
|
51547
|
+
"install_agent",
|
|
51492
51548
|
"refresh_local_skills",
|
|
51493
51549
|
"bridge_git_context_request",
|
|
51494
51550
|
"list_repo_branches_request"
|
|
@@ -51564,6 +51620,100 @@ var handleBridgeHeartbeatAck = (msg, deps) => {
|
|
|
51564
51620
|
deps.onBridgeHeartbeatAck?.(Math.trunc(raw));
|
|
51565
51621
|
};
|
|
51566
51622
|
|
|
51623
|
+
// src/routing/dispatch/connection.ts
|
|
51624
|
+
function dispatchBridgeConnectionMessage(msg, deps) {
|
|
51625
|
+
switch (msg.type) {
|
|
51626
|
+
case "auth_token":
|
|
51627
|
+
handleAuthToken(msg, deps);
|
|
51628
|
+
break;
|
|
51629
|
+
case "bridge_identified":
|
|
51630
|
+
handleBridgeIdentified(msg, deps);
|
|
51631
|
+
break;
|
|
51632
|
+
case "ha":
|
|
51633
|
+
handleBridgeHeartbeatAck(msg, deps);
|
|
51634
|
+
break;
|
|
51635
|
+
}
|
|
51636
|
+
}
|
|
51637
|
+
|
|
51638
|
+
// src/routing/handlers/preview-environment-control.ts
|
|
51639
|
+
var handlePreviewEnvironmentControl = (msg, deps) => {
|
|
51640
|
+
let wire;
|
|
51641
|
+
try {
|
|
51642
|
+
wire = deps.e2ee ? deps.e2ee.decryptMessage(msg) : msg;
|
|
51643
|
+
} catch (e) {
|
|
51644
|
+
deps.log(`[E2EE] Could not decrypt preview environment command: ${e instanceof Error ? e.message : String(e)}`);
|
|
51645
|
+
return;
|
|
51646
|
+
}
|
|
51647
|
+
const environmentId = typeof wire.environmentId === "string" ? wire.environmentId : "";
|
|
51648
|
+
const action = wire.action === "start" || wire.action === "stop" ? wire.action : null;
|
|
51649
|
+
if (!environmentId || !action) return;
|
|
51650
|
+
deps.previewEnvironmentManager?.handleControl(environmentId, action);
|
|
51651
|
+
};
|
|
51652
|
+
|
|
51653
|
+
// src/routing/handlers/preview-environments-config.ts
|
|
51654
|
+
var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
|
|
51655
|
+
var handlePreviewEnvironmentsConfig = (msg, deps) => {
|
|
51656
|
+
const previewEnvironments = msg.previewEnvironments;
|
|
51657
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
|
|
51658
|
+
setImmediate(() => {
|
|
51659
|
+
deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
|
|
51660
|
+
const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
|
|
51661
|
+
void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
|
|
51662
|
+
if (proxyPorts !== void 0) {
|
|
51663
|
+
deps.updateFirehoseProxyPorts?.(proxyPorts);
|
|
51664
|
+
}
|
|
51665
|
+
});
|
|
51666
|
+
};
|
|
51667
|
+
|
|
51668
|
+
// src/routing/handlers/send-deploy-session-to-preview-result.ts
|
|
51669
|
+
function sendDeploySessionToPreviewResult(ws, id, payload) {
|
|
51670
|
+
if (!ws) return;
|
|
51671
|
+
sendWsMessage(ws, { type: "deploy_session_to_preview_result", id, ...payload });
|
|
51672
|
+
}
|
|
51673
|
+
|
|
51674
|
+
// src/routing/handlers/deploy-session-to-preview.ts
|
|
51675
|
+
var handleDeploySessionToPreviewMessage = (msg, deps) => {
|
|
51676
|
+
if (typeof msg.id !== "string") return;
|
|
51677
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
51678
|
+
const environmentId = typeof msg.environmentId === "string" ? msg.environmentId : "";
|
|
51679
|
+
if (!sessionId || !environmentId) return;
|
|
51680
|
+
void (async () => {
|
|
51681
|
+
const ws = deps.getWs();
|
|
51682
|
+
const reply = (payload) => sendDeploySessionToPreviewResult(ws, msg.id, payload);
|
|
51683
|
+
try {
|
|
51684
|
+
if (!deps.previewWorktreeManager) {
|
|
51685
|
+
reply({ ok: false, error: "Preview worktree manager unavailable" });
|
|
51686
|
+
return;
|
|
51687
|
+
}
|
|
51688
|
+
const result = await deploySessionToPreviewEnvironment({
|
|
51689
|
+
sessionWorktreeManager: deps.sessionWorktreeManager,
|
|
51690
|
+
previewWorktreeManager: deps.previewWorktreeManager,
|
|
51691
|
+
sessionId,
|
|
51692
|
+
environmentId,
|
|
51693
|
+
log: deps.log
|
|
51694
|
+
});
|
|
51695
|
+
reply(result);
|
|
51696
|
+
} catch (e) {
|
|
51697
|
+
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
51698
|
+
}
|
|
51699
|
+
})();
|
|
51700
|
+
};
|
|
51701
|
+
|
|
51702
|
+
// src/routing/dispatch/preview.ts
|
|
51703
|
+
function dispatchBridgePreviewMessage(msg, deps) {
|
|
51704
|
+
switch (msg.type) {
|
|
51705
|
+
case "preview_environments_config":
|
|
51706
|
+
handlePreviewEnvironmentsConfig(msg, deps);
|
|
51707
|
+
break;
|
|
51708
|
+
case "preview_environment_control":
|
|
51709
|
+
handlePreviewEnvironmentControl(msg, deps);
|
|
51710
|
+
break;
|
|
51711
|
+
case "deploy_session_to_preview":
|
|
51712
|
+
handleDeploySessionToPreviewMessage(msg, deps);
|
|
51713
|
+
break;
|
|
51714
|
+
}
|
|
51715
|
+
}
|
|
51716
|
+
|
|
51567
51717
|
// src/agents/acp/from-bridge/handle-bridge-agent-config.ts
|
|
51568
51718
|
function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
51569
51719
|
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
|
|
@@ -52202,6 +52352,308 @@ var handleSessionRequestResponseMessage = (msg, deps) => {
|
|
|
52202
52352
|
handleBridgeSessionRequestResponse(msg, deps);
|
|
52203
52353
|
};
|
|
52204
52354
|
|
|
52355
|
+
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
52356
|
+
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
52357
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
52358
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
52359
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
52360
|
+
if (!branch.trim() || !message.trim()) {
|
|
52361
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
52362
|
+
return;
|
|
52363
|
+
}
|
|
52364
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
52365
|
+
sessionId,
|
|
52366
|
+
branch: branch.trim(),
|
|
52367
|
+
message: message.trim(),
|
|
52368
|
+
push: pushAfterCommit
|
|
52369
|
+
});
|
|
52370
|
+
if (!commitRes.ok) {
|
|
52371
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
52372
|
+
return;
|
|
52373
|
+
}
|
|
52374
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52375
|
+
reply({
|
|
52376
|
+
ok: true,
|
|
52377
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52378
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52379
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
52380
|
+
});
|
|
52381
|
+
}
|
|
52382
|
+
|
|
52383
|
+
// src/routing/handlers/git/session-git-changes-params.ts
|
|
52384
|
+
function readString(value) {
|
|
52385
|
+
return typeof value === "string" ? value.trim() : "";
|
|
52386
|
+
}
|
|
52387
|
+
function readChangesObject(msg) {
|
|
52388
|
+
const changes = msg.changes;
|
|
52389
|
+
if (!changes || typeof changes !== "object" || Array.isArray(changes)) return null;
|
|
52390
|
+
return changes;
|
|
52391
|
+
}
|
|
52392
|
+
function parseSessionGitChangesParams(msg) {
|
|
52393
|
+
const nested = readChangesObject(msg);
|
|
52394
|
+
const file2 = nested?.file && typeof nested.file === "object" && !Array.isArray(nested.file) ? nested.file : null;
|
|
52395
|
+
const repoRelPath = readString(nested?.repoRelPath) || readString(msg.changesRepoRelPath);
|
|
52396
|
+
const viewRaw = nested?.view ?? msg.changesView;
|
|
52397
|
+
const view = viewRaw === "commit" ? "commit" : "working";
|
|
52398
|
+
const commitSha = readString(nested?.commitSha) || readString(msg.changesCommitSha);
|
|
52399
|
+
const recentCommitsLimit = nested?.recentCommitsLimit ?? msg.changesRecentCommitsLimit;
|
|
52400
|
+
return {
|
|
52401
|
+
repoRelPath,
|
|
52402
|
+
view,
|
|
52403
|
+
commitSha,
|
|
52404
|
+
recentCommitsLimit: typeof recentCommitsLimit === "number" || typeof recentCommitsLimit === "string" ? recentCommitsLimit : void 0,
|
|
52405
|
+
fileWorkspaceRelPath: readString(file2?.workspaceRelPath),
|
|
52406
|
+
fileChange: readString(file2?.change),
|
|
52407
|
+
fileMovedFromWorkspaceRelPath: readString(file2?.movedFromWorkspaceRelPath)
|
|
52408
|
+
};
|
|
52409
|
+
}
|
|
52410
|
+
|
|
52411
|
+
// src/routing/handlers/git/handle-session-git-get-change-file-patch.ts
|
|
52412
|
+
async function handleSessionGitGetChangeFilePatchAction(deps, msg, reply) {
|
|
52413
|
+
const changes = parseSessionGitChangesParams(msg);
|
|
52414
|
+
const { repoRelPath: repoRel, view, commitSha, fileWorkspaceRelPath, fileChange, fileMovedFromWorkspaceRelPath } = changes;
|
|
52415
|
+
const change = parseWorkingTreeChangeKind(fileChange);
|
|
52416
|
+
if (!repoRel || !fileWorkspaceRelPath || !change) {
|
|
52417
|
+
reply({
|
|
52418
|
+
ok: false,
|
|
52419
|
+
error: "changes.repoRelPath, changes.file.workspaceRelPath, and changes.file.change are required"
|
|
52420
|
+
});
|
|
52421
|
+
return;
|
|
52422
|
+
}
|
|
52423
|
+
if (view === "commit" && !commitSha) {
|
|
52424
|
+
reply({ ok: false, error: "changes.commitSha is required for commit file patch" });
|
|
52425
|
+
return;
|
|
52426
|
+
}
|
|
52427
|
+
const patch = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeFilePatch(msg.sessionId, {
|
|
52428
|
+
repoRelPath: repoRel,
|
|
52429
|
+
workspaceRelPath: fileWorkspaceRelPath,
|
|
52430
|
+
change,
|
|
52431
|
+
movedFromWorkspaceRelPath: fileMovedFromWorkspaceRelPath || null,
|
|
52432
|
+
basis: view === "commit" ? { kind: "commit", sha: commitSha } : { kind: "working" }
|
|
52433
|
+
});
|
|
52434
|
+
reply(
|
|
52435
|
+
{
|
|
52436
|
+
ok: true,
|
|
52437
|
+
patchContent: patch.patchContent ?? null,
|
|
52438
|
+
totalLines: patch.totalLines
|
|
52439
|
+
},
|
|
52440
|
+
["patchContent"]
|
|
52441
|
+
);
|
|
52442
|
+
}
|
|
52443
|
+
|
|
52444
|
+
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
52445
|
+
var listChangesInflight = /* @__PURE__ */ new Map();
|
|
52446
|
+
function normalizeListChangesRepoPathRelativeToWorkspaceRoot(repoRelPath) {
|
|
52447
|
+
if (!repoRelPath?.trim()) return "";
|
|
52448
|
+
return normalizeRepoPathRelativeToWorkspaceRoot(repoRelPath.trim());
|
|
52449
|
+
}
|
|
52450
|
+
function listChangesInflightKey(sessionId, opts) {
|
|
52451
|
+
const basis = opts?.basis;
|
|
52452
|
+
return [
|
|
52453
|
+
sessionId,
|
|
52454
|
+
normalizeListChangesRepoPathRelativeToWorkspaceRoot(opts?.repoRelPath),
|
|
52455
|
+
basis?.kind === "commit" ? `commit:${basis.sha}` : "working",
|
|
52456
|
+
String(opts?.recentCommitsLimit ?? "")
|
|
52457
|
+
].join("|");
|
|
52458
|
+
}
|
|
52459
|
+
function getSessionWorkingTreeChangeDetailsCoalesced(sessionWorktreeManager, sessionId, opts) {
|
|
52460
|
+
const key = listChangesInflightKey(sessionId, opts);
|
|
52461
|
+
const existing = listChangesInflight.get(key);
|
|
52462
|
+
if (existing) return existing;
|
|
52463
|
+
const promise2 = sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts).finally(() => {
|
|
52464
|
+
if (listChangesInflight.get(key) === promise2) listChangesInflight.delete(key);
|
|
52465
|
+
});
|
|
52466
|
+
listChangesInflight.set(key, promise2);
|
|
52467
|
+
return promise2;
|
|
52468
|
+
}
|
|
52469
|
+
|
|
52470
|
+
// src/routing/handlers/git/handle-session-git-list-changes.ts
|
|
52471
|
+
async function handleSessionGitListChangesAction(deps, msg, reply) {
|
|
52472
|
+
const changes = parseSessionGitChangesParams(msg);
|
|
52473
|
+
const { repoRelPath: repoRel, view, commitSha, recentCommitsLimit } = changes;
|
|
52474
|
+
if (view === "commit") {
|
|
52475
|
+
if (!repoRel || !commitSha) {
|
|
52476
|
+
reply({
|
|
52477
|
+
ok: false,
|
|
52478
|
+
error: "changes.repoRelPath and changes.commitSha are required for commit view"
|
|
52479
|
+
});
|
|
52480
|
+
return;
|
|
52481
|
+
}
|
|
52482
|
+
}
|
|
52483
|
+
const opts = repoRel && view === "commit" && commitSha ? {
|
|
52484
|
+
repoRelPath: repoRel,
|
|
52485
|
+
basis: { kind: "commit", sha: commitSha },
|
|
52486
|
+
recentCommitsLimit
|
|
52487
|
+
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
52488
|
+
const repos = await getSessionWorkingTreeChangeDetailsCoalesced(
|
|
52489
|
+
deps.sessionWorktreeManager,
|
|
52490
|
+
msg.sessionId,
|
|
52491
|
+
opts
|
|
52492
|
+
);
|
|
52493
|
+
reply({ ok: true, repos }, ["repos"]);
|
|
52494
|
+
}
|
|
52495
|
+
|
|
52496
|
+
// src/routing/handlers/git/handle-session-git-push.ts
|
|
52497
|
+
async function handleSessionGitPushAction(deps, sessionId, reply) {
|
|
52498
|
+
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
52499
|
+
if (!pushRes.ok) {
|
|
52500
|
+
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
52501
|
+
return;
|
|
52502
|
+
}
|
|
52503
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52504
|
+
reply({
|
|
52505
|
+
ok: true,
|
|
52506
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52507
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52508
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
52509
|
+
});
|
|
52510
|
+
}
|
|
52511
|
+
|
|
52512
|
+
// src/routing/handlers/git/handle-session-git-status.ts
|
|
52513
|
+
async function handleSessionGitStatusAction(deps, sessionId, reply) {
|
|
52514
|
+
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52515
|
+
reply({
|
|
52516
|
+
ok: true,
|
|
52517
|
+
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
52518
|
+
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
52519
|
+
uncommittedFileCount: r.uncommittedFileCount
|
|
52520
|
+
});
|
|
52521
|
+
}
|
|
52522
|
+
|
|
52523
|
+
// src/routing/handlers/git/send-session-git-result.ts
|
|
52524
|
+
function sendSessionGitResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
52525
|
+
if (!ws) return;
|
|
52526
|
+
const message = { type: "session_git_result", id, ...payload };
|
|
52527
|
+
let wire = message;
|
|
52528
|
+
if (e2ee && encryptedFields.length > 0) {
|
|
52529
|
+
wire = e2ee.encryptFields(message, encryptedFields);
|
|
52530
|
+
}
|
|
52531
|
+
sendWsMessage(ws, wire);
|
|
52532
|
+
}
|
|
52533
|
+
|
|
52534
|
+
// src/routing/handlers/git/session-git-request.ts
|
|
52535
|
+
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
52536
|
+
if (typeof msg.id !== "string") return;
|
|
52537
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52538
|
+
const action = msg.action;
|
|
52539
|
+
if (!sessionId || action !== "status" && action !== "push" && action !== "commit" && action !== "list_changes" && action !== "file_diff")
|
|
52540
|
+
return;
|
|
52541
|
+
void (async () => {
|
|
52542
|
+
const ws = deps.getWs();
|
|
52543
|
+
const reply = (payload, encryptedFields = []) => sendSessionGitResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
52544
|
+
try {
|
|
52545
|
+
if (action === "status") {
|
|
52546
|
+
await handleSessionGitStatusAction(deps, sessionId, reply);
|
|
52547
|
+
return;
|
|
52548
|
+
}
|
|
52549
|
+
if (action === "list_changes") {
|
|
52550
|
+
await handleSessionGitListChangesAction(deps, { ...msg, sessionId }, reply);
|
|
52551
|
+
return;
|
|
52552
|
+
}
|
|
52553
|
+
if (action === "file_diff") {
|
|
52554
|
+
await handleSessionGitGetChangeFilePatchAction(deps, { ...msg, sessionId }, reply);
|
|
52555
|
+
return;
|
|
52556
|
+
}
|
|
52557
|
+
if (action === "push") {
|
|
52558
|
+
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
52559
|
+
return;
|
|
52560
|
+
}
|
|
52561
|
+
await handleSessionGitCommitAction(deps, sessionId, msg, reply);
|
|
52562
|
+
} catch (e) {
|
|
52563
|
+
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
52564
|
+
}
|
|
52565
|
+
})();
|
|
52566
|
+
};
|
|
52567
|
+
|
|
52568
|
+
// src/routing/handlers/rename-session-branch.ts
|
|
52569
|
+
var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
52570
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52571
|
+
const newBranch = typeof msg.newBranch === "string" ? msg.newBranch : "";
|
|
52572
|
+
if (!sessionId || !newBranch) return;
|
|
52573
|
+
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
52574
|
+
};
|
|
52575
|
+
|
|
52576
|
+
// src/routing/handlers/session-archived.ts
|
|
52577
|
+
var handleSessionArchivedMessage = (msg, deps) => {
|
|
52578
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52579
|
+
if (!sessionId) return;
|
|
52580
|
+
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
52581
|
+
};
|
|
52582
|
+
|
|
52583
|
+
// src/routing/handlers/session-discarded.ts
|
|
52584
|
+
var handleSessionDiscardedMessage = (msg, deps) => {
|
|
52585
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52586
|
+
if (!sessionId) return;
|
|
52587
|
+
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
52588
|
+
};
|
|
52589
|
+
|
|
52590
|
+
// src/routing/handlers/revert-turn-snapshot.ts
|
|
52591
|
+
import * as fs60 from "node:fs";
|
|
52592
|
+
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
52593
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52594
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52595
|
+
const turnId = typeof msg.turnId === "string" ? msg.turnId : "";
|
|
52596
|
+
if (!id || !sessionId || !turnId) return;
|
|
52597
|
+
const { getWs, log: log2, sessionWorktreeManager } = deps;
|
|
52598
|
+
void (async () => {
|
|
52599
|
+
const s = getWs();
|
|
52600
|
+
if (!s) return;
|
|
52601
|
+
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
52602
|
+
const file2 = snapshotFilePath(agentBase, turnId);
|
|
52603
|
+
try {
|
|
52604
|
+
await fs60.promises.access(file2, fs60.constants.F_OK);
|
|
52605
|
+
} catch {
|
|
52606
|
+
sendWsMessage(s, {
|
|
52607
|
+
type: "revert_turn_snapshot_result",
|
|
52608
|
+
id,
|
|
52609
|
+
ok: false,
|
|
52610
|
+
error: "No snapshot found for this turn (git state may be unavailable)."
|
|
52611
|
+
});
|
|
52612
|
+
return;
|
|
52613
|
+
}
|
|
52614
|
+
const res = await applyPreTurnSnapshot(file2, log2);
|
|
52615
|
+
sendWsMessage(s, {
|
|
52616
|
+
type: "revert_turn_snapshot_result",
|
|
52617
|
+
id,
|
|
52618
|
+
ok: res.ok,
|
|
52619
|
+
...res.error ? { error: res.error } : {}
|
|
52620
|
+
});
|
|
52621
|
+
})();
|
|
52622
|
+
};
|
|
52623
|
+
|
|
52624
|
+
// src/routing/dispatch/session.ts
|
|
52625
|
+
function dispatchBridgeSessionMessage(msg, deps) {
|
|
52626
|
+
switch (msg.type) {
|
|
52627
|
+
case "agent_config":
|
|
52628
|
+
handleAgentConfigMessage(msg, deps);
|
|
52629
|
+
break;
|
|
52630
|
+
case "prompt_queue_state":
|
|
52631
|
+
handlePromptQueueStateMessage(msg, deps);
|
|
52632
|
+
break;
|
|
52633
|
+
case "prompt":
|
|
52634
|
+
handlePromptMessage(msg, deps);
|
|
52635
|
+
break;
|
|
52636
|
+
case "session_git_request":
|
|
52637
|
+
handleSessionGitRequestMessage(msg, deps);
|
|
52638
|
+
break;
|
|
52639
|
+
case "rename_session_branch":
|
|
52640
|
+
handleRenameSessionBranchMessage(msg, deps);
|
|
52641
|
+
break;
|
|
52642
|
+
case "session_archived":
|
|
52643
|
+
handleSessionArchivedMessage(msg, deps);
|
|
52644
|
+
break;
|
|
52645
|
+
case "session_discarded":
|
|
52646
|
+
handleSessionDiscardedMessage(msg, deps);
|
|
52647
|
+
break;
|
|
52648
|
+
case "revert_turn_snapshot":
|
|
52649
|
+
handleRevertTurnSnapshotMessage(msg, deps);
|
|
52650
|
+
break;
|
|
52651
|
+
case "cursor_request_response":
|
|
52652
|
+
handleSessionRequestResponseMessage(msg, deps);
|
|
52653
|
+
break;
|
|
52654
|
+
}
|
|
52655
|
+
}
|
|
52656
|
+
|
|
52205
52657
|
// src/skills/preview.ts
|
|
52206
52658
|
import { spawn as spawn10 } from "node:child_process";
|
|
52207
52659
|
var PREVIEW_API_BASE_PATH = "/__preview";
|
|
@@ -52400,6 +52852,271 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
52400
52852
|
);
|
|
52401
52853
|
};
|
|
52402
52854
|
|
|
52855
|
+
// src/routing/handlers/skill-layout-request.ts
|
|
52856
|
+
function handleSkillLayoutRequest(msg, deps) {
|
|
52857
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52858
|
+
void (async () => {
|
|
52859
|
+
const socket = deps.getWs();
|
|
52860
|
+
const roots = await discoverSkillLayoutRootsAsync(getBridgeRoot());
|
|
52861
|
+
if (socket) {
|
|
52862
|
+
sendWsMessage(socket, { type: "skill_layout_response", id, roots });
|
|
52863
|
+
}
|
|
52864
|
+
})();
|
|
52865
|
+
}
|
|
52866
|
+
|
|
52867
|
+
// src/skills/install/is-valid-install-item.ts
|
|
52868
|
+
function isValidRemoteSkillInstallItem(item) {
|
|
52869
|
+
if (item === null || typeof item !== "object") return false;
|
|
52870
|
+
const o = item;
|
|
52871
|
+
return typeof o.sourceId === "string" && typeof o.skillName === "string" && typeof o.versionHash === "string" && Array.isArray(o.files);
|
|
52872
|
+
}
|
|
52873
|
+
|
|
52874
|
+
// src/skills/install/install-remote-skills-async.ts
|
|
52875
|
+
init_yield_to_event_loop();
|
|
52876
|
+
import fs61 from "node:fs";
|
|
52877
|
+
import path80 from "node:path";
|
|
52878
|
+
|
|
52879
|
+
// src/skills/install/constants.ts
|
|
52880
|
+
var INSTALL_SKILLS_YIELD_EVERY = 16;
|
|
52881
|
+
|
|
52882
|
+
// src/skills/install/install-remote-skills-async.ts
|
|
52883
|
+
async function writeInstallFileAsync(skillDir, f, filesWritten) {
|
|
52884
|
+
if (typeof f.path !== "string" || !f.text && !f.base64) return;
|
|
52885
|
+
if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
|
|
52886
|
+
await yieldToEventLoop();
|
|
52887
|
+
}
|
|
52888
|
+
const dest = path80.join(skillDir, f.path);
|
|
52889
|
+
await fs61.promises.mkdir(path80.dirname(dest), { recursive: true });
|
|
52890
|
+
if (f.text !== void 0) {
|
|
52891
|
+
await fs61.promises.writeFile(dest, f.text, "utf8");
|
|
52892
|
+
} else if (f.base64) {
|
|
52893
|
+
await fs61.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
|
|
52894
|
+
}
|
|
52895
|
+
}
|
|
52896
|
+
async function installRemoteSkillsAsync(cwd, targetDir, items) {
|
|
52897
|
+
const installed2 = [];
|
|
52898
|
+
if (!Array.isArray(items)) {
|
|
52899
|
+
return { success: false, error: "Invalid items" };
|
|
52900
|
+
}
|
|
52901
|
+
const filesWritten = { count: 0 };
|
|
52902
|
+
try {
|
|
52903
|
+
for (const item of items) {
|
|
52904
|
+
if (!isValidRemoteSkillInstallItem(item)) continue;
|
|
52905
|
+
const skillDir = path80.join(cwd, targetDir, item.skillName);
|
|
52906
|
+
for (const f of item.files) {
|
|
52907
|
+
await writeInstallFileAsync(skillDir, f, filesWritten);
|
|
52908
|
+
}
|
|
52909
|
+
installed2.push({
|
|
52910
|
+
sourceId: item.sourceId,
|
|
52911
|
+
skillName: item.skillName,
|
|
52912
|
+
versionHash: item.versionHash
|
|
52913
|
+
});
|
|
52914
|
+
}
|
|
52915
|
+
return { success: true, installed: installed2 };
|
|
52916
|
+
} catch (e) {
|
|
52917
|
+
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
52918
|
+
}
|
|
52919
|
+
}
|
|
52920
|
+
|
|
52921
|
+
// src/routing/handlers/install-skills.ts
|
|
52922
|
+
var handleInstallSkillsMessage = (msg, deps) => {
|
|
52923
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52924
|
+
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
52925
|
+
const rawItems = msg.items;
|
|
52926
|
+
const cwd = getBridgeRoot();
|
|
52927
|
+
void (async () => {
|
|
52928
|
+
const socket = deps.getWs();
|
|
52929
|
+
const result = await installRemoteSkillsAsync(cwd, targetDir, rawItems);
|
|
52930
|
+
if (!result.success) {
|
|
52931
|
+
const err = result.error ?? "Invalid items";
|
|
52932
|
+
deps.log(`[Bridge service] Install skills failed: ${err}`);
|
|
52933
|
+
if (socket) {
|
|
52934
|
+
sendWsMessage(socket, { type: "install_skills_result", id, success: false, error: err });
|
|
52935
|
+
}
|
|
52936
|
+
return;
|
|
52937
|
+
}
|
|
52938
|
+
if (socket) {
|
|
52939
|
+
sendWsMessage(socket, { type: "install_skills_result", id, success: true, installed: result.installed });
|
|
52940
|
+
}
|
|
52941
|
+
})();
|
|
52942
|
+
};
|
|
52943
|
+
|
|
52944
|
+
// src/agents/install/commands/run-npm-global-install.ts
|
|
52945
|
+
import { execFile as execFile9 } from "node:child_process";
|
|
52946
|
+
import { promisify as promisify10 } from "node:util";
|
|
52947
|
+
var execFileAsync8 = promisify10(execFile9);
|
|
52948
|
+
async function runNpmGlobalInstall(packageName, env, timeoutMs = 3e5) {
|
|
52949
|
+
await execFileAsync8("npm", ["install", "-g", packageName], { timeout: timeoutMs, env: bridgeAgentPathEnv(env) });
|
|
52950
|
+
}
|
|
52951
|
+
|
|
52952
|
+
// src/agents/install/commands/claude-code.ts
|
|
52953
|
+
var claudeCodeInstallCommand = {
|
|
52954
|
+
agentType: "claude-code",
|
|
52955
|
+
detectCommand: "claude",
|
|
52956
|
+
async install(ctx) {
|
|
52957
|
+
ctx.onProgress?.("Installing Anthropic Claude Code");
|
|
52958
|
+
await runNpmGlobalInstall("@anthropic-ai/claude-code", {
|
|
52959
|
+
...ctx.env,
|
|
52960
|
+
ANTHROPIC_API_KEY: ctx.authToken
|
|
52961
|
+
});
|
|
52962
|
+
}
|
|
52963
|
+
};
|
|
52964
|
+
|
|
52965
|
+
// src/agents/install/commands/codex-acp.ts
|
|
52966
|
+
var codexAcpInstallCommand = {
|
|
52967
|
+
agentType: "codex-acp",
|
|
52968
|
+
detectCommand: "codex",
|
|
52969
|
+
async install(ctx) {
|
|
52970
|
+
ctx.onProgress?.("Installing Codex");
|
|
52971
|
+
await runNpmGlobalInstall("@openai/codex", {
|
|
52972
|
+
...ctx.env,
|
|
52973
|
+
OPENAI_API_KEY: ctx.authToken
|
|
52974
|
+
});
|
|
52975
|
+
}
|
|
52976
|
+
};
|
|
52977
|
+
|
|
52978
|
+
// src/agents/install/commands/cursor-cli.ts
|
|
52979
|
+
import { execFile as execFile10 } from "node:child_process";
|
|
52980
|
+
import { promisify as promisify11 } from "node:util";
|
|
52981
|
+
var execFileAsync9 = promisify11(execFile10);
|
|
52982
|
+
var cursorCliInstallCommand = {
|
|
52983
|
+
agentType: "cursor-cli",
|
|
52984
|
+
detectCommand: "agent",
|
|
52985
|
+
async install(ctx) {
|
|
52986
|
+
ctx.onProgress?.("Installing Cursor CLI");
|
|
52987
|
+
await execFileAsync9("bash", ["-lc", "curl -fsSL https://cursor.com/install | bash"], {
|
|
52988
|
+
timeout: 3e5,
|
|
52989
|
+
env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken }
|
|
52990
|
+
});
|
|
52991
|
+
}
|
|
52992
|
+
};
|
|
52993
|
+
|
|
52994
|
+
// src/agents/install/commands/opencode.ts
|
|
52995
|
+
var opencodeInstallCommand = {
|
|
52996
|
+
agentType: "opencode",
|
|
52997
|
+
detectCommand: "opencode",
|
|
52998
|
+
async install(ctx) {
|
|
52999
|
+
ctx.onProgress?.("Installing OpenCode");
|
|
53000
|
+
await runNpmGlobalInstall("opencode-ai", {
|
|
53001
|
+
...ctx.env,
|
|
53002
|
+
OPENCODE_API_KEY: ctx.authToken
|
|
53003
|
+
});
|
|
53004
|
+
}
|
|
53005
|
+
};
|
|
53006
|
+
|
|
53007
|
+
// src/agents/install/commands/index.ts
|
|
53008
|
+
var COMMANDS = [
|
|
53009
|
+
claudeCodeInstallCommand,
|
|
53010
|
+
codexAcpInstallCommand,
|
|
53011
|
+
cursorCliInstallCommand,
|
|
53012
|
+
opencodeInstallCommand
|
|
53013
|
+
];
|
|
53014
|
+
var byType = new Map(COMMANDS.map((c) => [c.agentType, c]));
|
|
53015
|
+
function getAgentInstallCommand(agentType) {
|
|
53016
|
+
return byType.get(agentType);
|
|
53017
|
+
}
|
|
53018
|
+
|
|
53019
|
+
// src/agents/install/install-local-agent.ts
|
|
53020
|
+
async function installLocalAgentOnBridge(params) {
|
|
53021
|
+
const spec = INSTALLABLE_BRIDGE_AGENTS.find((a) => a.value === params.agentType);
|
|
53022
|
+
if (!spec) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
|
|
53023
|
+
const command = getAgentInstallCommand(params.agentType);
|
|
53024
|
+
if (!command) return { success: false, error: `No install command for ${params.agentType}` };
|
|
53025
|
+
params.onProgress?.(`Configuring ${spec.label} credentials`);
|
|
53026
|
+
try {
|
|
53027
|
+
await command.install({
|
|
53028
|
+
authToken: params.authToken,
|
|
53029
|
+
onProgress: params.onProgress,
|
|
53030
|
+
env: { ...process.env, [spec.tokenEnvVar]: params.authToken }
|
|
53031
|
+
});
|
|
53032
|
+
} catch (e) {
|
|
53033
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
53034
|
+
return { success: false, error: msg };
|
|
53035
|
+
}
|
|
53036
|
+
ensureBridgeAgentPathInProcessEnv();
|
|
53037
|
+
const found = await isCommandOnPath(command.detectCommand);
|
|
53038
|
+
if (!found) {
|
|
53039
|
+
return { success: false, error: `${command.detectCommand} not found on PATH after install` };
|
|
53040
|
+
}
|
|
53041
|
+
return { success: true };
|
|
53042
|
+
}
|
|
53043
|
+
|
|
53044
|
+
// src/routing/handlers/install-agent.ts
|
|
53045
|
+
var handleInstallAgentMessage = (msg, deps) => {
|
|
53046
|
+
const processId = typeof msg.processId === "string" ? msg.processId : "";
|
|
53047
|
+
const agentId = typeof msg.agentId === "string" ? msg.agentId : "";
|
|
53048
|
+
const tokenId = typeof msg.tokenId === "string" ? msg.tokenId : "";
|
|
53049
|
+
const agentType = typeof msg.agentType === "string" ? msg.agentType : "";
|
|
53050
|
+
const authToken = typeof msg.authToken === "string" ? msg.authToken : "";
|
|
53051
|
+
if (!processId || !agentId || !tokenId || !agentType || !authToken) return;
|
|
53052
|
+
void (async () => {
|
|
53053
|
+
const socket = deps.getWs();
|
|
53054
|
+
const report = (step, message) => {
|
|
53055
|
+
if (socket) {
|
|
53056
|
+
sendWsMessage(socket, {
|
|
53057
|
+
type: "install_agent_progress",
|
|
53058
|
+
processId,
|
|
53059
|
+
agentId,
|
|
53060
|
+
tokenId,
|
|
53061
|
+
agentType,
|
|
53062
|
+
step,
|
|
53063
|
+
message
|
|
53064
|
+
});
|
|
53065
|
+
}
|
|
53066
|
+
};
|
|
53067
|
+
const result = await installLocalAgentOnBridge({
|
|
53068
|
+
agentType,
|
|
53069
|
+
authToken,
|
|
53070
|
+
onProgress: (message) => report("agent_install_package", message)
|
|
53071
|
+
});
|
|
53072
|
+
if (socket) {
|
|
53073
|
+
sendWsMessage(socket, {
|
|
53074
|
+
type: "install_agent_result",
|
|
53075
|
+
processId,
|
|
53076
|
+
agentId,
|
|
53077
|
+
tokenId,
|
|
53078
|
+
agentType,
|
|
53079
|
+
success: result.success,
|
|
53080
|
+
error: result.error
|
|
53081
|
+
});
|
|
53082
|
+
}
|
|
53083
|
+
if (result.success) {
|
|
53084
|
+
await deps.reportAutoDetectedAgents?.();
|
|
53085
|
+
}
|
|
53086
|
+
if (!result.success) {
|
|
53087
|
+
deps.log(`[Bridge service] Install agent failed: ${result.error ?? "unknown"}`);
|
|
53088
|
+
}
|
|
53089
|
+
})();
|
|
53090
|
+
};
|
|
53091
|
+
|
|
53092
|
+
// src/routing/handlers/refresh-local-skills.ts
|
|
53093
|
+
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
53094
|
+
setImmediate(() => {
|
|
53095
|
+
deps.sendLocalSkillsReport?.();
|
|
53096
|
+
});
|
|
53097
|
+
};
|
|
53098
|
+
|
|
53099
|
+
// src/routing/dispatch/skills.ts
|
|
53100
|
+
function dispatchBridgeSkillsMessage(msg, deps) {
|
|
53101
|
+
switch (msg.type) {
|
|
53102
|
+
case "skill_call":
|
|
53103
|
+
handleSkillCallMessage(msg, deps);
|
|
53104
|
+
break;
|
|
53105
|
+
case "skill_layout_request":
|
|
53106
|
+
handleSkillLayoutRequest(msg, deps);
|
|
53107
|
+
break;
|
|
53108
|
+
case "install_skills":
|
|
53109
|
+
handleInstallSkillsMessage(msg, deps);
|
|
53110
|
+
break;
|
|
53111
|
+
case "install_agent":
|
|
53112
|
+
handleInstallAgentMessage(msg, deps);
|
|
53113
|
+
break;
|
|
53114
|
+
case "refresh_local_skills":
|
|
53115
|
+
handleRefreshLocalSkills(msg, deps);
|
|
53116
|
+
break;
|
|
53117
|
+
}
|
|
53118
|
+
}
|
|
53119
|
+
|
|
52403
53120
|
// src/files/browser/send-file-browser-message.ts
|
|
52404
53121
|
function sendFileBrowserMessage(socket, e2ee, payload) {
|
|
52405
53122
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
|
|
@@ -52461,13 +53178,13 @@ function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
|
52461
53178
|
|
|
52462
53179
|
// src/files/handle-file-browser-search.ts
|
|
52463
53180
|
init_yield_to_event_loop();
|
|
52464
|
-
import
|
|
53181
|
+
import path81 from "node:path";
|
|
52465
53182
|
var SEARCH_LIMIT = 100;
|
|
52466
53183
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
52467
53184
|
void (async () => {
|
|
52468
53185
|
await yieldToEventLoop();
|
|
52469
53186
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
52470
|
-
const sessionParentPath =
|
|
53187
|
+
const sessionParentPath = path81.resolve(
|
|
52471
53188
|
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
52472
53189
|
);
|
|
52473
53190
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
@@ -52564,435 +53281,6 @@ function handleFileBrowserCodeNavMessage(msg, { getWs, e2ee, sessionWorktreeMana
|
|
|
52564
53281
|
);
|
|
52565
53282
|
}
|
|
52566
53283
|
|
|
52567
|
-
// src/routing/handlers/skill-layout-request.ts
|
|
52568
|
-
function handleSkillLayoutRequest(msg, deps) {
|
|
52569
|
-
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52570
|
-
void (async () => {
|
|
52571
|
-
const socket = deps.getWs();
|
|
52572
|
-
const roots = await discoverSkillLayoutRootsAsync(getBridgeRoot());
|
|
52573
|
-
if (socket) {
|
|
52574
|
-
sendWsMessage(socket, { type: "skill_layout_response", id, roots });
|
|
52575
|
-
}
|
|
52576
|
-
})();
|
|
52577
|
-
}
|
|
52578
|
-
|
|
52579
|
-
// src/skills/install/is-valid-install-item.ts
|
|
52580
|
-
function isValidRemoteSkillInstallItem(item) {
|
|
52581
|
-
if (item === null || typeof item !== "object") return false;
|
|
52582
|
-
const o = item;
|
|
52583
|
-
return typeof o.sourceId === "string" && typeof o.skillName === "string" && typeof o.versionHash === "string" && Array.isArray(o.files);
|
|
52584
|
-
}
|
|
52585
|
-
|
|
52586
|
-
// src/skills/install/install-remote-skills-async.ts
|
|
52587
|
-
init_yield_to_event_loop();
|
|
52588
|
-
import fs60 from "node:fs";
|
|
52589
|
-
import path81 from "node:path";
|
|
52590
|
-
|
|
52591
|
-
// src/skills/install/constants.ts
|
|
52592
|
-
var INSTALL_SKILLS_YIELD_EVERY = 16;
|
|
52593
|
-
|
|
52594
|
-
// src/skills/install/install-remote-skills-async.ts
|
|
52595
|
-
async function writeInstallFileAsync(skillDir, f, filesWritten) {
|
|
52596
|
-
if (typeof f.path !== "string" || !f.text && !f.base64) return;
|
|
52597
|
-
if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
|
|
52598
|
-
await yieldToEventLoop();
|
|
52599
|
-
}
|
|
52600
|
-
const dest = path81.join(skillDir, f.path);
|
|
52601
|
-
await fs60.promises.mkdir(path81.dirname(dest), { recursive: true });
|
|
52602
|
-
if (f.text !== void 0) {
|
|
52603
|
-
await fs60.promises.writeFile(dest, f.text, "utf8");
|
|
52604
|
-
} else if (f.base64) {
|
|
52605
|
-
await fs60.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
|
|
52606
|
-
}
|
|
52607
|
-
}
|
|
52608
|
-
async function installRemoteSkillsAsync(cwd, targetDir, items) {
|
|
52609
|
-
const installed2 = [];
|
|
52610
|
-
if (!Array.isArray(items)) {
|
|
52611
|
-
return { success: false, error: "Invalid items" };
|
|
52612
|
-
}
|
|
52613
|
-
const filesWritten = { count: 0 };
|
|
52614
|
-
try {
|
|
52615
|
-
for (const item of items) {
|
|
52616
|
-
if (!isValidRemoteSkillInstallItem(item)) continue;
|
|
52617
|
-
const skillDir = path81.join(cwd, targetDir, item.skillName);
|
|
52618
|
-
for (const f of item.files) {
|
|
52619
|
-
await writeInstallFileAsync(skillDir, f, filesWritten);
|
|
52620
|
-
}
|
|
52621
|
-
installed2.push({
|
|
52622
|
-
sourceId: item.sourceId,
|
|
52623
|
-
skillName: item.skillName,
|
|
52624
|
-
versionHash: item.versionHash
|
|
52625
|
-
});
|
|
52626
|
-
}
|
|
52627
|
-
return { success: true, installed: installed2 };
|
|
52628
|
-
} catch (e) {
|
|
52629
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
52630
|
-
}
|
|
52631
|
-
}
|
|
52632
|
-
|
|
52633
|
-
// src/routing/handlers/install-skills.ts
|
|
52634
|
-
var handleInstallSkillsMessage = (msg, deps) => {
|
|
52635
|
-
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52636
|
-
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
52637
|
-
const rawItems = msg.items;
|
|
52638
|
-
const cwd = getBridgeRoot();
|
|
52639
|
-
void (async () => {
|
|
52640
|
-
const socket = deps.getWs();
|
|
52641
|
-
const result = await installRemoteSkillsAsync(cwd, targetDir, rawItems);
|
|
52642
|
-
if (!result.success) {
|
|
52643
|
-
const err = result.error ?? "Invalid items";
|
|
52644
|
-
deps.log(`[Bridge service] Install skills failed: ${err}`);
|
|
52645
|
-
if (socket) {
|
|
52646
|
-
sendWsMessage(socket, { type: "install_skills_result", id, success: false, error: err });
|
|
52647
|
-
}
|
|
52648
|
-
return;
|
|
52649
|
-
}
|
|
52650
|
-
if (socket) {
|
|
52651
|
-
sendWsMessage(socket, { type: "install_skills_result", id, success: true, installed: result.installed });
|
|
52652
|
-
}
|
|
52653
|
-
})();
|
|
52654
|
-
};
|
|
52655
|
-
|
|
52656
|
-
// src/routing/handlers/refresh-local-skills.ts
|
|
52657
|
-
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
52658
|
-
setImmediate(() => {
|
|
52659
|
-
deps.sendLocalSkillsReport?.();
|
|
52660
|
-
});
|
|
52661
|
-
};
|
|
52662
|
-
|
|
52663
|
-
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
52664
|
-
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
52665
|
-
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
52666
|
-
const message = typeof msg.message === "string" ? msg.message : "";
|
|
52667
|
-
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
52668
|
-
if (!branch.trim() || !message.trim()) {
|
|
52669
|
-
reply({ ok: false, error: "branch and message are required for commit" });
|
|
52670
|
-
return;
|
|
52671
|
-
}
|
|
52672
|
-
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
52673
|
-
sessionId,
|
|
52674
|
-
branch: branch.trim(),
|
|
52675
|
-
message: message.trim(),
|
|
52676
|
-
push: pushAfterCommit
|
|
52677
|
-
});
|
|
52678
|
-
if (!commitRes.ok) {
|
|
52679
|
-
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
52680
|
-
return;
|
|
52681
|
-
}
|
|
52682
|
-
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52683
|
-
reply({
|
|
52684
|
-
ok: true,
|
|
52685
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52686
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52687
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
52688
|
-
});
|
|
52689
|
-
}
|
|
52690
|
-
|
|
52691
|
-
// src/routing/handlers/git/session-git-changes-params.ts
|
|
52692
|
-
function readString(value) {
|
|
52693
|
-
return typeof value === "string" ? value.trim() : "";
|
|
52694
|
-
}
|
|
52695
|
-
function readChangesObject(msg) {
|
|
52696
|
-
const changes = msg.changes;
|
|
52697
|
-
if (!changes || typeof changes !== "object" || Array.isArray(changes)) return null;
|
|
52698
|
-
return changes;
|
|
52699
|
-
}
|
|
52700
|
-
function parseSessionGitChangesParams(msg) {
|
|
52701
|
-
const nested = readChangesObject(msg);
|
|
52702
|
-
const file2 = nested?.file && typeof nested.file === "object" && !Array.isArray(nested.file) ? nested.file : null;
|
|
52703
|
-
const repoRelPath = readString(nested?.repoRelPath) || readString(msg.changesRepoRelPath);
|
|
52704
|
-
const viewRaw = nested?.view ?? msg.changesView;
|
|
52705
|
-
const view = viewRaw === "commit" ? "commit" : "working";
|
|
52706
|
-
const commitSha = readString(nested?.commitSha) || readString(msg.changesCommitSha);
|
|
52707
|
-
const recentCommitsLimit = nested?.recentCommitsLimit ?? msg.changesRecentCommitsLimit;
|
|
52708
|
-
return {
|
|
52709
|
-
repoRelPath,
|
|
52710
|
-
view,
|
|
52711
|
-
commitSha,
|
|
52712
|
-
recentCommitsLimit: typeof recentCommitsLimit === "number" || typeof recentCommitsLimit === "string" ? recentCommitsLimit : void 0,
|
|
52713
|
-
fileWorkspaceRelPath: readString(file2?.workspaceRelPath),
|
|
52714
|
-
fileChange: readString(file2?.change),
|
|
52715
|
-
fileMovedFromWorkspaceRelPath: readString(file2?.movedFromWorkspaceRelPath)
|
|
52716
|
-
};
|
|
52717
|
-
}
|
|
52718
|
-
|
|
52719
|
-
// src/routing/handlers/git/handle-session-git-get-change-file-patch.ts
|
|
52720
|
-
async function handleSessionGitGetChangeFilePatchAction(deps, msg, reply) {
|
|
52721
|
-
const changes = parseSessionGitChangesParams(msg);
|
|
52722
|
-
const { repoRelPath: repoRel, view, commitSha, fileWorkspaceRelPath, fileChange, fileMovedFromWorkspaceRelPath } = changes;
|
|
52723
|
-
const change = parseWorkingTreeChangeKind(fileChange);
|
|
52724
|
-
if (!repoRel || !fileWorkspaceRelPath || !change) {
|
|
52725
|
-
reply({
|
|
52726
|
-
ok: false,
|
|
52727
|
-
error: "changes.repoRelPath, changes.file.workspaceRelPath, and changes.file.change are required"
|
|
52728
|
-
});
|
|
52729
|
-
return;
|
|
52730
|
-
}
|
|
52731
|
-
if (view === "commit" && !commitSha) {
|
|
52732
|
-
reply({ ok: false, error: "changes.commitSha is required for commit file patch" });
|
|
52733
|
-
return;
|
|
52734
|
-
}
|
|
52735
|
-
const patch = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeFilePatch(msg.sessionId, {
|
|
52736
|
-
repoRelPath: repoRel,
|
|
52737
|
-
workspaceRelPath: fileWorkspaceRelPath,
|
|
52738
|
-
change,
|
|
52739
|
-
movedFromWorkspaceRelPath: fileMovedFromWorkspaceRelPath || null,
|
|
52740
|
-
basis: view === "commit" ? { kind: "commit", sha: commitSha } : { kind: "working" }
|
|
52741
|
-
});
|
|
52742
|
-
reply(
|
|
52743
|
-
{
|
|
52744
|
-
ok: true,
|
|
52745
|
-
patchContent: patch.patchContent ?? null,
|
|
52746
|
-
totalLines: patch.totalLines
|
|
52747
|
-
},
|
|
52748
|
-
["patchContent"]
|
|
52749
|
-
);
|
|
52750
|
-
}
|
|
52751
|
-
|
|
52752
|
-
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
52753
|
-
var listChangesInflight = /* @__PURE__ */ new Map();
|
|
52754
|
-
function normalizeListChangesRepoPathRelativeToWorkspaceRoot(repoRelPath) {
|
|
52755
|
-
if (!repoRelPath?.trim()) return "";
|
|
52756
|
-
return normalizeRepoPathRelativeToWorkspaceRoot(repoRelPath.trim());
|
|
52757
|
-
}
|
|
52758
|
-
function listChangesInflightKey(sessionId, opts) {
|
|
52759
|
-
const basis = opts?.basis;
|
|
52760
|
-
return [
|
|
52761
|
-
sessionId,
|
|
52762
|
-
normalizeListChangesRepoPathRelativeToWorkspaceRoot(opts?.repoRelPath),
|
|
52763
|
-
basis?.kind === "commit" ? `commit:${basis.sha}` : "working",
|
|
52764
|
-
String(opts?.recentCommitsLimit ?? "")
|
|
52765
|
-
].join("|");
|
|
52766
|
-
}
|
|
52767
|
-
function getSessionWorkingTreeChangeDetailsCoalesced(sessionWorktreeManager, sessionId, opts) {
|
|
52768
|
-
const key = listChangesInflightKey(sessionId, opts);
|
|
52769
|
-
const existing = listChangesInflight.get(key);
|
|
52770
|
-
if (existing) return existing;
|
|
52771
|
-
const promise2 = sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts).finally(() => {
|
|
52772
|
-
if (listChangesInflight.get(key) === promise2) listChangesInflight.delete(key);
|
|
52773
|
-
});
|
|
52774
|
-
listChangesInflight.set(key, promise2);
|
|
52775
|
-
return promise2;
|
|
52776
|
-
}
|
|
52777
|
-
|
|
52778
|
-
// src/routing/handlers/git/handle-session-git-list-changes.ts
|
|
52779
|
-
async function handleSessionGitListChangesAction(deps, msg, reply) {
|
|
52780
|
-
const changes = parseSessionGitChangesParams(msg);
|
|
52781
|
-
const { repoRelPath: repoRel, view, commitSha, recentCommitsLimit } = changes;
|
|
52782
|
-
if (view === "commit") {
|
|
52783
|
-
if (!repoRel || !commitSha) {
|
|
52784
|
-
reply({
|
|
52785
|
-
ok: false,
|
|
52786
|
-
error: "changes.repoRelPath and changes.commitSha are required for commit view"
|
|
52787
|
-
});
|
|
52788
|
-
return;
|
|
52789
|
-
}
|
|
52790
|
-
}
|
|
52791
|
-
const opts = repoRel && view === "commit" && commitSha ? {
|
|
52792
|
-
repoRelPath: repoRel,
|
|
52793
|
-
basis: { kind: "commit", sha: commitSha },
|
|
52794
|
-
recentCommitsLimit
|
|
52795
|
-
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
52796
|
-
const repos = await getSessionWorkingTreeChangeDetailsCoalesced(
|
|
52797
|
-
deps.sessionWorktreeManager,
|
|
52798
|
-
msg.sessionId,
|
|
52799
|
-
opts
|
|
52800
|
-
);
|
|
52801
|
-
reply({ ok: true, repos }, ["repos"]);
|
|
52802
|
-
}
|
|
52803
|
-
|
|
52804
|
-
// src/routing/handlers/git/handle-session-git-push.ts
|
|
52805
|
-
async function handleSessionGitPushAction(deps, sessionId, reply) {
|
|
52806
|
-
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
52807
|
-
if (!pushRes.ok) {
|
|
52808
|
-
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
52809
|
-
return;
|
|
52810
|
-
}
|
|
52811
|
-
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52812
|
-
reply({
|
|
52813
|
-
ok: true,
|
|
52814
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52815
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52816
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
52817
|
-
});
|
|
52818
|
-
}
|
|
52819
|
-
|
|
52820
|
-
// src/routing/handlers/git/handle-session-git-status.ts
|
|
52821
|
-
async function handleSessionGitStatusAction(deps, sessionId, reply) {
|
|
52822
|
-
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52823
|
-
reply({
|
|
52824
|
-
ok: true,
|
|
52825
|
-
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
52826
|
-
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
52827
|
-
uncommittedFileCount: r.uncommittedFileCount
|
|
52828
|
-
});
|
|
52829
|
-
}
|
|
52830
|
-
|
|
52831
|
-
// src/routing/handlers/git/send-session-git-result.ts
|
|
52832
|
-
function sendSessionGitResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
52833
|
-
if (!ws) return;
|
|
52834
|
-
const message = { type: "session_git_result", id, ...payload };
|
|
52835
|
-
let wire = message;
|
|
52836
|
-
if (e2ee && encryptedFields.length > 0) {
|
|
52837
|
-
wire = e2ee.encryptFields(message, encryptedFields);
|
|
52838
|
-
}
|
|
52839
|
-
sendWsMessage(ws, wire);
|
|
52840
|
-
}
|
|
52841
|
-
|
|
52842
|
-
// src/routing/handlers/git/session-git-request.ts
|
|
52843
|
-
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
52844
|
-
if (typeof msg.id !== "string") return;
|
|
52845
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52846
|
-
const action = msg.action;
|
|
52847
|
-
if (!sessionId || action !== "status" && action !== "push" && action !== "commit" && action !== "list_changes" && action !== "file_diff")
|
|
52848
|
-
return;
|
|
52849
|
-
void (async () => {
|
|
52850
|
-
const ws = deps.getWs();
|
|
52851
|
-
const reply = (payload, encryptedFields = []) => sendSessionGitResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
52852
|
-
try {
|
|
52853
|
-
if (action === "status") {
|
|
52854
|
-
await handleSessionGitStatusAction(deps, sessionId, reply);
|
|
52855
|
-
return;
|
|
52856
|
-
}
|
|
52857
|
-
if (action === "list_changes") {
|
|
52858
|
-
await handleSessionGitListChangesAction(deps, { ...msg, sessionId }, reply);
|
|
52859
|
-
return;
|
|
52860
|
-
}
|
|
52861
|
-
if (action === "file_diff") {
|
|
52862
|
-
await handleSessionGitGetChangeFilePatchAction(deps, { ...msg, sessionId }, reply);
|
|
52863
|
-
return;
|
|
52864
|
-
}
|
|
52865
|
-
if (action === "push") {
|
|
52866
|
-
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
52867
|
-
return;
|
|
52868
|
-
}
|
|
52869
|
-
await handleSessionGitCommitAction(deps, sessionId, msg, reply);
|
|
52870
|
-
} catch (e) {
|
|
52871
|
-
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
52872
|
-
}
|
|
52873
|
-
})();
|
|
52874
|
-
};
|
|
52875
|
-
|
|
52876
|
-
// src/routing/handlers/rename-session-branch.ts
|
|
52877
|
-
var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
52878
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52879
|
-
const newBranch = typeof msg.newBranch === "string" ? msg.newBranch : "";
|
|
52880
|
-
if (!sessionId || !newBranch) return;
|
|
52881
|
-
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
52882
|
-
};
|
|
52883
|
-
|
|
52884
|
-
// src/routing/handlers/session-archived.ts
|
|
52885
|
-
var handleSessionArchivedMessage = (msg, deps) => {
|
|
52886
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52887
|
-
if (!sessionId) return;
|
|
52888
|
-
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
52889
|
-
};
|
|
52890
|
-
|
|
52891
|
-
// src/routing/handlers/session-discarded.ts
|
|
52892
|
-
var handleSessionDiscardedMessage = (msg, deps) => {
|
|
52893
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52894
|
-
if (!sessionId) return;
|
|
52895
|
-
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
52896
|
-
};
|
|
52897
|
-
|
|
52898
|
-
// src/routing/handlers/revert-turn-snapshot.ts
|
|
52899
|
-
import * as fs61 from "node:fs";
|
|
52900
|
-
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
52901
|
-
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52902
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52903
|
-
const turnId = typeof msg.turnId === "string" ? msg.turnId : "";
|
|
52904
|
-
if (!id || !sessionId || !turnId) return;
|
|
52905
|
-
const { getWs, log: log2, sessionWorktreeManager } = deps;
|
|
52906
|
-
void (async () => {
|
|
52907
|
-
const s = getWs();
|
|
52908
|
-
if (!s) return;
|
|
52909
|
-
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
52910
|
-
const file2 = snapshotFilePath(agentBase, turnId);
|
|
52911
|
-
try {
|
|
52912
|
-
await fs61.promises.access(file2, fs61.constants.F_OK);
|
|
52913
|
-
} catch {
|
|
52914
|
-
sendWsMessage(s, {
|
|
52915
|
-
type: "revert_turn_snapshot_result",
|
|
52916
|
-
id,
|
|
52917
|
-
ok: false,
|
|
52918
|
-
error: "No snapshot found for this turn (git state may be unavailable)."
|
|
52919
|
-
});
|
|
52920
|
-
return;
|
|
52921
|
-
}
|
|
52922
|
-
const res = await applyPreTurnSnapshot(file2, log2);
|
|
52923
|
-
sendWsMessage(s, {
|
|
52924
|
-
type: "revert_turn_snapshot_result",
|
|
52925
|
-
id,
|
|
52926
|
-
ok: res.ok,
|
|
52927
|
-
...res.error ? { error: res.error } : {}
|
|
52928
|
-
});
|
|
52929
|
-
})();
|
|
52930
|
-
};
|
|
52931
|
-
|
|
52932
|
-
// src/routing/handlers/preview-environment-control.ts
|
|
52933
|
-
var handlePreviewEnvironmentControl = (msg, deps) => {
|
|
52934
|
-
let wire;
|
|
52935
|
-
try {
|
|
52936
|
-
wire = deps.e2ee ? deps.e2ee.decryptMessage(msg) : msg;
|
|
52937
|
-
} catch (e) {
|
|
52938
|
-
deps.log(`[E2EE] Could not decrypt preview environment command: ${e instanceof Error ? e.message : String(e)}`);
|
|
52939
|
-
return;
|
|
52940
|
-
}
|
|
52941
|
-
const environmentId = typeof wire.environmentId === "string" ? wire.environmentId : "";
|
|
52942
|
-
const action = wire.action === "start" || wire.action === "stop" ? wire.action : null;
|
|
52943
|
-
if (!environmentId || !action) return;
|
|
52944
|
-
deps.previewEnvironmentManager?.handleControl(environmentId, action);
|
|
52945
|
-
};
|
|
52946
|
-
|
|
52947
|
-
// src/routing/handlers/preview-environments-config.ts
|
|
52948
|
-
var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
|
|
52949
|
-
var handlePreviewEnvironmentsConfig = (msg, deps) => {
|
|
52950
|
-
const previewEnvironments = msg.previewEnvironments;
|
|
52951
|
-
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
|
|
52952
|
-
setImmediate(() => {
|
|
52953
|
-
deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
|
|
52954
|
-
const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
|
|
52955
|
-
void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
|
|
52956
|
-
if (proxyPorts !== void 0) {
|
|
52957
|
-
deps.updateFirehoseProxyPorts?.(proxyPorts);
|
|
52958
|
-
}
|
|
52959
|
-
});
|
|
52960
|
-
};
|
|
52961
|
-
|
|
52962
|
-
// src/routing/handlers/send-deploy-session-to-preview-result.ts
|
|
52963
|
-
function sendDeploySessionToPreviewResult(ws, id, payload) {
|
|
52964
|
-
if (!ws) return;
|
|
52965
|
-
sendWsMessage(ws, { type: "deploy_session_to_preview_result", id, ...payload });
|
|
52966
|
-
}
|
|
52967
|
-
|
|
52968
|
-
// src/routing/handlers/deploy-session-to-preview.ts
|
|
52969
|
-
var handleDeploySessionToPreviewMessage = (msg, deps) => {
|
|
52970
|
-
if (typeof msg.id !== "string") return;
|
|
52971
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52972
|
-
const environmentId = typeof msg.environmentId === "string" ? msg.environmentId : "";
|
|
52973
|
-
if (!sessionId || !environmentId) return;
|
|
52974
|
-
void (async () => {
|
|
52975
|
-
const ws = deps.getWs();
|
|
52976
|
-
const reply = (payload) => sendDeploySessionToPreviewResult(ws, msg.id, payload);
|
|
52977
|
-
try {
|
|
52978
|
-
if (!deps.previewWorktreeManager) {
|
|
52979
|
-
reply({ ok: false, error: "Preview worktree manager unavailable" });
|
|
52980
|
-
return;
|
|
52981
|
-
}
|
|
52982
|
-
const result = await deploySessionToPreviewEnvironment({
|
|
52983
|
-
sessionWorktreeManager: deps.sessionWorktreeManager,
|
|
52984
|
-
previewWorktreeManager: deps.previewWorktreeManager,
|
|
52985
|
-
sessionId,
|
|
52986
|
-
environmentId,
|
|
52987
|
-
log: deps.log
|
|
52988
|
-
});
|
|
52989
|
-
reply(result);
|
|
52990
|
-
} catch (e) {
|
|
52991
|
-
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
52992
|
-
}
|
|
52993
|
-
})();
|
|
52994
|
-
};
|
|
52995
|
-
|
|
52996
53284
|
// src/git/bridge-git-context.ts
|
|
52997
53285
|
import * as path82 from "node:path";
|
|
52998
53286
|
init_yield_to_event_loop();
|
|
@@ -53138,80 +53426,64 @@ function handleListRepoBranchesRequestMessage(msg, getWs) {
|
|
|
53138
53426
|
})();
|
|
53139
53427
|
}
|
|
53140
53428
|
|
|
53141
|
-
// src/routing/dispatch-
|
|
53429
|
+
// src/routing/dispatch/file-browser.ts
|
|
53430
|
+
function dispatchBridgeFileBrowserMessage(msg, deps) {
|
|
53431
|
+
switch (msg.type) {
|
|
53432
|
+
case "file_browser_request":
|
|
53433
|
+
handleFileBrowserRequestMessage(msg, deps);
|
|
53434
|
+
break;
|
|
53435
|
+
case "file_browser_search":
|
|
53436
|
+
handleFileBrowserSearchMessage(msg, deps);
|
|
53437
|
+
break;
|
|
53438
|
+
case "code_nav":
|
|
53439
|
+
handleFileBrowserCodeNavMessage(msg, deps);
|
|
53440
|
+
break;
|
|
53441
|
+
case "bridge_git_context_request":
|
|
53442
|
+
handleBridgeGitContextRequestMessage(msg, deps.getWs);
|
|
53443
|
+
break;
|
|
53444
|
+
case "list_repo_branches_request":
|
|
53445
|
+
handleListRepoBranchesRequestMessage(msg, deps.getWs);
|
|
53446
|
+
break;
|
|
53447
|
+
}
|
|
53448
|
+
}
|
|
53449
|
+
|
|
53450
|
+
// src/routing/dispatch/index.ts
|
|
53142
53451
|
function dispatchBridgeMessage(msg, deps) {
|
|
53143
53452
|
switch (msg.type) {
|
|
53144
53453
|
case "auth_token":
|
|
53145
|
-
handleAuthToken(msg, deps);
|
|
53146
|
-
break;
|
|
53147
53454
|
case "bridge_identified":
|
|
53148
|
-
handleBridgeIdentified(msg, deps);
|
|
53149
|
-
break;
|
|
53150
53455
|
case "ha":
|
|
53151
|
-
|
|
53456
|
+
dispatchBridgeConnectionMessage(msg, deps);
|
|
53152
53457
|
break;
|
|
53153
53458
|
case "preview_environments_config":
|
|
53154
|
-
handlePreviewEnvironmentsConfig(msg, deps);
|
|
53155
|
-
break;
|
|
53156
53459
|
case "preview_environment_control":
|
|
53157
|
-
handlePreviewEnvironmentControl(msg, deps);
|
|
53158
|
-
break;
|
|
53159
53460
|
case "deploy_session_to_preview":
|
|
53160
|
-
|
|
53461
|
+
dispatchBridgePreviewMessage(msg, deps);
|
|
53161
53462
|
break;
|
|
53162
53463
|
case "agent_config":
|
|
53163
|
-
handleAgentConfigMessage(msg, deps);
|
|
53164
|
-
break;
|
|
53165
53464
|
case "prompt_queue_state":
|
|
53166
|
-
handlePromptQueueStateMessage(msg, deps);
|
|
53167
|
-
break;
|
|
53168
53465
|
case "prompt":
|
|
53169
|
-
handlePromptMessage(msg, deps);
|
|
53170
|
-
break;
|
|
53171
53466
|
case "session_git_request":
|
|
53172
|
-
handleSessionGitRequestMessage(msg, deps);
|
|
53173
|
-
break;
|
|
53174
53467
|
case "rename_session_branch":
|
|
53175
|
-
handleRenameSessionBranchMessage(msg, deps);
|
|
53176
|
-
break;
|
|
53177
53468
|
case "session_archived":
|
|
53178
|
-
handleSessionArchivedMessage(msg, deps);
|
|
53179
|
-
break;
|
|
53180
53469
|
case "session_discarded":
|
|
53181
|
-
handleSessionDiscardedMessage(msg, deps);
|
|
53182
|
-
break;
|
|
53183
53470
|
case "revert_turn_snapshot":
|
|
53184
|
-
handleRevertTurnSnapshotMessage(msg, deps);
|
|
53185
|
-
break;
|
|
53186
53471
|
case "cursor_request_response":
|
|
53187
|
-
|
|
53472
|
+
dispatchBridgeSessionMessage(msg, deps);
|
|
53188
53473
|
break;
|
|
53189
53474
|
case "skill_call":
|
|
53190
|
-
handleSkillCallMessage(msg, deps);
|
|
53191
|
-
break;
|
|
53192
|
-
case "file_browser_request":
|
|
53193
|
-
handleFileBrowserRequestMessage(msg, deps);
|
|
53194
|
-
break;
|
|
53195
|
-
case "file_browser_search":
|
|
53196
|
-
handleFileBrowserSearchMessage(msg, deps);
|
|
53197
|
-
break;
|
|
53198
|
-
case "code_nav":
|
|
53199
|
-
handleFileBrowserCodeNavMessage(msg, deps);
|
|
53200
|
-
break;
|
|
53201
53475
|
case "skill_layout_request":
|
|
53202
|
-
handleSkillLayoutRequest(msg, deps);
|
|
53203
|
-
break;
|
|
53204
53476
|
case "install_skills":
|
|
53205
|
-
|
|
53206
|
-
break;
|
|
53477
|
+
case "install_agent":
|
|
53207
53478
|
case "refresh_local_skills":
|
|
53208
|
-
|
|
53479
|
+
dispatchBridgeSkillsMessage(msg, deps);
|
|
53209
53480
|
break;
|
|
53481
|
+
case "file_browser_request":
|
|
53482
|
+
case "file_browser_search":
|
|
53483
|
+
case "code_nav":
|
|
53210
53484
|
case "bridge_git_context_request":
|
|
53211
|
-
handleBridgeGitContextRequestMessage(msg, deps.getWs);
|
|
53212
|
-
break;
|
|
53213
53485
|
case "list_repo_branches_request":
|
|
53214
|
-
|
|
53486
|
+
dispatchBridgeFileBrowserMessage(msg, deps);
|
|
53215
53487
|
break;
|
|
53216
53488
|
}
|
|
53217
53489
|
}
|
|
@@ -53496,6 +53768,7 @@ init_log();
|
|
|
53496
53768
|
async function createBridgeConnection(options) {
|
|
53497
53769
|
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
53498
53770
|
const logFn = options.log ?? log;
|
|
53771
|
+
ensureBridgeAgentPathInProcessEnv();
|
|
53499
53772
|
await ensureBridgeConnectionDatabases(logFn);
|
|
53500
53773
|
const { state, getWs } = createMainBridgeReconnectState();
|
|
53501
53774
|
const runtime = await createBridgeConnectionRuntime(options, { state, getWs, logFn });
|