@buildautomaton/cli 0.1.12 → 0.1.14

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/index.js CHANGED
@@ -4065,8 +4065,8 @@ var init_parseUtil = __esm({
4065
4065
  init_errors();
4066
4066
  init_en();
4067
4067
  makeIssue = (params) => {
4068
- const { data, path: path29, errorMaps, issueData } = params;
4069
- const fullPath = [...path29, ...issueData.path || []];
4068
+ const { data, path: path31, errorMaps, issueData } = params;
4069
+ const fullPath = [...path31, ...issueData.path || []];
4070
4070
  const fullIssue = {
4071
4071
  ...issueData,
4072
4072
  path: fullPath
@@ -4374,11 +4374,11 @@ var init_types = __esm({
4374
4374
  init_parseUtil();
4375
4375
  init_util();
4376
4376
  ParseInputLazyPath = class {
4377
- constructor(parent, value, path29, key) {
4377
+ constructor(parent, value, path31, key) {
4378
4378
  this._cachedPath = [];
4379
4379
  this.parent = parent;
4380
4380
  this.data = value;
4381
- this._path = path29;
4381
+ this._path = path31;
4382
4382
  this._key = key;
4383
4383
  }
4384
4384
  get path() {
@@ -7993,15 +7993,15 @@ function assignProp(target, prop, value) {
7993
7993
  configurable: true
7994
7994
  });
7995
7995
  }
7996
- function getElementAtPath(obj, path29) {
7997
- if (!path29)
7996
+ function getElementAtPath(obj, path31) {
7997
+ if (!path31)
7998
7998
  return obj;
7999
- return path29.reduce((acc, key) => acc?.[key], obj);
7999
+ return path31.reduce((acc, key) => acc?.[key], obj);
8000
8000
  }
8001
8001
  function promiseAllObject(promisesObj) {
8002
8002
  const keys = Object.keys(promisesObj);
8003
- const promises = keys.map((key) => promisesObj[key]);
8004
- return Promise.all(promises).then((results) => {
8003
+ const promises3 = keys.map((key) => promisesObj[key]);
8004
+ return Promise.all(promises3).then((results) => {
8005
8005
  const resolvedObj = {};
8006
8006
  for (let i = 0; i < keys.length; i++) {
8007
8007
  resolvedObj[keys[i]] = results[i];
@@ -8245,11 +8245,11 @@ function aborted(x, startIndex = 0) {
8245
8245
  }
8246
8246
  return false;
8247
8247
  }
8248
- function prefixIssues(path29, issues) {
8248
+ function prefixIssues(path31, issues) {
8249
8249
  return issues.map((iss) => {
8250
8250
  var _a2;
8251
8251
  (_a2 = iss).path ?? (_a2.path = []);
8252
- iss.path.unshift(path29);
8252
+ iss.path.unshift(path31);
8253
8253
  return iss;
8254
8254
  });
8255
8255
  }
@@ -8438,7 +8438,7 @@ function treeifyError(error40, _mapper) {
8438
8438
  return issue2.message;
8439
8439
  };
8440
8440
  const result = { errors: [] };
8441
- const processError = (error41, path29 = []) => {
8441
+ const processError = (error41, path31 = []) => {
8442
8442
  var _a2, _b;
8443
8443
  for (const issue2 of error41.issues) {
8444
8444
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -8448,7 +8448,7 @@ function treeifyError(error40, _mapper) {
8448
8448
  } else if (issue2.code === "invalid_element") {
8449
8449
  processError({ issues: issue2.issues }, issue2.path);
8450
8450
  } else {
8451
- const fullpath = [...path29, ...issue2.path];
8451
+ const fullpath = [...path31, ...issue2.path];
8452
8452
  if (fullpath.length === 0) {
8453
8453
  result.errors.push(mapper(issue2));
8454
8454
  continue;
@@ -8478,9 +8478,9 @@ function treeifyError(error40, _mapper) {
8478
8478
  processError(error40);
8479
8479
  return result;
8480
8480
  }
8481
- function toDotPath(path29) {
8481
+ function toDotPath(path31) {
8482
8482
  const segs = [];
8483
- for (const seg of path29) {
8483
+ for (const seg of path31) {
8484
8484
  if (typeof seg === "number")
8485
8485
  segs.push(`[${seg}]`);
8486
8486
  else if (typeof seg === "symbol")
@@ -20943,8 +20943,8 @@ var init_acp = __esm({
20943
20943
  this.#requestHandler = requestHandler;
20944
20944
  this.#notificationHandler = notificationHandler;
20945
20945
  this.#stream = stream;
20946
- this.#closedPromise = new Promise((resolve14) => {
20947
- this.#abortController.signal.addEventListener("abort", () => resolve14());
20946
+ this.#closedPromise = new Promise((resolve15) => {
20947
+ this.#abortController.signal.addEventListener("abort", () => resolve15());
20948
20948
  });
20949
20949
  this.#receive();
20950
20950
  }
@@ -21093,8 +21093,8 @@ var init_acp = __esm({
21093
21093
  }
21094
21094
  async sendRequest(method, params) {
21095
21095
  const id = this.#nextRequestId++;
21096
- const responsePromise = new Promise((resolve14, reject) => {
21097
- this.#pendingResponses.set(id, { resolve: resolve14, reject });
21096
+ const responsePromise = new Promise((resolve15, reject) => {
21097
+ this.#pendingResponses.set(id, { resolve: resolve15, reject });
21098
21098
  });
21099
21099
  await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
21100
21100
  return responsePromise;
@@ -21963,10 +21963,10 @@ var require_src2 = __commonJS({
21963
21963
  var fs_1 = __require("fs");
21964
21964
  var debug_1 = __importDefault(require_src());
21965
21965
  var log2 = debug_1.default("@kwsites/file-exists");
21966
- function check2(path29, isFile, isDirectory) {
21967
- log2(`checking %s`, path29);
21966
+ function check2(path31, isFile, isDirectory) {
21967
+ log2(`checking %s`, path31);
21968
21968
  try {
21969
- const stat2 = fs_1.statSync(path29);
21969
+ const stat2 = fs_1.statSync(path31);
21970
21970
  if (stat2.isFile() && isFile) {
21971
21971
  log2(`[OK] path represents a file`);
21972
21972
  return true;
@@ -21986,8 +21986,8 @@ var require_src2 = __commonJS({
21986
21986
  throw e;
21987
21987
  }
21988
21988
  }
21989
- function exists2(path29, type = exports.READABLE) {
21990
- return check2(path29, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
21989
+ function exists2(path31, type = exports.READABLE) {
21990
+ return check2(path31, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
21991
21991
  }
21992
21992
  exports.exists = exists2;
21993
21993
  exports.FILE = 1;
@@ -22189,258 +22189,7 @@ function sendWsMessage(ws, payload) {
22189
22189
  }
22190
22190
  }
22191
22191
 
22192
- // ../types/dist/index.js
22193
- init_zod();
22194
- init_zod();
22195
- init_zod();
22196
- init_zod();
22197
- init_zod();
22198
- init_zod();
22199
- init_zod();
22200
- init_zod();
22201
- init_zod();
22202
- init_zod();
22203
- init_zod();
22204
- init_zod();
22205
- var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
22206
- var WorkItemProgressSchema = external_exports.object({
22207
- remainingCriteria: external_exports.array(external_exports.string()).default([]),
22208
- openQuestions: external_exports.array(external_exports.string()).default([]),
22209
- assignedTo: external_exports.enum(["agent", "human-product", "human-expert"]).optional()
22210
- });
22211
- var ChangeSchema = external_exports.object({
22212
- id: external_exports.string(),
22213
- description: external_exports.string(),
22214
- buildingBlockId: external_exports.string(),
22215
- buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
22216
- action: external_exports.enum(["create", "update", "split", "combine"])
22217
- });
22218
- var CompletionCriterionSchema = external_exports.object({
22219
- id: external_exports.string(),
22220
- description: external_exports.string(),
22221
- type: external_exports.enum(["write-code", "write-tests", "verify-tests", "other"]),
22222
- verified: external_exports.boolean().default(false)
22223
- });
22224
- var WorkItemPrioritySchema = external_exports.enum(["low", "medium", "high", "critical"]);
22225
- var IterationPhaseSchema = external_exports.enum(["analysis", "implementation", "verify", "reprioritize", "completed"]);
22226
- var WorkItemDependencySchema = external_exports.object({
22227
- type: external_exports.enum(["work-item"]),
22228
- id: external_exports.string()
22229
- });
22230
- var WorkItemSchema = external_exports.object({
22231
- id: external_exports.string(),
22232
- sessionId: external_exports.string().optional(),
22233
- summary: external_exports.string().optional(),
22234
- description: external_exports.string(),
22235
- status: WorkItemStatusSchema,
22236
- buildingBlockId: external_exports.string().optional(),
22237
- buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
22238
- changes: external_exports.array(ChangeSchema).default([]),
22239
- completionCriteria: external_exports.array(CompletionCriterionSchema).default([]),
22240
- priority: WorkItemPrioritySchema.default("medium"),
22241
- dependencies: external_exports.array(WorkItemDependencySchema).default([]),
22242
- assignedToUserId: external_exports.string().optional()
22243
- });
22244
- var UserWorkspaceProfileSchema = external_exports.object({
22245
- id: external_exports.string(),
22246
- workspaceId: external_exports.string(),
22247
- userId: external_exports.string(),
22248
- roleDescription: external_exports.string().optional(),
22249
- expertiseAreas: external_exports.array(external_exports.string()),
22250
- preferences: external_exports.record(external_exports.unknown()).optional(),
22251
- learnings: external_exports.array(external_exports.string())
22252
- });
22253
- var WorkspaceOwnerInfoSchema = external_exports.object({
22254
- ownerId: external_exports.string(),
22255
- ownerName: external_exports.string().optional(),
22256
- ownerEmail: external_exports.string().optional(),
22257
- ownerProfilePictureUrl: external_exports.string().optional()
22258
- });
22259
- var WorkspaceRuntimeEntrySchema = external_exports.object({
22260
- workspaceId: external_exports.string(),
22261
- path: external_exports.string(),
22262
- name: external_exports.string().optional(),
22263
- owner: WorkspaceOwnerInfoSchema.optional(),
22264
- isOwner: external_exports.boolean().optional()
22265
- });
22266
- var ProjectContextSchema = external_exports.object({
22267
- projectId: external_exports.string(),
22268
- context: external_exports.record(external_exports.unknown()).default({}),
22269
- updatedAt: external_exports.string()
22270
- });
22271
- var WebSocketMessageTypeSchema = external_exports.enum([
22272
- "plan-update",
22273
- "work-item-update",
22274
- "work-item-added",
22275
- "work-item-removed",
22276
- "project-processing-start",
22277
- "project-processing-update",
22278
- "project-processing-complete",
22279
- "project-processing-error",
22280
- "file-tool-request",
22281
- "file-tool-response",
22282
- "file-generated"
22283
- ]);
22284
- var WebSocketMessageSchema = external_exports.object({
22285
- type: WebSocketMessageTypeSchema,
22286
- contextId: external_exports.string().optional(),
22287
- data: external_exports.any().optional(),
22288
- error: external_exports.string().optional()
22289
- });
22290
- var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
22291
- var CheckpointSummarySchema = external_exports.object({
22292
- id: external_exports.string(),
22293
- kind: CheckpointKindSchema,
22294
- /** ISO date for daily (YYYY-MM-DD), ISO week for weekly, null for overall */
22295
- periodKey: external_exports.string().nullable(),
22296
- summary: external_exports.string(),
22297
- createdAt: external_exports.string(),
22298
- updatedAt: external_exports.string()
22299
- });
22300
- var ThreadMetaSchema = external_exports.object({
22301
- threadId: external_exports.string(),
22302
- workspaceId: external_exports.string(),
22303
- /** External source (e.g. slack, discord); null if internal-only */
22304
- externalSource: external_exports.string().nullable(),
22305
- /** Id in the external system (e.g. channel_id + thread_ts) */
22306
- externalId: external_exports.string().nullable(),
22307
- title: external_exports.string().optional(),
22308
- createdAt: external_exports.string(),
22309
- updatedAt: external_exports.string()
22310
- });
22311
- var ThreadMessageSchema = external_exports.object({
22312
- messageId: external_exports.string(),
22313
- threadId: external_exports.string(),
22314
- /** Role: user, assistant, system */
22315
- role: external_exports.enum(["user", "assistant", "system"]),
22316
- content: external_exports.string(),
22317
- /** Optional reference to a ContentItem (e.g. doc, Notion page) */
22318
- contentItemId: external_exports.string().nullable(),
22319
- /** External message id if synced from external chat */
22320
- externalId: external_exports.string().nullable(),
22321
- createdAt: external_exports.string(),
22322
- updatedAt: external_exports.string()
22323
- });
22324
- var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
22325
- threadId: external_exports.string()
22326
- });
22327
- var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
22328
- var ContentItemMetaSchema = external_exports.object({
22329
- contentId: external_exports.string(),
22330
- workspaceId: external_exports.string(),
22331
- source: ContentSourceSchema,
22332
- /** Id in the external system (e.g. Notion page id, doc url) */
22333
- externalId: external_exports.string(),
22334
- /** If source is slack_thread, points to Thread DO id */
22335
- threadId: external_exports.string().nullable(),
22336
- title: external_exports.string().optional(),
22337
- createdAt: external_exports.string(),
22338
- updatedAt: external_exports.string()
22339
- });
22340
- var ContentStorageRefSchema = external_exports.object({
22341
- storageKey: external_exports.string(),
22342
- /** Optional: mime type or format hint */
22343
- contentType: external_exports.string().optional()
22344
- });
22345
- var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
22346
- contentId: external_exports.string()
22347
- });
22348
- var StoryMetaSchema = external_exports.object({
22349
- storyId: external_exports.string(),
22350
- workspaceId: external_exports.string(),
22351
- title: external_exports.string(),
22352
- /** feature | bug | epic */
22353
- kind: external_exports.enum(["feature", "bug", "epic"]).default("feature"),
22354
- createdAt: external_exports.string(),
22355
- updatedAt: external_exports.string()
22356
- });
22357
- var StoryContentItemRefSchema = external_exports.object({
22358
- id: external_exports.string(),
22359
- storyId: external_exports.string(),
22360
- contentItemId: external_exports.string(),
22361
- /** Snapshot summary when added to story (or updated) */
22362
- summary: external_exports.string(),
22363
- orderIndex: external_exports.number().default(0),
22364
- createdAt: external_exports.string(),
22365
- updatedAt: external_exports.string()
22366
- });
22367
- var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
22368
- storyId: external_exports.string()
22369
- });
22370
- var SessionMetaSchema = external_exports.object({
22371
- sessionId: external_exports.string(),
22372
- workspaceId: external_exports.string(),
22373
- title: external_exports.string().optional(),
22374
- createdAt: external_exports.string(),
22375
- updatedAt: external_exports.string()
22376
- });
22377
- var SessionPromptSchema = external_exports.object({
22378
- id: external_exports.string(),
22379
- sessionId: external_exports.string(),
22380
- /** text | resource */
22381
- type: external_exports.enum(["text", "resource"]).default("text"),
22382
- text: external_exports.string().optional(),
22383
- resourceUri: external_exports.string().optional(),
22384
- createdAt: external_exports.string()
22385
- });
22386
- var SessionResponseSchema = external_exports.object({
22387
- id: external_exports.string(),
22388
- sessionId: external_exports.string(),
22389
- promptId: external_exports.string(),
22390
- /** message | completion */
22391
- kind: external_exports.enum(["message", "completion"]),
22392
- content: external_exports.string().optional(),
22393
- /** For completion: stopReason etc. */
22394
- stopReason: external_exports.string().optional(),
22395
- createdAt: external_exports.string()
22396
- });
22397
- var SessionToolCallSchema = external_exports.object({
22398
- id: external_exports.string(),
22399
- sessionId: external_exports.string(),
22400
- promptId: external_exports.string(),
22401
- name: external_exports.string(),
22402
- params: external_exports.record(external_exports.unknown()).optional(),
22403
- result: external_exports.record(external_exports.unknown()).optional(),
22404
- createdAt: external_exports.string()
22405
- });
22406
- var SessionThreadRefSchema = external_exports.object({
22407
- sessionId: external_exports.string(),
22408
- threadId: external_exports.string(),
22409
- addedAt: external_exports.string()
22410
- });
22411
- var ArtifactMetaSchema = external_exports.object({
22412
- artifactId: external_exports.string(),
22413
- workspaceId: external_exports.string(),
22414
- /** Slug for permalink: /workspaces/:wid/artifacts/:slug */
22415
- permalinkSlug: external_exports.string(),
22416
- title: external_exports.string(),
22417
- /** e.g. summary_report, build_log */
22418
- type: external_exports.string().default("report"),
22419
- /** Optional session that produced this artifact */
22420
- sessionId: external_exports.string().nullable(),
22421
- createdAt: external_exports.string(),
22422
- updatedAt: external_exports.string()
22423
- });
22424
- var TemplateMetaSchema = external_exports.object({
22425
- templateId: external_exports.string(),
22426
- workspaceId: external_exports.string(),
22427
- name: external_exports.string(),
22428
- /** e.g. summary_report, build_log */
22429
- artifactType: external_exports.string().optional(),
22430
- createdAt: external_exports.string(),
22431
- updatedAt: external_exports.string()
22432
- });
22433
- var GitRepoMetaSchema = external_exports.object({
22434
- /** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
22435
- repoId: external_exports.string(),
22436
- /** Canonical external URL (e.g. https://github.com/org/repo). Normalize before storing. */
22437
- canonicalUrl: external_exports.string().url(),
22438
- /** Optional workspace this repo was first linked in. */
22439
- workspaceId: external_exports.string().nullable(),
22440
- displayName: external_exports.string().optional(),
22441
- createdAt: external_exports.string(),
22442
- updatedAt: external_exports.string()
22443
- });
22192
+ // src/lib/local-agent-auth.ts
22444
22193
  var LOCAL_AGENT_AUTH_ERROR_HINTS = {
22445
22194
  "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
22446
22195
  "cursor-cli": [/cursor_login/i, /authenticate.*cursor/i, /not logged in.*cursor/i, /run:\s*agent\s+login/i],
@@ -22664,7 +22413,7 @@ async function createSdkStdioAcpClient(options) {
22664
22413
  child.once("close", (code, signal) => {
22665
22414
  onAgentSubprocessExit?.({ code, signal });
22666
22415
  });
22667
- return new Promise((resolve14, reject) => {
22416
+ return new Promise((resolve15, reject) => {
22668
22417
  let initSettled = false;
22669
22418
  const settleReject = (err) => {
22670
22419
  if (initSettled) return;
@@ -22678,7 +22427,7 @@ async function createSdkStdioAcpClient(options) {
22678
22427
  const settleResolve = (handle) => {
22679
22428
  if (initSettled) return;
22680
22429
  initSettled = true;
22681
- resolve14(handle);
22430
+ resolve15(handle);
22682
22431
  };
22683
22432
  child.on("error", (err) => {
22684
22433
  settleReject(new Error(formatSpawnError(err, command[0])));
@@ -22714,8 +22463,8 @@ async function createSdkStdioAcpClient(options) {
22714
22463
  });
22715
22464
  } catch {
22716
22465
  }
22717
- return await new Promise((resolve15) => {
22718
- pendingPermissionResolvers.set(requestId, resolve15);
22466
+ return await new Promise((resolve16) => {
22467
+ pendingPermissionResolvers.set(requestId, resolve16);
22719
22468
  });
22720
22469
  },
22721
22470
  async readTextFile(params) {
@@ -22823,9 +22572,9 @@ async function createSdkStdioAcpClient(options) {
22823
22572
  }
22824
22573
  },
22825
22574
  async cancel() {
22826
- for (const [id, resolve15] of [...pendingPermissionResolvers.entries()]) {
22575
+ for (const [id, resolve16] of [...pendingPermissionResolvers.entries()]) {
22827
22576
  pendingPermissionResolvers.delete(id);
22828
- resolve15({ outcome: { outcome: "cancelled" } });
22577
+ resolve16({ outcome: { outcome: "cancelled" } });
22829
22578
  }
22830
22579
  try {
22831
22580
  await connection.cancel({ sessionId });
@@ -22841,10 +22590,10 @@ async function createSdkStdioAcpClient(options) {
22841
22590
  }
22842
22591
  },
22843
22592
  resolveRequest(requestId, result) {
22844
- const resolve15 = pendingPermissionResolvers.get(requestId);
22845
- if (!resolve15) return;
22593
+ const resolve16 = pendingPermissionResolvers.get(requestId);
22594
+ if (!resolve16) return;
22846
22595
  pendingPermissionResolvers.delete(requestId);
22847
- resolve15(result);
22596
+ resolve16(result);
22848
22597
  },
22849
22598
  disconnect() {
22850
22599
  child.kill();
@@ -22951,7 +22700,7 @@ async function proxyToLocal(request) {
22951
22700
  };
22952
22701
  const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
22953
22702
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
22954
- const once = await new Promise((resolve14) => {
22703
+ const once = await new Promise((resolve15) => {
22955
22704
  const req = mod.request(opts, (res) => {
22956
22705
  const chunks = [];
22957
22706
  res.on("data", (c) => chunks.push(c));
@@ -22962,7 +22711,7 @@ async function proxyToLocal(request) {
22962
22711
  if (typeof v === "string") headers[k] = v;
22963
22712
  else if (Array.isArray(v) && v[0]) headers[k] = v[0];
22964
22713
  }
22965
- resolve14({
22714
+ resolve15({
22966
22715
  id: request.id,
22967
22716
  statusCode: res.statusCode ?? 0,
22968
22717
  headers,
@@ -22971,7 +22720,7 @@ async function proxyToLocal(request) {
22971
22720
  });
22972
22721
  });
22973
22722
  req.on("error", (err) => {
22974
- resolve14({
22723
+ resolve15({
22975
22724
  id: request.id,
22976
22725
  statusCode: 0,
22977
22726
  headers: {},
@@ -23053,8 +22802,8 @@ function randomSecret() {
23053
22802
  }
23054
22803
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
23055
22804
  }
23056
- async function requestPreviewApi(port, secret, method, path29, body) {
23057
- const url2 = `http://127.0.0.1:${port}${path29}`;
22805
+ async function requestPreviewApi(port, secret, method, path31, body) {
22806
+ const url2 = `http://127.0.0.1:${port}${path31}`;
23058
22807
  const headers = {
23059
22808
  [PREVIEW_SECRET_HEADER]: secret,
23060
22809
  "Content-Type": "application/json"
@@ -23066,7 +22815,7 @@ async function requestPreviewApi(port, secret, method, path29, body) {
23066
22815
  });
23067
22816
  const data = await res.json().catch(() => ({}));
23068
22817
  if (!res.ok) {
23069
- throw new Error(data?.error ?? `Preview API ${method} ${path29}: ${res.status}`);
22818
+ throw new Error(data?.error ?? `Preview API ${method} ${path31}: ${res.status}`);
23070
22819
  }
23071
22820
  return data;
23072
22821
  }
@@ -23278,6 +23027,19 @@ function clearConfigForApi(apiUrl) {
23278
23027
  }
23279
23028
  }
23280
23029
 
23030
+ // src/process-bridge-resilience.ts
23031
+ var installed = false;
23032
+ function installBridgeProcessResilience() {
23033
+ if (installed) return;
23034
+ installed = true;
23035
+ process.on("uncaughtException", (err) => {
23036
+ logImmediate(`[bridge] uncaughtException \u2014 continuing: ${err.stack ?? String(err)}`);
23037
+ });
23038
+ process.on("unhandledRejection", (reason) => {
23039
+ logImmediate(`[bridge] unhandledRejection \u2014 continuing: ${reason instanceof Error ? reason.stack : String(reason)}`);
23040
+ });
23041
+ }
23042
+
23281
23043
  // src/auth/open-browser.ts
23282
23044
  import { execSync } from "node:child_process";
23283
23045
  function isLocalApiUrl(apiUrl) {
@@ -23497,8 +23259,8 @@ function runPendingAuth(options) {
23497
23259
  let hasOpenedBrowser = false;
23498
23260
  let resolved = false;
23499
23261
  let resolveAuth;
23500
- const authPromise = new Promise((resolve14) => {
23501
- resolveAuth = resolve14;
23262
+ const authPromise = new Promise((resolve15) => {
23263
+ resolveAuth = resolve15;
23502
23264
  });
23503
23265
  let reconnectAttempt = 0;
23504
23266
  const signInQuiet = createEmptyReconnectQuietSlot();
@@ -23620,7 +23382,7 @@ function runPendingAuth(options) {
23620
23382
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
23621
23383
  const say = log2 ?? logImmediate;
23622
23384
  say("Cleaning up connections\u2026");
23623
- await new Promise((resolve14) => setImmediate(resolve14));
23385
+ await new Promise((resolve15) => setImmediate(resolve15));
23624
23386
  state.closedByUser = true;
23625
23387
  clearReconnectQuietTimer(state.mainQuiet);
23626
23388
  clearReconnectQuietTimer(state.firehoseQuiet);
@@ -23715,8 +23477,8 @@ function pathspec(...paths) {
23715
23477
  cache.set(key, paths);
23716
23478
  return key;
23717
23479
  }
23718
- function isPathSpec(path29) {
23719
- return path29 instanceof String && cache.has(path29);
23480
+ function isPathSpec(path31) {
23481
+ return path31 instanceof String && cache.has(path31);
23720
23482
  }
23721
23483
  function toPaths(pathSpec) {
23722
23484
  return cache.get(pathSpec) || [];
@@ -23805,8 +23567,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
23805
23567
  function forEachLineWithContent(input, callback) {
23806
23568
  return toLinesWithContent(input, true).map((line) => callback(line));
23807
23569
  }
23808
- function folderExists(path29) {
23809
- return (0, import_file_exists.exists)(path29, import_file_exists.FOLDER);
23570
+ function folderExists(path31) {
23571
+ return (0, import_file_exists.exists)(path31, import_file_exists.FOLDER);
23810
23572
  }
23811
23573
  function append(target, item) {
23812
23574
  if (Array.isArray(target)) {
@@ -24210,8 +23972,8 @@ function checkIsRepoRootTask() {
24210
23972
  commands,
24211
23973
  format: "utf-8",
24212
23974
  onError,
24213
- parser(path29) {
24214
- return /^\.(git)?$/.test(path29.trim());
23975
+ parser(path31) {
23976
+ return /^\.(git)?$/.test(path31.trim());
24215
23977
  }
24216
23978
  };
24217
23979
  }
@@ -24645,11 +24407,11 @@ function parseGrep(grep) {
24645
24407
  const paths = /* @__PURE__ */ new Set();
24646
24408
  const results = {};
24647
24409
  forEachLineWithContent(grep, (input) => {
24648
- const [path29, line, preview] = input.split(NULL);
24649
- paths.add(path29);
24650
- (results[path29] = results[path29] || []).push({
24410
+ const [path31, line, preview] = input.split(NULL);
24411
+ paths.add(path31);
24412
+ (results[path31] = results[path31] || []).push({
24651
24413
  line: asNumber(line),
24652
- path: path29,
24414
+ path: path31,
24653
24415
  preview
24654
24416
  });
24655
24417
  });
@@ -25414,14 +25176,14 @@ var init_hash_object = __esm2({
25414
25176
  init_task();
25415
25177
  }
25416
25178
  });
25417
- function parseInit(bare, path29, text) {
25179
+ function parseInit(bare, path31, text) {
25418
25180
  const response = String(text).trim();
25419
25181
  let result;
25420
25182
  if (result = initResponseRegex.exec(response)) {
25421
- return new InitSummary(bare, path29, false, result[1]);
25183
+ return new InitSummary(bare, path31, false, result[1]);
25422
25184
  }
25423
25185
  if (result = reInitResponseRegex.exec(response)) {
25424
- return new InitSummary(bare, path29, true, result[1]);
25186
+ return new InitSummary(bare, path31, true, result[1]);
25425
25187
  }
25426
25188
  let gitDir = "";
25427
25189
  const tokens = response.split(" ");
@@ -25432,7 +25194,7 @@ function parseInit(bare, path29, text) {
25432
25194
  break;
25433
25195
  }
25434
25196
  }
25435
- return new InitSummary(bare, path29, /^re/i.test(response), gitDir);
25197
+ return new InitSummary(bare, path31, /^re/i.test(response), gitDir);
25436
25198
  }
25437
25199
  var InitSummary;
25438
25200
  var initResponseRegex;
@@ -25441,9 +25203,9 @@ var init_InitSummary = __esm2({
25441
25203
  "src/lib/responses/InitSummary.ts"() {
25442
25204
  "use strict";
25443
25205
  InitSummary = class {
25444
- constructor(bare, path29, existing, gitDir) {
25206
+ constructor(bare, path31, existing, gitDir) {
25445
25207
  this.bare = bare;
25446
- this.path = path29;
25208
+ this.path = path31;
25447
25209
  this.existing = existing;
25448
25210
  this.gitDir = gitDir;
25449
25211
  }
@@ -25455,7 +25217,7 @@ var init_InitSummary = __esm2({
25455
25217
  function hasBareCommand(command) {
25456
25218
  return command.includes(bareCommand);
25457
25219
  }
25458
- function initTask(bare = false, path29, customArgs) {
25220
+ function initTask(bare = false, path31, customArgs) {
25459
25221
  const commands = ["init", ...customArgs];
25460
25222
  if (bare && !hasBareCommand(commands)) {
25461
25223
  commands.splice(1, 0, bareCommand);
@@ -25464,7 +25226,7 @@ function initTask(bare = false, path29, customArgs) {
25464
25226
  commands,
25465
25227
  format: "utf-8",
25466
25228
  parser(text) {
25467
- return parseInit(commands.includes("--bare"), path29, text);
25229
+ return parseInit(commands.includes("--bare"), path31, text);
25468
25230
  }
25469
25231
  };
25470
25232
  }
@@ -26280,12 +26042,12 @@ var init_FileStatusSummary = __esm2({
26280
26042
  "use strict";
26281
26043
  fromPathRegex = /^(.+)\0(.+)$/;
26282
26044
  FileStatusSummary = class {
26283
- constructor(path29, index, working_dir) {
26284
- this.path = path29;
26045
+ constructor(path31, index, working_dir) {
26046
+ this.path = path31;
26285
26047
  this.index = index;
26286
26048
  this.working_dir = working_dir;
26287
26049
  if (index === "R" || working_dir === "R") {
26288
- const detail = fromPathRegex.exec(path29) || [null, path29, path29];
26050
+ const detail = fromPathRegex.exec(path31) || [null, path31, path31];
26289
26051
  this.from = detail[2] || "";
26290
26052
  this.path = detail[1] || "";
26291
26053
  }
@@ -26316,14 +26078,14 @@ function splitLine(result, lineStr) {
26316
26078
  default:
26317
26079
  return;
26318
26080
  }
26319
- function data(index, workingDir, path29) {
26081
+ function data(index, workingDir, path31) {
26320
26082
  const raw = `${index}${workingDir}`;
26321
26083
  const handler = parsers6.get(raw);
26322
26084
  if (handler) {
26323
- handler(result, path29);
26085
+ handler(result, path31);
26324
26086
  }
26325
26087
  if (raw !== "##" && raw !== "!!") {
26326
- result.files.push(new FileStatusSummary(path29, index, workingDir));
26088
+ result.files.push(new FileStatusSummary(path31, index, workingDir));
26327
26089
  }
26328
26090
  }
26329
26091
  }
@@ -26494,14 +26256,14 @@ var init_status = __esm2({
26494
26256
  ignoredOptions = ["--null", "-z"];
26495
26257
  }
26496
26258
  });
26497
- function versionResponse(major = 0, minor = 0, patch = 0, agent = "", installed = true) {
26259
+ function versionResponse(major = 0, minor = 0, patch = 0, agent = "", installed2 = true) {
26498
26260
  return Object.defineProperty(
26499
26261
  {
26500
26262
  major,
26501
26263
  minor,
26502
26264
  patch,
26503
26265
  agent,
26504
- installed
26266
+ installed: installed2
26505
26267
  },
26506
26268
  "toString",
26507
26269
  {
@@ -26632,9 +26394,9 @@ var init_simple_git_api = __esm2({
26632
26394
  next
26633
26395
  );
26634
26396
  }
26635
- hashObject(path29, write) {
26397
+ hashObject(path31, write) {
26636
26398
  return this._runTask(
26637
- hashObjectTask(path29, write === true),
26399
+ hashObjectTask(path31, write === true),
26638
26400
  trailingFunctionArgument(arguments)
26639
26401
  );
26640
26402
  }
@@ -26987,8 +26749,8 @@ var init_branch = __esm2({
26987
26749
  }
26988
26750
  });
26989
26751
  function toPath(input) {
26990
- const path29 = input.trim().replace(/^["']|["']$/g, "");
26991
- return path29 && normalize2(path29);
26752
+ const path31 = input.trim().replace(/^["']|["']$/g, "");
26753
+ return path31 && normalize2(path31);
26992
26754
  }
26993
26755
  var parseCheckIgnore;
26994
26756
  var init_CheckIgnore = __esm2({
@@ -27302,8 +27064,8 @@ __export2(sub_module_exports, {
27302
27064
  subModuleTask: () => subModuleTask,
27303
27065
  updateSubModuleTask: () => updateSubModuleTask
27304
27066
  });
27305
- function addSubModuleTask(repo, path29) {
27306
- return subModuleTask(["add", repo, path29]);
27067
+ function addSubModuleTask(repo, path31) {
27068
+ return subModuleTask(["add", repo, path31]);
27307
27069
  }
27308
27070
  function initSubModuleTask(customArgs) {
27309
27071
  return subModuleTask(["init", ...customArgs]);
@@ -27636,8 +27398,8 @@ var require_git = __commonJS2({
27636
27398
  }
27637
27399
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
27638
27400
  };
27639
- Git2.prototype.submoduleAdd = function(repo, path29, then) {
27640
- return this._runTask(addSubModuleTask2(repo, path29), trailingFunctionArgument2(arguments));
27401
+ Git2.prototype.submoduleAdd = function(repo, path31, then) {
27402
+ return this._runTask(addSubModuleTask2(repo, path31), trailingFunctionArgument2(arguments));
27641
27403
  };
27642
27404
  Git2.prototype.submoduleUpdate = function(args, then) {
27643
27405
  return this._runTask(
@@ -28726,7 +28488,7 @@ async function createCursorAcpClient(options) {
28726
28488
  });
28727
28489
  const stderrCapture = createStderrCapture(child);
28728
28490
  child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
28729
- return new Promise((resolve14, reject) => {
28491
+ return new Promise((resolve15, reject) => {
28730
28492
  child.on("error", (err) => {
28731
28493
  child.kill();
28732
28494
  reject(new Error(formatSpawnError2(err, command[0])));
@@ -28913,7 +28675,7 @@ async function createCursorAcpClient(options) {
28913
28675
  const newResult = await send("session/new", { cwd, mcpServers: [] });
28914
28676
  const sessionId = newResult?.sessionId ?? "";
28915
28677
  if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
28916
- resolve14({
28678
+ resolve15({
28917
28679
  sessionId,
28918
28680
  async sendPrompt(prompt, _options) {
28919
28681
  promptOutputBuffer = "";
@@ -29971,7 +29733,7 @@ async function createAcpManager(options) {
29971
29733
  }
29972
29734
 
29973
29735
  // src/worktrees/session-worktree-manager.ts
29974
- import * as path13 from "node:path";
29736
+ import * as path15 from "node:path";
29975
29737
  import os3 from "node:os";
29976
29738
 
29977
29739
  // src/worktrees/prepare-new-session-worktrees.ts
@@ -30138,7 +29900,7 @@ async function removeSessionWorktrees(paths, log2) {
30138
29900
  }
30139
29901
  }
30140
29902
 
30141
- // src/git/working-tree-status.ts
29903
+ // src/git/working-directory/status/working-tree-status.ts
30142
29904
  async function tryConfigGet(g, key) {
30143
29905
  try {
30144
29906
  const out = await g.raw(["config", "--get", key]);
@@ -30148,11 +29910,24 @@ async function tryConfigGet(g, key) {
30148
29910
  return null;
30149
29911
  }
30150
29912
  }
29913
+ async function revParseSafe(g, ref) {
29914
+ try {
29915
+ const v = (await g.raw(["rev-parse", ref])).trim();
29916
+ return v || null;
29917
+ } catch {
29918
+ return null;
29919
+ }
29920
+ }
30151
29921
  async function resolveRemoteTrackingRefForAhead(g) {
30152
29922
  try {
30153
- await g.raw(["rev-parse", "--verify", "@{u}"]);
30154
- return "@{u}";
29923
+ await g.raw(["rev-parse", "--verify", "HEAD@{upstream}"]);
29924
+ return "HEAD@{upstream}";
30155
29925
  } catch {
29926
+ try {
29927
+ await g.raw(["rev-parse", "--verify", "@{u}"]);
29928
+ return "@{u}";
29929
+ } catch {
29930
+ }
30156
29931
  }
30157
29932
  const branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim();
30158
29933
  if (!branch || branch === "HEAD") return null;
@@ -30175,16 +29950,76 @@ async function resolveRemoteTrackingRefForAhead(g) {
30175
29950
  return null;
30176
29951
  }
30177
29952
  }
29953
+ async function remoteForCurrentBranch(g) {
29954
+ const branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim();
29955
+ if (!branch || branch === "HEAD") return "origin";
29956
+ return await tryConfigGet(g, `branch.${branch}.remote`) ?? "origin";
29957
+ }
29958
+ async function resolveDefaultRemoteBranchRef(g, remote) {
29959
+ const headSym = `refs/remotes/${remote}/HEAD`;
29960
+ try {
29961
+ const resolved = (await g.raw(["symbolic-ref", "-q", "--verify", headSym])).trim();
29962
+ if (resolved.startsWith("refs/remotes/")) return resolved;
29963
+ } catch {
29964
+ }
29965
+ for (const name of ["main", "master", "trunk", "develop"]) {
29966
+ const r = `refs/remotes/${remote}/${name}`;
29967
+ try {
29968
+ await g.raw(["rev-parse", "--verify", r]);
29969
+ return r;
29970
+ } catch {
29971
+ }
29972
+ }
29973
+ return null;
29974
+ }
29975
+ async function resolveBaseShaForUnpushedCommits(g) {
29976
+ const trackingRef = await resolveRemoteTrackingRefForAhead(g);
29977
+ if (trackingRef) {
29978
+ const sha = await revParseSafe(g, trackingRef);
29979
+ if (sha) return sha;
29980
+ }
29981
+ const remote = await remoteForCurrentBranch(g);
29982
+ const defaultRef = await resolveDefaultRemoteBranchRef(g, remote);
29983
+ if (!defaultRef) return null;
29984
+ return revParseSafe(g, defaultRef);
29985
+ }
29986
+ function parseLogShaDateSubjectLines(raw) {
29987
+ const out = [];
29988
+ for (const line of String(raw).split("\n")) {
29989
+ const l = line.trimEnd();
29990
+ if (!l.trim()) continue;
29991
+ const parts = l.split(" ");
29992
+ if (parts.length < 3) continue;
29993
+ const sha = parts[0].trim();
29994
+ const committedAt = parts[1].trim();
29995
+ const subject = parts.slice(2).join(" ").trim();
29996
+ if (!/^[0-9a-f]{7,40}$/i.test(sha)) continue;
29997
+ out.push({ sha, shortSha: sha.slice(0, 7), subject, committedAt });
29998
+ }
29999
+ return out;
30000
+ }
30001
+ async function gitLogNotReachableFromBase(g, baseSha, headSha) {
30002
+ if (baseSha === headSha) return [];
30003
+ try {
30004
+ const logOut = await g.raw(["log", "--format=%H %cI %s", `${baseSha}..${headSha}`]);
30005
+ return parseLogShaDateSubjectLines(logOut);
30006
+ } catch {
30007
+ return [];
30008
+ }
30009
+ }
30178
30010
  async function commitsAheadOfRemoteTracking(repoDir) {
30179
30011
  const g = simpleGit(repoDir);
30180
- const trackingRef = await resolveRemoteTrackingRefForAhead(g);
30181
- if (!trackingRef) return 0;
30182
- const localSha = (await g.raw(["rev-parse", "HEAD"])).trim();
30183
- const remoteSha = (await g.raw(["rev-parse", trackingRef])).trim();
30184
- if (localSha === remoteSha) return 0;
30185
- const out = await g.raw(["rev-list", "--count", `${trackingRef}..HEAD`]);
30186
- const n = parseInt(String(out).trim(), 10);
30187
- return Number.isNaN(n) ? 0 : n;
30012
+ const headSha = await revParseSafe(g, "HEAD");
30013
+ if (!headSha) return 0;
30014
+ const baseSha = await resolveBaseShaForUnpushedCommits(g);
30015
+ if (!baseSha || baseSha === headSha) return 0;
30016
+ try {
30017
+ const out = await g.raw(["rev-list", "--count", `${baseSha}..${headSha}`]);
30018
+ const n = parseInt(String(out).trim(), 10);
30019
+ return Number.isNaN(n) ? 0 : n;
30020
+ } catch {
30021
+ return 0;
30022
+ }
30188
30023
  }
30189
30024
  async function getRepoWorkingTreeStatus(repoDir) {
30190
30025
  const g = simpleGit(repoDir);
@@ -30193,6 +30028,14 @@ async function getRepoWorkingTreeStatus(repoDir) {
30193
30028
  const ahead = await commitsAheadOfRemoteTracking(repoDir);
30194
30029
  return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0 };
30195
30030
  }
30031
+ async function listUnpushedCommits(repoDir) {
30032
+ const g = simpleGit(repoDir);
30033
+ const headSha = await revParseSafe(g, "HEAD");
30034
+ if (!headSha) return [];
30035
+ const baseSha = await resolveBaseShaForUnpushedCommits(g);
30036
+ if (!baseSha) return [];
30037
+ return gitLogNotReachableFromBase(g, baseSha, headSha);
30038
+ }
30196
30039
  async function aggregateSessionPathsWorkingTreeStatus(paths) {
30197
30040
  let hasUncommittedChanges = false;
30198
30041
  let hasUnpushedCommits = false;
@@ -30212,6 +30055,477 @@ async function pushAheadOfUpstreamForPaths(paths) {
30212
30055
  }
30213
30056
  }
30214
30057
 
30058
+ // src/git/working-directory/changes/types.ts
30059
+ var MAX_PATCH_CHARS = 35e4;
30060
+
30061
+ // src/git/working-directory/changes/repo-format.ts
30062
+ function posixJoinDirFile(dir, file2) {
30063
+ const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
30064
+ const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
30065
+ return d ? `${d}/${f}` : f;
30066
+ }
30067
+ function formatRepoShortTitle(remoteUrl, repoRelPath) {
30068
+ const u = remoteUrl.trim();
30069
+ if (u) {
30070
+ try {
30071
+ if (u.startsWith("git@")) {
30072
+ const colon = u.indexOf(":");
30073
+ if (colon > 0) {
30074
+ const pathPart = u.slice(colon + 1).replace(/\.git$/i, "").replace(/\/+$/, "");
30075
+ if (pathPart.includes("/")) return pathPart;
30076
+ }
30077
+ } else {
30078
+ const parsed = new URL(u);
30079
+ const p = parsed.pathname.replace(/^\//, "").replace(/\.git$/i, "");
30080
+ const parts = p.split("/").filter(Boolean);
30081
+ if (parts.length >= 2) {
30082
+ return `${parts[parts.length - 2]}/${parts[parts.length - 1]}`;
30083
+ }
30084
+ if (parts.length === 1) return parts[0];
30085
+ }
30086
+ } catch {
30087
+ }
30088
+ }
30089
+ if (repoRelPath && repoRelPath !== ".") {
30090
+ const segments = repoRelPath.split("/").filter(Boolean);
30091
+ const last2 = segments[segments.length - 1];
30092
+ if (last2) return last2;
30093
+ }
30094
+ return "Repository";
30095
+ }
30096
+ function formatRemoteDisplayLabel(remoteUrl) {
30097
+ const u = remoteUrl.trim();
30098
+ if (!u) return "";
30099
+ let hostPath = u;
30100
+ try {
30101
+ if (u.startsWith("git@")) {
30102
+ const rest = u.slice("git@".length);
30103
+ const slash = rest.indexOf(":");
30104
+ if (slash > 0) hostPath = `${rest.slice(0, slash)}/${rest.slice(slash + 1)}`;
30105
+ } else {
30106
+ const parsed = new URL(u);
30107
+ hostPath = `${parsed.hostname}${parsed.pathname}`.replace(/\/\.git$/i, "").replace(/\.git$/i, "");
30108
+ }
30109
+ } catch {
30110
+ hostPath = u.replace(/^https?:\/\//i, "").replace(/\.git$/i, "");
30111
+ }
30112
+ return `origin \xB7 ${hostPath}`;
30113
+ }
30114
+
30115
+ // src/git/working-directory/changes/get-working-tree-change-repo-details.ts
30116
+ import * as path14 from "node:path";
30117
+
30118
+ // src/git/working-directory/changes/parse-git-status.ts
30119
+ function parseNameStatusLines(lines) {
30120
+ const m = /* @__PURE__ */ new Map();
30121
+ for (const line of lines) {
30122
+ if (!line.trim()) continue;
30123
+ const tabParts = line.split(" ");
30124
+ if (tabParts.length < 2) continue;
30125
+ const status = tabParts[0].trim();
30126
+ const code = status[0];
30127
+ if (code === "A") {
30128
+ m.set(tabParts[tabParts.length - 1], "added");
30129
+ } else if (code === "D") {
30130
+ m.set(tabParts[tabParts.length - 1], "removed");
30131
+ } else if (code === "R" || code === "C") {
30132
+ if (tabParts.length >= 3) m.set(tabParts[tabParts.length - 1], "modified");
30133
+ } else if (code === "M" || code === "U" || code === "T") {
30134
+ m.set(tabParts[tabParts.length - 1], "modified");
30135
+ }
30136
+ }
30137
+ return m;
30138
+ }
30139
+ function parseNumstatFirstLine(line) {
30140
+ const parts = line.split(" ");
30141
+ if (parts.length < 3) return null;
30142
+ const [a, d] = parts;
30143
+ const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
30144
+ const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
30145
+ return { additions, deletions };
30146
+ }
30147
+ function parseNumstat(lines) {
30148
+ const m = /* @__PURE__ */ new Map();
30149
+ for (const line of lines) {
30150
+ if (!line.trim()) continue;
30151
+ const parts = line.split(" ");
30152
+ if (parts.length < 3) continue;
30153
+ const [a, d, p] = parts;
30154
+ const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
30155
+ const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
30156
+ m.set(p, { additions, deletions });
30157
+ }
30158
+ return m;
30159
+ }
30160
+ async function numstatFromGitNoIndex(g, pathInRepo) {
30161
+ const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
30162
+ try {
30163
+ const out = await g.raw(["diff", "--numstat", "--no-index", "--", devNull, pathInRepo]);
30164
+ const first2 = String(out).split("\n").find((l) => l.trim()) ?? "";
30165
+ return parseNumstatFirstLine(first2);
30166
+ } catch {
30167
+ return null;
30168
+ }
30169
+ }
30170
+
30171
+ // src/git/working-directory/changes/patch-truncate.ts
30172
+ function truncatePatch(s) {
30173
+ if (s.length <= MAX_PATCH_CHARS) return s;
30174
+ return `${s.slice(0, MAX_PATCH_CHARS)}
30175
+
30176
+ \u2026 (diff truncated)`;
30177
+ }
30178
+
30179
+ // src/git/working-directory/changes/list-changed-files-for-commit.ts
30180
+ var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
30181
+ async function parentForCommitDiff(g, sha) {
30182
+ try {
30183
+ return (await g.raw(["rev-parse", `${sha}^1`])).trim();
30184
+ } catch {
30185
+ try {
30186
+ return (await g.raw(["rev-parse", `${sha}^`])).trim();
30187
+ } catch {
30188
+ return EMPTY_TREE;
30189
+ }
30190
+ }
30191
+ }
30192
+ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
30193
+ const g = simpleGit(repoGitCwd);
30194
+ const parent = await parentForCommitDiff(g, commitSha);
30195
+ const range = `${parent}..${commitSha}`;
30196
+ const [nameStatusRaw, numstatRaw] = await Promise.all([
30197
+ g.raw(["diff", "--name-status", range]).catch(() => ""),
30198
+ g.raw(["diff", "--numstat", range]).catch(() => "")
30199
+ ]);
30200
+ const kindByPath = parseNameStatusLines(String(nameStatusRaw).split("\n"));
30201
+ const numByPath = parseNumstat(String(numstatRaw).split("\n"));
30202
+ const paths = new Set([...kindByPath.keys(), ...numByPath.keys()].filter(Boolean));
30203
+ const rows = [];
30204
+ const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
30205
+ for (const pathInRepo of paths) {
30206
+ const relLauncher = posixJoinDirFile(normRel, pathInRepo.replace(/\\/g, "/"));
30207
+ const nums = numByPath.get(pathInRepo);
30208
+ let additions = nums?.additions ?? 0;
30209
+ let deletions = nums?.deletions ?? 0;
30210
+ let change = kindByPath.get(pathInRepo) ?? "modified";
30211
+ if (!kindByPath.has(pathInRepo) && nums) {
30212
+ if (additions > 0 && deletions === 0) change = "added";
30213
+ else if (deletions > 0 && additions === 0) change = "removed";
30214
+ else change = "modified";
30215
+ }
30216
+ rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
30217
+ }
30218
+ for (const row of rows) {
30219
+ let pathInRepo;
30220
+ if (normRel === ".") {
30221
+ pathInRepo = row.pathRelLauncher;
30222
+ } else if (row.pathRelLauncher.startsWith(`${normRel}/`)) {
30223
+ pathInRepo = row.pathRelLauncher.slice(normRel.length + 1);
30224
+ } else {
30225
+ pathInRepo = row.pathRelLauncher;
30226
+ }
30227
+ const raw = await g.raw(["diff", "-U20000", range, "--", pathInRepo]).catch(() => "");
30228
+ const t = String(raw).trim();
30229
+ row.patchContent = t ? truncatePatch(t) : void 0;
30230
+ }
30231
+ rows.sort((a, b) => a.pathRelLauncher.localeCompare(b.pathRelLauncher));
30232
+ return rows;
30233
+ }
30234
+
30235
+ // src/git/working-directory/changes/list-changed-files-for-repo.ts
30236
+ import * as fs11 from "node:fs";
30237
+ import * as path13 from "node:path";
30238
+
30239
+ // src/git/working-directory/changes/count-lines.ts
30240
+ import { createReadStream } from "node:fs";
30241
+ import * as readline2 from "node:readline";
30242
+ async function countTextFileLines(absFile) {
30243
+ let bytes = 0;
30244
+ const maxBytes = 512e3;
30245
+ let lines = 0;
30246
+ const stream = createReadStream(absFile, { encoding: "utf8" });
30247
+ const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
30248
+ for await (const _line of rl) {
30249
+ lines += 1;
30250
+ bytes += Buffer.byteLength(String(_line), "utf8") + 1;
30251
+ if (bytes > maxBytes) {
30252
+ rl.close();
30253
+ stream.destroy();
30254
+ return lines;
30255
+ }
30256
+ }
30257
+ return lines;
30258
+ }
30259
+
30260
+ // src/git/working-directory/changes/hydrate-patch.ts
30261
+ import * as fs10 from "node:fs";
30262
+ var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
30263
+ var MAX_HYDRATE_LINES_PER_GAP = 8e3;
30264
+ var MAX_HYDRATE_LINES_PER_FILE = 8e4;
30265
+ async function readGitBlobLines(repoCwd, pathInRepo) {
30266
+ try {
30267
+ const rel = pathInRepo.replace(/\\/g, "/");
30268
+ const raw = await simpleGit(repoCwd).show([`HEAD:${rel}`]);
30269
+ return String(raw).split(/\r?\n/);
30270
+ } catch {
30271
+ return null;
30272
+ }
30273
+ }
30274
+ async function readWorktreeFileLines(abs) {
30275
+ try {
30276
+ const raw = await fs10.promises.readFile(abs, "utf8");
30277
+ return raw.split(/\r?\n/);
30278
+ } catch {
30279
+ return null;
30280
+ }
30281
+ }
30282
+ async function hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pathInRepo, change) {
30283
+ if (!patch.trim() || patch.includes("Binary files")) return patch;
30284
+ const all = patch.split("\n");
30285
+ const out = [];
30286
+ let prevOldEnd = 0;
30287
+ let prevNewEnd = 0;
30288
+ let injectedTotal = 0;
30289
+ let i = 0;
30290
+ let blobCache;
30291
+ let diskCache;
30292
+ const blobLines = async () => {
30293
+ if (blobCache !== void 0) return blobCache;
30294
+ blobCache = await readGitBlobLines(repoGitCwd, pathInRepo);
30295
+ return blobCache;
30296
+ };
30297
+ const diskLines = async () => {
30298
+ if (diskCache !== void 0) return diskCache;
30299
+ diskCache = await readWorktreeFileLines(absFile);
30300
+ return diskCache;
30301
+ };
30302
+ while (i < all.length) {
30303
+ const line = all[i];
30304
+ const hm = line.match(UNIFIED_HUNK_HEADER_RE);
30305
+ if (!hm) {
30306
+ out.push(line);
30307
+ i++;
30308
+ continue;
30309
+ }
30310
+ const oldStart = parseInt(hm[1], 10) || 0;
30311
+ const newStart = parseInt(hm[3], 10) || 0;
30312
+ const gapOldStart = prevOldEnd + 1;
30313
+ const gapOldEnd = oldStart - 1;
30314
+ const gapNewStart = prevNewEnd + 1;
30315
+ const gapNewEnd = newStart - 1;
30316
+ if (injectedTotal < MAX_HYDRATE_LINES_PER_FILE) {
30317
+ let inject = null;
30318
+ if (gapNewEnd >= gapNewStart && change !== "removed") {
30319
+ const nNew = gapNewEnd - gapNewStart + 1;
30320
+ if (gapOldEnd < gapOldStart || gapOldEnd - gapOldStart + 1 === nNew) {
30321
+ const cap = Math.min(nNew, MAX_HYDRATE_LINES_PER_GAP, MAX_HYDRATE_LINES_PER_FILE - injectedTotal);
30322
+ const dl = await diskLines();
30323
+ if (dl && cap > 0) {
30324
+ inject = dl.slice(gapNewStart - 1, gapNewStart - 1 + cap);
30325
+ }
30326
+ }
30327
+ } else if (gapOldEnd >= gapOldStart && change === "removed") {
30328
+ const nOld = gapOldEnd - gapOldStart + 1;
30329
+ const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, MAX_HYDRATE_LINES_PER_FILE - injectedTotal);
30330
+ const bl = await blobLines();
30331
+ if (bl && cap > 0) {
30332
+ inject = bl.slice(gapOldStart - 1, gapOldStart - 1 + cap);
30333
+ }
30334
+ }
30335
+ if (inject && inject.length > 0) {
30336
+ for (const t of inject) {
30337
+ out.push(` ${t}`);
30338
+ injectedTotal++;
30339
+ }
30340
+ }
30341
+ }
30342
+ out.push(line);
30343
+ i++;
30344
+ let oldConsumed = 0;
30345
+ let newConsumed = 0;
30346
+ while (i < all.length) {
30347
+ const bl = all[i];
30348
+ if (UNIFIED_HUNK_HEADER_RE.test(bl)) break;
30349
+ out.push(bl);
30350
+ i++;
30351
+ if (bl.startsWith("\\")) continue;
30352
+ const ch = bl[0];
30353
+ if (ch === " ") {
30354
+ oldConsumed++;
30355
+ newConsumed++;
30356
+ } else if (ch === "-") {
30357
+ oldConsumed++;
30358
+ } else if (ch === "+") {
30359
+ newConsumed++;
30360
+ }
30361
+ }
30362
+ if (oldStart > 0) {
30363
+ prevOldEnd = oldStart + oldConsumed - 1;
30364
+ } else {
30365
+ prevOldEnd = 0;
30366
+ }
30367
+ if (newStart > 0) {
30368
+ prevNewEnd = newStart + newConsumed - 1;
30369
+ } else {
30370
+ prevNewEnd = 0;
30371
+ }
30372
+ }
30373
+ return truncatePatch(out.join("\n"));
30374
+ }
30375
+
30376
+ // src/git/working-directory/changes/unified-diff-for-file.ts
30377
+ async function unifiedDiffForFile(repoCwd, pathInRepo, change) {
30378
+ const g = simpleGit(repoCwd);
30379
+ try {
30380
+ let raw;
30381
+ if (change === "added") {
30382
+ const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
30383
+ raw = await g.raw(["diff", "--no-index", "--", devNull, pathInRepo]);
30384
+ } else {
30385
+ raw = await g.raw(["diff", "HEAD", "--", pathInRepo]);
30386
+ }
30387
+ const t = String(raw).trim();
30388
+ if (!t) return void 0;
30389
+ return truncatePatch(t);
30390
+ } catch {
30391
+ return void 0;
30392
+ }
30393
+ }
30394
+
30395
+ // src/git/working-directory/changes/list-changed-files-for-repo.ts
30396
+ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
30397
+ const g = simpleGit(repoGitCwd);
30398
+ const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
30399
+ g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
30400
+ g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
30401
+ g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
30402
+ ]);
30403
+ const kindByPath = parseNameStatusLines(String(nameStatusRaw).split("\n"));
30404
+ const numByPath = parseNumstat(String(numstatRaw).split("\n"));
30405
+ const paths = /* @__PURE__ */ new Set([...kindByPath.keys(), ...numByPath.keys()]);
30406
+ const untracked = String(untrackedRaw).split("\n").map((s) => s.trim()).filter(Boolean);
30407
+ for (const p of untracked) paths.add(p);
30408
+ const rows = [];
30409
+ for (const pathInRepo of paths) {
30410
+ const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
30411
+ const abs = path13.join(repoGitCwd, pathInRepo);
30412
+ const nums = numByPath.get(pathInRepo);
30413
+ let additions = nums?.additions ?? 0;
30414
+ let deletions = nums?.deletions ?? 0;
30415
+ let change = kindByPath.get(pathInRepo) ?? "modified";
30416
+ if (untracked.includes(pathInRepo) && !kindByPath.has(pathInRepo)) {
30417
+ change = "added";
30418
+ const fromGit = await numstatFromGitNoIndex(g, pathInRepo);
30419
+ if (fromGit) {
30420
+ additions = fromGit.additions;
30421
+ deletions = fromGit.deletions;
30422
+ } else {
30423
+ try {
30424
+ const st = await fs11.promises.stat(abs);
30425
+ if (st.isFile()) additions = await countTextFileLines(abs);
30426
+ else additions = 0;
30427
+ } catch {
30428
+ additions = 0;
30429
+ }
30430
+ deletions = 0;
30431
+ }
30432
+ }
30433
+ if (!kindByPath.has(pathInRepo) && nums) {
30434
+ if (additions > 0 && deletions === 0) change = "added";
30435
+ else if (deletions > 0 && additions === 0) change = "removed";
30436
+ else change = "modified";
30437
+ }
30438
+ rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
30439
+ }
30440
+ const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
30441
+ for (const row of rows) {
30442
+ let pathInRepo;
30443
+ if (normRel === ".") {
30444
+ pathInRepo = row.pathRelLauncher;
30445
+ } else if (row.pathRelLauncher.startsWith(`${normRel}/`)) {
30446
+ pathInRepo = row.pathRelLauncher.slice(normRel.length + 1);
30447
+ } else {
30448
+ pathInRepo = row.pathRelLauncher;
30449
+ }
30450
+ const absFile = path13.join(repoGitCwd, pathInRepo);
30451
+ let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
30452
+ if (patch) {
30453
+ patch = await hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pathInRepo, row.change);
30454
+ }
30455
+ row.patchContent = patch;
30456
+ }
30457
+ return rows;
30458
+ }
30459
+
30460
+ // src/git/working-directory/changes/get-working-tree-change-repo-details.ts
30461
+ function normRepoRel(p) {
30462
+ const x = p.replace(/\\/g, "/").trim();
30463
+ return x === "" ? "." : x;
30464
+ }
30465
+ async function getWorkingTreeChangeRepoDetails(options) {
30466
+ const launcher = path14.resolve(getBridgeWorkspaceDirectory());
30467
+ const mirror = options.agentMirrorRootAbs ? path14.resolve(options.agentMirrorRootAbs) : null;
30468
+ const out = [];
30469
+ const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
30470
+ const basisInput = options.basis ?? { kind: "working" };
30471
+ if (basisInput.kind === "commit" && !filter) {
30472
+ throw new Error("repoFilterRelPath is required for commit changes");
30473
+ }
30474
+ if (basisInput.kind === "commit" && !basisInput.sha.trim()) {
30475
+ throw new Error("commit sha is required for commit changes");
30476
+ }
30477
+ const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
30478
+ for (const target of options.commitTargetAbsDirs) {
30479
+ const t = path14.resolve(target);
30480
+ if (!await isGitRepoDirectory(t)) continue;
30481
+ const g = simpleGit(t);
30482
+ let branch = "HEAD";
30483
+ try {
30484
+ branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim() || "HEAD";
30485
+ } catch {
30486
+ branch = "HEAD";
30487
+ }
30488
+ const remoteUrl = await getRemoteOriginUrl(t);
30489
+ const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
30490
+ let repoRelPath;
30491
+ if (mirror) {
30492
+ const relNorm = path14.relative(mirror, path14.dirname(t));
30493
+ repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
30494
+ } else {
30495
+ let top = t;
30496
+ try {
30497
+ top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
30498
+ } catch {
30499
+ top = t;
30500
+ }
30501
+ const rel = path14.relative(launcher, path14.resolve(top)).replace(/\\/g, "/") || ".";
30502
+ repoRelPath = rel.startsWith("..") ? path14.basename(path14.resolve(top)) : rel;
30503
+ }
30504
+ const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
30505
+ if (filter && norm !== filter) continue;
30506
+ const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
30507
+ const relForList = norm === "." ? "." : norm;
30508
+ const files = basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
30509
+ const st = await g.status();
30510
+ const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
30511
+ const unpushedCommits = await listUnpushedCommits(t);
30512
+ out.push({
30513
+ repoRelPath: norm,
30514
+ repoDisplayName,
30515
+ branch,
30516
+ remoteUrl,
30517
+ remoteDisplay,
30518
+ files,
30519
+ hasUncommittedChanges,
30520
+ unpushedCommits,
30521
+ changesView: basis.kind === "commit" ? "commit" : "working",
30522
+ changesCommitSha: basis.kind === "commit" ? basis.sha.trim() : null
30523
+ });
30524
+ if (filter) return out;
30525
+ }
30526
+ return out;
30527
+ }
30528
+
30215
30529
  // src/git/commit-and-push.ts
30216
30530
  async function gitCommitAllIfDirty(repoDir, message, options) {
30217
30531
  const g = simpleGit(repoDir);
@@ -30277,7 +30591,7 @@ var SessionWorktreeManager = class {
30277
30591
  }
30278
30592
  if (!opts.isNewSession) {
30279
30593
  const agentCwd = this.sessionAgentCwd.get(sessionId);
30280
- if (agentCwd) return path13.resolve(agentCwd);
30594
+ if (agentCwd) return path15.resolve(agentCwd);
30281
30595
  return void 0;
30282
30596
  }
30283
30597
  const prep = await prepareNewSessionWorktrees({
@@ -30290,7 +30604,7 @@ var SessionWorktreeManager = class {
30290
30604
  if (!prep) return void 0;
30291
30605
  this.sessionPaths.set(sessionId, prep.worktreePaths);
30292
30606
  this.sessionAgentCwd.set(sessionId, prep.agentCwd);
30293
- return path13.resolve(prep.agentCwd);
30607
+ return path15.resolve(prep.agentCwd);
30294
30608
  }
30295
30609
  async renameSessionBranch(sessionId, newBranch) {
30296
30610
  const paths = this.sessionPaths.get(sessionId);
@@ -30311,7 +30625,7 @@ var SessionWorktreeManager = class {
30311
30625
  getAgentCwdForSession(sessionId) {
30312
30626
  if (!sessionId) return null;
30313
30627
  const c = this.sessionAgentCwd.get(sessionId);
30314
- return c ? path13.resolve(c) : null;
30628
+ return c ? path15.resolve(c) : null;
30315
30629
  }
30316
30630
  async removeSessionWorktrees(sessionId) {
30317
30631
  const paths = this.sessionPaths.get(sessionId);
@@ -30337,6 +30651,17 @@ var SessionWorktreeManager = class {
30337
30651
  async getSessionWorkingTreeStatus(sessionId) {
30338
30652
  return aggregateSessionPathsWorkingTreeStatus(this.resolveCommitTargets(sessionId));
30339
30653
  }
30654
+ /** Per-repo changed files vs HEAD (or a single commit vs parent) for the same git roots used for commit/push. */
30655
+ async getSessionWorkingTreeChangeDetails(sessionId, opts) {
30656
+ const targets = this.resolveCommitTargets(sessionId);
30657
+ const mirror = this.getAgentCwdForSession(sessionId);
30658
+ return getWorkingTreeChangeRepoDetails({
30659
+ commitTargetAbsDirs: targets,
30660
+ agentMirrorRootAbs: mirror,
30661
+ repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
30662
+ basis: opts?.basis
30663
+ });
30664
+ }
30340
30665
  async pushSessionUpstream(sessionId) {
30341
30666
  try {
30342
30667
  await pushAheadOfUpstreamForPaths(this.resolveCommitTargets(sessionId));
@@ -30348,30 +30673,30 @@ var SessionWorktreeManager = class {
30348
30673
  }
30349
30674
  };
30350
30675
  function defaultWorktreesRootAbs() {
30351
- return path13.join(os3.homedir(), ".buildautomaton", "worktrees");
30676
+ return path15.join(os3.homedir(), ".buildautomaton", "worktrees");
30352
30677
  }
30353
30678
 
30354
30679
  // src/files/watch-file-index.ts
30355
30680
  import { watch } from "node:fs";
30356
- import path20 from "node:path";
30681
+ import path22 from "node:path";
30357
30682
 
30358
30683
  // src/files/index/build-file-index.ts
30359
- import path17 from "node:path";
30684
+ import path19 from "node:path";
30360
30685
 
30361
30686
  // src/runtime/yield-to-event-loop.ts
30362
30687
  function yieldToEventLoop() {
30363
- return new Promise((resolve14) => setImmediate(resolve14));
30688
+ return new Promise((resolve15) => setImmediate(resolve15));
30364
30689
  }
30365
30690
 
30366
30691
  // src/files/index/walk-workspace-tree.ts
30367
- import fs10 from "node:fs";
30368
- import path15 from "node:path";
30692
+ import fs12 from "node:fs";
30693
+ import path17 from "node:path";
30369
30694
 
30370
30695
  // src/files/index/constants.ts
30371
- import path14 from "node:path";
30696
+ import path16 from "node:path";
30372
30697
  import os4 from "node:os";
30373
30698
  var INDEX_WORK_YIELD_EVERY = 256;
30374
- var INDEX_DIR = path14.join(os4.homedir(), ".buildautomaton");
30699
+ var INDEX_DIR = path16.join(os4.homedir(), ".buildautomaton");
30375
30700
  var INDEX_HASH_LEN = 16;
30376
30701
  var INDEX_VERSION = 2;
30377
30702
  var INDEX_LOG_PREFIX = "[file-index]";
@@ -30380,31 +30705,31 @@ var INDEX_LOG_PREFIX = "[file-index]";
30380
30705
  function walkWorkspaceTreeSync(dir, baseDir, out) {
30381
30706
  let names;
30382
30707
  try {
30383
- names = fs10.readdirSync(dir);
30708
+ names = fs12.readdirSync(dir);
30384
30709
  } catch {
30385
30710
  return;
30386
30711
  }
30387
30712
  for (const name of names) {
30388
30713
  if (name.startsWith(".")) continue;
30389
- const full = path15.join(dir, name);
30714
+ const full = path17.join(dir, name);
30390
30715
  let stat2;
30391
30716
  try {
30392
- stat2 = fs10.statSync(full);
30717
+ stat2 = fs12.statSync(full);
30393
30718
  } catch {
30394
30719
  continue;
30395
30720
  }
30396
- const relative4 = path15.relative(baseDir, full).replace(/\\/g, "/");
30721
+ const relative5 = path17.relative(baseDir, full).replace(/\\/g, "/");
30397
30722
  if (stat2.isDirectory()) {
30398
30723
  walkWorkspaceTreeSync(full, baseDir, out);
30399
30724
  } else if (stat2.isFile()) {
30400
- out.push(relative4);
30725
+ out.push(relative5);
30401
30726
  }
30402
30727
  }
30403
30728
  }
30404
30729
  async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
30405
30730
  let names;
30406
30731
  try {
30407
- names = await fs10.promises.readdir(dir);
30732
+ names = await fs12.promises.readdir(dir);
30408
30733
  } catch {
30409
30734
  return;
30410
30735
  }
@@ -30414,18 +30739,18 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
30414
30739
  await yieldToEventLoop();
30415
30740
  }
30416
30741
  state.n++;
30417
- const full = path15.join(dir, name);
30742
+ const full = path17.join(dir, name);
30418
30743
  let stat2;
30419
30744
  try {
30420
- stat2 = await fs10.promises.stat(full);
30745
+ stat2 = await fs12.promises.stat(full);
30421
30746
  } catch {
30422
30747
  continue;
30423
30748
  }
30424
- const relative4 = path15.relative(baseDir, full).replace(/\\/g, "/");
30749
+ const relative5 = path17.relative(baseDir, full).replace(/\\/g, "/");
30425
30750
  if (stat2.isDirectory()) {
30426
30751
  await walkWorkspaceTreeAsync(full, baseDir, out, state);
30427
30752
  } else if (stat2.isFile()) {
30428
- out.push(relative4);
30753
+ out.push(relative5);
30429
30754
  }
30430
30755
  }
30431
30756
  }
@@ -30502,22 +30827,22 @@ async function buildTrigramMapForPathsAsync(paths) {
30502
30827
  }
30503
30828
 
30504
30829
  // src/files/index/write-index-file.ts
30505
- import fs11 from "node:fs";
30830
+ import fs13 from "node:fs";
30506
30831
 
30507
30832
  // src/files/index/paths.ts
30508
- import path16 from "node:path";
30833
+ import path18 from "node:path";
30509
30834
  import crypto2 from "node:crypto";
30510
30835
  function getIndexPathForCwd(resolvedCwd) {
30511
30836
  const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
30512
- return path16.join(INDEX_DIR, `.file-index-${hash}.json`);
30837
+ return path18.join(INDEX_DIR, `.file-index-${hash}.json`);
30513
30838
  }
30514
30839
 
30515
30840
  // src/files/index/write-index-file.ts
30516
30841
  function writeIndexFileSync(resolvedCwd, data) {
30517
30842
  const indexPath = getIndexPathForCwd(resolvedCwd);
30518
30843
  try {
30519
- if (!fs11.existsSync(INDEX_DIR)) fs11.mkdirSync(INDEX_DIR, { recursive: true });
30520
- fs11.writeFileSync(indexPath, JSON.stringify(data), "utf8");
30844
+ if (!fs13.existsSync(INDEX_DIR)) fs13.mkdirSync(INDEX_DIR, { recursive: true });
30845
+ fs13.writeFileSync(indexPath, JSON.stringify(data), "utf8");
30521
30846
  } catch (e) {
30522
30847
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
30523
30848
  }
@@ -30525,8 +30850,8 @@ function writeIndexFileSync(resolvedCwd, data) {
30525
30850
  async function writeIndexFileAsync(resolvedCwd, data) {
30526
30851
  const indexPath = getIndexPathForCwd(resolvedCwd);
30527
30852
  try {
30528
- await fs11.promises.mkdir(INDEX_DIR, { recursive: true });
30529
- await fs11.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
30853
+ await fs13.promises.mkdir(INDEX_DIR, { recursive: true });
30854
+ await fs13.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
30530
30855
  } catch (e) {
30531
30856
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
30532
30857
  }
@@ -30540,7 +30865,7 @@ function sortPaths(paths) {
30540
30865
  paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
30541
30866
  }
30542
30867
  function buildFileIndex(cwd) {
30543
- const resolved = path17.resolve(cwd);
30868
+ const resolved = path19.resolve(cwd);
30544
30869
  const paths = [];
30545
30870
  walkWorkspaceTreeSync(resolved, resolved, paths);
30546
30871
  sortPaths(paths);
@@ -30550,7 +30875,7 @@ function buildFileIndex(cwd) {
30550
30875
  return data;
30551
30876
  }
30552
30877
  async function buildFileIndexAsync(cwd) {
30553
- const resolved = path17.resolve(cwd);
30878
+ const resolved = path19.resolve(cwd);
30554
30879
  const paths = [];
30555
30880
  await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
30556
30881
  await yieldToEventLoop();
@@ -30562,13 +30887,13 @@ async function buildFileIndexAsync(cwd) {
30562
30887
  }
30563
30888
 
30564
30889
  // src/files/index/load-file-index.ts
30565
- import fs12 from "node:fs";
30566
- import path18 from "node:path";
30890
+ import fs14 from "node:fs";
30891
+ import path20 from "node:path";
30567
30892
  function loadFileIndex(cwd) {
30568
- const resolved = path18.resolve(cwd);
30893
+ const resolved = path20.resolve(cwd);
30569
30894
  const indexPath = getIndexPathForCwd(resolved);
30570
30895
  try {
30571
- const raw = fs12.readFileSync(indexPath, "utf8");
30896
+ const raw = fs14.readFileSync(indexPath, "utf8");
30572
30897
  const parsed = JSON.parse(raw);
30573
30898
  if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
30574
30899
  const obj = parsed;
@@ -30587,9 +30912,9 @@ function loadFileIndex(cwd) {
30587
30912
  }
30588
30913
 
30589
30914
  // src/files/index/ensure-file-index.ts
30590
- import path19 from "node:path";
30915
+ import path21 from "node:path";
30591
30916
  async function ensureFileIndexAsync(cwd) {
30592
- const resolved = path19.resolve(cwd);
30917
+ const resolved = path21.resolve(cwd);
30593
30918
  const cached2 = loadFileIndex(resolved);
30594
30919
  if (cached2 !== null) return { data: cached2, fromCache: true };
30595
30920
  const data = await buildFileIndexAsync(resolved);
@@ -30672,7 +30997,7 @@ function createFsWatcher(resolved, schedule) {
30672
30997
  }
30673
30998
  }
30674
30999
  function startFileIndexWatcher(cwd = getBridgeWorkspaceDirectory()) {
30675
- const resolved = path20.resolve(cwd);
31000
+ const resolved = path22.resolve(cwd);
30676
31001
  void buildFileIndexAsync(resolved).catch((e) => {
30677
31002
  console.error("[file-index] Initial index build failed:", e);
30678
31003
  });
@@ -30719,15 +31044,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
30719
31044
 
30720
31045
  // src/dev-servers/process/terminate-child-process.ts
30721
31046
  async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
30722
- const exited = new Promise((resolve14) => {
30723
- proc.once("exit", () => resolve14());
31047
+ const exited = new Promise((resolve15) => {
31048
+ proc.once("exit", () => resolve15());
30724
31049
  });
30725
31050
  log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
30726
31051
  try {
30727
31052
  proc.kill("SIGTERM");
30728
31053
  } catch {
30729
31054
  }
30730
- await Promise.race([exited, new Promise((resolve14) => setTimeout(resolve14, graceMs))]);
31055
+ await Promise.race([exited, new Promise((resolve15) => setTimeout(resolve15, graceMs))]);
30731
31056
  }
30732
31057
  function forceKillChild(proc, log2, shortId, graceMs) {
30733
31058
  log2(
@@ -30741,7 +31066,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
30741
31066
  }
30742
31067
 
30743
31068
  // src/dev-servers/process/wire-dev-server-child-process.ts
30744
- import fs13 from "node:fs";
31069
+ import fs15 from "node:fs";
30745
31070
 
30746
31071
  // src/dev-servers/manager/forward-pipe.ts
30747
31072
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -30777,7 +31102,7 @@ function wireDevServerChildProcess(d) {
30777
31102
  d.setPollInterval(void 0);
30778
31103
  return;
30779
31104
  }
30780
- fs13.readFile(d.mergedLogPath, (err, buf) => {
31105
+ fs15.readFile(d.mergedLogPath, (err, buf) => {
30781
31106
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
30782
31107
  if (buf.length <= d.mergedReadPos.value) return;
30783
31108
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -30815,7 +31140,7 @@ ${errTail}` : ""}`);
30815
31140
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
30816
31141
  };
30817
31142
  if (mergedPath) {
30818
- fs13.readFile(mergedPath, (err, buf) => {
31143
+ fs15.readFile(mergedPath, (err, buf) => {
30819
31144
  if (!err && buf.length > d.mergedReadPos.value) {
30820
31145
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
30821
31146
  if (chunk.length > 0) {
@@ -30917,13 +31242,13 @@ function parseDevServerDefs(servers) {
30917
31242
  }
30918
31243
 
30919
31244
  // src/dev-servers/manager/shell-spawn/utils.ts
30920
- import fs14 from "node:fs";
31245
+ import fs16 from "node:fs";
30921
31246
  function isSpawnEbadf(e) {
30922
31247
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
30923
31248
  }
30924
31249
  function rmDirQuiet(dir) {
30925
31250
  try {
30926
- fs14.rmSync(dir, { recursive: true, force: true });
31251
+ fs16.rmSync(dir, { recursive: true, force: true });
30927
31252
  } catch {
30928
31253
  }
30929
31254
  }
@@ -30931,7 +31256,7 @@ var cachedDevNullReadFd;
30931
31256
  function devNullReadFd() {
30932
31257
  if (cachedDevNullReadFd === void 0) {
30933
31258
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
30934
- cachedDevNullReadFd = fs14.openSync(devPath, "r");
31259
+ cachedDevNullReadFd = fs16.openSync(devPath, "r");
30935
31260
  }
30936
31261
  return cachedDevNullReadFd;
30937
31262
  }
@@ -31005,15 +31330,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
31005
31330
 
31006
31331
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
31007
31332
  import { spawn as spawn7 } from "node:child_process";
31008
- import fs15 from "node:fs";
31333
+ import fs17 from "node:fs";
31009
31334
  import { tmpdir } from "node:os";
31010
- import path21 from "node:path";
31335
+ import path23 from "node:path";
31011
31336
  function trySpawnMergedLogFile(command, env, cwd, signal) {
31012
- const tmpRoot = fs15.mkdtempSync(path21.join(tmpdir(), "ba-devsrv-log-"));
31013
- const logPath = path21.join(tmpRoot, "combined.log");
31337
+ const tmpRoot = fs17.mkdtempSync(path23.join(tmpdir(), "ba-devsrv-log-"));
31338
+ const logPath = path23.join(tmpRoot, "combined.log");
31014
31339
  let logFd;
31015
31340
  try {
31016
- logFd = fs15.openSync(logPath, "a");
31341
+ logFd = fs17.openSync(logPath, "a");
31017
31342
  } catch {
31018
31343
  rmDirQuiet(tmpRoot);
31019
31344
  return null;
@@ -31032,7 +31357,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
31032
31357
  } else {
31033
31358
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
31034
31359
  }
31035
- fs15.closeSync(logFd);
31360
+ fs17.closeSync(logFd);
31036
31361
  return {
31037
31362
  proc,
31038
31363
  pipedStdoutStderr: true,
@@ -31041,7 +31366,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
31041
31366
  };
31042
31367
  } catch (e) {
31043
31368
  try {
31044
- fs15.closeSync(logFd);
31369
+ fs17.closeSync(logFd);
31045
31370
  } catch {
31046
31371
  }
31047
31372
  rmDirQuiet(tmpRoot);
@@ -31052,22 +31377,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
31052
31377
 
31053
31378
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
31054
31379
  import { spawn as spawn8 } from "node:child_process";
31055
- import fs16 from "node:fs";
31380
+ import fs18 from "node:fs";
31056
31381
  import { tmpdir as tmpdir2 } from "node:os";
31057
- import path22 from "node:path";
31382
+ import path24 from "node:path";
31058
31383
  function shSingleQuote(s) {
31059
31384
  return `'${s.replace(/'/g, `'\\''`)}'`;
31060
31385
  }
31061
31386
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
31062
- const tmpRoot = fs16.mkdtempSync(path22.join(tmpdir2(), "ba-devsrv-sh-"));
31063
- const logPath = path22.join(tmpRoot, "combined.log");
31064
- const innerPath = path22.join(tmpRoot, "_cmd.sh");
31065
- const runnerPath = path22.join(tmpRoot, "_run.sh");
31387
+ const tmpRoot = fs18.mkdtempSync(path24.join(tmpdir2(), "ba-devsrv-sh-"));
31388
+ const logPath = path24.join(tmpRoot, "combined.log");
31389
+ const innerPath = path24.join(tmpRoot, "_cmd.sh");
31390
+ const runnerPath = path24.join(tmpRoot, "_run.sh");
31066
31391
  try {
31067
- fs16.writeFileSync(innerPath, `#!/bin/sh
31392
+ fs18.writeFileSync(innerPath, `#!/bin/sh
31068
31393
  ${command}
31069
31394
  `);
31070
- fs16.writeFileSync(
31395
+ fs18.writeFileSync(
31071
31396
  runnerPath,
31072
31397
  `#!/bin/sh
31073
31398
  cd ${shSingleQuote(cwd)}
@@ -31093,13 +31418,13 @@ cd ${shSingleQuote(cwd)}
31093
31418
  }
31094
31419
  }
31095
31420
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
31096
- const tmpRoot = fs16.mkdtempSync(path22.join(tmpdir2(), "ba-devsrv-sh-"));
31097
- const logPath = path22.join(tmpRoot, "combined.log");
31098
- const runnerPath = path22.join(tmpRoot, "_run.bat");
31421
+ const tmpRoot = fs18.mkdtempSync(path24.join(tmpdir2(), "ba-devsrv-sh-"));
31422
+ const logPath = path24.join(tmpRoot, "combined.log");
31423
+ const runnerPath = path24.join(tmpRoot, "_run.bat");
31099
31424
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
31100
31425
  const com = process.env.ComSpec || "cmd.exe";
31101
31426
  try {
31102
- fs16.writeFileSync(
31427
+ fs18.writeFileSync(
31103
31428
  runnerPath,
31104
31429
  `@ECHO OFF\r
31105
31430
  CD /D ${q(cwd)}\r
@@ -31781,30 +32106,30 @@ function createOnBridgeIdentified(opts) {
31781
32106
  }
31782
32107
 
31783
32108
  // src/skills/discover-local-agent-skills.ts
31784
- import fs17 from "node:fs";
31785
- import path23 from "node:path";
32109
+ import fs19 from "node:fs";
32110
+ import path25 from "node:path";
31786
32111
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
31787
32112
  function discoverLocalSkills(cwd) {
31788
32113
  const out = [];
31789
32114
  const seenKeys = /* @__PURE__ */ new Set();
31790
32115
  for (const rel of SKILL_DISCOVERY_ROOTS) {
31791
- const base = path23.join(cwd, rel);
31792
- if (!fs17.existsSync(base) || !fs17.statSync(base).isDirectory()) continue;
32116
+ const base = path25.join(cwd, rel);
32117
+ if (!fs19.existsSync(base) || !fs19.statSync(base).isDirectory()) continue;
31793
32118
  let entries = [];
31794
32119
  try {
31795
- entries = fs17.readdirSync(base);
32120
+ entries = fs19.readdirSync(base);
31796
32121
  } catch {
31797
32122
  continue;
31798
32123
  }
31799
32124
  for (const name of entries) {
31800
- const dir = path23.join(base, name);
32125
+ const dir = path25.join(base, name);
31801
32126
  try {
31802
- if (!fs17.statSync(dir).isDirectory()) continue;
32127
+ if (!fs19.statSync(dir).isDirectory()) continue;
31803
32128
  } catch {
31804
32129
  continue;
31805
32130
  }
31806
- const skillMd = path23.join(dir, "SKILL.md");
31807
- if (!fs17.existsSync(skillMd)) continue;
32131
+ const skillMd = path25.join(dir, "SKILL.md");
32132
+ if (!fs19.existsSync(skillMd)) continue;
31808
32133
  const key = `${rel}/${name}`;
31809
32134
  if (seenKeys.has(key)) continue;
31810
32135
  seenKeys.add(key);
@@ -31816,23 +32141,23 @@ function discoverLocalSkills(cwd) {
31816
32141
  function discoverSkillLayoutRoots(cwd) {
31817
32142
  const roots = [];
31818
32143
  for (const rel of SKILL_DISCOVERY_ROOTS) {
31819
- const base = path23.join(cwd, rel);
31820
- if (!fs17.existsSync(base) || !fs17.statSync(base).isDirectory()) continue;
32144
+ const base = path25.join(cwd, rel);
32145
+ if (!fs19.existsSync(base) || !fs19.statSync(base).isDirectory()) continue;
31821
32146
  let entries = [];
31822
32147
  try {
31823
- entries = fs17.readdirSync(base);
32148
+ entries = fs19.readdirSync(base);
31824
32149
  } catch {
31825
32150
  continue;
31826
32151
  }
31827
32152
  const skills2 = [];
31828
32153
  for (const name of entries) {
31829
- const dir = path23.join(base, name);
32154
+ const dir = path25.join(base, name);
31830
32155
  try {
31831
- if (!fs17.statSync(dir).isDirectory()) continue;
32156
+ if (!fs19.statSync(dir).isDirectory()) continue;
31832
32157
  } catch {
31833
32158
  continue;
31834
32159
  }
31835
- if (!fs17.existsSync(path23.join(dir, "SKILL.md"))) continue;
32160
+ if (!fs19.existsSync(path25.join(dir, "SKILL.md"))) continue;
31836
32161
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
31837
32162
  skills2.push({ name, relPath });
31838
32163
  }
@@ -31977,12 +32302,12 @@ var handleAgentConfigMessage = (msg, deps) => {
31977
32302
  };
31978
32303
 
31979
32304
  // src/agents/acp/from-bridge/handle-bridge-prompt.ts
31980
- import * as path25 from "node:path";
32305
+ import * as path27 from "node:path";
31981
32306
  import { execFile as execFile5 } from "node:child_process";
31982
32307
  import { promisify as promisify5 } from "node:util";
31983
32308
 
31984
32309
  // src/git/bridge-queue-key.ts
31985
- import * as path24 from "node:path";
32310
+ import * as path26 from "node:path";
31986
32311
  import { createHash } from "node:crypto";
31987
32312
  function normalizeCanonicalGitUrl(url2) {
31988
32313
  let s = url2.trim();
@@ -32010,11 +32335,11 @@ function canonicalUrlToRepoIdSync(url2) {
32010
32335
  return createHash("sha256").update(normalized).digest("hex").slice(0, 32);
32011
32336
  }
32012
32337
  function fallbackRepoIdFromPath(absPath) {
32013
- return createHash("sha256").update(path24.resolve(absPath)).digest("hex").slice(0, 32);
32338
+ return createHash("sha256").update(path26.resolve(absPath)).digest("hex").slice(0, 32);
32014
32339
  }
32015
32340
  async function resolveBridgeQueueBindFields(options) {
32016
32341
  const { effectiveCwd, worktreePaths, primaryRepoRoots, log: log2 } = options;
32017
- const cwdAbs = worktreePaths.length > 0 ? path24.resolve(worktreePaths[0]) : path24.resolve(effectiveCwd);
32342
+ const cwdAbs = worktreePaths.length > 0 ? path26.resolve(worktreePaths[0]) : path26.resolve(effectiveCwd);
32018
32343
  if (!primaryRepoRoots.length) {
32019
32344
  log2("[Bridge service] Prompt queue bind skipped: no Git repository roots under the working directory.");
32020
32345
  return null;
@@ -32079,7 +32404,7 @@ function handleBridgePrompt(msg, deps) {
32079
32404
  };
32080
32405
  async function preambleAndPrompt(resolvedCwd) {
32081
32406
  const s = getWs();
32082
- const effectiveCwd = path25.resolve(resolvedCwd ?? getBridgeWorkspaceDirectory());
32407
+ const effectiveCwd = path27.resolve(resolvedCwd ?? getBridgeWorkspaceDirectory());
32083
32408
  const worktreePaths = sessionWorktreeManager.getWorktreePathsForSession(sessionId) ?? [];
32084
32409
  const repoRoots = await resolveSnapshotRepoRoots({
32085
32410
  worktreePaths,
@@ -32204,15 +32529,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
32204
32529
  };
32205
32530
 
32206
32531
  // src/files/list-dir.ts
32207
- import fs18 from "node:fs";
32208
- import path27 from "node:path";
32532
+ import fs20 from "node:fs";
32533
+ import path29 from "node:path";
32209
32534
 
32210
32535
  // src/files/ensure-under-cwd.ts
32211
- import path26 from "node:path";
32536
+ import path28 from "node:path";
32212
32537
  function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
32213
- const normalized = path26.normalize(relativePath).replace(/^(\.\/)+/, "");
32214
- const resolved = path26.resolve(cwd, normalized);
32215
- if (!resolved.startsWith(cwd + path26.sep) && resolved !== cwd) {
32538
+ const normalized = path28.normalize(relativePath).replace(/^(\.\/)+/, "");
32539
+ const resolved = path28.resolve(cwd, normalized);
32540
+ if (!resolved.startsWith(cwd + path28.sep) && resolved !== cwd) {
32216
32541
  return null;
32217
32542
  }
32218
32543
  return resolved;
@@ -32226,7 +32551,7 @@ async function listDirAsync(relativePath) {
32226
32551
  return { error: "Path is outside working directory" };
32227
32552
  }
32228
32553
  try {
32229
- const names = await fs18.promises.readdir(resolved, { withFileTypes: true });
32554
+ const names = await fs20.promises.readdir(resolved, { withFileTypes: true });
32230
32555
  const visible = names.filter((d) => !d.name.startsWith("."));
32231
32556
  const entries = [];
32232
32557
  for (let i = 0; i < visible.length; i++) {
@@ -32234,12 +32559,12 @@ async function listDirAsync(relativePath) {
32234
32559
  await yieldToEventLoop();
32235
32560
  }
32236
32561
  const d = visible[i];
32237
- const entryPath = path27.join(relativePath || ".", d.name).replace(/\\/g, "/");
32238
- const fullPath = path27.join(resolved, d.name);
32562
+ const entryPath = path29.join(relativePath || ".", d.name).replace(/\\/g, "/");
32563
+ const fullPath = path29.join(resolved, d.name);
32239
32564
  let isDir = d.isDirectory();
32240
32565
  if (d.isSymbolicLink()) {
32241
32566
  try {
32242
- const targetStat = await fs18.promises.stat(fullPath);
32567
+ const targetStat = await fs20.promises.stat(fullPath);
32243
32568
  isDir = targetStat.isDirectory();
32244
32569
  } catch {
32245
32570
  isDir = false;
@@ -32264,25 +32589,25 @@ async function listDirAsync(relativePath) {
32264
32589
  }
32265
32590
 
32266
32591
  // src/files/read-file.ts
32267
- import fs19 from "node:fs";
32592
+ import fs21 from "node:fs";
32268
32593
  import { StringDecoder } from "node:string_decoder";
32269
32594
  function resolveFilePath(relativePath) {
32270
32595
  const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
32271
32596
  if (!resolved) return { error: "Path is outside working directory" };
32272
32597
  let real;
32273
32598
  try {
32274
- real = fs19.realpathSync(resolved);
32599
+ real = fs21.realpathSync(resolved);
32275
32600
  } catch {
32276
32601
  real = resolved;
32277
32602
  }
32278
- const stat2 = fs19.statSync(real);
32603
+ const stat2 = fs21.statSync(real);
32279
32604
  if (!stat2.isFile()) return { error: "Not a file" };
32280
32605
  return real;
32281
32606
  }
32282
32607
  var LINE_CHUNK_SIZE = 64 * 1024;
32283
32608
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
32284
- const fileSize = fs19.statSync(filePath).size;
32285
- const fd = fs19.openSync(filePath, "r");
32609
+ const fileSize = fs21.statSync(filePath).size;
32610
+ const fd = fs21.openSync(filePath, "r");
32286
32611
  const bufSize = 64 * 1024;
32287
32612
  const buf = Buffer.alloc(bufSize);
32288
32613
  const decoder = new StringDecoder("utf8");
@@ -32295,7 +32620,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
32295
32620
  let line0Accum = "";
32296
32621
  try {
32297
32622
  let bytesRead;
32298
- while (!done && (bytesRead = fs19.readSync(fd, buf, 0, bufSize, null)) > 0) {
32623
+ while (!done && (bytesRead = fs21.readSync(fd, buf, 0, bufSize, null)) > 0) {
32299
32624
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
32300
32625
  partial2 = "";
32301
32626
  let lineStart = 0;
@@ -32430,7 +32755,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
32430
32755
  }
32431
32756
  return { content: resultLines.join("\n"), size: fileSize };
32432
32757
  } finally {
32433
- fs19.closeSync(fd);
32758
+ fs21.closeSync(fd);
32434
32759
  }
32435
32760
  }
32436
32761
  function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
@@ -32441,8 +32766,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
32441
32766
  if (hasRange) {
32442
32767
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
32443
32768
  }
32444
- const stat2 = fs19.statSync(result);
32445
- const raw = fs19.readFileSync(result, "utf8");
32769
+ const stat2 = fs21.statSync(result);
32770
+ const raw = fs21.readFileSync(result, "utf8");
32446
32771
  const lines = raw.split(/\r?\n/);
32447
32772
  return { content: raw, totalLines: lines.length, size: stat2.size };
32448
32773
  } catch (err) {
@@ -32552,10 +32877,10 @@ function handleSkillLayoutRequest(msg, deps) {
32552
32877
  }
32553
32878
 
32554
32879
  // src/skills/install-remote-skills.ts
32555
- import fs20 from "node:fs";
32556
- import path28 from "node:path";
32880
+ import fs22 from "node:fs";
32881
+ import path30 from "node:path";
32557
32882
  function installRemoteSkills(cwd, targetDir, items) {
32558
- const installed = [];
32883
+ const installed2 = [];
32559
32884
  if (!Array.isArray(items)) {
32560
32885
  return { success: false, error: "Invalid items" };
32561
32886
  }
@@ -32564,24 +32889,24 @@ function installRemoteSkills(cwd, targetDir, items) {
32564
32889
  if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
32565
32890
  continue;
32566
32891
  }
32567
- const skillDir = path28.join(cwd, targetDir, item.skillName);
32892
+ const skillDir = path30.join(cwd, targetDir, item.skillName);
32568
32893
  for (const f of item.files) {
32569
32894
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
32570
- const dest = path28.join(skillDir, f.path);
32571
- fs20.mkdirSync(path28.dirname(dest), { recursive: true });
32895
+ const dest = path30.join(skillDir, f.path);
32896
+ fs22.mkdirSync(path30.dirname(dest), { recursive: true });
32572
32897
  if (f.text !== void 0) {
32573
- fs20.writeFileSync(dest, f.text, "utf8");
32898
+ fs22.writeFileSync(dest, f.text, "utf8");
32574
32899
  } else if (f.base64) {
32575
- fs20.writeFileSync(dest, Buffer.from(f.base64, "base64"));
32900
+ fs22.writeFileSync(dest, Buffer.from(f.base64, "base64"));
32576
32901
  }
32577
32902
  }
32578
- installed.push({
32903
+ installed2.push({
32579
32904
  sourceId: item.sourceId,
32580
32905
  skillName: item.skillName,
32581
32906
  versionHash: item.versionHash
32582
32907
  });
32583
32908
  }
32584
- return { success: true, installed };
32909
+ return { success: true, installed: installed2 };
32585
32910
  } catch (e) {
32586
32911
  return { success: false, error: e instanceof Error ? e.message : String(e) };
32587
32912
  }
@@ -32618,7 +32943,8 @@ var handleSessionGitRequestMessage = (msg, deps) => {
32618
32943
  if (typeof msg.id !== "string") return;
32619
32944
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
32620
32945
  const action = msg.action;
32621
- if (!sessionId || action !== "status" && action !== "push" && action !== "commit") return;
32946
+ if (!sessionId || action !== "status" && action !== "push" && action !== "commit" && action !== "list_changes")
32947
+ return;
32622
32948
  void (async () => {
32623
32949
  const ws = deps.getWs();
32624
32950
  const reply = (payload) => sendResult(ws, msg.id, payload);
@@ -32632,6 +32958,24 @@ var handleSessionGitRequestMessage = (msg, deps) => {
32632
32958
  });
32633
32959
  return;
32634
32960
  }
32961
+ if (action === "list_changes") {
32962
+ const repoRel = typeof msg.changesRepoRelPath === "string" ? msg.changesRepoRelPath.trim() : "";
32963
+ const view = msg.changesView === "commit" ? "commit" : "working";
32964
+ const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
32965
+ if (view === "commit") {
32966
+ if (!repoRel || !commitSha) {
32967
+ reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
32968
+ return;
32969
+ }
32970
+ }
32971
+ const opts = repoRel && view === "commit" && commitSha ? { repoRelPath: repoRel, basis: { kind: "commit", sha: commitSha } } : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" } } : void 0;
32972
+ const repos = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts);
32973
+ reply({
32974
+ ok: true,
32975
+ repos
32976
+ });
32977
+ return;
32978
+ }
32635
32979
  if (action === "push") {
32636
32980
  const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
32637
32981
  if (!pushRes.ok) {
@@ -32698,7 +33042,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
32698
33042
  };
32699
33043
 
32700
33044
  // src/bridge/routing/handlers/revert-turn-snapshot.ts
32701
- import * as fs21 from "node:fs";
33045
+ import * as fs23 from "node:fs";
32702
33046
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
32703
33047
  const id = typeof msg.id === "string" ? msg.id : "";
32704
33048
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -32710,7 +33054,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
32710
33054
  if (!s) return;
32711
33055
  const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
32712
33056
  const file2 = snapshotFilePath(agentBase, turnId);
32713
- if (!fs21.existsSync(file2)) {
33057
+ if (!fs23.existsSync(file2)) {
32714
33058
  sendWsMessage(s, {
32715
33059
  type: "revert_turn_snapshot_result",
32716
33060
  id,
@@ -33039,6 +33383,7 @@ async function createBridgeConnection(options) {
33039
33383
 
33040
33384
  // src/run-bridge.ts
33041
33385
  async function runBridge(options) {
33386
+ installBridgeProcessResilience();
33042
33387
  const { apiUrl, workspaceId, authToken, refreshToken, bridgeName, justAuthenticated, worktreesRootAbs } = options;
33043
33388
  const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
33044
33389
  const hasAuth = workspaceId && authToken;