@buildautomaton/cli 0.1.69 → 0.1.70
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 +954 -729
- package/dist/cli.js.map +4 -4
- package/dist/index.js +794 -569
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -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.70".length > 0 ? "0.1.70" : "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";
|
|
@@ -34902,6 +34902,18 @@ function getAgentModelFromAgentConfig(config2) {
|
|
|
34902
34902
|
return t !== "" ? t : null;
|
|
34903
34903
|
}
|
|
34904
34904
|
|
|
34905
|
+
// ../types/src/overview/heatmap/constants.ts
|
|
34906
|
+
var HOUR_MS = 36e5;
|
|
34907
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
34908
|
+
|
|
34909
|
+
// ../types/src/bridges/agents/types.ts
|
|
34910
|
+
var INSTALLABLE_BRIDGE_AGENTS = [
|
|
34911
|
+
{ value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
|
|
34912
|
+
{ value: "codex-acp", label: "Codex", tokenLabel: "OpenAI API key", tokenEnvVar: "OPENAI_API_KEY" },
|
|
34913
|
+
{ value: "cursor-cli", label: "Cursor CLI agent", tokenLabel: "Cursor API key", tokenEnvVar: "CURSOR_API_KEY" },
|
|
34914
|
+
{ value: "opencode", label: "OpenCode agent", tokenLabel: "Provider API key", tokenEnvVar: "OPENCODE_API_KEY" }
|
|
34915
|
+
];
|
|
34916
|
+
|
|
34905
34917
|
// src/paths/session-layout-paths.ts
|
|
34906
34918
|
import * as path26 from "node:path";
|
|
34907
34919
|
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
@@ -51489,6 +51501,7 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
|
|
|
51489
51501
|
"code_nav",
|
|
51490
51502
|
"skill_layout_request",
|
|
51491
51503
|
"install_skills",
|
|
51504
|
+
"install_agent",
|
|
51492
51505
|
"refresh_local_skills",
|
|
51493
51506
|
"bridge_git_context_request",
|
|
51494
51507
|
"list_repo_branches_request"
|
|
@@ -51564,6 +51577,100 @@ var handleBridgeHeartbeatAck = (msg, deps) => {
|
|
|
51564
51577
|
deps.onBridgeHeartbeatAck?.(Math.trunc(raw));
|
|
51565
51578
|
};
|
|
51566
51579
|
|
|
51580
|
+
// src/routing/dispatch/connection.ts
|
|
51581
|
+
function dispatchBridgeConnectionMessage(msg, deps) {
|
|
51582
|
+
switch (msg.type) {
|
|
51583
|
+
case "auth_token":
|
|
51584
|
+
handleAuthToken(msg, deps);
|
|
51585
|
+
break;
|
|
51586
|
+
case "bridge_identified":
|
|
51587
|
+
handleBridgeIdentified(msg, deps);
|
|
51588
|
+
break;
|
|
51589
|
+
case "ha":
|
|
51590
|
+
handleBridgeHeartbeatAck(msg, deps);
|
|
51591
|
+
break;
|
|
51592
|
+
}
|
|
51593
|
+
}
|
|
51594
|
+
|
|
51595
|
+
// src/routing/handlers/preview-environment-control.ts
|
|
51596
|
+
var handlePreviewEnvironmentControl = (msg, deps) => {
|
|
51597
|
+
let wire;
|
|
51598
|
+
try {
|
|
51599
|
+
wire = deps.e2ee ? deps.e2ee.decryptMessage(msg) : msg;
|
|
51600
|
+
} catch (e) {
|
|
51601
|
+
deps.log(`[E2EE] Could not decrypt preview environment command: ${e instanceof Error ? e.message : String(e)}`);
|
|
51602
|
+
return;
|
|
51603
|
+
}
|
|
51604
|
+
const environmentId = typeof wire.environmentId === "string" ? wire.environmentId : "";
|
|
51605
|
+
const action = wire.action === "start" || wire.action === "stop" ? wire.action : null;
|
|
51606
|
+
if (!environmentId || !action) return;
|
|
51607
|
+
deps.previewEnvironmentManager?.handleControl(environmentId, action);
|
|
51608
|
+
};
|
|
51609
|
+
|
|
51610
|
+
// src/routing/handlers/preview-environments-config.ts
|
|
51611
|
+
var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
|
|
51612
|
+
var handlePreviewEnvironmentsConfig = (msg, deps) => {
|
|
51613
|
+
const previewEnvironments = msg.previewEnvironments;
|
|
51614
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
|
|
51615
|
+
setImmediate(() => {
|
|
51616
|
+
deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
|
|
51617
|
+
const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
|
|
51618
|
+
void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
|
|
51619
|
+
if (proxyPorts !== void 0) {
|
|
51620
|
+
deps.updateFirehoseProxyPorts?.(proxyPorts);
|
|
51621
|
+
}
|
|
51622
|
+
});
|
|
51623
|
+
};
|
|
51624
|
+
|
|
51625
|
+
// src/routing/handlers/send-deploy-session-to-preview-result.ts
|
|
51626
|
+
function sendDeploySessionToPreviewResult(ws, id, payload) {
|
|
51627
|
+
if (!ws) return;
|
|
51628
|
+
sendWsMessage(ws, { type: "deploy_session_to_preview_result", id, ...payload });
|
|
51629
|
+
}
|
|
51630
|
+
|
|
51631
|
+
// src/routing/handlers/deploy-session-to-preview.ts
|
|
51632
|
+
var handleDeploySessionToPreviewMessage = (msg, deps) => {
|
|
51633
|
+
if (typeof msg.id !== "string") return;
|
|
51634
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
51635
|
+
const environmentId = typeof msg.environmentId === "string" ? msg.environmentId : "";
|
|
51636
|
+
if (!sessionId || !environmentId) return;
|
|
51637
|
+
void (async () => {
|
|
51638
|
+
const ws = deps.getWs();
|
|
51639
|
+
const reply = (payload) => sendDeploySessionToPreviewResult(ws, msg.id, payload);
|
|
51640
|
+
try {
|
|
51641
|
+
if (!deps.previewWorktreeManager) {
|
|
51642
|
+
reply({ ok: false, error: "Preview worktree manager unavailable" });
|
|
51643
|
+
return;
|
|
51644
|
+
}
|
|
51645
|
+
const result = await deploySessionToPreviewEnvironment({
|
|
51646
|
+
sessionWorktreeManager: deps.sessionWorktreeManager,
|
|
51647
|
+
previewWorktreeManager: deps.previewWorktreeManager,
|
|
51648
|
+
sessionId,
|
|
51649
|
+
environmentId,
|
|
51650
|
+
log: deps.log
|
|
51651
|
+
});
|
|
51652
|
+
reply(result);
|
|
51653
|
+
} catch (e) {
|
|
51654
|
+
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
51655
|
+
}
|
|
51656
|
+
})();
|
|
51657
|
+
};
|
|
51658
|
+
|
|
51659
|
+
// src/routing/dispatch/preview.ts
|
|
51660
|
+
function dispatchBridgePreviewMessage(msg, deps) {
|
|
51661
|
+
switch (msg.type) {
|
|
51662
|
+
case "preview_environments_config":
|
|
51663
|
+
handlePreviewEnvironmentsConfig(msg, deps);
|
|
51664
|
+
break;
|
|
51665
|
+
case "preview_environment_control":
|
|
51666
|
+
handlePreviewEnvironmentControl(msg, deps);
|
|
51667
|
+
break;
|
|
51668
|
+
case "deploy_session_to_preview":
|
|
51669
|
+
handleDeploySessionToPreviewMessage(msg, deps);
|
|
51670
|
+
break;
|
|
51671
|
+
}
|
|
51672
|
+
}
|
|
51673
|
+
|
|
51567
51674
|
// src/agents/acp/from-bridge/handle-bridge-agent-config.ts
|
|
51568
51675
|
function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
51569
51676
|
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
|
|
@@ -52202,367 +52309,505 @@ var handleSessionRequestResponseMessage = (msg, deps) => {
|
|
|
52202
52309
|
handleBridgeSessionRequestResponse(msg, deps);
|
|
52203
52310
|
};
|
|
52204
52311
|
|
|
52205
|
-
// src/
|
|
52206
|
-
|
|
52207
|
-
|
|
52208
|
-
|
|
52209
|
-
|
|
52210
|
-
|
|
52211
|
-
|
|
52212
|
-
|
|
52213
|
-
var previewProcess = null;
|
|
52214
|
-
var previewPort = DEFAULT_PORT;
|
|
52215
|
-
var previewSecret = "";
|
|
52216
|
-
function getPreviewCommand() {
|
|
52217
|
-
return process.env[PREVIEW_COMMAND_ENV]?.trim() || DEFAULT_COMMAND;
|
|
52218
|
-
}
|
|
52219
|
-
function randomSecret() {
|
|
52220
|
-
const bytes = new Uint8Array(32);
|
|
52221
|
-
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
52222
|
-
crypto.getRandomValues(bytes);
|
|
52312
|
+
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
52313
|
+
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
52314
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
52315
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
52316
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
52317
|
+
if (!branch.trim() || !message.trim()) {
|
|
52318
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
52319
|
+
return;
|
|
52223
52320
|
}
|
|
52224
|
-
|
|
52225
|
-
|
|
52226
|
-
|
|
52227
|
-
|
|
52228
|
-
|
|
52229
|
-
[PREVIEW_SECRET_HEADER]: secret,
|
|
52230
|
-
"Content-Type": "application/json"
|
|
52231
|
-
};
|
|
52232
|
-
const res = await fetch(url2, {
|
|
52233
|
-
method,
|
|
52234
|
-
headers,
|
|
52235
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
52321
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
52322
|
+
sessionId,
|
|
52323
|
+
branch: branch.trim(),
|
|
52324
|
+
message: message.trim(),
|
|
52325
|
+
push: pushAfterCommit
|
|
52236
52326
|
});
|
|
52237
|
-
|
|
52238
|
-
|
|
52239
|
-
|
|
52327
|
+
if (!commitRes.ok) {
|
|
52328
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
52329
|
+
return;
|
|
52240
52330
|
}
|
|
52241
|
-
|
|
52331
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52332
|
+
reply({
|
|
52333
|
+
ok: true,
|
|
52334
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52335
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52336
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
52337
|
+
});
|
|
52242
52338
|
}
|
|
52243
|
-
|
|
52244
|
-
|
|
52245
|
-
|
|
52246
|
-
|
|
52247
|
-
|
|
52248
|
-
|
|
52249
|
-
|
|
52250
|
-
|
|
52251
|
-
|
|
52252
|
-
|
|
52253
|
-
|
|
52254
|
-
|
|
52255
|
-
|
|
52256
|
-
|
|
52257
|
-
|
|
52258
|
-
|
|
52259
|
-
|
|
52339
|
+
|
|
52340
|
+
// src/routing/handlers/git/session-git-changes-params.ts
|
|
52341
|
+
function readString(value) {
|
|
52342
|
+
return typeof value === "string" ? value.trim() : "";
|
|
52343
|
+
}
|
|
52344
|
+
function readChangesObject(msg) {
|
|
52345
|
+
const changes = msg.changes;
|
|
52346
|
+
if (!changes || typeof changes !== "object" || Array.isArray(changes)) return null;
|
|
52347
|
+
return changes;
|
|
52348
|
+
}
|
|
52349
|
+
function parseSessionGitChangesParams(msg) {
|
|
52350
|
+
const nested = readChangesObject(msg);
|
|
52351
|
+
const file2 = nested?.file && typeof nested.file === "object" && !Array.isArray(nested.file) ? nested.file : null;
|
|
52352
|
+
const repoRelPath = readString(nested?.repoRelPath) || readString(msg.changesRepoRelPath);
|
|
52353
|
+
const viewRaw = nested?.view ?? msg.changesView;
|
|
52354
|
+
const view = viewRaw === "commit" ? "commit" : "working";
|
|
52355
|
+
const commitSha = readString(nested?.commitSha) || readString(msg.changesCommitSha);
|
|
52356
|
+
const recentCommitsLimit = nested?.recentCommitsLimit ?? msg.changesRecentCommitsLimit;
|
|
52357
|
+
return {
|
|
52358
|
+
repoRelPath,
|
|
52359
|
+
view,
|
|
52360
|
+
commitSha,
|
|
52361
|
+
recentCommitsLimit: typeof recentCommitsLimit === "number" || typeof recentCommitsLimit === "string" ? recentCommitsLimit : void 0,
|
|
52362
|
+
fileWorkspaceRelPath: readString(file2?.workspaceRelPath),
|
|
52363
|
+
fileChange: readString(file2?.change),
|
|
52364
|
+
fileMovedFromWorkspaceRelPath: readString(file2?.movedFromWorkspaceRelPath)
|
|
52365
|
+
};
|
|
52366
|
+
}
|
|
52367
|
+
|
|
52368
|
+
// src/routing/handlers/git/handle-session-git-get-change-file-patch.ts
|
|
52369
|
+
async function handleSessionGitGetChangeFilePatchAction(deps, msg, reply) {
|
|
52370
|
+
const changes = parseSessionGitChangesParams(msg);
|
|
52371
|
+
const { repoRelPath: repoRel, view, commitSha, fileWorkspaceRelPath, fileChange, fileMovedFromWorkspaceRelPath } = changes;
|
|
52372
|
+
const change = parseWorkingTreeChangeKind(fileChange);
|
|
52373
|
+
if (!repoRel || !fileWorkspaceRelPath || !change) {
|
|
52374
|
+
reply({
|
|
52375
|
+
ok: false,
|
|
52376
|
+
error: "changes.repoRelPath, changes.file.workspaceRelPath, and changes.file.change are required"
|
|
52377
|
+
});
|
|
52378
|
+
return;
|
|
52260
52379
|
}
|
|
52261
|
-
|
|
52262
|
-
|
|
52263
|
-
|
|
52264
|
-
name: "Preview",
|
|
52265
|
-
description: "Start and manage a local preview server that implements the BuildAutomaton Preview Server API. Configure the command with BUILDAUTOMATON_PREVIEW_COMMAND (default: npm run preview). The server receives PORT and PREVIEW_SECRET and must expose /__preview/status and /__preview/stop.",
|
|
52266
|
-
operations: OPERATIONS,
|
|
52267
|
-
async execute(operationId, params) {
|
|
52268
|
-
const command = getPreviewCommand();
|
|
52269
|
-
switch (operationId) {
|
|
52270
|
-
case "start": {
|
|
52271
|
-
if (previewProcess) {
|
|
52272
|
-
return {
|
|
52273
|
-
ok: false,
|
|
52274
|
-
message: "Preview server already running",
|
|
52275
|
-
url: `http://localhost:${previewPort}`
|
|
52276
|
-
};
|
|
52277
|
-
}
|
|
52278
|
-
const port = params.port ?? (Number(process.env[PREVIEW_PORT_ENV]) || DEFAULT_PORT);
|
|
52279
|
-
previewPort = port;
|
|
52280
|
-
previewSecret = randomSecret();
|
|
52281
|
-
const isWindows = process.platform === "win32";
|
|
52282
|
-
const parts = command.split(/\s+/);
|
|
52283
|
-
const exe = parts[0];
|
|
52284
|
-
const args = parts.slice(1);
|
|
52285
|
-
previewProcess = spawn10(isWindows && exe === "npm" ? "npm.cmd" : exe, args, {
|
|
52286
|
-
cwd: getBridgeRoot(),
|
|
52287
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
52288
|
-
env: {
|
|
52289
|
-
...process.env,
|
|
52290
|
-
PORT: String(port),
|
|
52291
|
-
PREVIEW_SECRET: previewSecret
|
|
52292
|
-
}
|
|
52293
|
-
});
|
|
52294
|
-
previewProcess.stdout?.on("data", (d) => process.stdout.write(d));
|
|
52295
|
-
previewProcess.stderr?.on("data", (d) => process.stderr.write(d));
|
|
52296
|
-
previewProcess.on("exit", (code) => {
|
|
52297
|
-
previewProcess = null;
|
|
52298
|
-
if (code !== null && code !== 0) {
|
|
52299
|
-
process.stderr.write(`Preview server exited with code ${code}
|
|
52300
|
-
`);
|
|
52301
|
-
}
|
|
52302
|
-
});
|
|
52303
|
-
return {
|
|
52304
|
-
ok: true,
|
|
52305
|
-
message: `Preview server starting (${command}, port=${port})`,
|
|
52306
|
-
url: `http://localhost:${port}`,
|
|
52307
|
-
port
|
|
52308
|
-
};
|
|
52309
|
-
}
|
|
52310
|
-
case "stop": {
|
|
52311
|
-
if (!previewProcess) {
|
|
52312
|
-
return { ok: true, message: "No preview server was running" };
|
|
52313
|
-
}
|
|
52314
|
-
if (!previewSecret) {
|
|
52315
|
-
previewProcess.kill("SIGTERM");
|
|
52316
|
-
previewProcess = null;
|
|
52317
|
-
return { ok: true, message: "Preview process stopped (no secret)" };
|
|
52318
|
-
}
|
|
52319
|
-
try {
|
|
52320
|
-
await requestPreviewApi(
|
|
52321
|
-
previewPort,
|
|
52322
|
-
previewSecret,
|
|
52323
|
-
"POST",
|
|
52324
|
-
`${PREVIEW_API_BASE_PATH}/stop`
|
|
52325
|
-
);
|
|
52326
|
-
} catch (e) {
|
|
52327
|
-
previewProcess.kill("SIGTERM");
|
|
52328
|
-
}
|
|
52329
|
-
previewProcess = null;
|
|
52330
|
-
previewSecret = "";
|
|
52331
|
-
return { ok: true, message: "Preview server stop requested" };
|
|
52332
|
-
}
|
|
52333
|
-
case "status": {
|
|
52334
|
-
if (!previewProcess || !previewSecret) {
|
|
52335
|
-
return {
|
|
52336
|
-
running: previewProcess != null,
|
|
52337
|
-
url: previewProcess ? `http://localhost:${previewPort}` : void 0,
|
|
52338
|
-
message: previewProcess ? `Process running at http://localhost:${previewPort}` : "No preview server running"
|
|
52339
|
-
};
|
|
52340
|
-
}
|
|
52341
|
-
try {
|
|
52342
|
-
const status = await requestPreviewApi(
|
|
52343
|
-
previewPort,
|
|
52344
|
-
previewSecret,
|
|
52345
|
-
"GET",
|
|
52346
|
-
`${PREVIEW_API_BASE_PATH}/status`
|
|
52347
|
-
);
|
|
52348
|
-
return {
|
|
52349
|
-
running: status.status === "running",
|
|
52350
|
-
status: status.status,
|
|
52351
|
-
url: status.url ?? `http://localhost:${previewPort}`,
|
|
52352
|
-
message: status.message ?? (status.status === "running" ? "Preview server running" : "Stopping")
|
|
52353
|
-
};
|
|
52354
|
-
} catch {
|
|
52355
|
-
return {
|
|
52356
|
-
running: previewProcess != null,
|
|
52357
|
-
url: `http://localhost:${previewPort}`,
|
|
52358
|
-
message: "Process running but status endpoint unreachable (server may not implement Preview Server API yet)"
|
|
52359
|
-
};
|
|
52360
|
-
}
|
|
52361
|
-
}
|
|
52362
|
-
default:
|
|
52363
|
-
throw new Error(`Unknown operation: ${operationId}`);
|
|
52364
|
-
}
|
|
52380
|
+
if (view === "commit" && !commitSha) {
|
|
52381
|
+
reply({ ok: false, error: "changes.commitSha is required for commit file patch" });
|
|
52382
|
+
return;
|
|
52365
52383
|
}
|
|
52366
|
-
|
|
52384
|
+
const patch = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeFilePatch(msg.sessionId, {
|
|
52385
|
+
repoRelPath: repoRel,
|
|
52386
|
+
workspaceRelPath: fileWorkspaceRelPath,
|
|
52387
|
+
change,
|
|
52388
|
+
movedFromWorkspaceRelPath: fileMovedFromWorkspaceRelPath || null,
|
|
52389
|
+
basis: view === "commit" ? { kind: "commit", sha: commitSha } : { kind: "working" }
|
|
52390
|
+
});
|
|
52391
|
+
reply(
|
|
52392
|
+
{
|
|
52393
|
+
ok: true,
|
|
52394
|
+
patchContent: patch.patchContent ?? null,
|
|
52395
|
+
totalLines: patch.totalLines
|
|
52396
|
+
},
|
|
52397
|
+
["patchContent"]
|
|
52398
|
+
);
|
|
52399
|
+
}
|
|
52367
52400
|
|
|
52368
|
-
// src/
|
|
52369
|
-
var
|
|
52370
|
-
function
|
|
52371
|
-
|
|
52401
|
+
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
52402
|
+
var listChangesInflight = /* @__PURE__ */ new Map();
|
|
52403
|
+
function normalizeListChangesRepoPathRelativeToWorkspaceRoot(repoRelPath) {
|
|
52404
|
+
if (!repoRelPath?.trim()) return "";
|
|
52405
|
+
return normalizeRepoPathRelativeToWorkspaceRoot(repoRelPath.trim());
|
|
52372
52406
|
}
|
|
52373
|
-
|
|
52374
|
-
const
|
|
52375
|
-
|
|
52376
|
-
|
|
52407
|
+
function listChangesInflightKey(sessionId, opts) {
|
|
52408
|
+
const basis = opts?.basis;
|
|
52409
|
+
return [
|
|
52410
|
+
sessionId,
|
|
52411
|
+
normalizeListChangesRepoPathRelativeToWorkspaceRoot(opts?.repoRelPath),
|
|
52412
|
+
basis?.kind === "commit" ? `commit:${basis.sha}` : "working",
|
|
52413
|
+
String(opts?.recentCommitsLimit ?? "")
|
|
52414
|
+
].join("|");
|
|
52377
52415
|
}
|
|
52378
|
-
|
|
52379
|
-
|
|
52380
|
-
|
|
52381
|
-
|
|
52382
|
-
|
|
52383
|
-
|
|
52384
|
-
sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
|
|
52385
|
-
log2(`[Bridge service] Skill invocation failed (${msg.skillId}/${msg.operationId}): ${err}`);
|
|
52416
|
+
function getSessionWorkingTreeChangeDetailsCoalesced(sessionWorktreeManager, sessionId, opts) {
|
|
52417
|
+
const key = listChangesInflightKey(sessionId, opts);
|
|
52418
|
+
const existing = listChangesInflight.get(key);
|
|
52419
|
+
if (existing) return existing;
|
|
52420
|
+
const promise2 = sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts).finally(() => {
|
|
52421
|
+
if (listChangesInflight.get(key) === promise2) listChangesInflight.delete(key);
|
|
52386
52422
|
});
|
|
52423
|
+
listChangesInflight.set(key, promise2);
|
|
52424
|
+
return promise2;
|
|
52387
52425
|
}
|
|
52388
52426
|
|
|
52389
|
-
// src/routing/handlers/
|
|
52390
|
-
|
|
52391
|
-
const
|
|
52392
|
-
const
|
|
52393
|
-
if (
|
|
52394
|
-
|
|
52395
|
-
|
|
52396
|
-
|
|
52397
|
-
|
|
52398
|
-
|
|
52399
|
-
|
|
52427
|
+
// src/routing/handlers/git/handle-session-git-list-changes.ts
|
|
52428
|
+
async function handleSessionGitListChangesAction(deps, msg, reply) {
|
|
52429
|
+
const changes = parseSessionGitChangesParams(msg);
|
|
52430
|
+
const { repoRelPath: repoRel, view, commitSha, recentCommitsLimit } = changes;
|
|
52431
|
+
if (view === "commit") {
|
|
52432
|
+
if (!repoRel || !commitSha) {
|
|
52433
|
+
reply({
|
|
52434
|
+
ok: false,
|
|
52435
|
+
error: "changes.repoRelPath and changes.commitSha are required for commit view"
|
|
52436
|
+
});
|
|
52437
|
+
return;
|
|
52438
|
+
}
|
|
52439
|
+
}
|
|
52440
|
+
const opts = repoRel && view === "commit" && commitSha ? {
|
|
52441
|
+
repoRelPath: repoRel,
|
|
52442
|
+
basis: { kind: "commit", sha: commitSha },
|
|
52443
|
+
recentCommitsLimit
|
|
52444
|
+
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
52445
|
+
const repos = await getSessionWorkingTreeChangeDetailsCoalesced(
|
|
52446
|
+
deps.sessionWorktreeManager,
|
|
52447
|
+
msg.sessionId,
|
|
52448
|
+
opts
|
|
52400
52449
|
);
|
|
52401
|
-
};
|
|
52402
|
-
|
|
52403
|
-
// src/files/browser/send-file-browser-message.ts
|
|
52404
|
-
function sendFileBrowserMessage(socket, e2ee, payload) {
|
|
52405
|
-
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
|
|
52450
|
+
reply({ ok: true, repos }, ["repos"]);
|
|
52406
52451
|
}
|
|
52407
52452
|
|
|
52408
|
-
// src/
|
|
52409
|
-
async function
|
|
52410
|
-
const
|
|
52411
|
-
if (
|
|
52412
|
-
|
|
52453
|
+
// src/routing/handlers/git/handle-session-git-push.ts
|
|
52454
|
+
async function handleSessionGitPushAction(deps, sessionId, reply) {
|
|
52455
|
+
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
52456
|
+
if (!pushRes.ok) {
|
|
52457
|
+
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
52413
52458
|
return;
|
|
52414
52459
|
}
|
|
52415
|
-
|
|
52460
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52461
|
+
reply({
|
|
52462
|
+
ok: true,
|
|
52463
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52464
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52465
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
52466
|
+
});
|
|
52416
52467
|
}
|
|
52417
52468
|
|
|
52418
|
-
// src/
|
|
52419
|
-
async function
|
|
52420
|
-
const
|
|
52421
|
-
|
|
52422
|
-
|
|
52423
|
-
|
|
52469
|
+
// src/routing/handlers/git/handle-session-git-status.ts
|
|
52470
|
+
async function handleSessionGitStatusAction(deps, sessionId, reply) {
|
|
52471
|
+
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52472
|
+
reply({
|
|
52473
|
+
ok: true,
|
|
52474
|
+
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
52475
|
+
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
52476
|
+
uncommittedFileCount: r.uncommittedFileCount
|
|
52477
|
+
});
|
|
52478
|
+
}
|
|
52479
|
+
|
|
52480
|
+
// src/routing/handlers/git/send-session-git-result.ts
|
|
52481
|
+
function sendSessionGitResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
52482
|
+
if (!ws) return;
|
|
52483
|
+
const message = { type: "session_git_result", id, ...payload };
|
|
52484
|
+
let wire = message;
|
|
52485
|
+
if (e2ee && encryptedFields.length > 0) {
|
|
52486
|
+
wire = e2ee.encryptFields(message, encryptedFields);
|
|
52424
52487
|
}
|
|
52425
|
-
|
|
52426
|
-
type: "file_browser_response",
|
|
52427
|
-
id: msg.id,
|
|
52428
|
-
content: result.content,
|
|
52429
|
-
totalLines: result.totalLines,
|
|
52430
|
-
size: result.size
|
|
52431
|
-
};
|
|
52432
|
-
if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
|
|
52433
|
-
if (result.mimeType != null) payload.mimeType = result.mimeType;
|
|
52434
|
-
if (result.resolvedPath != null) payload.resolvedPath = result.resolvedPath;
|
|
52435
|
-
sendFileBrowserMessage(socket, e2ee, payload);
|
|
52488
|
+
sendWsMessage(ws, wire);
|
|
52436
52489
|
}
|
|
52437
52490
|
|
|
52438
|
-
// src/
|
|
52439
|
-
|
|
52440
|
-
|
|
52441
|
-
|
|
52491
|
+
// src/routing/handlers/git/session-git-request.ts
|
|
52492
|
+
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
52493
|
+
if (typeof msg.id !== "string") return;
|
|
52494
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52495
|
+
const action = msg.action;
|
|
52496
|
+
if (!sessionId || action !== "status" && action !== "push" && action !== "commit" && action !== "list_changes" && action !== "file_diff")
|
|
52497
|
+
return;
|
|
52442
52498
|
void (async () => {
|
|
52499
|
+
const ws = deps.getWs();
|
|
52500
|
+
const reply = (payload, encryptedFields = []) => sendSessionGitResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
52443
52501
|
try {
|
|
52444
|
-
|
|
52445
|
-
|
|
52446
|
-
const gitScope = resolveGitBranchScope(msg);
|
|
52447
|
-
if (msg.source === "git_branch" && typeof msg.repoRelPath === "string" && typeof msg.branch === "string" && msg.branch.trim().length > 0 && !gitScope) {
|
|
52448
|
-
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: "Invalid repository path" });
|
|
52502
|
+
if (action === "status") {
|
|
52503
|
+
await handleSessionGitStatusAction(deps, sessionId, reply);
|
|
52449
52504
|
return;
|
|
52450
52505
|
}
|
|
52451
|
-
if (
|
|
52452
|
-
await
|
|
52453
|
-
|
|
52454
|
-
await handleFileBrowserList(socket, e2ee, msg.id, reqPath, sessionParentPath, gitScope);
|
|
52506
|
+
if (action === "list_changes") {
|
|
52507
|
+
await handleSessionGitListChangesAction(deps, { ...msg, sessionId }, reply);
|
|
52508
|
+
return;
|
|
52455
52509
|
}
|
|
52456
|
-
|
|
52457
|
-
|
|
52510
|
+
if (action === "file_diff") {
|
|
52511
|
+
await handleSessionGitGetChangeFilePatchAction(deps, { ...msg, sessionId }, reply);
|
|
52512
|
+
return;
|
|
52513
|
+
}
|
|
52514
|
+
if (action === "push") {
|
|
52515
|
+
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
52516
|
+
return;
|
|
52517
|
+
}
|
|
52518
|
+
await handleSessionGitCommitAction(deps, sessionId, msg, reply);
|
|
52519
|
+
} catch (e) {
|
|
52520
|
+
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
52458
52521
|
}
|
|
52459
52522
|
})();
|
|
52460
|
-
}
|
|
52523
|
+
};
|
|
52461
52524
|
|
|
52462
|
-
// src/
|
|
52463
|
-
|
|
52464
|
-
|
|
52465
|
-
|
|
52466
|
-
|
|
52467
|
-
void (
|
|
52468
|
-
|
|
52469
|
-
|
|
52470
|
-
|
|
52471
|
-
|
|
52472
|
-
|
|
52473
|
-
|
|
52474
|
-
|
|
52475
|
-
|
|
52476
|
-
|
|
52477
|
-
|
|
52478
|
-
|
|
52479
|
-
|
|
52480
|
-
|
|
52481
|
-
|
|
52525
|
+
// src/routing/handlers/rename-session-branch.ts
|
|
52526
|
+
var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
52527
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52528
|
+
const newBranch = typeof msg.newBranch === "string" ? msg.newBranch : "";
|
|
52529
|
+
if (!sessionId || !newBranch) return;
|
|
52530
|
+
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
52531
|
+
};
|
|
52532
|
+
|
|
52533
|
+
// src/routing/handlers/session-archived.ts
|
|
52534
|
+
var handleSessionArchivedMessage = (msg, deps) => {
|
|
52535
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52536
|
+
if (!sessionId) return;
|
|
52537
|
+
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
52538
|
+
};
|
|
52539
|
+
|
|
52540
|
+
// src/routing/handlers/session-discarded.ts
|
|
52541
|
+
var handleSessionDiscardedMessage = (msg, deps) => {
|
|
52542
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52543
|
+
if (!sessionId) return;
|
|
52544
|
+
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
52545
|
+
};
|
|
52546
|
+
|
|
52547
|
+
// src/routing/handlers/revert-turn-snapshot.ts
|
|
52548
|
+
import * as fs60 from "node:fs";
|
|
52549
|
+
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
52550
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52551
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
52552
|
+
const turnId = typeof msg.turnId === "string" ? msg.turnId : "";
|
|
52553
|
+
if (!id || !sessionId || !turnId) return;
|
|
52554
|
+
const { getWs, log: log2, sessionWorktreeManager } = deps;
|
|
52555
|
+
void (async () => {
|
|
52556
|
+
const s = getWs();
|
|
52557
|
+
if (!s) return;
|
|
52558
|
+
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
52559
|
+
const file2 = snapshotFilePath(agentBase, turnId);
|
|
52560
|
+
try {
|
|
52561
|
+
await fs60.promises.access(file2, fs60.constants.F_OK);
|
|
52562
|
+
} catch {
|
|
52563
|
+
sendWsMessage(s, {
|
|
52564
|
+
type: "revert_turn_snapshot_result",
|
|
52565
|
+
id,
|
|
52566
|
+
ok: false,
|
|
52567
|
+
error: "No snapshot found for this turn (git state may be unavailable)."
|
|
52568
|
+
});
|
|
52482
52569
|
return;
|
|
52483
52570
|
}
|
|
52484
|
-
const
|
|
52485
|
-
|
|
52486
|
-
type: "
|
|
52487
|
-
id
|
|
52488
|
-
|
|
52489
|
-
|
|
52490
|
-
};
|
|
52491
|
-
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
|
|
52492
|
-
})();
|
|
52493
|
-
}
|
|
52494
|
-
function triggerFileIndexBuild(sessionParentPath = getBridgeRoot()) {
|
|
52495
|
-
setImmediate(() => {
|
|
52496
|
-
void ensureFileIndexAsync(sessionParentPath).catch((e) => {
|
|
52497
|
-
console.error("[file-index] Background build failed:", e);
|
|
52571
|
+
const res = await applyPreTurnSnapshot(file2, log2);
|
|
52572
|
+
sendWsMessage(s, {
|
|
52573
|
+
type: "revert_turn_snapshot_result",
|
|
52574
|
+
id,
|
|
52575
|
+
ok: res.ok,
|
|
52576
|
+
...res.error ? { error: res.error } : {}
|
|
52498
52577
|
});
|
|
52499
|
-
});
|
|
52578
|
+
})();
|
|
52579
|
+
};
|
|
52580
|
+
|
|
52581
|
+
// src/routing/dispatch/session.ts
|
|
52582
|
+
function dispatchBridgeSessionMessage(msg, deps) {
|
|
52583
|
+
switch (msg.type) {
|
|
52584
|
+
case "agent_config":
|
|
52585
|
+
handleAgentConfigMessage(msg, deps);
|
|
52586
|
+
break;
|
|
52587
|
+
case "prompt_queue_state":
|
|
52588
|
+
handlePromptQueueStateMessage(msg, deps);
|
|
52589
|
+
break;
|
|
52590
|
+
case "prompt":
|
|
52591
|
+
handlePromptMessage(msg, deps);
|
|
52592
|
+
break;
|
|
52593
|
+
case "session_git_request":
|
|
52594
|
+
handleSessionGitRequestMessage(msg, deps);
|
|
52595
|
+
break;
|
|
52596
|
+
case "rename_session_branch":
|
|
52597
|
+
handleRenameSessionBranchMessage(msg, deps);
|
|
52598
|
+
break;
|
|
52599
|
+
case "session_archived":
|
|
52600
|
+
handleSessionArchivedMessage(msg, deps);
|
|
52601
|
+
break;
|
|
52602
|
+
case "session_discarded":
|
|
52603
|
+
handleSessionDiscardedMessage(msg, deps);
|
|
52604
|
+
break;
|
|
52605
|
+
case "revert_turn_snapshot":
|
|
52606
|
+
handleRevertTurnSnapshotMessage(msg, deps);
|
|
52607
|
+
break;
|
|
52608
|
+
case "cursor_request_response":
|
|
52609
|
+
handleSessionRequestResponseMessage(msg, deps);
|
|
52610
|
+
break;
|
|
52611
|
+
}
|
|
52500
52612
|
}
|
|
52501
52613
|
|
|
52502
|
-
// src/
|
|
52503
|
-
|
|
52504
|
-
|
|
52505
|
-
|
|
52506
|
-
|
|
52507
|
-
|
|
52614
|
+
// src/skills/preview.ts
|
|
52615
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
52616
|
+
var PREVIEW_API_BASE_PATH = "/__preview";
|
|
52617
|
+
var PREVIEW_SECRET_HEADER = "X-Preview-Secret";
|
|
52618
|
+
var DEFAULT_PORT = 3e3;
|
|
52619
|
+
var DEFAULT_COMMAND = "npm run preview";
|
|
52620
|
+
var PREVIEW_COMMAND_ENV = "BUILDAUTOMATON_PREVIEW_COMMAND";
|
|
52621
|
+
var PREVIEW_PORT_ENV = "BUILDAUTOMATON_PREVIEW_PORT";
|
|
52622
|
+
var previewProcess = null;
|
|
52623
|
+
var previewPort = DEFAULT_PORT;
|
|
52624
|
+
var previewSecret = "";
|
|
52625
|
+
function getPreviewCommand() {
|
|
52626
|
+
return process.env[PREVIEW_COMMAND_ENV]?.trim() || DEFAULT_COMMAND;
|
|
52508
52627
|
}
|
|
52509
|
-
function
|
|
52510
|
-
|
|
52511
|
-
|
|
52512
|
-
|
|
52513
|
-
|
|
52514
|
-
|
|
52515
|
-
socket,
|
|
52516
|
-
e2ee,
|
|
52517
|
-
sessionWorktreeManager
|
|
52518
|
-
);
|
|
52628
|
+
function randomSecret() {
|
|
52629
|
+
const bytes = new Uint8Array(32);
|
|
52630
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
52631
|
+
crypto.getRandomValues(bytes);
|
|
52632
|
+
}
|
|
52633
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
52519
52634
|
}
|
|
52520
|
-
|
|
52521
|
-
|
|
52522
|
-
|
|
52523
|
-
|
|
52524
|
-
|
|
52525
|
-
|
|
52526
|
-
|
|
52527
|
-
|
|
52528
|
-
|
|
52635
|
+
async function requestPreviewApi(port, secret, method, path84, body) {
|
|
52636
|
+
const url2 = `http://127.0.0.1:${port}${path84}`;
|
|
52637
|
+
const headers = {
|
|
52638
|
+
[PREVIEW_SECRET_HEADER]: secret,
|
|
52639
|
+
"Content-Type": "application/json"
|
|
52640
|
+
};
|
|
52641
|
+
const res = await fetch(url2, {
|
|
52642
|
+
method,
|
|
52643
|
+
headers,
|
|
52644
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
52645
|
+
});
|
|
52646
|
+
const data = await res.json().catch(() => ({}));
|
|
52647
|
+
if (!res.ok) {
|
|
52648
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path84}: ${res.status}`);
|
|
52649
|
+
}
|
|
52650
|
+
return data;
|
|
52529
52651
|
}
|
|
52652
|
+
var OPERATIONS = [
|
|
52653
|
+
{
|
|
52654
|
+
id: "start",
|
|
52655
|
+
description: "Start the preview server process (runs the configured command with PORT and PREVIEW_SECRET).",
|
|
52656
|
+
params: [
|
|
52657
|
+
{ name: "port", description: "Port for the preview server", type: "number", required: false }
|
|
52658
|
+
]
|
|
52659
|
+
},
|
|
52660
|
+
{
|
|
52661
|
+
id: "stop",
|
|
52662
|
+
description: "Stop the preview server via POST /__preview/stop (graceful shutdown).",
|
|
52663
|
+
params: []
|
|
52664
|
+
},
|
|
52665
|
+
{
|
|
52666
|
+
id: "status",
|
|
52667
|
+
description: "Return status from GET /__preview/status (running, url).",
|
|
52668
|
+
params: []
|
|
52669
|
+
}
|
|
52670
|
+
];
|
|
52671
|
+
var previewSkill = {
|
|
52672
|
+
id: "preview",
|
|
52673
|
+
name: "Preview",
|
|
52674
|
+
description: "Start and manage a local preview server that implements the BuildAutomaton Preview Server API. Configure the command with BUILDAUTOMATON_PREVIEW_COMMAND (default: npm run preview). The server receives PORT and PREVIEW_SECRET and must expose /__preview/status and /__preview/stop.",
|
|
52675
|
+
operations: OPERATIONS,
|
|
52676
|
+
async execute(operationId, params) {
|
|
52677
|
+
const command = getPreviewCommand();
|
|
52678
|
+
switch (operationId) {
|
|
52679
|
+
case "start": {
|
|
52680
|
+
if (previewProcess) {
|
|
52681
|
+
return {
|
|
52682
|
+
ok: false,
|
|
52683
|
+
message: "Preview server already running",
|
|
52684
|
+
url: `http://localhost:${previewPort}`
|
|
52685
|
+
};
|
|
52686
|
+
}
|
|
52687
|
+
const port = params.port ?? (Number(process.env[PREVIEW_PORT_ENV]) || DEFAULT_PORT);
|
|
52688
|
+
previewPort = port;
|
|
52689
|
+
previewSecret = randomSecret();
|
|
52690
|
+
const isWindows = process.platform === "win32";
|
|
52691
|
+
const parts = command.split(/\s+/);
|
|
52692
|
+
const exe = parts[0];
|
|
52693
|
+
const args = parts.slice(1);
|
|
52694
|
+
previewProcess = spawn10(isWindows && exe === "npm" ? "npm.cmd" : exe, args, {
|
|
52695
|
+
cwd: getBridgeRoot(),
|
|
52696
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
52697
|
+
env: {
|
|
52698
|
+
...process.env,
|
|
52699
|
+
PORT: String(port),
|
|
52700
|
+
PREVIEW_SECRET: previewSecret
|
|
52701
|
+
}
|
|
52702
|
+
});
|
|
52703
|
+
previewProcess.stdout?.on("data", (d) => process.stdout.write(d));
|
|
52704
|
+
previewProcess.stderr?.on("data", (d) => process.stderr.write(d));
|
|
52705
|
+
previewProcess.on("exit", (code) => {
|
|
52706
|
+
previewProcess = null;
|
|
52707
|
+
if (code !== null && code !== 0) {
|
|
52708
|
+
process.stderr.write(`Preview server exited with code ${code}
|
|
52709
|
+
`);
|
|
52710
|
+
}
|
|
52711
|
+
});
|
|
52712
|
+
return {
|
|
52713
|
+
ok: true,
|
|
52714
|
+
message: `Preview server starting (${command}, port=${port})`,
|
|
52715
|
+
url: `http://localhost:${port}`,
|
|
52716
|
+
port
|
|
52717
|
+
};
|
|
52718
|
+
}
|
|
52719
|
+
case "stop": {
|
|
52720
|
+
if (!previewProcess) {
|
|
52721
|
+
return { ok: true, message: "No preview server was running" };
|
|
52722
|
+
}
|
|
52723
|
+
if (!previewSecret) {
|
|
52724
|
+
previewProcess.kill("SIGTERM");
|
|
52725
|
+
previewProcess = null;
|
|
52726
|
+
return { ok: true, message: "Preview process stopped (no secret)" };
|
|
52727
|
+
}
|
|
52728
|
+
try {
|
|
52729
|
+
await requestPreviewApi(
|
|
52730
|
+
previewPort,
|
|
52731
|
+
previewSecret,
|
|
52732
|
+
"POST",
|
|
52733
|
+
`${PREVIEW_API_BASE_PATH}/stop`
|
|
52734
|
+
);
|
|
52735
|
+
} catch (e) {
|
|
52736
|
+
previewProcess.kill("SIGTERM");
|
|
52737
|
+
}
|
|
52738
|
+
previewProcess = null;
|
|
52739
|
+
previewSecret = "";
|
|
52740
|
+
return { ok: true, message: "Preview server stop requested" };
|
|
52741
|
+
}
|
|
52742
|
+
case "status": {
|
|
52743
|
+
if (!previewProcess || !previewSecret) {
|
|
52744
|
+
return {
|
|
52745
|
+
running: previewProcess != null,
|
|
52746
|
+
url: previewProcess ? `http://localhost:${previewPort}` : void 0,
|
|
52747
|
+
message: previewProcess ? `Process running at http://localhost:${previewPort}` : "No preview server running"
|
|
52748
|
+
};
|
|
52749
|
+
}
|
|
52750
|
+
try {
|
|
52751
|
+
const status = await requestPreviewApi(
|
|
52752
|
+
previewPort,
|
|
52753
|
+
previewSecret,
|
|
52754
|
+
"GET",
|
|
52755
|
+
`${PREVIEW_API_BASE_PATH}/status`
|
|
52756
|
+
);
|
|
52757
|
+
return {
|
|
52758
|
+
running: status.status === "running",
|
|
52759
|
+
status: status.status,
|
|
52760
|
+
url: status.url ?? `http://localhost:${previewPort}`,
|
|
52761
|
+
message: status.message ?? (status.status === "running" ? "Preview server running" : "Stopping")
|
|
52762
|
+
};
|
|
52763
|
+
} catch {
|
|
52764
|
+
return {
|
|
52765
|
+
running: previewProcess != null,
|
|
52766
|
+
url: `http://localhost:${previewPort}`,
|
|
52767
|
+
message: "Process running but status endpoint unreachable (server may not implement Preview Server API yet)"
|
|
52768
|
+
};
|
|
52769
|
+
}
|
|
52770
|
+
}
|
|
52771
|
+
default:
|
|
52772
|
+
throw new Error(`Unknown operation: ${operationId}`);
|
|
52773
|
+
}
|
|
52774
|
+
}
|
|
52775
|
+
};
|
|
52530
52776
|
|
|
52531
|
-
// src/
|
|
52532
|
-
|
|
52533
|
-
|
|
52534
|
-
|
|
52535
|
-
|
|
52536
|
-
|
|
52537
|
-
|
|
52538
|
-
|
|
52539
|
-
|
|
52540
|
-
})();
|
|
52777
|
+
// src/skills/index.ts
|
|
52778
|
+
var skills = [previewSkill];
|
|
52779
|
+
function getSkill(id) {
|
|
52780
|
+
return skills.find((s) => s.id === id);
|
|
52781
|
+
}
|
|
52782
|
+
async function callSkill(skillId, operationId, params) {
|
|
52783
|
+
const skill = getSkill(skillId);
|
|
52784
|
+
if (!skill) throw new Error(`Skill not found: ${skillId}`);
|
|
52785
|
+
return skill.execute(operationId, params);
|
|
52541
52786
|
}
|
|
52542
52787
|
|
|
52543
|
-
// src/
|
|
52544
|
-
|
|
52788
|
+
// src/skills/handle-skill-call.ts
|
|
52789
|
+
function handleSkillCall(msg, socket, log2) {
|
|
52790
|
+
callSkill(msg.skillId, msg.operationId, msg.params ?? {}).then((result) => {
|
|
52791
|
+
sendWsMessage(socket, { type: "skill_result", id: msg.id, result });
|
|
52792
|
+
}).catch((err) => {
|
|
52793
|
+
sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
|
|
52794
|
+
log2(`[Bridge service] Skill invocation failed (${msg.skillId}/${msg.operationId}): ${err}`);
|
|
52795
|
+
});
|
|
52796
|
+
}
|
|
52545
52797
|
|
|
52546
|
-
// src/routing/handlers/
|
|
52547
|
-
|
|
52548
|
-
|
|
52798
|
+
// src/routing/handlers/skill-call.ts
|
|
52799
|
+
var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
52800
|
+
const skillId = typeof msg.skillId === "string" ? msg.skillId : "";
|
|
52801
|
+
const operationId = typeof msg.operationId === "string" ? msg.operationId : "";
|
|
52802
|
+
if (!skillId || !operationId) return;
|
|
52549
52803
|
const socket = getWs();
|
|
52550
52804
|
if (!socket) return;
|
|
52551
|
-
|
|
52552
|
-
{
|
|
52553
|
-
id: msg.id,
|
|
52554
|
-
type: "code_nav",
|
|
52555
|
-
op: msg.op === "references" ? "references" : msg.op === "symbols" ? "symbols" : msg.op === "definitions" ? "definitions" : "definition",
|
|
52556
|
-
path: msg.path,
|
|
52557
|
-
line: typeof msg.line === "number" ? msg.line : 1,
|
|
52558
|
-
column: typeof msg.column === "number" ? msg.column : 0,
|
|
52559
|
-
sessionId: msg.sessionId
|
|
52560
|
-
},
|
|
52805
|
+
handleSkillCall(
|
|
52806
|
+
{ id: msg.id, skillId, operationId, params: msg.params },
|
|
52561
52807
|
socket,
|
|
52562
|
-
|
|
52563
|
-
sessionWorktreeManager
|
|
52808
|
+
log2
|
|
52564
52809
|
);
|
|
52565
|
-
}
|
|
52810
|
+
};
|
|
52566
52811
|
|
|
52567
52812
|
// src/routing/handlers/skill-layout-request.ts
|
|
52568
52813
|
function handleSkillLayoutRequest(msg, deps) {
|
|
@@ -52585,413 +52830,409 @@ function isValidRemoteSkillInstallItem(item) {
|
|
|
52585
52830
|
|
|
52586
52831
|
// src/skills/install/install-remote-skills-async.ts
|
|
52587
52832
|
init_yield_to_event_loop();
|
|
52588
|
-
import
|
|
52589
|
-
import
|
|
52833
|
+
import fs61 from "node:fs";
|
|
52834
|
+
import path80 from "node:path";
|
|
52590
52835
|
|
|
52591
52836
|
// src/skills/install/constants.ts
|
|
52592
52837
|
var INSTALL_SKILLS_YIELD_EVERY = 16;
|
|
52593
52838
|
|
|
52594
52839
|
// src/skills/install/install-remote-skills-async.ts
|
|
52595
52840
|
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 =
|
|
52601
|
-
await
|
|
52602
|
-
if (f.text !== void 0) {
|
|
52603
|
-
await
|
|
52604
|
-
} else if (f.base64) {
|
|
52605
|
-
await
|
|
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("|");
|
|
52841
|
+
if (typeof f.path !== "string" || !f.text && !f.base64) return;
|
|
52842
|
+
if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
|
|
52843
|
+
await yieldToEventLoop();
|
|
52844
|
+
}
|
|
52845
|
+
const dest = path80.join(skillDir, f.path);
|
|
52846
|
+
await fs61.promises.mkdir(path80.dirname(dest), { recursive: true });
|
|
52847
|
+
if (f.text !== void 0) {
|
|
52848
|
+
await fs61.promises.writeFile(dest, f.text, "utf8");
|
|
52849
|
+
} else if (f.base64) {
|
|
52850
|
+
await fs61.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
|
|
52851
|
+
}
|
|
52766
52852
|
}
|
|
52767
|
-
function
|
|
52768
|
-
const
|
|
52769
|
-
|
|
52770
|
-
|
|
52771
|
-
|
|
52772
|
-
|
|
52773
|
-
|
|
52774
|
-
|
|
52775
|
-
|
|
52853
|
+
async function installRemoteSkillsAsync(cwd, targetDir, items) {
|
|
52854
|
+
const installed2 = [];
|
|
52855
|
+
if (!Array.isArray(items)) {
|
|
52856
|
+
return { success: false, error: "Invalid items" };
|
|
52857
|
+
}
|
|
52858
|
+
const filesWritten = { count: 0 };
|
|
52859
|
+
try {
|
|
52860
|
+
for (const item of items) {
|
|
52861
|
+
if (!isValidRemoteSkillInstallItem(item)) continue;
|
|
52862
|
+
const skillDir = path80.join(cwd, targetDir, item.skillName);
|
|
52863
|
+
for (const f of item.files) {
|
|
52864
|
+
await writeInstallFileAsync(skillDir, f, filesWritten);
|
|
52865
|
+
}
|
|
52866
|
+
installed2.push({
|
|
52867
|
+
sourceId: item.sourceId,
|
|
52868
|
+
skillName: item.skillName,
|
|
52869
|
+
versionHash: item.versionHash
|
|
52870
|
+
});
|
|
52871
|
+
}
|
|
52872
|
+
return { success: true, installed: installed2 };
|
|
52873
|
+
} catch (e) {
|
|
52874
|
+
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
52875
|
+
}
|
|
52776
52876
|
}
|
|
52777
52877
|
|
|
52778
|
-
// src/routing/handlers/
|
|
52779
|
-
|
|
52780
|
-
const
|
|
52781
|
-
const
|
|
52782
|
-
|
|
52783
|
-
|
|
52784
|
-
|
|
52785
|
-
|
|
52786
|
-
|
|
52787
|
-
|
|
52878
|
+
// src/routing/handlers/install-skills.ts
|
|
52879
|
+
var handleInstallSkillsMessage = (msg, deps) => {
|
|
52880
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52881
|
+
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
52882
|
+
const rawItems = msg.items;
|
|
52883
|
+
const cwd = getBridgeRoot();
|
|
52884
|
+
void (async () => {
|
|
52885
|
+
const socket = deps.getWs();
|
|
52886
|
+
const result = await installRemoteSkillsAsync(cwd, targetDir, rawItems);
|
|
52887
|
+
if (!result.success) {
|
|
52888
|
+
const err = result.error ?? "Invalid items";
|
|
52889
|
+
deps.log(`[Bridge service] Install skills failed: ${err}`);
|
|
52890
|
+
if (socket) {
|
|
52891
|
+
sendWsMessage(socket, { type: "install_skills_result", id, success: false, error: err });
|
|
52892
|
+
}
|
|
52788
52893
|
return;
|
|
52789
52894
|
}
|
|
52790
|
-
|
|
52791
|
-
|
|
52792
|
-
|
|
52793
|
-
|
|
52794
|
-
|
|
52795
|
-
|
|
52796
|
-
|
|
52797
|
-
|
|
52798
|
-
|
|
52799
|
-
|
|
52800
|
-
|
|
52801
|
-
|
|
52895
|
+
if (socket) {
|
|
52896
|
+
sendWsMessage(socket, { type: "install_skills_result", id, success: true, installed: result.installed });
|
|
52897
|
+
}
|
|
52898
|
+
})();
|
|
52899
|
+
};
|
|
52900
|
+
|
|
52901
|
+
// src/agents/install/commands/run-npm-global-install.ts
|
|
52902
|
+
import { execFile as execFile9 } from "node:child_process";
|
|
52903
|
+
import { promisify as promisify10 } from "node:util";
|
|
52904
|
+
var execFileAsync8 = promisify10(execFile9);
|
|
52905
|
+
async function runNpmGlobalInstall(packageName, env, timeoutMs = 3e5) {
|
|
52906
|
+
await execFileAsync8("npm", ["install", "-g", packageName], { timeout: timeoutMs, env });
|
|
52802
52907
|
}
|
|
52803
52908
|
|
|
52804
|
-
// src/
|
|
52805
|
-
|
|
52806
|
-
|
|
52807
|
-
|
|
52808
|
-
|
|
52809
|
-
|
|
52909
|
+
// src/agents/install/commands/claude-code.ts
|
|
52910
|
+
var claudeCodeInstallCommand = {
|
|
52911
|
+
agentType: "claude-code",
|
|
52912
|
+
detectCommand: "claude",
|
|
52913
|
+
async install(ctx) {
|
|
52914
|
+
ctx.onProgress?.("Installing Anthropic Claude Code");
|
|
52915
|
+
await runNpmGlobalInstall("@anthropic-ai/claude-code", {
|
|
52916
|
+
...ctx.env,
|
|
52917
|
+
ANTHROPIC_API_KEY: ctx.authToken
|
|
52918
|
+
});
|
|
52810
52919
|
}
|
|
52811
|
-
|
|
52812
|
-
reply({
|
|
52813
|
-
ok: true,
|
|
52814
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52815
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52816
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
52817
|
-
});
|
|
52818
|
-
}
|
|
52920
|
+
};
|
|
52819
52921
|
|
|
52820
|
-
// src/
|
|
52821
|
-
|
|
52822
|
-
|
|
52823
|
-
|
|
52824
|
-
|
|
52825
|
-
|
|
52826
|
-
|
|
52827
|
-
|
|
52828
|
-
|
|
52829
|
-
}
|
|
52922
|
+
// src/agents/install/commands/codex-acp.ts
|
|
52923
|
+
var codexAcpInstallCommand = {
|
|
52924
|
+
agentType: "codex-acp",
|
|
52925
|
+
detectCommand: "codex",
|
|
52926
|
+
async install(ctx) {
|
|
52927
|
+
ctx.onProgress?.("Installing Codex");
|
|
52928
|
+
await runNpmGlobalInstall("@openai/codex", {
|
|
52929
|
+
...ctx.env,
|
|
52930
|
+
OPENAI_API_KEY: ctx.authToken
|
|
52931
|
+
});
|
|
52932
|
+
}
|
|
52933
|
+
};
|
|
52830
52934
|
|
|
52831
|
-
// src/
|
|
52832
|
-
|
|
52833
|
-
|
|
52834
|
-
|
|
52835
|
-
|
|
52836
|
-
|
|
52837
|
-
|
|
52935
|
+
// src/agents/install/commands/cursor-cli.ts
|
|
52936
|
+
import { execFile as execFile10 } from "node:child_process";
|
|
52937
|
+
import { promisify as promisify11 } from "node:util";
|
|
52938
|
+
var execFileAsync9 = promisify11(execFile10);
|
|
52939
|
+
var cursorCliInstallCommand = {
|
|
52940
|
+
agentType: "cursor-cli",
|
|
52941
|
+
detectCommand: "agent",
|
|
52942
|
+
async install(ctx) {
|
|
52943
|
+
ctx.onProgress?.("Installing Cursor CLI");
|
|
52944
|
+
await execFileAsync9("bash", ["-lc", "curl -fsSL https://cursor.com/install | bash"], {
|
|
52945
|
+
timeout: 3e5,
|
|
52946
|
+
env: { ...ctx.env, CURSOR_API_KEY: ctx.authToken }
|
|
52947
|
+
});
|
|
52838
52948
|
}
|
|
52839
|
-
|
|
52949
|
+
};
|
|
52950
|
+
|
|
52951
|
+
// src/agents/install/commands/opencode.ts
|
|
52952
|
+
var opencodeInstallCommand = {
|
|
52953
|
+
agentType: "opencode",
|
|
52954
|
+
detectCommand: "opencode",
|
|
52955
|
+
async install(ctx) {
|
|
52956
|
+
ctx.onProgress?.("Installing OpenCode");
|
|
52957
|
+
await runNpmGlobalInstall("opencode-ai", {
|
|
52958
|
+
...ctx.env,
|
|
52959
|
+
OPENCODE_API_KEY: ctx.authToken
|
|
52960
|
+
});
|
|
52961
|
+
}
|
|
52962
|
+
};
|
|
52963
|
+
|
|
52964
|
+
// src/agents/install/commands/index.ts
|
|
52965
|
+
var COMMANDS = [
|
|
52966
|
+
claudeCodeInstallCommand,
|
|
52967
|
+
codexAcpInstallCommand,
|
|
52968
|
+
cursorCliInstallCommand,
|
|
52969
|
+
opencodeInstallCommand
|
|
52970
|
+
];
|
|
52971
|
+
var byType = new Map(COMMANDS.map((c) => [c.agentType, c]));
|
|
52972
|
+
function getAgentInstallCommand(agentType) {
|
|
52973
|
+
return byType.get(agentType);
|
|
52974
|
+
}
|
|
52975
|
+
|
|
52976
|
+
// src/agents/install/install-local-agent.ts
|
|
52977
|
+
async function installLocalAgentOnBridge(params) {
|
|
52978
|
+
const spec = INSTALLABLE_BRIDGE_AGENTS.find((a) => a.value === params.agentType);
|
|
52979
|
+
if (!spec) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
|
|
52980
|
+
const command = getAgentInstallCommand(params.agentType);
|
|
52981
|
+
if (!command) return { success: false, error: `No install command for ${params.agentType}` };
|
|
52982
|
+
params.onProgress?.(`Configuring ${spec.label} credentials`);
|
|
52983
|
+
try {
|
|
52984
|
+
await command.install({
|
|
52985
|
+
authToken: params.authToken,
|
|
52986
|
+
onProgress: params.onProgress,
|
|
52987
|
+
env: { ...process.env, [spec.tokenEnvVar]: params.authToken }
|
|
52988
|
+
});
|
|
52989
|
+
} catch (e) {
|
|
52990
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
52991
|
+
return { success: false, error: msg };
|
|
52992
|
+
}
|
|
52993
|
+
const found = await isCommandOnPath(command.detectCommand);
|
|
52994
|
+
if (!found) {
|
|
52995
|
+
return { success: false, error: `${command.detectCommand} not found on PATH after install` };
|
|
52996
|
+
}
|
|
52997
|
+
return { success: true };
|
|
52840
52998
|
}
|
|
52841
52999
|
|
|
52842
|
-
// src/routing/handlers/
|
|
52843
|
-
var
|
|
52844
|
-
|
|
52845
|
-
const
|
|
52846
|
-
const
|
|
52847
|
-
|
|
52848
|
-
|
|
53000
|
+
// src/routing/handlers/install-agent.ts
|
|
53001
|
+
var handleInstallAgentMessage = (msg, deps) => {
|
|
53002
|
+
const processId = typeof msg.processId === "string" ? msg.processId : "";
|
|
53003
|
+
const agentId = typeof msg.agentId === "string" ? msg.agentId : "";
|
|
53004
|
+
const tokenId = typeof msg.tokenId === "string" ? msg.tokenId : "";
|
|
53005
|
+
const agentType = typeof msg.agentType === "string" ? msg.agentType : "";
|
|
53006
|
+
const authToken = typeof msg.authToken === "string" ? msg.authToken : "";
|
|
53007
|
+
if (!processId || !agentId || !tokenId || !agentType || !authToken) return;
|
|
52849
53008
|
void (async () => {
|
|
52850
|
-
const
|
|
52851
|
-
const
|
|
52852
|
-
|
|
52853
|
-
|
|
52854
|
-
|
|
52855
|
-
|
|
52856
|
-
|
|
52857
|
-
|
|
52858
|
-
|
|
52859
|
-
|
|
52860
|
-
|
|
52861
|
-
|
|
52862
|
-
await handleSessionGitGetChangeFilePatchAction(deps, { ...msg, sessionId }, reply);
|
|
52863
|
-
return;
|
|
52864
|
-
}
|
|
52865
|
-
if (action === "push") {
|
|
52866
|
-
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
52867
|
-
return;
|
|
53009
|
+
const socket = deps.getWs();
|
|
53010
|
+
const report = (step, message) => {
|
|
53011
|
+
if (socket) {
|
|
53012
|
+
sendWsMessage(socket, {
|
|
53013
|
+
type: "install_agent_progress",
|
|
53014
|
+
processId,
|
|
53015
|
+
agentId,
|
|
53016
|
+
tokenId,
|
|
53017
|
+
agentType,
|
|
53018
|
+
step,
|
|
53019
|
+
message
|
|
53020
|
+
});
|
|
52868
53021
|
}
|
|
52869
|
-
|
|
52870
|
-
|
|
52871
|
-
|
|
53022
|
+
};
|
|
53023
|
+
const result = await installLocalAgentOnBridge({
|
|
53024
|
+
agentType,
|
|
53025
|
+
authToken,
|
|
53026
|
+
onProgress: (message) => report("agent_install_package", message)
|
|
53027
|
+
});
|
|
53028
|
+
if (socket) {
|
|
53029
|
+
sendWsMessage(socket, {
|
|
53030
|
+
type: "install_agent_result",
|
|
53031
|
+
processId,
|
|
53032
|
+
agentId,
|
|
53033
|
+
tokenId,
|
|
53034
|
+
agentType,
|
|
53035
|
+
success: result.success,
|
|
53036
|
+
error: result.error
|
|
53037
|
+
});
|
|
53038
|
+
}
|
|
53039
|
+
if (!result.success) {
|
|
53040
|
+
deps.log(`[Bridge service] Install agent failed: ${result.error ?? "unknown"}`);
|
|
52872
53041
|
}
|
|
52873
53042
|
})();
|
|
52874
53043
|
};
|
|
52875
53044
|
|
|
52876
|
-
// src/routing/handlers/
|
|
52877
|
-
var
|
|
52878
|
-
|
|
52879
|
-
|
|
52880
|
-
|
|
52881
|
-
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
53045
|
+
// src/routing/handlers/refresh-local-skills.ts
|
|
53046
|
+
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
53047
|
+
setImmediate(() => {
|
|
53048
|
+
deps.sendLocalSkillsReport?.();
|
|
53049
|
+
});
|
|
52882
53050
|
};
|
|
52883
53051
|
|
|
52884
|
-
// src/routing/
|
|
52885
|
-
|
|
52886
|
-
|
|
52887
|
-
|
|
52888
|
-
|
|
52889
|
-
|
|
53052
|
+
// src/routing/dispatch/skills.ts
|
|
53053
|
+
function dispatchBridgeSkillsMessage(msg, deps) {
|
|
53054
|
+
switch (msg.type) {
|
|
53055
|
+
case "skill_call":
|
|
53056
|
+
handleSkillCallMessage(msg, deps);
|
|
53057
|
+
break;
|
|
53058
|
+
case "skill_layout_request":
|
|
53059
|
+
handleSkillLayoutRequest(msg, deps);
|
|
53060
|
+
break;
|
|
53061
|
+
case "install_skills":
|
|
53062
|
+
handleInstallSkillsMessage(msg, deps);
|
|
53063
|
+
break;
|
|
53064
|
+
case "install_agent":
|
|
53065
|
+
handleInstallAgentMessage(msg, deps);
|
|
53066
|
+
break;
|
|
53067
|
+
case "refresh_local_skills":
|
|
53068
|
+
handleRefreshLocalSkills(msg, deps);
|
|
53069
|
+
break;
|
|
53070
|
+
}
|
|
53071
|
+
}
|
|
52890
53072
|
|
|
52891
|
-
// src/
|
|
52892
|
-
|
|
52893
|
-
|
|
52894
|
-
|
|
52895
|
-
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
52896
|
-
};
|
|
53073
|
+
// src/files/browser/send-file-browser-message.ts
|
|
53074
|
+
function sendFileBrowserMessage(socket, e2ee, payload) {
|
|
53075
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
|
|
53076
|
+
}
|
|
52897
53077
|
|
|
52898
|
-
// src/
|
|
52899
|
-
|
|
52900
|
-
|
|
52901
|
-
|
|
52902
|
-
|
|
52903
|
-
|
|
52904
|
-
|
|
52905
|
-
|
|
53078
|
+
// src/files/browser/handle-file-browser-list.ts
|
|
53079
|
+
async function handleFileBrowserList(socket, e2ee, id, reqPath, sessionParentPath, gitScope) {
|
|
53080
|
+
const result = await executeFileBrowserList({ reqPath, sessionParentPath, gitScope });
|
|
53081
|
+
if ("error" in result) {
|
|
53082
|
+
sendWsMessage(socket, { type: "file_browser_response", id, error: result.error });
|
|
53083
|
+
return;
|
|
53084
|
+
}
|
|
53085
|
+
sendFileBrowserMessage(socket, e2ee, { type: "file_browser_response", id, entries: result.entries });
|
|
53086
|
+
}
|
|
53087
|
+
|
|
53088
|
+
// src/files/browser/handle-file-browser-read.ts
|
|
53089
|
+
async function handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope) {
|
|
53090
|
+
const result = await executeFileBrowserRead({ msg, reqPath, sessionParentPath, gitScope });
|
|
53091
|
+
if ("error" in result) {
|
|
53092
|
+
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
53093
|
+
return;
|
|
53094
|
+
}
|
|
53095
|
+
const payload = {
|
|
53096
|
+
type: "file_browser_response",
|
|
53097
|
+
id: msg.id,
|
|
53098
|
+
content: result.content,
|
|
53099
|
+
totalLines: result.totalLines,
|
|
53100
|
+
size: result.size
|
|
53101
|
+
};
|
|
53102
|
+
if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
|
|
53103
|
+
if (result.mimeType != null) payload.mimeType = result.mimeType;
|
|
53104
|
+
if (result.resolvedPath != null) payload.resolvedPath = result.resolvedPath;
|
|
53105
|
+
sendFileBrowserMessage(socket, e2ee, payload);
|
|
53106
|
+
}
|
|
53107
|
+
|
|
53108
|
+
// src/files/browser/index.ts
|
|
53109
|
+
init_in_flight();
|
|
53110
|
+
function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
53111
|
+
beginFileBrowserRequest();
|
|
52906
53112
|
void (async () => {
|
|
52907
|
-
const s = getWs();
|
|
52908
|
-
if (!s) return;
|
|
52909
|
-
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
52910
|
-
const file2 = snapshotFilePath(agentBase, turnId);
|
|
52911
53113
|
try {
|
|
52912
|
-
|
|
52913
|
-
|
|
52914
|
-
|
|
52915
|
-
|
|
52916
|
-
id,
|
|
52917
|
-
|
|
52918
|
-
|
|
52919
|
-
|
|
52920
|
-
|
|
53114
|
+
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
53115
|
+
const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
53116
|
+
const gitScope = resolveGitBranchScope(msg);
|
|
53117
|
+
if (msg.source === "git_branch" && typeof msg.repoRelPath === "string" && typeof msg.branch === "string" && msg.branch.trim().length > 0 && !gitScope) {
|
|
53118
|
+
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: "Invalid repository path" });
|
|
53119
|
+
return;
|
|
53120
|
+
}
|
|
53121
|
+
if (msg.op === "read") {
|
|
53122
|
+
await handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope);
|
|
53123
|
+
} else {
|
|
53124
|
+
await handleFileBrowserList(socket, e2ee, msg.id, reqPath, sessionParentPath, gitScope);
|
|
53125
|
+
}
|
|
53126
|
+
} finally {
|
|
53127
|
+
endFileBrowserRequest();
|
|
52921
53128
|
}
|
|
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
53129
|
})();
|
|
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
|
-
};
|
|
53130
|
+
}
|
|
52946
53131
|
|
|
52947
|
-
// src/
|
|
52948
|
-
|
|
52949
|
-
|
|
52950
|
-
|
|
52951
|
-
|
|
52952
|
-
|
|
52953
|
-
|
|
52954
|
-
const
|
|
52955
|
-
|
|
52956
|
-
|
|
52957
|
-
|
|
53132
|
+
// src/files/handle-file-browser-search.ts
|
|
53133
|
+
init_yield_to_event_loop();
|
|
53134
|
+
import path81 from "node:path";
|
|
53135
|
+
var SEARCH_LIMIT = 100;
|
|
53136
|
+
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
53137
|
+
void (async () => {
|
|
53138
|
+
await yieldToEventLoop();
|
|
53139
|
+
const q = typeof msg.q === "string" ? msg.q : "";
|
|
53140
|
+
const sessionParentPath = path81.resolve(
|
|
53141
|
+
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
53142
|
+
);
|
|
53143
|
+
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
53144
|
+
triggerFileIndexBuild(sessionParentPath);
|
|
53145
|
+
const payload2 = {
|
|
53146
|
+
type: "file_browser_search_response",
|
|
53147
|
+
id: msg.id,
|
|
53148
|
+
paths: [],
|
|
53149
|
+
indexReady: false
|
|
53150
|
+
};
|
|
53151
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
53152
|
+
return;
|
|
52958
53153
|
}
|
|
53154
|
+
const results = await searchBridgeFilePathsAsync(sessionParentPath, q, SEARCH_LIMIT);
|
|
53155
|
+
const payload = {
|
|
53156
|
+
type: "file_browser_search_response",
|
|
53157
|
+
id: msg.id,
|
|
53158
|
+
paths: results,
|
|
53159
|
+
indexReady: true
|
|
53160
|
+
};
|
|
53161
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
|
|
53162
|
+
})();
|
|
53163
|
+
}
|
|
53164
|
+
function triggerFileIndexBuild(sessionParentPath = getBridgeRoot()) {
|
|
53165
|
+
setImmediate(() => {
|
|
53166
|
+
void ensureFileIndexAsync(sessionParentPath).catch((e) => {
|
|
53167
|
+
console.error("[file-index] Background build failed:", e);
|
|
53168
|
+
});
|
|
52959
53169
|
});
|
|
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
53170
|
}
|
|
52967
53171
|
|
|
52968
|
-
// src/routing/handlers/
|
|
52969
|
-
|
|
53172
|
+
// src/routing/handlers/file-browser-messages.ts
|
|
53173
|
+
function handleFileBrowserRequestMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
53174
|
+
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
53175
|
+
const socket = getWs();
|
|
53176
|
+
if (!socket) return;
|
|
53177
|
+
handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager);
|
|
53178
|
+
}
|
|
53179
|
+
function handleFileBrowserSearchMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
52970
53180
|
if (typeof msg.id !== "string") return;
|
|
52971
|
-
const
|
|
52972
|
-
|
|
52973
|
-
|
|
53181
|
+
const socket = getWs();
|
|
53182
|
+
if (!socket) return;
|
|
53183
|
+
handleFileBrowserSearch(
|
|
53184
|
+
msg,
|
|
53185
|
+
socket,
|
|
53186
|
+
e2ee,
|
|
53187
|
+
sessionWorktreeManager
|
|
53188
|
+
);
|
|
53189
|
+
}
|
|
53190
|
+
|
|
53191
|
+
// src/code-nav/handlers/send-code-nav-response.ts
|
|
53192
|
+
var ENCRYPTED_FIELDS = ["definition", "definitions", "references", "symbols", "confidentTarget"];
|
|
53193
|
+
function sendCodeNavResponse(socket, e2ee, payload) {
|
|
53194
|
+
const fieldsToEncrypt = ENCRYPTED_FIELDS.filter((field) => field in payload && payload[field] !== void 0);
|
|
53195
|
+
sendWsMessage(
|
|
53196
|
+
socket,
|
|
53197
|
+
e2ee && fieldsToEncrypt.length > 0 ? e2ee.encryptFields(payload, [...fieldsToEncrypt]) : payload
|
|
53198
|
+
);
|
|
53199
|
+
}
|
|
53200
|
+
|
|
53201
|
+
// src/code-nav/handlers/handle-code-nav-request.ts
|
|
53202
|
+
function handleCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
52974
53203
|
void (async () => {
|
|
52975
|
-
const
|
|
52976
|
-
|
|
52977
|
-
|
|
52978
|
-
|
|
52979
|
-
|
|
52980
|
-
|
|
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
|
-
}
|
|
53204
|
+
const body = await executeCodeNavRequest(msg, sessionWorktreeManager);
|
|
53205
|
+
sendCodeNavResponse(socket, e2ee, {
|
|
53206
|
+
type: "code_nav_response",
|
|
53207
|
+
id: msg.id,
|
|
53208
|
+
...body
|
|
53209
|
+
});
|
|
52993
53210
|
})();
|
|
52994
|
-
}
|
|
53211
|
+
}
|
|
53212
|
+
|
|
53213
|
+
// src/code-nav/handlers/trigger-symbol-index-build.ts
|
|
53214
|
+
init_normalize_resolved_path();
|
|
53215
|
+
|
|
53216
|
+
// src/routing/handlers/code-nav-messages.ts
|
|
53217
|
+
function handleFileBrowserCodeNavMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
53218
|
+
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
53219
|
+
const socket = getWs();
|
|
53220
|
+
if (!socket) return;
|
|
53221
|
+
handleCodeNavRequest(
|
|
53222
|
+
{
|
|
53223
|
+
id: msg.id,
|
|
53224
|
+
type: "code_nav",
|
|
53225
|
+
op: msg.op === "references" ? "references" : msg.op === "symbols" ? "symbols" : msg.op === "definitions" ? "definitions" : "definition",
|
|
53226
|
+
path: msg.path,
|
|
53227
|
+
line: typeof msg.line === "number" ? msg.line : 1,
|
|
53228
|
+
column: typeof msg.column === "number" ? msg.column : 0,
|
|
53229
|
+
sessionId: msg.sessionId
|
|
53230
|
+
},
|
|
53231
|
+
socket,
|
|
53232
|
+
e2ee,
|
|
53233
|
+
sessionWorktreeManager
|
|
53234
|
+
);
|
|
53235
|
+
}
|
|
52995
53236
|
|
|
52996
53237
|
// src/git/bridge-git-context.ts
|
|
52997
53238
|
import * as path82 from "node:path";
|
|
@@ -53138,80 +53379,64 @@ function handleListRepoBranchesRequestMessage(msg, getWs) {
|
|
|
53138
53379
|
})();
|
|
53139
53380
|
}
|
|
53140
53381
|
|
|
53141
|
-
// src/routing/dispatch-
|
|
53382
|
+
// src/routing/dispatch/file-browser.ts
|
|
53383
|
+
function dispatchBridgeFileBrowserMessage(msg, deps) {
|
|
53384
|
+
switch (msg.type) {
|
|
53385
|
+
case "file_browser_request":
|
|
53386
|
+
handleFileBrowserRequestMessage(msg, deps);
|
|
53387
|
+
break;
|
|
53388
|
+
case "file_browser_search":
|
|
53389
|
+
handleFileBrowserSearchMessage(msg, deps);
|
|
53390
|
+
break;
|
|
53391
|
+
case "code_nav":
|
|
53392
|
+
handleFileBrowserCodeNavMessage(msg, deps);
|
|
53393
|
+
break;
|
|
53394
|
+
case "bridge_git_context_request":
|
|
53395
|
+
handleBridgeGitContextRequestMessage(msg, deps.getWs);
|
|
53396
|
+
break;
|
|
53397
|
+
case "list_repo_branches_request":
|
|
53398
|
+
handleListRepoBranchesRequestMessage(msg, deps.getWs);
|
|
53399
|
+
break;
|
|
53400
|
+
}
|
|
53401
|
+
}
|
|
53402
|
+
|
|
53403
|
+
// src/routing/dispatch/index.ts
|
|
53142
53404
|
function dispatchBridgeMessage(msg, deps) {
|
|
53143
53405
|
switch (msg.type) {
|
|
53144
53406
|
case "auth_token":
|
|
53145
|
-
handleAuthToken(msg, deps);
|
|
53146
|
-
break;
|
|
53147
53407
|
case "bridge_identified":
|
|
53148
|
-
handleBridgeIdentified(msg, deps);
|
|
53149
|
-
break;
|
|
53150
53408
|
case "ha":
|
|
53151
|
-
|
|
53409
|
+
dispatchBridgeConnectionMessage(msg, deps);
|
|
53152
53410
|
break;
|
|
53153
53411
|
case "preview_environments_config":
|
|
53154
|
-
handlePreviewEnvironmentsConfig(msg, deps);
|
|
53155
|
-
break;
|
|
53156
53412
|
case "preview_environment_control":
|
|
53157
|
-
handlePreviewEnvironmentControl(msg, deps);
|
|
53158
|
-
break;
|
|
53159
53413
|
case "deploy_session_to_preview":
|
|
53160
|
-
|
|
53414
|
+
dispatchBridgePreviewMessage(msg, deps);
|
|
53161
53415
|
break;
|
|
53162
53416
|
case "agent_config":
|
|
53163
|
-
handleAgentConfigMessage(msg, deps);
|
|
53164
|
-
break;
|
|
53165
53417
|
case "prompt_queue_state":
|
|
53166
|
-
handlePromptQueueStateMessage(msg, deps);
|
|
53167
|
-
break;
|
|
53168
53418
|
case "prompt":
|
|
53169
|
-
handlePromptMessage(msg, deps);
|
|
53170
|
-
break;
|
|
53171
53419
|
case "session_git_request":
|
|
53172
|
-
handleSessionGitRequestMessage(msg, deps);
|
|
53173
|
-
break;
|
|
53174
53420
|
case "rename_session_branch":
|
|
53175
|
-
handleRenameSessionBranchMessage(msg, deps);
|
|
53176
|
-
break;
|
|
53177
53421
|
case "session_archived":
|
|
53178
|
-
handleSessionArchivedMessage(msg, deps);
|
|
53179
|
-
break;
|
|
53180
53422
|
case "session_discarded":
|
|
53181
|
-
handleSessionDiscardedMessage(msg, deps);
|
|
53182
|
-
break;
|
|
53183
53423
|
case "revert_turn_snapshot":
|
|
53184
|
-
handleRevertTurnSnapshotMessage(msg, deps);
|
|
53185
|
-
break;
|
|
53186
53424
|
case "cursor_request_response":
|
|
53187
|
-
|
|
53425
|
+
dispatchBridgeSessionMessage(msg, deps);
|
|
53188
53426
|
break;
|
|
53189
53427
|
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
53428
|
case "skill_layout_request":
|
|
53202
|
-
handleSkillLayoutRequest(msg, deps);
|
|
53203
|
-
break;
|
|
53204
53429
|
case "install_skills":
|
|
53205
|
-
|
|
53206
|
-
break;
|
|
53430
|
+
case "install_agent":
|
|
53207
53431
|
case "refresh_local_skills":
|
|
53208
|
-
|
|
53432
|
+
dispatchBridgeSkillsMessage(msg, deps);
|
|
53209
53433
|
break;
|
|
53434
|
+
case "file_browser_request":
|
|
53435
|
+
case "file_browser_search":
|
|
53436
|
+
case "code_nav":
|
|
53210
53437
|
case "bridge_git_context_request":
|
|
53211
|
-
handleBridgeGitContextRequestMessage(msg, deps.getWs);
|
|
53212
|
-
break;
|
|
53213
53438
|
case "list_repo_branches_request":
|
|
53214
|
-
|
|
53439
|
+
dispatchBridgeFileBrowserMessage(msg, deps);
|
|
53215
53440
|
break;
|
|
53216
53441
|
}
|
|
53217
53442
|
}
|