@buildautomaton/cli 0.1.49 → 0.1.50
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 +1229 -943
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1208 -922
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4175,8 +4175,8 @@ var init_parseUtil = __esm({
|
|
|
4175
4175
|
init_errors();
|
|
4176
4176
|
init_en();
|
|
4177
4177
|
makeIssue = (params) => {
|
|
4178
|
-
const { data, path:
|
|
4179
|
-
const fullPath = [...
|
|
4178
|
+
const { data, path: path53, errorMaps, issueData } = params;
|
|
4179
|
+
const fullPath = [...path53, ...issueData.path || []];
|
|
4180
4180
|
const fullIssue = {
|
|
4181
4181
|
...issueData,
|
|
4182
4182
|
path: fullPath
|
|
@@ -4484,11 +4484,11 @@ var init_types = __esm({
|
|
|
4484
4484
|
init_parseUtil();
|
|
4485
4485
|
init_util();
|
|
4486
4486
|
ParseInputLazyPath = class {
|
|
4487
|
-
constructor(parent, value,
|
|
4487
|
+
constructor(parent, value, path53, key) {
|
|
4488
4488
|
this._cachedPath = [];
|
|
4489
4489
|
this.parent = parent;
|
|
4490
4490
|
this.data = value;
|
|
4491
|
-
this._path =
|
|
4491
|
+
this._path = path53;
|
|
4492
4492
|
this._key = key;
|
|
4493
4493
|
}
|
|
4494
4494
|
get path() {
|
|
@@ -8103,15 +8103,15 @@ function assignProp(target, prop, value) {
|
|
|
8103
8103
|
configurable: true
|
|
8104
8104
|
});
|
|
8105
8105
|
}
|
|
8106
|
-
function getElementAtPath(obj,
|
|
8107
|
-
if (!
|
|
8106
|
+
function getElementAtPath(obj, path53) {
|
|
8107
|
+
if (!path53)
|
|
8108
8108
|
return obj;
|
|
8109
|
-
return
|
|
8109
|
+
return path53.reduce((acc, key) => acc?.[key], obj);
|
|
8110
8110
|
}
|
|
8111
8111
|
function promiseAllObject(promisesObj) {
|
|
8112
8112
|
const keys = Object.keys(promisesObj);
|
|
8113
|
-
const
|
|
8114
|
-
return Promise.all(
|
|
8113
|
+
const promises11 = keys.map((key) => promisesObj[key]);
|
|
8114
|
+
return Promise.all(promises11).then((results) => {
|
|
8115
8115
|
const resolvedObj = {};
|
|
8116
8116
|
for (let i = 0; i < keys.length; i++) {
|
|
8117
8117
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -8355,11 +8355,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8355
8355
|
}
|
|
8356
8356
|
return false;
|
|
8357
8357
|
}
|
|
8358
|
-
function prefixIssues(
|
|
8358
|
+
function prefixIssues(path53, issues) {
|
|
8359
8359
|
return issues.map((iss) => {
|
|
8360
8360
|
var _a2;
|
|
8361
8361
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8362
|
-
iss.path.unshift(
|
|
8362
|
+
iss.path.unshift(path53);
|
|
8363
8363
|
return iss;
|
|
8364
8364
|
});
|
|
8365
8365
|
}
|
|
@@ -8548,7 +8548,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8548
8548
|
return issue2.message;
|
|
8549
8549
|
};
|
|
8550
8550
|
const result = { errors: [] };
|
|
8551
|
-
const processError = (error41,
|
|
8551
|
+
const processError = (error41, path53 = []) => {
|
|
8552
8552
|
var _a2, _b;
|
|
8553
8553
|
for (const issue2 of error41.issues) {
|
|
8554
8554
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8558,7 +8558,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8558
8558
|
} else if (issue2.code === "invalid_element") {
|
|
8559
8559
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8560
8560
|
} else {
|
|
8561
|
-
const fullpath = [...
|
|
8561
|
+
const fullpath = [...path53, ...issue2.path];
|
|
8562
8562
|
if (fullpath.length === 0) {
|
|
8563
8563
|
result.errors.push(mapper(issue2));
|
|
8564
8564
|
continue;
|
|
@@ -8588,9 +8588,9 @@ function treeifyError(error40, _mapper) {
|
|
|
8588
8588
|
processError(error40);
|
|
8589
8589
|
return result;
|
|
8590
8590
|
}
|
|
8591
|
-
function toDotPath(
|
|
8591
|
+
function toDotPath(path53) {
|
|
8592
8592
|
const segs = [];
|
|
8593
|
-
for (const seg of
|
|
8593
|
+
for (const seg of path53) {
|
|
8594
8594
|
if (typeof seg === "number")
|
|
8595
8595
|
segs.push(`[${seg}]`);
|
|
8596
8596
|
else if (typeof seg === "symbol")
|
|
@@ -21053,8 +21053,8 @@ var init_acp = __esm({
|
|
|
21053
21053
|
this.#requestHandler = requestHandler;
|
|
21054
21054
|
this.#notificationHandler = notificationHandler;
|
|
21055
21055
|
this.#stream = stream;
|
|
21056
|
-
this.#closedPromise = new Promise((
|
|
21057
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
21056
|
+
this.#closedPromise = new Promise((resolve26) => {
|
|
21057
|
+
this.#abortController.signal.addEventListener("abort", () => resolve26());
|
|
21058
21058
|
});
|
|
21059
21059
|
this.#receive();
|
|
21060
21060
|
}
|
|
@@ -21203,8 +21203,8 @@ var init_acp = __esm({
|
|
|
21203
21203
|
}
|
|
21204
21204
|
async sendRequest(method, params) {
|
|
21205
21205
|
const id = this.#nextRequestId++;
|
|
21206
|
-
const responsePromise = new Promise((
|
|
21207
|
-
this.#pendingResponses.set(id, { resolve:
|
|
21206
|
+
const responsePromise = new Promise((resolve26, reject) => {
|
|
21207
|
+
this.#pendingResponses.set(id, { resolve: resolve26, reject });
|
|
21208
21208
|
});
|
|
21209
21209
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
21210
21210
|
return responsePromise;
|
|
@@ -22073,10 +22073,10 @@ var require_src2 = __commonJS({
|
|
|
22073
22073
|
var fs_1 = __require("fs");
|
|
22074
22074
|
var debug_1 = __importDefault(require_src());
|
|
22075
22075
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
22076
|
-
function check2(
|
|
22077
|
-
log2(`checking %s`,
|
|
22076
|
+
function check2(path53, isFile, isDirectory) {
|
|
22077
|
+
log2(`checking %s`, path53);
|
|
22078
22078
|
try {
|
|
22079
|
-
const stat2 = fs_1.statSync(
|
|
22079
|
+
const stat2 = fs_1.statSync(path53);
|
|
22080
22080
|
if (stat2.isFile() && isFile) {
|
|
22081
22081
|
log2(`[OK] path represents a file`);
|
|
22082
22082
|
return true;
|
|
@@ -22096,8 +22096,8 @@ var require_src2 = __commonJS({
|
|
|
22096
22096
|
throw e;
|
|
22097
22097
|
}
|
|
22098
22098
|
}
|
|
22099
|
-
function exists2(
|
|
22100
|
-
return check2(
|
|
22099
|
+
function exists2(path53, type = exports.READABLE) {
|
|
22100
|
+
return check2(path53, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
22101
22101
|
}
|
|
22102
22102
|
exports.exists = exists2;
|
|
22103
22103
|
exports.FILE = 1;
|
|
@@ -22446,10 +22446,10 @@ async function killChildProcessTreeGracefully(child, graceMs = ACP_PROCESS_TREE_
|
|
|
22446
22446
|
}
|
|
22447
22447
|
await killProcessTree(pid, "SIGTERM");
|
|
22448
22448
|
if (graceMs <= 0) return;
|
|
22449
|
-
const exited = new Promise((
|
|
22450
|
-
child.once("exit", () =>
|
|
22449
|
+
const exited = new Promise((resolve26) => {
|
|
22450
|
+
child.once("exit", () => resolve26());
|
|
22451
22451
|
});
|
|
22452
|
-
await Promise.race([exited, new Promise((
|
|
22452
|
+
await Promise.race([exited, new Promise((resolve26) => setTimeout(resolve26, graceMs))]);
|
|
22453
22453
|
if (child.exitCode == null && child.signalCode == null) {
|
|
22454
22454
|
await killProcessTree(pid, "SIGKILL");
|
|
22455
22455
|
}
|
|
@@ -22466,8 +22466,8 @@ async function gracefulAcpSubprocessDisconnect(params) {
|
|
|
22466
22466
|
await transport.closeSession?.(sessionId);
|
|
22467
22467
|
} catch {
|
|
22468
22468
|
}
|
|
22469
|
-
await new Promise((
|
|
22470
|
-
const timer = setTimeout(
|
|
22469
|
+
await new Promise((resolve26) => {
|
|
22470
|
+
const timer = setTimeout(resolve26, ACP_GRACEFUL_SESSION_CLOSE_WAIT_MS);
|
|
22471
22471
|
timer.unref?.();
|
|
22472
22472
|
});
|
|
22473
22473
|
}
|
|
@@ -23172,9 +23172,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
23172
23172
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
23173
23173
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
23174
23174
|
if (!rawPath || !summary) continue;
|
|
23175
|
-
const
|
|
23176
|
-
if (!
|
|
23177
|
-
rows.push({ path:
|
|
23175
|
+
const path53 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
23176
|
+
if (!path53) continue;
|
|
23177
|
+
rows.push({ path: path53, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
23178
23178
|
}
|
|
23179
23179
|
return rows;
|
|
23180
23180
|
}
|
|
@@ -23392,7 +23392,7 @@ var GitRepoMetaSchema = external_exports.object({
|
|
|
23392
23392
|
updatedAt: external_exports.string()
|
|
23393
23393
|
});
|
|
23394
23394
|
|
|
23395
|
-
// ../types/src/bridge-mcp-
|
|
23395
|
+
// ../types/src/mcp/bridge-mcp-constants.ts
|
|
23396
23396
|
var GET_INTEGRATION_CONTENT_TOOL = "get_integration_content";
|
|
23397
23397
|
var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
|
|
23398
23398
|
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
|
|
@@ -23628,11 +23628,11 @@ function createSdkStdioExtNotificationHandler(options) {
|
|
|
23628
23628
|
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
23629
23629
|
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
23630
23630
|
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
23631
|
-
return new Promise((
|
|
23632
|
-
pending.set(requestId, { resolve:
|
|
23631
|
+
return new Promise((resolve26) => {
|
|
23632
|
+
pending.set(requestId, { resolve: resolve26, params: paramsRecord });
|
|
23633
23633
|
if (onRequest == null) {
|
|
23634
23634
|
pending.delete(requestId);
|
|
23635
|
-
|
|
23635
|
+
resolve26({ outcome: { outcome: "denied" } });
|
|
23636
23636
|
return;
|
|
23637
23637
|
}
|
|
23638
23638
|
try {
|
|
@@ -24176,10 +24176,10 @@ function createSdkStdioInitSettle(child) {
|
|
|
24176
24176
|
forceAcpSubprocessDisconnect(child);
|
|
24177
24177
|
reject(err);
|
|
24178
24178
|
},
|
|
24179
|
-
settleResolve(
|
|
24179
|
+
settleResolve(resolve26, handle) {
|
|
24180
24180
|
if (initSettled) return;
|
|
24181
24181
|
initSettled = true;
|
|
24182
|
-
|
|
24182
|
+
resolve26(handle);
|
|
24183
24183
|
}
|
|
24184
24184
|
};
|
|
24185
24185
|
}
|
|
@@ -24248,7 +24248,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
24248
24248
|
onFileChange,
|
|
24249
24249
|
stderrCapture
|
|
24250
24250
|
});
|
|
24251
|
-
return new Promise((
|
|
24251
|
+
return new Promise((resolve26, reject) => {
|
|
24252
24252
|
const init = createSdkStdioInitSettle(child);
|
|
24253
24253
|
child.on("error", (err) => {
|
|
24254
24254
|
init.settleReject(reject, new Error(formatSpawnError(err, command[0])));
|
|
@@ -24273,7 +24273,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
24273
24273
|
protocolVersion: PROTOCOL_VERSION2
|
|
24274
24274
|
});
|
|
24275
24275
|
init.settleResolve(
|
|
24276
|
-
|
|
24276
|
+
resolve26,
|
|
24277
24277
|
createSdkStdioHandle({
|
|
24278
24278
|
child,
|
|
24279
24279
|
sessionId: established.sessionId,
|
|
@@ -24381,7 +24381,7 @@ async function proxyToLocal(request) {
|
|
|
24381
24381
|
};
|
|
24382
24382
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
24383
24383
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
24384
|
-
const once = await new Promise((
|
|
24384
|
+
const once = await new Promise((resolve26) => {
|
|
24385
24385
|
const req = mod.request(opts, (res) => {
|
|
24386
24386
|
const chunks = [];
|
|
24387
24387
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -24392,7 +24392,7 @@ async function proxyToLocal(request) {
|
|
|
24392
24392
|
if (typeof v === "string") headers[k] = v;
|
|
24393
24393
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
24394
24394
|
}
|
|
24395
|
-
|
|
24395
|
+
resolve26({
|
|
24396
24396
|
id: request.id,
|
|
24397
24397
|
statusCode: res.statusCode ?? 0,
|
|
24398
24398
|
headers,
|
|
@@ -24401,7 +24401,7 @@ async function proxyToLocal(request) {
|
|
|
24401
24401
|
});
|
|
24402
24402
|
});
|
|
24403
24403
|
req.on("error", (err) => {
|
|
24404
|
-
|
|
24404
|
+
resolve26({
|
|
24405
24405
|
id: request.id,
|
|
24406
24406
|
statusCode: 0,
|
|
24407
24407
|
headers: {},
|
|
@@ -24483,8 +24483,8 @@ function randomSecret() {
|
|
|
24483
24483
|
}
|
|
24484
24484
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
24485
24485
|
}
|
|
24486
|
-
async function requestPreviewApi(port, secret, method,
|
|
24487
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
24486
|
+
async function requestPreviewApi(port, secret, method, path53, body) {
|
|
24487
|
+
const url2 = `http://127.0.0.1:${port}${path53}`;
|
|
24488
24488
|
const headers = {
|
|
24489
24489
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
24490
24490
|
"Content-Type": "application/json"
|
|
@@ -24496,7 +24496,7 @@ async function requestPreviewApi(port, secret, method, path46, body) {
|
|
|
24496
24496
|
});
|
|
24497
24497
|
const data = await res.json().catch(() => ({}));
|
|
24498
24498
|
if (!res.ok) {
|
|
24499
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
24499
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path53}: ${res.status}`);
|
|
24500
24500
|
}
|
|
24501
24501
|
return data;
|
|
24502
24502
|
}
|
|
@@ -24711,7 +24711,7 @@ function installBridgeProcessResilience() {
|
|
|
24711
24711
|
}
|
|
24712
24712
|
|
|
24713
24713
|
// src/cli-version.ts
|
|
24714
|
-
var CLI_VERSION = "0.1.
|
|
24714
|
+
var CLI_VERSION = "0.1.50".length > 0 ? "0.1.50" : "0.0.0-dev";
|
|
24715
24715
|
|
|
24716
24716
|
// src/connection/heartbeat/constants.ts
|
|
24717
24717
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -25152,14 +25152,14 @@ var baseOpen = async (options) => {
|
|
|
25152
25152
|
}
|
|
25153
25153
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
25154
25154
|
if (options.wait) {
|
|
25155
|
-
return new Promise((
|
|
25155
|
+
return new Promise((resolve26, reject) => {
|
|
25156
25156
|
subprocess.once("error", reject);
|
|
25157
25157
|
subprocess.once("close", (exitCode) => {
|
|
25158
25158
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
25159
25159
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
25160
25160
|
return;
|
|
25161
25161
|
}
|
|
25162
|
-
|
|
25162
|
+
resolve26(subprocess);
|
|
25163
25163
|
});
|
|
25164
25164
|
});
|
|
25165
25165
|
}
|
|
@@ -25703,8 +25703,8 @@ function runPendingAuth(options) {
|
|
|
25703
25703
|
let hasOpenedBrowser = false;
|
|
25704
25704
|
let resolved = false;
|
|
25705
25705
|
let resolveAuth;
|
|
25706
|
-
const authPromise = new Promise((
|
|
25707
|
-
resolveAuth =
|
|
25706
|
+
const authPromise = new Promise((resolve26) => {
|
|
25707
|
+
resolveAuth = resolve26;
|
|
25708
25708
|
});
|
|
25709
25709
|
let reconnectAttempt = 0;
|
|
25710
25710
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -25855,7 +25855,7 @@ import sqliteWasm from "node-sqlite3-wasm";
|
|
|
25855
25855
|
|
|
25856
25856
|
// src/runtime/yield-to-event-loop.ts
|
|
25857
25857
|
function yieldToEventLoop() {
|
|
25858
|
-
return new Promise((
|
|
25858
|
+
return new Promise((resolve26) => setImmediate(resolve26));
|
|
25859
25859
|
}
|
|
25860
25860
|
|
|
25861
25861
|
// src/sqlite/cli-sqlite-paths.ts
|
|
@@ -27019,7 +27019,7 @@ async function createCursorAcpClient(options) {
|
|
|
27019
27019
|
onFileChange,
|
|
27020
27020
|
stderrCapture
|
|
27021
27021
|
});
|
|
27022
|
-
return new Promise((
|
|
27022
|
+
return new Promise((resolve26, reject) => {
|
|
27023
27023
|
child.on("error", (err) => {
|
|
27024
27024
|
killChildProcessTree(child, "SIGKILL");
|
|
27025
27025
|
reject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -27031,7 +27031,7 @@ async function createCursorAcpClient(options) {
|
|
|
27031
27031
|
sessionCtx,
|
|
27032
27032
|
incomingDeps: { dbgFs, sessionCtx, onSessionUpdate, onRequest }
|
|
27033
27033
|
});
|
|
27034
|
-
|
|
27034
|
+
resolve26(
|
|
27035
27035
|
createCursorAcpHandle({
|
|
27036
27036
|
child,
|
|
27037
27037
|
sessionId: established.sessionId,
|
|
@@ -27969,7 +27969,7 @@ function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
|
|
|
27969
27969
|
}
|
|
27970
27970
|
|
|
27971
27971
|
// src/mcp/bridge-mcp-constants.ts
|
|
27972
|
-
var
|
|
27972
|
+
var BRIDGE_MCP_SERVER_NAME2 = "buildautomaton-bridge";
|
|
27973
27973
|
|
|
27974
27974
|
// src/mcp/resolve-bridge-mcp-server-path.ts
|
|
27975
27975
|
import { dirname as dirname4, join as join2 } from "node:path";
|
|
@@ -27984,7 +27984,7 @@ function buildAcpMcpServers(bridgeAccessPort) {
|
|
|
27984
27984
|
if (!Number.isFinite(bridgeAccessPort) || bridgeAccessPort <= 0) return [];
|
|
27985
27985
|
return [
|
|
27986
27986
|
{
|
|
27987
|
-
name:
|
|
27987
|
+
name: BRIDGE_MCP_SERVER_NAME2,
|
|
27988
27988
|
command: process.execPath,
|
|
27989
27989
|
args: [resolveBridgeMcpServerScriptPath(), String(bridgeAccessPort)],
|
|
27990
27990
|
env: []
|
|
@@ -28237,8 +28237,8 @@ function pathspec(...paths) {
|
|
|
28237
28237
|
cache.set(key, paths);
|
|
28238
28238
|
return key;
|
|
28239
28239
|
}
|
|
28240
|
-
function isPathSpec(
|
|
28241
|
-
return
|
|
28240
|
+
function isPathSpec(path53) {
|
|
28241
|
+
return path53 instanceof String && cache.has(path53);
|
|
28242
28242
|
}
|
|
28243
28243
|
function toPaths(pathSpec) {
|
|
28244
28244
|
return cache.get(pathSpec) || [];
|
|
@@ -28327,8 +28327,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
28327
28327
|
function forEachLineWithContent(input, callback) {
|
|
28328
28328
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
28329
28329
|
}
|
|
28330
|
-
function folderExists(
|
|
28331
|
-
return (0, import_file_exists.exists)(
|
|
28330
|
+
function folderExists(path53) {
|
|
28331
|
+
return (0, import_file_exists.exists)(path53, import_file_exists.FOLDER);
|
|
28332
28332
|
}
|
|
28333
28333
|
function append(target, item) {
|
|
28334
28334
|
if (Array.isArray(target)) {
|
|
@@ -28732,8 +28732,8 @@ function checkIsRepoRootTask() {
|
|
|
28732
28732
|
commands,
|
|
28733
28733
|
format: "utf-8",
|
|
28734
28734
|
onError,
|
|
28735
|
-
parser(
|
|
28736
|
-
return /^\.(git)?$/.test(
|
|
28735
|
+
parser(path53) {
|
|
28736
|
+
return /^\.(git)?$/.test(path53.trim());
|
|
28737
28737
|
}
|
|
28738
28738
|
};
|
|
28739
28739
|
}
|
|
@@ -29167,11 +29167,11 @@ function parseGrep(grep) {
|
|
|
29167
29167
|
const paths = /* @__PURE__ */ new Set();
|
|
29168
29168
|
const results = {};
|
|
29169
29169
|
forEachLineWithContent(grep, (input) => {
|
|
29170
|
-
const [
|
|
29171
|
-
paths.add(
|
|
29172
|
-
(results[
|
|
29170
|
+
const [path53, line, preview] = input.split(NULL);
|
|
29171
|
+
paths.add(path53);
|
|
29172
|
+
(results[path53] = results[path53] || []).push({
|
|
29173
29173
|
line: asNumber(line),
|
|
29174
|
-
path:
|
|
29174
|
+
path: path53,
|
|
29175
29175
|
preview
|
|
29176
29176
|
});
|
|
29177
29177
|
});
|
|
@@ -29936,14 +29936,14 @@ var init_hash_object = __esm2({
|
|
|
29936
29936
|
init_task();
|
|
29937
29937
|
}
|
|
29938
29938
|
});
|
|
29939
|
-
function parseInit(bare,
|
|
29939
|
+
function parseInit(bare, path53, text) {
|
|
29940
29940
|
const response = String(text).trim();
|
|
29941
29941
|
let result;
|
|
29942
29942
|
if (result = initResponseRegex.exec(response)) {
|
|
29943
|
-
return new InitSummary(bare,
|
|
29943
|
+
return new InitSummary(bare, path53, false, result[1]);
|
|
29944
29944
|
}
|
|
29945
29945
|
if (result = reInitResponseRegex.exec(response)) {
|
|
29946
|
-
return new InitSummary(bare,
|
|
29946
|
+
return new InitSummary(bare, path53, true, result[1]);
|
|
29947
29947
|
}
|
|
29948
29948
|
let gitDir = "";
|
|
29949
29949
|
const tokens = response.split(" ");
|
|
@@ -29954,7 +29954,7 @@ function parseInit(bare, path46, text) {
|
|
|
29954
29954
|
break;
|
|
29955
29955
|
}
|
|
29956
29956
|
}
|
|
29957
|
-
return new InitSummary(bare,
|
|
29957
|
+
return new InitSummary(bare, path53, /^re/i.test(response), gitDir);
|
|
29958
29958
|
}
|
|
29959
29959
|
var InitSummary;
|
|
29960
29960
|
var initResponseRegex;
|
|
@@ -29963,9 +29963,9 @@ var init_InitSummary = __esm2({
|
|
|
29963
29963
|
"src/lib/responses/InitSummary.ts"() {
|
|
29964
29964
|
"use strict";
|
|
29965
29965
|
InitSummary = class {
|
|
29966
|
-
constructor(bare,
|
|
29966
|
+
constructor(bare, path53, existing, gitDir) {
|
|
29967
29967
|
this.bare = bare;
|
|
29968
|
-
this.path =
|
|
29968
|
+
this.path = path53;
|
|
29969
29969
|
this.existing = existing;
|
|
29970
29970
|
this.gitDir = gitDir;
|
|
29971
29971
|
}
|
|
@@ -29977,7 +29977,7 @@ var init_InitSummary = __esm2({
|
|
|
29977
29977
|
function hasBareCommand(command) {
|
|
29978
29978
|
return command.includes(bareCommand);
|
|
29979
29979
|
}
|
|
29980
|
-
function initTask(bare = false,
|
|
29980
|
+
function initTask(bare = false, path53, customArgs) {
|
|
29981
29981
|
const commands = ["init", ...customArgs];
|
|
29982
29982
|
if (bare && !hasBareCommand(commands)) {
|
|
29983
29983
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29986,7 +29986,7 @@ function initTask(bare = false, path46, customArgs) {
|
|
|
29986
29986
|
commands,
|
|
29987
29987
|
format: "utf-8",
|
|
29988
29988
|
parser(text) {
|
|
29989
|
-
return parseInit(commands.includes("--bare"),
|
|
29989
|
+
return parseInit(commands.includes("--bare"), path53, text);
|
|
29990
29990
|
}
|
|
29991
29991
|
};
|
|
29992
29992
|
}
|
|
@@ -30802,12 +30802,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
30802
30802
|
"use strict";
|
|
30803
30803
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
30804
30804
|
FileStatusSummary = class {
|
|
30805
|
-
constructor(
|
|
30806
|
-
this.path =
|
|
30805
|
+
constructor(path53, index, working_dir) {
|
|
30806
|
+
this.path = path53;
|
|
30807
30807
|
this.index = index;
|
|
30808
30808
|
this.working_dir = working_dir;
|
|
30809
30809
|
if (index === "R" || working_dir === "R") {
|
|
30810
|
-
const detail = fromPathRegex.exec(
|
|
30810
|
+
const detail = fromPathRegex.exec(path53) || [null, path53, path53];
|
|
30811
30811
|
this.from = detail[2] || "";
|
|
30812
30812
|
this.path = detail[1] || "";
|
|
30813
30813
|
}
|
|
@@ -30838,14 +30838,14 @@ function splitLine(result, lineStr) {
|
|
|
30838
30838
|
default:
|
|
30839
30839
|
return;
|
|
30840
30840
|
}
|
|
30841
|
-
function data(index, workingDir,
|
|
30841
|
+
function data(index, workingDir, path53) {
|
|
30842
30842
|
const raw = `${index}${workingDir}`;
|
|
30843
30843
|
const handler = parsers6.get(raw);
|
|
30844
30844
|
if (handler) {
|
|
30845
|
-
handler(result,
|
|
30845
|
+
handler(result, path53);
|
|
30846
30846
|
}
|
|
30847
30847
|
if (raw !== "##" && raw !== "!!") {
|
|
30848
|
-
result.files.push(new FileStatusSummary(
|
|
30848
|
+
result.files.push(new FileStatusSummary(path53, index, workingDir));
|
|
30849
30849
|
}
|
|
30850
30850
|
}
|
|
30851
30851
|
}
|
|
@@ -31154,9 +31154,9 @@ var init_simple_git_api = __esm2({
|
|
|
31154
31154
|
next
|
|
31155
31155
|
);
|
|
31156
31156
|
}
|
|
31157
|
-
hashObject(
|
|
31157
|
+
hashObject(path53, write) {
|
|
31158
31158
|
return this._runTask(
|
|
31159
|
-
hashObjectTask(
|
|
31159
|
+
hashObjectTask(path53, write === true),
|
|
31160
31160
|
trailingFunctionArgument(arguments)
|
|
31161
31161
|
);
|
|
31162
31162
|
}
|
|
@@ -31509,8 +31509,8 @@ var init_branch = __esm2({
|
|
|
31509
31509
|
}
|
|
31510
31510
|
});
|
|
31511
31511
|
function toPath(input) {
|
|
31512
|
-
const
|
|
31513
|
-
return
|
|
31512
|
+
const path53 = input.trim().replace(/^["']|["']$/g, "");
|
|
31513
|
+
return path53 && normalize3(path53);
|
|
31514
31514
|
}
|
|
31515
31515
|
var parseCheckIgnore;
|
|
31516
31516
|
var init_CheckIgnore = __esm2({
|
|
@@ -31824,8 +31824,8 @@ __export2(sub_module_exports, {
|
|
|
31824
31824
|
subModuleTask: () => subModuleTask,
|
|
31825
31825
|
updateSubModuleTask: () => updateSubModuleTask
|
|
31826
31826
|
});
|
|
31827
|
-
function addSubModuleTask(repo,
|
|
31828
|
-
return subModuleTask(["add", repo,
|
|
31827
|
+
function addSubModuleTask(repo, path53) {
|
|
31828
|
+
return subModuleTask(["add", repo, path53]);
|
|
31829
31829
|
}
|
|
31830
31830
|
function initSubModuleTask(customArgs) {
|
|
31831
31831
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -32158,8 +32158,8 @@ var require_git = __commonJS2({
|
|
|
32158
32158
|
}
|
|
32159
32159
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
32160
32160
|
};
|
|
32161
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
32162
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
32161
|
+
Git2.prototype.submoduleAdd = function(repo, path53, then) {
|
|
32162
|
+
return this._runTask(addSubModuleTask2(repo, path53), trailingFunctionArgument2(arguments));
|
|
32163
32163
|
};
|
|
32164
32164
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
32165
32165
|
return this._runTask(
|
|
@@ -32796,14 +32796,14 @@ async function runGitTask(fn) {
|
|
|
32796
32796
|
}
|
|
32797
32797
|
async function yieldToEventLoop2() {
|
|
32798
32798
|
throwIfGitShutdownRequested();
|
|
32799
|
-
await new Promise((
|
|
32800
|
-
setImmediate(
|
|
32799
|
+
await new Promise((resolve26) => {
|
|
32800
|
+
setImmediate(resolve26);
|
|
32801
32801
|
});
|
|
32802
32802
|
throwIfGitShutdownRequested();
|
|
32803
32803
|
}
|
|
32804
32804
|
async function forEachWithGitYield(items, fn) {
|
|
32805
32805
|
for (let i = 0; i < items.length; i++) {
|
|
32806
|
-
|
|
32806
|
+
await yieldToEventLoop2();
|
|
32807
32807
|
await fn(items[i], i);
|
|
32808
32808
|
}
|
|
32809
32809
|
}
|
|
@@ -33122,9 +33122,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
33122
33122
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
33123
33123
|
async function putEncryptedChangeSummaryRows(params) {
|
|
33124
33124
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
33125
|
-
const entries = params.rows.map(({ path:
|
|
33125
|
+
const entries = params.rows.map(({ path: path53, summary }) => {
|
|
33126
33126
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
33127
|
-
return { path:
|
|
33127
|
+
return { path: path53, summary: JSON.stringify(enc) };
|
|
33128
33128
|
});
|
|
33129
33129
|
const res = await fetch(
|
|
33130
33130
|
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -33570,7 +33570,7 @@ function buildIntegrationContentAgentPromptNote(sessionId) {
|
|
|
33570
33570
|
"Use the get_integration_content MCP tool on the buildautomaton-bridge server to fetch the full content of each link.",
|
|
33571
33571
|
`When calling the tool, pass sessionId "${sessionRef}" and the URL as url.`,
|
|
33572
33572
|
"By default the tool links the fetched URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false when fetching additional links for context only (after the primary ticket is linked, or when you do not want association).",
|
|
33573
|
-
"If the tool reports unsupported_url, do not retry with the same URL. If it reports temporarily_unavailable, you may retry later."
|
|
33573
|
+
"If the tool reports unsupported_url, do not retry with the same URL. If it reports integration_reconnect_required, ask the user to reconnect the integration in workspace settings. If it reports temporarily_unavailable, you may retry later."
|
|
33574
33574
|
].join("\n");
|
|
33575
33575
|
}
|
|
33576
33576
|
function injectIntegrationContentAgentPromptNote(agentPrompt, sessionId) {
|
|
@@ -33605,7 +33605,7 @@ async function sendPromptToAgent(options) {
|
|
|
33605
33605
|
runId,
|
|
33606
33606
|
agentType,
|
|
33607
33607
|
agentCwd,
|
|
33608
|
-
sendResult
|
|
33608
|
+
sendResult,
|
|
33609
33609
|
sendSessionUpdate,
|
|
33610
33610
|
log: log2,
|
|
33611
33611
|
followUpCatalogPromptId,
|
|
@@ -33635,7 +33635,7 @@ async function sendPromptToAgent(options) {
|
|
|
33635
33635
|
let sendOpts = {};
|
|
33636
33636
|
if (attachments && attachments.length > 0) {
|
|
33637
33637
|
if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
|
|
33638
|
-
|
|
33638
|
+
sendResult({
|
|
33639
33639
|
type: "prompt_result",
|
|
33640
33640
|
id: promptId,
|
|
33641
33641
|
...sessionId ? { sessionId } : {},
|
|
@@ -33656,7 +33656,7 @@ async function sendPromptToAgent(options) {
|
|
|
33656
33656
|
log: log2
|
|
33657
33657
|
});
|
|
33658
33658
|
if (!resolved.ok) {
|
|
33659
|
-
|
|
33659
|
+
sendResult({
|
|
33660
33660
|
type: "prompt_result",
|
|
33661
33661
|
id: promptId,
|
|
33662
33662
|
...sessionId ? { sessionId } : {},
|
|
@@ -33695,7 +33695,7 @@ async function sendPromptToAgent(options) {
|
|
|
33695
33695
|
const errStr = typeof result.error === "string" ? result.error : void 0;
|
|
33696
33696
|
const resultStop = typeof result.stopReason === "string" ? result.stopReason.trim() : "";
|
|
33697
33697
|
const cancelledByAgent = resultStop.toLowerCase() === "cancelled" || errStr != null && isUserEndedSessionTurnErrorText(errStr);
|
|
33698
|
-
|
|
33698
|
+
sendResult({
|
|
33699
33699
|
type: "prompt_result",
|
|
33700
33700
|
id: promptId,
|
|
33701
33701
|
...sessionId ? { sessionId } : {},
|
|
@@ -33717,7 +33717,7 @@ async function sendPromptToAgent(options) {
|
|
|
33717
33717
|
} catch (err) {
|
|
33718
33718
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
33719
33719
|
log2(`[Agent] Send failed: ${errMsg}`);
|
|
33720
|
-
|
|
33720
|
+
sendResult({
|
|
33721
33721
|
type: "prompt_result",
|
|
33722
33722
|
id: promptId,
|
|
33723
33723
|
...sessionId ? { sessionId } : {},
|
|
@@ -33751,7 +33751,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33751
33751
|
agentType,
|
|
33752
33752
|
agentConfig,
|
|
33753
33753
|
sessionParentPath,
|
|
33754
|
-
sendResult
|
|
33754
|
+
sendResult,
|
|
33755
33755
|
sendSessionUpdate,
|
|
33756
33756
|
followUpCatalogPromptId,
|
|
33757
33757
|
sessionChangeSummaryFilePaths,
|
|
@@ -33768,7 +33768,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33768
33768
|
const activeRunId = runId;
|
|
33769
33769
|
const acpAgentKey = computeAcpAgentKey(preferredForPrompt, mode, agentConfig ?? null);
|
|
33770
33770
|
if (!acpAgentKey) {
|
|
33771
|
-
|
|
33771
|
+
sendResult({
|
|
33772
33772
|
type: "prompt_result",
|
|
33773
33773
|
id: promptId,
|
|
33774
33774
|
...sessionId ? { sessionId } : {},
|
|
@@ -33805,7 +33805,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33805
33805
|
const evaluated = Boolean(preferredForPrompt && errMsg.trim());
|
|
33806
33806
|
const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
|
|
33807
33807
|
const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
|
|
33808
|
-
|
|
33808
|
+
sendResult({
|
|
33809
33809
|
type: "prompt_result",
|
|
33810
33810
|
id: promptId,
|
|
33811
33811
|
...sessionId ? { sessionId } : {},
|
|
@@ -33825,7 +33825,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33825
33825
|
await handle.cancel?.();
|
|
33826
33826
|
} catch {
|
|
33827
33827
|
}
|
|
33828
|
-
|
|
33828
|
+
sendResult({
|
|
33829
33829
|
type: "prompt_result",
|
|
33830
33830
|
id: promptId,
|
|
33831
33831
|
...sessionId ? { sessionId } : {},
|
|
@@ -33846,7 +33846,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33846
33846
|
runId: activeRunId,
|
|
33847
33847
|
agentType: preferredForPrompt,
|
|
33848
33848
|
agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
|
|
33849
|
-
sendResult
|
|
33849
|
+
sendResult,
|
|
33850
33850
|
sendSessionUpdate,
|
|
33851
33851
|
log: ctx.log,
|
|
33852
33852
|
followUpCatalogPromptId,
|
|
@@ -33902,6 +33902,563 @@ async function createAcpManager(options) {
|
|
|
33902
33902
|
};
|
|
33903
33903
|
}
|
|
33904
33904
|
|
|
33905
|
+
// src/worktrees/worktree-layout-file.ts
|
|
33906
|
+
import * as fs16 from "node:fs";
|
|
33907
|
+
import * as path19 from "node:path";
|
|
33908
|
+
import os7 from "node:os";
|
|
33909
|
+
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
33910
|
+
function defaultWorktreeLayoutPath() {
|
|
33911
|
+
return path19.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
33912
|
+
}
|
|
33913
|
+
function normalizeLoadedLayout(raw) {
|
|
33914
|
+
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
33915
|
+
const j = raw;
|
|
33916
|
+
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
33917
|
+
}
|
|
33918
|
+
return { launcherCwds: [] };
|
|
33919
|
+
}
|
|
33920
|
+
function loadWorktreeLayout() {
|
|
33921
|
+
try {
|
|
33922
|
+
const p = defaultWorktreeLayoutPath();
|
|
33923
|
+
if (!fs16.existsSync(p)) return { launcherCwds: [] };
|
|
33924
|
+
const raw = JSON.parse(fs16.readFileSync(p, "utf8"));
|
|
33925
|
+
return normalizeLoadedLayout(raw);
|
|
33926
|
+
} catch {
|
|
33927
|
+
return { launcherCwds: [] };
|
|
33928
|
+
}
|
|
33929
|
+
}
|
|
33930
|
+
function saveWorktreeLayout(layout) {
|
|
33931
|
+
try {
|
|
33932
|
+
const dir = path19.dirname(defaultWorktreeLayoutPath());
|
|
33933
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
33934
|
+
fs16.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
33935
|
+
} catch {
|
|
33936
|
+
}
|
|
33937
|
+
}
|
|
33938
|
+
function baseNameSafe(pathString) {
|
|
33939
|
+
return path19.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
33940
|
+
}
|
|
33941
|
+
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
33942
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
33943
|
+
const existing = layout.launcherCwds.find((e) => path19.resolve(e.absolutePath) === norm);
|
|
33944
|
+
return existing?.dirName;
|
|
33945
|
+
}
|
|
33946
|
+
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
33947
|
+
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
33948
|
+
if (existing) return existing;
|
|
33949
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
33950
|
+
const base = baseNameSafe(norm);
|
|
33951
|
+
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
33952
|
+
let name = base;
|
|
33953
|
+
let n = 2;
|
|
33954
|
+
while (used.has(name)) {
|
|
33955
|
+
name = `${base}-${n}`;
|
|
33956
|
+
n += 1;
|
|
33957
|
+
}
|
|
33958
|
+
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
33959
|
+
saveWorktreeLayout(layout);
|
|
33960
|
+
return name;
|
|
33961
|
+
}
|
|
33962
|
+
|
|
33963
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
33964
|
+
import * as fs20 from "node:fs";
|
|
33965
|
+
import * as path24 from "node:path";
|
|
33966
|
+
|
|
33967
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
33968
|
+
import * as fs18 from "node:fs";
|
|
33969
|
+
import * as path21 from "node:path";
|
|
33970
|
+
|
|
33971
|
+
// src/worktrees/discovery/disk-walk-constants.ts
|
|
33972
|
+
var DISK_WALK_YIELD_EVERY = 64;
|
|
33973
|
+
var LEGACY_WALK_MAX_DEPTH = 12;
|
|
33974
|
+
var SKIP_DISK_WALK_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
33975
|
+
"node_modules",
|
|
33976
|
+
"bower_components",
|
|
33977
|
+
"vendor",
|
|
33978
|
+
"Pods",
|
|
33979
|
+
"Carthage",
|
|
33980
|
+
"DerivedData",
|
|
33981
|
+
".yarn",
|
|
33982
|
+
".pnpm-store",
|
|
33983
|
+
"dist",
|
|
33984
|
+
"build",
|
|
33985
|
+
".next",
|
|
33986
|
+
"coverage",
|
|
33987
|
+
".turbo",
|
|
33988
|
+
".cache",
|
|
33989
|
+
"target",
|
|
33990
|
+
"__pycache__"
|
|
33991
|
+
]);
|
|
33992
|
+
function shouldSkipDiskWalkEntry(name) {
|
|
33993
|
+
return name.startsWith(".") || SKIP_DISK_WALK_DIR_NAMES.has(name);
|
|
33994
|
+
}
|
|
33995
|
+
|
|
33996
|
+
// src/worktrees/discovery/disk-walk-utils.ts
|
|
33997
|
+
import * as fs17 from "node:fs";
|
|
33998
|
+
import * as path20 from "node:path";
|
|
33999
|
+
async function yieldDuringDiskWalk(state) {
|
|
34000
|
+
state.entries++;
|
|
34001
|
+
if (state.entries % DISK_WALK_YIELD_EVERY !== 0) return true;
|
|
34002
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
34003
|
+
await yieldToEventLoop();
|
|
34004
|
+
return !isCliImmediateShutdownRequested();
|
|
34005
|
+
}
|
|
34006
|
+
async function isGitDir(dirPath) {
|
|
34007
|
+
try {
|
|
34008
|
+
await fs17.promises.access(path20.join(dirPath, ".git"));
|
|
34009
|
+
return true;
|
|
34010
|
+
} catch {
|
|
34011
|
+
return false;
|
|
34012
|
+
}
|
|
34013
|
+
}
|
|
34014
|
+
|
|
34015
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
34016
|
+
async function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
34017
|
+
const out = [];
|
|
34018
|
+
const state = { entries: 0 };
|
|
34019
|
+
const walk = async (dir) => {
|
|
34020
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
34021
|
+
if (await isGitDir(dir)) {
|
|
34022
|
+
out.push(path21.resolve(dir));
|
|
34023
|
+
return;
|
|
34024
|
+
}
|
|
34025
|
+
let entries;
|
|
34026
|
+
try {
|
|
34027
|
+
entries = await fs18.promises.readdir(dir, { withFileTypes: true });
|
|
34028
|
+
} catch {
|
|
34029
|
+
return;
|
|
34030
|
+
}
|
|
34031
|
+
for (const e of entries) {
|
|
34032
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
34033
|
+
const full = path21.join(dir, e.name);
|
|
34034
|
+
if (!e.isDirectory()) continue;
|
|
34035
|
+
await walk(full);
|
|
34036
|
+
}
|
|
34037
|
+
};
|
|
34038
|
+
await walk(path21.resolve(rootPath));
|
|
34039
|
+
return { paths: [...new Set(out)], entriesVisited: state.entries };
|
|
34040
|
+
}
|
|
34041
|
+
async function collectWorktreeRootsNamed(root, sessionId, maxDepth = LEGACY_WALK_MAX_DEPTH) {
|
|
34042
|
+
const out = [];
|
|
34043
|
+
const state = { entries: 0 };
|
|
34044
|
+
const walk = async (dir, depth) => {
|
|
34045
|
+
if (depth > maxDepth) return;
|
|
34046
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
34047
|
+
let entries;
|
|
34048
|
+
try {
|
|
34049
|
+
entries = await fs18.promises.readdir(dir, { withFileTypes: true });
|
|
34050
|
+
} catch {
|
|
34051
|
+
return;
|
|
34052
|
+
}
|
|
34053
|
+
for (const e of entries) {
|
|
34054
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
34055
|
+
const full = path21.join(dir, e.name);
|
|
34056
|
+
if (!e.isDirectory()) continue;
|
|
34057
|
+
if (e.name === sessionId) {
|
|
34058
|
+
if (await isGitDir(full)) out.push(path21.resolve(full));
|
|
34059
|
+
continue;
|
|
34060
|
+
}
|
|
34061
|
+
if (await isGitDir(full)) continue;
|
|
34062
|
+
await walk(full, depth + 1);
|
|
34063
|
+
}
|
|
34064
|
+
};
|
|
34065
|
+
await walk(root, 0);
|
|
34066
|
+
return { paths: out, entriesVisited: state.entries };
|
|
34067
|
+
}
|
|
34068
|
+
|
|
34069
|
+
// src/worktrees/discovery/layout-keys-for-bridge-root.ts
|
|
34070
|
+
import * as path22 from "node:path";
|
|
34071
|
+
function layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk) {
|
|
34072
|
+
const bridge = path22.resolve(bridgeRoot);
|
|
34073
|
+
const preferred = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34074
|
+
const relevant = layout.launcherCwds.filter((e) => {
|
|
34075
|
+
const entry = path22.resolve(e.absolutePath);
|
|
34076
|
+
return bridge === entry || bridge.startsWith(entry + path22.sep) || entry.startsWith(bridge + path22.sep);
|
|
34077
|
+
}).sort((a, b) => path22.resolve(b.absolutePath).length - path22.resolve(a.absolutePath).length).map((e) => e.dirName).filter((name) => keysOnDisk.includes(name));
|
|
34078
|
+
const ordered = [];
|
|
34079
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34080
|
+
const add = (k) => {
|
|
34081
|
+
if (seen.has(k) || !keysOnDisk.includes(k)) return;
|
|
34082
|
+
seen.add(k);
|
|
34083
|
+
ordered.push(k);
|
|
34084
|
+
};
|
|
34085
|
+
if (preferred) add(preferred);
|
|
34086
|
+
for (const k of relevant) add(k);
|
|
34087
|
+
if (relevant.length > 0) {
|
|
34088
|
+
return ordered;
|
|
34089
|
+
}
|
|
34090
|
+
for (const k of keysOnDisk) add(k);
|
|
34091
|
+
return ordered;
|
|
34092
|
+
}
|
|
34093
|
+
|
|
34094
|
+
// src/worktrees/discovery/try-binding-from-session-directory.ts
|
|
34095
|
+
import * as fs19 from "node:fs";
|
|
34096
|
+
import * as path23 from "node:path";
|
|
34097
|
+
async function tryBindingFromSessionDirectory(sessionDir) {
|
|
34098
|
+
let st;
|
|
34099
|
+
try {
|
|
34100
|
+
st = await fs19.promises.stat(sessionDir);
|
|
34101
|
+
} catch {
|
|
34102
|
+
return null;
|
|
34103
|
+
}
|
|
34104
|
+
if (!st.isDirectory()) return null;
|
|
34105
|
+
const { paths: worktreePaths } = await collectGitRepoRootsUnderDirectory(sessionDir);
|
|
34106
|
+
if (worktreePaths.length === 0) return null;
|
|
34107
|
+
const abs = path23.resolve(sessionDir);
|
|
34108
|
+
return {
|
|
34109
|
+
sessionParentPath: abs,
|
|
34110
|
+
workingTreeRelRoot: abs,
|
|
34111
|
+
repoCheckoutPaths: worktreePaths
|
|
34112
|
+
};
|
|
34113
|
+
}
|
|
34114
|
+
|
|
34115
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
34116
|
+
async function discoverSessionWorktreeOnDisk(options) {
|
|
34117
|
+
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
34118
|
+
const sid = sessionId.trim();
|
|
34119
|
+
if (!sid) return null;
|
|
34120
|
+
try {
|
|
34121
|
+
await fs20.promises.access(worktreesRootPath);
|
|
34122
|
+
} catch {
|
|
34123
|
+
return null;
|
|
34124
|
+
}
|
|
34125
|
+
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34126
|
+
const keysOnDisk = [];
|
|
34127
|
+
if (preferredKey) keysOnDisk.push(preferredKey);
|
|
34128
|
+
try {
|
|
34129
|
+
for (const name of await fs20.promises.readdir(worktreesRootPath)) {
|
|
34130
|
+
if (name.startsWith(".")) continue;
|
|
34131
|
+
const p = path24.join(worktreesRootPath, name);
|
|
34132
|
+
let st;
|
|
34133
|
+
try {
|
|
34134
|
+
st = await fs20.promises.stat(p);
|
|
34135
|
+
} catch {
|
|
34136
|
+
continue;
|
|
34137
|
+
}
|
|
34138
|
+
if (!st.isDirectory()) continue;
|
|
34139
|
+
if (!keysOnDisk.includes(name)) keysOnDisk.push(name);
|
|
34140
|
+
}
|
|
34141
|
+
} catch {
|
|
34142
|
+
return null;
|
|
34143
|
+
}
|
|
34144
|
+
const keys = layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk);
|
|
34145
|
+
for (const key of keys) {
|
|
34146
|
+
if (isCliImmediateShutdownRequested()) return null;
|
|
34147
|
+
await yieldToEventLoop();
|
|
34148
|
+
const layoutRoot = path24.join(worktreesRootPath, key);
|
|
34149
|
+
let layoutSt;
|
|
34150
|
+
try {
|
|
34151
|
+
layoutSt = await fs20.promises.stat(layoutRoot);
|
|
34152
|
+
} catch {
|
|
34153
|
+
continue;
|
|
34154
|
+
}
|
|
34155
|
+
if (!layoutSt.isDirectory()) continue;
|
|
34156
|
+
const sessionDir = path24.join(layoutRoot, sid);
|
|
34157
|
+
const nested = await tryBindingFromSessionDirectory(sessionDir);
|
|
34158
|
+
if (nested) return nested;
|
|
34159
|
+
const legacy = await collectWorktreeRootsNamed(layoutRoot, sid);
|
|
34160
|
+
if (legacy.paths.length > 0) {
|
|
34161
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacy.paths) ?? path24.resolve(legacy.paths[0]);
|
|
34162
|
+
return {
|
|
34163
|
+
sessionParentPath: path24.resolve(isolated),
|
|
34164
|
+
workingTreeRelRoot: path24.resolve(layoutRoot),
|
|
34165
|
+
repoCheckoutPaths: legacy.paths.map((p) => path24.resolve(p))
|
|
34166
|
+
};
|
|
34167
|
+
}
|
|
34168
|
+
}
|
|
34169
|
+
return null;
|
|
34170
|
+
}
|
|
34171
|
+
|
|
34172
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
34173
|
+
import * as fs21 from "node:fs";
|
|
34174
|
+
import * as path26 from "node:path";
|
|
34175
|
+
|
|
34176
|
+
// src/worktrees/discovery/discover-legacy-binding-ascending-from-checkout.ts
|
|
34177
|
+
import * as path25 from "node:path";
|
|
34178
|
+
async function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
34179
|
+
const sid = sessionId.trim();
|
|
34180
|
+
if (!sid) return null;
|
|
34181
|
+
const hintR = path25.resolve(checkoutPath);
|
|
34182
|
+
let best = null;
|
|
34183
|
+
let cur = path25.dirname(hintR);
|
|
34184
|
+
for (let i = 0; i < 40; i++) {
|
|
34185
|
+
if (isCliImmediateShutdownRequested()) return best;
|
|
34186
|
+
await yieldToEventLoop();
|
|
34187
|
+
const paths = await collectWorktreeRootsNamed(cur, sid);
|
|
34188
|
+
if (paths.paths.some((p) => path25.resolve(p) === hintR)) {
|
|
34189
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths.paths) ?? path25.resolve(paths.paths[0]);
|
|
34190
|
+
best = {
|
|
34191
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34192
|
+
workingTreeRelRoot: path25.resolve(cur),
|
|
34193
|
+
repoCheckoutPaths: paths.paths.map((p) => path25.resolve(p))
|
|
34194
|
+
};
|
|
34195
|
+
}
|
|
34196
|
+
const next = path25.dirname(cur);
|
|
34197
|
+
if (next === cur) break;
|
|
34198
|
+
cur = next;
|
|
34199
|
+
}
|
|
34200
|
+
return best;
|
|
34201
|
+
}
|
|
34202
|
+
|
|
34203
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
34204
|
+
async function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
34205
|
+
const sid = sessionId.trim();
|
|
34206
|
+
if (!sid) return null;
|
|
34207
|
+
const hint = path26.resolve(sessionWorktreeRootPathOrHint);
|
|
34208
|
+
const underHint = await tryBindingFromSessionDirectory(path26.join(hint, sid));
|
|
34209
|
+
if (underHint) return underHint;
|
|
34210
|
+
const direct = await tryBindingFromSessionDirectory(hint);
|
|
34211
|
+
if (direct) {
|
|
34212
|
+
if (path26.basename(hint) === sid && await isGitDir(hint)) {
|
|
34213
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34214
|
+
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
34215
|
+
return legacyFromCheckout;
|
|
34216
|
+
}
|
|
34217
|
+
}
|
|
34218
|
+
return direct;
|
|
34219
|
+
}
|
|
34220
|
+
if (path26.basename(hint) === sid && await isGitDir(hint)) {
|
|
34221
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34222
|
+
if (legacyFromCheckout) return legacyFromCheckout;
|
|
34223
|
+
}
|
|
34224
|
+
let st;
|
|
34225
|
+
try {
|
|
34226
|
+
st = await fs21.promises.stat(hint);
|
|
34227
|
+
} catch {
|
|
34228
|
+
return null;
|
|
34229
|
+
}
|
|
34230
|
+
if (!st.isDirectory()) return null;
|
|
34231
|
+
const legacyPaths = await collectWorktreeRootsNamed(hint, sid);
|
|
34232
|
+
if (legacyPaths.paths.length === 0) return null;
|
|
34233
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths.paths) ?? path26.resolve(legacyPaths.paths[0]);
|
|
34234
|
+
return {
|
|
34235
|
+
sessionParentPath: path26.resolve(isolated),
|
|
34236
|
+
workingTreeRelRoot: hint,
|
|
34237
|
+
repoCheckoutPaths: legacyPaths.paths.map((p) => path26.resolve(p))
|
|
34238
|
+
};
|
|
34239
|
+
}
|
|
34240
|
+
|
|
34241
|
+
// src/worktrees/manager/discover-session-binding.ts
|
|
34242
|
+
var discoverInflightBySessionId = /* @__PURE__ */ new Map();
|
|
34243
|
+
function discoverSessionBindingAsync(params) {
|
|
34244
|
+
const sid = params.sessionId.trim();
|
|
34245
|
+
if (!sid) return Promise.resolve(null);
|
|
34246
|
+
const existing = discoverInflightBySessionId.get(sid);
|
|
34247
|
+
if (existing) return existing;
|
|
34248
|
+
const promise2 = discoverSessionWorktreeOnDisk({
|
|
34249
|
+
sessionId: sid,
|
|
34250
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
34251
|
+
layout: params.layout,
|
|
34252
|
+
bridgeRoot: getBridgeRoot()
|
|
34253
|
+
}).finally(() => {
|
|
34254
|
+
if (discoverInflightBySessionId.get(sid) === promise2) {
|
|
34255
|
+
discoverInflightBySessionId.delete(sid);
|
|
34256
|
+
}
|
|
34257
|
+
});
|
|
34258
|
+
discoverInflightBySessionId.set(sid, promise2);
|
|
34259
|
+
return promise2;
|
|
34260
|
+
}
|
|
34261
|
+
|
|
34262
|
+
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
34263
|
+
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
34264
|
+
if (!sessionId) return null;
|
|
34265
|
+
const sid = sessionId.trim();
|
|
34266
|
+
const cached2 = cache2.getSessionParentPath(sid);
|
|
34267
|
+
if (cached2) return cached2;
|
|
34268
|
+
const paths = ensureRepoCheckoutPaths(sid);
|
|
34269
|
+
if (!paths?.length) return null;
|
|
34270
|
+
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
34271
|
+
}
|
|
34272
|
+
function ensureRepoCheckoutPathsForSession(sessionId, cache2) {
|
|
34273
|
+
if (!sessionId?.trim()) return void 0;
|
|
34274
|
+
const cached2 = cache2.getRepoCheckoutPaths(sessionId.trim());
|
|
34275
|
+
return cached2?.length ? [...cached2] : void 0;
|
|
34276
|
+
}
|
|
34277
|
+
async function ensureRepoCheckoutPathsForSessionAsync(sessionId, cache2, discover) {
|
|
34278
|
+
if (!sessionId?.trim()) return void 0;
|
|
34279
|
+
const sid = sessionId.trim();
|
|
34280
|
+
const cached2 = cache2.getRepoCheckoutPaths(sid);
|
|
34281
|
+
if (cached2?.length) return cached2;
|
|
34282
|
+
const disc = await discover(sid);
|
|
34283
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
34284
|
+
cache2.remember(sid, disc);
|
|
34285
|
+
return [...disc.repoCheckoutPaths];
|
|
34286
|
+
}
|
|
34287
|
+
return void 0;
|
|
34288
|
+
}
|
|
34289
|
+
|
|
34290
|
+
// src/worktrees/manager/parse-session-parent.ts
|
|
34291
|
+
function parseSessionParent(v) {
|
|
34292
|
+
if (v === "bridge_root" || v === "worktrees_root") return v;
|
|
34293
|
+
if (v === "session_worktrees_root") return "worktrees_root";
|
|
34294
|
+
return null;
|
|
34295
|
+
}
|
|
34296
|
+
|
|
34297
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34298
|
+
import * as fs22 from "node:fs";
|
|
34299
|
+
import * as path27 from "node:path";
|
|
34300
|
+
|
|
34301
|
+
// src/git/worktrees/worktree-add.ts
|
|
34302
|
+
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
34303
|
+
const mainGit = cliSimpleGit(mainRepoPath);
|
|
34304
|
+
const base = baseRef.trim() || "HEAD";
|
|
34305
|
+
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
34306
|
+
}
|
|
34307
|
+
|
|
34308
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34309
|
+
function normalizeRepoRelPath(rel) {
|
|
34310
|
+
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
34311
|
+
}
|
|
34312
|
+
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
34313
|
+
if (!baseBranches) return "HEAD";
|
|
34314
|
+
const direct = baseBranches[relNorm]?.trim();
|
|
34315
|
+
if (direct) return direct;
|
|
34316
|
+
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
34317
|
+
return "HEAD";
|
|
34318
|
+
}
|
|
34319
|
+
async function prepareNewSessionWorktrees(options) {
|
|
34320
|
+
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
34321
|
+
const bridgeResolved = path27.resolve(bridgeRoot);
|
|
34322
|
+
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
34323
|
+
const bridgeKeyDir = path27.join(worktreesRootPath, cwdKey);
|
|
34324
|
+
const sessionDir = path27.join(bridgeKeyDir, sessionId);
|
|
34325
|
+
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
34326
|
+
if (repos.length === 0) {
|
|
34327
|
+
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
34328
|
+
return null;
|
|
34329
|
+
}
|
|
34330
|
+
const branch = `session-${sessionId}`;
|
|
34331
|
+
const worktreePaths = [];
|
|
34332
|
+
fs22.mkdirSync(sessionDir, { recursive: true });
|
|
34333
|
+
for (const repo of repos) {
|
|
34334
|
+
let rel = path27.relative(bridgeResolved, repo.absolutePath);
|
|
34335
|
+
if (rel.startsWith("..") || path27.isAbsolute(rel)) continue;
|
|
34336
|
+
const relNorm = normalizeRepoRelPath(rel === "" ? "." : rel);
|
|
34337
|
+
const wtPath = relNorm === "." ? sessionDir : path27.join(sessionDir, relNorm);
|
|
34338
|
+
if (relNorm !== ".") {
|
|
34339
|
+
fs22.mkdirSync(path27.dirname(wtPath), { recursive: true });
|
|
34340
|
+
}
|
|
34341
|
+
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
34342
|
+
try {
|
|
34343
|
+
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
34344
|
+
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
34345
|
+
worktreePaths.push(wtPath);
|
|
34346
|
+
} catch (e) {
|
|
34347
|
+
log2(
|
|
34348
|
+
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
34349
|
+
);
|
|
34350
|
+
}
|
|
34351
|
+
}
|
|
34352
|
+
if (worktreePaths.length === 0) return null;
|
|
34353
|
+
return {
|
|
34354
|
+
worktreePaths,
|
|
34355
|
+
sessionParentPath: sessionDir,
|
|
34356
|
+
workingTreeRelRoot: sessionDir
|
|
34357
|
+
};
|
|
34358
|
+
}
|
|
34359
|
+
|
|
34360
|
+
// src/worktrees/manager/prepare-and-remember-session-worktrees.ts
|
|
34361
|
+
async function prepareAndRememberSessionWorktrees(params) {
|
|
34362
|
+
const prep = await prepareNewSessionWorktrees({
|
|
34363
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
34364
|
+
bridgeRoot: getBridgeRoot(),
|
|
34365
|
+
sessionId: params.sessionId,
|
|
34366
|
+
layout: params.layout,
|
|
34367
|
+
log: params.log,
|
|
34368
|
+
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
34369
|
+
});
|
|
34370
|
+
if (!prep) return void 0;
|
|
34371
|
+
params.cache.remember(params.sessionId, {
|
|
34372
|
+
sessionParentPath: prep.sessionParentPath,
|
|
34373
|
+
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
34374
|
+
repoCheckoutPaths: prep.worktreePaths
|
|
34375
|
+
});
|
|
34376
|
+
return params.cache.getSessionParentPath(params.sessionId);
|
|
34377
|
+
}
|
|
34378
|
+
|
|
34379
|
+
// src/worktrees/manager/resolve-existing-session-parent-path.ts
|
|
34380
|
+
async function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
34381
|
+
const cached2 = cache2.getSessionParentPath(sessionId);
|
|
34382
|
+
if (cached2) return cached2;
|
|
34383
|
+
const disc = await discover();
|
|
34384
|
+
if (disc) {
|
|
34385
|
+
cache2.remember(sessionId, disc);
|
|
34386
|
+
return cache2.getSessionParentPath(sessionId);
|
|
34387
|
+
}
|
|
34388
|
+
return void 0;
|
|
34389
|
+
}
|
|
34390
|
+
|
|
34391
|
+
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
34392
|
+
import * as path28 from "node:path";
|
|
34393
|
+
async function resolveExplicitSessionParentPath(params) {
|
|
34394
|
+
const resolved = path28.resolve(params.parentPathRaw);
|
|
34395
|
+
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
34396
|
+
return resolved;
|
|
34397
|
+
}
|
|
34398
|
+
const rememberAndReturn = (binding) => {
|
|
34399
|
+
params.cache.remember(params.sessionId, binding);
|
|
34400
|
+
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
34401
|
+
};
|
|
34402
|
+
const diskFirst = await params.discover();
|
|
34403
|
+
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
34404
|
+
const fromRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
34405
|
+
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
34406
|
+
let cur = resolved;
|
|
34407
|
+
for (let i = 0; i < 16; i++) {
|
|
34408
|
+
await yieldToEventLoop();
|
|
34409
|
+
const tryRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
34410
|
+
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
34411
|
+
const next = path28.dirname(cur);
|
|
34412
|
+
if (next === cur) break;
|
|
34413
|
+
cur = next;
|
|
34414
|
+
}
|
|
34415
|
+
return resolved;
|
|
34416
|
+
}
|
|
34417
|
+
|
|
34418
|
+
// src/worktrees/manager/resolve-session-parent-path-for-prompt.ts
|
|
34419
|
+
async function resolveSessionParentPathForPrompt(params) {
|
|
34420
|
+
const { sessionId, cache: cache2, worktreesRootPath, layout, log: log2, discover, opts } = params;
|
|
34421
|
+
if (!sessionId) return void 0;
|
|
34422
|
+
const sid = sessionId.trim();
|
|
34423
|
+
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
34424
|
+
if (parentPathRaw) {
|
|
34425
|
+
return resolveExplicitSessionParentPath({
|
|
34426
|
+
sessionId: sid,
|
|
34427
|
+
sessionParent: opts.sessionParent,
|
|
34428
|
+
parentPathRaw,
|
|
34429
|
+
cache: cache2,
|
|
34430
|
+
discover: () => discover(sid)
|
|
34431
|
+
});
|
|
34432
|
+
}
|
|
34433
|
+
const parentKind = parseSessionParent(opts.sessionParent);
|
|
34434
|
+
if (parentKind === "bridge_root") {
|
|
34435
|
+
return void 0;
|
|
34436
|
+
}
|
|
34437
|
+
if (parentKind === "worktrees_root") {
|
|
34438
|
+
if (!opts.isNewSession) {
|
|
34439
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
34440
|
+
}
|
|
34441
|
+
return prepareAndRememberSessionWorktrees({
|
|
34442
|
+
cache: cache2,
|
|
34443
|
+
sessionId: sid,
|
|
34444
|
+
worktreesRootPath,
|
|
34445
|
+
layout,
|
|
34446
|
+
log: log2,
|
|
34447
|
+
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
34448
|
+
});
|
|
34449
|
+
}
|
|
34450
|
+
if (!opts.isNewSession) {
|
|
34451
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
34452
|
+
}
|
|
34453
|
+
return prepareAndRememberSessionWorktrees({
|
|
34454
|
+
cache: cache2,
|
|
34455
|
+
sessionId: sid,
|
|
34456
|
+
worktreesRootPath,
|
|
34457
|
+
layout,
|
|
34458
|
+
log: log2
|
|
34459
|
+
});
|
|
34460
|
+
}
|
|
34461
|
+
|
|
33905
34462
|
// src/git/changes/types.ts
|
|
33906
34463
|
var MAX_PATCH_CHARS = 35e4;
|
|
33907
34464
|
|
|
@@ -33959,8 +34516,11 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
33959
34516
|
return `origin \xB7 ${hostPath}`;
|
|
33960
34517
|
}
|
|
33961
34518
|
|
|
33962
|
-
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
33963
|
-
import * as
|
|
34519
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
34520
|
+
import * as path33 from "node:path";
|
|
34521
|
+
|
|
34522
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
34523
|
+
import * as path32 from "node:path";
|
|
33964
34524
|
|
|
33965
34525
|
// src/git/commits/resolve-remote-tracking.ts
|
|
33966
34526
|
async function tryConfigGet(g, key) {
|
|
@@ -34131,8 +34691,8 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
34131
34691
|
}
|
|
34132
34692
|
|
|
34133
34693
|
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
34134
|
-
function normalizeGitDiffPath(
|
|
34135
|
-
return
|
|
34694
|
+
function normalizeGitDiffPath(path53) {
|
|
34695
|
+
return path53.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
34136
34696
|
}
|
|
34137
34697
|
|
|
34138
34698
|
// src/git/changes/parse/expand-git-rename-numstat-path.ts
|
|
@@ -34245,8 +34805,8 @@ async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, mov
|
|
|
34245
34805
|
}
|
|
34246
34806
|
|
|
34247
34807
|
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
34248
|
-
import * as
|
|
34249
|
-
import * as
|
|
34808
|
+
import * as fs23 from "node:fs";
|
|
34809
|
+
import * as path29 from "node:path";
|
|
34250
34810
|
|
|
34251
34811
|
// src/git/changes/lines/count-lines.ts
|
|
34252
34812
|
import { createReadStream } from "node:fs";
|
|
@@ -34292,13 +34852,13 @@ async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
|
|
|
34292
34852
|
}
|
|
34293
34853
|
async function resolveWorkingTreeFileTotalLines(options) {
|
|
34294
34854
|
if (options.isBinary) return null;
|
|
34295
|
-
const filePath =
|
|
34855
|
+
const filePath = path29.join(options.repoGitCwd, options.pathInRepo);
|
|
34296
34856
|
if (options.change === "removed") {
|
|
34297
34857
|
return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
|
|
34298
34858
|
}
|
|
34299
34859
|
if (options.change === "moved" || options.change === "modified") {
|
|
34300
34860
|
try {
|
|
34301
|
-
const st = await
|
|
34861
|
+
const st = await fs23.promises.stat(filePath);
|
|
34302
34862
|
if (!st.isFile()) return null;
|
|
34303
34863
|
return await countTextFileLines(filePath);
|
|
34304
34864
|
} catch {
|
|
@@ -34327,7 +34887,7 @@ function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
|
|
|
34327
34887
|
}
|
|
34328
34888
|
return pathRelLauncher;
|
|
34329
34889
|
}
|
|
34330
|
-
function
|
|
34890
|
+
function normalizeRepoRelPath2(repoRelPath) {
|
|
34331
34891
|
return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
34332
34892
|
}
|
|
34333
34893
|
|
|
@@ -34429,8 +34989,8 @@ function parseNumstatEntries(lines) {
|
|
|
34429
34989
|
}
|
|
34430
34990
|
function parseNumstat(lines) {
|
|
34431
34991
|
const m = /* @__PURE__ */ new Map();
|
|
34432
|
-
for (const [
|
|
34433
|
-
m.set(
|
|
34992
|
+
for (const [path53, entry] of parseNumstatEntries(lines)) {
|
|
34993
|
+
m.set(path53, { additions: entry.additions, deletions: entry.deletions });
|
|
34434
34994
|
}
|
|
34435
34995
|
return m;
|
|
34436
34996
|
}
|
|
@@ -34561,7 +35121,7 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
34561
35121
|
g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
|
|
34562
35122
|
]);
|
|
34563
35123
|
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
34564
|
-
const normRel =
|
|
35124
|
+
const normRel = normalizeRepoRelPath2(repoRelPath);
|
|
34565
35125
|
const paths = collectChangedPaths({
|
|
34566
35126
|
nameEntries: parsed.nameEntries,
|
|
34567
35127
|
numByPath: parsed.numByPath
|
|
@@ -34589,14 +35149,14 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
34589
35149
|
}
|
|
34590
35150
|
|
|
34591
35151
|
// src/git/changes/listing/apply-untracked-file-stats.ts
|
|
34592
|
-
import * as
|
|
34593
|
-
import * as
|
|
35152
|
+
import * as fs24 from "node:fs";
|
|
35153
|
+
import * as path30 from "node:path";
|
|
34594
35154
|
function createUntrackedStatsApplier(options) {
|
|
34595
35155
|
return async (row, pathInRepo) => {
|
|
34596
35156
|
if (!options.untrackedSet.has(pathInRepo)) return;
|
|
34597
35157
|
if (options.nameByPath.has(pathInRepo)) return;
|
|
34598
35158
|
if (row.change === "moved") return;
|
|
34599
|
-
const repoFilePath =
|
|
35159
|
+
const repoFilePath = path30.join(options.repoGitCwd, pathInRepo);
|
|
34600
35160
|
const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
|
|
34601
35161
|
if (fromGit) {
|
|
34602
35162
|
row.additions = fromGit.additions;
|
|
@@ -34604,7 +35164,7 @@ function createUntrackedStatsApplier(options) {
|
|
|
34604
35164
|
return;
|
|
34605
35165
|
}
|
|
34606
35166
|
try {
|
|
34607
|
-
const st = await
|
|
35167
|
+
const st = await fs24.promises.stat(repoFilePath);
|
|
34608
35168
|
row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
|
|
34609
35169
|
} catch {
|
|
34610
35170
|
row.additions = 0;
|
|
@@ -34614,13 +35174,75 @@ function createUntrackedStatsApplier(options) {
|
|
|
34614
35174
|
}
|
|
34615
35175
|
|
|
34616
35176
|
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
34617
|
-
import * as
|
|
35177
|
+
import * as path31 from "node:path";
|
|
34618
35178
|
|
|
34619
|
-
// src/git/changes/patch/hydrate-
|
|
34620
|
-
|
|
35179
|
+
// src/git/changes/patch/hydrate/append-injected-context-lines.ts
|
|
35180
|
+
async function appendInjectedContextLines(out, inject, maybeYield, injectedTotal) {
|
|
35181
|
+
for (const t of inject) {
|
|
35182
|
+
out.push(` ${t}`);
|
|
35183
|
+
injectedTotal.value++;
|
|
35184
|
+
await maybeYield();
|
|
35185
|
+
}
|
|
35186
|
+
}
|
|
35187
|
+
|
|
35188
|
+
// src/git/changes/patch/hydrate/constants.ts
|
|
34621
35189
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
34622
35190
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
34623
35191
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
35192
|
+
var HYDRATE_YIELD_EVERY_LINES = 512;
|
|
35193
|
+
|
|
35194
|
+
// src/git/changes/patch/hydrate/collect-gap-inject-lines.ts
|
|
35195
|
+
async function collectGapInjectLines(options) {
|
|
35196
|
+
if (options.injectedTotal >= MAX_HYDRATE_LINES_PER_FILE) return null;
|
|
35197
|
+
const remaining = MAX_HYDRATE_LINES_PER_FILE - options.injectedTotal;
|
|
35198
|
+
if (options.gapNewEnd >= options.gapNewStart && options.change !== "removed") {
|
|
35199
|
+
const nNew = options.gapNewEnd - options.gapNewStart + 1;
|
|
35200
|
+
if (options.gapOldEnd < options.gapOldStart || options.gapOldEnd - options.gapOldStart + 1 === nNew) {
|
|
35201
|
+
const cap = Math.min(nNew, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
35202
|
+
const dl = await options.diskLines();
|
|
35203
|
+
if (dl && cap > 0) {
|
|
35204
|
+
return dl.slice(options.gapNewStart - 1, options.gapNewStart - 1 + cap);
|
|
35205
|
+
}
|
|
35206
|
+
}
|
|
35207
|
+
return null;
|
|
35208
|
+
}
|
|
35209
|
+
if (options.gapOldEnd >= options.gapOldStart && options.change === "removed") {
|
|
35210
|
+
const nOld = options.gapOldEnd - options.gapOldStart + 1;
|
|
35211
|
+
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
35212
|
+
const bl = await options.blobLines();
|
|
35213
|
+
if (bl && cap > 0) {
|
|
35214
|
+
return bl.slice(options.gapOldStart - 1, options.gapOldStart - 1 + cap);
|
|
35215
|
+
}
|
|
35216
|
+
}
|
|
35217
|
+
return null;
|
|
35218
|
+
}
|
|
35219
|
+
|
|
35220
|
+
// src/git/changes/patch/hydrate/consume-unified-hunk-body.ts
|
|
35221
|
+
async function consumeUnifiedHunkBody(options) {
|
|
35222
|
+
let i = options.startIndex;
|
|
35223
|
+
let oldConsumed = 0;
|
|
35224
|
+
let newConsumed = 0;
|
|
35225
|
+
while (i < options.all.length) {
|
|
35226
|
+
await options.maybeYield();
|
|
35227
|
+
const bl = options.all[i];
|
|
35228
|
+
if (UNIFIED_HUNK_HEADER_RE.test(bl)) break;
|
|
35229
|
+
options.out.push(bl);
|
|
35230
|
+
i++;
|
|
35231
|
+
if (bl.startsWith("\\")) continue;
|
|
35232
|
+
const ch = bl[0];
|
|
35233
|
+
if (ch === " ") {
|
|
35234
|
+
oldConsumed++;
|
|
35235
|
+
newConsumed++;
|
|
35236
|
+
} else if (ch === "-") {
|
|
35237
|
+
oldConsumed++;
|
|
35238
|
+
} else if (ch === "+") {
|
|
35239
|
+
newConsumed++;
|
|
35240
|
+
}
|
|
35241
|
+
}
|
|
35242
|
+
return { nextIndex: i, oldConsumed, newConsumed };
|
|
35243
|
+
}
|
|
35244
|
+
|
|
35245
|
+
// src/git/changes/patch/hydrate/read-git-blob-lines.ts
|
|
34624
35246
|
async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
34625
35247
|
try {
|
|
34626
35248
|
const rel = pathInRepo.replace(/\\/g, "/");
|
|
@@ -34630,35 +35252,66 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
34630
35252
|
return null;
|
|
34631
35253
|
}
|
|
34632
35254
|
}
|
|
35255
|
+
|
|
35256
|
+
// src/git/changes/patch/hydrate/read-worktree-file-lines.ts
|
|
35257
|
+
import * as fs25 from "node:fs";
|
|
34633
35258
|
async function readWorktreeFileLines(filePath) {
|
|
34634
35259
|
try {
|
|
34635
|
-
const raw = await
|
|
35260
|
+
const raw = await fs25.promises.readFile(filePath, "utf8");
|
|
34636
35261
|
return raw.split(/\r?\n/);
|
|
34637
35262
|
} catch {
|
|
34638
35263
|
return null;
|
|
34639
35264
|
}
|
|
34640
35265
|
}
|
|
34641
|
-
|
|
34642
|
-
|
|
34643
|
-
|
|
34644
|
-
const out = [];
|
|
34645
|
-
let prevOldEnd = 0;
|
|
34646
|
-
let prevNewEnd = 0;
|
|
34647
|
-
let injectedTotal = 0;
|
|
34648
|
-
let i = 0;
|
|
35266
|
+
|
|
35267
|
+
// src/git/changes/patch/hydrate/create-hydrate-source-lines.ts
|
|
35268
|
+
function createHydrateSourceLines(options) {
|
|
34649
35269
|
let blobCache;
|
|
34650
35270
|
let diskCache;
|
|
34651
35271
|
const blobLines = async () => {
|
|
34652
35272
|
if (blobCache !== void 0) return blobCache;
|
|
34653
|
-
blobCache = await readGitBlobLines(repoGitCwd, pathInRepo);
|
|
35273
|
+
blobCache = await readGitBlobLines(options.repoGitCwd, options.pathInRepo);
|
|
34654
35274
|
return blobCache;
|
|
34655
35275
|
};
|
|
34656
35276
|
const diskLines = async () => {
|
|
34657
35277
|
if (diskCache !== void 0) return diskCache;
|
|
34658
|
-
diskCache = await readWorktreeFileLines(filePath);
|
|
35278
|
+
diskCache = await readWorktreeFileLines(options.filePath);
|
|
34659
35279
|
return diskCache;
|
|
34660
35280
|
};
|
|
35281
|
+
return { blobLines, diskLines };
|
|
35282
|
+
}
|
|
35283
|
+
|
|
35284
|
+
// src/git/changes/patch/hydrate/create-hydrate-yield.ts
|
|
35285
|
+
function createHydrateYield() {
|
|
35286
|
+
let processedLines = 0;
|
|
35287
|
+
return async () => {
|
|
35288
|
+
processedLines++;
|
|
35289
|
+
if (processedLines % HYDRATE_YIELD_EVERY_LINES === 0) {
|
|
35290
|
+
await yieldToEventLoop();
|
|
35291
|
+
}
|
|
35292
|
+
};
|
|
35293
|
+
}
|
|
35294
|
+
|
|
35295
|
+
// src/git/changes/patch/hydrate/update-hunk-line-ends.ts
|
|
35296
|
+
function updateHunkLineEnds(options) {
|
|
35297
|
+
const prevOldEnd = options.oldStart > 0 ? options.oldStart + options.oldConsumed - 1 : 0;
|
|
35298
|
+
const prevNewEnd = options.newStart > 0 ? options.newStart + options.newConsumed - 1 : 0;
|
|
35299
|
+
return { prevOldEnd, prevNewEnd };
|
|
35300
|
+
}
|
|
35301
|
+
|
|
35302
|
+
// src/git/changes/patch/hydrate/hydrate-unified-patch-with-file-context.ts
|
|
35303
|
+
async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, change) {
|
|
35304
|
+
if (!patch.trim() || patch.includes("Binary files")) return patch;
|
|
35305
|
+
const all = patch.split("\n");
|
|
35306
|
+
const out = [];
|
|
35307
|
+
let prevOldEnd = 0;
|
|
35308
|
+
let prevNewEnd = 0;
|
|
35309
|
+
const injectedTotal = { value: 0 };
|
|
35310
|
+
let i = 0;
|
|
35311
|
+
const maybeYield = createHydrateYield();
|
|
35312
|
+
const { blobLines, diskLines } = createHydrateSourceLines({ repoGitCwd, pathInRepo, filePath });
|
|
34661
35313
|
while (i < all.length) {
|
|
35314
|
+
await maybeYield();
|
|
34662
35315
|
const line = all[i];
|
|
34663
35316
|
const hm = line.match(UNIFIED_HUNK_HEADER_RE);
|
|
34664
35317
|
if (!hm) {
|
|
@@ -34668,66 +35321,31 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
34668
35321
|
}
|
|
34669
35322
|
const oldStart = parseInt(hm[1], 10) || 0;
|
|
34670
35323
|
const newStart = parseInt(hm[3], 10) || 0;
|
|
34671
|
-
const
|
|
34672
|
-
|
|
34673
|
-
|
|
34674
|
-
|
|
34675
|
-
|
|
34676
|
-
|
|
34677
|
-
|
|
34678
|
-
|
|
34679
|
-
|
|
34680
|
-
|
|
34681
|
-
|
|
34682
|
-
|
|
34683
|
-
inject = dl.slice(gapNewStart - 1, gapNewStart - 1 + cap);
|
|
34684
|
-
}
|
|
34685
|
-
}
|
|
34686
|
-
} else if (gapOldEnd >= gapOldStart && change === "removed") {
|
|
34687
|
-
const nOld = gapOldEnd - gapOldStart + 1;
|
|
34688
|
-
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, MAX_HYDRATE_LINES_PER_FILE - injectedTotal);
|
|
34689
|
-
const bl = await blobLines();
|
|
34690
|
-
if (bl && cap > 0) {
|
|
34691
|
-
inject = bl.slice(gapOldStart - 1, gapOldStart - 1 + cap);
|
|
34692
|
-
}
|
|
34693
|
-
}
|
|
34694
|
-
if (inject && inject.length > 0) {
|
|
34695
|
-
for (const t of inject) {
|
|
34696
|
-
out.push(` ${t}`);
|
|
34697
|
-
injectedTotal++;
|
|
34698
|
-
}
|
|
34699
|
-
}
|
|
35324
|
+
const inject = await collectGapInjectLines({
|
|
35325
|
+
change,
|
|
35326
|
+
gapOldStart: prevOldEnd + 1,
|
|
35327
|
+
gapOldEnd: oldStart - 1,
|
|
35328
|
+
gapNewStart: prevNewEnd + 1,
|
|
35329
|
+
gapNewEnd: newStart - 1,
|
|
35330
|
+
injectedTotal: injectedTotal.value,
|
|
35331
|
+
blobLines,
|
|
35332
|
+
diskLines
|
|
35333
|
+
});
|
|
35334
|
+
if (inject && inject.length > 0) {
|
|
35335
|
+
await appendInjectedContextLines(out, inject, maybeYield, injectedTotal);
|
|
34700
35336
|
}
|
|
34701
35337
|
out.push(line);
|
|
34702
35338
|
i++;
|
|
34703
|
-
|
|
34704
|
-
|
|
34705
|
-
|
|
34706
|
-
|
|
34707
|
-
|
|
34708
|
-
|
|
34709
|
-
|
|
34710
|
-
|
|
34711
|
-
|
|
34712
|
-
|
|
34713
|
-
oldConsumed++;
|
|
34714
|
-
newConsumed++;
|
|
34715
|
-
} else if (ch === "-") {
|
|
34716
|
-
oldConsumed++;
|
|
34717
|
-
} else if (ch === "+") {
|
|
34718
|
-
newConsumed++;
|
|
34719
|
-
}
|
|
34720
|
-
}
|
|
34721
|
-
if (oldStart > 0) {
|
|
34722
|
-
prevOldEnd = oldStart + oldConsumed - 1;
|
|
34723
|
-
} else {
|
|
34724
|
-
prevOldEnd = 0;
|
|
34725
|
-
}
|
|
34726
|
-
if (newStart > 0) {
|
|
34727
|
-
prevNewEnd = newStart + newConsumed - 1;
|
|
34728
|
-
} else {
|
|
34729
|
-
prevNewEnd = 0;
|
|
34730
|
-
}
|
|
35339
|
+
const body = await consumeUnifiedHunkBody({ all, startIndex: i, out, maybeYield });
|
|
35340
|
+
i = body.nextIndex;
|
|
35341
|
+
const ends = updateHunkLineEnds({
|
|
35342
|
+
oldStart,
|
|
35343
|
+
newStart,
|
|
35344
|
+
oldConsumed: body.oldConsumed,
|
|
35345
|
+
newConsumed: body.newConsumed
|
|
35346
|
+
});
|
|
35347
|
+
prevOldEnd = ends.prevOldEnd;
|
|
35348
|
+
prevNewEnd = ends.prevNewEnd;
|
|
34731
35349
|
}
|
|
34732
35350
|
return truncatePatch(out.join("\n"));
|
|
34733
35351
|
}
|
|
@@ -34736,7 +35354,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
34736
35354
|
async function enrichWorkingTreeFileRows(options) {
|
|
34737
35355
|
await forEachWithGitYield(options.rows, async (row) => {
|
|
34738
35356
|
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
34739
|
-
const filePath =
|
|
35357
|
+
const filePath = path31.join(options.repoGitCwd, pathInRepo);
|
|
34740
35358
|
const hydrateKind = row.change === "moved" ? "modified" : row.change;
|
|
34741
35359
|
let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
|
|
34742
35360
|
if (patch) {
|
|
@@ -34798,14 +35416,76 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34798
35416
|
return dedupeChangedFileRows(rows);
|
|
34799
35417
|
}
|
|
34800
35418
|
|
|
34801
|
-
// src/git/changes/
|
|
35419
|
+
// src/git/changes/repo/norm-repo-rel-path.ts
|
|
34802
35420
|
function normRepoRel(p) {
|
|
34803
35421
|
const x = p.replace(/\\/g, "/").trim();
|
|
34804
35422
|
return x === "" ? "." : x;
|
|
34805
35423
|
}
|
|
35424
|
+
|
|
35425
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
35426
|
+
async function buildWorkingTreeChangeRepoDetail(options) {
|
|
35427
|
+
const t = path32.resolve(options.targetPath);
|
|
35428
|
+
if (!await isGitRepoDirectory(t)) return null;
|
|
35429
|
+
const g = cliSimpleGit(t);
|
|
35430
|
+
let branch = "HEAD";
|
|
35431
|
+
try {
|
|
35432
|
+
await yieldToEventLoop2();
|
|
35433
|
+
branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim() || "HEAD";
|
|
35434
|
+
} catch {
|
|
35435
|
+
branch = "HEAD";
|
|
35436
|
+
}
|
|
35437
|
+
await yieldToEventLoop2();
|
|
35438
|
+
const remoteUrl = await getRemoteOriginUrl(t);
|
|
35439
|
+
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
35440
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path32.resolve(options.sessionWorktreeRootPath) : null;
|
|
35441
|
+
const legacyNested = options.legacyRepoNestedSessionLayout;
|
|
35442
|
+
let repoRelPath;
|
|
35443
|
+
if (sessionWtRoot) {
|
|
35444
|
+
const anchor = legacyNested ? path32.dirname(t) : t;
|
|
35445
|
+
const relNorm = path32.relative(sessionWtRoot, anchor);
|
|
35446
|
+
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
35447
|
+
} else {
|
|
35448
|
+
let top = t;
|
|
35449
|
+
try {
|
|
35450
|
+
await yieldToEventLoop2();
|
|
35451
|
+
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
35452
|
+
} catch {
|
|
35453
|
+
top = t;
|
|
35454
|
+
}
|
|
35455
|
+
const rel = path32.relative(options.bridgeRoot, path32.resolve(top)).replace(/\\/g, "/") || ".";
|
|
35456
|
+
repoRelPath = rel.startsWith("..") ? path32.basename(path32.resolve(top)) : rel;
|
|
35457
|
+
}
|
|
35458
|
+
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
35459
|
+
if (options.repoFilterRelPath && norm !== options.repoFilterRelPath) return null;
|
|
35460
|
+
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
35461
|
+
const relForList = norm === "." ? "." : norm;
|
|
35462
|
+
const files = options.basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, options.basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
35463
|
+
const st = await g.status();
|
|
35464
|
+
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
35465
|
+
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
35466
|
+
listUnpushedCommits(t),
|
|
35467
|
+
listRecentCommits(t, options.recentCommitsLimit)
|
|
35468
|
+
]);
|
|
35469
|
+
return {
|
|
35470
|
+
repoRelPath: norm,
|
|
35471
|
+
repoDisplayName,
|
|
35472
|
+
branch,
|
|
35473
|
+
remoteUrl,
|
|
35474
|
+
remoteDisplay,
|
|
35475
|
+
files,
|
|
35476
|
+
hasUncommittedChanges,
|
|
35477
|
+
unpushedCommits,
|
|
35478
|
+
recentCommits: recentCommitList.commits,
|
|
35479
|
+
recentCommitsHasMore: recentCommitList.hasMore,
|
|
35480
|
+
changesView: options.basis.kind === "commit" ? "commit" : "working",
|
|
35481
|
+
changesCommitSha: options.basis.kind === "commit" ? options.basis.sha.trim() : null
|
|
35482
|
+
};
|
|
35483
|
+
}
|
|
35484
|
+
|
|
35485
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
34806
35486
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
34807
|
-
const bridgeRoot =
|
|
34808
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
35487
|
+
const bridgeRoot = path33.resolve(getBridgeRoot());
|
|
35488
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path33.resolve(options.sessionWorktreeRootPath) : null;
|
|
34809
35489
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
34810
35490
|
const out = [];
|
|
34811
35491
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -34818,59 +35498,18 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34818
35498
|
}
|
|
34819
35499
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
34820
35500
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
34821
|
-
|
|
34822
|
-
const
|
|
34823
|
-
|
|
34824
|
-
|
|
34825
|
-
|
|
34826
|
-
|
|
34827
|
-
|
|
34828
|
-
|
|
34829
|
-
|
|
34830
|
-
|
|
34831
|
-
|
|
34832
|
-
|
|
34833
|
-
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
34834
|
-
let repoRelPath;
|
|
34835
|
-
if (sessionWtRoot) {
|
|
34836
|
-
const anchor = legacyNested ? path22.dirname(t) : t;
|
|
34837
|
-
const relNorm = path22.relative(sessionWtRoot, anchor);
|
|
34838
|
-
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
34839
|
-
} else {
|
|
34840
|
-
let top = t;
|
|
34841
|
-
try {
|
|
34842
|
-
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
34843
|
-
} catch {
|
|
34844
|
-
top = t;
|
|
34845
|
-
}
|
|
34846
|
-
const rel = path22.relative(bridgeRoot, path22.resolve(top)).replace(/\\/g, "/") || ".";
|
|
34847
|
-
repoRelPath = rel.startsWith("..") ? path22.basename(path22.resolve(top)) : rel;
|
|
34848
|
-
}
|
|
34849
|
-
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
34850
|
-
if (filter && norm !== filter) continue;
|
|
34851
|
-
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
34852
|
-
const relForList = norm === "." ? "." : norm;
|
|
34853
|
-
const files = basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
34854
|
-
const st = await g.status();
|
|
34855
|
-
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
34856
|
-
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
34857
|
-
listUnpushedCommits(t),
|
|
34858
|
-
listRecentCommits(t, options.recentCommitsLimit)
|
|
34859
|
-
]);
|
|
34860
|
-
out.push({
|
|
34861
|
-
repoRelPath: norm,
|
|
34862
|
-
repoDisplayName,
|
|
34863
|
-
branch,
|
|
34864
|
-
remoteUrl,
|
|
34865
|
-
remoteDisplay,
|
|
34866
|
-
files,
|
|
34867
|
-
hasUncommittedChanges,
|
|
34868
|
-
unpushedCommits,
|
|
34869
|
-
recentCommits: recentCommitList.commits,
|
|
34870
|
-
recentCommitsHasMore: recentCommitList.hasMore,
|
|
34871
|
-
changesView: basis.kind === "commit" ? "commit" : "working",
|
|
34872
|
-
changesCommitSha: basis.kind === "commit" ? basis.sha.trim() : null
|
|
34873
|
-
});
|
|
35501
|
+
await yieldToEventLoop2();
|
|
35502
|
+
const detail = await buildWorkingTreeChangeRepoDetail({
|
|
35503
|
+
targetPath: options.commitTargetPaths[i],
|
|
35504
|
+
bridgeRoot,
|
|
35505
|
+
sessionWorktreeRootPath: sessionWtRoot,
|
|
35506
|
+
legacyRepoNestedSessionLayout: legacyNested,
|
|
35507
|
+
repoFilterRelPath: filter,
|
|
35508
|
+
basis,
|
|
35509
|
+
recentCommitsLimit: options.recentCommitsLimit
|
|
35510
|
+
});
|
|
35511
|
+
if (!detail) continue;
|
|
35512
|
+
out.push(detail);
|
|
34874
35513
|
if (filter) return out;
|
|
34875
35514
|
}
|
|
34876
35515
|
return out;
|
|
@@ -34972,23 +35611,23 @@ async function commitSessionWorktrees(options) {
|
|
|
34972
35611
|
}
|
|
34973
35612
|
|
|
34974
35613
|
// src/worktrees/remove-session-worktrees.ts
|
|
34975
|
-
import * as
|
|
35614
|
+
import * as fs28 from "node:fs";
|
|
34976
35615
|
|
|
34977
35616
|
// src/git/worktrees/worktree-remove.ts
|
|
34978
|
-
import * as
|
|
35617
|
+
import * as fs27 from "node:fs";
|
|
34979
35618
|
|
|
34980
35619
|
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
34981
|
-
import * as
|
|
34982
|
-
import * as
|
|
35620
|
+
import * as fs26 from "node:fs";
|
|
35621
|
+
import * as path34 from "node:path";
|
|
34983
35622
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34984
|
-
const gitDirFile =
|
|
34985
|
-
if (!
|
|
34986
|
-
const first2 =
|
|
35623
|
+
const gitDirFile = path34.join(wt, ".git");
|
|
35624
|
+
if (!fs26.existsSync(gitDirFile) || !fs26.statSync(gitDirFile).isFile()) return "";
|
|
35625
|
+
const first2 = fs26.readFileSync(gitDirFile, "utf8").trim();
|
|
34987
35626
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34988
35627
|
if (!m) return "";
|
|
34989
|
-
const gitWorktreePath =
|
|
34990
|
-
const gitDir =
|
|
34991
|
-
return
|
|
35628
|
+
const gitWorktreePath = path34.resolve(wt, m[1].trim());
|
|
35629
|
+
const gitDir = path34.dirname(path34.dirname(gitWorktreePath));
|
|
35630
|
+
return path34.dirname(gitDir);
|
|
34992
35631
|
}
|
|
34993
35632
|
|
|
34994
35633
|
// src/git/worktrees/worktree-remove.ts
|
|
@@ -34997,7 +35636,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
34997
35636
|
if (mainRepo) {
|
|
34998
35637
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34999
35638
|
} else {
|
|
35000
|
-
|
|
35639
|
+
fs27.rmSync(worktreePath, { recursive: true, force: true });
|
|
35001
35640
|
}
|
|
35002
35641
|
}
|
|
35003
35642
|
|
|
@@ -35010,7 +35649,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
35010
35649
|
} catch (e) {
|
|
35011
35650
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
35012
35651
|
try {
|
|
35013
|
-
|
|
35652
|
+
fs28.rmSync(wt, { recursive: true, force: true });
|
|
35014
35653
|
} catch {
|
|
35015
35654
|
}
|
|
35016
35655
|
}
|
|
@@ -35038,458 +35677,86 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
35038
35677
|
}
|
|
35039
35678
|
}
|
|
35040
35679
|
|
|
35041
|
-
// src/worktrees/
|
|
35042
|
-
|
|
35043
|
-
import * as path24 from "node:path";
|
|
35044
|
-
import os7 from "node:os";
|
|
35045
|
-
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
35046
|
-
function defaultWorktreeLayoutPath() {
|
|
35047
|
-
return path24.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
35048
|
-
}
|
|
35049
|
-
function normalizeLoadedLayout(raw) {
|
|
35050
|
-
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
35051
|
-
const j = raw;
|
|
35052
|
-
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
35053
|
-
}
|
|
35054
|
-
return { launcherCwds: [] };
|
|
35055
|
-
}
|
|
35056
|
-
function loadWorktreeLayout() {
|
|
35057
|
-
try {
|
|
35058
|
-
const p = defaultWorktreeLayoutPath();
|
|
35059
|
-
if (!fs22.existsSync(p)) return { launcherCwds: [] };
|
|
35060
|
-
const raw = JSON.parse(fs22.readFileSync(p, "utf8"));
|
|
35061
|
-
return normalizeLoadedLayout(raw);
|
|
35062
|
-
} catch {
|
|
35063
|
-
return { launcherCwds: [] };
|
|
35064
|
-
}
|
|
35065
|
-
}
|
|
35066
|
-
function saveWorktreeLayout(layout) {
|
|
35067
|
-
try {
|
|
35068
|
-
const dir = path24.dirname(defaultWorktreeLayoutPath());
|
|
35069
|
-
fs22.mkdirSync(dir, { recursive: true });
|
|
35070
|
-
fs22.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
35071
|
-
} catch {
|
|
35072
|
-
}
|
|
35073
|
-
}
|
|
35074
|
-
function baseNameSafe(pathString) {
|
|
35075
|
-
return path24.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
35076
|
-
}
|
|
35077
|
-
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
35078
|
-
const norm = path24.resolve(bridgeRootPath2);
|
|
35079
|
-
const existing = layout.launcherCwds.find((e) => path24.resolve(e.absolutePath) === norm);
|
|
35080
|
-
return existing?.dirName;
|
|
35081
|
-
}
|
|
35082
|
-
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
35083
|
-
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
35084
|
-
if (existing) return existing;
|
|
35085
|
-
const norm = path24.resolve(bridgeRootPath2);
|
|
35086
|
-
const base = baseNameSafe(norm);
|
|
35087
|
-
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
35088
|
-
let name = base;
|
|
35089
|
-
let n = 2;
|
|
35090
|
-
while (used.has(name)) {
|
|
35091
|
-
name = `${base}-${n}`;
|
|
35092
|
-
n += 1;
|
|
35093
|
-
}
|
|
35094
|
-
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
35095
|
-
saveWorktreeLayout(layout);
|
|
35096
|
-
return name;
|
|
35097
|
-
}
|
|
35098
|
-
|
|
35099
|
-
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
35100
|
-
import * as fs23 from "node:fs";
|
|
35101
|
-
import * as path25 from "node:path";
|
|
35102
|
-
function isGitDir(dirPath) {
|
|
35103
|
-
try {
|
|
35104
|
-
return fs23.existsSync(path25.join(dirPath, ".git"));
|
|
35105
|
-
} catch {
|
|
35106
|
-
return false;
|
|
35107
|
-
}
|
|
35108
|
-
}
|
|
35109
|
-
function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
35110
|
-
const out = [];
|
|
35111
|
-
const walk = (dir) => {
|
|
35112
|
-
if (isGitDir(dir)) {
|
|
35113
|
-
out.push(path25.resolve(dir));
|
|
35114
|
-
return;
|
|
35115
|
-
}
|
|
35116
|
-
let entries;
|
|
35117
|
-
try {
|
|
35118
|
-
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
35119
|
-
} catch {
|
|
35120
|
-
return;
|
|
35121
|
-
}
|
|
35122
|
-
for (const e of entries) {
|
|
35123
|
-
if (e.name.startsWith(".")) continue;
|
|
35124
|
-
const full = path25.join(dir, e.name);
|
|
35125
|
-
if (!e.isDirectory()) continue;
|
|
35126
|
-
walk(full);
|
|
35127
|
-
}
|
|
35128
|
-
};
|
|
35129
|
-
walk(path25.resolve(rootPath));
|
|
35130
|
-
return [...new Set(out)];
|
|
35131
|
-
}
|
|
35132
|
-
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
35133
|
-
const out = [];
|
|
35134
|
-
const walk = (dir, depth) => {
|
|
35135
|
-
if (depth > maxDepth) return;
|
|
35136
|
-
let entries;
|
|
35137
|
-
try {
|
|
35138
|
-
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
35139
|
-
} catch {
|
|
35140
|
-
return;
|
|
35141
|
-
}
|
|
35142
|
-
for (const e of entries) {
|
|
35143
|
-
if (e.name.startsWith(".")) continue;
|
|
35144
|
-
const full = path25.join(dir, e.name);
|
|
35145
|
-
if (!e.isDirectory()) continue;
|
|
35146
|
-
if (e.name === sessionId) {
|
|
35147
|
-
if (isGitDir(full)) out.push(path25.resolve(full));
|
|
35148
|
-
} else {
|
|
35149
|
-
walk(full, depth + 1);
|
|
35150
|
-
}
|
|
35151
|
-
}
|
|
35152
|
-
};
|
|
35153
|
-
walk(root, 0);
|
|
35154
|
-
return out;
|
|
35155
|
-
}
|
|
35156
|
-
function tryBindingFromSessionDirectory(sessionDir) {
|
|
35157
|
-
let st;
|
|
35158
|
-
try {
|
|
35159
|
-
st = fs23.statSync(sessionDir);
|
|
35160
|
-
} catch {
|
|
35161
|
-
return null;
|
|
35162
|
-
}
|
|
35163
|
-
if (!st.isDirectory()) return null;
|
|
35164
|
-
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
35165
|
-
if (worktreePaths.length === 0) return null;
|
|
35166
|
-
const abs = path25.resolve(sessionDir);
|
|
35167
|
-
return {
|
|
35168
|
-
sessionParentPath: abs,
|
|
35169
|
-
workingTreeRelRoot: abs,
|
|
35170
|
-
repoCheckoutPaths: worktreePaths
|
|
35171
|
-
};
|
|
35172
|
-
}
|
|
35173
|
-
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
35174
|
-
const sid = sessionId.trim();
|
|
35175
|
-
if (!sid) return null;
|
|
35176
|
-
const hintR = path25.resolve(checkoutPath);
|
|
35177
|
-
let best = null;
|
|
35178
|
-
let cur = path25.dirname(hintR);
|
|
35179
|
-
for (let i = 0; i < 40; i++) {
|
|
35180
|
-
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
35181
|
-
if (paths.some((p) => path25.resolve(p) === hintR)) {
|
|
35182
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path25.resolve(paths[0]);
|
|
35183
|
-
best = {
|
|
35184
|
-
sessionParentPath: path25.resolve(isolated),
|
|
35185
|
-
workingTreeRelRoot: path25.resolve(cur),
|
|
35186
|
-
repoCheckoutPaths: paths.map((p) => path25.resolve(p))
|
|
35187
|
-
};
|
|
35188
|
-
}
|
|
35189
|
-
const next = path25.dirname(cur);
|
|
35190
|
-
if (next === cur) break;
|
|
35191
|
-
cur = next;
|
|
35192
|
-
}
|
|
35193
|
-
return best;
|
|
35194
|
-
}
|
|
35195
|
-
function discoverSessionWorktreeOnDisk(options) {
|
|
35196
|
-
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
35197
|
-
if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
|
|
35198
|
-
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
35199
|
-
const keys = [];
|
|
35200
|
-
if (preferredKey) keys.push(preferredKey);
|
|
35201
|
-
try {
|
|
35202
|
-
for (const name of fs23.readdirSync(worktreesRootPath)) {
|
|
35203
|
-
if (name.startsWith(".")) continue;
|
|
35204
|
-
const p = path25.join(worktreesRootPath, name);
|
|
35205
|
-
if (!fs23.statSync(p).isDirectory()) continue;
|
|
35206
|
-
if (name !== preferredKey) keys.push(name);
|
|
35207
|
-
}
|
|
35208
|
-
} catch {
|
|
35209
|
-
return null;
|
|
35210
|
-
}
|
|
35211
|
-
for (const key of keys) {
|
|
35212
|
-
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
35213
|
-
if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
|
|
35214
|
-
const sessionDir = path25.join(layoutRoot, sessionId);
|
|
35215
|
-
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
35216
|
-
if (nested) return nested;
|
|
35217
|
-
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
35218
|
-
if (legacyPaths.length > 0) {
|
|
35219
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
35220
|
-
return {
|
|
35221
|
-
sessionParentPath: path25.resolve(isolated),
|
|
35222
|
-
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
35223
|
-
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
35224
|
-
};
|
|
35225
|
-
}
|
|
35226
|
-
}
|
|
35227
|
-
return null;
|
|
35228
|
-
}
|
|
35229
|
-
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
35230
|
-
const sid = sessionId.trim();
|
|
35231
|
-
if (!sid) return null;
|
|
35232
|
-
const hint = path25.resolve(sessionWorktreeRootPathOrHint);
|
|
35233
|
-
const underHint = tryBindingFromSessionDirectory(path25.join(hint, sid));
|
|
35234
|
-
if (underHint) return underHint;
|
|
35235
|
-
const direct = tryBindingFromSessionDirectory(hint);
|
|
35236
|
-
if (direct) {
|
|
35237
|
-
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
35238
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35239
|
-
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
35240
|
-
return legacyFromCheckout;
|
|
35241
|
-
}
|
|
35242
|
-
}
|
|
35243
|
-
return direct;
|
|
35244
|
-
}
|
|
35245
|
-
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
35246
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35247
|
-
if (legacyFromCheckout) return legacyFromCheckout;
|
|
35248
|
-
}
|
|
35249
|
-
let st;
|
|
35250
|
-
try {
|
|
35251
|
-
st = fs23.statSync(hint);
|
|
35252
|
-
} catch {
|
|
35253
|
-
return null;
|
|
35254
|
-
}
|
|
35255
|
-
if (!st.isDirectory()) return null;
|
|
35256
|
-
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
35257
|
-
if (legacyPaths.length === 0) return null;
|
|
35258
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
35680
|
+
// src/worktrees/manager/resolve-commit-targets.ts
|
|
35681
|
+
function bridgeRootBinding(bridgeRoot) {
|
|
35259
35682
|
return {
|
|
35260
|
-
sessionParentPath:
|
|
35261
|
-
workingTreeRelRoot:
|
|
35262
|
-
repoCheckoutPaths:
|
|
35683
|
+
sessionParentPath: bridgeRoot,
|
|
35684
|
+
workingTreeRelRoot: bridgeRoot,
|
|
35685
|
+
repoCheckoutPaths: [bridgeRoot]
|
|
35263
35686
|
};
|
|
35264
35687
|
}
|
|
35265
|
-
|
|
35266
|
-
// src/worktrees/manager/discover-session-binding.ts
|
|
35267
|
-
function discoverSessionBinding(params) {
|
|
35268
|
-
return discoverSessionWorktreeOnDisk({
|
|
35269
|
-
sessionId: params.sessionId,
|
|
35270
|
-
worktreesRootPath: params.worktreesRootPath,
|
|
35271
|
-
layout: params.layout,
|
|
35272
|
-
bridgeRoot: getBridgeRoot()
|
|
35273
|
-
});
|
|
35274
|
-
}
|
|
35275
|
-
|
|
35276
|
-
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
35277
|
-
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
35278
|
-
if (!sessionId) return null;
|
|
35279
|
-
const sid = sessionId.trim();
|
|
35280
|
-
const cached2 = cache2.getSessionParentPath(sid);
|
|
35281
|
-
if (cached2) return cached2;
|
|
35282
|
-
const paths = ensureRepoCheckoutPaths(sid);
|
|
35283
|
-
if (!paths?.length) return null;
|
|
35284
|
-
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
35285
|
-
}
|
|
35286
|
-
function ensureRepoCheckoutPathsForSession(sessionId, cache2, discover) {
|
|
35287
|
-
if (!sessionId?.trim()) return void 0;
|
|
35688
|
+
async function resolveCommitTargetsAsync(sessionId, cache2, discover) {
|
|
35288
35689
|
const sid = sessionId.trim();
|
|
35289
|
-
const
|
|
35290
|
-
if (cached2?.length) return cached2;
|
|
35291
|
-
const disc = discover(sid);
|
|
35292
|
-
if (disc?.repoCheckoutPaths.length) {
|
|
35293
|
-
cache2.remember(sid, disc);
|
|
35294
|
-
return [...disc.repoCheckoutPaths];
|
|
35295
|
-
}
|
|
35296
|
-
return void 0;
|
|
35297
|
-
}
|
|
35298
|
-
|
|
35299
|
-
// src/worktrees/manager/resolve-commit-targets.ts
|
|
35300
|
-
function resolveCommitTargets(sessionId, cache2, discover) {
|
|
35301
|
-
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
35690
|
+
const paths = cache2.getRepoCheckoutPathsRef(sid);
|
|
35302
35691
|
if (paths?.length) return paths;
|
|
35303
|
-
const disc = discover(
|
|
35692
|
+
const disc = await discover(sid);
|
|
35304
35693
|
if (disc?.repoCheckoutPaths.length) {
|
|
35305
|
-
cache2.remember(
|
|
35694
|
+
cache2.remember(sid, disc);
|
|
35306
35695
|
return disc.repoCheckoutPaths;
|
|
35307
35696
|
}
|
|
35308
|
-
|
|
35697
|
+
const bridgeRoot = getBridgeRoot();
|
|
35698
|
+
cache2.remember(sid, bridgeRootBinding(bridgeRoot));
|
|
35699
|
+
return [bridgeRoot];
|
|
35309
35700
|
}
|
|
35310
35701
|
|
|
35311
|
-
// src/worktrees/manager/
|
|
35312
|
-
function
|
|
35313
|
-
|
|
35314
|
-
|
|
35315
|
-
return
|
|
35316
|
-
|
|
35317
|
-
|
|
35318
|
-
|
|
35319
|
-
|
|
35320
|
-
|
|
35321
|
-
|
|
35322
|
-
// src/git/worktrees/worktree-add.ts
|
|
35323
|
-
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
35324
|
-
const mainGit = cliSimpleGit(mainRepoPath);
|
|
35325
|
-
const base = baseRef.trim() || "HEAD";
|
|
35326
|
-
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
35327
|
-
}
|
|
35328
|
-
|
|
35329
|
-
// src/worktrees/prepare-new-session-worktrees.ts
|
|
35330
|
-
function normalizeRepoRelPath2(rel) {
|
|
35331
|
-
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
35332
|
-
}
|
|
35333
|
-
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
35334
|
-
if (!baseBranches) return "HEAD";
|
|
35335
|
-
const direct = baseBranches[relNorm]?.trim();
|
|
35336
|
-
if (direct) return direct;
|
|
35337
|
-
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
35338
|
-
return "HEAD";
|
|
35702
|
+
// src/worktrees/manager/session-git-ops.ts
|
|
35703
|
+
async function commitSessionWorktree(cache2, params) {
|
|
35704
|
+
const paths = cache2.getRepoCheckoutPathsRef(params.sessionId);
|
|
35705
|
+
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
35706
|
+
return commitSessionWorktrees({
|
|
35707
|
+
paths: targets,
|
|
35708
|
+
branch: params.branch,
|
|
35709
|
+
message: params.message,
|
|
35710
|
+
push: params.push
|
|
35711
|
+
});
|
|
35339
35712
|
}
|
|
35340
|
-
async function
|
|
35341
|
-
|
|
35342
|
-
|
|
35343
|
-
|
|
35344
|
-
const bridgeKeyDir = path26.join(worktreesRootPath, cwdKey);
|
|
35345
|
-
const sessionDir = path26.join(bridgeKeyDir, sessionId);
|
|
35346
|
-
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
35347
|
-
if (repos.length === 0) {
|
|
35348
|
-
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
35349
|
-
return null;
|
|
35350
|
-
}
|
|
35351
|
-
const branch = `session-${sessionId}`;
|
|
35352
|
-
const worktreePaths = [];
|
|
35353
|
-
fs24.mkdirSync(sessionDir, { recursive: true });
|
|
35354
|
-
for (const repo of repos) {
|
|
35355
|
-
let rel = path26.relative(bridgeResolved, repo.absolutePath);
|
|
35356
|
-
if (rel.startsWith("..") || path26.isAbsolute(rel)) continue;
|
|
35357
|
-
const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
|
|
35358
|
-
const wtPath = relNorm === "." ? sessionDir : path26.join(sessionDir, relNorm);
|
|
35359
|
-
if (relNorm !== ".") {
|
|
35360
|
-
fs24.mkdirSync(path26.dirname(wtPath), { recursive: true });
|
|
35361
|
-
}
|
|
35362
|
-
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
35363
|
-
try {
|
|
35364
|
-
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
35365
|
-
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
35366
|
-
worktreePaths.push(wtPath);
|
|
35367
|
-
} catch (e) {
|
|
35368
|
-
log2(
|
|
35369
|
-
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
35370
|
-
);
|
|
35371
|
-
}
|
|
35372
|
-
}
|
|
35373
|
-
if (worktreePaths.length === 0) return null;
|
|
35374
|
-
return {
|
|
35375
|
-
worktreePaths,
|
|
35376
|
-
sessionParentPath: sessionDir,
|
|
35377
|
-
workingTreeRelRoot: sessionDir
|
|
35378
|
-
};
|
|
35713
|
+
async function getSessionWorkingTreeStatus(cache2, sessionId, discover) {
|
|
35714
|
+
return aggregateSessionPathsWorkingTreeStatus(
|
|
35715
|
+
await resolveCommitTargetsAsync(sessionId, cache2, discover)
|
|
35716
|
+
);
|
|
35379
35717
|
}
|
|
35380
|
-
|
|
35381
|
-
|
|
35382
|
-
|
|
35383
|
-
|
|
35384
|
-
|
|
35385
|
-
|
|
35386
|
-
|
|
35387
|
-
|
|
35388
|
-
|
|
35389
|
-
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
35390
|
-
});
|
|
35391
|
-
if (!prep) return void 0;
|
|
35392
|
-
params.cache.remember(params.sessionId, {
|
|
35393
|
-
sessionParentPath: prep.sessionParentPath,
|
|
35394
|
-
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
35395
|
-
repoCheckoutPaths: prep.worktreePaths
|
|
35718
|
+
async function getSessionWorkingTreeChangeDetails(cache2, sessionId, discover, opts) {
|
|
35719
|
+
const targets = await resolveCommitTargetsAsync(sessionId, cache2, discover);
|
|
35720
|
+
return getWorkingTreeChangeRepoDetails({
|
|
35721
|
+
commitTargetPaths: targets,
|
|
35722
|
+
sessionWorktreeRootPath: cache2.getWorkingTreeRelRoot(sessionId),
|
|
35723
|
+
legacyRepoNestedSessionLayout: cache2.isLegacyNestedLayout(sessionId),
|
|
35724
|
+
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
35725
|
+
basis: opts?.basis,
|
|
35726
|
+
recentCommitsLimit: opts?.recentCommitsLimit
|
|
35396
35727
|
});
|
|
35397
|
-
return params.cache.getSessionParentPath(params.sessionId);
|
|
35398
35728
|
}
|
|
35399
|
-
|
|
35400
|
-
|
|
35401
|
-
|
|
35402
|
-
|
|
35403
|
-
|
|
35404
|
-
|
|
35405
|
-
|
|
35406
|
-
cache2.remember(sessionId, disc);
|
|
35407
|
-
return cache2.getSessionParentPath(sessionId);
|
|
35729
|
+
async function pushSessionUpstream(cache2, sessionId, discover) {
|
|
35730
|
+
try {
|
|
35731
|
+
await pushAheadOfUpstreamForPaths(await resolveCommitTargetsAsync(sessionId, cache2, discover));
|
|
35732
|
+
return { ok: true };
|
|
35733
|
+
} catch (e) {
|
|
35734
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
35735
|
+
return { ok: false, error: err };
|
|
35408
35736
|
}
|
|
35409
|
-
return void 0;
|
|
35410
35737
|
}
|
|
35411
|
-
|
|
35412
|
-
|
|
35413
|
-
|
|
35414
|
-
|
|
35415
|
-
const resolved = path27.resolve(params.parentPathRaw);
|
|
35416
|
-
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
35417
|
-
return resolved;
|
|
35418
|
-
}
|
|
35419
|
-
const rememberAndReturn = (binding) => {
|
|
35420
|
-
params.cache.remember(params.sessionId, binding);
|
|
35421
|
-
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
35422
|
-
};
|
|
35423
|
-
const diskFirst = params.discover();
|
|
35424
|
-
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
35425
|
-
const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
35426
|
-
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
35427
|
-
let cur = resolved;
|
|
35428
|
-
for (let i = 0; i < 16; i++) {
|
|
35429
|
-
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
35430
|
-
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
35431
|
-
const next = path27.dirname(cur);
|
|
35432
|
-
if (next === cur) break;
|
|
35433
|
-
cur = next;
|
|
35434
|
-
}
|
|
35435
|
-
return resolved;
|
|
35738
|
+
async function removeSessionWorktreeCheckouts(cache2, sessionId, log2) {
|
|
35739
|
+
const paths = cache2.clearSession(sessionId);
|
|
35740
|
+
if (!paths?.length) return;
|
|
35741
|
+
await removeSessionWorktrees(paths, log2);
|
|
35436
35742
|
}
|
|
35437
|
-
|
|
35438
|
-
|
|
35439
|
-
|
|
35440
|
-
|
|
35441
|
-
if (!sessionId) return void 0;
|
|
35442
|
-
const sid = sessionId.trim();
|
|
35443
|
-
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
35444
|
-
if (parentPathRaw) {
|
|
35445
|
-
return resolveExplicitSessionParentPath({
|
|
35446
|
-
sessionId: sid,
|
|
35447
|
-
sessionParent: opts.sessionParent,
|
|
35448
|
-
parentPathRaw,
|
|
35449
|
-
cache: cache2,
|
|
35450
|
-
discover: () => discover(sid)
|
|
35451
|
-
});
|
|
35452
|
-
}
|
|
35453
|
-
const parentKind = parseSessionParent(opts.sessionParent);
|
|
35454
|
-
if (parentKind === "bridge_root") {
|
|
35455
|
-
return void 0;
|
|
35456
|
-
}
|
|
35457
|
-
if (parentKind === "worktrees_root") {
|
|
35458
|
-
if (!opts.isNewSession) {
|
|
35459
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
35460
|
-
}
|
|
35461
|
-
return prepareAndRememberSessionWorktrees({
|
|
35462
|
-
cache: cache2,
|
|
35463
|
-
sessionId: sid,
|
|
35464
|
-
worktreesRootPath,
|
|
35465
|
-
layout,
|
|
35466
|
-
log: log2,
|
|
35467
|
-
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
35468
|
-
});
|
|
35469
|
-
}
|
|
35470
|
-
if (!opts.isNewSession) {
|
|
35471
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
35472
|
-
}
|
|
35473
|
-
return prepareAndRememberSessionWorktrees({
|
|
35474
|
-
cache: cache2,
|
|
35475
|
-
sessionId: sid,
|
|
35476
|
-
worktreesRootPath,
|
|
35477
|
-
layout,
|
|
35478
|
-
log: log2
|
|
35479
|
-
});
|
|
35743
|
+
async function renameSessionWorktreeBranch(cache2, sessionId, newBranch, log2) {
|
|
35744
|
+
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
35745
|
+
if (!paths?.length) return;
|
|
35746
|
+
await renameSessionWorktreeBranches(paths, newBranch, log2);
|
|
35480
35747
|
}
|
|
35481
35748
|
|
|
35482
35749
|
// src/worktrees/manager/session-worktree-cache.ts
|
|
35483
|
-
import * as
|
|
35750
|
+
import * as path35 from "node:path";
|
|
35484
35751
|
var SessionWorktreeCache = class {
|
|
35485
35752
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
35486
35753
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
35487
35754
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
35488
35755
|
remember(sessionId, binding) {
|
|
35489
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
35756
|
+
const paths = binding.repoCheckoutPaths.map((p) => path35.resolve(p));
|
|
35490
35757
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
35491
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
35492
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
35758
|
+
this.sessionParentPathBySession.set(sessionId, path35.resolve(binding.sessionParentPath));
|
|
35759
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path35.resolve(binding.workingTreeRelRoot));
|
|
35493
35760
|
}
|
|
35494
35761
|
clearSession(sessionId) {
|
|
35495
35762
|
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
@@ -35519,7 +35786,7 @@ var SessionWorktreeCache = class {
|
|
|
35519
35786
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
35520
35787
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
35521
35788
|
if (!parent || !relRoot) return false;
|
|
35522
|
-
return
|
|
35789
|
+
return path35.resolve(parent) !== path35.resolve(relRoot);
|
|
35523
35790
|
}
|
|
35524
35791
|
};
|
|
35525
35792
|
|
|
@@ -35534,8 +35801,8 @@ var SessionWorktreeManager = class {
|
|
|
35534
35801
|
this.log = options.log;
|
|
35535
35802
|
this.layout = loadWorktreeLayout();
|
|
35536
35803
|
}
|
|
35537
|
-
|
|
35538
|
-
return
|
|
35804
|
+
discoverAsync(sessionId) {
|
|
35805
|
+
return discoverSessionBindingAsync({
|
|
35539
35806
|
sessionId,
|
|
35540
35807
|
worktreesRootPath: this.worktreesRootPath,
|
|
35541
35808
|
layout: this.layout
|
|
@@ -35555,14 +35822,12 @@ var SessionWorktreeManager = class {
|
|
|
35555
35822
|
worktreesRootPath: this.worktreesRootPath,
|
|
35556
35823
|
layout: this.layout,
|
|
35557
35824
|
log: this.log,
|
|
35558
|
-
discover: (sid) => this.
|
|
35825
|
+
discover: (sid) => this.discoverAsync(sid),
|
|
35559
35826
|
opts
|
|
35560
35827
|
});
|
|
35561
35828
|
}
|
|
35562
35829
|
async renameSessionBranch(sessionId, newBranch) {
|
|
35563
|
-
|
|
35564
|
-
if (!paths?.length) return;
|
|
35565
|
-
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
35830
|
+
await renameSessionWorktreeBranch(this.cache, sessionId, newBranch, this.log);
|
|
35566
35831
|
}
|
|
35567
35832
|
usesWorktreeSession(sessionId) {
|
|
35568
35833
|
if (!sessionId) return false;
|
|
@@ -35573,79 +35838,55 @@ var SessionWorktreeManager = class {
|
|
|
35573
35838
|
return this.cache.getRepoCheckoutPaths(sessionId);
|
|
35574
35839
|
}
|
|
35575
35840
|
ensureRepoCheckoutPathsForSession(sessionId) {
|
|
35576
|
-
return ensureRepoCheckoutPathsForSession(sessionId, this.cache
|
|
35841
|
+
return ensureRepoCheckoutPathsForSession(sessionId, this.cache);
|
|
35842
|
+
}
|
|
35843
|
+
async ensureRepoCheckoutPathsForSessionAsync(sessionId) {
|
|
35844
|
+
return ensureRepoCheckoutPathsForSessionAsync(sessionId, this.cache, (sid) => this.discoverAsync(sid));
|
|
35577
35845
|
}
|
|
35578
35846
|
getSessionWorktreeRootForSession(sessionId) {
|
|
35579
35847
|
return this.getIsolatedSessionParentPathForSession(sessionId);
|
|
35580
35848
|
}
|
|
35581
35849
|
async removeSessionWorktrees(sessionId) {
|
|
35582
|
-
|
|
35583
|
-
if (!paths?.length) return;
|
|
35584
|
-
await removeSessionWorktrees(paths, this.log);
|
|
35850
|
+
await removeSessionWorktreeCheckouts(this.cache, sessionId, this.log);
|
|
35585
35851
|
}
|
|
35586
35852
|
async commitSession(params) {
|
|
35587
|
-
|
|
35588
|
-
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
35589
|
-
return commitSessionWorktrees({
|
|
35590
|
-
paths: targets,
|
|
35591
|
-
branch: params.branch,
|
|
35592
|
-
message: params.message,
|
|
35593
|
-
push: params.push
|
|
35594
|
-
});
|
|
35853
|
+
return commitSessionWorktree(this.cache, params);
|
|
35595
35854
|
}
|
|
35596
35855
|
async getSessionWorkingTreeStatus(sessionId) {
|
|
35597
|
-
return
|
|
35598
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
35599
|
-
);
|
|
35856
|
+
return getSessionWorkingTreeStatus(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
35600
35857
|
}
|
|
35601
35858
|
async getSessionWorkingTreeChangeDetails(sessionId, opts) {
|
|
35602
|
-
|
|
35603
|
-
return getWorkingTreeChangeRepoDetails({
|
|
35604
|
-
commitTargetPaths: targets,
|
|
35605
|
-
sessionWorktreeRootPath: this.cache.getWorkingTreeRelRoot(sessionId),
|
|
35606
|
-
legacyRepoNestedSessionLayout: this.cache.isLegacyNestedLayout(sessionId),
|
|
35607
|
-
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
35608
|
-
basis: opts?.basis,
|
|
35609
|
-
recentCommitsLimit: opts?.recentCommitsLimit
|
|
35610
|
-
});
|
|
35859
|
+
return getSessionWorkingTreeChangeDetails(this.cache, sessionId, (sid) => this.discoverAsync(sid), opts);
|
|
35611
35860
|
}
|
|
35612
35861
|
async pushSessionUpstream(sessionId) {
|
|
35613
|
-
|
|
35614
|
-
await pushAheadOfUpstreamForPaths(
|
|
35615
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
35616
|
-
);
|
|
35617
|
-
return { ok: true };
|
|
35618
|
-
} catch (e) {
|
|
35619
|
-
const err = e instanceof Error ? e.message : String(e);
|
|
35620
|
-
return { ok: false, error: err };
|
|
35621
|
-
}
|
|
35862
|
+
return pushSessionUpstream(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
35622
35863
|
}
|
|
35623
35864
|
};
|
|
35624
35865
|
|
|
35625
35866
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
35626
|
-
import * as
|
|
35867
|
+
import * as path36 from "node:path";
|
|
35627
35868
|
import os8 from "node:os";
|
|
35628
35869
|
function defaultWorktreesRootPath() {
|
|
35629
|
-
return
|
|
35870
|
+
return path36.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
35630
35871
|
}
|
|
35631
35872
|
|
|
35632
35873
|
// src/files/watch-file-index.ts
|
|
35633
35874
|
import { watch } from "node:fs";
|
|
35634
|
-
import
|
|
35875
|
+
import path41 from "node:path";
|
|
35635
35876
|
|
|
35636
35877
|
// src/files/index/paths.ts
|
|
35637
|
-
import
|
|
35878
|
+
import path37 from "node:path";
|
|
35638
35879
|
import crypto2 from "node:crypto";
|
|
35639
35880
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
35640
|
-
return crypto2.createHash("sha256").update(
|
|
35881
|
+
return crypto2.createHash("sha256").update(path37.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
35641
35882
|
}
|
|
35642
35883
|
|
|
35643
35884
|
// src/files/index/build-file-index.ts
|
|
35644
|
-
import
|
|
35885
|
+
import path39 from "node:path";
|
|
35645
35886
|
|
|
35646
35887
|
// src/files/index/walk-workspace-tree.ts
|
|
35647
|
-
import
|
|
35648
|
-
import
|
|
35888
|
+
import fs29 from "node:fs";
|
|
35889
|
+
import path38 from "node:path";
|
|
35649
35890
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
35650
35891
|
"node_modules",
|
|
35651
35892
|
"bower_components",
|
|
@@ -35662,7 +35903,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
|
|
|
35662
35903
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
35663
35904
|
let names;
|
|
35664
35905
|
try {
|
|
35665
|
-
names = await
|
|
35906
|
+
names = await fs29.promises.readdir(dir);
|
|
35666
35907
|
} catch {
|
|
35667
35908
|
return;
|
|
35668
35909
|
}
|
|
@@ -35674,14 +35915,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
35674
35915
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
35675
35916
|
}
|
|
35676
35917
|
state.n++;
|
|
35677
|
-
const full =
|
|
35918
|
+
const full = path38.join(dir, name);
|
|
35678
35919
|
let stat2;
|
|
35679
35920
|
try {
|
|
35680
|
-
stat2 = await
|
|
35921
|
+
stat2 = await fs29.promises.stat(full);
|
|
35681
35922
|
} catch {
|
|
35682
35923
|
continue;
|
|
35683
35924
|
}
|
|
35684
|
-
const relative6 =
|
|
35925
|
+
const relative6 = path38.relative(baseDir, full).replace(/\\/g, "/");
|
|
35685
35926
|
if (stat2.isDirectory()) {
|
|
35686
35927
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
35687
35928
|
} else if (stat2.isFile()) {
|
|
@@ -35694,7 +35935,7 @@ function createWalkYieldState() {
|
|
|
35694
35935
|
}
|
|
35695
35936
|
|
|
35696
35937
|
// src/files/index/file-index-sqlite-lock.ts
|
|
35697
|
-
import
|
|
35938
|
+
import fs30 from "node:fs";
|
|
35698
35939
|
function isSqliteCorruptError(e) {
|
|
35699
35940
|
const msg = e instanceof Error ? e.message : String(e);
|
|
35700
35941
|
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
@@ -35708,7 +35949,7 @@ function withFileIndexSqliteLock(fn) {
|
|
|
35708
35949
|
if (!isSqliteCorruptError(e)) throw e;
|
|
35709
35950
|
closeAllCliSqliteConnections();
|
|
35710
35951
|
try {
|
|
35711
|
-
|
|
35952
|
+
fs30.unlinkSync(getCliSqlitePath());
|
|
35712
35953
|
} catch {
|
|
35713
35954
|
}
|
|
35714
35955
|
chain = Promise.resolve();
|
|
@@ -35783,7 +36024,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
35783
36024
|
}
|
|
35784
36025
|
async function buildFileIndexAsync(cwd) {
|
|
35785
36026
|
return withFileIndexSqliteLock(async () => {
|
|
35786
|
-
const resolved =
|
|
36027
|
+
const resolved = path39.resolve(cwd);
|
|
35787
36028
|
await yieldToEventLoop();
|
|
35788
36029
|
assertNotShutdown();
|
|
35789
36030
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -35795,7 +36036,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
35795
36036
|
}
|
|
35796
36037
|
|
|
35797
36038
|
// src/files/index/ensure-file-index.ts
|
|
35798
|
-
import
|
|
36039
|
+
import path40 from "node:path";
|
|
35799
36040
|
|
|
35800
36041
|
// src/files/index/search-file-index.ts
|
|
35801
36042
|
function escapeLikePattern(fragment) {
|
|
@@ -35847,7 +36088,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
35847
36088
|
|
|
35848
36089
|
// src/files/index/ensure-file-index.ts
|
|
35849
36090
|
async function ensureFileIndexAsync(cwd) {
|
|
35850
|
-
const resolved =
|
|
36091
|
+
const resolved = path40.resolve(cwd);
|
|
35851
36092
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
35852
36093
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
35853
36094
|
}
|
|
@@ -35891,7 +36132,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
35891
36132
|
}
|
|
35892
36133
|
}
|
|
35893
36134
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
35894
|
-
const resolved =
|
|
36135
|
+
const resolved = path41.resolve(cwd);
|
|
35895
36136
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
35896
36137
|
if (e instanceof CliSqliteInterrupted) return;
|
|
35897
36138
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -35921,7 +36162,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
35921
36162
|
}
|
|
35922
36163
|
|
|
35923
36164
|
// src/connection/create-bridge-connection.ts
|
|
35924
|
-
import * as
|
|
36165
|
+
import * as path52 from "node:path";
|
|
35925
36166
|
|
|
35926
36167
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
35927
36168
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -35943,15 +36184,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
35943
36184
|
|
|
35944
36185
|
// src/dev-servers/process/terminate-child-process.ts
|
|
35945
36186
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
35946
|
-
const exited = new Promise((
|
|
35947
|
-
proc.once("exit", () =>
|
|
36187
|
+
const exited = new Promise((resolve26) => {
|
|
36188
|
+
proc.once("exit", () => resolve26());
|
|
35948
36189
|
});
|
|
35949
36190
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
35950
36191
|
try {
|
|
35951
36192
|
proc.kill("SIGTERM");
|
|
35952
36193
|
} catch {
|
|
35953
36194
|
}
|
|
35954
|
-
await Promise.race([exited, new Promise((
|
|
36195
|
+
await Promise.race([exited, new Promise((resolve26) => setTimeout(resolve26, graceMs))]);
|
|
35955
36196
|
}
|
|
35956
36197
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
35957
36198
|
log2(
|
|
@@ -35965,7 +36206,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
35965
36206
|
}
|
|
35966
36207
|
|
|
35967
36208
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
35968
|
-
import
|
|
36209
|
+
import fs31 from "node:fs";
|
|
35969
36210
|
|
|
35970
36211
|
// src/dev-servers/manager/forward-pipe.ts
|
|
35971
36212
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -36001,7 +36242,7 @@ function wireDevServerChildProcess(d) {
|
|
|
36001
36242
|
d.setPollInterval(void 0);
|
|
36002
36243
|
return;
|
|
36003
36244
|
}
|
|
36004
|
-
|
|
36245
|
+
fs31.readFile(d.mergedLogPath, (err, buf) => {
|
|
36005
36246
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
36006
36247
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
36007
36248
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -36039,7 +36280,7 @@ ${errTail}` : ""}`);
|
|
|
36039
36280
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
36040
36281
|
};
|
|
36041
36282
|
if (mergedPath) {
|
|
36042
|
-
|
|
36283
|
+
fs31.readFile(mergedPath, (err, buf) => {
|
|
36043
36284
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
36044
36285
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
36045
36286
|
if (chunk.length > 0) {
|
|
@@ -36141,13 +36382,13 @@ function parseDevServerDefs(servers) {
|
|
|
36141
36382
|
}
|
|
36142
36383
|
|
|
36143
36384
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
36144
|
-
import
|
|
36385
|
+
import fs32 from "node:fs";
|
|
36145
36386
|
function isSpawnEbadf(e) {
|
|
36146
36387
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
36147
36388
|
}
|
|
36148
36389
|
function rmDirQuiet(dir) {
|
|
36149
36390
|
try {
|
|
36150
|
-
|
|
36391
|
+
fs32.rmSync(dir, { recursive: true, force: true });
|
|
36151
36392
|
} catch {
|
|
36152
36393
|
}
|
|
36153
36394
|
}
|
|
@@ -36155,7 +36396,7 @@ var cachedDevNullReadFd;
|
|
|
36155
36396
|
function devNullReadFd() {
|
|
36156
36397
|
if (cachedDevNullReadFd === void 0) {
|
|
36157
36398
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
36158
|
-
cachedDevNullReadFd =
|
|
36399
|
+
cachedDevNullReadFd = fs32.openSync(devPath, "r");
|
|
36159
36400
|
}
|
|
36160
36401
|
return cachedDevNullReadFd;
|
|
36161
36402
|
}
|
|
@@ -36229,15 +36470,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
36229
36470
|
|
|
36230
36471
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
36231
36472
|
import { spawn as spawn8 } from "node:child_process";
|
|
36232
|
-
import
|
|
36473
|
+
import fs33 from "node:fs";
|
|
36233
36474
|
import { tmpdir } from "node:os";
|
|
36234
|
-
import
|
|
36475
|
+
import path42 from "node:path";
|
|
36235
36476
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
36236
|
-
const tmpRoot =
|
|
36237
|
-
const logPath =
|
|
36477
|
+
const tmpRoot = fs33.mkdtempSync(path42.join(tmpdir(), "ba-devsrv-log-"));
|
|
36478
|
+
const logPath = path42.join(tmpRoot, "combined.log");
|
|
36238
36479
|
let logFd;
|
|
36239
36480
|
try {
|
|
36240
|
-
logFd =
|
|
36481
|
+
logFd = fs33.openSync(logPath, "a");
|
|
36241
36482
|
} catch {
|
|
36242
36483
|
rmDirQuiet(tmpRoot);
|
|
36243
36484
|
return null;
|
|
@@ -36256,7 +36497,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36256
36497
|
} else {
|
|
36257
36498
|
proc = spawn8("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
36258
36499
|
}
|
|
36259
|
-
|
|
36500
|
+
fs33.closeSync(logFd);
|
|
36260
36501
|
return {
|
|
36261
36502
|
proc,
|
|
36262
36503
|
pipedStdoutStderr: true,
|
|
@@ -36265,7 +36506,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36265
36506
|
};
|
|
36266
36507
|
} catch (e) {
|
|
36267
36508
|
try {
|
|
36268
|
-
|
|
36509
|
+
fs33.closeSync(logFd);
|
|
36269
36510
|
} catch {
|
|
36270
36511
|
}
|
|
36271
36512
|
rmDirQuiet(tmpRoot);
|
|
@@ -36276,22 +36517,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36276
36517
|
|
|
36277
36518
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
36278
36519
|
import { spawn as spawn9 } from "node:child_process";
|
|
36279
|
-
import
|
|
36520
|
+
import fs34 from "node:fs";
|
|
36280
36521
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
36281
|
-
import
|
|
36522
|
+
import path43 from "node:path";
|
|
36282
36523
|
function shSingleQuote(s) {
|
|
36283
36524
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
36284
36525
|
}
|
|
36285
36526
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
36286
|
-
const tmpRoot =
|
|
36287
|
-
const logPath =
|
|
36288
|
-
const innerPath =
|
|
36289
|
-
const runnerPath =
|
|
36527
|
+
const tmpRoot = fs34.mkdtempSync(path43.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36528
|
+
const logPath = path43.join(tmpRoot, "combined.log");
|
|
36529
|
+
const innerPath = path43.join(tmpRoot, "_cmd.sh");
|
|
36530
|
+
const runnerPath = path43.join(tmpRoot, "_run.sh");
|
|
36290
36531
|
try {
|
|
36291
|
-
|
|
36532
|
+
fs34.writeFileSync(innerPath, `#!/bin/sh
|
|
36292
36533
|
${command}
|
|
36293
36534
|
`);
|
|
36294
|
-
|
|
36535
|
+
fs34.writeFileSync(
|
|
36295
36536
|
runnerPath,
|
|
36296
36537
|
`#!/bin/sh
|
|
36297
36538
|
cd ${shSingleQuote(cwd)}
|
|
@@ -36317,13 +36558,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
36317
36558
|
}
|
|
36318
36559
|
}
|
|
36319
36560
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
36320
|
-
const tmpRoot =
|
|
36321
|
-
const logPath =
|
|
36322
|
-
const runnerPath =
|
|
36561
|
+
const tmpRoot = fs34.mkdtempSync(path43.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36562
|
+
const logPath = path43.join(tmpRoot, "combined.log");
|
|
36563
|
+
const runnerPath = path43.join(tmpRoot, "_run.bat");
|
|
36323
36564
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
36324
36565
|
const com = process.env.ComSpec || "cmd.exe";
|
|
36325
36566
|
try {
|
|
36326
|
-
|
|
36567
|
+
fs34.writeFileSync(
|
|
36327
36568
|
runnerPath,
|
|
36328
36569
|
`@ECHO OFF\r
|
|
36329
36570
|
CD /D ${q(cwd)}\r
|
|
@@ -37092,30 +37333,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
37092
37333
|
}
|
|
37093
37334
|
|
|
37094
37335
|
// src/skills/discover-local-agent-skills.ts
|
|
37095
|
-
import
|
|
37096
|
-
import
|
|
37336
|
+
import fs35 from "node:fs";
|
|
37337
|
+
import path44 from "node:path";
|
|
37097
37338
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
37098
37339
|
function discoverLocalSkills(cwd) {
|
|
37099
37340
|
const out = [];
|
|
37100
37341
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
37101
37342
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37102
|
-
const base =
|
|
37103
|
-
if (!
|
|
37343
|
+
const base = path44.join(cwd, rel);
|
|
37344
|
+
if (!fs35.existsSync(base) || !fs35.statSync(base).isDirectory()) continue;
|
|
37104
37345
|
let entries = [];
|
|
37105
37346
|
try {
|
|
37106
|
-
entries =
|
|
37347
|
+
entries = fs35.readdirSync(base);
|
|
37107
37348
|
} catch {
|
|
37108
37349
|
continue;
|
|
37109
37350
|
}
|
|
37110
37351
|
for (const name of entries) {
|
|
37111
|
-
const dir =
|
|
37352
|
+
const dir = path44.join(base, name);
|
|
37112
37353
|
try {
|
|
37113
|
-
if (!
|
|
37354
|
+
if (!fs35.statSync(dir).isDirectory()) continue;
|
|
37114
37355
|
} catch {
|
|
37115
37356
|
continue;
|
|
37116
37357
|
}
|
|
37117
|
-
const skillMd =
|
|
37118
|
-
if (!
|
|
37358
|
+
const skillMd = path44.join(dir, "SKILL.md");
|
|
37359
|
+
if (!fs35.existsSync(skillMd)) continue;
|
|
37119
37360
|
const key = `${rel}/${name}`;
|
|
37120
37361
|
if (seenKeys.has(key)) continue;
|
|
37121
37362
|
seenKeys.add(key);
|
|
@@ -37127,23 +37368,23 @@ function discoverLocalSkills(cwd) {
|
|
|
37127
37368
|
function discoverSkillLayoutRoots(cwd) {
|
|
37128
37369
|
const roots = [];
|
|
37129
37370
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37130
|
-
const base =
|
|
37131
|
-
if (!
|
|
37371
|
+
const base = path44.join(cwd, rel);
|
|
37372
|
+
if (!fs35.existsSync(base) || !fs35.statSync(base).isDirectory()) continue;
|
|
37132
37373
|
let entries = [];
|
|
37133
37374
|
try {
|
|
37134
|
-
entries =
|
|
37375
|
+
entries = fs35.readdirSync(base);
|
|
37135
37376
|
} catch {
|
|
37136
37377
|
continue;
|
|
37137
37378
|
}
|
|
37138
37379
|
const skills2 = [];
|
|
37139
37380
|
for (const name of entries) {
|
|
37140
|
-
const dir =
|
|
37381
|
+
const dir = path44.join(base, name);
|
|
37141
37382
|
try {
|
|
37142
|
-
if (!
|
|
37383
|
+
if (!fs35.statSync(dir).isDirectory()) continue;
|
|
37143
37384
|
} catch {
|
|
37144
37385
|
continue;
|
|
37145
37386
|
}
|
|
37146
|
-
if (!
|
|
37387
|
+
if (!fs35.existsSync(path44.join(dir, "SKILL.md"))) continue;
|
|
37147
37388
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
37148
37389
|
skills2.push({ name, relPath });
|
|
37149
37390
|
}
|
|
@@ -37499,7 +37740,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
37499
37740
|
}
|
|
37500
37741
|
|
|
37501
37742
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
37502
|
-
import
|
|
37743
|
+
import fs36 from "node:fs";
|
|
37503
37744
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
37504
37745
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
37505
37746
|
const sid = next.sessionId;
|
|
@@ -37508,7 +37749,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
37508
37749
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
37509
37750
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
37510
37751
|
try {
|
|
37511
|
-
await
|
|
37752
|
+
await fs36.promises.access(file2, fs36.constants.F_OK);
|
|
37512
37753
|
} catch {
|
|
37513
37754
|
deps.log(
|
|
37514
37755
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -37623,7 +37864,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
37623
37864
|
sendWsMessage(s, wire);
|
|
37624
37865
|
return true;
|
|
37625
37866
|
};
|
|
37626
|
-
const
|
|
37867
|
+
const sendResult = (result) => {
|
|
37627
37868
|
const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
37628
37869
|
const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
|
|
37629
37870
|
sendBridgeMessage(result, encryptedFields);
|
|
@@ -37656,7 +37897,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
37656
37897
|
]) : payload;
|
|
37657
37898
|
sendWsMessage(s, wire);
|
|
37658
37899
|
};
|
|
37659
|
-
return { sendBridgeMessage, sendResult
|
|
37900
|
+
return { sendBridgeMessage, sendResult, sendSessionUpdate };
|
|
37660
37901
|
}
|
|
37661
37902
|
|
|
37662
37903
|
// src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
|
|
@@ -37760,7 +38001,7 @@ async function readGitBranch(cwd) {
|
|
|
37760
38001
|
async function runBridgePromptPreamble(params) {
|
|
37761
38002
|
const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
|
|
37762
38003
|
const s = getWs();
|
|
37763
|
-
const repoCheckoutPaths = sessionWorktreeManager.
|
|
38004
|
+
const repoCheckoutPaths = await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sessionId);
|
|
37764
38005
|
const repoRoots = await resolveSnapshotRepoRoots({
|
|
37765
38006
|
worktreePaths: repoCheckoutPaths,
|
|
37766
38007
|
fallbackCwd: effectiveCwd,
|
|
@@ -37796,9 +38037,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
37796
38037
|
for (const item of raw) {
|
|
37797
38038
|
if (!item || typeof item !== "object") continue;
|
|
37798
38039
|
const o = item;
|
|
37799
|
-
const
|
|
37800
|
-
if (!
|
|
37801
|
-
const row = { path:
|
|
38040
|
+
const path53 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
38041
|
+
if (!path53) continue;
|
|
38042
|
+
const row = { path: path53 };
|
|
37802
38043
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
37803
38044
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
37804
38045
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -37832,7 +38073,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
37832
38073
|
agentId,
|
|
37833
38074
|
agentConfig,
|
|
37834
38075
|
resolvedCwd,
|
|
37835
|
-
senders: { sendResult
|
|
38076
|
+
senders: { sendResult, sendSessionUpdate }
|
|
37836
38077
|
} = params;
|
|
37837
38078
|
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
37838
38079
|
await runBridgePromptPreamble({
|
|
@@ -37870,7 +38111,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
37870
38111
|
agentId,
|
|
37871
38112
|
agentConfig,
|
|
37872
38113
|
sessionParentPath: effectiveCwd,
|
|
37873
|
-
sendResult
|
|
38114
|
+
sendResult,
|
|
37874
38115
|
sendSessionUpdate,
|
|
37875
38116
|
followUpCatalogPromptId,
|
|
37876
38117
|
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
@@ -38012,14 +38253,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
38012
38253
|
};
|
|
38013
38254
|
|
|
38014
38255
|
// src/files/list-dir/index.ts
|
|
38015
|
-
import
|
|
38256
|
+
import fs38 from "node:fs";
|
|
38016
38257
|
|
|
38017
38258
|
// src/files/ensure-under-cwd.ts
|
|
38018
|
-
import
|
|
38259
|
+
import path45 from "node:path";
|
|
38019
38260
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
38020
|
-
const normalized =
|
|
38021
|
-
const resolved =
|
|
38022
|
-
if (!resolved.startsWith(cwd +
|
|
38261
|
+
const normalized = path45.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
38262
|
+
const resolved = path45.resolve(cwd, normalized);
|
|
38263
|
+
if (!resolved.startsWith(cwd + path45.sep) && resolved !== cwd) {
|
|
38023
38264
|
return null;
|
|
38024
38265
|
}
|
|
38025
38266
|
return resolved;
|
|
@@ -38029,15 +38270,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
38029
38270
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
38030
38271
|
|
|
38031
38272
|
// src/files/list-dir/map-dir-entry.ts
|
|
38032
|
-
import
|
|
38033
|
-
import
|
|
38273
|
+
import path46 from "node:path";
|
|
38274
|
+
import fs37 from "node:fs";
|
|
38034
38275
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
38035
|
-
const entryPath =
|
|
38036
|
-
const fullPath =
|
|
38276
|
+
const entryPath = path46.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
38277
|
+
const fullPath = path46.join(resolved, d.name);
|
|
38037
38278
|
let isDir = d.isDirectory();
|
|
38038
38279
|
if (d.isSymbolicLink()) {
|
|
38039
38280
|
try {
|
|
38040
|
-
const targetStat = await
|
|
38281
|
+
const targetStat = await fs37.promises.stat(fullPath);
|
|
38041
38282
|
isDir = targetStat.isDirectory();
|
|
38042
38283
|
} catch {
|
|
38043
38284
|
isDir = false;
|
|
@@ -38067,7 +38308,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
38067
38308
|
return { error: "Path is outside working directory" };
|
|
38068
38309
|
}
|
|
38069
38310
|
try {
|
|
38070
|
-
const names = await
|
|
38311
|
+
const names = await fs38.promises.readdir(resolved, { withFileTypes: true });
|
|
38071
38312
|
const entries = [];
|
|
38072
38313
|
for (let i = 0; i < names.length; i++) {
|
|
38073
38314
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -38087,18 +38328,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
|
|
|
38087
38328
|
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
38088
38329
|
|
|
38089
38330
|
// src/files/read-file/resolve-file-path.ts
|
|
38090
|
-
import
|
|
38331
|
+
import fs39 from "node:fs";
|
|
38091
38332
|
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
38092
38333
|
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
38093
38334
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
38094
38335
|
let real;
|
|
38095
38336
|
try {
|
|
38096
|
-
real = await
|
|
38337
|
+
real = await fs39.promises.realpath(resolved);
|
|
38097
38338
|
} catch {
|
|
38098
38339
|
real = resolved;
|
|
38099
38340
|
}
|
|
38100
38341
|
try {
|
|
38101
|
-
const stat2 = await
|
|
38342
|
+
const stat2 = await fs39.promises.stat(real);
|
|
38102
38343
|
if (!stat2.isFile()) return { error: "Not a file" };
|
|
38103
38344
|
return real;
|
|
38104
38345
|
} catch (err) {
|
|
@@ -38107,11 +38348,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
38107
38348
|
}
|
|
38108
38349
|
|
|
38109
38350
|
// src/files/read-file/read-file-range-async.ts
|
|
38110
|
-
import
|
|
38351
|
+
import fs40 from "node:fs";
|
|
38111
38352
|
import { StringDecoder } from "node:string_decoder";
|
|
38112
38353
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
38113
|
-
const fileSize = (await
|
|
38114
|
-
const fd = await
|
|
38354
|
+
const fileSize = (await fs40.promises.stat(filePath)).size;
|
|
38355
|
+
const fd = await fs40.promises.open(filePath, "r");
|
|
38115
38356
|
const bufSize = 64 * 1024;
|
|
38116
38357
|
const buf = Buffer.alloc(bufSize);
|
|
38117
38358
|
const decoder = new StringDecoder("utf8");
|
|
@@ -38273,11 +38514,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
38273
38514
|
}
|
|
38274
38515
|
|
|
38275
38516
|
// src/files/read-file/read-file-buffer-full-async.ts
|
|
38276
|
-
import
|
|
38517
|
+
import fs41 from "node:fs";
|
|
38277
38518
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
38278
38519
|
async function readFileBufferFullAsync(filePath) {
|
|
38279
|
-
const stat2 = await
|
|
38280
|
-
const fd = await
|
|
38520
|
+
const stat2 = await fs41.promises.stat(filePath);
|
|
38521
|
+
const fd = await fs41.promises.open(filePath, "r");
|
|
38281
38522
|
const chunks = [];
|
|
38282
38523
|
let position = 0;
|
|
38283
38524
|
let bytesSinceYield = 0;
|
|
@@ -38373,10 +38614,10 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
38373
38614
|
}
|
|
38374
38615
|
|
|
38375
38616
|
// src/files/resolve-file-browser-session-parent.ts
|
|
38376
|
-
function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
38617
|
+
async function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
38377
38618
|
const sid = sessionId?.trim();
|
|
38378
38619
|
if (sid) {
|
|
38379
|
-
sessionWorktreeManager.
|
|
38620
|
+
await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sid);
|
|
38380
38621
|
const worktreeRoot = sessionWorktreeManager.getSessionWorktreeRootForSession(sid);
|
|
38381
38622
|
if (worktreeRoot) return worktreeRoot;
|
|
38382
38623
|
}
|
|
@@ -38384,14 +38625,14 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
38384
38625
|
}
|
|
38385
38626
|
|
|
38386
38627
|
// src/files/handle-file-browser-search.ts
|
|
38387
|
-
import
|
|
38628
|
+
import path47 from "node:path";
|
|
38388
38629
|
var SEARCH_LIMIT = 100;
|
|
38389
38630
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
38390
38631
|
void (async () => {
|
|
38391
38632
|
await yieldToEventLoop();
|
|
38392
38633
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
38393
|
-
const sessionParentPath =
|
|
38394
|
-
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
38634
|
+
const sessionParentPath = path47.resolve(
|
|
38635
|
+
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
38395
38636
|
);
|
|
38396
38637
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
38397
38638
|
const payload2 = {
|
|
@@ -38429,7 +38670,7 @@ function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
|
38429
38670
|
void (async () => {
|
|
38430
38671
|
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
38431
38672
|
const op = msg.op === "read" ? "read" : "list";
|
|
38432
|
-
const sessionParentPath = sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
38673
|
+
const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
38433
38674
|
if (op === "list") {
|
|
38434
38675
|
const result = await listDirAsync(reqPath, sessionParentPath);
|
|
38435
38676
|
if ("error" in result) {
|
|
@@ -38509,8 +38750,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
38509
38750
|
}
|
|
38510
38751
|
|
|
38511
38752
|
// src/skills/install-remote-skills.ts
|
|
38512
|
-
import
|
|
38513
|
-
import
|
|
38753
|
+
import fs42 from "node:fs";
|
|
38754
|
+
import path48 from "node:path";
|
|
38514
38755
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
38515
38756
|
const installed2 = [];
|
|
38516
38757
|
if (!Array.isArray(items)) {
|
|
@@ -38521,15 +38762,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
38521
38762
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
38522
38763
|
continue;
|
|
38523
38764
|
}
|
|
38524
|
-
const skillDir =
|
|
38765
|
+
const skillDir = path48.join(cwd, targetDir, item.skillName);
|
|
38525
38766
|
for (const f of item.files) {
|
|
38526
38767
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
38527
|
-
const dest =
|
|
38528
|
-
|
|
38768
|
+
const dest = path48.join(skillDir, f.path);
|
|
38769
|
+
fs42.mkdirSync(path48.dirname(dest), { recursive: true });
|
|
38529
38770
|
if (f.text !== void 0) {
|
|
38530
|
-
|
|
38771
|
+
fs42.writeFileSync(dest, f.text, "utf8");
|
|
38531
38772
|
} else if (f.base64) {
|
|
38532
|
-
|
|
38773
|
+
fs42.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
38533
38774
|
}
|
|
38534
38775
|
}
|
|
38535
38776
|
installed2.push({
|
|
@@ -38570,12 +38811,116 @@ var handleRefreshLocalSkills = (_msg, deps) => {
|
|
|
38570
38811
|
deps.sendLocalSkillsReport?.();
|
|
38571
38812
|
};
|
|
38572
38813
|
|
|
38573
|
-
// src/routing/handlers/session-git-
|
|
38574
|
-
function
|
|
38814
|
+
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
38815
|
+
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
38816
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
38817
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
38818
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
38819
|
+
if (!branch.trim() || !message.trim()) {
|
|
38820
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
38821
|
+
return;
|
|
38822
|
+
}
|
|
38823
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
38824
|
+
sessionId,
|
|
38825
|
+
branch: branch.trim(),
|
|
38826
|
+
message: message.trim(),
|
|
38827
|
+
push: pushAfterCommit
|
|
38828
|
+
});
|
|
38829
|
+
if (!commitRes.ok) {
|
|
38830
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
38831
|
+
return;
|
|
38832
|
+
}
|
|
38833
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38834
|
+
reply({
|
|
38835
|
+
ok: true,
|
|
38836
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
38837
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
38838
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
38839
|
+
});
|
|
38840
|
+
}
|
|
38841
|
+
|
|
38842
|
+
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
38843
|
+
var listChangesInflight = /* @__PURE__ */ new Map();
|
|
38844
|
+
function listChangesInflightKey(sessionId, opts) {
|
|
38845
|
+
const basis = opts?.basis;
|
|
38846
|
+
return [
|
|
38847
|
+
sessionId,
|
|
38848
|
+
opts?.repoRelPath ?? "",
|
|
38849
|
+
basis?.kind === "commit" ? `commit:${basis.sha}` : "working",
|
|
38850
|
+
String(opts?.recentCommitsLimit ?? "")
|
|
38851
|
+
].join("|");
|
|
38852
|
+
}
|
|
38853
|
+
function getSessionWorkingTreeChangeDetailsCoalesced(sessionWorktreeManager, sessionId, opts) {
|
|
38854
|
+
const key = listChangesInflightKey(sessionId, opts);
|
|
38855
|
+
const existing = listChangesInflight.get(key);
|
|
38856
|
+
if (existing) return existing;
|
|
38857
|
+
const promise2 = sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts).finally(() => {
|
|
38858
|
+
if (listChangesInflight.get(key) === promise2) listChangesInflight.delete(key);
|
|
38859
|
+
});
|
|
38860
|
+
listChangesInflight.set(key, promise2);
|
|
38861
|
+
return promise2;
|
|
38862
|
+
}
|
|
38863
|
+
|
|
38864
|
+
// src/routing/handlers/git/handle-session-git-list-changes.ts
|
|
38865
|
+
async function handleSessionGitListChangesAction(deps, msg, reply) {
|
|
38866
|
+
const repoRel = typeof msg.changesRepoRelPath === "string" ? msg.changesRepoRelPath.trim() : "";
|
|
38867
|
+
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
38868
|
+
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
38869
|
+
if (view === "commit") {
|
|
38870
|
+
if (!repoRel || !commitSha) {
|
|
38871
|
+
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
38872
|
+
return;
|
|
38873
|
+
}
|
|
38874
|
+
}
|
|
38875
|
+
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
38876
|
+
const opts = repoRel && view === "commit" && commitSha ? {
|
|
38877
|
+
repoRelPath: repoRel,
|
|
38878
|
+
basis: { kind: "commit", sha: commitSha },
|
|
38879
|
+
recentCommitsLimit
|
|
38880
|
+
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
38881
|
+
const repos = await getSessionWorkingTreeChangeDetailsCoalesced(
|
|
38882
|
+
deps.sessionWorktreeManager,
|
|
38883
|
+
msg.sessionId,
|
|
38884
|
+
opts
|
|
38885
|
+
);
|
|
38886
|
+
reply({ ok: true, repos }, ["repos"]);
|
|
38887
|
+
}
|
|
38888
|
+
|
|
38889
|
+
// src/routing/handlers/git/handle-session-git-push.ts
|
|
38890
|
+
async function handleSessionGitPushAction(deps, sessionId, reply) {
|
|
38891
|
+
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
38892
|
+
if (!pushRes.ok) {
|
|
38893
|
+
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
38894
|
+
return;
|
|
38895
|
+
}
|
|
38896
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38897
|
+
reply({
|
|
38898
|
+
ok: true,
|
|
38899
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
38900
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
38901
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
38902
|
+
});
|
|
38903
|
+
}
|
|
38904
|
+
|
|
38905
|
+
// src/routing/handlers/git/handle-session-git-status.ts
|
|
38906
|
+
async function handleSessionGitStatusAction(deps, sessionId, reply) {
|
|
38907
|
+
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38908
|
+
reply({
|
|
38909
|
+
ok: true,
|
|
38910
|
+
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
38911
|
+
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
38912
|
+
uncommittedFileCount: r.uncommittedFileCount
|
|
38913
|
+
});
|
|
38914
|
+
}
|
|
38915
|
+
|
|
38916
|
+
// src/routing/handlers/git/send-session-git-result.ts
|
|
38917
|
+
function sendSessionGitResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
38575
38918
|
if (!ws) return;
|
|
38576
38919
|
const message = { type: "session_git_result", id, ...payload };
|
|
38577
38920
|
sendWsMessage(ws, e2ee && encryptedFields.length > 0 ? e2ee.encryptFields(message, encryptedFields) : message);
|
|
38578
38921
|
}
|
|
38922
|
+
|
|
38923
|
+
// src/routing/handlers/git/session-git-request.ts
|
|
38579
38924
|
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
38580
38925
|
if (typeof msg.id !== "string") return;
|
|
38581
38926
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -38584,80 +38929,21 @@ var handleSessionGitRequestMessage = (msg, deps) => {
|
|
|
38584
38929
|
return;
|
|
38585
38930
|
void (async () => {
|
|
38586
38931
|
const ws = deps.getWs();
|
|
38587
|
-
const reply = (payload, encryptedFields = []) =>
|
|
38932
|
+
const reply = (payload, encryptedFields = []) => sendSessionGitResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
38588
38933
|
try {
|
|
38589
38934
|
if (action === "status") {
|
|
38590
|
-
|
|
38591
|
-
reply({
|
|
38592
|
-
ok: true,
|
|
38593
|
-
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
38594
|
-
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
38595
|
-
uncommittedFileCount: r.uncommittedFileCount
|
|
38596
|
-
});
|
|
38935
|
+
await handleSessionGitStatusAction(deps, sessionId, reply);
|
|
38597
38936
|
return;
|
|
38598
38937
|
}
|
|
38599
38938
|
if (action === "list_changes") {
|
|
38600
|
-
|
|
38601
|
-
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
38602
|
-
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
38603
|
-
if (view === "commit") {
|
|
38604
|
-
if (!repoRel || !commitSha) {
|
|
38605
|
-
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
38606
|
-
return;
|
|
38607
|
-
}
|
|
38608
|
-
}
|
|
38609
|
-
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
38610
|
-
const opts = repoRel && view === "commit" && commitSha ? {
|
|
38611
|
-
repoRelPath: repoRel,
|
|
38612
|
-
basis: { kind: "commit", sha: commitSha },
|
|
38613
|
-
recentCommitsLimit
|
|
38614
|
-
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
38615
|
-
const repos = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts);
|
|
38616
|
-
reply({
|
|
38617
|
-
ok: true,
|
|
38618
|
-
repos
|
|
38619
|
-
}, ["repos"]);
|
|
38939
|
+
await handleSessionGitListChangesAction(deps, { ...msg, sessionId }, reply);
|
|
38620
38940
|
return;
|
|
38621
38941
|
}
|
|
38622
38942
|
if (action === "push") {
|
|
38623
|
-
|
|
38624
|
-
if (!pushRes.ok) {
|
|
38625
|
-
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
38626
|
-
return;
|
|
38627
|
-
}
|
|
38628
|
-
const st2 = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38629
|
-
reply({
|
|
38630
|
-
ok: true,
|
|
38631
|
-
hasUncommittedChanges: st2.hasUncommittedChanges,
|
|
38632
|
-
hasUnpushedCommits: st2.hasUnpushedCommits,
|
|
38633
|
-
uncommittedFileCount: st2.uncommittedFileCount
|
|
38634
|
-
});
|
|
38635
|
-
return;
|
|
38636
|
-
}
|
|
38637
|
-
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
38638
|
-
const message = typeof msg.message === "string" ? msg.message : "";
|
|
38639
|
-
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
38640
|
-
if (!branch.trim() || !message.trim()) {
|
|
38641
|
-
reply({ ok: false, error: "branch and message are required for commit" });
|
|
38943
|
+
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
38642
38944
|
return;
|
|
38643
38945
|
}
|
|
38644
|
-
|
|
38645
|
-
sessionId,
|
|
38646
|
-
branch: branch.trim(),
|
|
38647
|
-
message: message.trim(),
|
|
38648
|
-
push: pushAfterCommit
|
|
38649
|
-
});
|
|
38650
|
-
if (!commitRes.ok) {
|
|
38651
|
-
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
38652
|
-
return;
|
|
38653
|
-
}
|
|
38654
|
-
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38655
|
-
reply({
|
|
38656
|
-
ok: true,
|
|
38657
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
38658
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
38659
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
38660
|
-
});
|
|
38946
|
+
await handleSessionGitCommitAction(deps, sessionId, msg, reply);
|
|
38661
38947
|
} catch (e) {
|
|
38662
38948
|
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
38663
38949
|
}
|
|
@@ -38687,7 +38973,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
38687
38973
|
};
|
|
38688
38974
|
|
|
38689
38975
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
38690
|
-
import * as
|
|
38976
|
+
import * as fs43 from "node:fs";
|
|
38691
38977
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
38692
38978
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
38693
38979
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -38700,7 +38986,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
38700
38986
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
38701
38987
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
38702
38988
|
try {
|
|
38703
|
-
await
|
|
38989
|
+
await fs43.promises.access(file2, fs43.constants.F_OK);
|
|
38704
38990
|
} catch {
|
|
38705
38991
|
sendWsMessage(s, {
|
|
38706
38992
|
type: "revert_turn_snapshot_result",
|
|
@@ -38742,7 +39028,7 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
38742
39028
|
};
|
|
38743
39029
|
|
|
38744
39030
|
// src/git/bridge-git-context.ts
|
|
38745
|
-
import * as
|
|
39031
|
+
import * as path49 from "node:path";
|
|
38746
39032
|
|
|
38747
39033
|
// src/git/branches/get-current-branch.ts
|
|
38748
39034
|
async function getCurrentBranch(repoPath) {
|
|
@@ -38792,12 +39078,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
38792
39078
|
// src/git/bridge-git-context.ts
|
|
38793
39079
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
38794
39080
|
if (relPath === "." || relPath === "") {
|
|
38795
|
-
return
|
|
39081
|
+
return path49.basename(path49.resolve(bridgeRoot)) || "repo";
|
|
38796
39082
|
}
|
|
38797
|
-
return
|
|
39083
|
+
return path49.basename(relPath) || relPath;
|
|
38798
39084
|
}
|
|
38799
39085
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
38800
|
-
const root =
|
|
39086
|
+
const root = path49.resolve(bridgeRoot);
|
|
38801
39087
|
if (await isGitRepoDirectory(root)) {
|
|
38802
39088
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
38803
39089
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -38805,17 +39091,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
38805
39091
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
38806
39092
|
const byPath = /* @__PURE__ */ new Map();
|
|
38807
39093
|
for (const repo of [...deep, ...shallow]) {
|
|
38808
|
-
byPath.set(
|
|
39094
|
+
byPath.set(path49.resolve(repo.absolutePath), repo);
|
|
38809
39095
|
}
|
|
38810
39096
|
return [...byPath.values()];
|
|
38811
39097
|
}
|
|
38812
39098
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
38813
|
-
const bridgeResolved =
|
|
39099
|
+
const bridgeResolved = path49.resolve(bridgeRoot);
|
|
38814
39100
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
38815
39101
|
const rows = [];
|
|
38816
39102
|
for (const repo of repos) {
|
|
38817
|
-
let rel =
|
|
38818
|
-
if (rel.startsWith("..") ||
|
|
39103
|
+
let rel = path49.relative(bridgeResolved, repo.absolutePath);
|
|
39104
|
+
if (rel.startsWith("..") || path49.isAbsolute(rel)) continue;
|
|
38819
39105
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
38820
39106
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
38821
39107
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -38830,11 +39116,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
38830
39116
|
return rows;
|
|
38831
39117
|
}
|
|
38832
39118
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
38833
|
-
const bridgeResolved =
|
|
39119
|
+
const bridgeResolved = path49.resolve(bridgeRoot);
|
|
38834
39120
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
38835
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
38836
|
-
const resolved =
|
|
38837
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
39121
|
+
const repoPath = rel === "" ? bridgeResolved : path49.join(bridgeResolved, rel);
|
|
39122
|
+
const resolved = path49.resolve(repoPath);
|
|
39123
|
+
if (!resolved.startsWith(bridgeResolved + path49.sep) && resolved !== bridgeResolved) {
|
|
38838
39124
|
return [];
|
|
38839
39125
|
}
|
|
38840
39126
|
return listRepoBranchRefs(resolved);
|
|
@@ -39418,10 +39704,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
39418
39704
|
}
|
|
39419
39705
|
|
|
39420
39706
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
39421
|
-
import * as
|
|
39707
|
+
import * as path51 from "node:path";
|
|
39422
39708
|
|
|
39423
39709
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
39424
|
-
import * as
|
|
39710
|
+
import * as path50 from "node:path";
|
|
39425
39711
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
39426
39712
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
|
|
39427
39713
|
const canContinue = () => shouldContinue?.() !== false;
|
|
@@ -39459,7 +39745,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
39459
39745
|
if (!canContinue()) return false;
|
|
39460
39746
|
handle = await resolved.createClient({
|
|
39461
39747
|
command: resolved.command,
|
|
39462
|
-
cwd:
|
|
39748
|
+
cwd: path50.resolve(cwd),
|
|
39463
39749
|
backendAgentType: agentType,
|
|
39464
39750
|
sessionMode: "agent",
|
|
39465
39751
|
persistedAcpSessionId: null,
|
|
@@ -39537,7 +39823,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
39537
39823
|
const { workspaceId, log: log2, getWs } = params;
|
|
39538
39824
|
const isCurrent = beginAgentCapabilityWarmupRun();
|
|
39539
39825
|
if (!isCurrent()) return;
|
|
39540
|
-
const cwd =
|
|
39826
|
+
const cwd = path51.resolve(getBridgeRoot());
|
|
39541
39827
|
async function sendBatchFromCache() {
|
|
39542
39828
|
if (!isCurrent()) return;
|
|
39543
39829
|
const socket = getWs();
|
|
@@ -39883,18 +40169,18 @@ import * as http from "node:http";
|
|
|
39883
40169
|
|
|
39884
40170
|
// src/mcp/bridge-access/read-json-body.ts
|
|
39885
40171
|
function readJsonBody(req) {
|
|
39886
|
-
return new Promise((
|
|
40172
|
+
return new Promise((resolve26, reject) => {
|
|
39887
40173
|
const chunks = [];
|
|
39888
40174
|
req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
39889
40175
|
req.on("end", () => {
|
|
39890
40176
|
try {
|
|
39891
40177
|
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
39892
40178
|
if (!raw) {
|
|
39893
|
-
|
|
40179
|
+
resolve26({});
|
|
39894
40180
|
return;
|
|
39895
40181
|
}
|
|
39896
40182
|
const parsed = JSON.parse(raw);
|
|
39897
|
-
|
|
40183
|
+
resolve26(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
|
|
39898
40184
|
} catch (e) {
|
|
39899
40185
|
reject(e);
|
|
39900
40186
|
}
|
|
@@ -39952,7 +40238,7 @@ function createBridgeAccessRequestHandler(registry2) {
|
|
|
39952
40238
|
// src/mcp/bridge-access/start-server.ts
|
|
39953
40239
|
function startBridgeAccessServer(registry2) {
|
|
39954
40240
|
const server = http.createServer(createBridgeAccessRequestHandler(registry2));
|
|
39955
|
-
return new Promise((
|
|
40241
|
+
return new Promise((resolve26, reject) => {
|
|
39956
40242
|
server.once("error", reject);
|
|
39957
40243
|
server.listen(0, "127.0.0.1", () => {
|
|
39958
40244
|
const addr = server.address();
|
|
@@ -39960,7 +40246,7 @@ function startBridgeAccessServer(registry2) {
|
|
|
39960
40246
|
reject(new Error("Bridge access server did not bind"));
|
|
39961
40247
|
return;
|
|
39962
40248
|
}
|
|
39963
|
-
|
|
40249
|
+
resolve26({
|
|
39964
40250
|
port: addr.port,
|
|
39965
40251
|
close: () => new Promise((closeResolve, closeReject) => {
|
|
39966
40252
|
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
@@ -40100,8 +40386,8 @@ async function createBridgeConnection(options) {
|
|
|
40100
40386
|
getCloudAccessToken: () => tokens.accessToken
|
|
40101
40387
|
};
|
|
40102
40388
|
const identifyReportedPaths = {
|
|
40103
|
-
bridgeRootPath:
|
|
40104
|
-
worktreesRootPath:
|
|
40389
|
+
bridgeRootPath: path52.resolve(getBridgeRoot()),
|
|
40390
|
+
worktreesRootPath: path52.resolve(worktreesRootPath)
|
|
40105
40391
|
};
|
|
40106
40392
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
40107
40393
|
state,
|