@buildautomaton/cli 0.1.48 → 0.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1665 -950
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1644 -929
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4175,8 +4175,8 @@ var init_parseUtil = __esm({
|
|
|
4175
4175
|
init_errors();
|
|
4176
4176
|
init_en();
|
|
4177
4177
|
makeIssue = (params) => {
|
|
4178
|
-
const { data, path:
|
|
4179
|
-
const fullPath = [...
|
|
4178
|
+
const { data, path: path53, errorMaps, issueData } = params;
|
|
4179
|
+
const fullPath = [...path53, ...issueData.path || []];
|
|
4180
4180
|
const fullIssue = {
|
|
4181
4181
|
...issueData,
|
|
4182
4182
|
path: fullPath
|
|
@@ -4484,11 +4484,11 @@ var init_types = __esm({
|
|
|
4484
4484
|
init_parseUtil();
|
|
4485
4485
|
init_util();
|
|
4486
4486
|
ParseInputLazyPath = class {
|
|
4487
|
-
constructor(parent, value,
|
|
4487
|
+
constructor(parent, value, path53, key) {
|
|
4488
4488
|
this._cachedPath = [];
|
|
4489
4489
|
this.parent = parent;
|
|
4490
4490
|
this.data = value;
|
|
4491
|
-
this._path =
|
|
4491
|
+
this._path = path53;
|
|
4492
4492
|
this._key = key;
|
|
4493
4493
|
}
|
|
4494
4494
|
get path() {
|
|
@@ -8103,15 +8103,15 @@ function assignProp(target, prop, value) {
|
|
|
8103
8103
|
configurable: true
|
|
8104
8104
|
});
|
|
8105
8105
|
}
|
|
8106
|
-
function getElementAtPath(obj,
|
|
8107
|
-
if (!
|
|
8106
|
+
function getElementAtPath(obj, path53) {
|
|
8107
|
+
if (!path53)
|
|
8108
8108
|
return obj;
|
|
8109
|
-
return
|
|
8109
|
+
return path53.reduce((acc, key) => acc?.[key], obj);
|
|
8110
8110
|
}
|
|
8111
8111
|
function promiseAllObject(promisesObj) {
|
|
8112
8112
|
const keys = Object.keys(promisesObj);
|
|
8113
|
-
const
|
|
8114
|
-
return Promise.all(
|
|
8113
|
+
const promises11 = keys.map((key) => promisesObj[key]);
|
|
8114
|
+
return Promise.all(promises11).then((results) => {
|
|
8115
8115
|
const resolvedObj = {};
|
|
8116
8116
|
for (let i = 0; i < keys.length; i++) {
|
|
8117
8117
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -8355,11 +8355,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8355
8355
|
}
|
|
8356
8356
|
return false;
|
|
8357
8357
|
}
|
|
8358
|
-
function prefixIssues(
|
|
8358
|
+
function prefixIssues(path53, issues) {
|
|
8359
8359
|
return issues.map((iss) => {
|
|
8360
8360
|
var _a2;
|
|
8361
8361
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8362
|
-
iss.path.unshift(
|
|
8362
|
+
iss.path.unshift(path53);
|
|
8363
8363
|
return iss;
|
|
8364
8364
|
});
|
|
8365
8365
|
}
|
|
@@ -8548,7 +8548,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8548
8548
|
return issue2.message;
|
|
8549
8549
|
};
|
|
8550
8550
|
const result = { errors: [] };
|
|
8551
|
-
const processError = (error41,
|
|
8551
|
+
const processError = (error41, path53 = []) => {
|
|
8552
8552
|
var _a2, _b;
|
|
8553
8553
|
for (const issue2 of error41.issues) {
|
|
8554
8554
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8558,7 +8558,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8558
8558
|
} else if (issue2.code === "invalid_element") {
|
|
8559
8559
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8560
8560
|
} else {
|
|
8561
|
-
const fullpath = [...
|
|
8561
|
+
const fullpath = [...path53, ...issue2.path];
|
|
8562
8562
|
if (fullpath.length === 0) {
|
|
8563
8563
|
result.errors.push(mapper(issue2));
|
|
8564
8564
|
continue;
|
|
@@ -8588,9 +8588,9 @@ function treeifyError(error40, _mapper) {
|
|
|
8588
8588
|
processError(error40);
|
|
8589
8589
|
return result;
|
|
8590
8590
|
}
|
|
8591
|
-
function toDotPath(
|
|
8591
|
+
function toDotPath(path53) {
|
|
8592
8592
|
const segs = [];
|
|
8593
|
-
for (const seg of
|
|
8593
|
+
for (const seg of path53) {
|
|
8594
8594
|
if (typeof seg === "number")
|
|
8595
8595
|
segs.push(`[${seg}]`);
|
|
8596
8596
|
else if (typeof seg === "symbol")
|
|
@@ -21053,8 +21053,8 @@ var init_acp = __esm({
|
|
|
21053
21053
|
this.#requestHandler = requestHandler;
|
|
21054
21054
|
this.#notificationHandler = notificationHandler;
|
|
21055
21055
|
this.#stream = stream;
|
|
21056
|
-
this.#closedPromise = new Promise((
|
|
21057
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
21056
|
+
this.#closedPromise = new Promise((resolve26) => {
|
|
21057
|
+
this.#abortController.signal.addEventListener("abort", () => resolve26());
|
|
21058
21058
|
});
|
|
21059
21059
|
this.#receive();
|
|
21060
21060
|
}
|
|
@@ -21203,8 +21203,8 @@ var init_acp = __esm({
|
|
|
21203
21203
|
}
|
|
21204
21204
|
async sendRequest(method, params) {
|
|
21205
21205
|
const id = this.#nextRequestId++;
|
|
21206
|
-
const responsePromise = new Promise((
|
|
21207
|
-
this.#pendingResponses.set(id, { resolve:
|
|
21206
|
+
const responsePromise = new Promise((resolve26, reject) => {
|
|
21207
|
+
this.#pendingResponses.set(id, { resolve: resolve26, reject });
|
|
21208
21208
|
});
|
|
21209
21209
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
21210
21210
|
return responsePromise;
|
|
@@ -22073,10 +22073,10 @@ var require_src2 = __commonJS({
|
|
|
22073
22073
|
var fs_1 = __require("fs");
|
|
22074
22074
|
var debug_1 = __importDefault(require_src());
|
|
22075
22075
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
22076
|
-
function check2(
|
|
22077
|
-
log2(`checking %s`,
|
|
22076
|
+
function check2(path53, isFile, isDirectory) {
|
|
22077
|
+
log2(`checking %s`, path53);
|
|
22078
22078
|
try {
|
|
22079
|
-
const stat2 = fs_1.statSync(
|
|
22079
|
+
const stat2 = fs_1.statSync(path53);
|
|
22080
22080
|
if (stat2.isFile() && isFile) {
|
|
22081
22081
|
log2(`[OK] path represents a file`);
|
|
22082
22082
|
return true;
|
|
@@ -22096,8 +22096,8 @@ var require_src2 = __commonJS({
|
|
|
22096
22096
|
throw e;
|
|
22097
22097
|
}
|
|
22098
22098
|
}
|
|
22099
|
-
function exists2(
|
|
22100
|
-
return check2(
|
|
22099
|
+
function exists2(path53, type = exports.READABLE) {
|
|
22100
|
+
return check2(path53, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
22101
22101
|
}
|
|
22102
22102
|
exports.exists = exists2;
|
|
22103
22103
|
exports.FILE = 1;
|
|
@@ -22446,10 +22446,10 @@ async function killChildProcessTreeGracefully(child, graceMs = ACP_PROCESS_TREE_
|
|
|
22446
22446
|
}
|
|
22447
22447
|
await killProcessTree(pid, "SIGTERM");
|
|
22448
22448
|
if (graceMs <= 0) return;
|
|
22449
|
-
const exited = new Promise((
|
|
22450
|
-
child.once("exit", () =>
|
|
22449
|
+
const exited = new Promise((resolve26) => {
|
|
22450
|
+
child.once("exit", () => resolve26());
|
|
22451
22451
|
});
|
|
22452
|
-
await Promise.race([exited, new Promise((
|
|
22452
|
+
await Promise.race([exited, new Promise((resolve26) => setTimeout(resolve26, graceMs))]);
|
|
22453
22453
|
if (child.exitCode == null && child.signalCode == null) {
|
|
22454
22454
|
await killProcessTree(pid, "SIGKILL");
|
|
22455
22455
|
}
|
|
@@ -22466,8 +22466,8 @@ async function gracefulAcpSubprocessDisconnect(params) {
|
|
|
22466
22466
|
await transport.closeSession?.(sessionId);
|
|
22467
22467
|
} catch {
|
|
22468
22468
|
}
|
|
22469
|
-
await new Promise((
|
|
22470
|
-
const timer = setTimeout(
|
|
22469
|
+
await new Promise((resolve26) => {
|
|
22470
|
+
const timer = setTimeout(resolve26, ACP_GRACEFUL_SESSION_CLOSE_WAIT_MS);
|
|
22471
22471
|
timer.unref?.();
|
|
22472
22472
|
});
|
|
22473
22473
|
}
|
|
@@ -22733,6 +22733,238 @@ var WebSocketMessageSchema = external_exports.object({
|
|
|
22733
22733
|
error: external_exports.string().optional()
|
|
22734
22734
|
});
|
|
22735
22735
|
|
|
22736
|
+
// ../types/src/integrations/link-detection/linear.ts
|
|
22737
|
+
function detectLinearLink(url2) {
|
|
22738
|
+
const linearMatch = url2.match(
|
|
22739
|
+
/https?:\/\/(?:app\.)?linear\.app\/([^/]+)\/issue\/([A-Z]+-\d+)/i
|
|
22740
|
+
);
|
|
22741
|
+
if (linearMatch) {
|
|
22742
|
+
return {
|
|
22743
|
+
url: url2,
|
|
22744
|
+
integrationType: "linear",
|
|
22745
|
+
resourceType: "work-item",
|
|
22746
|
+
resourceId: linearMatch[2],
|
|
22747
|
+
workspaceId: linearMatch[1]
|
|
22748
|
+
};
|
|
22749
|
+
}
|
|
22750
|
+
return null;
|
|
22751
|
+
}
|
|
22752
|
+
|
|
22753
|
+
// ../types/src/integrations/link-detection/github.ts
|
|
22754
|
+
function detectGitHubLink(url2) {
|
|
22755
|
+
const githubIssueMatch = url2.match(
|
|
22756
|
+
/https?:\/\/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)/i
|
|
22757
|
+
);
|
|
22758
|
+
if (githubIssueMatch) {
|
|
22759
|
+
return {
|
|
22760
|
+
url: url2,
|
|
22761
|
+
integrationType: "github",
|
|
22762
|
+
resourceType: "issue",
|
|
22763
|
+
resourceId: githubIssueMatch[3],
|
|
22764
|
+
owner: githubIssueMatch[1],
|
|
22765
|
+
repo: githubIssueMatch[2]
|
|
22766
|
+
};
|
|
22767
|
+
}
|
|
22768
|
+
const githubPRMatch = url2.match(
|
|
22769
|
+
/https?:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/i
|
|
22770
|
+
);
|
|
22771
|
+
if (githubPRMatch) {
|
|
22772
|
+
return {
|
|
22773
|
+
url: url2,
|
|
22774
|
+
integrationType: "github",
|
|
22775
|
+
resourceType: "pull-request",
|
|
22776
|
+
resourceId: githubPRMatch[3],
|
|
22777
|
+
owner: githubPRMatch[1],
|
|
22778
|
+
repo: githubPRMatch[2]
|
|
22779
|
+
};
|
|
22780
|
+
}
|
|
22781
|
+
return null;
|
|
22782
|
+
}
|
|
22783
|
+
|
|
22784
|
+
// ../types/src/integrations/link-detection/jira.ts
|
|
22785
|
+
function detectJIRALink(url2) {
|
|
22786
|
+
const jiraMatch = url2.match(
|
|
22787
|
+
/https?:\/\/([^/]+)\.atlassian\.net\/(?:browse|jira\/software\/projects\/[^/]+\/issues)\/([A-Z]+-\d+)/i
|
|
22788
|
+
);
|
|
22789
|
+
if (jiraMatch) {
|
|
22790
|
+
return {
|
|
22791
|
+
url: url2,
|
|
22792
|
+
integrationType: "jira",
|
|
22793
|
+
resourceType: "issue",
|
|
22794
|
+
resourceId: jiraMatch[2],
|
|
22795
|
+
projectKey: jiraMatch[2].split("-")[0]
|
|
22796
|
+
};
|
|
22797
|
+
}
|
|
22798
|
+
return null;
|
|
22799
|
+
}
|
|
22800
|
+
|
|
22801
|
+
// ../types/src/integrations/link-detection/notion.ts
|
|
22802
|
+
function formatNotionPageId(hex) {
|
|
22803
|
+
if (hex.length !== 32) return hex;
|
|
22804
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
22805
|
+
}
|
|
22806
|
+
function detectNotionLink(url2) {
|
|
22807
|
+
const standardMatch = url2.match(
|
|
22808
|
+
/https?:\/\/(?:www\.)?notion\.(?:so|site)\/(?:[^/#?]+\/)?(?:[^/#?-]+-)?([a-f0-9]{32})/i
|
|
22809
|
+
);
|
|
22810
|
+
if (standardMatch) {
|
|
22811
|
+
return {
|
|
22812
|
+
url: url2,
|
|
22813
|
+
integrationType: "notion",
|
|
22814
|
+
resourceType: "page",
|
|
22815
|
+
resourceId: formatNotionPageId(standardMatch[1])
|
|
22816
|
+
};
|
|
22817
|
+
}
|
|
22818
|
+
const siteMatch = url2.match(
|
|
22819
|
+
/https?:\/\/([^.]+)\.notion\.(?:so|site)\/(?:[^/#?-]+-)?([a-f0-9]{32})/i
|
|
22820
|
+
);
|
|
22821
|
+
if (siteMatch) {
|
|
22822
|
+
return {
|
|
22823
|
+
url: url2,
|
|
22824
|
+
integrationType: "notion",
|
|
22825
|
+
resourceType: "page",
|
|
22826
|
+
resourceId: formatNotionPageId(siteMatch[2]),
|
|
22827
|
+
notionWorkspaceId: siteMatch[1]
|
|
22828
|
+
};
|
|
22829
|
+
}
|
|
22830
|
+
return null;
|
|
22831
|
+
}
|
|
22832
|
+
|
|
22833
|
+
// ../types/src/integrations/link-detection/slack.ts
|
|
22834
|
+
function detectSlackLink(url2) {
|
|
22835
|
+
const archiveThreadMatch = url2.match(
|
|
22836
|
+
/https?:\/\/(?:([^./]+)\.)?slack\.com\/archives\/([A-Z0-9]+)\/p(\d+)(?:\?.*)?$/i
|
|
22837
|
+
);
|
|
22838
|
+
if (archiveThreadMatch) {
|
|
22839
|
+
return {
|
|
22840
|
+
url: url2,
|
|
22841
|
+
integrationType: "slack",
|
|
22842
|
+
resourceType: "thread",
|
|
22843
|
+
resourceId: `${archiveThreadMatch[2]}-${archiveThreadMatch[3]}`,
|
|
22844
|
+
isChannel: false
|
|
22845
|
+
};
|
|
22846
|
+
}
|
|
22847
|
+
const appThreadMatch = url2.match(
|
|
22848
|
+
/https?:\/\/app\.slack\.com\/client\/([^/]+)\/([A-Z0-9]+)\/thread\/[A-Z0-9]+-(\d+)/i
|
|
22849
|
+
);
|
|
22850
|
+
if (appThreadMatch) {
|
|
22851
|
+
return {
|
|
22852
|
+
url: url2,
|
|
22853
|
+
integrationType: "slack",
|
|
22854
|
+
resourceType: "thread",
|
|
22855
|
+
resourceId: `${appThreadMatch[2]}-${appThreadMatch[3]}`,
|
|
22856
|
+
isChannel: false
|
|
22857
|
+
};
|
|
22858
|
+
}
|
|
22859
|
+
const channelOnlyMatch = url2.match(
|
|
22860
|
+
/https?:\/\/(?:app\.)?(?:([^./]+)\.)?slack\.com\/archives\/([A-Z0-9]+)\/?(\?.*)?$/i
|
|
22861
|
+
);
|
|
22862
|
+
if (channelOnlyMatch && !url2.includes("/p")) {
|
|
22863
|
+
return {
|
|
22864
|
+
url: url2,
|
|
22865
|
+
integrationType: "slack",
|
|
22866
|
+
resourceType: "channel",
|
|
22867
|
+
resourceId: channelOnlyMatch[2],
|
|
22868
|
+
isChannel: true
|
|
22869
|
+
};
|
|
22870
|
+
}
|
|
22871
|
+
return null;
|
|
22872
|
+
}
|
|
22873
|
+
|
|
22874
|
+
// ../types/src/integrations/link-detection/zoom.ts
|
|
22875
|
+
function detectZoomLink(url2) {
|
|
22876
|
+
try {
|
|
22877
|
+
const u = new URL(url2);
|
|
22878
|
+
const host = u.hostname.toLowerCase();
|
|
22879
|
+
if (!host.endsWith("zoom.us") && !host.endsWith("zoom.com")) return null;
|
|
22880
|
+
const pathParts = u.pathname.split("/").filter(Boolean);
|
|
22881
|
+
if (pathParts.length >= 2 && (pathParts[0] === "j" || pathParts[0] === "s" || pathParts[0] === "my")) {
|
|
22882
|
+
const meetingId = pathParts[1].replace(/\s/g, "");
|
|
22883
|
+
if (meetingId.length >= 9) {
|
|
22884
|
+
return {
|
|
22885
|
+
url: url2,
|
|
22886
|
+
integrationType: "zoom",
|
|
22887
|
+
resourceType: "meeting",
|
|
22888
|
+
resourceId: meetingId,
|
|
22889
|
+
zoomMeetingId: meetingId
|
|
22890
|
+
};
|
|
22891
|
+
}
|
|
22892
|
+
}
|
|
22893
|
+
} catch {
|
|
22894
|
+
}
|
|
22895
|
+
return null;
|
|
22896
|
+
}
|
|
22897
|
+
|
|
22898
|
+
// ../types/src/integrations/link-detection/asana.ts
|
|
22899
|
+
var ASANA_TASK_GID = /\d{10,}/;
|
|
22900
|
+
function parseAsanaTaskGid(segment) {
|
|
22901
|
+
const trimmed2 = segment.trim();
|
|
22902
|
+
if (!ASANA_TASK_GID.test(trimmed2)) return null;
|
|
22903
|
+
return trimmed2;
|
|
22904
|
+
}
|
|
22905
|
+
function detectAsanaLink(url2) {
|
|
22906
|
+
const v1ProjectMatch = url2.match(
|
|
22907
|
+
/https?:\/\/app\.asana\.com\/1\/[^/]+\/project\/([^/?#]+)\/task\/([^/?#]+)/i
|
|
22908
|
+
);
|
|
22909
|
+
if (v1ProjectMatch) {
|
|
22910
|
+
const taskGid = parseAsanaTaskGid(v1ProjectMatch[2]);
|
|
22911
|
+
if (!taskGid) return null;
|
|
22912
|
+
return {
|
|
22913
|
+
url: url2,
|
|
22914
|
+
integrationType: "asana",
|
|
22915
|
+
resourceType: "task",
|
|
22916
|
+
resourceId: taskGid,
|
|
22917
|
+
asanaProjectGid: v1ProjectMatch[1]
|
|
22918
|
+
};
|
|
22919
|
+
}
|
|
22920
|
+
const v1TaskMatch = url2.match(/https?:\/\/app\.asana\.com\/1\/[^/]+(?:\/[^/]+)*\/task\/([^/?#]+)/i);
|
|
22921
|
+
if (v1TaskMatch) {
|
|
22922
|
+
const taskGid = parseAsanaTaskGid(v1TaskMatch[1]);
|
|
22923
|
+
if (!taskGid) return null;
|
|
22924
|
+
return {
|
|
22925
|
+
url: url2,
|
|
22926
|
+
integrationType: "asana",
|
|
22927
|
+
resourceType: "task",
|
|
22928
|
+
resourceId: taskGid
|
|
22929
|
+
};
|
|
22930
|
+
}
|
|
22931
|
+
const legacyMatch = url2.match(/https?:\/\/app\.asana\.com\/0\/([^/?#]+)\/([^/?#]+)/i);
|
|
22932
|
+
if (legacyMatch) {
|
|
22933
|
+
const projectGid = legacyMatch[1];
|
|
22934
|
+
const taskGid = parseAsanaTaskGid(legacyMatch[2]);
|
|
22935
|
+
if (!taskGid) return null;
|
|
22936
|
+
if (projectGid === "inbox" || projectGid === "my_tasks") {
|
|
22937
|
+
return null;
|
|
22938
|
+
}
|
|
22939
|
+
return {
|
|
22940
|
+
url: url2,
|
|
22941
|
+
integrationType: "asana",
|
|
22942
|
+
resourceType: "task",
|
|
22943
|
+
resourceId: taskGid,
|
|
22944
|
+
asanaProjectGid: projectGid === "0" ? void 0 : projectGid
|
|
22945
|
+
};
|
|
22946
|
+
}
|
|
22947
|
+
return null;
|
|
22948
|
+
}
|
|
22949
|
+
|
|
22950
|
+
// ../types/src/integrations/link-detection/index.ts
|
|
22951
|
+
function detectIntegrationLink(url2) {
|
|
22952
|
+
return detectLinearLink(url2) || detectGitHubLink(url2) || detectJIRALink(url2) || detectNotionLink(url2) || detectSlackLink(url2) || detectZoomLink(url2) || detectAsanaLink(url2);
|
|
22953
|
+
}
|
|
22954
|
+
function extractIntegrationLinks(text) {
|
|
22955
|
+
const urlRegex = /https?:\/\/[^\s<>"{}|\\^`[\]]+/gi;
|
|
22956
|
+
const urls = text.match(urlRegex) || [];
|
|
22957
|
+
const links = [];
|
|
22958
|
+
for (const url2 of urls) {
|
|
22959
|
+
const detected = detectIntegrationLink(url2);
|
|
22960
|
+
if (detected) links.push(detected);
|
|
22961
|
+
}
|
|
22962
|
+
return links;
|
|
22963
|
+
}
|
|
22964
|
+
function extractFetchableIntegrationLinks(text) {
|
|
22965
|
+
return extractIntegrationLinks(text).filter((link) => !(link.integrationType === "slack" && link.isChannel));
|
|
22966
|
+
}
|
|
22967
|
+
|
|
22736
22968
|
// ../types/src/checkpoints.ts
|
|
22737
22969
|
init_zod();
|
|
22738
22970
|
var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
|
|
@@ -22940,9 +23172,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
22940
23172
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
22941
23173
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
22942
23174
|
if (!rawPath || !summary) continue;
|
|
22943
|
-
const
|
|
22944
|
-
if (!
|
|
22945
|
-
rows.push({ path:
|
|
23175
|
+
const path53 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
23176
|
+
if (!path53) continue;
|
|
23177
|
+
rows.push({ path: path53, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
22946
23178
|
}
|
|
22947
23179
|
return rows;
|
|
22948
23180
|
}
|
|
@@ -23160,6 +23392,16 @@ var GitRepoMetaSchema = external_exports.object({
|
|
|
23160
23392
|
updatedAt: external_exports.string()
|
|
23161
23393
|
});
|
|
23162
23394
|
|
|
23395
|
+
// ../types/src/mcp/bridge-mcp-constants.ts
|
|
23396
|
+
var GET_INTEGRATION_CONTENT_TOOL = "get_integration_content";
|
|
23397
|
+
var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
|
|
23398
|
+
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
|
|
23399
|
+
var BRIDGE_MCP_TOOL_LABELS = {
|
|
23400
|
+
[GET_INTEGRATION_CONTENT_TOOL]: "Fetch external ticket content",
|
|
23401
|
+
[LIST_PARENT_SESSION_PROMPTS_TOOL]: "List parent session prompts",
|
|
23402
|
+
[GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL]: "Read parent session transcript"
|
|
23403
|
+
};
|
|
23404
|
+
|
|
23163
23405
|
// ../types/src/claude-code-permission-mode.ts
|
|
23164
23406
|
var CLAUDE_CODE_PERMISSION_MODES = [
|
|
23165
23407
|
"default",
|
|
@@ -23386,11 +23628,11 @@ function createSdkStdioExtNotificationHandler(options) {
|
|
|
23386
23628
|
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
23387
23629
|
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
23388
23630
|
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
23389
|
-
return new Promise((
|
|
23390
|
-
pending.set(requestId, { resolve:
|
|
23631
|
+
return new Promise((resolve26) => {
|
|
23632
|
+
pending.set(requestId, { resolve: resolve26, params: paramsRecord });
|
|
23391
23633
|
if (onRequest == null) {
|
|
23392
23634
|
pending.delete(requestId);
|
|
23393
|
-
|
|
23635
|
+
resolve26({ outcome: { outcome: "denied" } });
|
|
23394
23636
|
return;
|
|
23395
23637
|
}
|
|
23396
23638
|
try {
|
|
@@ -23934,10 +24176,10 @@ function createSdkStdioInitSettle(child) {
|
|
|
23934
24176
|
forceAcpSubprocessDisconnect(child);
|
|
23935
24177
|
reject(err);
|
|
23936
24178
|
},
|
|
23937
|
-
settleResolve(
|
|
24179
|
+
settleResolve(resolve26, handle) {
|
|
23938
24180
|
if (initSettled) return;
|
|
23939
24181
|
initSettled = true;
|
|
23940
|
-
|
|
24182
|
+
resolve26(handle);
|
|
23941
24183
|
}
|
|
23942
24184
|
};
|
|
23943
24185
|
}
|
|
@@ -24006,7 +24248,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
24006
24248
|
onFileChange,
|
|
24007
24249
|
stderrCapture
|
|
24008
24250
|
});
|
|
24009
|
-
return new Promise((
|
|
24251
|
+
return new Promise((resolve26, reject) => {
|
|
24010
24252
|
const init = createSdkStdioInitSettle(child);
|
|
24011
24253
|
child.on("error", (err) => {
|
|
24012
24254
|
init.settleReject(reject, new Error(formatSpawnError(err, command[0])));
|
|
@@ -24031,7 +24273,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
24031
24273
|
protocolVersion: PROTOCOL_VERSION2
|
|
24032
24274
|
});
|
|
24033
24275
|
init.settleResolve(
|
|
24034
|
-
|
|
24276
|
+
resolve26,
|
|
24035
24277
|
createSdkStdioHandle({
|
|
24036
24278
|
child,
|
|
24037
24279
|
sessionId: established.sessionId,
|
|
@@ -24139,7 +24381,7 @@ async function proxyToLocal(request) {
|
|
|
24139
24381
|
};
|
|
24140
24382
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
24141
24383
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
24142
|
-
const once = await new Promise((
|
|
24384
|
+
const once = await new Promise((resolve26) => {
|
|
24143
24385
|
const req = mod.request(opts, (res) => {
|
|
24144
24386
|
const chunks = [];
|
|
24145
24387
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -24150,7 +24392,7 @@ async function proxyToLocal(request) {
|
|
|
24150
24392
|
if (typeof v === "string") headers[k] = v;
|
|
24151
24393
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
24152
24394
|
}
|
|
24153
|
-
|
|
24395
|
+
resolve26({
|
|
24154
24396
|
id: request.id,
|
|
24155
24397
|
statusCode: res.statusCode ?? 0,
|
|
24156
24398
|
headers,
|
|
@@ -24159,7 +24401,7 @@ async function proxyToLocal(request) {
|
|
|
24159
24401
|
});
|
|
24160
24402
|
});
|
|
24161
24403
|
req.on("error", (err) => {
|
|
24162
|
-
|
|
24404
|
+
resolve26({
|
|
24163
24405
|
id: request.id,
|
|
24164
24406
|
statusCode: 0,
|
|
24165
24407
|
headers: {},
|
|
@@ -24241,8 +24483,8 @@ function randomSecret() {
|
|
|
24241
24483
|
}
|
|
24242
24484
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
24243
24485
|
}
|
|
24244
|
-
async function requestPreviewApi(port, secret, method,
|
|
24245
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
24486
|
+
async function requestPreviewApi(port, secret, method, path53, body) {
|
|
24487
|
+
const url2 = `http://127.0.0.1:${port}${path53}`;
|
|
24246
24488
|
const headers = {
|
|
24247
24489
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
24248
24490
|
"Content-Type": "application/json"
|
|
@@ -24254,7 +24496,7 @@ async function requestPreviewApi(port, secret, method, path46, body) {
|
|
|
24254
24496
|
});
|
|
24255
24497
|
const data = await res.json().catch(() => ({}));
|
|
24256
24498
|
if (!res.ok) {
|
|
24257
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
24499
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path53}: ${res.status}`);
|
|
24258
24500
|
}
|
|
24259
24501
|
return data;
|
|
24260
24502
|
}
|
|
@@ -24469,7 +24711,7 @@ function installBridgeProcessResilience() {
|
|
|
24469
24711
|
}
|
|
24470
24712
|
|
|
24471
24713
|
// src/cli-version.ts
|
|
24472
|
-
var CLI_VERSION = "0.1.
|
|
24714
|
+
var CLI_VERSION = "0.1.50".length > 0 ? "0.1.50" : "0.0.0-dev";
|
|
24473
24715
|
|
|
24474
24716
|
// src/connection/heartbeat/constants.ts
|
|
24475
24717
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -24910,14 +25152,14 @@ var baseOpen = async (options) => {
|
|
|
24910
25152
|
}
|
|
24911
25153
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
24912
25154
|
if (options.wait) {
|
|
24913
|
-
return new Promise((
|
|
25155
|
+
return new Promise((resolve26, reject) => {
|
|
24914
25156
|
subprocess.once("error", reject);
|
|
24915
25157
|
subprocess.once("close", (exitCode) => {
|
|
24916
25158
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
24917
25159
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
24918
25160
|
return;
|
|
24919
25161
|
}
|
|
24920
|
-
|
|
25162
|
+
resolve26(subprocess);
|
|
24921
25163
|
});
|
|
24922
25164
|
});
|
|
24923
25165
|
}
|
|
@@ -25461,8 +25703,8 @@ function runPendingAuth(options) {
|
|
|
25461
25703
|
let hasOpenedBrowser = false;
|
|
25462
25704
|
let resolved = false;
|
|
25463
25705
|
let resolveAuth;
|
|
25464
|
-
const authPromise = new Promise((
|
|
25465
|
-
resolveAuth =
|
|
25706
|
+
const authPromise = new Promise((resolve26) => {
|
|
25707
|
+
resolveAuth = resolve26;
|
|
25466
25708
|
});
|
|
25467
25709
|
let reconnectAttempt = 0;
|
|
25468
25710
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -25613,7 +25855,7 @@ import sqliteWasm from "node-sqlite3-wasm";
|
|
|
25613
25855
|
|
|
25614
25856
|
// src/runtime/yield-to-event-loop.ts
|
|
25615
25857
|
function yieldToEventLoop() {
|
|
25616
|
-
return new Promise((
|
|
25858
|
+
return new Promise((resolve26) => setImmediate(resolve26));
|
|
25617
25859
|
}
|
|
25618
25860
|
|
|
25619
25861
|
// src/sqlite/cli-sqlite-paths.ts
|
|
@@ -26777,7 +27019,7 @@ async function createCursorAcpClient(options) {
|
|
|
26777
27019
|
onFileChange,
|
|
26778
27020
|
stderrCapture
|
|
26779
27021
|
});
|
|
26780
|
-
return new Promise((
|
|
27022
|
+
return new Promise((resolve26, reject) => {
|
|
26781
27023
|
child.on("error", (err) => {
|
|
26782
27024
|
killChildProcessTree(child, "SIGKILL");
|
|
26783
27025
|
reject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -26789,7 +27031,7 @@ async function createCursorAcpClient(options) {
|
|
|
26789
27031
|
sessionCtx,
|
|
26790
27032
|
incomingDeps: { dbgFs, sessionCtx, onSessionUpdate, onRequest }
|
|
26791
27033
|
});
|
|
26792
|
-
|
|
27034
|
+
resolve26(
|
|
26793
27035
|
createCursorAcpHandle({
|
|
26794
27036
|
child,
|
|
26795
27037
|
sessionId: established.sessionId,
|
|
@@ -27727,7 +27969,7 @@ function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
|
|
|
27727
27969
|
}
|
|
27728
27970
|
|
|
27729
27971
|
// src/mcp/bridge-mcp-constants.ts
|
|
27730
|
-
var
|
|
27972
|
+
var BRIDGE_MCP_SERVER_NAME2 = "buildautomaton-bridge";
|
|
27731
27973
|
|
|
27732
27974
|
// src/mcp/resolve-bridge-mcp-server-path.ts
|
|
27733
27975
|
import { dirname as dirname4, join as join2 } from "node:path";
|
|
@@ -27742,7 +27984,7 @@ function buildAcpMcpServers(bridgeAccessPort) {
|
|
|
27742
27984
|
if (!Number.isFinite(bridgeAccessPort) || bridgeAccessPort <= 0) return [];
|
|
27743
27985
|
return [
|
|
27744
27986
|
{
|
|
27745
|
-
name:
|
|
27987
|
+
name: BRIDGE_MCP_SERVER_NAME2,
|
|
27746
27988
|
command: process.execPath,
|
|
27747
27989
|
args: [resolveBridgeMcpServerScriptPath(), String(bridgeAccessPort)],
|
|
27748
27990
|
env: []
|
|
@@ -27995,8 +28237,8 @@ function pathspec(...paths) {
|
|
|
27995
28237
|
cache.set(key, paths);
|
|
27996
28238
|
return key;
|
|
27997
28239
|
}
|
|
27998
|
-
function isPathSpec(
|
|
27999
|
-
return
|
|
28240
|
+
function isPathSpec(path53) {
|
|
28241
|
+
return path53 instanceof String && cache.has(path53);
|
|
28000
28242
|
}
|
|
28001
28243
|
function toPaths(pathSpec) {
|
|
28002
28244
|
return cache.get(pathSpec) || [];
|
|
@@ -28085,8 +28327,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
28085
28327
|
function forEachLineWithContent(input, callback) {
|
|
28086
28328
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
28087
28329
|
}
|
|
28088
|
-
function folderExists(
|
|
28089
|
-
return (0, import_file_exists.exists)(
|
|
28330
|
+
function folderExists(path53) {
|
|
28331
|
+
return (0, import_file_exists.exists)(path53, import_file_exists.FOLDER);
|
|
28090
28332
|
}
|
|
28091
28333
|
function append(target, item) {
|
|
28092
28334
|
if (Array.isArray(target)) {
|
|
@@ -28490,8 +28732,8 @@ function checkIsRepoRootTask() {
|
|
|
28490
28732
|
commands,
|
|
28491
28733
|
format: "utf-8",
|
|
28492
28734
|
onError,
|
|
28493
|
-
parser(
|
|
28494
|
-
return /^\.(git)?$/.test(
|
|
28735
|
+
parser(path53) {
|
|
28736
|
+
return /^\.(git)?$/.test(path53.trim());
|
|
28495
28737
|
}
|
|
28496
28738
|
};
|
|
28497
28739
|
}
|
|
@@ -28925,11 +29167,11 @@ function parseGrep(grep) {
|
|
|
28925
29167
|
const paths = /* @__PURE__ */ new Set();
|
|
28926
29168
|
const results = {};
|
|
28927
29169
|
forEachLineWithContent(grep, (input) => {
|
|
28928
|
-
const [
|
|
28929
|
-
paths.add(
|
|
28930
|
-
(results[
|
|
29170
|
+
const [path53, line, preview] = input.split(NULL);
|
|
29171
|
+
paths.add(path53);
|
|
29172
|
+
(results[path53] = results[path53] || []).push({
|
|
28931
29173
|
line: asNumber(line),
|
|
28932
|
-
path:
|
|
29174
|
+
path: path53,
|
|
28933
29175
|
preview
|
|
28934
29176
|
});
|
|
28935
29177
|
});
|
|
@@ -29694,14 +29936,14 @@ var init_hash_object = __esm2({
|
|
|
29694
29936
|
init_task();
|
|
29695
29937
|
}
|
|
29696
29938
|
});
|
|
29697
|
-
function parseInit(bare,
|
|
29939
|
+
function parseInit(bare, path53, text) {
|
|
29698
29940
|
const response = String(text).trim();
|
|
29699
29941
|
let result;
|
|
29700
29942
|
if (result = initResponseRegex.exec(response)) {
|
|
29701
|
-
return new InitSummary(bare,
|
|
29943
|
+
return new InitSummary(bare, path53, false, result[1]);
|
|
29702
29944
|
}
|
|
29703
29945
|
if (result = reInitResponseRegex.exec(response)) {
|
|
29704
|
-
return new InitSummary(bare,
|
|
29946
|
+
return new InitSummary(bare, path53, true, result[1]);
|
|
29705
29947
|
}
|
|
29706
29948
|
let gitDir = "";
|
|
29707
29949
|
const tokens = response.split(" ");
|
|
@@ -29712,7 +29954,7 @@ function parseInit(bare, path46, text) {
|
|
|
29712
29954
|
break;
|
|
29713
29955
|
}
|
|
29714
29956
|
}
|
|
29715
|
-
return new InitSummary(bare,
|
|
29957
|
+
return new InitSummary(bare, path53, /^re/i.test(response), gitDir);
|
|
29716
29958
|
}
|
|
29717
29959
|
var InitSummary;
|
|
29718
29960
|
var initResponseRegex;
|
|
@@ -29721,9 +29963,9 @@ var init_InitSummary = __esm2({
|
|
|
29721
29963
|
"src/lib/responses/InitSummary.ts"() {
|
|
29722
29964
|
"use strict";
|
|
29723
29965
|
InitSummary = class {
|
|
29724
|
-
constructor(bare,
|
|
29966
|
+
constructor(bare, path53, existing, gitDir) {
|
|
29725
29967
|
this.bare = bare;
|
|
29726
|
-
this.path =
|
|
29968
|
+
this.path = path53;
|
|
29727
29969
|
this.existing = existing;
|
|
29728
29970
|
this.gitDir = gitDir;
|
|
29729
29971
|
}
|
|
@@ -29735,7 +29977,7 @@ var init_InitSummary = __esm2({
|
|
|
29735
29977
|
function hasBareCommand(command) {
|
|
29736
29978
|
return command.includes(bareCommand);
|
|
29737
29979
|
}
|
|
29738
|
-
function initTask(bare = false,
|
|
29980
|
+
function initTask(bare = false, path53, customArgs) {
|
|
29739
29981
|
const commands = ["init", ...customArgs];
|
|
29740
29982
|
if (bare && !hasBareCommand(commands)) {
|
|
29741
29983
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29744,7 +29986,7 @@ function initTask(bare = false, path46, customArgs) {
|
|
|
29744
29986
|
commands,
|
|
29745
29987
|
format: "utf-8",
|
|
29746
29988
|
parser(text) {
|
|
29747
|
-
return parseInit(commands.includes("--bare"),
|
|
29989
|
+
return parseInit(commands.includes("--bare"), path53, text);
|
|
29748
29990
|
}
|
|
29749
29991
|
};
|
|
29750
29992
|
}
|
|
@@ -30560,12 +30802,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
30560
30802
|
"use strict";
|
|
30561
30803
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
30562
30804
|
FileStatusSummary = class {
|
|
30563
|
-
constructor(
|
|
30564
|
-
this.path =
|
|
30805
|
+
constructor(path53, index, working_dir) {
|
|
30806
|
+
this.path = path53;
|
|
30565
30807
|
this.index = index;
|
|
30566
30808
|
this.working_dir = working_dir;
|
|
30567
30809
|
if (index === "R" || working_dir === "R") {
|
|
30568
|
-
const detail = fromPathRegex.exec(
|
|
30810
|
+
const detail = fromPathRegex.exec(path53) || [null, path53, path53];
|
|
30569
30811
|
this.from = detail[2] || "";
|
|
30570
30812
|
this.path = detail[1] || "";
|
|
30571
30813
|
}
|
|
@@ -30596,14 +30838,14 @@ function splitLine(result, lineStr) {
|
|
|
30596
30838
|
default:
|
|
30597
30839
|
return;
|
|
30598
30840
|
}
|
|
30599
|
-
function data(index, workingDir,
|
|
30841
|
+
function data(index, workingDir, path53) {
|
|
30600
30842
|
const raw = `${index}${workingDir}`;
|
|
30601
30843
|
const handler = parsers6.get(raw);
|
|
30602
30844
|
if (handler) {
|
|
30603
|
-
handler(result,
|
|
30845
|
+
handler(result, path53);
|
|
30604
30846
|
}
|
|
30605
30847
|
if (raw !== "##" && raw !== "!!") {
|
|
30606
|
-
result.files.push(new FileStatusSummary(
|
|
30848
|
+
result.files.push(new FileStatusSummary(path53, index, workingDir));
|
|
30607
30849
|
}
|
|
30608
30850
|
}
|
|
30609
30851
|
}
|
|
@@ -30912,9 +31154,9 @@ var init_simple_git_api = __esm2({
|
|
|
30912
31154
|
next
|
|
30913
31155
|
);
|
|
30914
31156
|
}
|
|
30915
|
-
hashObject(
|
|
31157
|
+
hashObject(path53, write) {
|
|
30916
31158
|
return this._runTask(
|
|
30917
|
-
hashObjectTask(
|
|
31159
|
+
hashObjectTask(path53, write === true),
|
|
30918
31160
|
trailingFunctionArgument(arguments)
|
|
30919
31161
|
);
|
|
30920
31162
|
}
|
|
@@ -31267,8 +31509,8 @@ var init_branch = __esm2({
|
|
|
31267
31509
|
}
|
|
31268
31510
|
});
|
|
31269
31511
|
function toPath(input) {
|
|
31270
|
-
const
|
|
31271
|
-
return
|
|
31512
|
+
const path53 = input.trim().replace(/^["']|["']$/g, "");
|
|
31513
|
+
return path53 && normalize3(path53);
|
|
31272
31514
|
}
|
|
31273
31515
|
var parseCheckIgnore;
|
|
31274
31516
|
var init_CheckIgnore = __esm2({
|
|
@@ -31582,8 +31824,8 @@ __export2(sub_module_exports, {
|
|
|
31582
31824
|
subModuleTask: () => subModuleTask,
|
|
31583
31825
|
updateSubModuleTask: () => updateSubModuleTask
|
|
31584
31826
|
});
|
|
31585
|
-
function addSubModuleTask(repo,
|
|
31586
|
-
return subModuleTask(["add", repo,
|
|
31827
|
+
function addSubModuleTask(repo, path53) {
|
|
31828
|
+
return subModuleTask(["add", repo, path53]);
|
|
31587
31829
|
}
|
|
31588
31830
|
function initSubModuleTask(customArgs) {
|
|
31589
31831
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -31916,8 +32158,8 @@ var require_git = __commonJS2({
|
|
|
31916
32158
|
}
|
|
31917
32159
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
31918
32160
|
};
|
|
31919
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
31920
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
32161
|
+
Git2.prototype.submoduleAdd = function(repo, path53, then) {
|
|
32162
|
+
return this._runTask(addSubModuleTask2(repo, path53), trailingFunctionArgument2(arguments));
|
|
31921
32163
|
};
|
|
31922
32164
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
31923
32165
|
return this._runTask(
|
|
@@ -32554,14 +32796,14 @@ async function runGitTask(fn) {
|
|
|
32554
32796
|
}
|
|
32555
32797
|
async function yieldToEventLoop2() {
|
|
32556
32798
|
throwIfGitShutdownRequested();
|
|
32557
|
-
await new Promise((
|
|
32558
|
-
setImmediate(
|
|
32799
|
+
await new Promise((resolve26) => {
|
|
32800
|
+
setImmediate(resolve26);
|
|
32559
32801
|
});
|
|
32560
32802
|
throwIfGitShutdownRequested();
|
|
32561
32803
|
}
|
|
32562
32804
|
async function forEachWithGitYield(items, fn) {
|
|
32563
32805
|
for (let i = 0; i < items.length; i++) {
|
|
32564
|
-
|
|
32806
|
+
await yieldToEventLoop2();
|
|
32565
32807
|
await fn(items[i], i);
|
|
32566
32808
|
}
|
|
32567
32809
|
}
|
|
@@ -32880,9 +33122,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32880
33122
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32881
33123
|
async function putEncryptedChangeSummaryRows(params) {
|
|
32882
33124
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32883
|
-
const entries = params.rows.map(({ path:
|
|
33125
|
+
const entries = params.rows.map(({ path: path53, summary }) => {
|
|
32884
33126
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32885
|
-
return { path:
|
|
33127
|
+
return { path: path53, summary: JSON.stringify(enc) };
|
|
32886
33128
|
});
|
|
32887
33129
|
const res = await fetch(
|
|
32888
33130
|
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -33129,7 +33371,15 @@ async function fetchInternalApiJson(params) {
|
|
|
33129
33371
|
const token = params.getCloudAccessToken();
|
|
33130
33372
|
if (!token) return { ok: false, error: "Missing cloud access token." };
|
|
33131
33373
|
const url2 = `${internalApiBase(params.cloudApiBaseUrl)}${params.path}`;
|
|
33132
|
-
const
|
|
33374
|
+
const method = params.method ?? "GET";
|
|
33375
|
+
const res = await fetch(url2, {
|
|
33376
|
+
method,
|
|
33377
|
+
headers: {
|
|
33378
|
+
Authorization: `Bearer ${token}`,
|
|
33379
|
+
...params.body != null ? { "Content-Type": "application/json" } : {}
|
|
33380
|
+
},
|
|
33381
|
+
...params.body != null ? { body: JSON.stringify(params.body) } : {}
|
|
33382
|
+
});
|
|
33133
33383
|
if (!res.ok) {
|
|
33134
33384
|
const t = await res.text().catch(() => "");
|
|
33135
33385
|
return { ok: false, error: `${params.errorLabel} (${res.status}): ${t.slice(0, 200)}` };
|
|
@@ -33312,6 +33562,39 @@ async function enrichForkedSessionPromptForAgent(params) {
|
|
|
33312
33562
|
return buildForkedSessionAgentPrompt(params.promptText, params.sessionId, parentSessionId);
|
|
33313
33563
|
}
|
|
33314
33564
|
|
|
33565
|
+
// src/agents/acp/build-integration-content-agent-prompt-note.ts
|
|
33566
|
+
function buildIntegrationContentAgentPromptNote(sessionId) {
|
|
33567
|
+
const sessionRef = sessionId.trim();
|
|
33568
|
+
return [
|
|
33569
|
+
"The user message includes link(s) to external integration resources (Linear, GitHub, Jira, Notion, Slack thread, Zoom, or Asana).",
|
|
33570
|
+
"Use the get_integration_content MCP tool on the buildautomaton-bridge server to fetch the full content of each link.",
|
|
33571
|
+
`When calling the tool, pass sessionId "${sessionRef}" and the URL as url.`,
|
|
33572
|
+
"By default the tool links the fetched URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false when fetching additional links for context only (after the primary ticket is linked, or when you do not want association).",
|
|
33573
|
+
"If the tool reports unsupported_url, do not retry with the same URL. If it reports integration_reconnect_required, ask the user to reconnect the integration in workspace settings. If it reports temporarily_unavailable, you may retry later."
|
|
33574
|
+
].join("\n");
|
|
33575
|
+
}
|
|
33576
|
+
function injectIntegrationContentAgentPromptNote(agentPrompt, sessionId) {
|
|
33577
|
+
const note = buildIntegrationContentAgentPromptNote(sessionId);
|
|
33578
|
+
const marker = "\nUser request:\n";
|
|
33579
|
+
const idx = agentPrompt.indexOf(marker);
|
|
33580
|
+
if (idx >= 0) {
|
|
33581
|
+
return `${agentPrompt.slice(0, idx)}
|
|
33582
|
+
${note}${agentPrompt.slice(idx)}`;
|
|
33583
|
+
}
|
|
33584
|
+
return `${note}
|
|
33585
|
+
|
|
33586
|
+
${agentPrompt.trim()}`;
|
|
33587
|
+
}
|
|
33588
|
+
|
|
33589
|
+
// src/agents/acp/enrich-integration-content-prompt-for-agent.ts
|
|
33590
|
+
function enrichIntegrationContentPromptForAgent(params) {
|
|
33591
|
+
if (!params.sessionId.trim()) return params.agentPromptText;
|
|
33592
|
+
if (extractFetchableIntegrationLinks(params.originalPromptText).length === 0) {
|
|
33593
|
+
return params.agentPromptText;
|
|
33594
|
+
}
|
|
33595
|
+
return injectIntegrationContentAgentPromptNote(params.agentPromptText, params.sessionId);
|
|
33596
|
+
}
|
|
33597
|
+
|
|
33315
33598
|
// src/agents/acp/send-prompt-to-agent.ts
|
|
33316
33599
|
async function sendPromptToAgent(options) {
|
|
33317
33600
|
const {
|
|
@@ -33322,7 +33605,7 @@ async function sendPromptToAgent(options) {
|
|
|
33322
33605
|
runId,
|
|
33323
33606
|
agentType,
|
|
33324
33607
|
agentCwd,
|
|
33325
|
-
sendResult
|
|
33608
|
+
sendResult,
|
|
33326
33609
|
sendSessionUpdate,
|
|
33327
33610
|
log: log2,
|
|
33328
33611
|
followUpCatalogPromptId,
|
|
@@ -33342,10 +33625,17 @@ async function sendPromptToAgent(options) {
|
|
|
33342
33625
|
getCloudAccessToken
|
|
33343
33626
|
});
|
|
33344
33627
|
}
|
|
33628
|
+
if (sessionId) {
|
|
33629
|
+
agentPromptText = enrichIntegrationContentPromptForAgent({
|
|
33630
|
+
sessionId,
|
|
33631
|
+
originalPromptText: promptText,
|
|
33632
|
+
agentPromptText
|
|
33633
|
+
});
|
|
33634
|
+
}
|
|
33345
33635
|
let sendOpts = {};
|
|
33346
33636
|
if (attachments && attachments.length > 0) {
|
|
33347
33637
|
if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
|
|
33348
|
-
|
|
33638
|
+
sendResult({
|
|
33349
33639
|
type: "prompt_result",
|
|
33350
33640
|
id: promptId,
|
|
33351
33641
|
...sessionId ? { sessionId } : {},
|
|
@@ -33366,7 +33656,7 @@ async function sendPromptToAgent(options) {
|
|
|
33366
33656
|
log: log2
|
|
33367
33657
|
});
|
|
33368
33658
|
if (!resolved.ok) {
|
|
33369
|
-
|
|
33659
|
+
sendResult({
|
|
33370
33660
|
type: "prompt_result",
|
|
33371
33661
|
id: promptId,
|
|
33372
33662
|
...sessionId ? { sessionId } : {},
|
|
@@ -33405,7 +33695,7 @@ async function sendPromptToAgent(options) {
|
|
|
33405
33695
|
const errStr = typeof result.error === "string" ? result.error : void 0;
|
|
33406
33696
|
const resultStop = typeof result.stopReason === "string" ? result.stopReason.trim() : "";
|
|
33407
33697
|
const cancelledByAgent = resultStop.toLowerCase() === "cancelled" || errStr != null && isUserEndedSessionTurnErrorText(errStr);
|
|
33408
|
-
|
|
33698
|
+
sendResult({
|
|
33409
33699
|
type: "prompt_result",
|
|
33410
33700
|
id: promptId,
|
|
33411
33701
|
...sessionId ? { sessionId } : {},
|
|
@@ -33427,7 +33717,7 @@ async function sendPromptToAgent(options) {
|
|
|
33427
33717
|
} catch (err) {
|
|
33428
33718
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
33429
33719
|
log2(`[Agent] Send failed: ${errMsg}`);
|
|
33430
|
-
|
|
33720
|
+
sendResult({
|
|
33431
33721
|
type: "prompt_result",
|
|
33432
33722
|
id: promptId,
|
|
33433
33723
|
...sessionId ? { sessionId } : {},
|
|
@@ -33461,7 +33751,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33461
33751
|
agentType,
|
|
33462
33752
|
agentConfig,
|
|
33463
33753
|
sessionParentPath,
|
|
33464
|
-
sendResult
|
|
33754
|
+
sendResult,
|
|
33465
33755
|
sendSessionUpdate,
|
|
33466
33756
|
followUpCatalogPromptId,
|
|
33467
33757
|
sessionChangeSummaryFilePaths,
|
|
@@ -33478,7 +33768,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33478
33768
|
const activeRunId = runId;
|
|
33479
33769
|
const acpAgentKey = computeAcpAgentKey(preferredForPrompt, mode, agentConfig ?? null);
|
|
33480
33770
|
if (!acpAgentKey) {
|
|
33481
|
-
|
|
33771
|
+
sendResult({
|
|
33482
33772
|
type: "prompt_result",
|
|
33483
33773
|
id: promptId,
|
|
33484
33774
|
...sessionId ? { sessionId } : {},
|
|
@@ -33515,7 +33805,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33515
33805
|
const evaluated = Boolean(preferredForPrompt && errMsg.trim());
|
|
33516
33806
|
const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
|
|
33517
33807
|
const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
|
|
33518
|
-
|
|
33808
|
+
sendResult({
|
|
33519
33809
|
type: "prompt_result",
|
|
33520
33810
|
id: promptId,
|
|
33521
33811
|
...sessionId ? { sessionId } : {},
|
|
@@ -33535,7 +33825,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33535
33825
|
await handle.cancel?.();
|
|
33536
33826
|
} catch {
|
|
33537
33827
|
}
|
|
33538
|
-
|
|
33828
|
+
sendResult({
|
|
33539
33829
|
type: "prompt_result",
|
|
33540
33830
|
id: promptId,
|
|
33541
33831
|
...sessionId ? { sessionId } : {},
|
|
@@ -33556,7 +33846,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33556
33846
|
runId: activeRunId,
|
|
33557
33847
|
agentType: preferredForPrompt,
|
|
33558
33848
|
agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
|
|
33559
|
-
sendResult
|
|
33849
|
+
sendResult,
|
|
33560
33850
|
sendSessionUpdate,
|
|
33561
33851
|
log: ctx.log,
|
|
33562
33852
|
followUpCatalogPromptId,
|
|
@@ -33612,6 +33902,563 @@ async function createAcpManager(options) {
|
|
|
33612
33902
|
};
|
|
33613
33903
|
}
|
|
33614
33904
|
|
|
33905
|
+
// src/worktrees/worktree-layout-file.ts
|
|
33906
|
+
import * as fs16 from "node:fs";
|
|
33907
|
+
import * as path19 from "node:path";
|
|
33908
|
+
import os7 from "node:os";
|
|
33909
|
+
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
33910
|
+
function defaultWorktreeLayoutPath() {
|
|
33911
|
+
return path19.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
33912
|
+
}
|
|
33913
|
+
function normalizeLoadedLayout(raw) {
|
|
33914
|
+
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
33915
|
+
const j = raw;
|
|
33916
|
+
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
33917
|
+
}
|
|
33918
|
+
return { launcherCwds: [] };
|
|
33919
|
+
}
|
|
33920
|
+
function loadWorktreeLayout() {
|
|
33921
|
+
try {
|
|
33922
|
+
const p = defaultWorktreeLayoutPath();
|
|
33923
|
+
if (!fs16.existsSync(p)) return { launcherCwds: [] };
|
|
33924
|
+
const raw = JSON.parse(fs16.readFileSync(p, "utf8"));
|
|
33925
|
+
return normalizeLoadedLayout(raw);
|
|
33926
|
+
} catch {
|
|
33927
|
+
return { launcherCwds: [] };
|
|
33928
|
+
}
|
|
33929
|
+
}
|
|
33930
|
+
function saveWorktreeLayout(layout) {
|
|
33931
|
+
try {
|
|
33932
|
+
const dir = path19.dirname(defaultWorktreeLayoutPath());
|
|
33933
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
33934
|
+
fs16.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
33935
|
+
} catch {
|
|
33936
|
+
}
|
|
33937
|
+
}
|
|
33938
|
+
function baseNameSafe(pathString) {
|
|
33939
|
+
return path19.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
33940
|
+
}
|
|
33941
|
+
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
33942
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
33943
|
+
const existing = layout.launcherCwds.find((e) => path19.resolve(e.absolutePath) === norm);
|
|
33944
|
+
return existing?.dirName;
|
|
33945
|
+
}
|
|
33946
|
+
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
33947
|
+
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
33948
|
+
if (existing) return existing;
|
|
33949
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
33950
|
+
const base = baseNameSafe(norm);
|
|
33951
|
+
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
33952
|
+
let name = base;
|
|
33953
|
+
let n = 2;
|
|
33954
|
+
while (used.has(name)) {
|
|
33955
|
+
name = `${base}-${n}`;
|
|
33956
|
+
n += 1;
|
|
33957
|
+
}
|
|
33958
|
+
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
33959
|
+
saveWorktreeLayout(layout);
|
|
33960
|
+
return name;
|
|
33961
|
+
}
|
|
33962
|
+
|
|
33963
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
33964
|
+
import * as fs20 from "node:fs";
|
|
33965
|
+
import * as path24 from "node:path";
|
|
33966
|
+
|
|
33967
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
33968
|
+
import * as fs18 from "node:fs";
|
|
33969
|
+
import * as path21 from "node:path";
|
|
33970
|
+
|
|
33971
|
+
// src/worktrees/discovery/disk-walk-constants.ts
|
|
33972
|
+
var DISK_WALK_YIELD_EVERY = 64;
|
|
33973
|
+
var LEGACY_WALK_MAX_DEPTH = 12;
|
|
33974
|
+
var SKIP_DISK_WALK_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
33975
|
+
"node_modules",
|
|
33976
|
+
"bower_components",
|
|
33977
|
+
"vendor",
|
|
33978
|
+
"Pods",
|
|
33979
|
+
"Carthage",
|
|
33980
|
+
"DerivedData",
|
|
33981
|
+
".yarn",
|
|
33982
|
+
".pnpm-store",
|
|
33983
|
+
"dist",
|
|
33984
|
+
"build",
|
|
33985
|
+
".next",
|
|
33986
|
+
"coverage",
|
|
33987
|
+
".turbo",
|
|
33988
|
+
".cache",
|
|
33989
|
+
"target",
|
|
33990
|
+
"__pycache__"
|
|
33991
|
+
]);
|
|
33992
|
+
function shouldSkipDiskWalkEntry(name) {
|
|
33993
|
+
return name.startsWith(".") || SKIP_DISK_WALK_DIR_NAMES.has(name);
|
|
33994
|
+
}
|
|
33995
|
+
|
|
33996
|
+
// src/worktrees/discovery/disk-walk-utils.ts
|
|
33997
|
+
import * as fs17 from "node:fs";
|
|
33998
|
+
import * as path20 from "node:path";
|
|
33999
|
+
async function yieldDuringDiskWalk(state) {
|
|
34000
|
+
state.entries++;
|
|
34001
|
+
if (state.entries % DISK_WALK_YIELD_EVERY !== 0) return true;
|
|
34002
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
34003
|
+
await yieldToEventLoop();
|
|
34004
|
+
return !isCliImmediateShutdownRequested();
|
|
34005
|
+
}
|
|
34006
|
+
async function isGitDir(dirPath) {
|
|
34007
|
+
try {
|
|
34008
|
+
await fs17.promises.access(path20.join(dirPath, ".git"));
|
|
34009
|
+
return true;
|
|
34010
|
+
} catch {
|
|
34011
|
+
return false;
|
|
34012
|
+
}
|
|
34013
|
+
}
|
|
34014
|
+
|
|
34015
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
34016
|
+
async function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
34017
|
+
const out = [];
|
|
34018
|
+
const state = { entries: 0 };
|
|
34019
|
+
const walk = async (dir) => {
|
|
34020
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
34021
|
+
if (await isGitDir(dir)) {
|
|
34022
|
+
out.push(path21.resolve(dir));
|
|
34023
|
+
return;
|
|
34024
|
+
}
|
|
34025
|
+
let entries;
|
|
34026
|
+
try {
|
|
34027
|
+
entries = await fs18.promises.readdir(dir, { withFileTypes: true });
|
|
34028
|
+
} catch {
|
|
34029
|
+
return;
|
|
34030
|
+
}
|
|
34031
|
+
for (const e of entries) {
|
|
34032
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
34033
|
+
const full = path21.join(dir, e.name);
|
|
34034
|
+
if (!e.isDirectory()) continue;
|
|
34035
|
+
await walk(full);
|
|
34036
|
+
}
|
|
34037
|
+
};
|
|
34038
|
+
await walk(path21.resolve(rootPath));
|
|
34039
|
+
return { paths: [...new Set(out)], entriesVisited: state.entries };
|
|
34040
|
+
}
|
|
34041
|
+
async function collectWorktreeRootsNamed(root, sessionId, maxDepth = LEGACY_WALK_MAX_DEPTH) {
|
|
34042
|
+
const out = [];
|
|
34043
|
+
const state = { entries: 0 };
|
|
34044
|
+
const walk = async (dir, depth) => {
|
|
34045
|
+
if (depth > maxDepth) return;
|
|
34046
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
34047
|
+
let entries;
|
|
34048
|
+
try {
|
|
34049
|
+
entries = await fs18.promises.readdir(dir, { withFileTypes: true });
|
|
34050
|
+
} catch {
|
|
34051
|
+
return;
|
|
34052
|
+
}
|
|
34053
|
+
for (const e of entries) {
|
|
34054
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
34055
|
+
const full = path21.join(dir, e.name);
|
|
34056
|
+
if (!e.isDirectory()) continue;
|
|
34057
|
+
if (e.name === sessionId) {
|
|
34058
|
+
if (await isGitDir(full)) out.push(path21.resolve(full));
|
|
34059
|
+
continue;
|
|
34060
|
+
}
|
|
34061
|
+
if (await isGitDir(full)) continue;
|
|
34062
|
+
await walk(full, depth + 1);
|
|
34063
|
+
}
|
|
34064
|
+
};
|
|
34065
|
+
await walk(root, 0);
|
|
34066
|
+
return { paths: out, entriesVisited: state.entries };
|
|
34067
|
+
}
|
|
34068
|
+
|
|
34069
|
+
// src/worktrees/discovery/layout-keys-for-bridge-root.ts
|
|
34070
|
+
import * as path22 from "node:path";
|
|
34071
|
+
function layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk) {
|
|
34072
|
+
const bridge = path22.resolve(bridgeRoot);
|
|
34073
|
+
const preferred = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34074
|
+
const relevant = layout.launcherCwds.filter((e) => {
|
|
34075
|
+
const entry = path22.resolve(e.absolutePath);
|
|
34076
|
+
return bridge === entry || bridge.startsWith(entry + path22.sep) || entry.startsWith(bridge + path22.sep);
|
|
34077
|
+
}).sort((a, b) => path22.resolve(b.absolutePath).length - path22.resolve(a.absolutePath).length).map((e) => e.dirName).filter((name) => keysOnDisk.includes(name));
|
|
34078
|
+
const ordered = [];
|
|
34079
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34080
|
+
const add = (k) => {
|
|
34081
|
+
if (seen.has(k) || !keysOnDisk.includes(k)) return;
|
|
34082
|
+
seen.add(k);
|
|
34083
|
+
ordered.push(k);
|
|
34084
|
+
};
|
|
34085
|
+
if (preferred) add(preferred);
|
|
34086
|
+
for (const k of relevant) add(k);
|
|
34087
|
+
if (relevant.length > 0) {
|
|
34088
|
+
return ordered;
|
|
34089
|
+
}
|
|
34090
|
+
for (const k of keysOnDisk) add(k);
|
|
34091
|
+
return ordered;
|
|
34092
|
+
}
|
|
34093
|
+
|
|
34094
|
+
// src/worktrees/discovery/try-binding-from-session-directory.ts
|
|
34095
|
+
import * as fs19 from "node:fs";
|
|
34096
|
+
import * as path23 from "node:path";
|
|
34097
|
+
async function tryBindingFromSessionDirectory(sessionDir) {
|
|
34098
|
+
let st;
|
|
34099
|
+
try {
|
|
34100
|
+
st = await fs19.promises.stat(sessionDir);
|
|
34101
|
+
} catch {
|
|
34102
|
+
return null;
|
|
34103
|
+
}
|
|
34104
|
+
if (!st.isDirectory()) return null;
|
|
34105
|
+
const { paths: worktreePaths } = await collectGitRepoRootsUnderDirectory(sessionDir);
|
|
34106
|
+
if (worktreePaths.length === 0) return null;
|
|
34107
|
+
const abs = path23.resolve(sessionDir);
|
|
34108
|
+
return {
|
|
34109
|
+
sessionParentPath: abs,
|
|
34110
|
+
workingTreeRelRoot: abs,
|
|
34111
|
+
repoCheckoutPaths: worktreePaths
|
|
34112
|
+
};
|
|
34113
|
+
}
|
|
34114
|
+
|
|
34115
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
34116
|
+
async function discoverSessionWorktreeOnDisk(options) {
|
|
34117
|
+
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
34118
|
+
const sid = sessionId.trim();
|
|
34119
|
+
if (!sid) return null;
|
|
34120
|
+
try {
|
|
34121
|
+
await fs20.promises.access(worktreesRootPath);
|
|
34122
|
+
} catch {
|
|
34123
|
+
return null;
|
|
34124
|
+
}
|
|
34125
|
+
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34126
|
+
const keysOnDisk = [];
|
|
34127
|
+
if (preferredKey) keysOnDisk.push(preferredKey);
|
|
34128
|
+
try {
|
|
34129
|
+
for (const name of await fs20.promises.readdir(worktreesRootPath)) {
|
|
34130
|
+
if (name.startsWith(".")) continue;
|
|
34131
|
+
const p = path24.join(worktreesRootPath, name);
|
|
34132
|
+
let st;
|
|
34133
|
+
try {
|
|
34134
|
+
st = await fs20.promises.stat(p);
|
|
34135
|
+
} catch {
|
|
34136
|
+
continue;
|
|
34137
|
+
}
|
|
34138
|
+
if (!st.isDirectory()) continue;
|
|
34139
|
+
if (!keysOnDisk.includes(name)) keysOnDisk.push(name);
|
|
34140
|
+
}
|
|
34141
|
+
} catch {
|
|
34142
|
+
return null;
|
|
34143
|
+
}
|
|
34144
|
+
const keys = layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk);
|
|
34145
|
+
for (const key of keys) {
|
|
34146
|
+
if (isCliImmediateShutdownRequested()) return null;
|
|
34147
|
+
await yieldToEventLoop();
|
|
34148
|
+
const layoutRoot = path24.join(worktreesRootPath, key);
|
|
34149
|
+
let layoutSt;
|
|
34150
|
+
try {
|
|
34151
|
+
layoutSt = await fs20.promises.stat(layoutRoot);
|
|
34152
|
+
} catch {
|
|
34153
|
+
continue;
|
|
34154
|
+
}
|
|
34155
|
+
if (!layoutSt.isDirectory()) continue;
|
|
34156
|
+
const sessionDir = path24.join(layoutRoot, sid);
|
|
34157
|
+
const nested = await tryBindingFromSessionDirectory(sessionDir);
|
|
34158
|
+
if (nested) return nested;
|
|
34159
|
+
const legacy = await collectWorktreeRootsNamed(layoutRoot, sid);
|
|
34160
|
+
if (legacy.paths.length > 0) {
|
|
34161
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacy.paths) ?? path24.resolve(legacy.paths[0]);
|
|
34162
|
+
return {
|
|
34163
|
+
sessionParentPath: path24.resolve(isolated),
|
|
34164
|
+
workingTreeRelRoot: path24.resolve(layoutRoot),
|
|
34165
|
+
repoCheckoutPaths: legacy.paths.map((p) => path24.resolve(p))
|
|
34166
|
+
};
|
|
34167
|
+
}
|
|
34168
|
+
}
|
|
34169
|
+
return null;
|
|
34170
|
+
}
|
|
34171
|
+
|
|
34172
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
34173
|
+
import * as fs21 from "node:fs";
|
|
34174
|
+
import * as path26 from "node:path";
|
|
34175
|
+
|
|
34176
|
+
// src/worktrees/discovery/discover-legacy-binding-ascending-from-checkout.ts
|
|
34177
|
+
import * as path25 from "node:path";
|
|
34178
|
+
async function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
34179
|
+
const sid = sessionId.trim();
|
|
34180
|
+
if (!sid) return null;
|
|
34181
|
+
const hintR = path25.resolve(checkoutPath);
|
|
34182
|
+
let best = null;
|
|
34183
|
+
let cur = path25.dirname(hintR);
|
|
34184
|
+
for (let i = 0; i < 40; i++) {
|
|
34185
|
+
if (isCliImmediateShutdownRequested()) return best;
|
|
34186
|
+
await yieldToEventLoop();
|
|
34187
|
+
const paths = await collectWorktreeRootsNamed(cur, sid);
|
|
34188
|
+
if (paths.paths.some((p) => path25.resolve(p) === hintR)) {
|
|
34189
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths.paths) ?? path25.resolve(paths.paths[0]);
|
|
34190
|
+
best = {
|
|
34191
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34192
|
+
workingTreeRelRoot: path25.resolve(cur),
|
|
34193
|
+
repoCheckoutPaths: paths.paths.map((p) => path25.resolve(p))
|
|
34194
|
+
};
|
|
34195
|
+
}
|
|
34196
|
+
const next = path25.dirname(cur);
|
|
34197
|
+
if (next === cur) break;
|
|
34198
|
+
cur = next;
|
|
34199
|
+
}
|
|
34200
|
+
return best;
|
|
34201
|
+
}
|
|
34202
|
+
|
|
34203
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
34204
|
+
async function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
34205
|
+
const sid = sessionId.trim();
|
|
34206
|
+
if (!sid) return null;
|
|
34207
|
+
const hint = path26.resolve(sessionWorktreeRootPathOrHint);
|
|
34208
|
+
const underHint = await tryBindingFromSessionDirectory(path26.join(hint, sid));
|
|
34209
|
+
if (underHint) return underHint;
|
|
34210
|
+
const direct = await tryBindingFromSessionDirectory(hint);
|
|
34211
|
+
if (direct) {
|
|
34212
|
+
if (path26.basename(hint) === sid && await isGitDir(hint)) {
|
|
34213
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34214
|
+
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
34215
|
+
return legacyFromCheckout;
|
|
34216
|
+
}
|
|
34217
|
+
}
|
|
34218
|
+
return direct;
|
|
34219
|
+
}
|
|
34220
|
+
if (path26.basename(hint) === sid && await isGitDir(hint)) {
|
|
34221
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34222
|
+
if (legacyFromCheckout) return legacyFromCheckout;
|
|
34223
|
+
}
|
|
34224
|
+
let st;
|
|
34225
|
+
try {
|
|
34226
|
+
st = await fs21.promises.stat(hint);
|
|
34227
|
+
} catch {
|
|
34228
|
+
return null;
|
|
34229
|
+
}
|
|
34230
|
+
if (!st.isDirectory()) return null;
|
|
34231
|
+
const legacyPaths = await collectWorktreeRootsNamed(hint, sid);
|
|
34232
|
+
if (legacyPaths.paths.length === 0) return null;
|
|
34233
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths.paths) ?? path26.resolve(legacyPaths.paths[0]);
|
|
34234
|
+
return {
|
|
34235
|
+
sessionParentPath: path26.resolve(isolated),
|
|
34236
|
+
workingTreeRelRoot: hint,
|
|
34237
|
+
repoCheckoutPaths: legacyPaths.paths.map((p) => path26.resolve(p))
|
|
34238
|
+
};
|
|
34239
|
+
}
|
|
34240
|
+
|
|
34241
|
+
// src/worktrees/manager/discover-session-binding.ts
|
|
34242
|
+
var discoverInflightBySessionId = /* @__PURE__ */ new Map();
|
|
34243
|
+
function discoverSessionBindingAsync(params) {
|
|
34244
|
+
const sid = params.sessionId.trim();
|
|
34245
|
+
if (!sid) return Promise.resolve(null);
|
|
34246
|
+
const existing = discoverInflightBySessionId.get(sid);
|
|
34247
|
+
if (existing) return existing;
|
|
34248
|
+
const promise2 = discoverSessionWorktreeOnDisk({
|
|
34249
|
+
sessionId: sid,
|
|
34250
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
34251
|
+
layout: params.layout,
|
|
34252
|
+
bridgeRoot: getBridgeRoot()
|
|
34253
|
+
}).finally(() => {
|
|
34254
|
+
if (discoverInflightBySessionId.get(sid) === promise2) {
|
|
34255
|
+
discoverInflightBySessionId.delete(sid);
|
|
34256
|
+
}
|
|
34257
|
+
});
|
|
34258
|
+
discoverInflightBySessionId.set(sid, promise2);
|
|
34259
|
+
return promise2;
|
|
34260
|
+
}
|
|
34261
|
+
|
|
34262
|
+
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
34263
|
+
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
34264
|
+
if (!sessionId) return null;
|
|
34265
|
+
const sid = sessionId.trim();
|
|
34266
|
+
const cached2 = cache2.getSessionParentPath(sid);
|
|
34267
|
+
if (cached2) return cached2;
|
|
34268
|
+
const paths = ensureRepoCheckoutPaths(sid);
|
|
34269
|
+
if (!paths?.length) return null;
|
|
34270
|
+
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
34271
|
+
}
|
|
34272
|
+
function ensureRepoCheckoutPathsForSession(sessionId, cache2) {
|
|
34273
|
+
if (!sessionId?.trim()) return void 0;
|
|
34274
|
+
const cached2 = cache2.getRepoCheckoutPaths(sessionId.trim());
|
|
34275
|
+
return cached2?.length ? [...cached2] : void 0;
|
|
34276
|
+
}
|
|
34277
|
+
async function ensureRepoCheckoutPathsForSessionAsync(sessionId, cache2, discover) {
|
|
34278
|
+
if (!sessionId?.trim()) return void 0;
|
|
34279
|
+
const sid = sessionId.trim();
|
|
34280
|
+
const cached2 = cache2.getRepoCheckoutPaths(sid);
|
|
34281
|
+
if (cached2?.length) return cached2;
|
|
34282
|
+
const disc = await discover(sid);
|
|
34283
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
34284
|
+
cache2.remember(sid, disc);
|
|
34285
|
+
return [...disc.repoCheckoutPaths];
|
|
34286
|
+
}
|
|
34287
|
+
return void 0;
|
|
34288
|
+
}
|
|
34289
|
+
|
|
34290
|
+
// src/worktrees/manager/parse-session-parent.ts
|
|
34291
|
+
function parseSessionParent(v) {
|
|
34292
|
+
if (v === "bridge_root" || v === "worktrees_root") return v;
|
|
34293
|
+
if (v === "session_worktrees_root") return "worktrees_root";
|
|
34294
|
+
return null;
|
|
34295
|
+
}
|
|
34296
|
+
|
|
34297
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34298
|
+
import * as fs22 from "node:fs";
|
|
34299
|
+
import * as path27 from "node:path";
|
|
34300
|
+
|
|
34301
|
+
// src/git/worktrees/worktree-add.ts
|
|
34302
|
+
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
34303
|
+
const mainGit = cliSimpleGit(mainRepoPath);
|
|
34304
|
+
const base = baseRef.trim() || "HEAD";
|
|
34305
|
+
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
34306
|
+
}
|
|
34307
|
+
|
|
34308
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34309
|
+
function normalizeRepoRelPath(rel) {
|
|
34310
|
+
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
34311
|
+
}
|
|
34312
|
+
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
34313
|
+
if (!baseBranches) return "HEAD";
|
|
34314
|
+
const direct = baseBranches[relNorm]?.trim();
|
|
34315
|
+
if (direct) return direct;
|
|
34316
|
+
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
34317
|
+
return "HEAD";
|
|
34318
|
+
}
|
|
34319
|
+
async function prepareNewSessionWorktrees(options) {
|
|
34320
|
+
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
34321
|
+
const bridgeResolved = path27.resolve(bridgeRoot);
|
|
34322
|
+
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
34323
|
+
const bridgeKeyDir = path27.join(worktreesRootPath, cwdKey);
|
|
34324
|
+
const sessionDir = path27.join(bridgeKeyDir, sessionId);
|
|
34325
|
+
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
34326
|
+
if (repos.length === 0) {
|
|
34327
|
+
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
34328
|
+
return null;
|
|
34329
|
+
}
|
|
34330
|
+
const branch = `session-${sessionId}`;
|
|
34331
|
+
const worktreePaths = [];
|
|
34332
|
+
fs22.mkdirSync(sessionDir, { recursive: true });
|
|
34333
|
+
for (const repo of repos) {
|
|
34334
|
+
let rel = path27.relative(bridgeResolved, repo.absolutePath);
|
|
34335
|
+
if (rel.startsWith("..") || path27.isAbsolute(rel)) continue;
|
|
34336
|
+
const relNorm = normalizeRepoRelPath(rel === "" ? "." : rel);
|
|
34337
|
+
const wtPath = relNorm === "." ? sessionDir : path27.join(sessionDir, relNorm);
|
|
34338
|
+
if (relNorm !== ".") {
|
|
34339
|
+
fs22.mkdirSync(path27.dirname(wtPath), { recursive: true });
|
|
34340
|
+
}
|
|
34341
|
+
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
34342
|
+
try {
|
|
34343
|
+
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
34344
|
+
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
34345
|
+
worktreePaths.push(wtPath);
|
|
34346
|
+
} catch (e) {
|
|
34347
|
+
log2(
|
|
34348
|
+
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
34349
|
+
);
|
|
34350
|
+
}
|
|
34351
|
+
}
|
|
34352
|
+
if (worktreePaths.length === 0) return null;
|
|
34353
|
+
return {
|
|
34354
|
+
worktreePaths,
|
|
34355
|
+
sessionParentPath: sessionDir,
|
|
34356
|
+
workingTreeRelRoot: sessionDir
|
|
34357
|
+
};
|
|
34358
|
+
}
|
|
34359
|
+
|
|
34360
|
+
// src/worktrees/manager/prepare-and-remember-session-worktrees.ts
|
|
34361
|
+
async function prepareAndRememberSessionWorktrees(params) {
|
|
34362
|
+
const prep = await prepareNewSessionWorktrees({
|
|
34363
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
34364
|
+
bridgeRoot: getBridgeRoot(),
|
|
34365
|
+
sessionId: params.sessionId,
|
|
34366
|
+
layout: params.layout,
|
|
34367
|
+
log: params.log,
|
|
34368
|
+
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
34369
|
+
});
|
|
34370
|
+
if (!prep) return void 0;
|
|
34371
|
+
params.cache.remember(params.sessionId, {
|
|
34372
|
+
sessionParentPath: prep.sessionParentPath,
|
|
34373
|
+
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
34374
|
+
repoCheckoutPaths: prep.worktreePaths
|
|
34375
|
+
});
|
|
34376
|
+
return params.cache.getSessionParentPath(params.sessionId);
|
|
34377
|
+
}
|
|
34378
|
+
|
|
34379
|
+
// src/worktrees/manager/resolve-existing-session-parent-path.ts
|
|
34380
|
+
async function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
34381
|
+
const cached2 = cache2.getSessionParentPath(sessionId);
|
|
34382
|
+
if (cached2) return cached2;
|
|
34383
|
+
const disc = await discover();
|
|
34384
|
+
if (disc) {
|
|
34385
|
+
cache2.remember(sessionId, disc);
|
|
34386
|
+
return cache2.getSessionParentPath(sessionId);
|
|
34387
|
+
}
|
|
34388
|
+
return void 0;
|
|
34389
|
+
}
|
|
34390
|
+
|
|
34391
|
+
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
34392
|
+
import * as path28 from "node:path";
|
|
34393
|
+
async function resolveExplicitSessionParentPath(params) {
|
|
34394
|
+
const resolved = path28.resolve(params.parentPathRaw);
|
|
34395
|
+
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
34396
|
+
return resolved;
|
|
34397
|
+
}
|
|
34398
|
+
const rememberAndReturn = (binding) => {
|
|
34399
|
+
params.cache.remember(params.sessionId, binding);
|
|
34400
|
+
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
34401
|
+
};
|
|
34402
|
+
const diskFirst = await params.discover();
|
|
34403
|
+
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
34404
|
+
const fromRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
34405
|
+
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
34406
|
+
let cur = resolved;
|
|
34407
|
+
for (let i = 0; i < 16; i++) {
|
|
34408
|
+
await yieldToEventLoop();
|
|
34409
|
+
const tryRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
34410
|
+
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
34411
|
+
const next = path28.dirname(cur);
|
|
34412
|
+
if (next === cur) break;
|
|
34413
|
+
cur = next;
|
|
34414
|
+
}
|
|
34415
|
+
return resolved;
|
|
34416
|
+
}
|
|
34417
|
+
|
|
34418
|
+
// src/worktrees/manager/resolve-session-parent-path-for-prompt.ts
|
|
34419
|
+
async function resolveSessionParentPathForPrompt(params) {
|
|
34420
|
+
const { sessionId, cache: cache2, worktreesRootPath, layout, log: log2, discover, opts } = params;
|
|
34421
|
+
if (!sessionId) return void 0;
|
|
34422
|
+
const sid = sessionId.trim();
|
|
34423
|
+
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
34424
|
+
if (parentPathRaw) {
|
|
34425
|
+
return resolveExplicitSessionParentPath({
|
|
34426
|
+
sessionId: sid,
|
|
34427
|
+
sessionParent: opts.sessionParent,
|
|
34428
|
+
parentPathRaw,
|
|
34429
|
+
cache: cache2,
|
|
34430
|
+
discover: () => discover(sid)
|
|
34431
|
+
});
|
|
34432
|
+
}
|
|
34433
|
+
const parentKind = parseSessionParent(opts.sessionParent);
|
|
34434
|
+
if (parentKind === "bridge_root") {
|
|
34435
|
+
return void 0;
|
|
34436
|
+
}
|
|
34437
|
+
if (parentKind === "worktrees_root") {
|
|
34438
|
+
if (!opts.isNewSession) {
|
|
34439
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
34440
|
+
}
|
|
34441
|
+
return prepareAndRememberSessionWorktrees({
|
|
34442
|
+
cache: cache2,
|
|
34443
|
+
sessionId: sid,
|
|
34444
|
+
worktreesRootPath,
|
|
34445
|
+
layout,
|
|
34446
|
+
log: log2,
|
|
34447
|
+
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
34448
|
+
});
|
|
34449
|
+
}
|
|
34450
|
+
if (!opts.isNewSession) {
|
|
34451
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
34452
|
+
}
|
|
34453
|
+
return prepareAndRememberSessionWorktrees({
|
|
34454
|
+
cache: cache2,
|
|
34455
|
+
sessionId: sid,
|
|
34456
|
+
worktreesRootPath,
|
|
34457
|
+
layout,
|
|
34458
|
+
log: log2
|
|
34459
|
+
});
|
|
34460
|
+
}
|
|
34461
|
+
|
|
33615
34462
|
// src/git/changes/types.ts
|
|
33616
34463
|
var MAX_PATCH_CHARS = 35e4;
|
|
33617
34464
|
|
|
@@ -33669,8 +34516,11 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
33669
34516
|
return `origin \xB7 ${hostPath}`;
|
|
33670
34517
|
}
|
|
33671
34518
|
|
|
33672
|
-
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
33673
|
-
import * as
|
|
34519
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
34520
|
+
import * as path33 from "node:path";
|
|
34521
|
+
|
|
34522
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
34523
|
+
import * as path32 from "node:path";
|
|
33674
34524
|
|
|
33675
34525
|
// src/git/commits/resolve-remote-tracking.ts
|
|
33676
34526
|
async function tryConfigGet(g, key) {
|
|
@@ -33841,8 +34691,8 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
33841
34691
|
}
|
|
33842
34692
|
|
|
33843
34693
|
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
33844
|
-
function normalizeGitDiffPath(
|
|
33845
|
-
return
|
|
34694
|
+
function normalizeGitDiffPath(path53) {
|
|
34695
|
+
return path53.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
33846
34696
|
}
|
|
33847
34697
|
|
|
33848
34698
|
// src/git/changes/parse/expand-git-rename-numstat-path.ts
|
|
@@ -33955,8 +34805,8 @@ async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, mov
|
|
|
33955
34805
|
}
|
|
33956
34806
|
|
|
33957
34807
|
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
33958
|
-
import * as
|
|
33959
|
-
import * as
|
|
34808
|
+
import * as fs23 from "node:fs";
|
|
34809
|
+
import * as path29 from "node:path";
|
|
33960
34810
|
|
|
33961
34811
|
// src/git/changes/lines/count-lines.ts
|
|
33962
34812
|
import { createReadStream } from "node:fs";
|
|
@@ -34002,13 +34852,13 @@ async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
|
|
|
34002
34852
|
}
|
|
34003
34853
|
async function resolveWorkingTreeFileTotalLines(options) {
|
|
34004
34854
|
if (options.isBinary) return null;
|
|
34005
|
-
const filePath =
|
|
34855
|
+
const filePath = path29.join(options.repoGitCwd, options.pathInRepo);
|
|
34006
34856
|
if (options.change === "removed") {
|
|
34007
34857
|
return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
|
|
34008
34858
|
}
|
|
34009
34859
|
if (options.change === "moved" || options.change === "modified") {
|
|
34010
34860
|
try {
|
|
34011
|
-
const st = await
|
|
34861
|
+
const st = await fs23.promises.stat(filePath);
|
|
34012
34862
|
if (!st.isFile()) return null;
|
|
34013
34863
|
return await countTextFileLines(filePath);
|
|
34014
34864
|
} catch {
|
|
@@ -34037,7 +34887,7 @@ function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
|
|
|
34037
34887
|
}
|
|
34038
34888
|
return pathRelLauncher;
|
|
34039
34889
|
}
|
|
34040
|
-
function
|
|
34890
|
+
function normalizeRepoRelPath2(repoRelPath) {
|
|
34041
34891
|
return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
34042
34892
|
}
|
|
34043
34893
|
|
|
@@ -34139,8 +34989,8 @@ function parseNumstatEntries(lines) {
|
|
|
34139
34989
|
}
|
|
34140
34990
|
function parseNumstat(lines) {
|
|
34141
34991
|
const m = /* @__PURE__ */ new Map();
|
|
34142
|
-
for (const [
|
|
34143
|
-
m.set(
|
|
34992
|
+
for (const [path53, entry] of parseNumstatEntries(lines)) {
|
|
34993
|
+
m.set(path53, { additions: entry.additions, deletions: entry.deletions });
|
|
34144
34994
|
}
|
|
34145
34995
|
return m;
|
|
34146
34996
|
}
|
|
@@ -34271,7 +35121,7 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
34271
35121
|
g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
|
|
34272
35122
|
]);
|
|
34273
35123
|
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
34274
|
-
const normRel =
|
|
35124
|
+
const normRel = normalizeRepoRelPath2(repoRelPath);
|
|
34275
35125
|
const paths = collectChangedPaths({
|
|
34276
35126
|
nameEntries: parsed.nameEntries,
|
|
34277
35127
|
numByPath: parsed.numByPath
|
|
@@ -34299,14 +35149,14 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
34299
35149
|
}
|
|
34300
35150
|
|
|
34301
35151
|
// src/git/changes/listing/apply-untracked-file-stats.ts
|
|
34302
|
-
import * as
|
|
34303
|
-
import * as
|
|
35152
|
+
import * as fs24 from "node:fs";
|
|
35153
|
+
import * as path30 from "node:path";
|
|
34304
35154
|
function createUntrackedStatsApplier(options) {
|
|
34305
35155
|
return async (row, pathInRepo) => {
|
|
34306
35156
|
if (!options.untrackedSet.has(pathInRepo)) return;
|
|
34307
35157
|
if (options.nameByPath.has(pathInRepo)) return;
|
|
34308
35158
|
if (row.change === "moved") return;
|
|
34309
|
-
const repoFilePath =
|
|
35159
|
+
const repoFilePath = path30.join(options.repoGitCwd, pathInRepo);
|
|
34310
35160
|
const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
|
|
34311
35161
|
if (fromGit) {
|
|
34312
35162
|
row.additions = fromGit.additions;
|
|
@@ -34314,7 +35164,7 @@ function createUntrackedStatsApplier(options) {
|
|
|
34314
35164
|
return;
|
|
34315
35165
|
}
|
|
34316
35166
|
try {
|
|
34317
|
-
const st = await
|
|
35167
|
+
const st = await fs24.promises.stat(repoFilePath);
|
|
34318
35168
|
row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
|
|
34319
35169
|
} catch {
|
|
34320
35170
|
row.additions = 0;
|
|
@@ -34324,13 +35174,75 @@ function createUntrackedStatsApplier(options) {
|
|
|
34324
35174
|
}
|
|
34325
35175
|
|
|
34326
35176
|
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
34327
|
-
import * as
|
|
35177
|
+
import * as path31 from "node:path";
|
|
34328
35178
|
|
|
34329
|
-
// src/git/changes/patch/hydrate-
|
|
34330
|
-
|
|
35179
|
+
// src/git/changes/patch/hydrate/append-injected-context-lines.ts
|
|
35180
|
+
async function appendInjectedContextLines(out, inject, maybeYield, injectedTotal) {
|
|
35181
|
+
for (const t of inject) {
|
|
35182
|
+
out.push(` ${t}`);
|
|
35183
|
+
injectedTotal.value++;
|
|
35184
|
+
await maybeYield();
|
|
35185
|
+
}
|
|
35186
|
+
}
|
|
35187
|
+
|
|
35188
|
+
// src/git/changes/patch/hydrate/constants.ts
|
|
34331
35189
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
34332
35190
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
34333
35191
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
35192
|
+
var HYDRATE_YIELD_EVERY_LINES = 512;
|
|
35193
|
+
|
|
35194
|
+
// src/git/changes/patch/hydrate/collect-gap-inject-lines.ts
|
|
35195
|
+
async function collectGapInjectLines(options) {
|
|
35196
|
+
if (options.injectedTotal >= MAX_HYDRATE_LINES_PER_FILE) return null;
|
|
35197
|
+
const remaining = MAX_HYDRATE_LINES_PER_FILE - options.injectedTotal;
|
|
35198
|
+
if (options.gapNewEnd >= options.gapNewStart && options.change !== "removed") {
|
|
35199
|
+
const nNew = options.gapNewEnd - options.gapNewStart + 1;
|
|
35200
|
+
if (options.gapOldEnd < options.gapOldStart || options.gapOldEnd - options.gapOldStart + 1 === nNew) {
|
|
35201
|
+
const cap = Math.min(nNew, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
35202
|
+
const dl = await options.diskLines();
|
|
35203
|
+
if (dl && cap > 0) {
|
|
35204
|
+
return dl.slice(options.gapNewStart - 1, options.gapNewStart - 1 + cap);
|
|
35205
|
+
}
|
|
35206
|
+
}
|
|
35207
|
+
return null;
|
|
35208
|
+
}
|
|
35209
|
+
if (options.gapOldEnd >= options.gapOldStart && options.change === "removed") {
|
|
35210
|
+
const nOld = options.gapOldEnd - options.gapOldStart + 1;
|
|
35211
|
+
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
35212
|
+
const bl = await options.blobLines();
|
|
35213
|
+
if (bl && cap > 0) {
|
|
35214
|
+
return bl.slice(options.gapOldStart - 1, options.gapOldStart - 1 + cap);
|
|
35215
|
+
}
|
|
35216
|
+
}
|
|
35217
|
+
return null;
|
|
35218
|
+
}
|
|
35219
|
+
|
|
35220
|
+
// src/git/changes/patch/hydrate/consume-unified-hunk-body.ts
|
|
35221
|
+
async function consumeUnifiedHunkBody(options) {
|
|
35222
|
+
let i = options.startIndex;
|
|
35223
|
+
let oldConsumed = 0;
|
|
35224
|
+
let newConsumed = 0;
|
|
35225
|
+
while (i < options.all.length) {
|
|
35226
|
+
await options.maybeYield();
|
|
35227
|
+
const bl = options.all[i];
|
|
35228
|
+
if (UNIFIED_HUNK_HEADER_RE.test(bl)) break;
|
|
35229
|
+
options.out.push(bl);
|
|
35230
|
+
i++;
|
|
35231
|
+
if (bl.startsWith("\\")) continue;
|
|
35232
|
+
const ch = bl[0];
|
|
35233
|
+
if (ch === " ") {
|
|
35234
|
+
oldConsumed++;
|
|
35235
|
+
newConsumed++;
|
|
35236
|
+
} else if (ch === "-") {
|
|
35237
|
+
oldConsumed++;
|
|
35238
|
+
} else if (ch === "+") {
|
|
35239
|
+
newConsumed++;
|
|
35240
|
+
}
|
|
35241
|
+
}
|
|
35242
|
+
return { nextIndex: i, oldConsumed, newConsumed };
|
|
35243
|
+
}
|
|
35244
|
+
|
|
35245
|
+
// src/git/changes/patch/hydrate/read-git-blob-lines.ts
|
|
34334
35246
|
async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
34335
35247
|
try {
|
|
34336
35248
|
const rel = pathInRepo.replace(/\\/g, "/");
|
|
@@ -34340,35 +35252,66 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
34340
35252
|
return null;
|
|
34341
35253
|
}
|
|
34342
35254
|
}
|
|
35255
|
+
|
|
35256
|
+
// src/git/changes/patch/hydrate/read-worktree-file-lines.ts
|
|
35257
|
+
import * as fs25 from "node:fs";
|
|
34343
35258
|
async function readWorktreeFileLines(filePath) {
|
|
34344
35259
|
try {
|
|
34345
|
-
const raw = await
|
|
35260
|
+
const raw = await fs25.promises.readFile(filePath, "utf8");
|
|
34346
35261
|
return raw.split(/\r?\n/);
|
|
34347
35262
|
} catch {
|
|
34348
35263
|
return null;
|
|
34349
35264
|
}
|
|
34350
35265
|
}
|
|
34351
|
-
|
|
34352
|
-
|
|
34353
|
-
|
|
34354
|
-
const out = [];
|
|
34355
|
-
let prevOldEnd = 0;
|
|
34356
|
-
let prevNewEnd = 0;
|
|
34357
|
-
let injectedTotal = 0;
|
|
34358
|
-
let i = 0;
|
|
35266
|
+
|
|
35267
|
+
// src/git/changes/patch/hydrate/create-hydrate-source-lines.ts
|
|
35268
|
+
function createHydrateSourceLines(options) {
|
|
34359
35269
|
let blobCache;
|
|
34360
35270
|
let diskCache;
|
|
34361
35271
|
const blobLines = async () => {
|
|
34362
35272
|
if (blobCache !== void 0) return blobCache;
|
|
34363
|
-
blobCache = await readGitBlobLines(repoGitCwd, pathInRepo);
|
|
35273
|
+
blobCache = await readGitBlobLines(options.repoGitCwd, options.pathInRepo);
|
|
34364
35274
|
return blobCache;
|
|
34365
35275
|
};
|
|
34366
35276
|
const diskLines = async () => {
|
|
34367
35277
|
if (diskCache !== void 0) return diskCache;
|
|
34368
|
-
diskCache = await readWorktreeFileLines(filePath);
|
|
35278
|
+
diskCache = await readWorktreeFileLines(options.filePath);
|
|
34369
35279
|
return diskCache;
|
|
34370
35280
|
};
|
|
35281
|
+
return { blobLines, diskLines };
|
|
35282
|
+
}
|
|
35283
|
+
|
|
35284
|
+
// src/git/changes/patch/hydrate/create-hydrate-yield.ts
|
|
35285
|
+
function createHydrateYield() {
|
|
35286
|
+
let processedLines = 0;
|
|
35287
|
+
return async () => {
|
|
35288
|
+
processedLines++;
|
|
35289
|
+
if (processedLines % HYDRATE_YIELD_EVERY_LINES === 0) {
|
|
35290
|
+
await yieldToEventLoop();
|
|
35291
|
+
}
|
|
35292
|
+
};
|
|
35293
|
+
}
|
|
35294
|
+
|
|
35295
|
+
// src/git/changes/patch/hydrate/update-hunk-line-ends.ts
|
|
35296
|
+
function updateHunkLineEnds(options) {
|
|
35297
|
+
const prevOldEnd = options.oldStart > 0 ? options.oldStart + options.oldConsumed - 1 : 0;
|
|
35298
|
+
const prevNewEnd = options.newStart > 0 ? options.newStart + options.newConsumed - 1 : 0;
|
|
35299
|
+
return { prevOldEnd, prevNewEnd };
|
|
35300
|
+
}
|
|
35301
|
+
|
|
35302
|
+
// src/git/changes/patch/hydrate/hydrate-unified-patch-with-file-context.ts
|
|
35303
|
+
async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, change) {
|
|
35304
|
+
if (!patch.trim() || patch.includes("Binary files")) return patch;
|
|
35305
|
+
const all = patch.split("\n");
|
|
35306
|
+
const out = [];
|
|
35307
|
+
let prevOldEnd = 0;
|
|
35308
|
+
let prevNewEnd = 0;
|
|
35309
|
+
const injectedTotal = { value: 0 };
|
|
35310
|
+
let i = 0;
|
|
35311
|
+
const maybeYield = createHydrateYield();
|
|
35312
|
+
const { blobLines, diskLines } = createHydrateSourceLines({ repoGitCwd, pathInRepo, filePath });
|
|
34371
35313
|
while (i < all.length) {
|
|
35314
|
+
await maybeYield();
|
|
34372
35315
|
const line = all[i];
|
|
34373
35316
|
const hm = line.match(UNIFIED_HUNK_HEADER_RE);
|
|
34374
35317
|
if (!hm) {
|
|
@@ -34378,66 +35321,31 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
34378
35321
|
}
|
|
34379
35322
|
const oldStart = parseInt(hm[1], 10) || 0;
|
|
34380
35323
|
const newStart = parseInt(hm[3], 10) || 0;
|
|
34381
|
-
const
|
|
34382
|
-
|
|
34383
|
-
|
|
34384
|
-
|
|
34385
|
-
|
|
34386
|
-
|
|
34387
|
-
|
|
34388
|
-
|
|
34389
|
-
|
|
34390
|
-
|
|
34391
|
-
|
|
34392
|
-
|
|
34393
|
-
inject = dl.slice(gapNewStart - 1, gapNewStart - 1 + cap);
|
|
34394
|
-
}
|
|
34395
|
-
}
|
|
34396
|
-
} else if (gapOldEnd >= gapOldStart && change === "removed") {
|
|
34397
|
-
const nOld = gapOldEnd - gapOldStart + 1;
|
|
34398
|
-
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, MAX_HYDRATE_LINES_PER_FILE - injectedTotal);
|
|
34399
|
-
const bl = await blobLines();
|
|
34400
|
-
if (bl && cap > 0) {
|
|
34401
|
-
inject = bl.slice(gapOldStart - 1, gapOldStart - 1 + cap);
|
|
34402
|
-
}
|
|
34403
|
-
}
|
|
34404
|
-
if (inject && inject.length > 0) {
|
|
34405
|
-
for (const t of inject) {
|
|
34406
|
-
out.push(` ${t}`);
|
|
34407
|
-
injectedTotal++;
|
|
34408
|
-
}
|
|
34409
|
-
}
|
|
35324
|
+
const inject = await collectGapInjectLines({
|
|
35325
|
+
change,
|
|
35326
|
+
gapOldStart: prevOldEnd + 1,
|
|
35327
|
+
gapOldEnd: oldStart - 1,
|
|
35328
|
+
gapNewStart: prevNewEnd + 1,
|
|
35329
|
+
gapNewEnd: newStart - 1,
|
|
35330
|
+
injectedTotal: injectedTotal.value,
|
|
35331
|
+
blobLines,
|
|
35332
|
+
diskLines
|
|
35333
|
+
});
|
|
35334
|
+
if (inject && inject.length > 0) {
|
|
35335
|
+
await appendInjectedContextLines(out, inject, maybeYield, injectedTotal);
|
|
34410
35336
|
}
|
|
34411
35337
|
out.push(line);
|
|
34412
35338
|
i++;
|
|
34413
|
-
|
|
34414
|
-
|
|
34415
|
-
|
|
34416
|
-
|
|
34417
|
-
|
|
34418
|
-
|
|
34419
|
-
|
|
34420
|
-
|
|
34421
|
-
|
|
34422
|
-
|
|
34423
|
-
oldConsumed++;
|
|
34424
|
-
newConsumed++;
|
|
34425
|
-
} else if (ch === "-") {
|
|
34426
|
-
oldConsumed++;
|
|
34427
|
-
} else if (ch === "+") {
|
|
34428
|
-
newConsumed++;
|
|
34429
|
-
}
|
|
34430
|
-
}
|
|
34431
|
-
if (oldStart > 0) {
|
|
34432
|
-
prevOldEnd = oldStart + oldConsumed - 1;
|
|
34433
|
-
} else {
|
|
34434
|
-
prevOldEnd = 0;
|
|
34435
|
-
}
|
|
34436
|
-
if (newStart > 0) {
|
|
34437
|
-
prevNewEnd = newStart + newConsumed - 1;
|
|
34438
|
-
} else {
|
|
34439
|
-
prevNewEnd = 0;
|
|
34440
|
-
}
|
|
35339
|
+
const body = await consumeUnifiedHunkBody({ all, startIndex: i, out, maybeYield });
|
|
35340
|
+
i = body.nextIndex;
|
|
35341
|
+
const ends = updateHunkLineEnds({
|
|
35342
|
+
oldStart,
|
|
35343
|
+
newStart,
|
|
35344
|
+
oldConsumed: body.oldConsumed,
|
|
35345
|
+
newConsumed: body.newConsumed
|
|
35346
|
+
});
|
|
35347
|
+
prevOldEnd = ends.prevOldEnd;
|
|
35348
|
+
prevNewEnd = ends.prevNewEnd;
|
|
34441
35349
|
}
|
|
34442
35350
|
return truncatePatch(out.join("\n"));
|
|
34443
35351
|
}
|
|
@@ -34446,7 +35354,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
34446
35354
|
async function enrichWorkingTreeFileRows(options) {
|
|
34447
35355
|
await forEachWithGitYield(options.rows, async (row) => {
|
|
34448
35356
|
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
34449
|
-
const filePath =
|
|
35357
|
+
const filePath = path31.join(options.repoGitCwd, pathInRepo);
|
|
34450
35358
|
const hydrateKind = row.change === "moved" ? "modified" : row.change;
|
|
34451
35359
|
let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
|
|
34452
35360
|
if (patch) {
|
|
@@ -34508,14 +35416,76 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34508
35416
|
return dedupeChangedFileRows(rows);
|
|
34509
35417
|
}
|
|
34510
35418
|
|
|
34511
|
-
// src/git/changes/
|
|
35419
|
+
// src/git/changes/repo/norm-repo-rel-path.ts
|
|
34512
35420
|
function normRepoRel(p) {
|
|
34513
35421
|
const x = p.replace(/\\/g, "/").trim();
|
|
34514
35422
|
return x === "" ? "." : x;
|
|
34515
35423
|
}
|
|
35424
|
+
|
|
35425
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
35426
|
+
async function buildWorkingTreeChangeRepoDetail(options) {
|
|
35427
|
+
const t = path32.resolve(options.targetPath);
|
|
35428
|
+
if (!await isGitRepoDirectory(t)) return null;
|
|
35429
|
+
const g = cliSimpleGit(t);
|
|
35430
|
+
let branch = "HEAD";
|
|
35431
|
+
try {
|
|
35432
|
+
await yieldToEventLoop2();
|
|
35433
|
+
branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim() || "HEAD";
|
|
35434
|
+
} catch {
|
|
35435
|
+
branch = "HEAD";
|
|
35436
|
+
}
|
|
35437
|
+
await yieldToEventLoop2();
|
|
35438
|
+
const remoteUrl = await getRemoteOriginUrl(t);
|
|
35439
|
+
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
35440
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path32.resolve(options.sessionWorktreeRootPath) : null;
|
|
35441
|
+
const legacyNested = options.legacyRepoNestedSessionLayout;
|
|
35442
|
+
let repoRelPath;
|
|
35443
|
+
if (sessionWtRoot) {
|
|
35444
|
+
const anchor = legacyNested ? path32.dirname(t) : t;
|
|
35445
|
+
const relNorm = path32.relative(sessionWtRoot, anchor);
|
|
35446
|
+
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
35447
|
+
} else {
|
|
35448
|
+
let top = t;
|
|
35449
|
+
try {
|
|
35450
|
+
await yieldToEventLoop2();
|
|
35451
|
+
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
35452
|
+
} catch {
|
|
35453
|
+
top = t;
|
|
35454
|
+
}
|
|
35455
|
+
const rel = path32.relative(options.bridgeRoot, path32.resolve(top)).replace(/\\/g, "/") || ".";
|
|
35456
|
+
repoRelPath = rel.startsWith("..") ? path32.basename(path32.resolve(top)) : rel;
|
|
35457
|
+
}
|
|
35458
|
+
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
35459
|
+
if (options.repoFilterRelPath && norm !== options.repoFilterRelPath) return null;
|
|
35460
|
+
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
35461
|
+
const relForList = norm === "." ? "." : norm;
|
|
35462
|
+
const files = options.basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, options.basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
35463
|
+
const st = await g.status();
|
|
35464
|
+
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
35465
|
+
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
35466
|
+
listUnpushedCommits(t),
|
|
35467
|
+
listRecentCommits(t, options.recentCommitsLimit)
|
|
35468
|
+
]);
|
|
35469
|
+
return {
|
|
35470
|
+
repoRelPath: norm,
|
|
35471
|
+
repoDisplayName,
|
|
35472
|
+
branch,
|
|
35473
|
+
remoteUrl,
|
|
35474
|
+
remoteDisplay,
|
|
35475
|
+
files,
|
|
35476
|
+
hasUncommittedChanges,
|
|
35477
|
+
unpushedCommits,
|
|
35478
|
+
recentCommits: recentCommitList.commits,
|
|
35479
|
+
recentCommitsHasMore: recentCommitList.hasMore,
|
|
35480
|
+
changesView: options.basis.kind === "commit" ? "commit" : "working",
|
|
35481
|
+
changesCommitSha: options.basis.kind === "commit" ? options.basis.sha.trim() : null
|
|
35482
|
+
};
|
|
35483
|
+
}
|
|
35484
|
+
|
|
35485
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
34516
35486
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
34517
|
-
const bridgeRoot =
|
|
34518
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
35487
|
+
const bridgeRoot = path33.resolve(getBridgeRoot());
|
|
35488
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path33.resolve(options.sessionWorktreeRootPath) : null;
|
|
34519
35489
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
34520
35490
|
const out = [];
|
|
34521
35491
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -34528,59 +35498,18 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34528
35498
|
}
|
|
34529
35499
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
34530
35500
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
34531
|
-
|
|
34532
|
-
const
|
|
34533
|
-
|
|
34534
|
-
|
|
34535
|
-
|
|
34536
|
-
|
|
34537
|
-
|
|
34538
|
-
|
|
34539
|
-
|
|
34540
|
-
|
|
34541
|
-
|
|
34542
|
-
|
|
34543
|
-
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
34544
|
-
let repoRelPath;
|
|
34545
|
-
if (sessionWtRoot) {
|
|
34546
|
-
const anchor = legacyNested ? path22.dirname(t) : t;
|
|
34547
|
-
const relNorm = path22.relative(sessionWtRoot, anchor);
|
|
34548
|
-
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
34549
|
-
} else {
|
|
34550
|
-
let top = t;
|
|
34551
|
-
try {
|
|
34552
|
-
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
34553
|
-
} catch {
|
|
34554
|
-
top = t;
|
|
34555
|
-
}
|
|
34556
|
-
const rel = path22.relative(bridgeRoot, path22.resolve(top)).replace(/\\/g, "/") || ".";
|
|
34557
|
-
repoRelPath = rel.startsWith("..") ? path22.basename(path22.resolve(top)) : rel;
|
|
34558
|
-
}
|
|
34559
|
-
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
34560
|
-
if (filter && norm !== filter) continue;
|
|
34561
|
-
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
34562
|
-
const relForList = norm === "." ? "." : norm;
|
|
34563
|
-
const files = basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
34564
|
-
const st = await g.status();
|
|
34565
|
-
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
34566
|
-
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
34567
|
-
listUnpushedCommits(t),
|
|
34568
|
-
listRecentCommits(t, options.recentCommitsLimit)
|
|
34569
|
-
]);
|
|
34570
|
-
out.push({
|
|
34571
|
-
repoRelPath: norm,
|
|
34572
|
-
repoDisplayName,
|
|
34573
|
-
branch,
|
|
34574
|
-
remoteUrl,
|
|
34575
|
-
remoteDisplay,
|
|
34576
|
-
files,
|
|
34577
|
-
hasUncommittedChanges,
|
|
34578
|
-
unpushedCommits,
|
|
34579
|
-
recentCommits: recentCommitList.commits,
|
|
34580
|
-
recentCommitsHasMore: recentCommitList.hasMore,
|
|
34581
|
-
changesView: basis.kind === "commit" ? "commit" : "working",
|
|
34582
|
-
changesCommitSha: basis.kind === "commit" ? basis.sha.trim() : null
|
|
34583
|
-
});
|
|
35501
|
+
await yieldToEventLoop2();
|
|
35502
|
+
const detail = await buildWorkingTreeChangeRepoDetail({
|
|
35503
|
+
targetPath: options.commitTargetPaths[i],
|
|
35504
|
+
bridgeRoot,
|
|
35505
|
+
sessionWorktreeRootPath: sessionWtRoot,
|
|
35506
|
+
legacyRepoNestedSessionLayout: legacyNested,
|
|
35507
|
+
repoFilterRelPath: filter,
|
|
35508
|
+
basis,
|
|
35509
|
+
recentCommitsLimit: options.recentCommitsLimit
|
|
35510
|
+
});
|
|
35511
|
+
if (!detail) continue;
|
|
35512
|
+
out.push(detail);
|
|
34584
35513
|
if (filter) return out;
|
|
34585
35514
|
}
|
|
34586
35515
|
return out;
|
|
@@ -34682,23 +35611,23 @@ async function commitSessionWorktrees(options) {
|
|
|
34682
35611
|
}
|
|
34683
35612
|
|
|
34684
35613
|
// src/worktrees/remove-session-worktrees.ts
|
|
34685
|
-
import * as
|
|
35614
|
+
import * as fs28 from "node:fs";
|
|
34686
35615
|
|
|
34687
35616
|
// src/git/worktrees/worktree-remove.ts
|
|
34688
|
-
import * as
|
|
35617
|
+
import * as fs27 from "node:fs";
|
|
34689
35618
|
|
|
34690
35619
|
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
34691
|
-
import * as
|
|
34692
|
-
import * as
|
|
35620
|
+
import * as fs26 from "node:fs";
|
|
35621
|
+
import * as path34 from "node:path";
|
|
34693
35622
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34694
|
-
const gitDirFile =
|
|
34695
|
-
if (!
|
|
34696
|
-
const first2 =
|
|
35623
|
+
const gitDirFile = path34.join(wt, ".git");
|
|
35624
|
+
if (!fs26.existsSync(gitDirFile) || !fs26.statSync(gitDirFile).isFile()) return "";
|
|
35625
|
+
const first2 = fs26.readFileSync(gitDirFile, "utf8").trim();
|
|
34697
35626
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34698
35627
|
if (!m) return "";
|
|
34699
|
-
const gitWorktreePath =
|
|
34700
|
-
const gitDir =
|
|
34701
|
-
return
|
|
35628
|
+
const gitWorktreePath = path34.resolve(wt, m[1].trim());
|
|
35629
|
+
const gitDir = path34.dirname(path34.dirname(gitWorktreePath));
|
|
35630
|
+
return path34.dirname(gitDir);
|
|
34702
35631
|
}
|
|
34703
35632
|
|
|
34704
35633
|
// src/git/worktrees/worktree-remove.ts
|
|
@@ -34707,7 +35636,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
34707
35636
|
if (mainRepo) {
|
|
34708
35637
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34709
35638
|
} else {
|
|
34710
|
-
|
|
35639
|
+
fs27.rmSync(worktreePath, { recursive: true, force: true });
|
|
34711
35640
|
}
|
|
34712
35641
|
}
|
|
34713
35642
|
|
|
@@ -34720,7 +35649,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
34720
35649
|
} catch (e) {
|
|
34721
35650
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34722
35651
|
try {
|
|
34723
|
-
|
|
35652
|
+
fs28.rmSync(wt, { recursive: true, force: true });
|
|
34724
35653
|
} catch {
|
|
34725
35654
|
}
|
|
34726
35655
|
}
|
|
@@ -34748,458 +35677,86 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
34748
35677
|
}
|
|
34749
35678
|
}
|
|
34750
35679
|
|
|
34751
|
-
// src/worktrees/
|
|
34752
|
-
|
|
34753
|
-
import * as path24 from "node:path";
|
|
34754
|
-
import os7 from "node:os";
|
|
34755
|
-
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
34756
|
-
function defaultWorktreeLayoutPath() {
|
|
34757
|
-
return path24.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
34758
|
-
}
|
|
34759
|
-
function normalizeLoadedLayout(raw) {
|
|
34760
|
-
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
34761
|
-
const j = raw;
|
|
34762
|
-
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
34763
|
-
}
|
|
34764
|
-
return { launcherCwds: [] };
|
|
34765
|
-
}
|
|
34766
|
-
function loadWorktreeLayout() {
|
|
34767
|
-
try {
|
|
34768
|
-
const p = defaultWorktreeLayoutPath();
|
|
34769
|
-
if (!fs22.existsSync(p)) return { launcherCwds: [] };
|
|
34770
|
-
const raw = JSON.parse(fs22.readFileSync(p, "utf8"));
|
|
34771
|
-
return normalizeLoadedLayout(raw);
|
|
34772
|
-
} catch {
|
|
34773
|
-
return { launcherCwds: [] };
|
|
34774
|
-
}
|
|
34775
|
-
}
|
|
34776
|
-
function saveWorktreeLayout(layout) {
|
|
34777
|
-
try {
|
|
34778
|
-
const dir = path24.dirname(defaultWorktreeLayoutPath());
|
|
34779
|
-
fs22.mkdirSync(dir, { recursive: true });
|
|
34780
|
-
fs22.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
34781
|
-
} catch {
|
|
34782
|
-
}
|
|
34783
|
-
}
|
|
34784
|
-
function baseNameSafe(pathString) {
|
|
34785
|
-
return path24.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
34786
|
-
}
|
|
34787
|
-
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
34788
|
-
const norm = path24.resolve(bridgeRootPath2);
|
|
34789
|
-
const existing = layout.launcherCwds.find((e) => path24.resolve(e.absolutePath) === norm);
|
|
34790
|
-
return existing?.dirName;
|
|
34791
|
-
}
|
|
34792
|
-
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
34793
|
-
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
34794
|
-
if (existing) return existing;
|
|
34795
|
-
const norm = path24.resolve(bridgeRootPath2);
|
|
34796
|
-
const base = baseNameSafe(norm);
|
|
34797
|
-
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
34798
|
-
let name = base;
|
|
34799
|
-
let n = 2;
|
|
34800
|
-
while (used.has(name)) {
|
|
34801
|
-
name = `${base}-${n}`;
|
|
34802
|
-
n += 1;
|
|
34803
|
-
}
|
|
34804
|
-
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
34805
|
-
saveWorktreeLayout(layout);
|
|
34806
|
-
return name;
|
|
34807
|
-
}
|
|
34808
|
-
|
|
34809
|
-
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
34810
|
-
import * as fs23 from "node:fs";
|
|
34811
|
-
import * as path25 from "node:path";
|
|
34812
|
-
function isGitDir(dirPath) {
|
|
34813
|
-
try {
|
|
34814
|
-
return fs23.existsSync(path25.join(dirPath, ".git"));
|
|
34815
|
-
} catch {
|
|
34816
|
-
return false;
|
|
34817
|
-
}
|
|
34818
|
-
}
|
|
34819
|
-
function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
34820
|
-
const out = [];
|
|
34821
|
-
const walk = (dir) => {
|
|
34822
|
-
if (isGitDir(dir)) {
|
|
34823
|
-
out.push(path25.resolve(dir));
|
|
34824
|
-
return;
|
|
34825
|
-
}
|
|
34826
|
-
let entries;
|
|
34827
|
-
try {
|
|
34828
|
-
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
34829
|
-
} catch {
|
|
34830
|
-
return;
|
|
34831
|
-
}
|
|
34832
|
-
for (const e of entries) {
|
|
34833
|
-
if (e.name.startsWith(".")) continue;
|
|
34834
|
-
const full = path25.join(dir, e.name);
|
|
34835
|
-
if (!e.isDirectory()) continue;
|
|
34836
|
-
walk(full);
|
|
34837
|
-
}
|
|
34838
|
-
};
|
|
34839
|
-
walk(path25.resolve(rootPath));
|
|
34840
|
-
return [...new Set(out)];
|
|
34841
|
-
}
|
|
34842
|
-
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
34843
|
-
const out = [];
|
|
34844
|
-
const walk = (dir, depth) => {
|
|
34845
|
-
if (depth > maxDepth) return;
|
|
34846
|
-
let entries;
|
|
34847
|
-
try {
|
|
34848
|
-
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
34849
|
-
} catch {
|
|
34850
|
-
return;
|
|
34851
|
-
}
|
|
34852
|
-
for (const e of entries) {
|
|
34853
|
-
if (e.name.startsWith(".")) continue;
|
|
34854
|
-
const full = path25.join(dir, e.name);
|
|
34855
|
-
if (!e.isDirectory()) continue;
|
|
34856
|
-
if (e.name === sessionId) {
|
|
34857
|
-
if (isGitDir(full)) out.push(path25.resolve(full));
|
|
34858
|
-
} else {
|
|
34859
|
-
walk(full, depth + 1);
|
|
34860
|
-
}
|
|
34861
|
-
}
|
|
34862
|
-
};
|
|
34863
|
-
walk(root, 0);
|
|
34864
|
-
return out;
|
|
34865
|
-
}
|
|
34866
|
-
function tryBindingFromSessionDirectory(sessionDir) {
|
|
34867
|
-
let st;
|
|
34868
|
-
try {
|
|
34869
|
-
st = fs23.statSync(sessionDir);
|
|
34870
|
-
} catch {
|
|
34871
|
-
return null;
|
|
34872
|
-
}
|
|
34873
|
-
if (!st.isDirectory()) return null;
|
|
34874
|
-
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
34875
|
-
if (worktreePaths.length === 0) return null;
|
|
34876
|
-
const abs = path25.resolve(sessionDir);
|
|
34877
|
-
return {
|
|
34878
|
-
sessionParentPath: abs,
|
|
34879
|
-
workingTreeRelRoot: abs,
|
|
34880
|
-
repoCheckoutPaths: worktreePaths
|
|
34881
|
-
};
|
|
34882
|
-
}
|
|
34883
|
-
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
34884
|
-
const sid = sessionId.trim();
|
|
34885
|
-
if (!sid) return null;
|
|
34886
|
-
const hintR = path25.resolve(checkoutPath);
|
|
34887
|
-
let best = null;
|
|
34888
|
-
let cur = path25.dirname(hintR);
|
|
34889
|
-
for (let i = 0; i < 40; i++) {
|
|
34890
|
-
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
34891
|
-
if (paths.some((p) => path25.resolve(p) === hintR)) {
|
|
34892
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path25.resolve(paths[0]);
|
|
34893
|
-
best = {
|
|
34894
|
-
sessionParentPath: path25.resolve(isolated),
|
|
34895
|
-
workingTreeRelRoot: path25.resolve(cur),
|
|
34896
|
-
repoCheckoutPaths: paths.map((p) => path25.resolve(p))
|
|
34897
|
-
};
|
|
34898
|
-
}
|
|
34899
|
-
const next = path25.dirname(cur);
|
|
34900
|
-
if (next === cur) break;
|
|
34901
|
-
cur = next;
|
|
34902
|
-
}
|
|
34903
|
-
return best;
|
|
34904
|
-
}
|
|
34905
|
-
function discoverSessionWorktreeOnDisk(options) {
|
|
34906
|
-
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
34907
|
-
if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
|
|
34908
|
-
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34909
|
-
const keys = [];
|
|
34910
|
-
if (preferredKey) keys.push(preferredKey);
|
|
34911
|
-
try {
|
|
34912
|
-
for (const name of fs23.readdirSync(worktreesRootPath)) {
|
|
34913
|
-
if (name.startsWith(".")) continue;
|
|
34914
|
-
const p = path25.join(worktreesRootPath, name);
|
|
34915
|
-
if (!fs23.statSync(p).isDirectory()) continue;
|
|
34916
|
-
if (name !== preferredKey) keys.push(name);
|
|
34917
|
-
}
|
|
34918
|
-
} catch {
|
|
34919
|
-
return null;
|
|
34920
|
-
}
|
|
34921
|
-
for (const key of keys) {
|
|
34922
|
-
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
34923
|
-
if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
|
|
34924
|
-
const sessionDir = path25.join(layoutRoot, sessionId);
|
|
34925
|
-
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
34926
|
-
if (nested) return nested;
|
|
34927
|
-
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
34928
|
-
if (legacyPaths.length > 0) {
|
|
34929
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
34930
|
-
return {
|
|
34931
|
-
sessionParentPath: path25.resolve(isolated),
|
|
34932
|
-
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
34933
|
-
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
34934
|
-
};
|
|
34935
|
-
}
|
|
34936
|
-
}
|
|
34937
|
-
return null;
|
|
34938
|
-
}
|
|
34939
|
-
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
34940
|
-
const sid = sessionId.trim();
|
|
34941
|
-
if (!sid) return null;
|
|
34942
|
-
const hint = path25.resolve(sessionWorktreeRootPathOrHint);
|
|
34943
|
-
const underHint = tryBindingFromSessionDirectory(path25.join(hint, sid));
|
|
34944
|
-
if (underHint) return underHint;
|
|
34945
|
-
const direct = tryBindingFromSessionDirectory(hint);
|
|
34946
|
-
if (direct) {
|
|
34947
|
-
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
34948
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34949
|
-
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
34950
|
-
return legacyFromCheckout;
|
|
34951
|
-
}
|
|
34952
|
-
}
|
|
34953
|
-
return direct;
|
|
34954
|
-
}
|
|
34955
|
-
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
34956
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34957
|
-
if (legacyFromCheckout) return legacyFromCheckout;
|
|
34958
|
-
}
|
|
34959
|
-
let st;
|
|
34960
|
-
try {
|
|
34961
|
-
st = fs23.statSync(hint);
|
|
34962
|
-
} catch {
|
|
34963
|
-
return null;
|
|
34964
|
-
}
|
|
34965
|
-
if (!st.isDirectory()) return null;
|
|
34966
|
-
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
34967
|
-
if (legacyPaths.length === 0) return null;
|
|
34968
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
35680
|
+
// src/worktrees/manager/resolve-commit-targets.ts
|
|
35681
|
+
function bridgeRootBinding(bridgeRoot) {
|
|
34969
35682
|
return {
|
|
34970
|
-
sessionParentPath:
|
|
34971
|
-
workingTreeRelRoot:
|
|
34972
|
-
repoCheckoutPaths:
|
|
35683
|
+
sessionParentPath: bridgeRoot,
|
|
35684
|
+
workingTreeRelRoot: bridgeRoot,
|
|
35685
|
+
repoCheckoutPaths: [bridgeRoot]
|
|
34973
35686
|
};
|
|
34974
35687
|
}
|
|
34975
|
-
|
|
34976
|
-
// src/worktrees/manager/discover-session-binding.ts
|
|
34977
|
-
function discoverSessionBinding(params) {
|
|
34978
|
-
return discoverSessionWorktreeOnDisk({
|
|
34979
|
-
sessionId: params.sessionId,
|
|
34980
|
-
worktreesRootPath: params.worktreesRootPath,
|
|
34981
|
-
layout: params.layout,
|
|
34982
|
-
bridgeRoot: getBridgeRoot()
|
|
34983
|
-
});
|
|
34984
|
-
}
|
|
34985
|
-
|
|
34986
|
-
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
34987
|
-
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
34988
|
-
if (!sessionId) return null;
|
|
34989
|
-
const sid = sessionId.trim();
|
|
34990
|
-
const cached2 = cache2.getSessionParentPath(sid);
|
|
34991
|
-
if (cached2) return cached2;
|
|
34992
|
-
const paths = ensureRepoCheckoutPaths(sid);
|
|
34993
|
-
if (!paths?.length) return null;
|
|
34994
|
-
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
34995
|
-
}
|
|
34996
|
-
function ensureRepoCheckoutPathsForSession(sessionId, cache2, discover) {
|
|
34997
|
-
if (!sessionId?.trim()) return void 0;
|
|
35688
|
+
async function resolveCommitTargetsAsync(sessionId, cache2, discover) {
|
|
34998
35689
|
const sid = sessionId.trim();
|
|
34999
|
-
const
|
|
35000
|
-
if (cached2?.length) return cached2;
|
|
35001
|
-
const disc = discover(sid);
|
|
35002
|
-
if (disc?.repoCheckoutPaths.length) {
|
|
35003
|
-
cache2.remember(sid, disc);
|
|
35004
|
-
return [...disc.repoCheckoutPaths];
|
|
35005
|
-
}
|
|
35006
|
-
return void 0;
|
|
35007
|
-
}
|
|
35008
|
-
|
|
35009
|
-
// src/worktrees/manager/resolve-commit-targets.ts
|
|
35010
|
-
function resolveCommitTargets(sessionId, cache2, discover) {
|
|
35011
|
-
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
35690
|
+
const paths = cache2.getRepoCheckoutPathsRef(sid);
|
|
35012
35691
|
if (paths?.length) return paths;
|
|
35013
|
-
const disc = discover(
|
|
35692
|
+
const disc = await discover(sid);
|
|
35014
35693
|
if (disc?.repoCheckoutPaths.length) {
|
|
35015
|
-
cache2.remember(
|
|
35694
|
+
cache2.remember(sid, disc);
|
|
35016
35695
|
return disc.repoCheckoutPaths;
|
|
35017
35696
|
}
|
|
35018
|
-
|
|
35697
|
+
const bridgeRoot = getBridgeRoot();
|
|
35698
|
+
cache2.remember(sid, bridgeRootBinding(bridgeRoot));
|
|
35699
|
+
return [bridgeRoot];
|
|
35019
35700
|
}
|
|
35020
35701
|
|
|
35021
|
-
// src/worktrees/manager/
|
|
35022
|
-
function
|
|
35023
|
-
|
|
35024
|
-
|
|
35025
|
-
return
|
|
35026
|
-
|
|
35027
|
-
|
|
35028
|
-
|
|
35029
|
-
|
|
35030
|
-
|
|
35031
|
-
|
|
35032
|
-
// src/git/worktrees/worktree-add.ts
|
|
35033
|
-
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
35034
|
-
const mainGit = cliSimpleGit(mainRepoPath);
|
|
35035
|
-
const base = baseRef.trim() || "HEAD";
|
|
35036
|
-
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
35037
|
-
}
|
|
35038
|
-
|
|
35039
|
-
// src/worktrees/prepare-new-session-worktrees.ts
|
|
35040
|
-
function normalizeRepoRelPath2(rel) {
|
|
35041
|
-
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
35042
|
-
}
|
|
35043
|
-
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
35044
|
-
if (!baseBranches) return "HEAD";
|
|
35045
|
-
const direct = baseBranches[relNorm]?.trim();
|
|
35046
|
-
if (direct) return direct;
|
|
35047
|
-
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
35048
|
-
return "HEAD";
|
|
35702
|
+
// src/worktrees/manager/session-git-ops.ts
|
|
35703
|
+
async function commitSessionWorktree(cache2, params) {
|
|
35704
|
+
const paths = cache2.getRepoCheckoutPathsRef(params.sessionId);
|
|
35705
|
+
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
35706
|
+
return commitSessionWorktrees({
|
|
35707
|
+
paths: targets,
|
|
35708
|
+
branch: params.branch,
|
|
35709
|
+
message: params.message,
|
|
35710
|
+
push: params.push
|
|
35711
|
+
});
|
|
35049
35712
|
}
|
|
35050
|
-
async function
|
|
35051
|
-
|
|
35052
|
-
|
|
35053
|
-
|
|
35054
|
-
const bridgeKeyDir = path26.join(worktreesRootPath, cwdKey);
|
|
35055
|
-
const sessionDir = path26.join(bridgeKeyDir, sessionId);
|
|
35056
|
-
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
35057
|
-
if (repos.length === 0) {
|
|
35058
|
-
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
35059
|
-
return null;
|
|
35060
|
-
}
|
|
35061
|
-
const branch = `session-${sessionId}`;
|
|
35062
|
-
const worktreePaths = [];
|
|
35063
|
-
fs24.mkdirSync(sessionDir, { recursive: true });
|
|
35064
|
-
for (const repo of repos) {
|
|
35065
|
-
let rel = path26.relative(bridgeResolved, repo.absolutePath);
|
|
35066
|
-
if (rel.startsWith("..") || path26.isAbsolute(rel)) continue;
|
|
35067
|
-
const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
|
|
35068
|
-
const wtPath = relNorm === "." ? sessionDir : path26.join(sessionDir, relNorm);
|
|
35069
|
-
if (relNorm !== ".") {
|
|
35070
|
-
fs24.mkdirSync(path26.dirname(wtPath), { recursive: true });
|
|
35071
|
-
}
|
|
35072
|
-
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
35073
|
-
try {
|
|
35074
|
-
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
35075
|
-
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
35076
|
-
worktreePaths.push(wtPath);
|
|
35077
|
-
} catch (e) {
|
|
35078
|
-
log2(
|
|
35079
|
-
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
35080
|
-
);
|
|
35081
|
-
}
|
|
35082
|
-
}
|
|
35083
|
-
if (worktreePaths.length === 0) return null;
|
|
35084
|
-
return {
|
|
35085
|
-
worktreePaths,
|
|
35086
|
-
sessionParentPath: sessionDir,
|
|
35087
|
-
workingTreeRelRoot: sessionDir
|
|
35088
|
-
};
|
|
35713
|
+
async function getSessionWorkingTreeStatus(cache2, sessionId, discover) {
|
|
35714
|
+
return aggregateSessionPathsWorkingTreeStatus(
|
|
35715
|
+
await resolveCommitTargetsAsync(sessionId, cache2, discover)
|
|
35716
|
+
);
|
|
35089
35717
|
}
|
|
35090
|
-
|
|
35091
|
-
|
|
35092
|
-
|
|
35093
|
-
|
|
35094
|
-
|
|
35095
|
-
|
|
35096
|
-
|
|
35097
|
-
|
|
35098
|
-
|
|
35099
|
-
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
35718
|
+
async function getSessionWorkingTreeChangeDetails(cache2, sessionId, discover, opts) {
|
|
35719
|
+
const targets = await resolveCommitTargetsAsync(sessionId, cache2, discover);
|
|
35720
|
+
return getWorkingTreeChangeRepoDetails({
|
|
35721
|
+
commitTargetPaths: targets,
|
|
35722
|
+
sessionWorktreeRootPath: cache2.getWorkingTreeRelRoot(sessionId),
|
|
35723
|
+
legacyRepoNestedSessionLayout: cache2.isLegacyNestedLayout(sessionId),
|
|
35724
|
+
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
35725
|
+
basis: opts?.basis,
|
|
35726
|
+
recentCommitsLimit: opts?.recentCommitsLimit
|
|
35100
35727
|
});
|
|
35101
|
-
if (!prep) return void 0;
|
|
35102
|
-
params.cache.remember(params.sessionId, {
|
|
35103
|
-
sessionParentPath: prep.sessionParentPath,
|
|
35104
|
-
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
35105
|
-
repoCheckoutPaths: prep.worktreePaths
|
|
35106
|
-
});
|
|
35107
|
-
return params.cache.getSessionParentPath(params.sessionId);
|
|
35108
35728
|
}
|
|
35109
|
-
|
|
35110
|
-
|
|
35111
|
-
|
|
35112
|
-
|
|
35113
|
-
|
|
35114
|
-
|
|
35115
|
-
|
|
35116
|
-
cache2.remember(sessionId, disc);
|
|
35117
|
-
return cache2.getSessionParentPath(sessionId);
|
|
35729
|
+
async function pushSessionUpstream(cache2, sessionId, discover) {
|
|
35730
|
+
try {
|
|
35731
|
+
await pushAheadOfUpstreamForPaths(await resolveCommitTargetsAsync(sessionId, cache2, discover));
|
|
35732
|
+
return { ok: true };
|
|
35733
|
+
} catch (e) {
|
|
35734
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
35735
|
+
return { ok: false, error: err };
|
|
35118
35736
|
}
|
|
35119
|
-
return void 0;
|
|
35120
35737
|
}
|
|
35121
|
-
|
|
35122
|
-
|
|
35123
|
-
|
|
35124
|
-
|
|
35125
|
-
const resolved = path27.resolve(params.parentPathRaw);
|
|
35126
|
-
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
35127
|
-
return resolved;
|
|
35128
|
-
}
|
|
35129
|
-
const rememberAndReturn = (binding) => {
|
|
35130
|
-
params.cache.remember(params.sessionId, binding);
|
|
35131
|
-
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
35132
|
-
};
|
|
35133
|
-
const diskFirst = params.discover();
|
|
35134
|
-
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
35135
|
-
const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
35136
|
-
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
35137
|
-
let cur = resolved;
|
|
35138
|
-
for (let i = 0; i < 16; i++) {
|
|
35139
|
-
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
35140
|
-
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
35141
|
-
const next = path27.dirname(cur);
|
|
35142
|
-
if (next === cur) break;
|
|
35143
|
-
cur = next;
|
|
35144
|
-
}
|
|
35145
|
-
return resolved;
|
|
35738
|
+
async function removeSessionWorktreeCheckouts(cache2, sessionId, log2) {
|
|
35739
|
+
const paths = cache2.clearSession(sessionId);
|
|
35740
|
+
if (!paths?.length) return;
|
|
35741
|
+
await removeSessionWorktrees(paths, log2);
|
|
35146
35742
|
}
|
|
35147
|
-
|
|
35148
|
-
|
|
35149
|
-
|
|
35150
|
-
|
|
35151
|
-
if (!sessionId) return void 0;
|
|
35152
|
-
const sid = sessionId.trim();
|
|
35153
|
-
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
35154
|
-
if (parentPathRaw) {
|
|
35155
|
-
return resolveExplicitSessionParentPath({
|
|
35156
|
-
sessionId: sid,
|
|
35157
|
-
sessionParent: opts.sessionParent,
|
|
35158
|
-
parentPathRaw,
|
|
35159
|
-
cache: cache2,
|
|
35160
|
-
discover: () => discover(sid)
|
|
35161
|
-
});
|
|
35162
|
-
}
|
|
35163
|
-
const parentKind = parseSessionParent(opts.sessionParent);
|
|
35164
|
-
if (parentKind === "bridge_root") {
|
|
35165
|
-
return void 0;
|
|
35166
|
-
}
|
|
35167
|
-
if (parentKind === "worktrees_root") {
|
|
35168
|
-
if (!opts.isNewSession) {
|
|
35169
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
35170
|
-
}
|
|
35171
|
-
return prepareAndRememberSessionWorktrees({
|
|
35172
|
-
cache: cache2,
|
|
35173
|
-
sessionId: sid,
|
|
35174
|
-
worktreesRootPath,
|
|
35175
|
-
layout,
|
|
35176
|
-
log: log2,
|
|
35177
|
-
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
35178
|
-
});
|
|
35179
|
-
}
|
|
35180
|
-
if (!opts.isNewSession) {
|
|
35181
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
35182
|
-
}
|
|
35183
|
-
return prepareAndRememberSessionWorktrees({
|
|
35184
|
-
cache: cache2,
|
|
35185
|
-
sessionId: sid,
|
|
35186
|
-
worktreesRootPath,
|
|
35187
|
-
layout,
|
|
35188
|
-
log: log2
|
|
35189
|
-
});
|
|
35743
|
+
async function renameSessionWorktreeBranch(cache2, sessionId, newBranch, log2) {
|
|
35744
|
+
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
35745
|
+
if (!paths?.length) return;
|
|
35746
|
+
await renameSessionWorktreeBranches(paths, newBranch, log2);
|
|
35190
35747
|
}
|
|
35191
35748
|
|
|
35192
35749
|
// src/worktrees/manager/session-worktree-cache.ts
|
|
35193
|
-
import * as
|
|
35750
|
+
import * as path35 from "node:path";
|
|
35194
35751
|
var SessionWorktreeCache = class {
|
|
35195
35752
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
35196
35753
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
35197
35754
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
35198
35755
|
remember(sessionId, binding) {
|
|
35199
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
35756
|
+
const paths = binding.repoCheckoutPaths.map((p) => path35.resolve(p));
|
|
35200
35757
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
35201
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
35202
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
35758
|
+
this.sessionParentPathBySession.set(sessionId, path35.resolve(binding.sessionParentPath));
|
|
35759
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path35.resolve(binding.workingTreeRelRoot));
|
|
35203
35760
|
}
|
|
35204
35761
|
clearSession(sessionId) {
|
|
35205
35762
|
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
@@ -35229,7 +35786,7 @@ var SessionWorktreeCache = class {
|
|
|
35229
35786
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
35230
35787
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
35231
35788
|
if (!parent || !relRoot) return false;
|
|
35232
|
-
return
|
|
35789
|
+
return path35.resolve(parent) !== path35.resolve(relRoot);
|
|
35233
35790
|
}
|
|
35234
35791
|
};
|
|
35235
35792
|
|
|
@@ -35244,8 +35801,8 @@ var SessionWorktreeManager = class {
|
|
|
35244
35801
|
this.log = options.log;
|
|
35245
35802
|
this.layout = loadWorktreeLayout();
|
|
35246
35803
|
}
|
|
35247
|
-
|
|
35248
|
-
return
|
|
35804
|
+
discoverAsync(sessionId) {
|
|
35805
|
+
return discoverSessionBindingAsync({
|
|
35249
35806
|
sessionId,
|
|
35250
35807
|
worktreesRootPath: this.worktreesRootPath,
|
|
35251
35808
|
layout: this.layout
|
|
@@ -35265,14 +35822,12 @@ var SessionWorktreeManager = class {
|
|
|
35265
35822
|
worktreesRootPath: this.worktreesRootPath,
|
|
35266
35823
|
layout: this.layout,
|
|
35267
35824
|
log: this.log,
|
|
35268
|
-
discover: (sid) => this.
|
|
35825
|
+
discover: (sid) => this.discoverAsync(sid),
|
|
35269
35826
|
opts
|
|
35270
35827
|
});
|
|
35271
35828
|
}
|
|
35272
35829
|
async renameSessionBranch(sessionId, newBranch) {
|
|
35273
|
-
|
|
35274
|
-
if (!paths?.length) return;
|
|
35275
|
-
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
35830
|
+
await renameSessionWorktreeBranch(this.cache, sessionId, newBranch, this.log);
|
|
35276
35831
|
}
|
|
35277
35832
|
usesWorktreeSession(sessionId) {
|
|
35278
35833
|
if (!sessionId) return false;
|
|
@@ -35283,79 +35838,55 @@ var SessionWorktreeManager = class {
|
|
|
35283
35838
|
return this.cache.getRepoCheckoutPaths(sessionId);
|
|
35284
35839
|
}
|
|
35285
35840
|
ensureRepoCheckoutPathsForSession(sessionId) {
|
|
35286
|
-
return ensureRepoCheckoutPathsForSession(sessionId, this.cache
|
|
35841
|
+
return ensureRepoCheckoutPathsForSession(sessionId, this.cache);
|
|
35842
|
+
}
|
|
35843
|
+
async ensureRepoCheckoutPathsForSessionAsync(sessionId) {
|
|
35844
|
+
return ensureRepoCheckoutPathsForSessionAsync(sessionId, this.cache, (sid) => this.discoverAsync(sid));
|
|
35287
35845
|
}
|
|
35288
35846
|
getSessionWorktreeRootForSession(sessionId) {
|
|
35289
35847
|
return this.getIsolatedSessionParentPathForSession(sessionId);
|
|
35290
35848
|
}
|
|
35291
35849
|
async removeSessionWorktrees(sessionId) {
|
|
35292
|
-
|
|
35293
|
-
if (!paths?.length) return;
|
|
35294
|
-
await removeSessionWorktrees(paths, this.log);
|
|
35850
|
+
await removeSessionWorktreeCheckouts(this.cache, sessionId, this.log);
|
|
35295
35851
|
}
|
|
35296
35852
|
async commitSession(params) {
|
|
35297
|
-
|
|
35298
|
-
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
35299
|
-
return commitSessionWorktrees({
|
|
35300
|
-
paths: targets,
|
|
35301
|
-
branch: params.branch,
|
|
35302
|
-
message: params.message,
|
|
35303
|
-
push: params.push
|
|
35304
|
-
});
|
|
35853
|
+
return commitSessionWorktree(this.cache, params);
|
|
35305
35854
|
}
|
|
35306
35855
|
async getSessionWorkingTreeStatus(sessionId) {
|
|
35307
|
-
return
|
|
35308
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
35309
|
-
);
|
|
35856
|
+
return getSessionWorkingTreeStatus(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
35310
35857
|
}
|
|
35311
35858
|
async getSessionWorkingTreeChangeDetails(sessionId, opts) {
|
|
35312
|
-
|
|
35313
|
-
return getWorkingTreeChangeRepoDetails({
|
|
35314
|
-
commitTargetPaths: targets,
|
|
35315
|
-
sessionWorktreeRootPath: this.cache.getWorkingTreeRelRoot(sessionId),
|
|
35316
|
-
legacyRepoNestedSessionLayout: this.cache.isLegacyNestedLayout(sessionId),
|
|
35317
|
-
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
35318
|
-
basis: opts?.basis,
|
|
35319
|
-
recentCommitsLimit: opts?.recentCommitsLimit
|
|
35320
|
-
});
|
|
35859
|
+
return getSessionWorkingTreeChangeDetails(this.cache, sessionId, (sid) => this.discoverAsync(sid), opts);
|
|
35321
35860
|
}
|
|
35322
35861
|
async pushSessionUpstream(sessionId) {
|
|
35323
|
-
|
|
35324
|
-
await pushAheadOfUpstreamForPaths(
|
|
35325
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
35326
|
-
);
|
|
35327
|
-
return { ok: true };
|
|
35328
|
-
} catch (e) {
|
|
35329
|
-
const err = e instanceof Error ? e.message : String(e);
|
|
35330
|
-
return { ok: false, error: err };
|
|
35331
|
-
}
|
|
35862
|
+
return pushSessionUpstream(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
35332
35863
|
}
|
|
35333
35864
|
};
|
|
35334
35865
|
|
|
35335
35866
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
35336
|
-
import * as
|
|
35867
|
+
import * as path36 from "node:path";
|
|
35337
35868
|
import os8 from "node:os";
|
|
35338
35869
|
function defaultWorktreesRootPath() {
|
|
35339
|
-
return
|
|
35870
|
+
return path36.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
35340
35871
|
}
|
|
35341
35872
|
|
|
35342
35873
|
// src/files/watch-file-index.ts
|
|
35343
35874
|
import { watch } from "node:fs";
|
|
35344
|
-
import
|
|
35875
|
+
import path41 from "node:path";
|
|
35345
35876
|
|
|
35346
35877
|
// src/files/index/paths.ts
|
|
35347
|
-
import
|
|
35878
|
+
import path37 from "node:path";
|
|
35348
35879
|
import crypto2 from "node:crypto";
|
|
35349
35880
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
35350
|
-
return crypto2.createHash("sha256").update(
|
|
35881
|
+
return crypto2.createHash("sha256").update(path37.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
35351
35882
|
}
|
|
35352
35883
|
|
|
35353
35884
|
// src/files/index/build-file-index.ts
|
|
35354
|
-
import
|
|
35885
|
+
import path39 from "node:path";
|
|
35355
35886
|
|
|
35356
35887
|
// src/files/index/walk-workspace-tree.ts
|
|
35357
|
-
import
|
|
35358
|
-
import
|
|
35888
|
+
import fs29 from "node:fs";
|
|
35889
|
+
import path38 from "node:path";
|
|
35359
35890
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
35360
35891
|
"node_modules",
|
|
35361
35892
|
"bower_components",
|
|
@@ -35372,7 +35903,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
|
|
|
35372
35903
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
35373
35904
|
let names;
|
|
35374
35905
|
try {
|
|
35375
|
-
names = await
|
|
35906
|
+
names = await fs29.promises.readdir(dir);
|
|
35376
35907
|
} catch {
|
|
35377
35908
|
return;
|
|
35378
35909
|
}
|
|
@@ -35384,14 +35915,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
35384
35915
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
35385
35916
|
}
|
|
35386
35917
|
state.n++;
|
|
35387
|
-
const full =
|
|
35918
|
+
const full = path38.join(dir, name);
|
|
35388
35919
|
let stat2;
|
|
35389
35920
|
try {
|
|
35390
|
-
stat2 = await
|
|
35921
|
+
stat2 = await fs29.promises.stat(full);
|
|
35391
35922
|
} catch {
|
|
35392
35923
|
continue;
|
|
35393
35924
|
}
|
|
35394
|
-
const relative6 =
|
|
35925
|
+
const relative6 = path38.relative(baseDir, full).replace(/\\/g, "/");
|
|
35395
35926
|
if (stat2.isDirectory()) {
|
|
35396
35927
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
35397
35928
|
} else if (stat2.isFile()) {
|
|
@@ -35404,7 +35935,7 @@ function createWalkYieldState() {
|
|
|
35404
35935
|
}
|
|
35405
35936
|
|
|
35406
35937
|
// src/files/index/file-index-sqlite-lock.ts
|
|
35407
|
-
import
|
|
35938
|
+
import fs30 from "node:fs";
|
|
35408
35939
|
function isSqliteCorruptError(e) {
|
|
35409
35940
|
const msg = e instanceof Error ? e.message : String(e);
|
|
35410
35941
|
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
@@ -35418,7 +35949,7 @@ function withFileIndexSqliteLock(fn) {
|
|
|
35418
35949
|
if (!isSqliteCorruptError(e)) throw e;
|
|
35419
35950
|
closeAllCliSqliteConnections();
|
|
35420
35951
|
try {
|
|
35421
|
-
|
|
35952
|
+
fs30.unlinkSync(getCliSqlitePath());
|
|
35422
35953
|
} catch {
|
|
35423
35954
|
}
|
|
35424
35955
|
chain = Promise.resolve();
|
|
@@ -35493,7 +36024,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
35493
36024
|
}
|
|
35494
36025
|
async function buildFileIndexAsync(cwd) {
|
|
35495
36026
|
return withFileIndexSqliteLock(async () => {
|
|
35496
|
-
const resolved =
|
|
36027
|
+
const resolved = path39.resolve(cwd);
|
|
35497
36028
|
await yieldToEventLoop();
|
|
35498
36029
|
assertNotShutdown();
|
|
35499
36030
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -35505,7 +36036,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
35505
36036
|
}
|
|
35506
36037
|
|
|
35507
36038
|
// src/files/index/ensure-file-index.ts
|
|
35508
|
-
import
|
|
36039
|
+
import path40 from "node:path";
|
|
35509
36040
|
|
|
35510
36041
|
// src/files/index/search-file-index.ts
|
|
35511
36042
|
function escapeLikePattern(fragment) {
|
|
@@ -35557,7 +36088,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
35557
36088
|
|
|
35558
36089
|
// src/files/index/ensure-file-index.ts
|
|
35559
36090
|
async function ensureFileIndexAsync(cwd) {
|
|
35560
|
-
const resolved =
|
|
36091
|
+
const resolved = path40.resolve(cwd);
|
|
35561
36092
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
35562
36093
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
35563
36094
|
}
|
|
@@ -35601,7 +36132,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
35601
36132
|
}
|
|
35602
36133
|
}
|
|
35603
36134
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
35604
|
-
const resolved =
|
|
36135
|
+
const resolved = path41.resolve(cwd);
|
|
35605
36136
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
35606
36137
|
if (e instanceof CliSqliteInterrupted) return;
|
|
35607
36138
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -35631,7 +36162,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
35631
36162
|
}
|
|
35632
36163
|
|
|
35633
36164
|
// src/connection/create-bridge-connection.ts
|
|
35634
|
-
import * as
|
|
36165
|
+
import * as path52 from "node:path";
|
|
35635
36166
|
|
|
35636
36167
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
35637
36168
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -35653,15 +36184,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
35653
36184
|
|
|
35654
36185
|
// src/dev-servers/process/terminate-child-process.ts
|
|
35655
36186
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
35656
|
-
const exited = new Promise((
|
|
35657
|
-
proc.once("exit", () =>
|
|
36187
|
+
const exited = new Promise((resolve26) => {
|
|
36188
|
+
proc.once("exit", () => resolve26());
|
|
35658
36189
|
});
|
|
35659
36190
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
35660
36191
|
try {
|
|
35661
36192
|
proc.kill("SIGTERM");
|
|
35662
36193
|
} catch {
|
|
35663
36194
|
}
|
|
35664
|
-
await Promise.race([exited, new Promise((
|
|
36195
|
+
await Promise.race([exited, new Promise((resolve26) => setTimeout(resolve26, graceMs))]);
|
|
35665
36196
|
}
|
|
35666
36197
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
35667
36198
|
log2(
|
|
@@ -35675,7 +36206,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
35675
36206
|
}
|
|
35676
36207
|
|
|
35677
36208
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
35678
|
-
import
|
|
36209
|
+
import fs31 from "node:fs";
|
|
35679
36210
|
|
|
35680
36211
|
// src/dev-servers/manager/forward-pipe.ts
|
|
35681
36212
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -35711,7 +36242,7 @@ function wireDevServerChildProcess(d) {
|
|
|
35711
36242
|
d.setPollInterval(void 0);
|
|
35712
36243
|
return;
|
|
35713
36244
|
}
|
|
35714
|
-
|
|
36245
|
+
fs31.readFile(d.mergedLogPath, (err, buf) => {
|
|
35715
36246
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
35716
36247
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
35717
36248
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -35749,7 +36280,7 @@ ${errTail}` : ""}`);
|
|
|
35749
36280
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
35750
36281
|
};
|
|
35751
36282
|
if (mergedPath) {
|
|
35752
|
-
|
|
36283
|
+
fs31.readFile(mergedPath, (err, buf) => {
|
|
35753
36284
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
35754
36285
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
35755
36286
|
if (chunk.length > 0) {
|
|
@@ -35851,13 +36382,13 @@ function parseDevServerDefs(servers) {
|
|
|
35851
36382
|
}
|
|
35852
36383
|
|
|
35853
36384
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
35854
|
-
import
|
|
36385
|
+
import fs32 from "node:fs";
|
|
35855
36386
|
function isSpawnEbadf(e) {
|
|
35856
36387
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
35857
36388
|
}
|
|
35858
36389
|
function rmDirQuiet(dir) {
|
|
35859
36390
|
try {
|
|
35860
|
-
|
|
36391
|
+
fs32.rmSync(dir, { recursive: true, force: true });
|
|
35861
36392
|
} catch {
|
|
35862
36393
|
}
|
|
35863
36394
|
}
|
|
@@ -35865,7 +36396,7 @@ var cachedDevNullReadFd;
|
|
|
35865
36396
|
function devNullReadFd() {
|
|
35866
36397
|
if (cachedDevNullReadFd === void 0) {
|
|
35867
36398
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
35868
|
-
cachedDevNullReadFd =
|
|
36399
|
+
cachedDevNullReadFd = fs32.openSync(devPath, "r");
|
|
35869
36400
|
}
|
|
35870
36401
|
return cachedDevNullReadFd;
|
|
35871
36402
|
}
|
|
@@ -35939,15 +36470,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
35939
36470
|
|
|
35940
36471
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
35941
36472
|
import { spawn as spawn8 } from "node:child_process";
|
|
35942
|
-
import
|
|
36473
|
+
import fs33 from "node:fs";
|
|
35943
36474
|
import { tmpdir } from "node:os";
|
|
35944
|
-
import
|
|
36475
|
+
import path42 from "node:path";
|
|
35945
36476
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
35946
|
-
const tmpRoot =
|
|
35947
|
-
const logPath =
|
|
36477
|
+
const tmpRoot = fs33.mkdtempSync(path42.join(tmpdir(), "ba-devsrv-log-"));
|
|
36478
|
+
const logPath = path42.join(tmpRoot, "combined.log");
|
|
35948
36479
|
let logFd;
|
|
35949
36480
|
try {
|
|
35950
|
-
logFd =
|
|
36481
|
+
logFd = fs33.openSync(logPath, "a");
|
|
35951
36482
|
} catch {
|
|
35952
36483
|
rmDirQuiet(tmpRoot);
|
|
35953
36484
|
return null;
|
|
@@ -35966,7 +36497,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35966
36497
|
} else {
|
|
35967
36498
|
proc = spawn8("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
35968
36499
|
}
|
|
35969
|
-
|
|
36500
|
+
fs33.closeSync(logFd);
|
|
35970
36501
|
return {
|
|
35971
36502
|
proc,
|
|
35972
36503
|
pipedStdoutStderr: true,
|
|
@@ -35975,7 +36506,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35975
36506
|
};
|
|
35976
36507
|
} catch (e) {
|
|
35977
36508
|
try {
|
|
35978
|
-
|
|
36509
|
+
fs33.closeSync(logFd);
|
|
35979
36510
|
} catch {
|
|
35980
36511
|
}
|
|
35981
36512
|
rmDirQuiet(tmpRoot);
|
|
@@ -35986,22 +36517,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35986
36517
|
|
|
35987
36518
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
35988
36519
|
import { spawn as spawn9 } from "node:child_process";
|
|
35989
|
-
import
|
|
36520
|
+
import fs34 from "node:fs";
|
|
35990
36521
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
35991
|
-
import
|
|
36522
|
+
import path43 from "node:path";
|
|
35992
36523
|
function shSingleQuote(s) {
|
|
35993
36524
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
35994
36525
|
}
|
|
35995
36526
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
35996
|
-
const tmpRoot =
|
|
35997
|
-
const logPath =
|
|
35998
|
-
const innerPath =
|
|
35999
|
-
const runnerPath =
|
|
36527
|
+
const tmpRoot = fs34.mkdtempSync(path43.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36528
|
+
const logPath = path43.join(tmpRoot, "combined.log");
|
|
36529
|
+
const innerPath = path43.join(tmpRoot, "_cmd.sh");
|
|
36530
|
+
const runnerPath = path43.join(tmpRoot, "_run.sh");
|
|
36000
36531
|
try {
|
|
36001
|
-
|
|
36532
|
+
fs34.writeFileSync(innerPath, `#!/bin/sh
|
|
36002
36533
|
${command}
|
|
36003
36534
|
`);
|
|
36004
|
-
|
|
36535
|
+
fs34.writeFileSync(
|
|
36005
36536
|
runnerPath,
|
|
36006
36537
|
`#!/bin/sh
|
|
36007
36538
|
cd ${shSingleQuote(cwd)}
|
|
@@ -36027,13 +36558,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
36027
36558
|
}
|
|
36028
36559
|
}
|
|
36029
36560
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
36030
|
-
const tmpRoot =
|
|
36031
|
-
const logPath =
|
|
36032
|
-
const runnerPath =
|
|
36561
|
+
const tmpRoot = fs34.mkdtempSync(path43.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36562
|
+
const logPath = path43.join(tmpRoot, "combined.log");
|
|
36563
|
+
const runnerPath = path43.join(tmpRoot, "_run.bat");
|
|
36033
36564
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
36034
36565
|
const com = process.env.ComSpec || "cmd.exe";
|
|
36035
36566
|
try {
|
|
36036
|
-
|
|
36567
|
+
fs34.writeFileSync(
|
|
36037
36568
|
runnerPath,
|
|
36038
36569
|
`@ECHO OFF\r
|
|
36039
36570
|
CD /D ${q(cwd)}\r
|
|
@@ -36802,30 +37333,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
36802
37333
|
}
|
|
36803
37334
|
|
|
36804
37335
|
// src/skills/discover-local-agent-skills.ts
|
|
36805
|
-
import
|
|
36806
|
-
import
|
|
37336
|
+
import fs35 from "node:fs";
|
|
37337
|
+
import path44 from "node:path";
|
|
36807
37338
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
36808
37339
|
function discoverLocalSkills(cwd) {
|
|
36809
37340
|
const out = [];
|
|
36810
37341
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
36811
37342
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36812
|
-
const base =
|
|
36813
|
-
if (!
|
|
37343
|
+
const base = path44.join(cwd, rel);
|
|
37344
|
+
if (!fs35.existsSync(base) || !fs35.statSync(base).isDirectory()) continue;
|
|
36814
37345
|
let entries = [];
|
|
36815
37346
|
try {
|
|
36816
|
-
entries =
|
|
37347
|
+
entries = fs35.readdirSync(base);
|
|
36817
37348
|
} catch {
|
|
36818
37349
|
continue;
|
|
36819
37350
|
}
|
|
36820
37351
|
for (const name of entries) {
|
|
36821
|
-
const dir =
|
|
37352
|
+
const dir = path44.join(base, name);
|
|
36822
37353
|
try {
|
|
36823
|
-
if (!
|
|
37354
|
+
if (!fs35.statSync(dir).isDirectory()) continue;
|
|
36824
37355
|
} catch {
|
|
36825
37356
|
continue;
|
|
36826
37357
|
}
|
|
36827
|
-
const skillMd =
|
|
36828
|
-
if (!
|
|
37358
|
+
const skillMd = path44.join(dir, "SKILL.md");
|
|
37359
|
+
if (!fs35.existsSync(skillMd)) continue;
|
|
36829
37360
|
const key = `${rel}/${name}`;
|
|
36830
37361
|
if (seenKeys.has(key)) continue;
|
|
36831
37362
|
seenKeys.add(key);
|
|
@@ -36837,23 +37368,23 @@ function discoverLocalSkills(cwd) {
|
|
|
36837
37368
|
function discoverSkillLayoutRoots(cwd) {
|
|
36838
37369
|
const roots = [];
|
|
36839
37370
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36840
|
-
const base =
|
|
36841
|
-
if (!
|
|
37371
|
+
const base = path44.join(cwd, rel);
|
|
37372
|
+
if (!fs35.existsSync(base) || !fs35.statSync(base).isDirectory()) continue;
|
|
36842
37373
|
let entries = [];
|
|
36843
37374
|
try {
|
|
36844
|
-
entries =
|
|
37375
|
+
entries = fs35.readdirSync(base);
|
|
36845
37376
|
} catch {
|
|
36846
37377
|
continue;
|
|
36847
37378
|
}
|
|
36848
37379
|
const skills2 = [];
|
|
36849
37380
|
for (const name of entries) {
|
|
36850
|
-
const dir =
|
|
37381
|
+
const dir = path44.join(base, name);
|
|
36851
37382
|
try {
|
|
36852
|
-
if (!
|
|
37383
|
+
if (!fs35.statSync(dir).isDirectory()) continue;
|
|
36853
37384
|
} catch {
|
|
36854
37385
|
continue;
|
|
36855
37386
|
}
|
|
36856
|
-
if (!
|
|
37387
|
+
if (!fs35.existsSync(path44.join(dir, "SKILL.md"))) continue;
|
|
36857
37388
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
36858
37389
|
skills2.push({ name, relPath });
|
|
36859
37390
|
}
|
|
@@ -37209,7 +37740,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
37209
37740
|
}
|
|
37210
37741
|
|
|
37211
37742
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
37212
|
-
import
|
|
37743
|
+
import fs36 from "node:fs";
|
|
37213
37744
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
37214
37745
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
37215
37746
|
const sid = next.sessionId;
|
|
@@ -37218,7 +37749,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
37218
37749
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
37219
37750
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
37220
37751
|
try {
|
|
37221
|
-
await
|
|
37752
|
+
await fs36.promises.access(file2, fs36.constants.F_OK);
|
|
37222
37753
|
} catch {
|
|
37223
37754
|
deps.log(
|
|
37224
37755
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -37333,7 +37864,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
37333
37864
|
sendWsMessage(s, wire);
|
|
37334
37865
|
return true;
|
|
37335
37866
|
};
|
|
37336
|
-
const
|
|
37867
|
+
const sendResult = (result) => {
|
|
37337
37868
|
const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
37338
37869
|
const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
|
|
37339
37870
|
sendBridgeMessage(result, encryptedFields);
|
|
@@ -37366,7 +37897,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
37366
37897
|
]) : payload;
|
|
37367
37898
|
sendWsMessage(s, wire);
|
|
37368
37899
|
};
|
|
37369
|
-
return { sendBridgeMessage, sendResult
|
|
37900
|
+
return { sendBridgeMessage, sendResult, sendSessionUpdate };
|
|
37370
37901
|
}
|
|
37371
37902
|
|
|
37372
37903
|
// src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
|
|
@@ -37470,7 +38001,7 @@ async function readGitBranch(cwd) {
|
|
|
37470
38001
|
async function runBridgePromptPreamble(params) {
|
|
37471
38002
|
const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
|
|
37472
38003
|
const s = getWs();
|
|
37473
|
-
const repoCheckoutPaths = sessionWorktreeManager.
|
|
38004
|
+
const repoCheckoutPaths = await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sessionId);
|
|
37474
38005
|
const repoRoots = await resolveSnapshotRepoRoots({
|
|
37475
38006
|
worktreePaths: repoCheckoutPaths,
|
|
37476
38007
|
fallbackCwd: effectiveCwd,
|
|
@@ -37506,9 +38037,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
37506
38037
|
for (const item of raw) {
|
|
37507
38038
|
if (!item || typeof item !== "object") continue;
|
|
37508
38039
|
const o = item;
|
|
37509
|
-
const
|
|
37510
|
-
if (!
|
|
37511
|
-
const row = { path:
|
|
38040
|
+
const path53 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
38041
|
+
if (!path53) continue;
|
|
38042
|
+
const row = { path: path53 };
|
|
37512
38043
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
37513
38044
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
37514
38045
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -37542,7 +38073,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
37542
38073
|
agentId,
|
|
37543
38074
|
agentConfig,
|
|
37544
38075
|
resolvedCwd,
|
|
37545
|
-
senders: { sendResult
|
|
38076
|
+
senders: { sendResult, sendSessionUpdate }
|
|
37546
38077
|
} = params;
|
|
37547
38078
|
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
37548
38079
|
await runBridgePromptPreamble({
|
|
@@ -37580,7 +38111,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
37580
38111
|
agentId,
|
|
37581
38112
|
agentConfig,
|
|
37582
38113
|
sessionParentPath: effectiveCwd,
|
|
37583
|
-
sendResult
|
|
38114
|
+
sendResult,
|
|
37584
38115
|
sendSessionUpdate,
|
|
37585
38116
|
followUpCatalogPromptId,
|
|
37586
38117
|
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
@@ -37722,14 +38253,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
37722
38253
|
};
|
|
37723
38254
|
|
|
37724
38255
|
// src/files/list-dir/index.ts
|
|
37725
|
-
import
|
|
38256
|
+
import fs38 from "node:fs";
|
|
37726
38257
|
|
|
37727
38258
|
// src/files/ensure-under-cwd.ts
|
|
37728
|
-
import
|
|
38259
|
+
import path45 from "node:path";
|
|
37729
38260
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
37730
|
-
const normalized =
|
|
37731
|
-
const resolved =
|
|
37732
|
-
if (!resolved.startsWith(cwd +
|
|
38261
|
+
const normalized = path45.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
38262
|
+
const resolved = path45.resolve(cwd, normalized);
|
|
38263
|
+
if (!resolved.startsWith(cwd + path45.sep) && resolved !== cwd) {
|
|
37733
38264
|
return null;
|
|
37734
38265
|
}
|
|
37735
38266
|
return resolved;
|
|
@@ -37739,15 +38270,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
37739
38270
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
37740
38271
|
|
|
37741
38272
|
// src/files/list-dir/map-dir-entry.ts
|
|
37742
|
-
import
|
|
37743
|
-
import
|
|
38273
|
+
import path46 from "node:path";
|
|
38274
|
+
import fs37 from "node:fs";
|
|
37744
38275
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
37745
|
-
const entryPath =
|
|
37746
|
-
const fullPath =
|
|
38276
|
+
const entryPath = path46.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
38277
|
+
const fullPath = path46.join(resolved, d.name);
|
|
37747
38278
|
let isDir = d.isDirectory();
|
|
37748
38279
|
if (d.isSymbolicLink()) {
|
|
37749
38280
|
try {
|
|
37750
|
-
const targetStat = await
|
|
38281
|
+
const targetStat = await fs37.promises.stat(fullPath);
|
|
37751
38282
|
isDir = targetStat.isDirectory();
|
|
37752
38283
|
} catch {
|
|
37753
38284
|
isDir = false;
|
|
@@ -37777,7 +38308,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
37777
38308
|
return { error: "Path is outside working directory" };
|
|
37778
38309
|
}
|
|
37779
38310
|
try {
|
|
37780
|
-
const names = await
|
|
38311
|
+
const names = await fs38.promises.readdir(resolved, { withFileTypes: true });
|
|
37781
38312
|
const entries = [];
|
|
37782
38313
|
for (let i = 0; i < names.length; i++) {
|
|
37783
38314
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -37797,18 +38328,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
|
|
|
37797
38328
|
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
37798
38329
|
|
|
37799
38330
|
// src/files/read-file/resolve-file-path.ts
|
|
37800
|
-
import
|
|
38331
|
+
import fs39 from "node:fs";
|
|
37801
38332
|
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
37802
38333
|
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
37803
38334
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
37804
38335
|
let real;
|
|
37805
38336
|
try {
|
|
37806
|
-
real = await
|
|
38337
|
+
real = await fs39.promises.realpath(resolved);
|
|
37807
38338
|
} catch {
|
|
37808
38339
|
real = resolved;
|
|
37809
38340
|
}
|
|
37810
38341
|
try {
|
|
37811
|
-
const stat2 = await
|
|
38342
|
+
const stat2 = await fs39.promises.stat(real);
|
|
37812
38343
|
if (!stat2.isFile()) return { error: "Not a file" };
|
|
37813
38344
|
return real;
|
|
37814
38345
|
} catch (err) {
|
|
@@ -37817,11 +38348,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
37817
38348
|
}
|
|
37818
38349
|
|
|
37819
38350
|
// src/files/read-file/read-file-range-async.ts
|
|
37820
|
-
import
|
|
38351
|
+
import fs40 from "node:fs";
|
|
37821
38352
|
import { StringDecoder } from "node:string_decoder";
|
|
37822
38353
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
37823
|
-
const fileSize = (await
|
|
37824
|
-
const fd = await
|
|
38354
|
+
const fileSize = (await fs40.promises.stat(filePath)).size;
|
|
38355
|
+
const fd = await fs40.promises.open(filePath, "r");
|
|
37825
38356
|
const bufSize = 64 * 1024;
|
|
37826
38357
|
const buf = Buffer.alloc(bufSize);
|
|
37827
38358
|
const decoder = new StringDecoder("utf8");
|
|
@@ -37983,11 +38514,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
37983
38514
|
}
|
|
37984
38515
|
|
|
37985
38516
|
// src/files/read-file/read-file-buffer-full-async.ts
|
|
37986
|
-
import
|
|
38517
|
+
import fs41 from "node:fs";
|
|
37987
38518
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
37988
38519
|
async function readFileBufferFullAsync(filePath) {
|
|
37989
|
-
const stat2 = await
|
|
37990
|
-
const fd = await
|
|
38520
|
+
const stat2 = await fs41.promises.stat(filePath);
|
|
38521
|
+
const fd = await fs41.promises.open(filePath, "r");
|
|
37991
38522
|
const chunks = [];
|
|
37992
38523
|
let position = 0;
|
|
37993
38524
|
let bytesSinceYield = 0;
|
|
@@ -38083,10 +38614,10 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
38083
38614
|
}
|
|
38084
38615
|
|
|
38085
38616
|
// src/files/resolve-file-browser-session-parent.ts
|
|
38086
|
-
function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
38617
|
+
async function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
38087
38618
|
const sid = sessionId?.trim();
|
|
38088
38619
|
if (sid) {
|
|
38089
|
-
sessionWorktreeManager.
|
|
38620
|
+
await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sid);
|
|
38090
38621
|
const worktreeRoot = sessionWorktreeManager.getSessionWorktreeRootForSession(sid);
|
|
38091
38622
|
if (worktreeRoot) return worktreeRoot;
|
|
38092
38623
|
}
|
|
@@ -38094,14 +38625,14 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
38094
38625
|
}
|
|
38095
38626
|
|
|
38096
38627
|
// src/files/handle-file-browser-search.ts
|
|
38097
|
-
import
|
|
38628
|
+
import path47 from "node:path";
|
|
38098
38629
|
var SEARCH_LIMIT = 100;
|
|
38099
38630
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
38100
38631
|
void (async () => {
|
|
38101
38632
|
await yieldToEventLoop();
|
|
38102
38633
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
38103
|
-
const sessionParentPath =
|
|
38104
|
-
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
38634
|
+
const sessionParentPath = path47.resolve(
|
|
38635
|
+
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
38105
38636
|
);
|
|
38106
38637
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
38107
38638
|
const payload2 = {
|
|
@@ -38139,7 +38670,7 @@ function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
|
38139
38670
|
void (async () => {
|
|
38140
38671
|
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
38141
38672
|
const op = msg.op === "read" ? "read" : "list";
|
|
38142
|
-
const sessionParentPath = sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
38673
|
+
const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
38143
38674
|
if (op === "list") {
|
|
38144
38675
|
const result = await listDirAsync(reqPath, sessionParentPath);
|
|
38145
38676
|
if ("error" in result) {
|
|
@@ -38219,8 +38750,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
38219
38750
|
}
|
|
38220
38751
|
|
|
38221
38752
|
// src/skills/install-remote-skills.ts
|
|
38222
|
-
import
|
|
38223
|
-
import
|
|
38753
|
+
import fs42 from "node:fs";
|
|
38754
|
+
import path48 from "node:path";
|
|
38224
38755
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
38225
38756
|
const installed2 = [];
|
|
38226
38757
|
if (!Array.isArray(items)) {
|
|
@@ -38231,15 +38762,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
38231
38762
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
38232
38763
|
continue;
|
|
38233
38764
|
}
|
|
38234
|
-
const skillDir =
|
|
38765
|
+
const skillDir = path48.join(cwd, targetDir, item.skillName);
|
|
38235
38766
|
for (const f of item.files) {
|
|
38236
38767
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
38237
|
-
const dest =
|
|
38238
|
-
|
|
38768
|
+
const dest = path48.join(skillDir, f.path);
|
|
38769
|
+
fs42.mkdirSync(path48.dirname(dest), { recursive: true });
|
|
38239
38770
|
if (f.text !== void 0) {
|
|
38240
|
-
|
|
38771
|
+
fs42.writeFileSync(dest, f.text, "utf8");
|
|
38241
38772
|
} else if (f.base64) {
|
|
38242
|
-
|
|
38773
|
+
fs42.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
38243
38774
|
}
|
|
38244
38775
|
}
|
|
38245
38776
|
installed2.push({
|
|
@@ -38280,12 +38811,116 @@ var handleRefreshLocalSkills = (_msg, deps) => {
|
|
|
38280
38811
|
deps.sendLocalSkillsReport?.();
|
|
38281
38812
|
};
|
|
38282
38813
|
|
|
38283
|
-
// src/routing/handlers/session-git-
|
|
38284
|
-
function
|
|
38814
|
+
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
38815
|
+
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
38816
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
38817
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
38818
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
38819
|
+
if (!branch.trim() || !message.trim()) {
|
|
38820
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
38821
|
+
return;
|
|
38822
|
+
}
|
|
38823
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
38824
|
+
sessionId,
|
|
38825
|
+
branch: branch.trim(),
|
|
38826
|
+
message: message.trim(),
|
|
38827
|
+
push: pushAfterCommit
|
|
38828
|
+
});
|
|
38829
|
+
if (!commitRes.ok) {
|
|
38830
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
38831
|
+
return;
|
|
38832
|
+
}
|
|
38833
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38834
|
+
reply({
|
|
38835
|
+
ok: true,
|
|
38836
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
38837
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
38838
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
38839
|
+
});
|
|
38840
|
+
}
|
|
38841
|
+
|
|
38842
|
+
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
38843
|
+
var listChangesInflight = /* @__PURE__ */ new Map();
|
|
38844
|
+
function listChangesInflightKey(sessionId, opts) {
|
|
38845
|
+
const basis = opts?.basis;
|
|
38846
|
+
return [
|
|
38847
|
+
sessionId,
|
|
38848
|
+
opts?.repoRelPath ?? "",
|
|
38849
|
+
basis?.kind === "commit" ? `commit:${basis.sha}` : "working",
|
|
38850
|
+
String(opts?.recentCommitsLimit ?? "")
|
|
38851
|
+
].join("|");
|
|
38852
|
+
}
|
|
38853
|
+
function getSessionWorkingTreeChangeDetailsCoalesced(sessionWorktreeManager, sessionId, opts) {
|
|
38854
|
+
const key = listChangesInflightKey(sessionId, opts);
|
|
38855
|
+
const existing = listChangesInflight.get(key);
|
|
38856
|
+
if (existing) return existing;
|
|
38857
|
+
const promise2 = sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts).finally(() => {
|
|
38858
|
+
if (listChangesInflight.get(key) === promise2) listChangesInflight.delete(key);
|
|
38859
|
+
});
|
|
38860
|
+
listChangesInflight.set(key, promise2);
|
|
38861
|
+
return promise2;
|
|
38862
|
+
}
|
|
38863
|
+
|
|
38864
|
+
// src/routing/handlers/git/handle-session-git-list-changes.ts
|
|
38865
|
+
async function handleSessionGitListChangesAction(deps, msg, reply) {
|
|
38866
|
+
const repoRel = typeof msg.changesRepoRelPath === "string" ? msg.changesRepoRelPath.trim() : "";
|
|
38867
|
+
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
38868
|
+
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
38869
|
+
if (view === "commit") {
|
|
38870
|
+
if (!repoRel || !commitSha) {
|
|
38871
|
+
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
38872
|
+
return;
|
|
38873
|
+
}
|
|
38874
|
+
}
|
|
38875
|
+
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
38876
|
+
const opts = repoRel && view === "commit" && commitSha ? {
|
|
38877
|
+
repoRelPath: repoRel,
|
|
38878
|
+
basis: { kind: "commit", sha: commitSha },
|
|
38879
|
+
recentCommitsLimit
|
|
38880
|
+
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
38881
|
+
const repos = await getSessionWorkingTreeChangeDetailsCoalesced(
|
|
38882
|
+
deps.sessionWorktreeManager,
|
|
38883
|
+
msg.sessionId,
|
|
38884
|
+
opts
|
|
38885
|
+
);
|
|
38886
|
+
reply({ ok: true, repos }, ["repos"]);
|
|
38887
|
+
}
|
|
38888
|
+
|
|
38889
|
+
// src/routing/handlers/git/handle-session-git-push.ts
|
|
38890
|
+
async function handleSessionGitPushAction(deps, sessionId, reply) {
|
|
38891
|
+
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
38892
|
+
if (!pushRes.ok) {
|
|
38893
|
+
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
38894
|
+
return;
|
|
38895
|
+
}
|
|
38896
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38897
|
+
reply({
|
|
38898
|
+
ok: true,
|
|
38899
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
38900
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
38901
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
38902
|
+
});
|
|
38903
|
+
}
|
|
38904
|
+
|
|
38905
|
+
// src/routing/handlers/git/handle-session-git-status.ts
|
|
38906
|
+
async function handleSessionGitStatusAction(deps, sessionId, reply) {
|
|
38907
|
+
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38908
|
+
reply({
|
|
38909
|
+
ok: true,
|
|
38910
|
+
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
38911
|
+
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
38912
|
+
uncommittedFileCount: r.uncommittedFileCount
|
|
38913
|
+
});
|
|
38914
|
+
}
|
|
38915
|
+
|
|
38916
|
+
// src/routing/handlers/git/send-session-git-result.ts
|
|
38917
|
+
function sendSessionGitResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
38285
38918
|
if (!ws) return;
|
|
38286
38919
|
const message = { type: "session_git_result", id, ...payload };
|
|
38287
38920
|
sendWsMessage(ws, e2ee && encryptedFields.length > 0 ? e2ee.encryptFields(message, encryptedFields) : message);
|
|
38288
38921
|
}
|
|
38922
|
+
|
|
38923
|
+
// src/routing/handlers/git/session-git-request.ts
|
|
38289
38924
|
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
38290
38925
|
if (typeof msg.id !== "string") return;
|
|
38291
38926
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -38294,80 +38929,21 @@ var handleSessionGitRequestMessage = (msg, deps) => {
|
|
|
38294
38929
|
return;
|
|
38295
38930
|
void (async () => {
|
|
38296
38931
|
const ws = deps.getWs();
|
|
38297
|
-
const reply = (payload, encryptedFields = []) =>
|
|
38932
|
+
const reply = (payload, encryptedFields = []) => sendSessionGitResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
38298
38933
|
try {
|
|
38299
38934
|
if (action === "status") {
|
|
38300
|
-
|
|
38301
|
-
reply({
|
|
38302
|
-
ok: true,
|
|
38303
|
-
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
38304
|
-
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
38305
|
-
uncommittedFileCount: r.uncommittedFileCount
|
|
38306
|
-
});
|
|
38935
|
+
await handleSessionGitStatusAction(deps, sessionId, reply);
|
|
38307
38936
|
return;
|
|
38308
38937
|
}
|
|
38309
38938
|
if (action === "list_changes") {
|
|
38310
|
-
|
|
38311
|
-
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
38312
|
-
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
38313
|
-
if (view === "commit") {
|
|
38314
|
-
if (!repoRel || !commitSha) {
|
|
38315
|
-
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
38316
|
-
return;
|
|
38317
|
-
}
|
|
38318
|
-
}
|
|
38319
|
-
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
38320
|
-
const opts = repoRel && view === "commit" && commitSha ? {
|
|
38321
|
-
repoRelPath: repoRel,
|
|
38322
|
-
basis: { kind: "commit", sha: commitSha },
|
|
38323
|
-
recentCommitsLimit
|
|
38324
|
-
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
38325
|
-
const repos = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts);
|
|
38326
|
-
reply({
|
|
38327
|
-
ok: true,
|
|
38328
|
-
repos
|
|
38329
|
-
}, ["repos"]);
|
|
38939
|
+
await handleSessionGitListChangesAction(deps, { ...msg, sessionId }, reply);
|
|
38330
38940
|
return;
|
|
38331
38941
|
}
|
|
38332
38942
|
if (action === "push") {
|
|
38333
|
-
|
|
38334
|
-
if (!pushRes.ok) {
|
|
38335
|
-
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
38336
|
-
return;
|
|
38337
|
-
}
|
|
38338
|
-
const st2 = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38339
|
-
reply({
|
|
38340
|
-
ok: true,
|
|
38341
|
-
hasUncommittedChanges: st2.hasUncommittedChanges,
|
|
38342
|
-
hasUnpushedCommits: st2.hasUnpushedCommits,
|
|
38343
|
-
uncommittedFileCount: st2.uncommittedFileCount
|
|
38344
|
-
});
|
|
38345
|
-
return;
|
|
38346
|
-
}
|
|
38347
|
-
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
38348
|
-
const message = typeof msg.message === "string" ? msg.message : "";
|
|
38349
|
-
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
38350
|
-
if (!branch.trim() || !message.trim()) {
|
|
38351
|
-
reply({ ok: false, error: "branch and message are required for commit" });
|
|
38943
|
+
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
38352
38944
|
return;
|
|
38353
38945
|
}
|
|
38354
|
-
|
|
38355
|
-
sessionId,
|
|
38356
|
-
branch: branch.trim(),
|
|
38357
|
-
message: message.trim(),
|
|
38358
|
-
push: pushAfterCommit
|
|
38359
|
-
});
|
|
38360
|
-
if (!commitRes.ok) {
|
|
38361
|
-
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
38362
|
-
return;
|
|
38363
|
-
}
|
|
38364
|
-
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
38365
|
-
reply({
|
|
38366
|
-
ok: true,
|
|
38367
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
38368
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
38369
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
38370
|
-
});
|
|
38946
|
+
await handleSessionGitCommitAction(deps, sessionId, msg, reply);
|
|
38371
38947
|
} catch (e) {
|
|
38372
38948
|
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
38373
38949
|
}
|
|
@@ -38397,7 +38973,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
38397
38973
|
};
|
|
38398
38974
|
|
|
38399
38975
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
38400
|
-
import * as
|
|
38976
|
+
import * as fs43 from "node:fs";
|
|
38401
38977
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
38402
38978
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
38403
38979
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -38410,7 +38986,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
38410
38986
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
38411
38987
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
38412
38988
|
try {
|
|
38413
|
-
await
|
|
38989
|
+
await fs43.promises.access(file2, fs43.constants.F_OK);
|
|
38414
38990
|
} catch {
|
|
38415
38991
|
sendWsMessage(s, {
|
|
38416
38992
|
type: "revert_turn_snapshot_result",
|
|
@@ -38452,7 +39028,7 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
38452
39028
|
};
|
|
38453
39029
|
|
|
38454
39030
|
// src/git/bridge-git-context.ts
|
|
38455
|
-
import * as
|
|
39031
|
+
import * as path49 from "node:path";
|
|
38456
39032
|
|
|
38457
39033
|
// src/git/branches/get-current-branch.ts
|
|
38458
39034
|
async function getCurrentBranch(repoPath) {
|
|
@@ -38502,12 +39078,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
38502
39078
|
// src/git/bridge-git-context.ts
|
|
38503
39079
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
38504
39080
|
if (relPath === "." || relPath === "") {
|
|
38505
|
-
return
|
|
39081
|
+
return path49.basename(path49.resolve(bridgeRoot)) || "repo";
|
|
38506
39082
|
}
|
|
38507
|
-
return
|
|
39083
|
+
return path49.basename(relPath) || relPath;
|
|
38508
39084
|
}
|
|
38509
39085
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
38510
|
-
const root =
|
|
39086
|
+
const root = path49.resolve(bridgeRoot);
|
|
38511
39087
|
if (await isGitRepoDirectory(root)) {
|
|
38512
39088
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
38513
39089
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -38515,17 +39091,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
38515
39091
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
38516
39092
|
const byPath = /* @__PURE__ */ new Map();
|
|
38517
39093
|
for (const repo of [...deep, ...shallow]) {
|
|
38518
|
-
byPath.set(
|
|
39094
|
+
byPath.set(path49.resolve(repo.absolutePath), repo);
|
|
38519
39095
|
}
|
|
38520
39096
|
return [...byPath.values()];
|
|
38521
39097
|
}
|
|
38522
39098
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
38523
|
-
const bridgeResolved =
|
|
39099
|
+
const bridgeResolved = path49.resolve(bridgeRoot);
|
|
38524
39100
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
38525
39101
|
const rows = [];
|
|
38526
39102
|
for (const repo of repos) {
|
|
38527
|
-
let rel =
|
|
38528
|
-
if (rel.startsWith("..") ||
|
|
39103
|
+
let rel = path49.relative(bridgeResolved, repo.absolutePath);
|
|
39104
|
+
if (rel.startsWith("..") || path49.isAbsolute(rel)) continue;
|
|
38529
39105
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
38530
39106
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
38531
39107
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -38540,11 +39116,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
38540
39116
|
return rows;
|
|
38541
39117
|
}
|
|
38542
39118
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
38543
|
-
const bridgeResolved =
|
|
39119
|
+
const bridgeResolved = path49.resolve(bridgeRoot);
|
|
38544
39120
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
38545
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
38546
|
-
const resolved =
|
|
38547
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
39121
|
+
const repoPath = rel === "" ? bridgeResolved : path49.join(bridgeResolved, rel);
|
|
39122
|
+
const resolved = path49.resolve(repoPath);
|
|
39123
|
+
if (!resolved.startsWith(bridgeResolved + path49.sep) && resolved !== bridgeResolved) {
|
|
38548
39124
|
return [];
|
|
38549
39125
|
}
|
|
38550
39126
|
return listRepoBranchRefs(resolved);
|
|
@@ -39128,10 +39704,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
39128
39704
|
}
|
|
39129
39705
|
|
|
39130
39706
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
39131
|
-
import * as
|
|
39707
|
+
import * as path51 from "node:path";
|
|
39132
39708
|
|
|
39133
39709
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
39134
|
-
import * as
|
|
39710
|
+
import * as path50 from "node:path";
|
|
39135
39711
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
39136
39712
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
|
|
39137
39713
|
const canContinue = () => shouldContinue?.() !== false;
|
|
@@ -39169,7 +39745,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
39169
39745
|
if (!canContinue()) return false;
|
|
39170
39746
|
handle = await resolved.createClient({
|
|
39171
39747
|
command: resolved.command,
|
|
39172
|
-
cwd:
|
|
39748
|
+
cwd: path50.resolve(cwd),
|
|
39173
39749
|
backendAgentType: agentType,
|
|
39174
39750
|
sessionMode: "agent",
|
|
39175
39751
|
persistedAcpSessionId: null,
|
|
@@ -39247,7 +39823,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
39247
39823
|
const { workspaceId, log: log2, getWs } = params;
|
|
39248
39824
|
const isCurrent = beginAgentCapabilityWarmupRun();
|
|
39249
39825
|
if (!isCurrent()) return;
|
|
39250
|
-
const cwd =
|
|
39826
|
+
const cwd = path51.resolve(getBridgeRoot());
|
|
39251
39827
|
async function sendBatchFromCache() {
|
|
39252
39828
|
if (!isCurrent()) return;
|
|
39253
39829
|
const socket = getWs();
|
|
@@ -39353,8 +39929,8 @@ async function callListParentSessionPromptsTool(ctx, cloud, childSessionId, pare
|
|
|
39353
39929
|
}
|
|
39354
39930
|
|
|
39355
39931
|
// src/mcp/tools/session-history/fork/tool-names.ts
|
|
39356
|
-
var
|
|
39357
|
-
var
|
|
39932
|
+
var LIST_PARENT_SESSION_PROMPTS_TOOL2 = "list_parent_session_prompts";
|
|
39933
|
+
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2 = "get_parent_session_turn_transcript";
|
|
39358
39934
|
|
|
39359
39935
|
// src/mcp/tools/session-history/fork/call-fork-session-mcp-tool.ts
|
|
39360
39936
|
async function callForkSessionMcpTool(ctx, cloud, name, args) {
|
|
@@ -39371,10 +39947,10 @@ async function callForkSessionMcpTool(ctx, cloud, name, args) {
|
|
|
39371
39947
|
return mcpTextResult(parentResolved.error, true);
|
|
39372
39948
|
}
|
|
39373
39949
|
const parentSessionId = parentResolved.parentSessionId;
|
|
39374
|
-
if (name ===
|
|
39950
|
+
if (name === LIST_PARENT_SESSION_PROMPTS_TOOL2) {
|
|
39375
39951
|
return callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId);
|
|
39376
39952
|
}
|
|
39377
|
-
if (name ===
|
|
39953
|
+
if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2) {
|
|
39378
39954
|
return callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args);
|
|
39379
39955
|
}
|
|
39380
39956
|
return mcpTextResult(`Unknown fork session tool: ${name}`, true);
|
|
@@ -39387,7 +39963,7 @@ var SESSION_ID_SCHEMA = {
|
|
|
39387
39963
|
};
|
|
39388
39964
|
var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
39389
39965
|
{
|
|
39390
|
-
name:
|
|
39966
|
+
name: LIST_PARENT_SESSION_PROMPTS_TOOL2,
|
|
39391
39967
|
description: "List user prompts (main turns) from the parent session a fork was created from. Requires sessionId. Returns an error if the session has no parent history (not a fork).",
|
|
39392
39968
|
inputSchema: {
|
|
39393
39969
|
type: "object",
|
|
@@ -39397,7 +39973,7 @@ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
|
39397
39973
|
}
|
|
39398
39974
|
},
|
|
39399
39975
|
{
|
|
39400
|
-
name:
|
|
39976
|
+
name: GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2,
|
|
39401
39977
|
description: "Full transcript for one parent-session turn, including tool calls and agent messages. Requires sessionId and turnId. Returns an error if the session has no parent history (not a fork).",
|
|
39402
39978
|
inputSchema: {
|
|
39403
39979
|
type: "object",
|
|
@@ -39413,7 +39989,130 @@ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
|
39413
39989
|
|
|
39414
39990
|
// src/mcp/tools/session-history/fork/is-fork-session-mcp-tool-name.ts
|
|
39415
39991
|
function isForkSessionMcpToolName(name) {
|
|
39416
|
-
return name ===
|
|
39992
|
+
return name === LIST_PARENT_SESSION_PROMPTS_TOOL2 || name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2;
|
|
39993
|
+
}
|
|
39994
|
+
|
|
39995
|
+
// src/mcp/tools/integration-content/tool-names.ts
|
|
39996
|
+
var GET_INTEGRATION_CONTENT_TOOL2 = "get_integration_content";
|
|
39997
|
+
|
|
39998
|
+
// src/mcp/tools/integration-content/cloud/fetch-integration-content.ts
|
|
39999
|
+
async function fetchCloudIntegrationContent(params) {
|
|
40000
|
+
return fetchInternalApiJson({
|
|
40001
|
+
...params,
|
|
40002
|
+
path: `/internal/sessions/${encodeURIComponent(params.sessionId)}/integrations/content`,
|
|
40003
|
+
errorLabel: "Integration content fetch failed",
|
|
40004
|
+
method: "POST",
|
|
40005
|
+
body: {
|
|
40006
|
+
url: params.url,
|
|
40007
|
+
associateAsSessionTicket: params.associateAsSessionTicket !== false
|
|
40008
|
+
}
|
|
40009
|
+
});
|
|
40010
|
+
}
|
|
40011
|
+
|
|
40012
|
+
// src/mcp/tools/integration-content/format-integration-content-for-mcp.ts
|
|
40013
|
+
function formatIntegrationContentForMcp(result) {
|
|
40014
|
+
if (!result.ok) {
|
|
40015
|
+
const lines2 = [`status: ${result.code}`, `message: ${result.message}`];
|
|
40016
|
+
if (result.integrationType) lines2.push(`integrationType: ${result.integrationType}`);
|
|
40017
|
+
if (result.retryable) lines2.push("retryable: true");
|
|
40018
|
+
lines2.push(...formatSessionTicketAssociationLines(result.sessionTicketAssociation));
|
|
40019
|
+
return lines2.join("\n");
|
|
40020
|
+
}
|
|
40021
|
+
const lines = [
|
|
40022
|
+
formatIntegrationContentBody(result.integrationType, result.content),
|
|
40023
|
+
...formatSessionTicketAssociationLines(result.sessionTicketAssociation)
|
|
40024
|
+
];
|
|
40025
|
+
return lines.join("\n");
|
|
40026
|
+
}
|
|
40027
|
+
function formatSessionTicketAssociationLines(association) {
|
|
40028
|
+
if (association.status === "associated") {
|
|
40029
|
+
const title = association.externalTicket.displayTitle?.trim() || association.externalTicket.normalizedUrl;
|
|
40030
|
+
return ["", "--- session ticket ---", "status: associated", `displayTitle: ${title}`];
|
|
40031
|
+
}
|
|
40032
|
+
if (association.status === "failed") {
|
|
40033
|
+
return ["", "--- session ticket ---", "status: failed", `reason: ${association.reason}`];
|
|
40034
|
+
}
|
|
40035
|
+
return ["", "--- session ticket ---", `status: ${association.status}`, `reason: ${association.reason}`];
|
|
40036
|
+
}
|
|
40037
|
+
function formatIntegrationContentBody(integrationType, content) {
|
|
40038
|
+
const lines = [
|
|
40039
|
+
`integrationType: ${integrationType}`,
|
|
40040
|
+
`title: ${content.title}`,
|
|
40041
|
+
`url: ${content.url}`,
|
|
40042
|
+
"",
|
|
40043
|
+
"--- body ---",
|
|
40044
|
+
content.body
|
|
40045
|
+
];
|
|
40046
|
+
if (content.comments?.length) {
|
|
40047
|
+
lines.push("", "--- comments ---");
|
|
40048
|
+
for (const comment of content.comments) {
|
|
40049
|
+
lines.push(`[${comment.createdAt}] ${comment.author}:`, comment.body, "");
|
|
40050
|
+
}
|
|
40051
|
+
}
|
|
40052
|
+
const threadMessages = content.threadMessages;
|
|
40053
|
+
if (threadMessages?.length) {
|
|
40054
|
+
lines.push("", "--- thread messages ---");
|
|
40055
|
+
for (const msg of threadMessages) {
|
|
40056
|
+
lines.push(`[${msg.ts}] ${msg.displayName}: ${msg.text}`);
|
|
40057
|
+
}
|
|
40058
|
+
}
|
|
40059
|
+
if (content.metadata && Object.keys(content.metadata).length > 0) {
|
|
40060
|
+
lines.push("", "--- metadata ---", JSON.stringify(content.metadata, null, 2));
|
|
40061
|
+
}
|
|
40062
|
+
return lines.join("\n");
|
|
40063
|
+
}
|
|
40064
|
+
|
|
40065
|
+
// src/mcp/tools/integration-content/call-integration-content-mcp-tool.ts
|
|
40066
|
+
async function callIntegrationContentMcpTool(ctx, cloud, name, args) {
|
|
40067
|
+
if (name !== GET_INTEGRATION_CONTENT_TOOL2) {
|
|
40068
|
+
return mcpTextResult(`Unknown integration content tool: ${name}`, true);
|
|
40069
|
+
}
|
|
40070
|
+
const sessionId = ctx.sessionId.trim();
|
|
40071
|
+
if (!sessionId) return mcpTextResult("sessionId is required.", true);
|
|
40072
|
+
const url2 = typeof args.url === "string" ? args.url.trim() : "";
|
|
40073
|
+
if (!url2) return mcpTextResult("url is required.", true);
|
|
40074
|
+
const associateAsSessionTicket = args.associateAsSessionTicket !== false;
|
|
40075
|
+
const fetched = await fetchCloudIntegrationContent({
|
|
40076
|
+
sessionId,
|
|
40077
|
+
url: url2,
|
|
40078
|
+
associateAsSessionTicket,
|
|
40079
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
40080
|
+
getCloudAccessToken: cloud.getCloudAccessToken
|
|
40081
|
+
});
|
|
40082
|
+
if (!fetched.ok) return mcpTextResult(fetched.error, true);
|
|
40083
|
+
const text = formatIntegrationContentForMcp(fetched.data);
|
|
40084
|
+
const isError = !fetched.data.ok;
|
|
40085
|
+
return mcpTextResult(text, isError);
|
|
40086
|
+
}
|
|
40087
|
+
|
|
40088
|
+
// src/mcp/tools/integration-content/tool-definitions.ts
|
|
40089
|
+
var SESSION_ID_SCHEMA2 = {
|
|
40090
|
+
type: "string",
|
|
40091
|
+
description: "Id of the current session. Required on every tool call so the workspace integration credentials can be resolved."
|
|
40092
|
+
};
|
|
40093
|
+
var INTEGRATION_CONTENT_MCP_TOOL_DEFINITIONS = [
|
|
40094
|
+
{
|
|
40095
|
+
name: GET_INTEGRATION_CONTENT_TOOL2,
|
|
40096
|
+
description: "Fetch the full content of a supported external integration link (Linear, GitHub, Jira, Notion, Slack thread, Zoom meeting, Asana). Requires sessionId and url. By default, links the URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false to fetch content only (e.g. additional context links). Returns an error when the URL is unsupported, the integration is not connected, or content is temporarily unavailable (retry may succeed).",
|
|
40097
|
+
inputSchema: {
|
|
40098
|
+
type: "object",
|
|
40099
|
+
properties: {
|
|
40100
|
+
sessionId: SESSION_ID_SCHEMA2,
|
|
40101
|
+
url: { type: "string", description: "External integration URL to fetch" },
|
|
40102
|
+
associateAsSessionTicket: {
|
|
40103
|
+
type: "boolean",
|
|
40104
|
+
description: "Defaults to true. When true and the session has no linked external ticket yet, links this URL as the session external ticket. Pass false when fetching additional links for context only."
|
|
40105
|
+
}
|
|
40106
|
+
},
|
|
40107
|
+
required: ["sessionId", "url"],
|
|
40108
|
+
additionalProperties: false
|
|
40109
|
+
}
|
|
40110
|
+
}
|
|
40111
|
+
];
|
|
40112
|
+
|
|
40113
|
+
// src/mcp/tools/integration-content/index.ts
|
|
40114
|
+
function isIntegrationContentMcpToolName(name) {
|
|
40115
|
+
return name === GET_INTEGRATION_CONTENT_TOOL2;
|
|
39417
40116
|
}
|
|
39418
40117
|
|
|
39419
40118
|
// src/mcp/bridge-mcp-tools.ts
|
|
@@ -39426,7 +40125,7 @@ function requireCloud(shared) {
|
|
|
39426
40125
|
function createBridgeMcpToolRegistry(shared) {
|
|
39427
40126
|
const cloud = requireCloud(shared);
|
|
39428
40127
|
return {
|
|
39429
|
-
listTools: async () => [...FORK_SESSION_MCP_TOOL_DEFINITIONS],
|
|
40128
|
+
listTools: async () => [...FORK_SESSION_MCP_TOOL_DEFINITIONS, ...INTEGRATION_CONTENT_MCP_TOOL_DEFINITIONS],
|
|
39430
40129
|
callTool: async (name, args) => {
|
|
39431
40130
|
if (isForkSessionMcpToolName(name)) {
|
|
39432
40131
|
if (!cloud) {
|
|
@@ -39444,6 +40143,22 @@ function createBridgeMcpToolRegistry(shared) {
|
|
|
39444
40143
|
}
|
|
39445
40144
|
return callForkSessionMcpTool({ ...shared, sessionId }, cloud, name, args);
|
|
39446
40145
|
}
|
|
40146
|
+
if (isIntegrationContentMcpToolName(name)) {
|
|
40147
|
+
if (!cloud) {
|
|
40148
|
+
return {
|
|
40149
|
+
content: [{ type: "text", text: "Bridge MCP tools require cloud API credentials." }],
|
|
40150
|
+
isError: true
|
|
40151
|
+
};
|
|
40152
|
+
}
|
|
40153
|
+
const sessionId = typeof args.sessionId === "string" ? args.sessionId.trim() : "";
|
|
40154
|
+
if (!sessionId) {
|
|
40155
|
+
return {
|
|
40156
|
+
content: [{ type: "text", text: "sessionId is required." }],
|
|
40157
|
+
isError: true
|
|
40158
|
+
};
|
|
40159
|
+
}
|
|
40160
|
+
return callIntegrationContentMcpTool({ ...shared, sessionId }, cloud, name, args);
|
|
40161
|
+
}
|
|
39447
40162
|
throw new Error(`Unknown bridge MCP tool: ${name}`);
|
|
39448
40163
|
}
|
|
39449
40164
|
};
|
|
@@ -39454,18 +40169,18 @@ import * as http from "node:http";
|
|
|
39454
40169
|
|
|
39455
40170
|
// src/mcp/bridge-access/read-json-body.ts
|
|
39456
40171
|
function readJsonBody(req) {
|
|
39457
|
-
return new Promise((
|
|
40172
|
+
return new Promise((resolve26, reject) => {
|
|
39458
40173
|
const chunks = [];
|
|
39459
40174
|
req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
39460
40175
|
req.on("end", () => {
|
|
39461
40176
|
try {
|
|
39462
40177
|
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
39463
40178
|
if (!raw) {
|
|
39464
|
-
|
|
40179
|
+
resolve26({});
|
|
39465
40180
|
return;
|
|
39466
40181
|
}
|
|
39467
40182
|
const parsed = JSON.parse(raw);
|
|
39468
|
-
|
|
40183
|
+
resolve26(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
|
|
39469
40184
|
} catch (e) {
|
|
39470
40185
|
reject(e);
|
|
39471
40186
|
}
|
|
@@ -39523,7 +40238,7 @@ function createBridgeAccessRequestHandler(registry2) {
|
|
|
39523
40238
|
// src/mcp/bridge-access/start-server.ts
|
|
39524
40239
|
function startBridgeAccessServer(registry2) {
|
|
39525
40240
|
const server = http.createServer(createBridgeAccessRequestHandler(registry2));
|
|
39526
|
-
return new Promise((
|
|
40241
|
+
return new Promise((resolve26, reject) => {
|
|
39527
40242
|
server.once("error", reject);
|
|
39528
40243
|
server.listen(0, "127.0.0.1", () => {
|
|
39529
40244
|
const addr = server.address();
|
|
@@ -39531,7 +40246,7 @@ function startBridgeAccessServer(registry2) {
|
|
|
39531
40246
|
reject(new Error("Bridge access server did not bind"));
|
|
39532
40247
|
return;
|
|
39533
40248
|
}
|
|
39534
|
-
|
|
40249
|
+
resolve26({
|
|
39535
40250
|
port: addr.port,
|
|
39536
40251
|
close: () => new Promise((closeResolve, closeReject) => {
|
|
39537
40252
|
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
@@ -39671,8 +40386,8 @@ async function createBridgeConnection(options) {
|
|
|
39671
40386
|
getCloudAccessToken: () => tokens.accessToken
|
|
39672
40387
|
};
|
|
39673
40388
|
const identifyReportedPaths = {
|
|
39674
|
-
bridgeRootPath:
|
|
39675
|
-
worktreesRootPath:
|
|
40389
|
+
bridgeRootPath: path52.resolve(getBridgeRoot()),
|
|
40390
|
+
worktreesRootPath: path52.resolve(worktreesRootPath)
|
|
39676
40391
|
};
|
|
39677
40392
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
39678
40393
|
state,
|