@buildautomaton/cli 0.1.27 → 0.1.29
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 +946 -616
- package/dist/cli.js.map +4 -4
- package/dist/index.js +911 -581
- package/dist/index.js.map +4 -4
- package/dist/migrations/000_bootstrap_migrations_table.sql +4 -0
- package/dist/migrations/001_cli_sqlite_checkpoint_v1.sql +20 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -4065,8 +4065,8 @@ var init_parseUtil = __esm({
|
|
|
4065
4065
|
init_errors();
|
|
4066
4066
|
init_en();
|
|
4067
4067
|
makeIssue = (params) => {
|
|
4068
|
-
const { data, path:
|
|
4069
|
-
const fullPath = [...
|
|
4068
|
+
const { data, path: path39, errorMaps, issueData } = params;
|
|
4069
|
+
const fullPath = [...path39, ...issueData.path || []];
|
|
4070
4070
|
const fullIssue = {
|
|
4071
4071
|
...issueData,
|
|
4072
4072
|
path: fullPath
|
|
@@ -4374,11 +4374,11 @@ var init_types = __esm({
|
|
|
4374
4374
|
init_parseUtil();
|
|
4375
4375
|
init_util();
|
|
4376
4376
|
ParseInputLazyPath = class {
|
|
4377
|
-
constructor(parent, value,
|
|
4377
|
+
constructor(parent, value, path39, key) {
|
|
4378
4378
|
this._cachedPath = [];
|
|
4379
4379
|
this.parent = parent;
|
|
4380
4380
|
this.data = value;
|
|
4381
|
-
this._path =
|
|
4381
|
+
this._path = path39;
|
|
4382
4382
|
this._key = key;
|
|
4383
4383
|
}
|
|
4384
4384
|
get path() {
|
|
@@ -7993,10 +7993,10 @@ function assignProp(target, prop, value) {
|
|
|
7993
7993
|
configurable: true
|
|
7994
7994
|
});
|
|
7995
7995
|
}
|
|
7996
|
-
function getElementAtPath(obj,
|
|
7997
|
-
if (!
|
|
7996
|
+
function getElementAtPath(obj, path39) {
|
|
7997
|
+
if (!path39)
|
|
7998
7998
|
return obj;
|
|
7999
|
-
return
|
|
7999
|
+
return path39.reduce((acc, key) => acc?.[key], obj);
|
|
8000
8000
|
}
|
|
8001
8001
|
function promiseAllObject(promisesObj) {
|
|
8002
8002
|
const keys = Object.keys(promisesObj);
|
|
@@ -8245,11 +8245,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8245
8245
|
}
|
|
8246
8246
|
return false;
|
|
8247
8247
|
}
|
|
8248
|
-
function prefixIssues(
|
|
8248
|
+
function prefixIssues(path39, issues) {
|
|
8249
8249
|
return issues.map((iss) => {
|
|
8250
8250
|
var _a2;
|
|
8251
8251
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8252
|
-
iss.path.unshift(
|
|
8252
|
+
iss.path.unshift(path39);
|
|
8253
8253
|
return iss;
|
|
8254
8254
|
});
|
|
8255
8255
|
}
|
|
@@ -8438,7 +8438,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8438
8438
|
return issue2.message;
|
|
8439
8439
|
};
|
|
8440
8440
|
const result = { errors: [] };
|
|
8441
|
-
const processError = (error41,
|
|
8441
|
+
const processError = (error41, path39 = []) => {
|
|
8442
8442
|
var _a2, _b;
|
|
8443
8443
|
for (const issue2 of error41.issues) {
|
|
8444
8444
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8448,7 +8448,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8448
8448
|
} else if (issue2.code === "invalid_element") {
|
|
8449
8449
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8450
8450
|
} else {
|
|
8451
|
-
const fullpath = [...
|
|
8451
|
+
const fullpath = [...path39, ...issue2.path];
|
|
8452
8452
|
if (fullpath.length === 0) {
|
|
8453
8453
|
result.errors.push(mapper(issue2));
|
|
8454
8454
|
continue;
|
|
@@ -8478,9 +8478,9 @@ function treeifyError(error40, _mapper) {
|
|
|
8478
8478
|
processError(error40);
|
|
8479
8479
|
return result;
|
|
8480
8480
|
}
|
|
8481
|
-
function toDotPath(
|
|
8481
|
+
function toDotPath(path39) {
|
|
8482
8482
|
const segs = [];
|
|
8483
|
-
for (const seg of
|
|
8483
|
+
for (const seg of path39) {
|
|
8484
8484
|
if (typeof seg === "number")
|
|
8485
8485
|
segs.push(`[${seg}]`);
|
|
8486
8486
|
else if (typeof seg === "symbol")
|
|
@@ -21669,7 +21669,7 @@ var require_has_flag = __commonJS({
|
|
|
21669
21669
|
var require_supports_color = __commonJS({
|
|
21670
21670
|
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
|
|
21671
21671
|
"use strict";
|
|
21672
|
-
var
|
|
21672
|
+
var os9 = __require("os");
|
|
21673
21673
|
var tty = __require("tty");
|
|
21674
21674
|
var hasFlag = require_has_flag();
|
|
21675
21675
|
var { env } = process;
|
|
@@ -21717,7 +21717,7 @@ var require_supports_color = __commonJS({
|
|
|
21717
21717
|
return min;
|
|
21718
21718
|
}
|
|
21719
21719
|
if (process.platform === "win32") {
|
|
21720
|
-
const osRelease =
|
|
21720
|
+
const osRelease = os9.release().split(".");
|
|
21721
21721
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
21722
21722
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
21723
21723
|
}
|
|
@@ -21963,10 +21963,10 @@ var require_src2 = __commonJS({
|
|
|
21963
21963
|
var fs_1 = __require("fs");
|
|
21964
21964
|
var debug_1 = __importDefault(require_src());
|
|
21965
21965
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
21966
|
-
function check2(
|
|
21967
|
-
log2(`checking %s`,
|
|
21966
|
+
function check2(path39, isFile, isDirectory) {
|
|
21967
|
+
log2(`checking %s`, path39);
|
|
21968
21968
|
try {
|
|
21969
|
-
const stat2 = fs_1.statSync(
|
|
21969
|
+
const stat2 = fs_1.statSync(path39);
|
|
21970
21970
|
if (stat2.isFile() && isFile) {
|
|
21971
21971
|
log2(`[OK] path represents a file`);
|
|
21972
21972
|
return true;
|
|
@@ -21986,8 +21986,8 @@ var require_src2 = __commonJS({
|
|
|
21986
21986
|
throw e;
|
|
21987
21987
|
}
|
|
21988
21988
|
}
|
|
21989
|
-
function exists2(
|
|
21990
|
-
return check2(
|
|
21989
|
+
function exists2(path39, type = exports.READABLE) {
|
|
21990
|
+
return check2(path39, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
21991
21991
|
}
|
|
21992
21992
|
exports.exists = exists2;
|
|
21993
21993
|
exports.FILE = 1;
|
|
@@ -22792,9 +22792,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
22792
22792
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
22793
22793
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
22794
22794
|
if (!rawPath || !summary) continue;
|
|
22795
|
-
const
|
|
22796
|
-
if (!
|
|
22797
|
-
rows.push({ path:
|
|
22795
|
+
const path39 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
22796
|
+
if (!path39) continue;
|
|
22797
|
+
rows.push({ path: path39, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
22798
22798
|
}
|
|
22799
22799
|
return rows;
|
|
22800
22800
|
}
|
|
@@ -23668,8 +23668,8 @@ function randomSecret() {
|
|
|
23668
23668
|
}
|
|
23669
23669
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
23670
23670
|
}
|
|
23671
|
-
async function requestPreviewApi(port, secret, method,
|
|
23672
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
23671
|
+
async function requestPreviewApi(port, secret, method, path39, body) {
|
|
23672
|
+
const url2 = `http://127.0.0.1:${port}${path39}`;
|
|
23673
23673
|
const headers = {
|
|
23674
23674
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
23675
23675
|
"Content-Type": "application/json"
|
|
@@ -23681,7 +23681,7 @@ async function requestPreviewApi(port, secret, method, path35, body) {
|
|
|
23681
23681
|
});
|
|
23682
23682
|
const data = await res.json().catch(() => ({}));
|
|
23683
23683
|
if (!res.ok) {
|
|
23684
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
23684
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path39}: ${res.status}`);
|
|
23685
23685
|
}
|
|
23686
23686
|
return data;
|
|
23687
23687
|
}
|
|
@@ -23896,7 +23896,13 @@ function installBridgeProcessResilience() {
|
|
|
23896
23896
|
}
|
|
23897
23897
|
|
|
23898
23898
|
// src/cli-version.ts
|
|
23899
|
-
var CLI_VERSION = "0.1.
|
|
23899
|
+
var CLI_VERSION = "0.1.29".length > 0 ? "0.1.29" : "0.0.0-dev";
|
|
23900
|
+
|
|
23901
|
+
// src/connection/heartbeat/constants.ts
|
|
23902
|
+
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
23903
|
+
var BRIDGE_HEARTBEAT_SEQ_MAX = 2147483646;
|
|
23904
|
+
var BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT = 4;
|
|
23905
|
+
var BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX = 5;
|
|
23900
23906
|
|
|
23901
23907
|
// ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
|
|
23902
23908
|
import process7 from "node:process";
|
|
@@ -24876,14 +24882,18 @@ function runPendingAuth(options) {
|
|
|
24876
24882
|
}
|
|
24877
24883
|
function connect() {
|
|
24878
24884
|
const url2 = buildPendingBridgeUrl(apiUrl, connectionId);
|
|
24885
|
+
let pendingHbSeq = -1;
|
|
24879
24886
|
ws = createWsBridge({
|
|
24880
24887
|
url: url2,
|
|
24881
24888
|
onOpen: () => {
|
|
24882
24889
|
clearQuietOnOpen();
|
|
24890
|
+
pendingHbSeq = -1;
|
|
24883
24891
|
sendWsMessage(ws, { type: "identify", role: "cli", cliVersion: CLI_VERSION });
|
|
24884
24892
|
keepaliveInterval = setInterval(() => {
|
|
24885
24893
|
if (resolved || !ws || ws.readyState !== 1) return;
|
|
24886
|
-
|
|
24894
|
+
pendingHbSeq = pendingHbSeq >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : pendingHbSeq + 1;
|
|
24895
|
+
const hb = { t: "h", s: pendingHbSeq };
|
|
24896
|
+
sendWsMessage(ws, hb);
|
|
24887
24897
|
}, PENDING_KEEPALIVE_MS);
|
|
24888
24898
|
if (browserFallback) {
|
|
24889
24899
|
clearTimeout(browserFallback);
|
|
@@ -24946,6 +24956,321 @@ function runPendingAuth(options) {
|
|
|
24946
24956
|
};
|
|
24947
24957
|
}
|
|
24948
24958
|
|
|
24959
|
+
// src/sqlite/cli-database.ts
|
|
24960
|
+
import sqliteWasm from "node-sqlite3-wasm";
|
|
24961
|
+
|
|
24962
|
+
// src/sqlite/cli-sqlite-paths.ts
|
|
24963
|
+
import fs7 from "node:fs";
|
|
24964
|
+
import path5 from "node:path";
|
|
24965
|
+
import os3 from "node:os";
|
|
24966
|
+
function getCliSqlitePath() {
|
|
24967
|
+
const override = process.env.BUILDAMATON_CLI_SQLITE_PATH?.trim();
|
|
24968
|
+
if (override) return path5.resolve(override);
|
|
24969
|
+
return path5.join(os3.homedir(), ".buildautomaton", "cli.sqlite");
|
|
24970
|
+
}
|
|
24971
|
+
function ensureCliSqliteParentDir(sqlitePath) {
|
|
24972
|
+
const dir = path5.dirname(sqlitePath);
|
|
24973
|
+
if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
|
|
24974
|
+
}
|
|
24975
|
+
|
|
24976
|
+
// src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
|
|
24977
|
+
import fs12 from "node:fs";
|
|
24978
|
+
|
|
24979
|
+
// src/files/index/constants.ts
|
|
24980
|
+
import path6 from "node:path";
|
|
24981
|
+
import os4 from "node:os";
|
|
24982
|
+
var INDEX_WORK_YIELD_EVERY = 256;
|
|
24983
|
+
var INDEX_DIR = path6.join(os4.homedir(), ".buildautomaton");
|
|
24984
|
+
var INDEX_HASH_LEN = 16;
|
|
24985
|
+
|
|
24986
|
+
// src/prompt-turn-queue/paths.ts
|
|
24987
|
+
import path7 from "node:path";
|
|
24988
|
+
import os5 from "node:os";
|
|
24989
|
+
function getPromptQueuesDirectory() {
|
|
24990
|
+
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
24991
|
+
if (override) return path7.resolve(override);
|
|
24992
|
+
return path7.join(os5.homedir(), ".buildautomaton", "queues");
|
|
24993
|
+
}
|
|
24994
|
+
|
|
24995
|
+
// src/sqlite/legacy_migration/archive-file-index-json.ts
|
|
24996
|
+
import fs9 from "node:fs";
|
|
24997
|
+
import path9 from "node:path";
|
|
24998
|
+
|
|
24999
|
+
// src/sqlite/legacy_migration/archive-to-old-version.ts
|
|
25000
|
+
import fs8 from "node:fs";
|
|
25001
|
+
import path8 from "node:path";
|
|
25002
|
+
var OLD_VERSION_DIR = path8.join(INDEX_DIR, "old-version");
|
|
25003
|
+
function moveLegacyFileToOldVersionBackup(category, sourcePath) {
|
|
25004
|
+
const destDir = path8.join(OLD_VERSION_DIR, category);
|
|
25005
|
+
fs8.mkdirSync(destDir, { recursive: true });
|
|
25006
|
+
const base = path8.basename(sourcePath);
|
|
25007
|
+
let dest = path8.join(destDir, base);
|
|
25008
|
+
if (fs8.existsSync(dest)) {
|
|
25009
|
+
const ext = path8.extname(base);
|
|
25010
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
25011
|
+
dest = path8.join(destDir, `${stem}-${Date.now()}${ext}`);
|
|
25012
|
+
}
|
|
25013
|
+
fs8.renameSync(sourcePath, dest);
|
|
25014
|
+
}
|
|
25015
|
+
|
|
25016
|
+
// src/sqlite/legacy_migration/archive-file-index-json.ts
|
|
25017
|
+
function archiveLegacyFileIndexJsonFiles() {
|
|
25018
|
+
try {
|
|
25019
|
+
if (!fs9.existsSync(INDEX_DIR)) return;
|
|
25020
|
+
for (const name of fs9.readdirSync(INDEX_DIR)) {
|
|
25021
|
+
if (name.startsWith(".file-index-") && name.endsWith(".json")) {
|
|
25022
|
+
const full = path9.join(INDEX_DIR, name);
|
|
25023
|
+
try {
|
|
25024
|
+
moveLegacyFileToOldVersionBackup("file-index", full);
|
|
25025
|
+
} catch (err) {
|
|
25026
|
+
console.error(`[cli-sqlite] legacy import: could not archive ${name}`, err);
|
|
25027
|
+
}
|
|
25028
|
+
}
|
|
25029
|
+
}
|
|
25030
|
+
} catch (e) {
|
|
25031
|
+
console.error("[cli-sqlite] legacy import: archive file-index json failed", e);
|
|
25032
|
+
}
|
|
25033
|
+
}
|
|
25034
|
+
|
|
25035
|
+
// src/sqlite/legacy_migration/import-agent-sessions-from-disk.ts
|
|
25036
|
+
import fs10 from "node:fs";
|
|
25037
|
+
import path10 from "node:path";
|
|
25038
|
+
import os6 from "node:os";
|
|
25039
|
+
var LEGACY_AGENT_SESSION_DIR = path10.join(os6.homedir(), ".buildautomaton", "agent-sessions");
|
|
25040
|
+
function importLegacyAgentSessionsFromDisk(db) {
|
|
25041
|
+
try {
|
|
25042
|
+
if (!fs10.existsSync(LEGACY_AGENT_SESSION_DIR)) return;
|
|
25043
|
+
const names = fs10.readdirSync(LEGACY_AGENT_SESSION_DIR).filter((n) => n.endsWith(".json"));
|
|
25044
|
+
for (const name of names) {
|
|
25045
|
+
const sessionKey = name.slice(0, -".json".length);
|
|
25046
|
+
const full = path10.join(LEGACY_AGENT_SESSION_DIR, name);
|
|
25047
|
+
let raw;
|
|
25048
|
+
try {
|
|
25049
|
+
raw = fs10.readFileSync(full, "utf8");
|
|
25050
|
+
} catch {
|
|
25051
|
+
continue;
|
|
25052
|
+
}
|
|
25053
|
+
let parsed;
|
|
25054
|
+
try {
|
|
25055
|
+
parsed = JSON.parse(raw);
|
|
25056
|
+
} catch {
|
|
25057
|
+
continue;
|
|
25058
|
+
}
|
|
25059
|
+
if (parsed.v !== 1) continue;
|
|
25060
|
+
const acpSessionId = typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null;
|
|
25061
|
+
const backendAgentType = typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null;
|
|
25062
|
+
const configOptionsJson = Array.isArray(parsed.configOptions) ? JSON.stringify(parsed.configOptions) : null;
|
|
25063
|
+
const updatedAt = typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
25064
|
+
db.run(
|
|
25065
|
+
`INSERT OR REPLACE INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
|
|
25066
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
25067
|
+
[sessionKey, acpSessionId, backendAgentType, configOptionsJson, updatedAt]
|
|
25068
|
+
);
|
|
25069
|
+
try {
|
|
25070
|
+
moveLegacyFileToOldVersionBackup("agent-sessions", full);
|
|
25071
|
+
} catch {
|
|
25072
|
+
}
|
|
25073
|
+
}
|
|
25074
|
+
} catch (e) {
|
|
25075
|
+
console.error("[cli-sqlite] legacy import: agent_sessions from disk failed", e);
|
|
25076
|
+
}
|
|
25077
|
+
}
|
|
25078
|
+
|
|
25079
|
+
// src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
|
|
25080
|
+
import fs11 from "node:fs";
|
|
25081
|
+
import path11 from "node:path";
|
|
25082
|
+
|
|
25083
|
+
// src/sqlite/legacy_migration/parse-persisted-queue-json.ts
|
|
25084
|
+
function parsePersistedQueueFromJson(raw) {
|
|
25085
|
+
try {
|
|
25086
|
+
const o = JSON.parse(raw);
|
|
25087
|
+
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
25088
|
+
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
25089
|
+
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
25090
|
+
} catch {
|
|
25091
|
+
return null;
|
|
25092
|
+
}
|
|
25093
|
+
}
|
|
25094
|
+
|
|
25095
|
+
// src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
|
|
25096
|
+
function importLegacyPromptQueuesFromDisk(db) {
|
|
25097
|
+
try {
|
|
25098
|
+
const dir = getPromptQueuesDirectory();
|
|
25099
|
+
if (!fs11.existsSync(dir)) return;
|
|
25100
|
+
for (const name of fs11.readdirSync(dir)) {
|
|
25101
|
+
if (!name.endsWith(".json")) continue;
|
|
25102
|
+
const full = path11.join(dir, name);
|
|
25103
|
+
let raw;
|
|
25104
|
+
try {
|
|
25105
|
+
raw = fs11.readFileSync(full, "utf8");
|
|
25106
|
+
} catch {
|
|
25107
|
+
continue;
|
|
25108
|
+
}
|
|
25109
|
+
const file2 = parsePersistedQueueFromJson(raw);
|
|
25110
|
+
if (!file2) continue;
|
|
25111
|
+
db.run(
|
|
25112
|
+
`INSERT OR REPLACE INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)`,
|
|
25113
|
+
[file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
|
|
25114
|
+
);
|
|
25115
|
+
try {
|
|
25116
|
+
moveLegacyFileToOldVersionBackup("queues", full);
|
|
25117
|
+
} catch {
|
|
25118
|
+
}
|
|
25119
|
+
}
|
|
25120
|
+
} catch (e) {
|
|
25121
|
+
console.error("[cli-sqlite] legacy import: prompt queues from disk failed", e);
|
|
25122
|
+
}
|
|
25123
|
+
}
|
|
25124
|
+
|
|
25125
|
+
// src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
|
|
25126
|
+
function legacyCliDiskMigrationIsPending() {
|
|
25127
|
+
try {
|
|
25128
|
+
if (fs12.existsSync(INDEX_DIR)) {
|
|
25129
|
+
for (const name of fs12.readdirSync(INDEX_DIR)) {
|
|
25130
|
+
if (name.startsWith(".file-index-") && name.endsWith(".json")) return true;
|
|
25131
|
+
}
|
|
25132
|
+
}
|
|
25133
|
+
} catch {
|
|
25134
|
+
}
|
|
25135
|
+
try {
|
|
25136
|
+
if (fs12.existsSync(LEGACY_AGENT_SESSION_DIR)) {
|
|
25137
|
+
if (fs12.readdirSync(LEGACY_AGENT_SESSION_DIR).some((n) => n.endsWith(".json"))) return true;
|
|
25138
|
+
}
|
|
25139
|
+
} catch {
|
|
25140
|
+
}
|
|
25141
|
+
try {
|
|
25142
|
+
const dir = getPromptQueuesDirectory();
|
|
25143
|
+
if (fs12.existsSync(dir) && fs12.readdirSync(dir).some((n) => n.endsWith(".json"))) return true;
|
|
25144
|
+
} catch {
|
|
25145
|
+
}
|
|
25146
|
+
return false;
|
|
25147
|
+
}
|
|
25148
|
+
function importCliSqliteLegacyDiskData(db, log2) {
|
|
25149
|
+
const pending = legacyCliDiskMigrationIsPending();
|
|
25150
|
+
if (pending && log2) {
|
|
25151
|
+
log2("Migrating legacy on-disk CLI data to SQLite\u2026");
|
|
25152
|
+
}
|
|
25153
|
+
archiveLegacyFileIndexJsonFiles();
|
|
25154
|
+
importLegacyAgentSessionsFromDisk(db);
|
|
25155
|
+
importLegacyPromptQueuesFromDisk(db);
|
|
25156
|
+
if (pending && log2) {
|
|
25157
|
+
log2("Legacy on-disk CLI data migration finished.");
|
|
25158
|
+
}
|
|
25159
|
+
}
|
|
25160
|
+
|
|
25161
|
+
// src/sqlite/load-cli-migration-sql.ts
|
|
25162
|
+
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
25163
|
+
import { dirname as dirname2, join } from "node:path";
|
|
25164
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
25165
|
+
function readCliSqliteMigrationSql(filename) {
|
|
25166
|
+
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
25167
|
+
const resolved = join(dir, "migrations", filename);
|
|
25168
|
+
if (!existsSync(resolved)) {
|
|
25169
|
+
throw new Error(`Missing CLI SQLite migration SQL: ${resolved}`);
|
|
25170
|
+
}
|
|
25171
|
+
return readFileSync2(resolved, "utf8");
|
|
25172
|
+
}
|
|
25173
|
+
|
|
25174
|
+
// src/sqlite/migrate-cli-sqlite.ts
|
|
25175
|
+
function checkpointSatisfiedByLegacyChain(applied2, replacesLegacyMigrations) {
|
|
25176
|
+
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) => applied2.has(n));
|
|
25177
|
+
}
|
|
25178
|
+
function recordMigrationAndPruneCheckpointLegacy(db, migration, applied2) {
|
|
25179
|
+
db.run("INSERT INTO __migrations (name) VALUES (?)", [migration.name]);
|
|
25180
|
+
applied2.add(migration.name);
|
|
25181
|
+
if (migration.checkpoint !== true) return;
|
|
25182
|
+
const legacy = migration.replacesLegacyMigrations;
|
|
25183
|
+
if (!legacy?.length) return;
|
|
25184
|
+
for (const legacyName of legacy) {
|
|
25185
|
+
if (legacyName === migration.name) continue;
|
|
25186
|
+
db.run("DELETE FROM __migrations WHERE name = ?", [legacyName]);
|
|
25187
|
+
applied2.delete(legacyName);
|
|
25188
|
+
}
|
|
25189
|
+
}
|
|
25190
|
+
var CHECKPOINT_V1 = "001_cli_sqlite_checkpoint_v1";
|
|
25191
|
+
var CHECKPOINT_V1_SQL = readCliSqliteMigrationSql("001_cli_sqlite_checkpoint_v1.sql");
|
|
25192
|
+
var CLI_SQLITE_MIGRATIONS = [
|
|
25193
|
+
{
|
|
25194
|
+
name: CHECKPOINT_V1,
|
|
25195
|
+
checkpoint: true,
|
|
25196
|
+
migrate: (db) => {
|
|
25197
|
+
db.exec(CHECKPOINT_V1_SQL);
|
|
25198
|
+
}
|
|
25199
|
+
}
|
|
25200
|
+
];
|
|
25201
|
+
function migrateCliSqlite(db) {
|
|
25202
|
+
db.exec(readCliSqliteMigrationSql("000_bootstrap_migrations_table.sql"));
|
|
25203
|
+
const appliedRows = db.all("SELECT name FROM __migrations");
|
|
25204
|
+
const applied2 = new Set(appliedRows.map((r) => r.name));
|
|
25205
|
+
for (const migration of CLI_SQLITE_MIGRATIONS) {
|
|
25206
|
+
if (applied2.has(migration.name)) continue;
|
|
25207
|
+
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied2, migration.replacesLegacyMigrations)) {
|
|
25208
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
25209
|
+
continue;
|
|
25210
|
+
}
|
|
25211
|
+
if (migration.alreadyApplied?.(db)) {
|
|
25212
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
25213
|
+
continue;
|
|
25214
|
+
}
|
|
25215
|
+
try {
|
|
25216
|
+
migration.migrate(db);
|
|
25217
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
25218
|
+
} catch (e) {
|
|
25219
|
+
console.error(`[cli-sqlite] Migration failed: ${migration.name}`, e);
|
|
25220
|
+
throw e;
|
|
25221
|
+
}
|
|
25222
|
+
}
|
|
25223
|
+
}
|
|
25224
|
+
|
|
25225
|
+
// src/sqlite/cli-database.ts
|
|
25226
|
+
var { Database: SqliteDatabase } = sqliteWasm;
|
|
25227
|
+
var openDatabases = /* @__PURE__ */ new Map();
|
|
25228
|
+
var processExitCloseRegistered = false;
|
|
25229
|
+
function registerProcessExitSqliteClose() {
|
|
25230
|
+
if (processExitCloseRegistered) return;
|
|
25231
|
+
processExitCloseRegistered = true;
|
|
25232
|
+
process.once("exit", () => {
|
|
25233
|
+
for (const db of openDatabases.values()) {
|
|
25234
|
+
safeCloseCliSqliteDatabase(db);
|
|
25235
|
+
}
|
|
25236
|
+
openDatabases.clear();
|
|
25237
|
+
});
|
|
25238
|
+
}
|
|
25239
|
+
function safeCloseCliSqliteDatabase(db) {
|
|
25240
|
+
if (db == null) return;
|
|
25241
|
+
try {
|
|
25242
|
+
if (db.isOpen) db.close();
|
|
25243
|
+
} catch {
|
|
25244
|
+
}
|
|
25245
|
+
}
|
|
25246
|
+
function closeAllCliSqliteConnections() {
|
|
25247
|
+
for (const db of openDatabases.values()) {
|
|
25248
|
+
safeCloseCliSqliteDatabase(db);
|
|
25249
|
+
}
|
|
25250
|
+
openDatabases.clear();
|
|
25251
|
+
}
|
|
25252
|
+
function getCliDatabase(options) {
|
|
25253
|
+
const sqlitePath = getCliSqlitePath();
|
|
25254
|
+
const existing = openDatabases.get(sqlitePath);
|
|
25255
|
+
if (existing?.isOpen) return existing;
|
|
25256
|
+
if (existing && !existing.isOpen) {
|
|
25257
|
+
safeCloseCliSqliteDatabase(existing);
|
|
25258
|
+
openDatabases.delete(sqlitePath);
|
|
25259
|
+
}
|
|
25260
|
+
ensureCliSqliteParentDir(sqlitePath);
|
|
25261
|
+
const db = new SqliteDatabase(sqlitePath);
|
|
25262
|
+
try {
|
|
25263
|
+
migrateCliSqlite(db);
|
|
25264
|
+
importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
|
|
25265
|
+
} catch (e) {
|
|
25266
|
+
safeCloseCliSqliteDatabase(db);
|
|
25267
|
+
throw e;
|
|
25268
|
+
}
|
|
25269
|
+
openDatabases.set(sqlitePath, db);
|
|
25270
|
+
registerProcessExitSqliteClose();
|
|
25271
|
+
return db;
|
|
25272
|
+
}
|
|
25273
|
+
|
|
24949
25274
|
// src/connection/close-bridge-connection.ts
|
|
24950
25275
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
24951
25276
|
const say = log2 ?? logImmediate;
|
|
@@ -24989,20 +25314,24 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
|
|
|
24989
25314
|
say("Stopping local dev server processes\u2026");
|
|
24990
25315
|
await devServerManager.shutdownAllGraceful();
|
|
24991
25316
|
}
|
|
25317
|
+
try {
|
|
25318
|
+
closeAllCliSqliteConnections();
|
|
25319
|
+
} catch {
|
|
25320
|
+
}
|
|
24992
25321
|
say("Shutdown complete.");
|
|
24993
25322
|
}
|
|
24994
25323
|
|
|
24995
25324
|
// src/paths/session-layout-paths.ts
|
|
24996
|
-
import * as
|
|
25325
|
+
import * as path12 from "node:path";
|
|
24997
25326
|
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
24998
|
-
const resolved = worktreePaths.map((p) =>
|
|
25327
|
+
const resolved = worktreePaths.map((p) => path12.resolve(p)).filter(Boolean);
|
|
24999
25328
|
if (resolved.length === 0) return null;
|
|
25000
25329
|
resolved.sort();
|
|
25001
25330
|
return resolved[0];
|
|
25002
25331
|
}
|
|
25003
25332
|
function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
|
|
25004
25333
|
if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
|
|
25005
|
-
return
|
|
25334
|
+
return path12.resolve(String(resolvedSessionParentPath).trim());
|
|
25006
25335
|
}
|
|
25007
25336
|
return getBridgeRoot();
|
|
25008
25337
|
}
|
|
@@ -25011,17 +25340,17 @@ function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
|
|
|
25011
25340
|
import { execFile as execFile7 } from "node:child_process";
|
|
25012
25341
|
import { readFile, stat } from "node:fs/promises";
|
|
25013
25342
|
import { promisify as promisify7 } from "node:util";
|
|
25014
|
-
import * as
|
|
25343
|
+
import * as path15 from "node:path";
|
|
25015
25344
|
|
|
25016
25345
|
// src/git/pre-turn-snapshot.ts
|
|
25017
|
-
import * as
|
|
25018
|
-
import * as
|
|
25346
|
+
import * as fs14 from "node:fs";
|
|
25347
|
+
import * as path14 from "node:path";
|
|
25019
25348
|
import { execFile as execFile6 } from "node:child_process";
|
|
25020
25349
|
import { promisify as promisify6 } from "node:util";
|
|
25021
25350
|
|
|
25022
25351
|
// src/git/discover-repos.ts
|
|
25023
|
-
import * as
|
|
25024
|
-
import * as
|
|
25352
|
+
import * as fs13 from "node:fs";
|
|
25353
|
+
import * as path13 from "node:path";
|
|
25025
25354
|
|
|
25026
25355
|
// ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
|
|
25027
25356
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -25060,8 +25389,8 @@ function pathspec(...paths) {
|
|
|
25060
25389
|
cache.set(key, paths);
|
|
25061
25390
|
return key;
|
|
25062
25391
|
}
|
|
25063
|
-
function isPathSpec(
|
|
25064
|
-
return
|
|
25392
|
+
function isPathSpec(path39) {
|
|
25393
|
+
return path39 instanceof String && cache.has(path39);
|
|
25065
25394
|
}
|
|
25066
25395
|
function toPaths(pathSpec) {
|
|
25067
25396
|
return cache.get(pathSpec) || [];
|
|
@@ -25150,8 +25479,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
25150
25479
|
function forEachLineWithContent(input, callback) {
|
|
25151
25480
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
25152
25481
|
}
|
|
25153
|
-
function folderExists(
|
|
25154
|
-
return (0, import_file_exists.exists)(
|
|
25482
|
+
function folderExists(path39) {
|
|
25483
|
+
return (0, import_file_exists.exists)(path39, import_file_exists.FOLDER);
|
|
25155
25484
|
}
|
|
25156
25485
|
function append(target, item) {
|
|
25157
25486
|
if (Array.isArray(target)) {
|
|
@@ -25555,8 +25884,8 @@ function checkIsRepoRootTask() {
|
|
|
25555
25884
|
commands,
|
|
25556
25885
|
format: "utf-8",
|
|
25557
25886
|
onError,
|
|
25558
|
-
parser(
|
|
25559
|
-
return /^\.(git)?$/.test(
|
|
25887
|
+
parser(path39) {
|
|
25888
|
+
return /^\.(git)?$/.test(path39.trim());
|
|
25560
25889
|
}
|
|
25561
25890
|
};
|
|
25562
25891
|
}
|
|
@@ -25990,11 +26319,11 @@ function parseGrep(grep) {
|
|
|
25990
26319
|
const paths = /* @__PURE__ */ new Set();
|
|
25991
26320
|
const results = {};
|
|
25992
26321
|
forEachLineWithContent(grep, (input) => {
|
|
25993
|
-
const [
|
|
25994
|
-
paths.add(
|
|
25995
|
-
(results[
|
|
26322
|
+
const [path39, line, preview] = input.split(NULL);
|
|
26323
|
+
paths.add(path39);
|
|
26324
|
+
(results[path39] = results[path39] || []).push({
|
|
25996
26325
|
line: asNumber(line),
|
|
25997
|
-
path:
|
|
26326
|
+
path: path39,
|
|
25998
26327
|
preview
|
|
25999
26328
|
});
|
|
26000
26329
|
});
|
|
@@ -26759,14 +27088,14 @@ var init_hash_object = __esm2({
|
|
|
26759
27088
|
init_task();
|
|
26760
27089
|
}
|
|
26761
27090
|
});
|
|
26762
|
-
function parseInit(bare,
|
|
27091
|
+
function parseInit(bare, path39, text) {
|
|
26763
27092
|
const response = String(text).trim();
|
|
26764
27093
|
let result;
|
|
26765
27094
|
if (result = initResponseRegex.exec(response)) {
|
|
26766
|
-
return new InitSummary(bare,
|
|
27095
|
+
return new InitSummary(bare, path39, false, result[1]);
|
|
26767
27096
|
}
|
|
26768
27097
|
if (result = reInitResponseRegex.exec(response)) {
|
|
26769
|
-
return new InitSummary(bare,
|
|
27098
|
+
return new InitSummary(bare, path39, true, result[1]);
|
|
26770
27099
|
}
|
|
26771
27100
|
let gitDir = "";
|
|
26772
27101
|
const tokens = response.split(" ");
|
|
@@ -26777,7 +27106,7 @@ function parseInit(bare, path35, text) {
|
|
|
26777
27106
|
break;
|
|
26778
27107
|
}
|
|
26779
27108
|
}
|
|
26780
|
-
return new InitSummary(bare,
|
|
27109
|
+
return new InitSummary(bare, path39, /^re/i.test(response), gitDir);
|
|
26781
27110
|
}
|
|
26782
27111
|
var InitSummary;
|
|
26783
27112
|
var initResponseRegex;
|
|
@@ -26786,9 +27115,9 @@ var init_InitSummary = __esm2({
|
|
|
26786
27115
|
"src/lib/responses/InitSummary.ts"() {
|
|
26787
27116
|
"use strict";
|
|
26788
27117
|
InitSummary = class {
|
|
26789
|
-
constructor(bare,
|
|
27118
|
+
constructor(bare, path39, existing, gitDir) {
|
|
26790
27119
|
this.bare = bare;
|
|
26791
|
-
this.path =
|
|
27120
|
+
this.path = path39;
|
|
26792
27121
|
this.existing = existing;
|
|
26793
27122
|
this.gitDir = gitDir;
|
|
26794
27123
|
}
|
|
@@ -26800,7 +27129,7 @@ var init_InitSummary = __esm2({
|
|
|
26800
27129
|
function hasBareCommand(command) {
|
|
26801
27130
|
return command.includes(bareCommand);
|
|
26802
27131
|
}
|
|
26803
|
-
function initTask(bare = false,
|
|
27132
|
+
function initTask(bare = false, path39, customArgs) {
|
|
26804
27133
|
const commands = ["init", ...customArgs];
|
|
26805
27134
|
if (bare && !hasBareCommand(commands)) {
|
|
26806
27135
|
commands.splice(1, 0, bareCommand);
|
|
@@ -26809,7 +27138,7 @@ function initTask(bare = false, path35, customArgs) {
|
|
|
26809
27138
|
commands,
|
|
26810
27139
|
format: "utf-8",
|
|
26811
27140
|
parser(text) {
|
|
26812
|
-
return parseInit(commands.includes("--bare"),
|
|
27141
|
+
return parseInit(commands.includes("--bare"), path39, text);
|
|
26813
27142
|
}
|
|
26814
27143
|
};
|
|
26815
27144
|
}
|
|
@@ -27625,12 +27954,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
27625
27954
|
"use strict";
|
|
27626
27955
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
27627
27956
|
FileStatusSummary = class {
|
|
27628
|
-
constructor(
|
|
27629
|
-
this.path =
|
|
27957
|
+
constructor(path39, index, working_dir) {
|
|
27958
|
+
this.path = path39;
|
|
27630
27959
|
this.index = index;
|
|
27631
27960
|
this.working_dir = working_dir;
|
|
27632
27961
|
if (index === "R" || working_dir === "R") {
|
|
27633
|
-
const detail = fromPathRegex.exec(
|
|
27962
|
+
const detail = fromPathRegex.exec(path39) || [null, path39, path39];
|
|
27634
27963
|
this.from = detail[2] || "";
|
|
27635
27964
|
this.path = detail[1] || "";
|
|
27636
27965
|
}
|
|
@@ -27661,14 +27990,14 @@ function splitLine(result, lineStr) {
|
|
|
27661
27990
|
default:
|
|
27662
27991
|
return;
|
|
27663
27992
|
}
|
|
27664
|
-
function data(index, workingDir,
|
|
27993
|
+
function data(index, workingDir, path39) {
|
|
27665
27994
|
const raw = `${index}${workingDir}`;
|
|
27666
27995
|
const handler = parsers6.get(raw);
|
|
27667
27996
|
if (handler) {
|
|
27668
|
-
handler(result,
|
|
27997
|
+
handler(result, path39);
|
|
27669
27998
|
}
|
|
27670
27999
|
if (raw !== "##" && raw !== "!!") {
|
|
27671
|
-
result.files.push(new FileStatusSummary(
|
|
28000
|
+
result.files.push(new FileStatusSummary(path39, index, workingDir));
|
|
27672
28001
|
}
|
|
27673
28002
|
}
|
|
27674
28003
|
}
|
|
@@ -27941,15 +28270,15 @@ var init_simple_git_api = __esm2({
|
|
|
27941
28270
|
this._executor = _executor;
|
|
27942
28271
|
}
|
|
27943
28272
|
_runTask(task, then) {
|
|
27944
|
-
const
|
|
27945
|
-
const promise2 =
|
|
28273
|
+
const chain2 = this._executor.chain();
|
|
28274
|
+
const promise2 = chain2.push(task);
|
|
27946
28275
|
if (then) {
|
|
27947
28276
|
taskCallback(task, promise2, then);
|
|
27948
28277
|
}
|
|
27949
28278
|
return Object.create(this, {
|
|
27950
28279
|
then: { value: promise2.then.bind(promise2) },
|
|
27951
28280
|
catch: { value: promise2.catch.bind(promise2) },
|
|
27952
|
-
_executor: { value:
|
|
28281
|
+
_executor: { value: chain2 }
|
|
27953
28282
|
});
|
|
27954
28283
|
}
|
|
27955
28284
|
add(files) {
|
|
@@ -27977,9 +28306,9 @@ var init_simple_git_api = __esm2({
|
|
|
27977
28306
|
next
|
|
27978
28307
|
);
|
|
27979
28308
|
}
|
|
27980
|
-
hashObject(
|
|
28309
|
+
hashObject(path39, write) {
|
|
27981
28310
|
return this._runTask(
|
|
27982
|
-
hashObjectTask(
|
|
28311
|
+
hashObjectTask(path39, write === true),
|
|
27983
28312
|
trailingFunctionArgument(arguments)
|
|
27984
28313
|
);
|
|
27985
28314
|
}
|
|
@@ -28332,8 +28661,8 @@ var init_branch = __esm2({
|
|
|
28332
28661
|
}
|
|
28333
28662
|
});
|
|
28334
28663
|
function toPath(input) {
|
|
28335
|
-
const
|
|
28336
|
-
return
|
|
28664
|
+
const path39 = input.trim().replace(/^["']|["']$/g, "");
|
|
28665
|
+
return path39 && normalize2(path39);
|
|
28337
28666
|
}
|
|
28338
28667
|
var parseCheckIgnore;
|
|
28339
28668
|
var init_CheckIgnore = __esm2({
|
|
@@ -28647,8 +28976,8 @@ __export2(sub_module_exports, {
|
|
|
28647
28976
|
subModuleTask: () => subModuleTask,
|
|
28648
28977
|
updateSubModuleTask: () => updateSubModuleTask
|
|
28649
28978
|
});
|
|
28650
|
-
function addSubModuleTask(repo,
|
|
28651
|
-
return subModuleTask(["add", repo,
|
|
28979
|
+
function addSubModuleTask(repo, path39) {
|
|
28980
|
+
return subModuleTask(["add", repo, path39]);
|
|
28652
28981
|
}
|
|
28653
28982
|
function initSubModuleTask(customArgs) {
|
|
28654
28983
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -28981,8 +29310,8 @@ var require_git = __commonJS2({
|
|
|
28981
29310
|
}
|
|
28982
29311
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
28983
29312
|
};
|
|
28984
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
28985
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
29313
|
+
Git2.prototype.submoduleAdd = function(repo, path39, then) {
|
|
29314
|
+
return this._runTask(addSubModuleTask2(repo, path39), trailingFunctionArgument2(arguments));
|
|
28986
29315
|
};
|
|
28987
29316
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
28988
29317
|
return this._runTask(
|
|
@@ -29626,20 +29955,20 @@ async function isGitRepoDirectory(dirPath) {
|
|
|
29626
29955
|
// src/git/discover-repos.ts
|
|
29627
29956
|
async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
29628
29957
|
const result = [];
|
|
29629
|
-
const cwdResolved =
|
|
29958
|
+
const cwdResolved = path13.resolve(cwd);
|
|
29630
29959
|
if (await isGitRepoDirectory(cwdResolved)) {
|
|
29631
29960
|
const remoteUrl = await getRemoteOriginUrl(cwdResolved);
|
|
29632
29961
|
result.push({ absolutePath: cwdResolved, remoteUrl });
|
|
29633
29962
|
}
|
|
29634
29963
|
let entries;
|
|
29635
29964
|
try {
|
|
29636
|
-
entries =
|
|
29965
|
+
entries = fs13.readdirSync(cwdResolved, { withFileTypes: true });
|
|
29637
29966
|
} catch {
|
|
29638
29967
|
return result;
|
|
29639
29968
|
}
|
|
29640
29969
|
for (const ent of entries) {
|
|
29641
29970
|
if (!ent.isDirectory()) continue;
|
|
29642
|
-
const childPath =
|
|
29971
|
+
const childPath = path13.join(cwdResolved, ent.name);
|
|
29643
29972
|
if (await isGitRepoDirectory(childPath)) {
|
|
29644
29973
|
const remoteUrl = await getRemoteOriginUrl(childPath);
|
|
29645
29974
|
result.push({ absolutePath: childPath, remoteUrl });
|
|
@@ -29648,22 +29977,22 @@ async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
|
29648
29977
|
return result;
|
|
29649
29978
|
}
|
|
29650
29979
|
async function discoverGitReposUnderRoot(rootPath) {
|
|
29651
|
-
const root =
|
|
29980
|
+
const root = path13.resolve(rootPath);
|
|
29652
29981
|
const roots = [];
|
|
29653
29982
|
async function walk(dir) {
|
|
29654
29983
|
if (await isGitRepoDirectory(dir)) {
|
|
29655
|
-
roots.push(
|
|
29984
|
+
roots.push(path13.resolve(dir));
|
|
29656
29985
|
return;
|
|
29657
29986
|
}
|
|
29658
29987
|
let entries;
|
|
29659
29988
|
try {
|
|
29660
|
-
entries =
|
|
29989
|
+
entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
29661
29990
|
} catch {
|
|
29662
29991
|
return;
|
|
29663
29992
|
}
|
|
29664
29993
|
for (const ent of entries) {
|
|
29665
29994
|
if (!ent.isDirectory() || ent.name === ".git") continue;
|
|
29666
|
-
await walk(
|
|
29995
|
+
await walk(path13.join(dir, ent.name));
|
|
29667
29996
|
}
|
|
29668
29997
|
}
|
|
29669
29998
|
await walk(root);
|
|
@@ -29679,7 +30008,7 @@ async function discoverGitReposUnderRoot(rootPath) {
|
|
|
29679
30008
|
// src/git/pre-turn-snapshot.ts
|
|
29680
30009
|
var execFileAsync5 = promisify6(execFile6);
|
|
29681
30010
|
function snapshotsDirForCwd(agentCwd) {
|
|
29682
|
-
return
|
|
30011
|
+
return path14.join(agentCwd, ".buildautomaton", "snapshots");
|
|
29683
30012
|
}
|
|
29684
30013
|
async function gitStashCreate(repoRoot, log2) {
|
|
29685
30014
|
try {
|
|
@@ -29708,7 +30037,7 @@ async function gitRun(repoRoot, args, log2, label) {
|
|
|
29708
30037
|
async function resolveSnapshotRepoRoots(options) {
|
|
29709
30038
|
const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
|
|
29710
30039
|
if (worktreePaths?.length) {
|
|
29711
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
30040
|
+
const uniq = [...new Set(worktreePaths.map((p) => path14.resolve(p)))];
|
|
29712
30041
|
return uniq;
|
|
29713
30042
|
}
|
|
29714
30043
|
try {
|
|
@@ -29716,7 +30045,7 @@ async function resolveSnapshotRepoRoots(options) {
|
|
|
29716
30045
|
const mapped = repos.map((r) => r.absolutePath);
|
|
29717
30046
|
const sid = sessionId?.trim();
|
|
29718
30047
|
if (sid) {
|
|
29719
|
-
const filtered = mapped.filter((root) =>
|
|
30048
|
+
const filtered = mapped.filter((root) => path14.basename(root) === sid);
|
|
29720
30049
|
if (filtered.length > 0) return filtered;
|
|
29721
30050
|
}
|
|
29722
30051
|
return mapped;
|
|
@@ -29737,7 +30066,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
29737
30066
|
}
|
|
29738
30067
|
const dir = snapshotsDirForCwd(agentCwd);
|
|
29739
30068
|
try {
|
|
29740
|
-
|
|
30069
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
29741
30070
|
} catch (e) {
|
|
29742
30071
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
29743
30072
|
}
|
|
@@ -29746,9 +30075,9 @@ async function capturePreTurnSnapshot(options) {
|
|
|
29746
30075
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29747
30076
|
repos
|
|
29748
30077
|
};
|
|
29749
|
-
const filePath =
|
|
30078
|
+
const filePath = path14.join(dir, `${runId}.json`);
|
|
29750
30079
|
try {
|
|
29751
|
-
|
|
30080
|
+
fs14.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
29752
30081
|
} catch (e) {
|
|
29753
30082
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
29754
30083
|
}
|
|
@@ -29761,7 +30090,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
29761
30090
|
async function applyPreTurnSnapshot(filePath, log2) {
|
|
29762
30091
|
let data;
|
|
29763
30092
|
try {
|
|
29764
|
-
const raw =
|
|
30093
|
+
const raw = fs14.readFileSync(filePath, "utf8");
|
|
29765
30094
|
data = JSON.parse(raw);
|
|
29766
30095
|
} catch (e) {
|
|
29767
30096
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
@@ -29784,7 +30113,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
|
|
|
29784
30113
|
return { ok: true };
|
|
29785
30114
|
}
|
|
29786
30115
|
function snapshotFilePath(agentCwd, runId) {
|
|
29787
|
-
return
|
|
30116
|
+
return path14.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
|
|
29788
30117
|
}
|
|
29789
30118
|
|
|
29790
30119
|
// src/git/session-git-queue.ts
|
|
@@ -29833,7 +30162,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
29833
30162
|
continue;
|
|
29834
30163
|
}
|
|
29835
30164
|
const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
29836
|
-
const slug =
|
|
30165
|
+
const slug = path15.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
|
|
29837
30166
|
for (const rel of lines) {
|
|
29838
30167
|
if (rel.includes("..")) continue;
|
|
29839
30168
|
try {
|
|
@@ -29847,7 +30176,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
29847
30176
|
);
|
|
29848
30177
|
if (!patchContent.trim()) continue;
|
|
29849
30178
|
const displayPath = multiRepo ? `${slug}/${rel}` : rel;
|
|
29850
|
-
const workspaceFilePath =
|
|
30179
|
+
const workspaceFilePath = path15.join(repo.path, rel);
|
|
29851
30180
|
const newText = await readWorkspaceFileAsUtf8(workspaceFilePath);
|
|
29852
30181
|
sendSessionUpdate({
|
|
29853
30182
|
type: "session_file_change",
|
|
@@ -29869,9 +30198,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
29869
30198
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
29870
30199
|
async function putEncryptedChangeSummaryRows(params) {
|
|
29871
30200
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
29872
|
-
const entries = params.rows.map(({ path:
|
|
30201
|
+
const entries = params.rows.map(({ path: path39, summary }) => {
|
|
29873
30202
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
29874
|
-
return { path:
|
|
30203
|
+
return { path: path39, summary: JSON.stringify(enc) };
|
|
29875
30204
|
});
|
|
29876
30205
|
const res = await fetch(
|
|
29877
30206
|
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -30208,8 +30537,8 @@ async function sendPromptToAgent(options) {
|
|
|
30208
30537
|
}
|
|
30209
30538
|
|
|
30210
30539
|
// src/agents/acp/ensure-acp-client.ts
|
|
30211
|
-
import * as
|
|
30212
|
-
import * as
|
|
30540
|
+
import * as fs15 from "node:fs";
|
|
30541
|
+
import * as path18 from "node:path";
|
|
30213
30542
|
|
|
30214
30543
|
// src/error-message.ts
|
|
30215
30544
|
function errorMessage(err) {
|
|
@@ -30711,20 +31040,20 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
30711
31040
|
|
|
30712
31041
|
// src/agents/acp/session-file-change-path-kind.ts
|
|
30713
31042
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
30714
|
-
import { existsSync, statSync } from "node:fs";
|
|
31043
|
+
import { existsSync as existsSync2, statSync } from "node:fs";
|
|
30715
31044
|
|
|
30716
31045
|
// src/git/get-git-repo-root-sync.ts
|
|
30717
31046
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
30718
|
-
import * as
|
|
31047
|
+
import * as path16 from "node:path";
|
|
30719
31048
|
function getGitRepoRootSync(startDir) {
|
|
30720
31049
|
try {
|
|
30721
31050
|
const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
30722
|
-
cwd:
|
|
31051
|
+
cwd: path16.resolve(startDir),
|
|
30723
31052
|
encoding: "utf8",
|
|
30724
31053
|
stdio: ["ignore", "pipe", "ignore"],
|
|
30725
31054
|
maxBuffer: 1024 * 1024
|
|
30726
31055
|
}).trim();
|
|
30727
|
-
return out ?
|
|
31056
|
+
return out ? path16.resolve(out) : null;
|
|
30728
31057
|
} catch {
|
|
30729
31058
|
return null;
|
|
30730
31059
|
}
|
|
@@ -30732,26 +31061,26 @@ function getGitRepoRootSync(startDir) {
|
|
|
30732
31061
|
|
|
30733
31062
|
// src/agents/acp/workspace-files.ts
|
|
30734
31063
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
30735
|
-
import { readFileSync as
|
|
30736
|
-
import * as
|
|
31064
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
31065
|
+
import * as path17 from "node:path";
|
|
30737
31066
|
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
30738
31067
|
const trimmed2 = rawPath.trim();
|
|
30739
31068
|
if (!trimmed2) return null;
|
|
30740
|
-
const normalizedSessionParent =
|
|
31069
|
+
const normalizedSessionParent = path17.resolve(sessionParentPath);
|
|
30741
31070
|
let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
|
|
30742
31071
|
if (!resolvedPath) {
|
|
30743
|
-
const candidate =
|
|
31072
|
+
const candidate = path17.isAbsolute(trimmed2) ? path17.normalize(trimmed2) : path17.normalize(path17.resolve(normalizedSessionParent, trimmed2));
|
|
30744
31073
|
const gitRoot2 = getGitRepoRootSync(sessionParentPath);
|
|
30745
31074
|
if (!gitRoot2) return null;
|
|
30746
|
-
const rel =
|
|
30747
|
-
if (rel.startsWith("..") ||
|
|
31075
|
+
const rel = path17.relative(gitRoot2, candidate);
|
|
31076
|
+
if (rel.startsWith("..") || path17.isAbsolute(rel)) return null;
|
|
30748
31077
|
resolvedPath = candidate;
|
|
30749
31078
|
}
|
|
30750
31079
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30751
31080
|
if (gitRoot) {
|
|
30752
|
-
const relFromRoot =
|
|
30753
|
-
if (!relFromRoot.startsWith("..") && !
|
|
30754
|
-
return { resolvedPath, display: relFromRoot.split(
|
|
31081
|
+
const relFromRoot = path17.relative(gitRoot, resolvedPath);
|
|
31082
|
+
if (!relFromRoot.startsWith("..") && !path17.isAbsolute(relFromRoot)) {
|
|
31083
|
+
return { resolvedPath, display: relFromRoot.split(path17.sep).join("/") };
|
|
30755
31084
|
}
|
|
30756
31085
|
}
|
|
30757
31086
|
return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
|
|
@@ -30760,11 +31089,11 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
30760
31089
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
30761
31090
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30762
31091
|
if (gitRoot) {
|
|
30763
|
-
const resolvedPath2 =
|
|
30764
|
-
const rel =
|
|
30765
|
-
if (!rel.startsWith("..") && !
|
|
31092
|
+
const resolvedPath2 = path17.resolve(gitRoot, displayPath);
|
|
31093
|
+
const rel = path17.relative(gitRoot, resolvedPath2);
|
|
31094
|
+
if (!rel.startsWith("..") && !path17.isAbsolute(rel)) {
|
|
30766
31095
|
try {
|
|
30767
|
-
return
|
|
31096
|
+
return readFileSync4(resolvedPath2, "utf8");
|
|
30768
31097
|
} catch {
|
|
30769
31098
|
}
|
|
30770
31099
|
}
|
|
@@ -30772,7 +31101,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
30772
31101
|
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
30773
31102
|
if (!resolvedPath) return "";
|
|
30774
31103
|
try {
|
|
30775
|
-
return
|
|
31104
|
+
return readFileSync4(resolvedPath, "utf8");
|
|
30776
31105
|
} catch {
|
|
30777
31106
|
return "";
|
|
30778
31107
|
}
|
|
@@ -30781,9 +31110,9 @@ function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
|
|
|
30781
31110
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
30782
31111
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30783
31112
|
if (gitRoot) {
|
|
30784
|
-
const resolvedPath =
|
|
30785
|
-
const rel =
|
|
30786
|
-
if (!rel.startsWith("..") && !
|
|
31113
|
+
const resolvedPath = path17.resolve(gitRoot, displayPath);
|
|
31114
|
+
const rel = path17.relative(gitRoot, resolvedPath);
|
|
31115
|
+
if (!rel.startsWith("..") && !path17.isAbsolute(rel)) return resolvedPath;
|
|
30787
31116
|
}
|
|
30788
31117
|
return resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
30789
31118
|
}
|
|
@@ -30818,7 +31147,7 @@ function gitHeadPathObjectType(sessionParentPath, displayPath) {
|
|
|
30818
31147
|
}
|
|
30819
31148
|
function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
|
|
30820
31149
|
const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
|
|
30821
|
-
if (resolvedPath &&
|
|
31150
|
+
if (resolvedPath && existsSync2(resolvedPath)) {
|
|
30822
31151
|
try {
|
|
30823
31152
|
if (statSync(resolvedPath).isDirectory()) {
|
|
30824
31153
|
return { isDirectory: true, directoryRemoved: false };
|
|
@@ -30918,7 +31247,7 @@ function createBridgeOnRequest(opts) {
|
|
|
30918
31247
|
}
|
|
30919
31248
|
|
|
30920
31249
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
|
|
30921
|
-
import { fileURLToPath as
|
|
31250
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
30922
31251
|
function readOptionalTextField(v) {
|
|
30923
31252
|
if (v === null || v === void 0) return "";
|
|
30924
31253
|
if (typeof v === "string") return v;
|
|
@@ -30928,7 +31257,7 @@ function normalizePathField(raw) {
|
|
|
30928
31257
|
const t = raw.trim();
|
|
30929
31258
|
if (t.startsWith("file://")) {
|
|
30930
31259
|
try {
|
|
30931
|
-
return
|
|
31260
|
+
return fileURLToPath3(t);
|
|
30932
31261
|
} catch {
|
|
30933
31262
|
return t;
|
|
30934
31263
|
}
|
|
@@ -31386,29 +31715,34 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
31386
31715
|
}
|
|
31387
31716
|
|
|
31388
31717
|
// src/agents/acp/local-agent-session-file.ts
|
|
31389
|
-
|
|
31390
|
-
import os3 from "node:os";
|
|
31391
|
-
import path11 from "node:path";
|
|
31392
|
-
var LOCAL_AGENT_SESSION_DIR = path11.join(os3.homedir(), ".buildautomaton", "agent-sessions");
|
|
31393
|
-
function safeFileSlug(cloudSessionId) {
|
|
31718
|
+
function sessionKeyForCloudSessionId(cloudSessionId) {
|
|
31394
31719
|
const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
|
|
31395
31720
|
return t.length > 0 ? t : "session";
|
|
31396
31721
|
}
|
|
31397
|
-
function localAgentSessionFilePath(cloudSessionId) {
|
|
31398
|
-
return path11.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
|
|
31399
|
-
}
|
|
31400
31722
|
function readLocalAgentSessionFile(cloudSessionId) {
|
|
31401
31723
|
try {
|
|
31402
|
-
const
|
|
31403
|
-
const
|
|
31404
|
-
const
|
|
31405
|
-
|
|
31724
|
+
const db = getCliDatabase();
|
|
31725
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
31726
|
+
const row = db.get(
|
|
31727
|
+
"SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
|
|
31728
|
+
[key]
|
|
31729
|
+
);
|
|
31730
|
+
if (!row) return null;
|
|
31731
|
+
let configOptions = null;
|
|
31732
|
+
if (row.config_options_json != null && row.config_options_json !== "") {
|
|
31733
|
+
try {
|
|
31734
|
+
const parsed = JSON.parse(row.config_options_json);
|
|
31735
|
+
configOptions = Array.isArray(parsed) ? parsed : null;
|
|
31736
|
+
} catch {
|
|
31737
|
+
configOptions = null;
|
|
31738
|
+
}
|
|
31739
|
+
}
|
|
31406
31740
|
return {
|
|
31407
31741
|
v: 1,
|
|
31408
|
-
acpSessionId:
|
|
31409
|
-
backendAgentType:
|
|
31410
|
-
configOptions
|
|
31411
|
-
updatedAt:
|
|
31742
|
+
acpSessionId: row.acp_session_id,
|
|
31743
|
+
backendAgentType: row.backend_agent_type,
|
|
31744
|
+
configOptions,
|
|
31745
|
+
updatedAt: row.updated_at
|
|
31412
31746
|
};
|
|
31413
31747
|
} catch {
|
|
31414
31748
|
return null;
|
|
@@ -31416,9 +31750,8 @@ function readLocalAgentSessionFile(cloudSessionId) {
|
|
|
31416
31750
|
}
|
|
31417
31751
|
function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
31418
31752
|
try {
|
|
31419
|
-
const
|
|
31420
|
-
|
|
31421
|
-
const p = localAgentSessionFilePath(cloudSessionId);
|
|
31753
|
+
const db = getCliDatabase();
|
|
31754
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
31422
31755
|
const prev = readLocalAgentSessionFile(cloudSessionId);
|
|
31423
31756
|
const next = {
|
|
31424
31757
|
v: 1,
|
|
@@ -31427,7 +31760,17 @@ function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
|
31427
31760
|
configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
|
|
31428
31761
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
31429
31762
|
};
|
|
31430
|
-
|
|
31763
|
+
const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
|
|
31764
|
+
db.run(
|
|
31765
|
+
`INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
|
|
31766
|
+
VALUES (?, ?, ?, ?, ?)
|
|
31767
|
+
ON CONFLICT(session_key) DO UPDATE SET
|
|
31768
|
+
acp_session_id = excluded.acp_session_id,
|
|
31769
|
+
backend_agent_type = excluded.backend_agent_type,
|
|
31770
|
+
config_options_json = excluded.config_options_json,
|
|
31771
|
+
updated_at = excluded.updated_at`,
|
|
31772
|
+
[key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
|
|
31773
|
+
);
|
|
31431
31774
|
} catch {
|
|
31432
31775
|
}
|
|
31433
31776
|
}
|
|
@@ -31451,7 +31794,7 @@ async function ensureAcpClient(options) {
|
|
|
31451
31794
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
31452
31795
|
await state.acpStartPromise;
|
|
31453
31796
|
}
|
|
31454
|
-
if (state.acpHandle && state.lastAcpCwd != null &&
|
|
31797
|
+
if (state.acpHandle && state.lastAcpCwd != null && path18.resolve(state.lastAcpCwd) !== path18.resolve(targetSessionParentPath)) {
|
|
31455
31798
|
try {
|
|
31456
31799
|
state.acpHandle.disconnect();
|
|
31457
31800
|
} catch {
|
|
@@ -31486,7 +31829,7 @@ async function ensureAcpClient(options) {
|
|
|
31486
31829
|
if (!state.acpStartPromise) {
|
|
31487
31830
|
let statOk = false;
|
|
31488
31831
|
try {
|
|
31489
|
-
const st =
|
|
31832
|
+
const st = fs15.statSync(targetSessionParentPath);
|
|
31490
31833
|
statOk = st.isDirectory();
|
|
31491
31834
|
if (!statOk) {
|
|
31492
31835
|
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
@@ -31733,12 +32076,12 @@ async function createAcpManager(options) {
|
|
|
31733
32076
|
}
|
|
31734
32077
|
|
|
31735
32078
|
// src/worktrees/session-worktree-manager.ts
|
|
31736
|
-
import * as
|
|
31737
|
-
import
|
|
32079
|
+
import * as path25 from "node:path";
|
|
32080
|
+
import os8 from "node:os";
|
|
31738
32081
|
|
|
31739
32082
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
31740
|
-
import * as
|
|
31741
|
-
import * as
|
|
32083
|
+
import * as fs17 from "node:fs";
|
|
32084
|
+
import * as path20 from "node:path";
|
|
31742
32085
|
|
|
31743
32086
|
// src/git/worktree-add.ts
|
|
31744
32087
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -31747,12 +32090,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
31747
32090
|
}
|
|
31748
32091
|
|
|
31749
32092
|
// src/worktrees/worktree-layout-file.ts
|
|
31750
|
-
import * as
|
|
31751
|
-
import * as
|
|
31752
|
-
import
|
|
32093
|
+
import * as fs16 from "node:fs";
|
|
32094
|
+
import * as path19 from "node:path";
|
|
32095
|
+
import os7 from "node:os";
|
|
31753
32096
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
31754
32097
|
function defaultWorktreeLayoutPath() {
|
|
31755
|
-
return
|
|
32098
|
+
return path19.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
31756
32099
|
}
|
|
31757
32100
|
function normalizeLoadedLayout(raw) {
|
|
31758
32101
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -31764,8 +32107,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
31764
32107
|
function loadWorktreeLayout() {
|
|
31765
32108
|
try {
|
|
31766
32109
|
const p = defaultWorktreeLayoutPath();
|
|
31767
|
-
if (!
|
|
31768
|
-
const raw = JSON.parse(
|
|
32110
|
+
if (!fs16.existsSync(p)) return { launcherCwds: [] };
|
|
32111
|
+
const raw = JSON.parse(fs16.readFileSync(p, "utf8"));
|
|
31769
32112
|
return normalizeLoadedLayout(raw);
|
|
31770
32113
|
} catch {
|
|
31771
32114
|
return { launcherCwds: [] };
|
|
@@ -31773,24 +32116,24 @@ function loadWorktreeLayout() {
|
|
|
31773
32116
|
}
|
|
31774
32117
|
function saveWorktreeLayout(layout) {
|
|
31775
32118
|
try {
|
|
31776
|
-
const dir =
|
|
31777
|
-
|
|
31778
|
-
|
|
32119
|
+
const dir = path19.dirname(defaultWorktreeLayoutPath());
|
|
32120
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
32121
|
+
fs16.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
31779
32122
|
} catch {
|
|
31780
32123
|
}
|
|
31781
32124
|
}
|
|
31782
32125
|
function baseNameSafe(pathString) {
|
|
31783
|
-
return
|
|
32126
|
+
return path19.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
31784
32127
|
}
|
|
31785
32128
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
31786
|
-
const norm =
|
|
31787
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
32129
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
32130
|
+
const existing = layout.launcherCwds.find((e) => path19.resolve(e.absolutePath) === norm);
|
|
31788
32131
|
return existing?.dirName;
|
|
31789
32132
|
}
|
|
31790
32133
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
31791
32134
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
31792
32135
|
if (existing) return existing;
|
|
31793
|
-
const norm =
|
|
32136
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
31794
32137
|
const base = baseNameSafe(norm);
|
|
31795
32138
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
31796
32139
|
let name = base;
|
|
@@ -31807,10 +32150,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
31807
32150
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
31808
32151
|
async function prepareNewSessionWorktrees(options) {
|
|
31809
32152
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
31810
|
-
const bridgeResolved =
|
|
32153
|
+
const bridgeResolved = path20.resolve(bridgeRoot);
|
|
31811
32154
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
31812
|
-
const bridgeKeyDir =
|
|
31813
|
-
const sessionDir =
|
|
32155
|
+
const bridgeKeyDir = path20.join(worktreesRootPath, cwdKey);
|
|
32156
|
+
const sessionDir = path20.join(bridgeKeyDir, sessionId);
|
|
31814
32157
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
31815
32158
|
if (repos.length === 0) {
|
|
31816
32159
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -31818,14 +32161,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
31818
32161
|
}
|
|
31819
32162
|
const branch = `session-${sessionId}`;
|
|
31820
32163
|
const worktreePaths = [];
|
|
31821
|
-
|
|
32164
|
+
fs17.mkdirSync(sessionDir, { recursive: true });
|
|
31822
32165
|
for (const repo of repos) {
|
|
31823
|
-
let rel =
|
|
31824
|
-
if (rel.startsWith("..") ||
|
|
32166
|
+
let rel = path20.relative(bridgeResolved, repo.absolutePath);
|
|
32167
|
+
if (rel.startsWith("..") || path20.isAbsolute(rel)) continue;
|
|
31825
32168
|
const relNorm = rel === "" ? "." : rel;
|
|
31826
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
32169
|
+
const wtPath = relNorm === "." ? sessionDir : path20.join(sessionDir, relNorm);
|
|
31827
32170
|
if (relNorm !== ".") {
|
|
31828
|
-
|
|
32171
|
+
fs17.mkdirSync(path20.dirname(wtPath), { recursive: true });
|
|
31829
32172
|
}
|
|
31830
32173
|
try {
|
|
31831
32174
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
@@ -31867,23 +32210,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
31867
32210
|
}
|
|
31868
32211
|
|
|
31869
32212
|
// src/worktrees/remove-session-worktrees.ts
|
|
31870
|
-
import * as
|
|
32213
|
+
import * as fs20 from "node:fs";
|
|
31871
32214
|
|
|
31872
32215
|
// src/git/worktree-remove.ts
|
|
31873
|
-
import * as
|
|
32216
|
+
import * as fs19 from "node:fs";
|
|
31874
32217
|
|
|
31875
32218
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
31876
|
-
import * as
|
|
31877
|
-
import * as
|
|
32219
|
+
import * as fs18 from "node:fs";
|
|
32220
|
+
import * as path21 from "node:path";
|
|
31878
32221
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
31879
|
-
const gitDirFile =
|
|
31880
|
-
if (!
|
|
31881
|
-
const first2 =
|
|
32222
|
+
const gitDirFile = path21.join(wt, ".git");
|
|
32223
|
+
if (!fs18.existsSync(gitDirFile) || !fs18.statSync(gitDirFile).isFile()) return "";
|
|
32224
|
+
const first2 = fs18.readFileSync(gitDirFile, "utf8").trim();
|
|
31882
32225
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
31883
32226
|
if (!m) return "";
|
|
31884
|
-
const gitWorktreePath =
|
|
31885
|
-
const gitDir =
|
|
31886
|
-
return
|
|
32227
|
+
const gitWorktreePath = path21.resolve(wt, m[1].trim());
|
|
32228
|
+
const gitDir = path21.dirname(path21.dirname(gitWorktreePath));
|
|
32229
|
+
return path21.dirname(gitDir);
|
|
31887
32230
|
}
|
|
31888
32231
|
|
|
31889
32232
|
// src/git/worktree-remove.ts
|
|
@@ -31892,7 +32235,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
31892
32235
|
if (mainRepo) {
|
|
31893
32236
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
31894
32237
|
} else {
|
|
31895
|
-
|
|
32238
|
+
fs19.rmSync(worktreePath, { recursive: true, force: true });
|
|
31896
32239
|
}
|
|
31897
32240
|
}
|
|
31898
32241
|
|
|
@@ -31905,7 +32248,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
31905
32248
|
} catch (e) {
|
|
31906
32249
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
31907
32250
|
try {
|
|
31908
|
-
|
|
32251
|
+
fs20.rmSync(wt, { recursive: true, force: true });
|
|
31909
32252
|
} catch {
|
|
31910
32253
|
}
|
|
31911
32254
|
}
|
|
@@ -32125,7 +32468,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
32125
32468
|
}
|
|
32126
32469
|
|
|
32127
32470
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
32128
|
-
import * as
|
|
32471
|
+
import * as path23 from "node:path";
|
|
32129
32472
|
|
|
32130
32473
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
32131
32474
|
function parseNameStatusLines(lines) {
|
|
@@ -32245,8 +32588,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
32245
32588
|
}
|
|
32246
32589
|
|
|
32247
32590
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
32248
|
-
import * as
|
|
32249
|
-
import * as
|
|
32591
|
+
import * as fs22 from "node:fs";
|
|
32592
|
+
import * as path22 from "node:path";
|
|
32250
32593
|
|
|
32251
32594
|
// src/git/working-directory/changes/count-lines.ts
|
|
32252
32595
|
import { createReadStream } from "node:fs";
|
|
@@ -32270,7 +32613,7 @@ async function countTextFileLines(filePath) {
|
|
|
32270
32613
|
}
|
|
32271
32614
|
|
|
32272
32615
|
// src/git/working-directory/changes/hydrate-patch.ts
|
|
32273
|
-
import * as
|
|
32616
|
+
import * as fs21 from "node:fs";
|
|
32274
32617
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
32275
32618
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
32276
32619
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -32285,7 +32628,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
32285
32628
|
}
|
|
32286
32629
|
async function readWorktreeFileLines(filePath) {
|
|
32287
32630
|
try {
|
|
32288
|
-
const raw = await
|
|
32631
|
+
const raw = await fs21.promises.readFile(filePath, "utf8");
|
|
32289
32632
|
return raw.split(/\r?\n/);
|
|
32290
32633
|
} catch {
|
|
32291
32634
|
return null;
|
|
@@ -32420,7 +32763,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
32420
32763
|
const rows = [];
|
|
32421
32764
|
for (const pathInRepo of paths) {
|
|
32422
32765
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
32423
|
-
const repoFilePath =
|
|
32766
|
+
const repoFilePath = path22.join(repoGitCwd, pathInRepo);
|
|
32424
32767
|
const nums = numByPath.get(pathInRepo);
|
|
32425
32768
|
let additions = nums?.additions ?? 0;
|
|
32426
32769
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -32433,7 +32776,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
32433
32776
|
deletions = fromGit.deletions;
|
|
32434
32777
|
} else {
|
|
32435
32778
|
try {
|
|
32436
|
-
const st = await
|
|
32779
|
+
const st = await fs22.promises.stat(repoFilePath);
|
|
32437
32780
|
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
32438
32781
|
else additions = 0;
|
|
32439
32782
|
} catch {
|
|
@@ -32459,7 +32802,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
32459
32802
|
} else {
|
|
32460
32803
|
pathInRepo = row.pathRelLauncher;
|
|
32461
32804
|
}
|
|
32462
|
-
const filePath =
|
|
32805
|
+
const filePath = path22.join(repoGitCwd, pathInRepo);
|
|
32463
32806
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
32464
32807
|
if (patch) {
|
|
32465
32808
|
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
@@ -32475,8 +32818,8 @@ function normRepoRel(p) {
|
|
|
32475
32818
|
return x === "" ? "." : x;
|
|
32476
32819
|
}
|
|
32477
32820
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
32478
|
-
const bridgeRoot =
|
|
32479
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
32821
|
+
const bridgeRoot = path23.resolve(getBridgeRoot());
|
|
32822
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path23.resolve(options.sessionWorktreeRootPath) : null;
|
|
32480
32823
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
32481
32824
|
const out = [];
|
|
32482
32825
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -32489,7 +32832,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
32489
32832
|
}
|
|
32490
32833
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
32491
32834
|
for (const target of options.commitTargetPaths) {
|
|
32492
|
-
const t =
|
|
32835
|
+
const t = path23.resolve(target);
|
|
32493
32836
|
if (!await isGitRepoDirectory(t)) continue;
|
|
32494
32837
|
const g = cliSimpleGit(t);
|
|
32495
32838
|
let branch = "HEAD";
|
|
@@ -32502,8 +32845,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
32502
32845
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
32503
32846
|
let repoRelPath;
|
|
32504
32847
|
if (sessionWtRoot) {
|
|
32505
|
-
const anchor = legacyNested ?
|
|
32506
|
-
const relNorm =
|
|
32848
|
+
const anchor = legacyNested ? path23.dirname(t) : t;
|
|
32849
|
+
const relNorm = path23.relative(sessionWtRoot, anchor);
|
|
32507
32850
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
32508
32851
|
} else {
|
|
32509
32852
|
let top = t;
|
|
@@ -32512,8 +32855,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
32512
32855
|
} catch {
|
|
32513
32856
|
top = t;
|
|
32514
32857
|
}
|
|
32515
|
-
const rel =
|
|
32516
|
-
repoRelPath = rel.startsWith("..") ?
|
|
32858
|
+
const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
|
|
32859
|
+
repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
|
|
32517
32860
|
}
|
|
32518
32861
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
32519
32862
|
if (filter && norm !== filter) continue;
|
|
@@ -32578,11 +32921,11 @@ async function commitSessionWorktrees(options) {
|
|
|
32578
32921
|
}
|
|
32579
32922
|
|
|
32580
32923
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
32581
|
-
import * as
|
|
32582
|
-
import * as
|
|
32924
|
+
import * as fs23 from "node:fs";
|
|
32925
|
+
import * as path24 from "node:path";
|
|
32583
32926
|
function isGitDir(dirPath) {
|
|
32584
32927
|
try {
|
|
32585
|
-
return
|
|
32928
|
+
return fs23.existsSync(path24.join(dirPath, ".git"));
|
|
32586
32929
|
} catch {
|
|
32587
32930
|
return false;
|
|
32588
32931
|
}
|
|
@@ -32591,23 +32934,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
32591
32934
|
const out = [];
|
|
32592
32935
|
const walk = (dir) => {
|
|
32593
32936
|
if (isGitDir(dir)) {
|
|
32594
|
-
out.push(
|
|
32937
|
+
out.push(path24.resolve(dir));
|
|
32595
32938
|
return;
|
|
32596
32939
|
}
|
|
32597
32940
|
let entries;
|
|
32598
32941
|
try {
|
|
32599
|
-
entries =
|
|
32942
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
32600
32943
|
} catch {
|
|
32601
32944
|
return;
|
|
32602
32945
|
}
|
|
32603
32946
|
for (const e of entries) {
|
|
32604
32947
|
if (e.name.startsWith(".")) continue;
|
|
32605
|
-
const full =
|
|
32948
|
+
const full = path24.join(dir, e.name);
|
|
32606
32949
|
if (!e.isDirectory()) continue;
|
|
32607
32950
|
walk(full);
|
|
32608
32951
|
}
|
|
32609
32952
|
};
|
|
32610
|
-
walk(
|
|
32953
|
+
walk(path24.resolve(rootPath));
|
|
32611
32954
|
return [...new Set(out)];
|
|
32612
32955
|
}
|
|
32613
32956
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -32616,16 +32959,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
32616
32959
|
if (depth > maxDepth) return;
|
|
32617
32960
|
let entries;
|
|
32618
32961
|
try {
|
|
32619
|
-
entries =
|
|
32962
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
32620
32963
|
} catch {
|
|
32621
32964
|
return;
|
|
32622
32965
|
}
|
|
32623
32966
|
for (const e of entries) {
|
|
32624
32967
|
if (e.name.startsWith(".")) continue;
|
|
32625
|
-
const full =
|
|
32968
|
+
const full = path24.join(dir, e.name);
|
|
32626
32969
|
if (!e.isDirectory()) continue;
|
|
32627
32970
|
if (e.name === sessionId) {
|
|
32628
|
-
if (isGitDir(full)) out.push(
|
|
32971
|
+
if (isGitDir(full)) out.push(path24.resolve(full));
|
|
32629
32972
|
} else {
|
|
32630
32973
|
walk(full, depth + 1);
|
|
32631
32974
|
}
|
|
@@ -32637,14 +32980,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
32637
32980
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
32638
32981
|
let st;
|
|
32639
32982
|
try {
|
|
32640
|
-
st =
|
|
32983
|
+
st = fs23.statSync(sessionDir);
|
|
32641
32984
|
} catch {
|
|
32642
32985
|
return null;
|
|
32643
32986
|
}
|
|
32644
32987
|
if (!st.isDirectory()) return null;
|
|
32645
32988
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
32646
32989
|
if (worktreePaths.length === 0) return null;
|
|
32647
|
-
const abs =
|
|
32990
|
+
const abs = path24.resolve(sessionDir);
|
|
32648
32991
|
return {
|
|
32649
32992
|
sessionParentPath: abs,
|
|
32650
32993
|
workingTreeRelRoot: abs,
|
|
@@ -32654,20 +32997,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
32654
32997
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
32655
32998
|
const sid = sessionId.trim();
|
|
32656
32999
|
if (!sid) return null;
|
|
32657
|
-
const hintR =
|
|
33000
|
+
const hintR = path24.resolve(checkoutPath);
|
|
32658
33001
|
let best = null;
|
|
32659
|
-
let cur =
|
|
33002
|
+
let cur = path24.dirname(hintR);
|
|
32660
33003
|
for (let i = 0; i < 40; i++) {
|
|
32661
33004
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
32662
|
-
if (paths.some((p) =>
|
|
32663
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
33005
|
+
if (paths.some((p) => path24.resolve(p) === hintR)) {
|
|
33006
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path24.resolve(paths[0]);
|
|
32664
33007
|
best = {
|
|
32665
|
-
sessionParentPath:
|
|
32666
|
-
workingTreeRelRoot:
|
|
32667
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
33008
|
+
sessionParentPath: path24.resolve(isolated),
|
|
33009
|
+
workingTreeRelRoot: path24.resolve(cur),
|
|
33010
|
+
repoCheckoutPaths: paths.map((p) => path24.resolve(p))
|
|
32668
33011
|
};
|
|
32669
33012
|
}
|
|
32670
|
-
const next =
|
|
33013
|
+
const next = path24.dirname(cur);
|
|
32671
33014
|
if (next === cur) break;
|
|
32672
33015
|
cur = next;
|
|
32673
33016
|
}
|
|
@@ -32675,33 +33018,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
32675
33018
|
}
|
|
32676
33019
|
function discoverSessionWorktreeOnDisk(options) {
|
|
32677
33020
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
32678
|
-
if (!sessionId.trim() || !
|
|
33021
|
+
if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
|
|
32679
33022
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
32680
33023
|
const keys = [];
|
|
32681
33024
|
if (preferredKey) keys.push(preferredKey);
|
|
32682
33025
|
try {
|
|
32683
|
-
for (const name of
|
|
33026
|
+
for (const name of fs23.readdirSync(worktreesRootPath)) {
|
|
32684
33027
|
if (name.startsWith(".")) continue;
|
|
32685
|
-
const p =
|
|
32686
|
-
if (!
|
|
33028
|
+
const p = path24.join(worktreesRootPath, name);
|
|
33029
|
+
if (!fs23.statSync(p).isDirectory()) continue;
|
|
32687
33030
|
if (name !== preferredKey) keys.push(name);
|
|
32688
33031
|
}
|
|
32689
33032
|
} catch {
|
|
32690
33033
|
return null;
|
|
32691
33034
|
}
|
|
32692
33035
|
for (const key of keys) {
|
|
32693
|
-
const layoutRoot =
|
|
32694
|
-
if (!
|
|
32695
|
-
const sessionDir =
|
|
33036
|
+
const layoutRoot = path24.join(worktreesRootPath, key);
|
|
33037
|
+
if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
|
|
33038
|
+
const sessionDir = path24.join(layoutRoot, sessionId);
|
|
32696
33039
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
32697
33040
|
if (nested) return nested;
|
|
32698
33041
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
32699
33042
|
if (legacyPaths.length > 0) {
|
|
32700
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
33043
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
|
|
32701
33044
|
return {
|
|
32702
|
-
sessionParentPath:
|
|
32703
|
-
workingTreeRelRoot:
|
|
32704
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
33045
|
+
sessionParentPath: path24.resolve(isolated),
|
|
33046
|
+
workingTreeRelRoot: path24.resolve(layoutRoot),
|
|
33047
|
+
repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
|
|
32705
33048
|
};
|
|
32706
33049
|
}
|
|
32707
33050
|
}
|
|
@@ -32710,12 +33053,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
32710
33053
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
32711
33054
|
const sid = sessionId.trim();
|
|
32712
33055
|
if (!sid) return null;
|
|
32713
|
-
const hint =
|
|
32714
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
33056
|
+
const hint = path24.resolve(sessionWorktreeRootPathOrHint);
|
|
33057
|
+
const underHint = tryBindingFromSessionDirectory(path24.join(hint, sid));
|
|
32715
33058
|
if (underHint) return underHint;
|
|
32716
33059
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
32717
33060
|
if (direct) {
|
|
32718
|
-
if (
|
|
33061
|
+
if (path24.basename(hint) === sid && isGitDir(hint)) {
|
|
32719
33062
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
32720
33063
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
32721
33064
|
return legacyFromCheckout;
|
|
@@ -32723,24 +33066,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
32723
33066
|
}
|
|
32724
33067
|
return direct;
|
|
32725
33068
|
}
|
|
32726
|
-
if (
|
|
33069
|
+
if (path24.basename(hint) === sid && isGitDir(hint)) {
|
|
32727
33070
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
32728
33071
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
32729
33072
|
}
|
|
32730
33073
|
let st;
|
|
32731
33074
|
try {
|
|
32732
|
-
st =
|
|
33075
|
+
st = fs23.statSync(hint);
|
|
32733
33076
|
} catch {
|
|
32734
33077
|
return null;
|
|
32735
33078
|
}
|
|
32736
33079
|
if (!st.isDirectory()) return null;
|
|
32737
33080
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
32738
33081
|
if (legacyPaths.length === 0) return null;
|
|
32739
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
33082
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
|
|
32740
33083
|
return {
|
|
32741
|
-
sessionParentPath:
|
|
33084
|
+
sessionParentPath: path24.resolve(isolated),
|
|
32742
33085
|
workingTreeRelRoot: hint,
|
|
32743
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
33086
|
+
repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
|
|
32744
33087
|
};
|
|
32745
33088
|
}
|
|
32746
33089
|
|
|
@@ -32763,10 +33106,10 @@ var SessionWorktreeManager = class {
|
|
|
32763
33106
|
this.layout = loadWorktreeLayout();
|
|
32764
33107
|
}
|
|
32765
33108
|
rememberSessionWorktrees(sessionId, binding) {
|
|
32766
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
33109
|
+
const paths = binding.repoCheckoutPaths.map((p) => path25.resolve(p));
|
|
32767
33110
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
32768
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
32769
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
33111
|
+
this.sessionParentPathBySession.set(sessionId, path25.resolve(binding.sessionParentPath));
|
|
33112
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path25.resolve(binding.workingTreeRelRoot));
|
|
32770
33113
|
}
|
|
32771
33114
|
sessionParentPathAfterRemember(sessionId) {
|
|
32772
33115
|
return this.sessionParentPathBySession.get(sessionId);
|
|
@@ -32783,7 +33126,7 @@ var SessionWorktreeManager = class {
|
|
|
32783
33126
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
32784
33127
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
32785
33128
|
if (!parent || !relRoot) return false;
|
|
32786
|
-
return
|
|
33129
|
+
return path25.resolve(parent) !== path25.resolve(relRoot);
|
|
32787
33130
|
}
|
|
32788
33131
|
/**
|
|
32789
33132
|
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
@@ -32792,7 +33135,7 @@ var SessionWorktreeManager = class {
|
|
|
32792
33135
|
if (!sessionId) return null;
|
|
32793
33136
|
const sid = sessionId.trim();
|
|
32794
33137
|
const cached2 = this.sessionParentPathBySession.get(sid);
|
|
32795
|
-
if (cached2) return
|
|
33138
|
+
if (cached2) return path25.resolve(cached2);
|
|
32796
33139
|
const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
|
|
32797
33140
|
if (!paths?.length) return null;
|
|
32798
33141
|
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
@@ -32806,7 +33149,7 @@ var SessionWorktreeManager = class {
|
|
|
32806
33149
|
const sid = sessionId.trim();
|
|
32807
33150
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
32808
33151
|
if (parentPathRaw) {
|
|
32809
|
-
const resolved =
|
|
33152
|
+
const resolved = path25.resolve(parentPathRaw);
|
|
32810
33153
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
32811
33154
|
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
32812
33155
|
if (diskFirst) {
|
|
@@ -32825,7 +33168,7 @@ var SessionWorktreeManager = class {
|
|
|
32825
33168
|
this.rememberSessionWorktrees(sid, tryRoot);
|
|
32826
33169
|
return this.sessionParentPathAfterRemember(sid);
|
|
32827
33170
|
}
|
|
32828
|
-
const next =
|
|
33171
|
+
const next = path25.dirname(cur);
|
|
32829
33172
|
if (next === cur) break;
|
|
32830
33173
|
cur = next;
|
|
32831
33174
|
}
|
|
@@ -32978,15 +33321,22 @@ var SessionWorktreeManager = class {
|
|
|
32978
33321
|
}
|
|
32979
33322
|
};
|
|
32980
33323
|
function defaultWorktreesRootPath() {
|
|
32981
|
-
return
|
|
33324
|
+
return path25.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
32982
33325
|
}
|
|
32983
33326
|
|
|
32984
33327
|
// src/files/watch-file-index.ts
|
|
32985
33328
|
import { watch } from "node:fs";
|
|
33329
|
+
import path30 from "node:path";
|
|
33330
|
+
|
|
33331
|
+
// src/files/index/paths.ts
|
|
32986
33332
|
import path26 from "node:path";
|
|
33333
|
+
import crypto2 from "node:crypto";
|
|
33334
|
+
function getCwdHashForFileIndex(resolvedCwd) {
|
|
33335
|
+
return crypto2.createHash("sha256").update(path26.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
33336
|
+
}
|
|
32987
33337
|
|
|
32988
33338
|
// src/files/index/build-file-index.ts
|
|
32989
|
-
import
|
|
33339
|
+
import path28 from "node:path";
|
|
32990
33340
|
|
|
32991
33341
|
// src/runtime/yield-to-event-loop.ts
|
|
32992
33342
|
function yieldToEventLoop() {
|
|
@@ -32994,47 +33344,12 @@ function yieldToEventLoop() {
|
|
|
32994
33344
|
}
|
|
32995
33345
|
|
|
32996
33346
|
// src/files/index/walk-workspace-tree.ts
|
|
32997
|
-
import
|
|
32998
|
-
import
|
|
32999
|
-
|
|
33000
|
-
// src/files/index/constants.ts
|
|
33001
|
-
import path20 from "node:path";
|
|
33002
|
-
import os6 from "node:os";
|
|
33003
|
-
var INDEX_WORK_YIELD_EVERY = 256;
|
|
33004
|
-
var INDEX_DIR = path20.join(os6.homedir(), ".buildautomaton");
|
|
33005
|
-
var INDEX_HASH_LEN = 16;
|
|
33006
|
-
var INDEX_VERSION = 2;
|
|
33007
|
-
var INDEX_LOG_PREFIX = "[file-index]";
|
|
33008
|
-
|
|
33009
|
-
// src/files/index/walk-workspace-tree.ts
|
|
33010
|
-
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
33011
|
-
let names;
|
|
33012
|
-
try {
|
|
33013
|
-
names = fs19.readdirSync(dir);
|
|
33014
|
-
} catch {
|
|
33015
|
-
return;
|
|
33016
|
-
}
|
|
33017
|
-
for (const name of names) {
|
|
33018
|
-
if (name.startsWith(".")) continue;
|
|
33019
|
-
const full = path21.join(dir, name);
|
|
33020
|
-
let stat2;
|
|
33021
|
-
try {
|
|
33022
|
-
stat2 = fs19.statSync(full);
|
|
33023
|
-
} catch {
|
|
33024
|
-
continue;
|
|
33025
|
-
}
|
|
33026
|
-
const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
|
|
33027
|
-
if (stat2.isDirectory()) {
|
|
33028
|
-
walkWorkspaceTreeSync(full, baseDir, out);
|
|
33029
|
-
} else if (stat2.isFile()) {
|
|
33030
|
-
out.push(relative5);
|
|
33031
|
-
}
|
|
33032
|
-
}
|
|
33033
|
-
}
|
|
33347
|
+
import fs24 from "node:fs";
|
|
33348
|
+
import path27 from "node:path";
|
|
33034
33349
|
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
33035
33350
|
let names;
|
|
33036
33351
|
try {
|
|
33037
|
-
names = await
|
|
33352
|
+
names = await fs24.promises.readdir(dir);
|
|
33038
33353
|
} catch {
|
|
33039
33354
|
return;
|
|
33040
33355
|
}
|
|
@@ -33044,14 +33359,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
33044
33359
|
await yieldToEventLoop();
|
|
33045
33360
|
}
|
|
33046
33361
|
state.n++;
|
|
33047
|
-
const full =
|
|
33362
|
+
const full = path27.join(dir, name);
|
|
33048
33363
|
let stat2;
|
|
33049
33364
|
try {
|
|
33050
|
-
stat2 = await
|
|
33365
|
+
stat2 = await fs24.promises.stat(full);
|
|
33051
33366
|
} catch {
|
|
33052
33367
|
continue;
|
|
33053
33368
|
}
|
|
33054
|
-
const relative5 =
|
|
33369
|
+
const relative5 = path27.relative(baseDir, full).replace(/\\/g, "/");
|
|
33055
33370
|
if (stat2.isDirectory()) {
|
|
33056
33371
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
33057
33372
|
} else if (stat2.isFile()) {
|
|
@@ -33063,205 +33378,124 @@ function createWalkYieldState() {
|
|
|
33063
33378
|
return { n: 0 };
|
|
33064
33379
|
}
|
|
33065
33380
|
|
|
33066
|
-
// src/files/index/
|
|
33067
|
-
|
|
33068
|
-
|
|
33069
|
-
const
|
|
33070
|
-
|
|
33071
|
-
out.push(lower.slice(i, i + 3));
|
|
33072
|
-
}
|
|
33073
|
-
return out;
|
|
33074
|
-
}
|
|
33075
|
-
function binarySearch(arr, x) {
|
|
33076
|
-
let lo = 0;
|
|
33077
|
-
let hi = arr.length - 1;
|
|
33078
|
-
while (lo <= hi) {
|
|
33079
|
-
const mid = lo + hi >>> 1;
|
|
33080
|
-
if (arr[mid] < x) lo = mid + 1;
|
|
33081
|
-
else if (arr[mid] > x) hi = mid - 1;
|
|
33082
|
-
else return mid;
|
|
33083
|
-
}
|
|
33084
|
-
return -1;
|
|
33085
|
-
}
|
|
33086
|
-
function intersectSortedTrigramSets(arrays) {
|
|
33087
|
-
if (arrays.length === 0) return [];
|
|
33088
|
-
if (arrays.length === 1) return arrays[0];
|
|
33089
|
-
const byLength = arrays.slice().sort((a, b) => a.length - b.length);
|
|
33090
|
-
const smallest = byLength[0];
|
|
33091
|
-
const rest = byLength.slice(1);
|
|
33092
|
-
const result = [];
|
|
33093
|
-
for (const idx of smallest) {
|
|
33094
|
-
if (rest.every((arr) => binarySearch(arr, idx) >= 0)) {
|
|
33095
|
-
result.push(idx);
|
|
33096
|
-
}
|
|
33097
|
-
}
|
|
33098
|
-
return result;
|
|
33099
|
-
}
|
|
33100
|
-
|
|
33101
|
-
// src/files/index/build-trigram-map.ts
|
|
33102
|
-
function buildTrigramMapForPaths(paths) {
|
|
33103
|
-
const trigramIndex = {};
|
|
33104
|
-
for (let i = 0; i < paths.length; i++) {
|
|
33105
|
-
const trigrams = getTrigrams(paths[i]);
|
|
33106
|
-
const seen = /* @__PURE__ */ new Set();
|
|
33107
|
-
for (const tri of trigrams) {
|
|
33108
|
-
if (seen.has(tri)) continue;
|
|
33109
|
-
seen.add(tri);
|
|
33110
|
-
if (!trigramIndex[tri]) trigramIndex[tri] = [];
|
|
33111
|
-
trigramIndex[tri].push(i);
|
|
33112
|
-
}
|
|
33113
|
-
}
|
|
33114
|
-
return trigramIndex;
|
|
33381
|
+
// src/files/index/file-index-sqlite-lock.ts
|
|
33382
|
+
import fs25 from "node:fs";
|
|
33383
|
+
function isSqliteCorruptError(e) {
|
|
33384
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
33385
|
+
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
33115
33386
|
}
|
|
33116
|
-
|
|
33117
|
-
|
|
33118
|
-
|
|
33119
|
-
|
|
33120
|
-
await
|
|
33121
|
-
}
|
|
33122
|
-
|
|
33123
|
-
|
|
33124
|
-
|
|
33125
|
-
|
|
33126
|
-
|
|
33127
|
-
|
|
33128
|
-
|
|
33387
|
+
var chain = Promise.resolve();
|
|
33388
|
+
function withFileIndexSqliteLock(fn) {
|
|
33389
|
+
const run = async () => {
|
|
33390
|
+
try {
|
|
33391
|
+
return await Promise.resolve(fn());
|
|
33392
|
+
} catch (e) {
|
|
33393
|
+
if (!isSqliteCorruptError(e)) throw e;
|
|
33394
|
+
closeAllCliSqliteConnections();
|
|
33395
|
+
try {
|
|
33396
|
+
fs25.unlinkSync(getCliSqlitePath());
|
|
33397
|
+
} catch {
|
|
33398
|
+
}
|
|
33399
|
+
chain = Promise.resolve();
|
|
33400
|
+
return await Promise.resolve(fn());
|
|
33129
33401
|
}
|
|
33130
|
-
}
|
|
33131
|
-
|
|
33132
|
-
|
|
33133
|
-
|
|
33134
|
-
|
|
33135
|
-
|
|
33136
|
-
|
|
33137
|
-
// src/files/index/paths.ts
|
|
33138
|
-
import path22 from "node:path";
|
|
33139
|
-
import crypto2 from "node:crypto";
|
|
33140
|
-
function getIndexPathForCwd(resolvedCwd) {
|
|
33141
|
-
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
33142
|
-
return path22.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
33143
|
-
}
|
|
33144
|
-
|
|
33145
|
-
// src/files/index/write-index-file.ts
|
|
33146
|
-
function writeIndexFileSync(resolvedCwd, data) {
|
|
33147
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
33148
|
-
try {
|
|
33149
|
-
if (!fs20.existsSync(INDEX_DIR)) fs20.mkdirSync(INDEX_DIR, { recursive: true });
|
|
33150
|
-
fs20.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
33151
|
-
} catch (e) {
|
|
33152
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
33153
|
-
}
|
|
33154
|
-
}
|
|
33155
|
-
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
33156
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
33157
|
-
try {
|
|
33158
|
-
await fs20.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
33159
|
-
await fs20.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
33160
|
-
} catch (e) {
|
|
33161
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
33162
|
-
}
|
|
33163
|
-
}
|
|
33164
|
-
function makeTrigramIndexData(paths, trigramIndex) {
|
|
33165
|
-
return { version: INDEX_VERSION, paths, trigramIndex };
|
|
33402
|
+
};
|
|
33403
|
+
const next = chain.then(run);
|
|
33404
|
+
chain = next.then(
|
|
33405
|
+
() => void 0,
|
|
33406
|
+
() => void 0
|
|
33407
|
+
);
|
|
33408
|
+
return next;
|
|
33166
33409
|
}
|
|
33167
33410
|
|
|
33168
33411
|
// src/files/index/build-file-index.ts
|
|
33169
33412
|
function sortPaths(paths) {
|
|
33170
33413
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
33171
33414
|
}
|
|
33172
|
-
function
|
|
33173
|
-
const
|
|
33174
|
-
const
|
|
33175
|
-
|
|
33176
|
-
sortPaths(paths);
|
|
33177
|
-
const trigramIndex = buildTrigramMapForPaths(paths);
|
|
33178
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
33179
|
-
writeIndexFileSync(resolved, data);
|
|
33180
|
-
return data;
|
|
33181
|
-
}
|
|
33182
|
-
async function buildFileIndexAsync(cwd) {
|
|
33183
|
-
const resolved = path23.resolve(cwd);
|
|
33184
|
-
const paths = [];
|
|
33185
|
-
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
33186
|
-
await yieldToEventLoop();
|
|
33187
|
-
sortPaths(paths);
|
|
33188
|
-
const trigramIndex = await buildTrigramMapForPathsAsync(paths);
|
|
33189
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
33190
|
-
await writeIndexFileAsync(resolved, data);
|
|
33191
|
-
return data;
|
|
33192
|
-
}
|
|
33193
|
-
|
|
33194
|
-
// src/files/index/load-file-index.ts
|
|
33195
|
-
import fs21 from "node:fs";
|
|
33196
|
-
import path24 from "node:path";
|
|
33197
|
-
function loadFileIndex(cwd) {
|
|
33198
|
-
const resolved = path24.resolve(cwd);
|
|
33199
|
-
const indexPath = getIndexPathForCwd(resolved);
|
|
33415
|
+
function persistPathsToSqlite(resolved, paths) {
|
|
33416
|
+
const db = getCliDatabase();
|
|
33417
|
+
const h = getCwdHashForFileIndex(resolved);
|
|
33418
|
+
db.run("BEGIN IMMEDIATE");
|
|
33200
33419
|
try {
|
|
33201
|
-
|
|
33202
|
-
const
|
|
33203
|
-
|
|
33204
|
-
const
|
|
33205
|
-
|
|
33206
|
-
return obj;
|
|
33420
|
+
db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
33421
|
+
const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
|
|
33422
|
+
try {
|
|
33423
|
+
for (const rel of paths) {
|
|
33424
|
+
ins.run([h, rel]);
|
|
33207
33425
|
}
|
|
33208
|
-
|
|
33426
|
+
} finally {
|
|
33427
|
+
ins.finalize();
|
|
33209
33428
|
}
|
|
33210
|
-
|
|
33211
|
-
|
|
33429
|
+
db.run("COMMIT");
|
|
33430
|
+
} catch (e) {
|
|
33431
|
+
try {
|
|
33432
|
+
db.run("ROLLBACK");
|
|
33433
|
+
} catch {
|
|
33212
33434
|
}
|
|
33213
|
-
|
|
33214
|
-
} catch {
|
|
33215
|
-
return null;
|
|
33435
|
+
throw e;
|
|
33216
33436
|
}
|
|
33217
33437
|
}
|
|
33438
|
+
async function buildFileIndexAsync(cwd) {
|
|
33439
|
+
return withFileIndexSqliteLock(async () => {
|
|
33440
|
+
const resolved = path28.resolve(cwd);
|
|
33441
|
+
const paths = [];
|
|
33442
|
+
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
33443
|
+
await yieldToEventLoop();
|
|
33444
|
+
sortPaths(paths);
|
|
33445
|
+
persistPathsToSqlite(resolved, paths);
|
|
33446
|
+
return { pathCount: paths.length };
|
|
33447
|
+
});
|
|
33448
|
+
}
|
|
33218
33449
|
|
|
33219
33450
|
// src/files/index/ensure-file-index.ts
|
|
33220
|
-
import
|
|
33221
|
-
async function ensureFileIndexAsync(cwd) {
|
|
33222
|
-
const resolved = path25.resolve(cwd);
|
|
33223
|
-
const cached2 = loadFileIndex(resolved);
|
|
33224
|
-
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
33225
|
-
const data = await buildFileIndexAsync(resolved);
|
|
33226
|
-
return { data, fromCache: false };
|
|
33227
|
-
}
|
|
33451
|
+
import path29 from "node:path";
|
|
33228
33452
|
|
|
33229
33453
|
// src/files/index/search-file-index.ts
|
|
33230
|
-
function
|
|
33231
|
-
|
|
33232
|
-
|
|
33233
|
-
|
|
33234
|
-
|
|
33235
|
-
const
|
|
33236
|
-
|
|
33237
|
-
|
|
33238
|
-
|
|
33239
|
-
|
|
33240
|
-
|
|
33241
|
-
|
|
33242
|
-
|
|
33243
|
-
|
|
33244
|
-
|
|
33454
|
+
function escapeLikePattern(fragment) {
|
|
33455
|
+
return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
33456
|
+
}
|
|
33457
|
+
function bridgeFileIndexIsPopulated(resolvedCwd) {
|
|
33458
|
+
const db = getCliDatabase();
|
|
33459
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
33460
|
+
const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
|
|
33461
|
+
return row != null;
|
|
33462
|
+
}
|
|
33463
|
+
function bridgeFileIndexPathCount(resolvedCwd) {
|
|
33464
|
+
const db = getCliDatabase();
|
|
33465
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
33466
|
+
const row = db.get("SELECT COUNT(*) as c FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
33467
|
+
const c = row?.c ?? 0;
|
|
33468
|
+
return Number(c);
|
|
33469
|
+
}
|
|
33470
|
+
function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
|
|
33245
33471
|
const q = query.trim().toLowerCase();
|
|
33246
33472
|
if (!q) return [];
|
|
33247
|
-
const
|
|
33248
|
-
const
|
|
33249
|
-
const
|
|
33250
|
-
|
|
33251
|
-
|
|
33252
|
-
|
|
33253
|
-
|
|
33254
|
-
|
|
33255
|
-
|
|
33256
|
-
|
|
33257
|
-
|
|
33258
|
-
|
|
33259
|
-
|
|
33260
|
-
|
|
33261
|
-
}
|
|
33473
|
+
const db = getCliDatabase();
|
|
33474
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
33475
|
+
const pattern = `%${escapeLikePattern(q)}%`;
|
|
33476
|
+
const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
|
|
33477
|
+
const rows = db.all(
|
|
33478
|
+
`SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' LIMIT ?`,
|
|
33479
|
+
[h, pattern, lim]
|
|
33480
|
+
);
|
|
33481
|
+
return rows.map((r) => String(r.path));
|
|
33482
|
+
}
|
|
33483
|
+
async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
33484
|
+
await yieldToEventLoop();
|
|
33485
|
+
const out = searchBridgeFilePaths(resolvedCwd, query, limit);
|
|
33486
|
+
if (out.length >= INDEX_WORK_YIELD_EVERY) await yieldToEventLoop();
|
|
33262
33487
|
return out;
|
|
33263
33488
|
}
|
|
33264
33489
|
|
|
33490
|
+
// src/files/index/ensure-file-index.ts
|
|
33491
|
+
async function ensureFileIndexAsync(cwd) {
|
|
33492
|
+
const resolved = path29.resolve(cwd);
|
|
33493
|
+
if (bridgeFileIndexIsPopulated(resolved)) {
|
|
33494
|
+
return { fromCache: true, pathCount: bridgeFileIndexPathCount(resolved) };
|
|
33495
|
+
}
|
|
33496
|
+
return { ...await buildFileIndexAsync(resolved), fromCache: false };
|
|
33497
|
+
}
|
|
33498
|
+
|
|
33265
33499
|
// src/files/watch-file-index.ts
|
|
33266
33500
|
var DEBOUNCE_MS = 900;
|
|
33267
33501
|
function shouldIgnoreRelative(rel) {
|
|
@@ -33302,7 +33536,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
33302
33536
|
}
|
|
33303
33537
|
}
|
|
33304
33538
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
33305
|
-
const resolved =
|
|
33539
|
+
const resolved = path30.resolve(cwd);
|
|
33306
33540
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
33307
33541
|
console.error("[file-index] Initial index build failed:", e);
|
|
33308
33542
|
});
|
|
@@ -33330,7 +33564,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
33330
33564
|
}
|
|
33331
33565
|
|
|
33332
33566
|
// src/connection/create-bridge-connection.ts
|
|
33333
|
-
import * as
|
|
33567
|
+
import * as path38 from "node:path";
|
|
33334
33568
|
|
|
33335
33569
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
33336
33570
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -33374,7 +33608,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
33374
33608
|
}
|
|
33375
33609
|
|
|
33376
33610
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
33377
|
-
import
|
|
33611
|
+
import fs26 from "node:fs";
|
|
33378
33612
|
|
|
33379
33613
|
// src/dev-servers/manager/forward-pipe.ts
|
|
33380
33614
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -33410,7 +33644,7 @@ function wireDevServerChildProcess(d) {
|
|
|
33410
33644
|
d.setPollInterval(void 0);
|
|
33411
33645
|
return;
|
|
33412
33646
|
}
|
|
33413
|
-
|
|
33647
|
+
fs26.readFile(d.mergedLogPath, (err, buf) => {
|
|
33414
33648
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
33415
33649
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
33416
33650
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -33448,7 +33682,7 @@ ${errTail}` : ""}`);
|
|
|
33448
33682
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
33449
33683
|
};
|
|
33450
33684
|
if (mergedPath) {
|
|
33451
|
-
|
|
33685
|
+
fs26.readFile(mergedPath, (err, buf) => {
|
|
33452
33686
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
33453
33687
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
33454
33688
|
if (chunk.length > 0) {
|
|
@@ -33550,13 +33784,13 @@ function parseDevServerDefs(servers) {
|
|
|
33550
33784
|
}
|
|
33551
33785
|
|
|
33552
33786
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
33553
|
-
import
|
|
33787
|
+
import fs27 from "node:fs";
|
|
33554
33788
|
function isSpawnEbadf(e) {
|
|
33555
33789
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
33556
33790
|
}
|
|
33557
33791
|
function rmDirQuiet(dir) {
|
|
33558
33792
|
try {
|
|
33559
|
-
|
|
33793
|
+
fs27.rmSync(dir, { recursive: true, force: true });
|
|
33560
33794
|
} catch {
|
|
33561
33795
|
}
|
|
33562
33796
|
}
|
|
@@ -33564,7 +33798,7 @@ var cachedDevNullReadFd;
|
|
|
33564
33798
|
function devNullReadFd() {
|
|
33565
33799
|
if (cachedDevNullReadFd === void 0) {
|
|
33566
33800
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
33567
|
-
cachedDevNullReadFd =
|
|
33801
|
+
cachedDevNullReadFd = fs27.openSync(devPath, "r");
|
|
33568
33802
|
}
|
|
33569
33803
|
return cachedDevNullReadFd;
|
|
33570
33804
|
}
|
|
@@ -33638,15 +33872,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
33638
33872
|
|
|
33639
33873
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
33640
33874
|
import { spawn as spawn7 } from "node:child_process";
|
|
33641
|
-
import
|
|
33875
|
+
import fs28 from "node:fs";
|
|
33642
33876
|
import { tmpdir } from "node:os";
|
|
33643
|
-
import
|
|
33877
|
+
import path31 from "node:path";
|
|
33644
33878
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
33645
|
-
const tmpRoot =
|
|
33646
|
-
const logPath =
|
|
33879
|
+
const tmpRoot = fs28.mkdtempSync(path31.join(tmpdir(), "ba-devsrv-log-"));
|
|
33880
|
+
const logPath = path31.join(tmpRoot, "combined.log");
|
|
33647
33881
|
let logFd;
|
|
33648
33882
|
try {
|
|
33649
|
-
logFd =
|
|
33883
|
+
logFd = fs28.openSync(logPath, "a");
|
|
33650
33884
|
} catch {
|
|
33651
33885
|
rmDirQuiet(tmpRoot);
|
|
33652
33886
|
return null;
|
|
@@ -33665,7 +33899,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
33665
33899
|
} else {
|
|
33666
33900
|
proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
33667
33901
|
}
|
|
33668
|
-
|
|
33902
|
+
fs28.closeSync(logFd);
|
|
33669
33903
|
return {
|
|
33670
33904
|
proc,
|
|
33671
33905
|
pipedStdoutStderr: true,
|
|
@@ -33674,7 +33908,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
33674
33908
|
};
|
|
33675
33909
|
} catch (e) {
|
|
33676
33910
|
try {
|
|
33677
|
-
|
|
33911
|
+
fs28.closeSync(logFd);
|
|
33678
33912
|
} catch {
|
|
33679
33913
|
}
|
|
33680
33914
|
rmDirQuiet(tmpRoot);
|
|
@@ -33685,22 +33919,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
33685
33919
|
|
|
33686
33920
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
33687
33921
|
import { spawn as spawn8 } from "node:child_process";
|
|
33688
|
-
import
|
|
33922
|
+
import fs29 from "node:fs";
|
|
33689
33923
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
33690
|
-
import
|
|
33924
|
+
import path32 from "node:path";
|
|
33691
33925
|
function shSingleQuote(s) {
|
|
33692
33926
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
33693
33927
|
}
|
|
33694
33928
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
33695
|
-
const tmpRoot =
|
|
33696
|
-
const logPath =
|
|
33697
|
-
const innerPath =
|
|
33698
|
-
const runnerPath =
|
|
33929
|
+
const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
33930
|
+
const logPath = path32.join(tmpRoot, "combined.log");
|
|
33931
|
+
const innerPath = path32.join(tmpRoot, "_cmd.sh");
|
|
33932
|
+
const runnerPath = path32.join(tmpRoot, "_run.sh");
|
|
33699
33933
|
try {
|
|
33700
|
-
|
|
33934
|
+
fs29.writeFileSync(innerPath, `#!/bin/sh
|
|
33701
33935
|
${command}
|
|
33702
33936
|
`);
|
|
33703
|
-
|
|
33937
|
+
fs29.writeFileSync(
|
|
33704
33938
|
runnerPath,
|
|
33705
33939
|
`#!/bin/sh
|
|
33706
33940
|
cd ${shSingleQuote(cwd)}
|
|
@@ -33726,13 +33960,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
33726
33960
|
}
|
|
33727
33961
|
}
|
|
33728
33962
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
33729
|
-
const tmpRoot =
|
|
33730
|
-
const logPath =
|
|
33731
|
-
const runnerPath =
|
|
33963
|
+
const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
33964
|
+
const logPath = path32.join(tmpRoot, "combined.log");
|
|
33965
|
+
const runnerPath = path32.join(tmpRoot, "_run.bat");
|
|
33732
33966
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
33733
33967
|
const com = process.env.ComSpec || "cmd.exe";
|
|
33734
33968
|
try {
|
|
33735
|
-
|
|
33969
|
+
fs29.writeFileSync(
|
|
33736
33970
|
runnerPath,
|
|
33737
33971
|
`@ECHO OFF\r
|
|
33738
33972
|
CD /D ${q(cwd)}\r
|
|
@@ -34501,30 +34735,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
34501
34735
|
}
|
|
34502
34736
|
|
|
34503
34737
|
// src/skills/discover-local-agent-skills.ts
|
|
34504
|
-
import
|
|
34505
|
-
import
|
|
34738
|
+
import fs30 from "node:fs";
|
|
34739
|
+
import path33 from "node:path";
|
|
34506
34740
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
34507
34741
|
function discoverLocalSkills(cwd) {
|
|
34508
34742
|
const out = [];
|
|
34509
34743
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
34510
34744
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
34511
|
-
const base =
|
|
34512
|
-
if (!
|
|
34745
|
+
const base = path33.join(cwd, rel);
|
|
34746
|
+
if (!fs30.existsSync(base) || !fs30.statSync(base).isDirectory()) continue;
|
|
34513
34747
|
let entries = [];
|
|
34514
34748
|
try {
|
|
34515
|
-
entries =
|
|
34749
|
+
entries = fs30.readdirSync(base);
|
|
34516
34750
|
} catch {
|
|
34517
34751
|
continue;
|
|
34518
34752
|
}
|
|
34519
34753
|
for (const name of entries) {
|
|
34520
|
-
const dir =
|
|
34754
|
+
const dir = path33.join(base, name);
|
|
34521
34755
|
try {
|
|
34522
|
-
if (!
|
|
34756
|
+
if (!fs30.statSync(dir).isDirectory()) continue;
|
|
34523
34757
|
} catch {
|
|
34524
34758
|
continue;
|
|
34525
34759
|
}
|
|
34526
|
-
const skillMd =
|
|
34527
|
-
if (!
|
|
34760
|
+
const skillMd = path33.join(dir, "SKILL.md");
|
|
34761
|
+
if (!fs30.existsSync(skillMd)) continue;
|
|
34528
34762
|
const key = `${rel}/${name}`;
|
|
34529
34763
|
if (seenKeys.has(key)) continue;
|
|
34530
34764
|
seenKeys.add(key);
|
|
@@ -34536,23 +34770,23 @@ function discoverLocalSkills(cwd) {
|
|
|
34536
34770
|
function discoverSkillLayoutRoots(cwd) {
|
|
34537
34771
|
const roots = [];
|
|
34538
34772
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
34539
|
-
const base =
|
|
34540
|
-
if (!
|
|
34773
|
+
const base = path33.join(cwd, rel);
|
|
34774
|
+
if (!fs30.existsSync(base) || !fs30.statSync(base).isDirectory()) continue;
|
|
34541
34775
|
let entries = [];
|
|
34542
34776
|
try {
|
|
34543
|
-
entries =
|
|
34777
|
+
entries = fs30.readdirSync(base);
|
|
34544
34778
|
} catch {
|
|
34545
34779
|
continue;
|
|
34546
34780
|
}
|
|
34547
34781
|
const skills2 = [];
|
|
34548
34782
|
for (const name of entries) {
|
|
34549
|
-
const dir =
|
|
34783
|
+
const dir = path33.join(base, name);
|
|
34550
34784
|
try {
|
|
34551
|
-
if (!
|
|
34785
|
+
if (!fs30.statSync(dir).isDirectory()) continue;
|
|
34552
34786
|
} catch {
|
|
34553
34787
|
continue;
|
|
34554
34788
|
}
|
|
34555
|
-
if (!
|
|
34789
|
+
if (!fs30.existsSync(path33.join(dir, "SKILL.md"))) continue;
|
|
34556
34790
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
34557
34791
|
skills2.push({ name, relPath });
|
|
34558
34792
|
}
|
|
@@ -34654,6 +34888,7 @@ function reportGitRepos(getWs, log2) {
|
|
|
34654
34888
|
var API_TO_BRIDGE_MESSAGE_TYPES = [
|
|
34655
34889
|
"auth_token",
|
|
34656
34890
|
"bridge_identified",
|
|
34891
|
+
"ha",
|
|
34657
34892
|
"dev_servers_config",
|
|
34658
34893
|
"server_control",
|
|
34659
34894
|
"agent_config",
|
|
@@ -34682,6 +34917,10 @@ function parseApiToBridgeMessage(data, log2) {
|
|
|
34682
34917
|
}
|
|
34683
34918
|
return null;
|
|
34684
34919
|
}
|
|
34920
|
+
if (t === "ha") {
|
|
34921
|
+
const s = data.s;
|
|
34922
|
+
if (typeof s !== "number" || !Number.isFinite(s)) return null;
|
|
34923
|
+
}
|
|
34685
34924
|
return data;
|
|
34686
34925
|
}
|
|
34687
34926
|
|
|
@@ -34722,6 +34961,13 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
34722
34961
|
});
|
|
34723
34962
|
};
|
|
34724
34963
|
|
|
34964
|
+
// src/connection/heartbeat/ack.ts
|
|
34965
|
+
var handleBridgeHeartbeatAck = (msg, deps) => {
|
|
34966
|
+
const raw = msg.s;
|
|
34967
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) return;
|
|
34968
|
+
deps.onBridgeHeartbeatAck?.(Math.trunc(raw));
|
|
34969
|
+
};
|
|
34970
|
+
|
|
34725
34971
|
// src/agents/acp/from-bridge/handle-bridge-agent-config.ts
|
|
34726
34972
|
function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
34727
34973
|
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
|
|
@@ -34734,7 +34980,7 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
34734
34980
|
};
|
|
34735
34981
|
|
|
34736
34982
|
// src/prompt-turn-queue/runner.ts
|
|
34737
|
-
import
|
|
34983
|
+
import fs31 from "node:fs";
|
|
34738
34984
|
|
|
34739
34985
|
// src/prompt-turn-queue/client-report.ts
|
|
34740
34986
|
function sendPromptQueueClientReport(ws, queues) {
|
|
@@ -34743,32 +34989,6 @@ function sendPromptQueueClientReport(ws, queues) {
|
|
|
34743
34989
|
return true;
|
|
34744
34990
|
}
|
|
34745
34991
|
|
|
34746
|
-
// src/prompt-turn-queue/disk-store.ts
|
|
34747
|
-
import fs28 from "node:fs";
|
|
34748
|
-
|
|
34749
|
-
// src/prompt-turn-queue/paths.ts
|
|
34750
|
-
import crypto3 from "node:crypto";
|
|
34751
|
-
import fs27 from "node:fs";
|
|
34752
|
-
import path30 from "node:path";
|
|
34753
|
-
import os7 from "node:os";
|
|
34754
|
-
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
34755
|
-
function queueStateFileSlug(queueKey) {
|
|
34756
|
-
if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
|
|
34757
|
-
return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
|
|
34758
|
-
}
|
|
34759
|
-
function getPromptQueuesDirectory() {
|
|
34760
|
-
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
34761
|
-
if (override) return path30.resolve(override);
|
|
34762
|
-
return path30.join(os7.homedir(), ".buildautomaton", "queues");
|
|
34763
|
-
}
|
|
34764
|
-
function ensurePromptQueuesDirectory() {
|
|
34765
|
-
const dir = getPromptQueuesDirectory();
|
|
34766
|
-
if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
|
|
34767
|
-
}
|
|
34768
|
-
function queueStateFilePath(queueKey) {
|
|
34769
|
-
return path30.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
34770
|
-
}
|
|
34771
|
-
|
|
34772
34992
|
// src/prompt-turn-queue/disk-store.ts
|
|
34773
34993
|
var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
34774
34994
|
"queued",
|
|
@@ -34778,28 +34998,27 @@ var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
|
34778
34998
|
"stopping",
|
|
34779
34999
|
"discarded"
|
|
34780
35000
|
]);
|
|
34781
|
-
function parsePersistedQueueFile(raw) {
|
|
34782
|
-
try {
|
|
34783
|
-
const o = JSON.parse(raw);
|
|
34784
|
-
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
34785
|
-
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
34786
|
-
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
34787
|
-
} catch {
|
|
34788
|
-
return null;
|
|
34789
|
-
}
|
|
34790
|
-
}
|
|
34791
35001
|
function readPersistedQueue(queueKey) {
|
|
34792
|
-
const
|
|
35002
|
+
const db = getCliDatabase();
|
|
35003
|
+
const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
|
|
35004
|
+
queueKey
|
|
35005
|
+
]);
|
|
35006
|
+
if (!row) return null;
|
|
34793
35007
|
try {
|
|
34794
|
-
|
|
35008
|
+
const turns = JSON.parse(row.turns_json);
|
|
35009
|
+
if (!Array.isArray(turns)) return null;
|
|
35010
|
+
return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
|
|
34795
35011
|
} catch {
|
|
34796
35012
|
return null;
|
|
34797
35013
|
}
|
|
34798
35014
|
}
|
|
34799
35015
|
function writePersistedQueue(file2) {
|
|
34800
|
-
|
|
34801
|
-
|
|
34802
|
-
|
|
35016
|
+
const db = getCliDatabase();
|
|
35017
|
+
db.run(
|
|
35018
|
+
`INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
|
|
35019
|
+
ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
|
|
35020
|
+
[file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
|
|
35021
|
+
);
|
|
34803
35022
|
}
|
|
34804
35023
|
function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
34805
35024
|
const prev = readPersistedQueue(queueKey);
|
|
@@ -34857,7 +35076,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
34857
35076
|
const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
|
|
34858
35077
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
34859
35078
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
34860
|
-
if (!
|
|
35079
|
+
if (!fs31.existsSync(file2)) {
|
|
34861
35080
|
deps.log(
|
|
34862
35081
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
34863
35082
|
);
|
|
@@ -35081,9 +35300,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
35081
35300
|
for (const item of raw) {
|
|
35082
35301
|
if (!item || typeof item !== "object") continue;
|
|
35083
35302
|
const o = item;
|
|
35084
|
-
const
|
|
35085
|
-
if (!
|
|
35086
|
-
const row = { path:
|
|
35303
|
+
const path39 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
35304
|
+
if (!path39) continue;
|
|
35305
|
+
const row = { path: path39 };
|
|
35087
35306
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
35088
35307
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
35089
35308
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -35304,15 +35523,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
35304
35523
|
};
|
|
35305
35524
|
|
|
35306
35525
|
// src/files/list-dir.ts
|
|
35307
|
-
import
|
|
35308
|
-
import
|
|
35526
|
+
import fs32 from "node:fs";
|
|
35527
|
+
import path35 from "node:path";
|
|
35309
35528
|
|
|
35310
35529
|
// src/files/ensure-under-cwd.ts
|
|
35311
|
-
import
|
|
35530
|
+
import path34 from "node:path";
|
|
35312
35531
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
35313
|
-
const normalized =
|
|
35314
|
-
const resolved =
|
|
35315
|
-
if (!resolved.startsWith(cwd +
|
|
35532
|
+
const normalized = path34.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
35533
|
+
const resolved = path34.resolve(cwd, normalized);
|
|
35534
|
+
if (!resolved.startsWith(cwd + path34.sep) && resolved !== cwd) {
|
|
35316
35535
|
return null;
|
|
35317
35536
|
}
|
|
35318
35537
|
return resolved;
|
|
@@ -35326,7 +35545,7 @@ async function listDirAsync(relativePath) {
|
|
|
35326
35545
|
return { error: "Path is outside working directory" };
|
|
35327
35546
|
}
|
|
35328
35547
|
try {
|
|
35329
|
-
const names = await
|
|
35548
|
+
const names = await fs32.promises.readdir(resolved, { withFileTypes: true });
|
|
35330
35549
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
35331
35550
|
const entries = [];
|
|
35332
35551
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -35334,12 +35553,12 @@ async function listDirAsync(relativePath) {
|
|
|
35334
35553
|
await yieldToEventLoop();
|
|
35335
35554
|
}
|
|
35336
35555
|
const d = visible[i];
|
|
35337
|
-
const entryPath =
|
|
35338
|
-
const fullPath =
|
|
35556
|
+
const entryPath = path35.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
35557
|
+
const fullPath = path35.join(resolved, d.name);
|
|
35339
35558
|
let isDir = d.isDirectory();
|
|
35340
35559
|
if (d.isSymbolicLink()) {
|
|
35341
35560
|
try {
|
|
35342
|
-
const targetStat = await
|
|
35561
|
+
const targetStat = await fs32.promises.stat(fullPath);
|
|
35343
35562
|
isDir = targetStat.isDirectory();
|
|
35344
35563
|
} catch {
|
|
35345
35564
|
isDir = false;
|
|
@@ -35364,25 +35583,25 @@ async function listDirAsync(relativePath) {
|
|
|
35364
35583
|
}
|
|
35365
35584
|
|
|
35366
35585
|
// src/files/read-file.ts
|
|
35367
|
-
import
|
|
35586
|
+
import fs33 from "node:fs";
|
|
35368
35587
|
import { StringDecoder } from "node:string_decoder";
|
|
35369
35588
|
function resolveFilePath(relativePath) {
|
|
35370
35589
|
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
35371
35590
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
35372
35591
|
let real;
|
|
35373
35592
|
try {
|
|
35374
|
-
real =
|
|
35593
|
+
real = fs33.realpathSync(resolved);
|
|
35375
35594
|
} catch {
|
|
35376
35595
|
real = resolved;
|
|
35377
35596
|
}
|
|
35378
|
-
const stat2 =
|
|
35597
|
+
const stat2 = fs33.statSync(real);
|
|
35379
35598
|
if (!stat2.isFile()) return { error: "Not a file" };
|
|
35380
35599
|
return real;
|
|
35381
35600
|
}
|
|
35382
35601
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
35383
35602
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
35384
|
-
const fileSize =
|
|
35385
|
-
const fd =
|
|
35603
|
+
const fileSize = fs33.statSync(filePath).size;
|
|
35604
|
+
const fd = fs33.openSync(filePath, "r");
|
|
35386
35605
|
const bufSize = 64 * 1024;
|
|
35387
35606
|
const buf = Buffer.alloc(bufSize);
|
|
35388
35607
|
const decoder = new StringDecoder("utf8");
|
|
@@ -35395,7 +35614,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
35395
35614
|
let line0Accum = "";
|
|
35396
35615
|
try {
|
|
35397
35616
|
let bytesRead;
|
|
35398
|
-
while (!done && (bytesRead =
|
|
35617
|
+
while (!done && (bytesRead = fs33.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
35399
35618
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
35400
35619
|
partial2 = "";
|
|
35401
35620
|
let lineStart = 0;
|
|
@@ -35530,7 +35749,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
35530
35749
|
}
|
|
35531
35750
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
35532
35751
|
} finally {
|
|
35533
|
-
|
|
35752
|
+
fs33.closeSync(fd);
|
|
35534
35753
|
}
|
|
35535
35754
|
}
|
|
35536
35755
|
function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
@@ -35541,8 +35760,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
35541
35760
|
if (hasRange) {
|
|
35542
35761
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
35543
35762
|
}
|
|
35544
|
-
const stat2 =
|
|
35545
|
-
const raw =
|
|
35763
|
+
const stat2 = fs33.statSync(result);
|
|
35764
|
+
const raw = fs33.readFileSync(result, "utf8");
|
|
35546
35765
|
const lines = raw.split(/\r?\n/);
|
|
35547
35766
|
return { content: raw, totalLines: lines.length, size: stat2.size };
|
|
35548
35767
|
} catch (err) {
|
|
@@ -35555,14 +35774,14 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
35555
35774
|
}
|
|
35556
35775
|
|
|
35557
35776
|
// src/files/handle-file-browser-search.ts
|
|
35777
|
+
import path36 from "node:path";
|
|
35558
35778
|
var SEARCH_LIMIT = 100;
|
|
35559
35779
|
function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
35560
35780
|
void (async () => {
|
|
35561
35781
|
await yieldToEventLoop();
|
|
35562
35782
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
35563
|
-
const cwd = getBridgeRoot();
|
|
35564
|
-
|
|
35565
|
-
if (index === null) {
|
|
35783
|
+
const cwd = path36.resolve(getBridgeRoot());
|
|
35784
|
+
if (!bridgeFileIndexIsPopulated(cwd)) {
|
|
35566
35785
|
const payload2 = {
|
|
35567
35786
|
type: "file_browser_search_response",
|
|
35568
35787
|
id: msg.id,
|
|
@@ -35572,7 +35791,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
35572
35791
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
35573
35792
|
return;
|
|
35574
35793
|
}
|
|
35575
|
-
const results = await
|
|
35794
|
+
const results = await searchBridgeFilePathsAsync(cwd, q, SEARCH_LIMIT);
|
|
35576
35795
|
const payload = {
|
|
35577
35796
|
type: "file_browser_search_response",
|
|
35578
35797
|
id: msg.id,
|
|
@@ -35660,8 +35879,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
35660
35879
|
}
|
|
35661
35880
|
|
|
35662
35881
|
// src/skills/install-remote-skills.ts
|
|
35663
|
-
import
|
|
35664
|
-
import
|
|
35882
|
+
import fs34 from "node:fs";
|
|
35883
|
+
import path37 from "node:path";
|
|
35665
35884
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
35666
35885
|
const installed2 = [];
|
|
35667
35886
|
if (!Array.isArray(items)) {
|
|
@@ -35672,15 +35891,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
35672
35891
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
35673
35892
|
continue;
|
|
35674
35893
|
}
|
|
35675
|
-
const skillDir =
|
|
35894
|
+
const skillDir = path37.join(cwd, targetDir, item.skillName);
|
|
35676
35895
|
for (const f of item.files) {
|
|
35677
35896
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
35678
|
-
const dest =
|
|
35679
|
-
|
|
35897
|
+
const dest = path37.join(skillDir, f.path);
|
|
35898
|
+
fs34.mkdirSync(path37.dirname(dest), { recursive: true });
|
|
35680
35899
|
if (f.text !== void 0) {
|
|
35681
|
-
|
|
35900
|
+
fs34.writeFileSync(dest, f.text, "utf8");
|
|
35682
35901
|
} else if (f.base64) {
|
|
35683
|
-
|
|
35902
|
+
fs34.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
35684
35903
|
}
|
|
35685
35904
|
}
|
|
35686
35905
|
installed2.push({
|
|
@@ -35830,7 +36049,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
35830
36049
|
};
|
|
35831
36050
|
|
|
35832
36051
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
35833
|
-
import * as
|
|
36052
|
+
import * as fs35 from "node:fs";
|
|
35834
36053
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
35835
36054
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
35836
36055
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -35842,7 +36061,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
35842
36061
|
if (!s) return;
|
|
35843
36062
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
35844
36063
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
35845
|
-
if (!
|
|
36064
|
+
if (!fs35.existsSync(file2)) {
|
|
35846
36065
|
sendWsMessage(s, {
|
|
35847
36066
|
type: "revert_turn_snapshot_result",
|
|
35848
36067
|
id,
|
|
@@ -35891,6 +36110,9 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
35891
36110
|
case "bridge_identified":
|
|
35892
36111
|
handleBridgeIdentified(msg, deps);
|
|
35893
36112
|
break;
|
|
36113
|
+
case "ha":
|
|
36114
|
+
handleBridgeHeartbeatAck(msg, deps);
|
|
36115
|
+
break;
|
|
35894
36116
|
case "dev_servers_config":
|
|
35895
36117
|
handleDevServersConfig(msg, deps);
|
|
35896
36118
|
break;
|
|
@@ -35946,9 +36168,17 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
35946
36168
|
}
|
|
35947
36169
|
|
|
35948
36170
|
// src/routing/handle-bridge-message.ts
|
|
36171
|
+
function normalizeInboundBridgeWebSocketJson(data) {
|
|
36172
|
+
if (data === null || typeof data !== "object" || Array.isArray(data)) return data;
|
|
36173
|
+
const o = data;
|
|
36174
|
+
if (o.t === "ha" && typeof o.s === "number" && Number.isFinite(o.s)) {
|
|
36175
|
+
return { type: "ha", s: Math.trunc(o.s) };
|
|
36176
|
+
}
|
|
36177
|
+
return data;
|
|
36178
|
+
}
|
|
35949
36179
|
function handleBridgeMessage(data, deps) {
|
|
35950
36180
|
if (!deps.getWs()) return;
|
|
35951
|
-
const msg = parseApiToBridgeMessage(data, deps.log);
|
|
36181
|
+
const msg = parseApiToBridgeMessage(normalizeInboundBridgeWebSocketJson(data), deps.log);
|
|
35952
36182
|
if (!msg) return;
|
|
35953
36183
|
setImmediate(() => {
|
|
35954
36184
|
dispatchBridgeMessage(msg, deps);
|
|
@@ -35996,7 +36226,8 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
35996
36226
|
persistTokens,
|
|
35997
36227
|
onAuthInvalid,
|
|
35998
36228
|
e2ee,
|
|
35999
|
-
identifyReportedPaths
|
|
36229
|
+
identifyReportedPaths,
|
|
36230
|
+
bridgeHeartbeat
|
|
36000
36231
|
} = params;
|
|
36001
36232
|
let authRefreshInFlight = false;
|
|
36002
36233
|
function handleOpen() {
|
|
@@ -36028,6 +36259,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
36028
36259
|
}
|
|
36029
36260
|
}
|
|
36030
36261
|
function handleClose(code, reason) {
|
|
36262
|
+
bridgeHeartbeat?.stop();
|
|
36031
36263
|
try {
|
|
36032
36264
|
const was = state.currentWs;
|
|
36033
36265
|
state.currentWs = null;
|
|
@@ -36062,6 +36294,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
36062
36294
|
} catch {
|
|
36063
36295
|
}
|
|
36064
36296
|
}
|
|
36297
|
+
bridgeHeartbeat?.stop();
|
|
36065
36298
|
const prev = state.currentWs;
|
|
36066
36299
|
if (prev) {
|
|
36067
36300
|
prev.removeAllListeners();
|
|
@@ -36232,11 +36465,98 @@ function createCliE2eeRuntime(key) {
|
|
|
36232
36465
|
};
|
|
36233
36466
|
}
|
|
36234
36467
|
|
|
36468
|
+
// src/connection/heartbeat/controller.ts
|
|
36469
|
+
function meanRttMs(samples) {
|
|
36470
|
+
if (samples.length === 0) return void 0;
|
|
36471
|
+
let sum = 0;
|
|
36472
|
+
for (const x of samples) sum += x;
|
|
36473
|
+
return sum / samples.length;
|
|
36474
|
+
}
|
|
36475
|
+
function createBridgeHeartbeatController(params) {
|
|
36476
|
+
const { getWs, log: log2 } = params;
|
|
36477
|
+
let interval = null;
|
|
36478
|
+
let seqCursor = -1;
|
|
36479
|
+
let awaitingSeq = null;
|
|
36480
|
+
let sentAtMs = 0;
|
|
36481
|
+
let missed = 0;
|
|
36482
|
+
const rttSamples = [];
|
|
36483
|
+
function clearTimer() {
|
|
36484
|
+
if (interval != null) {
|
|
36485
|
+
clearInterval(interval);
|
|
36486
|
+
interval = null;
|
|
36487
|
+
}
|
|
36488
|
+
}
|
|
36489
|
+
function nextSeq() {
|
|
36490
|
+
seqCursor = seqCursor >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : seqCursor + 1;
|
|
36491
|
+
return seqCursor;
|
|
36492
|
+
}
|
|
36493
|
+
function tick() {
|
|
36494
|
+
const ws = getWs();
|
|
36495
|
+
if (!ws || ws.readyState !== wrapper_default.OPEN) return;
|
|
36496
|
+
if (awaitingSeq !== null) {
|
|
36497
|
+
missed++;
|
|
36498
|
+
if (missed >= BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT) {
|
|
36499
|
+
try {
|
|
36500
|
+
log2("[Bridge service] Heartbeat missed repeatedly; reconnecting\u2026");
|
|
36501
|
+
} catch {
|
|
36502
|
+
}
|
|
36503
|
+
clearTimer();
|
|
36504
|
+
awaitingSeq = null;
|
|
36505
|
+
missed = 0;
|
|
36506
|
+
rttSamples.length = 0;
|
|
36507
|
+
safeCloseWebSocket(ws);
|
|
36508
|
+
return;
|
|
36509
|
+
}
|
|
36510
|
+
}
|
|
36511
|
+
const seq = nextSeq();
|
|
36512
|
+
const mean = meanRttMs(rttSamples);
|
|
36513
|
+
const payload = mean !== void 0 && Number.isFinite(mean) ? { t: "h", s: seq, m: Math.round(mean) } : { t: "h", s: seq };
|
|
36514
|
+
sendWsMessage(ws, payload);
|
|
36515
|
+
awaitingSeq = seq;
|
|
36516
|
+
sentAtMs = Date.now();
|
|
36517
|
+
}
|
|
36518
|
+
return {
|
|
36519
|
+
start() {
|
|
36520
|
+
clearTimer();
|
|
36521
|
+
awaitingSeq = null;
|
|
36522
|
+
missed = 0;
|
|
36523
|
+
seqCursor = -1;
|
|
36524
|
+
rttSamples.length = 0;
|
|
36525
|
+
interval = setInterval(tick, BRIDGE_APP_HEARTBEAT_INTERVAL_MS);
|
|
36526
|
+
},
|
|
36527
|
+
stop() {
|
|
36528
|
+
clearTimer();
|
|
36529
|
+
awaitingSeq = null;
|
|
36530
|
+
missed = 0;
|
|
36531
|
+
rttSamples.length = 0;
|
|
36532
|
+
},
|
|
36533
|
+
onAck(seq) {
|
|
36534
|
+
if (awaitingSeq === null) return;
|
|
36535
|
+
if (!Number.isFinite(seq)) return;
|
|
36536
|
+
const ack = Math.trunc(seq);
|
|
36537
|
+
const pending = awaitingSeq;
|
|
36538
|
+
if (ack < pending) return;
|
|
36539
|
+
if (ack === pending) {
|
|
36540
|
+
const rtt = Date.now() - sentAtMs;
|
|
36541
|
+
if (Number.isFinite(rtt) && rtt >= 0 && rtt < 6e5) {
|
|
36542
|
+
rttSamples.push(rtt);
|
|
36543
|
+
if (rttSamples.length > BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX) {
|
|
36544
|
+
rttSamples.splice(0, rttSamples.length - BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX);
|
|
36545
|
+
}
|
|
36546
|
+
}
|
|
36547
|
+
}
|
|
36548
|
+
awaitingSeq = null;
|
|
36549
|
+
missed = 0;
|
|
36550
|
+
}
|
|
36551
|
+
};
|
|
36552
|
+
}
|
|
36553
|
+
|
|
36235
36554
|
// src/connection/create-bridge-connection.ts
|
|
36236
36555
|
async function createBridgeConnection(options) {
|
|
36237
36556
|
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
36238
36557
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
36239
36558
|
const logFn = options.log ?? log;
|
|
36559
|
+
getCliDatabase({ logLegacyMigration: logFn });
|
|
36240
36560
|
const tokens = {
|
|
36241
36561
|
accessToken: options.authToken,
|
|
36242
36562
|
refreshToken: options.refreshToken
|
|
@@ -36271,13 +36591,18 @@ async function createBridgeConnection(options) {
|
|
|
36271
36591
|
}
|
|
36272
36592
|
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
36273
36593
|
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
|
|
36274
|
-
const
|
|
36594
|
+
const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
|
|
36595
|
+
const baseOnBridgeIdentified = createOnBridgeIdentified({
|
|
36275
36596
|
devServerManager,
|
|
36276
36597
|
firehoseServerUrl,
|
|
36277
36598
|
workspaceId,
|
|
36278
36599
|
state,
|
|
36279
36600
|
logFn
|
|
36280
36601
|
});
|
|
36602
|
+
const onBridgeIdentified = (msg) => {
|
|
36603
|
+
baseOnBridgeIdentified(msg);
|
|
36604
|
+
bridgeHeartbeat.start();
|
|
36605
|
+
};
|
|
36281
36606
|
const sendLocalSkillsReport = createSendLocalSkillsReport(getWs, logFn);
|
|
36282
36607
|
const reportAutoDetectedAgents = createReportAutoDetectedAgents(getWs, logFn);
|
|
36283
36608
|
const messageDeps = {
|
|
@@ -36286,6 +36611,9 @@ async function createBridgeConnection(options) {
|
|
|
36286
36611
|
acpManager,
|
|
36287
36612
|
sessionWorktreeManager,
|
|
36288
36613
|
onBridgeIdentified,
|
|
36614
|
+
onBridgeHeartbeatAck: (seq) => {
|
|
36615
|
+
bridgeHeartbeat.onAck(seq);
|
|
36616
|
+
},
|
|
36289
36617
|
sendLocalSkillsReport,
|
|
36290
36618
|
reportAutoDetectedAgents,
|
|
36291
36619
|
devServerManager,
|
|
@@ -36294,8 +36622,8 @@ async function createBridgeConnection(options) {
|
|
|
36294
36622
|
getCloudAccessToken: () => tokens.accessToken
|
|
36295
36623
|
};
|
|
36296
36624
|
const identifyReportedPaths = {
|
|
36297
|
-
bridgeRootPath:
|
|
36298
|
-
worktreesRootPath:
|
|
36625
|
+
bridgeRootPath: path38.resolve(getBridgeRoot()),
|
|
36626
|
+
worktreesRootPath: path38.resolve(worktreesRootPath)
|
|
36299
36627
|
};
|
|
36300
36628
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
36301
36629
|
state,
|
|
@@ -36309,13 +36637,15 @@ async function createBridgeConnection(options) {
|
|
|
36309
36637
|
persistTokens,
|
|
36310
36638
|
onAuthInvalid,
|
|
36311
36639
|
e2ee,
|
|
36312
|
-
identifyReportedPaths
|
|
36640
|
+
identifyReportedPaths,
|
|
36641
|
+
bridgeHeartbeat
|
|
36313
36642
|
});
|
|
36314
36643
|
connect();
|
|
36315
36644
|
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
|
|
36316
36645
|
return {
|
|
36317
36646
|
close: async () => {
|
|
36318
36647
|
stopFileIndexWatcher();
|
|
36648
|
+
bridgeHeartbeat.stop();
|
|
36319
36649
|
await closeBridgeConnection(state, acpManager, devServerManager, logFn);
|
|
36320
36650
|
}
|
|
36321
36651
|
};
|