@buildautomaton/cli 0.1.41 → 0.1.43

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
@@ -22636,342 +22636,6 @@ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
22636
22636
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
22637
22637
  import { dirname } from "node:path";
22638
22638
 
22639
- // src/files/diff/unified-diff.ts
22640
- function computeLineDiff(oldText, newText) {
22641
- const oldLines = oldText.split("\n");
22642
- const newLines = newText.split("\n");
22643
- const m = oldLines.length;
22644
- const n = newLines.length;
22645
- const dp = Array(m + 1);
22646
- for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
22647
- for (let i2 = 1; i2 <= m; i2++) {
22648
- for (let j2 = 1; j2 <= n; j2++) {
22649
- if (oldLines[i2 - 1] === newLines[j2 - 1]) {
22650
- dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
22651
- } else {
22652
- dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
22653
- }
22654
- }
22655
- }
22656
- const result = [];
22657
- let i = m;
22658
- let j = n;
22659
- while (i > 0 || j > 0) {
22660
- if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
22661
- result.unshift({ type: "context", line: oldLines[i - 1] });
22662
- i--;
22663
- j--;
22664
- } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
22665
- result.unshift({ type: "add", line: newLines[j - 1] });
22666
- j--;
22667
- } else {
22668
- result.unshift({ type: "remove", line: oldLines[i - 1] });
22669
- i--;
22670
- }
22671
- }
22672
- return result;
22673
- }
22674
- function editSnippetToUnifiedDiff(filePath, oldText, newText) {
22675
- const lines = computeLineDiff(oldText, newText);
22676
- const out = [`--- ${filePath}`, `+++ ${filePath}`];
22677
- for (const d of lines) {
22678
- if (d.type === "add") out.push(`+${d.line}`);
22679
- else if (d.type === "remove") out.push(`-${d.line}`);
22680
- else out.push(` ${d.line}`);
22681
- }
22682
- return out.join("\n");
22683
- }
22684
-
22685
- // src/agents/acp/safe-fs-path.ts
22686
- import * as path2 from "node:path";
22687
- function resolveSafePathUnderCwd(cwd, filePath) {
22688
- const trimmed2 = filePath.trim();
22689
- if (!trimmed2) return null;
22690
- const normalizedCwd = path2.resolve(cwd);
22691
- const resolved = path2.isAbsolute(trimmed2) ? path2.normalize(trimmed2) : path2.resolve(normalizedCwd, trimmed2);
22692
- const rel = path2.relative(normalizedCwd, resolved);
22693
- if (rel.startsWith("..") || path2.isAbsolute(rel)) return null;
22694
- return resolved;
22695
- }
22696
- function toDisplayPathRelativeToCwd(cwd, absolutePath) {
22697
- const normalizedCwd = path2.resolve(cwd);
22698
- const rel = path2.relative(normalizedCwd, path2.resolve(absolutePath));
22699
- if (!rel || rel === "") return path2.basename(absolutePath);
22700
- return rel.split(path2.sep).join("/");
22701
- }
22702
-
22703
- // src/agents/acp/clients/shared/acp-fs-read-write.ts
22704
- function sliceFileContentForAcp(content, line, limit) {
22705
- if (line == null && limit == null) return content;
22706
- const lines = content.split("\n");
22707
- const start = line != null && line > 0 ? line - 1 : 0;
22708
- const end = limit != null && limit > 0 ? start + limit : lines.length;
22709
- return lines.slice(start, end).join("\n");
22710
- }
22711
- function acpReadTextFileInProcess(ctx, filePath, line, limit) {
22712
- const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
22713
- if (!resolvedPath) throw new Error("Invalid or disallowed path");
22714
- try {
22715
- let content = readFileSync(resolvedPath, "utf8");
22716
- content = sliceFileContentForAcp(content, line, limit);
22717
- return { content };
22718
- } catch (e) {
22719
- if (e.code === "ENOENT") return { content: "" };
22720
- throw e;
22721
- }
22722
- }
22723
- function acpWriteTextFileInProcess(ctx, filePath, newText) {
22724
- const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
22725
- if (!resolvedPath) throw new Error("Invalid or disallowed path");
22726
- let oldText = "";
22727
- try {
22728
- oldText = readFileSync(resolvedPath, "utf8");
22729
- } catch (e) {
22730
- if (e.code !== "ENOENT") throw e;
22731
- }
22732
- mkdirSync(dirname(resolvedPath), { recursive: true });
22733
- writeFileSync(resolvedPath, newText, "utf8");
22734
- const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
22735
- const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
22736
- ctx.onFileChange?.({ path: displayPath, oldText, newText, patchContent });
22737
- return {};
22738
- }
22739
-
22740
- // src/agents/acp/clients/shared/dispatch-session-update.ts
22741
- function dispatchAcpSessionUpdate(opts) {
22742
- const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
22743
- const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
22744
- if (su === "config_option_update") {
22745
- const co = flatPayload.configOptions;
22746
- if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
22747
- return;
22748
- }
22749
- if (suppressLoadReplay()) return;
22750
- onSessionUpdate?.(flatPayload);
22751
- }
22752
-
22753
- // src/agents/acp/clients/shared/flatten-sdk-session-notification.ts
22754
- function flattenSdkSessionNotificationParams(params) {
22755
- return { sessionId: params.sessionId, ...params.update };
22756
- }
22757
-
22758
- // src/agents/acp/clients/kiro-sdk-ext-notifications.ts
22759
- function createKiroSdkExtNotificationHandler(options) {
22760
- const { onSessionUpdate } = options;
22761
- return async (method, params) => {
22762
- if (method === "_kiro.dev/metadata") {
22763
- const p = params && typeof params === "object" ? params : {};
22764
- const pct = p.contextUsagePercentage;
22765
- if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
22766
- onSessionUpdate({
22767
- sessionUpdate: "context_usage",
22768
- contextUsagePercentage: pct
22769
- });
22770
- return;
22771
- }
22772
- };
22773
- }
22774
-
22775
- // src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
22776
- var noopExtNotification = async () => {
22777
- };
22778
- function createSdkStdioExtNotificationHandler(options) {
22779
- const { backendAgentType, onSessionUpdate } = options;
22780
- switch (backendAgentType) {
22781
- case "kiro-acp":
22782
- return createKiroSdkExtNotificationHandler({ onSessionUpdate });
22783
- default:
22784
- return noopExtNotification;
22785
- }
22786
- }
22787
-
22788
- // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
22789
- function awaitSdkStdioPermissionRequestHandshake(params) {
22790
- const { requestId, paramsRecord, pending, onRequest } = params;
22791
- return new Promise((resolve20) => {
22792
- pending.set(requestId, { resolve: resolve20, params: paramsRecord });
22793
- if (onRequest == null) {
22794
- pending.delete(requestId);
22795
- resolve20({ outcome: { outcome: "denied" } });
22796
- return;
22797
- }
22798
- try {
22799
- onRequest({
22800
- requestId,
22801
- method: "session/request_permission",
22802
- params: paramsRecord
22803
- });
22804
- } catch {
22805
- }
22806
- });
22807
- }
22808
-
22809
- // src/agents/acp/clients/sdk/sdk-stdio-permission-pending.ts
22810
- function resolvePendingSdkStdioPermissionCancellations(pending) {
22811
- for (const [id, entry] of [...pending.entries()]) {
22812
- pending.delete(id);
22813
- entry.resolve({ outcome: { outcome: "cancelled" } });
22814
- }
22815
- }
22816
-
22817
- // src/agents/acp/clients/sdk/sdk-stdio-connection-client.ts
22818
- function createSdkStdioConnectionClient(deps) {
22819
- const { backendAgentType, onSessionUpdate, onRequest, sessionCtx, pendingPermissionReplies } = deps;
22820
- const extNotification = createSdkStdioExtNotificationHandler({
22821
- backendAgentType,
22822
- onSessionUpdate
22823
- });
22824
- let permissionSeq = 0;
22825
- return (_agent) => ({
22826
- async requestPermission(params) {
22827
- const requestId = `perm-${++permissionSeq}`;
22828
- const paramsRecord = params != null && typeof params === "object" ? params : {};
22829
- return await awaitSdkStdioPermissionRequestHandshake({
22830
- requestId,
22831
- paramsRecord,
22832
- pending: pendingPermissionReplies,
22833
- onRequest
22834
- });
22835
- },
22836
- async readTextFile(params) {
22837
- return acpReadTextFileInProcess(sessionCtx, params.path, params.line, params.limit);
22838
- },
22839
- async writeTextFile(params) {
22840
- return acpWriteTextFileInProcess(sessionCtx, params.path, params.content);
22841
- },
22842
- async sessionUpdate(params) {
22843
- const bridged = flattenSdkSessionNotificationParams(params);
22844
- dispatchAcpSessionUpdate({
22845
- flatPayload: bridged,
22846
- onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
22847
- onSessionUpdate,
22848
- suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
22849
- });
22850
- },
22851
- async extNotification(method, params) {
22852
- await extNotification(method, params);
22853
- }
22854
- });
22855
- }
22856
- function resolveSdkStdioPermissionRequest(pendingPermissionReplies, requestId, result) {
22857
- const entry = pendingPermissionReplies.get(requestId);
22858
- if (!entry) return;
22859
- pendingPermissionReplies.delete(requestId);
22860
- const enriched = enrichAcpPermissionRpcResultFromRequestParams(result, entry.params);
22861
- entry.resolve(enriched);
22862
- }
22863
-
22864
- // src/agents/acp/clients/sdk/create-sdk-stdio-handle.ts
22865
- function createSdkStdioHandle(options) {
22866
- let teardownStarted = false;
22867
- async function disconnectGracefully() {
22868
- if (teardownStarted) return;
22869
- teardownStarted = true;
22870
- await gracefulAcpSubprocessDisconnect({
22871
- child: options.child,
22872
- sessionId: options.sessionId,
22873
- transport: options.transport,
22874
- resolvePendingPermissionCancellations: () => resolvePendingSdkStdioPermissionCancellations(options.pendingPermissionReplies)
22875
- });
22876
- }
22877
- return {
22878
- sessionId: options.sessionId,
22879
- async sendPrompt(prompt, sendOptions) {
22880
- const imgs = sendOptions?.images?.map((im) => ({
22881
- type: "image",
22882
- mimeType: im.mimeType,
22883
- data: im.dataBase64
22884
- }));
22885
- return sendAcpPromptViaTransport(
22886
- options.transport,
22887
- options.sessionCtx,
22888
- options.sessionId,
22889
- prompt,
22890
- imgs
22891
- );
22892
- },
22893
- async cancel() {
22894
- resolvePendingSdkStdioPermissionCancellations(options.pendingPermissionReplies);
22895
- try {
22896
- await options.transport.cancelSession(options.sessionId);
22897
- } catch {
22898
- }
22899
- if (options.killSubprocessAfterCancelMs != null && options.killSubprocessAfterCancelMs >= 0) {
22900
- const t = setTimeout(() => {
22901
- if (options.child.exitCode == null && options.child.signalCode == null) {
22902
- void disconnectGracefully();
22903
- }
22904
- }, options.killSubprocessAfterCancelMs);
22905
- t.unref?.();
22906
- }
22907
- },
22908
- resolveRequest(requestId, result) {
22909
- resolveSdkStdioPermissionRequest(options.pendingPermissionReplies, requestId, result);
22910
- },
22911
- disconnectGracefully,
22912
- disconnect() {
22913
- void disconnectGracefully();
22914
- }
22915
- };
22916
- }
22917
-
22918
- // src/cli-log-level.ts
22919
- var verbosity = "info";
22920
- function setCliLogVerbosity(level) {
22921
- verbosity = level;
22922
- }
22923
- function getCliLogVerbosity() {
22924
- return verbosity;
22925
- }
22926
- function isCliTrace() {
22927
- return verbosity === "trace";
22928
- }
22929
-
22930
- // src/log.ts
22931
- function timestampPrefix() {
22932
- const time3 = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
22933
- return `[${time3}]`;
22934
- }
22935
- function log(line) {
22936
- console.log(`${timestampPrefix()} ${line}`);
22937
- }
22938
- function logImmediate(line) {
22939
- process.stdout.write(`${timestampPrefix()} ${line}
22940
- `);
22941
- }
22942
- function logDebug(line) {
22943
- const v = getCliLogVerbosity();
22944
- if (v !== "debug" && v !== "trace") return;
22945
- console.log(`${timestampPrefix()} [debug] ${line}`);
22946
- }
22947
- function logTrace(line) {
22948
- if (getCliLogVerbosity() !== "trace") return;
22949
- console.log(`${timestampPrefix()} [trace] ${line}`);
22950
- }
22951
-
22952
- // src/agents/acp/clients/sdk/create-sdk-stdio-session-context.ts
22953
- function createSdkStdioSessionContext(options) {
22954
- const suppressLoadReplayRef = { value: false };
22955
- return {
22956
- cwd: options.cwd,
22957
- onFileChange: options.onFileChange,
22958
- mcpServers: [],
22959
- persistedAcpSessionId: options.persistedAcpSessionId,
22960
- agentLabel: "ACP",
22961
- suppressLoadReplay: suppressLoadReplayRef,
22962
- backendAgentType: options.backendAgentType ?? null,
22963
- agentConfig: options.agentConfig,
22964
- getActiveConfigOptions: options.getActiveConfigOptions,
22965
- onAcpSessionEstablished: options.onAcpSessionEstablished,
22966
- onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
22967
- logDebug,
22968
- getStderrText: () => options.stderrCapture.getText()
22969
- };
22970
- }
22971
-
22972
- // src/agents/acp/clients/sdk/sdk-stdio-bootstrap-connection.ts
22973
- import { Readable, Writable } from "node:stream";
22974
-
22975
22639
  // ../types/src/work-items.ts
22976
22640
  init_zod();
22977
22641
  var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
@@ -23335,30 +22999,123 @@ function buildSessionChangeSummaryPrompt(files) {
23335
22999
  lines.push("Previous snippet:", clip(oldT, 6e3));
23336
23000
  lines.push("New snippet:", clip(newT, 6e3));
23337
23001
  } else {
23338
- lines.push("(no diff body stored for this path)");
23002
+ lines.push("(no diff body stored for this path)");
23003
+ }
23004
+ lines.push("");
23005
+ }
23006
+ return lines.join("\n");
23007
+ }
23008
+
23009
+ // ../types/src/dedupe-session-file-changes-by-path.ts
23010
+ function defaultRichness(c) {
23011
+ const patch = typeof c.patchContent === "string" ? c.patchContent.length : 0;
23012
+ const nt = typeof c.newText === "string" ? c.newText.length : 0;
23013
+ const ot = typeof c.oldText === "string" ? c.oldText.length : 0;
23014
+ const dir = c.directoryRemoved === true ? 8 : 0;
23015
+ return (patch > 0 ? 4 : 0) + (nt > 0 ? 2 : 0) + (ot > 0 ? 1 : 0) + dir;
23016
+ }
23017
+ function dedupeSessionFileChangesByPath(items, richness = (item) => defaultRichness(item)) {
23018
+ const byPath = /* @__PURE__ */ new Map();
23019
+ for (const item of items) {
23020
+ const p = typeof item.path === "string" ? item.path.trim() : "";
23021
+ if (!p) continue;
23022
+ const prev = byPath.get(p);
23023
+ if (!prev || richness(item) >= richness(prev)) byPath.set(p, item);
23024
+ }
23025
+ return Array.from(byPath.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
23026
+ }
23027
+
23028
+ // ../types/src/diff/line-diff.ts
23029
+ function normalizeDiffLineText(line) {
23030
+ return line.replace(/\r$/, "").replace(/\s*\\s*$/, "");
23031
+ }
23032
+ function normalizePatchContent(patch) {
23033
+ return patch.replace(/^\n+/, "").replace(/\n+$/, "");
23034
+ }
23035
+ function splitTextIntoDiffLines(text) {
23036
+ if (text.length === 0) return [];
23037
+ const lines = text.split("\n").map((line) => normalizeDiffLineText(line));
23038
+ if (text.endsWith("\n") && lines.at(-1) === "") {
23039
+ lines.pop();
23040
+ }
23041
+ return lines;
23042
+ }
23043
+ function createEofNewlineDiffLine(change) {
23044
+ return {
23045
+ type: change === "added" ? "add" : "remove",
23046
+ line: "",
23047
+ oldLineNo: null,
23048
+ newLineNo: null,
23049
+ eofNewlineChange: change
23050
+ };
23051
+ }
23052
+ function hasSameLogicalLines(left, right) {
23053
+ return left.length === right.length && left.every((line, index) => line === right[index]);
23054
+ }
23055
+ function detectEofNewlineChange(oldText, newText, oldLines, newLines) {
23056
+ if (!hasSameLogicalLines(oldLines, newLines) || oldLines.length === 0) return null;
23057
+ if (!oldText.endsWith("\n") && newText.endsWith("\n")) return "added";
23058
+ if (oldText.endsWith("\n") && !newText.endsWith("\n")) return "removed";
23059
+ return null;
23060
+ }
23061
+ function computeLineDiff(oldText, newText) {
23062
+ const oldLines = splitTextIntoDiffLines(oldText);
23063
+ const newLines = splitTextIntoDiffLines(newText);
23064
+ const m = oldLines.length;
23065
+ const n = newLines.length;
23066
+ const dp = Array(m + 1);
23067
+ for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
23068
+ for (let i2 = 1; i2 <= m; i2++) {
23069
+ for (let j2 = 1; j2 <= n; j2++) {
23070
+ if (oldLines[i2 - 1] === newLines[j2 - 1]) {
23071
+ dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
23072
+ } else {
23073
+ dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
23074
+ }
23075
+ }
23076
+ }
23077
+ const result = [];
23078
+ let i = m;
23079
+ let j = n;
23080
+ while (i > 0 || j > 0) {
23081
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
23082
+ result.unshift({ type: "context", line: oldLines[i - 1] });
23083
+ i--;
23084
+ j--;
23085
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
23086
+ result.unshift({ type: "add", line: newLines[j - 1] });
23087
+ j--;
23088
+ } else {
23089
+ result.unshift({ type: "remove", line: oldLines[i - 1] });
23090
+ i--;
23339
23091
  }
23340
- lines.push("");
23341
23092
  }
23342
- return lines.join("\n");
23343
- }
23344
-
23345
- // ../types/src/dedupe-session-file-changes-by-path.ts
23346
- function defaultRichness(c) {
23347
- const patch = typeof c.patchContent === "string" ? c.patchContent.length : 0;
23348
- const nt = typeof c.newText === "string" ? c.newText.length : 0;
23349
- const ot = typeof c.oldText === "string" ? c.oldText.length : 0;
23350
- const dir = c.directoryRemoved === true ? 8 : 0;
23351
- return (patch > 0 ? 4 : 0) + (nt > 0 ? 2 : 0) + (ot > 0 ? 1 : 0) + dir;
23093
+ const eofNewlineChange = detectEofNewlineChange(oldText, newText, oldLines, newLines);
23094
+ if (eofNewlineChange) result.push(createEofNewlineDiffLine(eofNewlineChange));
23095
+ return result;
23352
23096
  }
23353
- function dedupeSessionFileChangesByPath(items, richness = (item) => defaultRichness(item)) {
23354
- const byPath = /* @__PURE__ */ new Map();
23355
- for (const item of items) {
23356
- const p = typeof item.path === "string" ? item.path.trim() : "";
23357
- if (!p) continue;
23358
- const prev = byPath.get(p);
23359
- if (!prev || richness(item) >= richness(prev)) byPath.set(p, item);
23097
+ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
23098
+ const lines = computeLineDiff(oldText, newText);
23099
+ const out = [`--- ${filePath}`, `+++ ${filePath}`];
23100
+ for (const d of lines) {
23101
+ if (d.eofNewlineChange) {
23102
+ const previous = out.at(-1);
23103
+ if (previous?.startsWith(" ")) {
23104
+ const line = previous.slice(1);
23105
+ out.pop();
23106
+ if (d.eofNewlineChange === "added") {
23107
+ out.push(`-${line}`, "\", `+${line}`);
23108
+ } else {
23109
+ out.push(`-${line}`, `+${line}`, "\");
23110
+ }
23111
+ continue;
23112
+ }
23113
+ }
23114
+ if (d.type === "add") out.push(`+${d.line}`);
23115
+ else if (d.type === "remove") out.push(`-${d.line}`);
23116
+ else out.push(` ${d.line}`);
23360
23117
  }
23361
- return Array.from(byPath.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
23118
+ return out.join("\n");
23362
23119
  }
23363
23120
 
23364
23121
  // ../types/src/artifacts.ts
@@ -23427,102 +23184,392 @@ function normalizeCodexPermissionModeInput(raw) {
23427
23184
  return isCodexPermissionMode(t) ? t : null;
23428
23185
  }
23429
23186
 
23430
- // ../types/src/cli-permission-mode.ts
23431
- var CLI_PERMISSION_MODE_DEFAULT = "default";
23432
- var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
23433
- function normalizeCliPermissionModeInput(raw) {
23434
- if (typeof raw !== "string") return CLI_PERMISSION_MODE_DEFAULT;
23435
- const t = raw.trim();
23436
- if (t === CLI_PERMISSION_MODE_DANGEROUS) return CLI_PERMISSION_MODE_DANGEROUS;
23437
- if (t === "standard") return CLI_PERMISSION_MODE_DEFAULT;
23438
- return CLI_PERMISSION_MODE_DEFAULT;
23187
+ // ../types/src/cli-permission-mode.ts
23188
+ var CLI_PERMISSION_MODE_DEFAULT = "default";
23189
+ var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
23190
+ function normalizeCliPermissionModeInput(raw) {
23191
+ if (typeof raw !== "string") return CLI_PERMISSION_MODE_DEFAULT;
23192
+ const t = raw.trim();
23193
+ if (t === CLI_PERMISSION_MODE_DANGEROUS) return CLI_PERMISSION_MODE_DANGEROUS;
23194
+ if (t === "standard") return CLI_PERMISSION_MODE_DEFAULT;
23195
+ return CLI_PERMISSION_MODE_DEFAULT;
23196
+ }
23197
+
23198
+ // ../types/src/acp-permission-auto-approve.ts
23199
+ function isRejectKind(kind) {
23200
+ return kind === "reject_once" || kind === "reject_always";
23201
+ }
23202
+ function normalizeOptions(raw) {
23203
+ if (!Array.isArray(raw)) return [];
23204
+ const out = [];
23205
+ for (const item of raw) {
23206
+ if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
23207
+ const o = item;
23208
+ const rawId = o.optionId ?? o.id;
23209
+ const optionId = typeof rawId === "string" && rawId.trim() !== "" ? rawId.trim() : typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : "";
23210
+ if (!optionId) continue;
23211
+ const kind = typeof o.kind === "string" ? o.kind : void 0;
23212
+ out.push({ optionId, ...kind ? { kind } : {} });
23213
+ }
23214
+ return out;
23215
+ }
23216
+ function pickAllowOption(options) {
23217
+ const nonReject = options.filter((o) => !isRejectKind(o.kind));
23218
+ if (nonReject.length === 0) return null;
23219
+ const allowOnce = nonReject.find((o) => o.kind === "allow_once");
23220
+ if (allowOnce) return allowOnce;
23221
+ const notAlways = nonReject.filter((o) => o.kind !== "allow_always");
23222
+ if (notAlways.length > 0) return notAlways[0] ?? null;
23223
+ return nonReject.find((o) => o.kind === "allow_always") ?? nonReject[0] ?? null;
23224
+ }
23225
+ function firstNonEmptyOptionsArray(...candidates) {
23226
+ for (const c of candidates) {
23227
+ if (Array.isArray(c) && c.length > 0) return c;
23228
+ }
23229
+ const fallback = candidates[0];
23230
+ return Array.isArray(fallback) ? fallback : [];
23231
+ }
23232
+ function extractAcpPermissionRequestOptionArray(params) {
23233
+ const toolCall = params.toolCall;
23234
+ const fromToolCall = toolCall != null && typeof toolCall === "object" && !Array.isArray(toolCall) ? toolCall : null;
23235
+ return firstNonEmptyOptionsArray(
23236
+ params.options,
23237
+ params.permissionOptions,
23238
+ fromToolCall?.options,
23239
+ fromToolCall?.permissionOptions
23240
+ );
23241
+ }
23242
+ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
23243
+ const opt = pickAllowOption(normalizeOptions(extractAcpPermissionRequestOptionArray(requestParams)));
23244
+ if (!opt) return null;
23245
+ const kind = opt.kind?.trim();
23246
+ return {
23247
+ outcome: {
23248
+ outcome: "selected",
23249
+ optionId: opt.optionId,
23250
+ ...kind ? { _meta: { permissionOptionKind: kind } } : {}
23251
+ }
23252
+ };
23253
+ }
23254
+
23255
+ // ../types/src/agent-config.ts
23256
+ var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
23257
+ var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
23258
+ var AGENT_CONFIG_CODEX_PERMISSION_MODE_KEY = "codex_permission_mode";
23259
+ var AGENT_CONFIG_AGENT_MODEL_KEY = "agent_model";
23260
+ function getClaudePermissionModeFromAgentConfig(config2) {
23261
+ if (!config2) return null;
23262
+ const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
23263
+ if (typeof raw !== "string") return null;
23264
+ const t = raw.trim();
23265
+ return isClaudeCodePermissionMode(t) ? t : null;
23266
+ }
23267
+ function getCliPermissionModeFromAgentConfig(config2) {
23268
+ if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
23269
+ return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
23270
+ }
23271
+ function getCodexPermissionModeFromAgentConfig(config2) {
23272
+ if (!config2) return null;
23273
+ return normalizeCodexPermissionModeInput(config2[AGENT_CONFIG_CODEX_PERMISSION_MODE_KEY]);
23274
+ }
23275
+ function getAgentModelFromAgentConfig(config2) {
23276
+ if (!config2) return null;
23277
+ const cur = config2[AGENT_CONFIG_AGENT_MODEL_KEY];
23278
+ if (typeof cur !== "string") return null;
23279
+ const t = cur.trim();
23280
+ return t !== "" ? t : null;
23281
+ }
23282
+
23283
+ // src/agents/acp/safe-fs-path.ts
23284
+ import * as path2 from "node:path";
23285
+ function resolveSafePathUnderCwd(cwd, filePath) {
23286
+ const trimmed2 = filePath.trim();
23287
+ if (!trimmed2) return null;
23288
+ const normalizedCwd = path2.resolve(cwd);
23289
+ const resolved = path2.isAbsolute(trimmed2) ? path2.normalize(trimmed2) : path2.resolve(normalizedCwd, trimmed2);
23290
+ const rel = path2.relative(normalizedCwd, resolved);
23291
+ if (rel.startsWith("..") || path2.isAbsolute(rel)) return null;
23292
+ return resolved;
23293
+ }
23294
+ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
23295
+ const normalizedCwd = path2.resolve(cwd);
23296
+ const rel = path2.relative(normalizedCwd, path2.resolve(absolutePath));
23297
+ if (!rel || rel === "") return path2.basename(absolutePath);
23298
+ return rel.split(path2.sep).join("/");
23299
+ }
23300
+
23301
+ // src/agents/acp/clients/shared/acp-fs-read-write.ts
23302
+ function sliceFileContentForAcp(content, line, limit) {
23303
+ if (line == null && limit == null) return content;
23304
+ const lines = content.split("\n");
23305
+ const start = line != null && line > 0 ? line - 1 : 0;
23306
+ const end = limit != null && limit > 0 ? start + limit : lines.length;
23307
+ return lines.slice(start, end).join("\n");
23308
+ }
23309
+ function acpReadTextFileInProcess(ctx, filePath, line, limit) {
23310
+ const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
23311
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
23312
+ try {
23313
+ let content = readFileSync(resolvedPath, "utf8");
23314
+ content = sliceFileContentForAcp(content, line, limit);
23315
+ return { content };
23316
+ } catch (e) {
23317
+ if (e.code === "ENOENT") return { content: "" };
23318
+ throw e;
23319
+ }
23320
+ }
23321
+ function acpWriteTextFileInProcess(ctx, filePath, newText) {
23322
+ const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
23323
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
23324
+ let oldText = "";
23325
+ try {
23326
+ oldText = readFileSync(resolvedPath, "utf8");
23327
+ } catch (e) {
23328
+ if (e.code !== "ENOENT") throw e;
23329
+ }
23330
+ mkdirSync(dirname(resolvedPath), { recursive: true });
23331
+ writeFileSync(resolvedPath, newText, "utf8");
23332
+ const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
23333
+ const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
23334
+ ctx.onFileChange?.({ path: displayPath, oldText, newText, patchContent });
23335
+ return {};
23336
+ }
23337
+
23338
+ // src/agents/acp/clients/shared/dispatch-session-update.ts
23339
+ function dispatchAcpSessionUpdate(opts) {
23340
+ const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
23341
+ const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
23342
+ if (su === "config_option_update") {
23343
+ const co = flatPayload.configOptions;
23344
+ if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
23345
+ return;
23346
+ }
23347
+ if (suppressLoadReplay()) return;
23348
+ onSessionUpdate?.(flatPayload);
23349
+ }
23350
+
23351
+ // src/agents/acp/clients/shared/flatten-sdk-session-notification.ts
23352
+ function flattenSdkSessionNotificationParams(params) {
23353
+ return { sessionId: params.sessionId, ...params.update };
23354
+ }
23355
+
23356
+ // src/agents/acp/clients/kiro-sdk-ext-notifications.ts
23357
+ function createKiroSdkExtNotificationHandler(options) {
23358
+ const { onSessionUpdate } = options;
23359
+ return async (method, params) => {
23360
+ if (method === "_kiro.dev/metadata") {
23361
+ const p = params && typeof params === "object" ? params : {};
23362
+ const pct = p.contextUsagePercentage;
23363
+ if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
23364
+ onSessionUpdate({
23365
+ sessionUpdate: "context_usage",
23366
+ contextUsagePercentage: pct
23367
+ });
23368
+ return;
23369
+ }
23370
+ };
23371
+ }
23372
+
23373
+ // src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
23374
+ var noopExtNotification = async () => {
23375
+ };
23376
+ function createSdkStdioExtNotificationHandler(options) {
23377
+ const { backendAgentType, onSessionUpdate } = options;
23378
+ switch (backendAgentType) {
23379
+ case "kiro-acp":
23380
+ return createKiroSdkExtNotificationHandler({ onSessionUpdate });
23381
+ default:
23382
+ return noopExtNotification;
23383
+ }
23384
+ }
23385
+
23386
+ // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
23387
+ function awaitSdkStdioPermissionRequestHandshake(params) {
23388
+ const { requestId, paramsRecord, pending, onRequest } = params;
23389
+ return new Promise((resolve20) => {
23390
+ pending.set(requestId, { resolve: resolve20, params: paramsRecord });
23391
+ if (onRequest == null) {
23392
+ pending.delete(requestId);
23393
+ resolve20({ outcome: { outcome: "denied" } });
23394
+ return;
23395
+ }
23396
+ try {
23397
+ onRequest({
23398
+ requestId,
23399
+ method: "session/request_permission",
23400
+ params: paramsRecord
23401
+ });
23402
+ } catch {
23403
+ }
23404
+ });
23405
+ }
23406
+
23407
+ // src/agents/acp/clients/sdk/sdk-stdio-permission-pending.ts
23408
+ function resolvePendingSdkStdioPermissionCancellations(pending) {
23409
+ for (const [id, entry] of [...pending.entries()]) {
23410
+ pending.delete(id);
23411
+ entry.resolve({ outcome: { outcome: "cancelled" } });
23412
+ }
23439
23413
  }
23440
23414
 
23441
- // ../types/src/acp-permission-auto-approve.ts
23442
- function isRejectKind(kind) {
23443
- return kind === "reject_once" || kind === "reject_always";
23444
- }
23445
- function normalizeOptions(raw) {
23446
- if (!Array.isArray(raw)) return [];
23447
- const out = [];
23448
- for (const item of raw) {
23449
- if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
23450
- const o = item;
23451
- const rawId = o.optionId ?? o.id;
23452
- const optionId = typeof rawId === "string" && rawId.trim() !== "" ? rawId.trim() : typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : "";
23453
- if (!optionId) continue;
23454
- const kind = typeof o.kind === "string" ? o.kind : void 0;
23455
- out.push({ optionId, ...kind ? { kind } : {} });
23456
- }
23457
- return out;
23415
+ // src/agents/acp/clients/sdk/sdk-stdio-connection-client.ts
23416
+ function createSdkStdioConnectionClient(deps) {
23417
+ const { backendAgentType, onSessionUpdate, onRequest, sessionCtx, pendingPermissionReplies } = deps;
23418
+ const extNotification = createSdkStdioExtNotificationHandler({
23419
+ backendAgentType,
23420
+ onSessionUpdate
23421
+ });
23422
+ let permissionSeq = 0;
23423
+ return (_agent) => ({
23424
+ async requestPermission(params) {
23425
+ const requestId = `perm-${++permissionSeq}`;
23426
+ const paramsRecord = params != null && typeof params === "object" ? params : {};
23427
+ return await awaitSdkStdioPermissionRequestHandshake({
23428
+ requestId,
23429
+ paramsRecord,
23430
+ pending: pendingPermissionReplies,
23431
+ onRequest
23432
+ });
23433
+ },
23434
+ async readTextFile(params) {
23435
+ return acpReadTextFileInProcess(sessionCtx, params.path, params.line, params.limit);
23436
+ },
23437
+ async writeTextFile(params) {
23438
+ return acpWriteTextFileInProcess(sessionCtx, params.path, params.content);
23439
+ },
23440
+ async sessionUpdate(params) {
23441
+ const bridged = flattenSdkSessionNotificationParams(params);
23442
+ dispatchAcpSessionUpdate({
23443
+ flatPayload: bridged,
23444
+ onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
23445
+ onSessionUpdate,
23446
+ suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
23447
+ });
23448
+ },
23449
+ async extNotification(method, params) {
23450
+ await extNotification(method, params);
23451
+ }
23452
+ });
23458
23453
  }
23459
- function pickAllowOption(options) {
23460
- const nonReject = options.filter((o) => !isRejectKind(o.kind));
23461
- if (nonReject.length === 0) return null;
23462
- const allowOnce = nonReject.find((o) => o.kind === "allow_once");
23463
- if (allowOnce) return allowOnce;
23464
- const notAlways = nonReject.filter((o) => o.kind !== "allow_always");
23465
- if (notAlways.length > 0) return notAlways[0] ?? null;
23466
- return nonReject.find((o) => o.kind === "allow_always") ?? nonReject[0] ?? null;
23454
+ function resolveSdkStdioPermissionRequest(pendingPermissionReplies, requestId, result) {
23455
+ const entry = pendingPermissionReplies.get(requestId);
23456
+ if (!entry) return;
23457
+ pendingPermissionReplies.delete(requestId);
23458
+ const enriched = enrichAcpPermissionRpcResultFromRequestParams(result, entry.params);
23459
+ entry.resolve(enriched);
23467
23460
  }
23468
- function firstNonEmptyOptionsArray(...candidates) {
23469
- for (const c of candidates) {
23470
- if (Array.isArray(c) && c.length > 0) return c;
23461
+
23462
+ // src/agents/acp/clients/sdk/create-sdk-stdio-handle.ts
23463
+ function createSdkStdioHandle(options) {
23464
+ let teardownStarted = false;
23465
+ async function disconnectGracefully() {
23466
+ if (teardownStarted) return;
23467
+ teardownStarted = true;
23468
+ await gracefulAcpSubprocessDisconnect({
23469
+ child: options.child,
23470
+ sessionId: options.sessionId,
23471
+ transport: options.transport,
23472
+ resolvePendingPermissionCancellations: () => resolvePendingSdkStdioPermissionCancellations(options.pendingPermissionReplies)
23473
+ });
23471
23474
  }
23472
- const fallback = candidates[0];
23473
- return Array.isArray(fallback) ? fallback : [];
23474
- }
23475
- function extractAcpPermissionRequestOptionArray(params) {
23476
- const toolCall = params.toolCall;
23477
- const fromToolCall = toolCall != null && typeof toolCall === "object" && !Array.isArray(toolCall) ? toolCall : null;
23478
- return firstNonEmptyOptionsArray(
23479
- params.options,
23480
- params.permissionOptions,
23481
- fromToolCall?.options,
23482
- fromToolCall?.permissionOptions
23483
- );
23484
- }
23485
- function buildCliAutoApprovedPermissionRpcResult(requestParams) {
23486
- const opt = pickAllowOption(normalizeOptions(extractAcpPermissionRequestOptionArray(requestParams)));
23487
- if (!opt) return null;
23488
- const kind = opt.kind?.trim();
23489
23475
  return {
23490
- outcome: {
23491
- outcome: "selected",
23492
- optionId: opt.optionId,
23493
- ...kind ? { _meta: { permissionOptionKind: kind } } : {}
23476
+ sessionId: options.sessionId,
23477
+ async sendPrompt(prompt, sendOptions) {
23478
+ const imgs = sendOptions?.images?.map((im) => ({
23479
+ type: "image",
23480
+ mimeType: im.mimeType,
23481
+ data: im.dataBase64
23482
+ }));
23483
+ return sendAcpPromptViaTransport(
23484
+ options.transport,
23485
+ options.sessionCtx,
23486
+ options.sessionId,
23487
+ prompt,
23488
+ imgs
23489
+ );
23490
+ },
23491
+ async cancel() {
23492
+ resolvePendingSdkStdioPermissionCancellations(options.pendingPermissionReplies);
23493
+ try {
23494
+ await options.transport.cancelSession(options.sessionId);
23495
+ } catch {
23496
+ }
23497
+ if (options.killSubprocessAfterCancelMs != null && options.killSubprocessAfterCancelMs >= 0) {
23498
+ const t = setTimeout(() => {
23499
+ if (options.child.exitCode == null && options.child.signalCode == null) {
23500
+ void disconnectGracefully();
23501
+ }
23502
+ }, options.killSubprocessAfterCancelMs);
23503
+ t.unref?.();
23504
+ }
23505
+ },
23506
+ resolveRequest(requestId, result) {
23507
+ resolveSdkStdioPermissionRequest(options.pendingPermissionReplies, requestId, result);
23508
+ },
23509
+ disconnectGracefully,
23510
+ disconnect() {
23511
+ void disconnectGracefully();
23494
23512
  }
23495
23513
  };
23496
23514
  }
23497
23515
 
23498
- // ../types/src/agent-config.ts
23499
- var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
23500
- var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
23501
- var AGENT_CONFIG_CODEX_PERMISSION_MODE_KEY = "codex_permission_mode";
23502
- var AGENT_CONFIG_AGENT_MODEL_KEY = "agent_model";
23503
- function getClaudePermissionModeFromAgentConfig(config2) {
23504
- if (!config2) return null;
23505
- const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
23506
- if (typeof raw !== "string") return null;
23507
- const t = raw.trim();
23508
- return isClaudeCodePermissionMode(t) ? t : null;
23516
+ // src/cli-log-level.ts
23517
+ var verbosity = "info";
23518
+ function setCliLogVerbosity(level) {
23519
+ verbosity = level;
23509
23520
  }
23510
- function getCliPermissionModeFromAgentConfig(config2) {
23511
- if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
23512
- return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
23521
+ function getCliLogVerbosity() {
23522
+ return verbosity;
23513
23523
  }
23514
- function getCodexPermissionModeFromAgentConfig(config2) {
23515
- if (!config2) return null;
23516
- return normalizeCodexPermissionModeInput(config2[AGENT_CONFIG_CODEX_PERMISSION_MODE_KEY]);
23524
+ function isCliTrace() {
23525
+ return verbosity === "trace";
23517
23526
  }
23518
- function getAgentModelFromAgentConfig(config2) {
23519
- if (!config2) return null;
23520
- const cur = config2[AGENT_CONFIG_AGENT_MODEL_KEY];
23521
- if (typeof cur !== "string") return null;
23522
- const t = cur.trim();
23523
- return t !== "" ? t : null;
23527
+
23528
+ // src/log.ts
23529
+ function timestampPrefix() {
23530
+ const time3 = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
23531
+ return `[${time3}]`;
23532
+ }
23533
+ function log(line) {
23534
+ console.log(`${timestampPrefix()} ${line}`);
23535
+ }
23536
+ function logImmediate(line) {
23537
+ process.stdout.write(`${timestampPrefix()} ${line}
23538
+ `);
23539
+ }
23540
+ function logDebug(line) {
23541
+ const v = getCliLogVerbosity();
23542
+ if (v !== "debug" && v !== "trace") return;
23543
+ console.log(`${timestampPrefix()} [debug] ${line}`);
23544
+ }
23545
+ function logTrace(line) {
23546
+ if (getCliLogVerbosity() !== "trace") return;
23547
+ console.log(`${timestampPrefix()} [trace] ${line}`);
23548
+ }
23549
+
23550
+ // src/agents/acp/clients/sdk/create-sdk-stdio-session-context.ts
23551
+ function createSdkStdioSessionContext(options) {
23552
+ const suppressLoadReplayRef = { value: false };
23553
+ return {
23554
+ cwd: options.cwd,
23555
+ onFileChange: options.onFileChange,
23556
+ mcpServers: [],
23557
+ persistedAcpSessionId: options.persistedAcpSessionId,
23558
+ agentLabel: "ACP",
23559
+ suppressLoadReplay: suppressLoadReplayRef,
23560
+ backendAgentType: options.backendAgentType ?? null,
23561
+ agentConfig: options.agentConfig,
23562
+ getActiveConfigOptions: options.getActiveConfigOptions,
23563
+ onAcpSessionEstablished: options.onAcpSessionEstablished,
23564
+ onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
23565
+ logDebug,
23566
+ getStderrText: () => options.stderrCapture.getText()
23567
+ };
23524
23568
  }
23525
23569
 
23570
+ // src/agents/acp/clients/sdk/sdk-stdio-bootstrap-connection.ts
23571
+ import { Readable, Writable } from "node:stream";
23572
+
23526
23573
  // src/agents/acp/claude-acp-permission-from-session.ts
23527
23574
  function flattenSelectOptions(options) {
23528
23575
  if (options == null || options.length === 0) return [];
@@ -24421,7 +24468,7 @@ function installBridgeProcessResilience() {
24421
24468
  }
24422
24469
 
24423
24470
  // src/cli-version.ts
24424
- var CLI_VERSION = "0.1.41".length > 0 ? "0.1.41" : "0.0.0-dev";
24471
+ var CLI_VERSION = "0.1.43".length > 0 ? "0.1.43" : "0.0.0-dev";
24425
24472
 
24426
24473
  // src/connection/heartbeat/constants.ts
24427
24474
  var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
@@ -26066,18 +26113,6 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
26066
26113
  say("Shutdown complete.");
26067
26114
  }
26068
26115
 
26069
- // src/agents/acp/acp-idle-disconnect-ms.ts
26070
- var DEFAULT_ACP_IDLE_DISCONNECT_MS = 10 * 60 * 1e3;
26071
- function resolveAcpIdleDisconnectMs() {
26072
- const raw = process.env.BUILDAUTOMATON_ACP_IDLE_DISCONNECT_MS;
26073
- if (raw === "0") return 0;
26074
- if (raw != null && raw.trim() !== "") {
26075
- const parsed = Number(raw);
26076
- if (Number.isFinite(parsed) && parsed >= 0) return parsed;
26077
- }
26078
- return DEFAULT_ACP_IDLE_DISCONNECT_MS;
26079
- }
26080
-
26081
26116
  // src/agents/acp/acp-prompt-routing-registry.ts
26082
26117
  var AcpPromptRoutingRegistry = class {
26083
26118
  runs = /* @__PURE__ */ new Map();
@@ -26127,9 +26162,7 @@ function createAcpManagerContext(options) {
26127
26162
  acpAgents: /* @__PURE__ */ new Map(),
26128
26163
  promptRouting: new AcpPromptRoutingRegistry(),
26129
26164
  runDispatch: /* @__PURE__ */ new Map(),
26130
- pendingCancelRunIds: /* @__PURE__ */ new Set(),
26131
- idleDisconnectTimers: /* @__PURE__ */ new Map(),
26132
- idleDisconnectMs: options.idleDisconnectMs
26165
+ pendingCancelRunIds: /* @__PURE__ */ new Set()
26133
26166
  };
26134
26167
  }
26135
26168
 
@@ -27860,55 +27893,8 @@ async function ensureAcpClient(options) {
27860
27893
  return state.acpStartPromise;
27861
27894
  }
27862
27895
 
27863
- // src/agents/acp/manager/idle-disconnect.ts
27864
- function hasActiveWorkForAcpAgent(ctx, acpAgentKey) {
27865
- if (ctx.promptRouting.getStreamingRunId(acpAgentKey)) return true;
27866
- for (const meta of ctx.runDispatch.values()) {
27867
- if (meta.acpAgentKey === acpAgentKey) return true;
27868
- }
27869
- return false;
27870
- }
27871
- function clearIdleDisconnectTimer(ctx, acpAgentKey) {
27872
- const timer = ctx.idleDisconnectTimers.get(acpAgentKey);
27873
- if (timer == null) return;
27874
- clearTimeout(timer);
27875
- ctx.idleDisconnectTimers.delete(acpAgentKey);
27876
- }
27877
- function disconnectIdleAcpAgent(ctx, acpAgentKey) {
27878
- clearIdleDisconnectTimer(ctx, acpAgentKey);
27879
- if (hasActiveWorkForAcpAgent(ctx, acpAgentKey)) return;
27880
- const state = ctx.acpAgents.get(acpAgentKey);
27881
- if (!state?.acpHandle && !state?.acpStartPromise) {
27882
- ctx.acpAgents.delete(acpAgentKey);
27883
- return;
27884
- }
27885
- const handle = state.acpHandle;
27886
- void (async () => {
27887
- try {
27888
- await handle?.disconnectGracefully();
27889
- } catch {
27890
- }
27891
- invalidateAcpClientState(state);
27892
- ctx.acpAgents.delete(acpAgentKey);
27893
- logDebug(`[Agent] Idle disconnect (${acpAgentKey.split("::")[0] ?? acpAgentKey})`);
27894
- })();
27895
- }
27896
- function scheduleIdleDisconnect(ctx, acpAgentKey) {
27897
- if (ctx.idleDisconnectMs <= 0) return;
27898
- clearIdleDisconnectTimer(ctx, acpAgentKey);
27899
- const timer = setTimeout(() => {
27900
- ctx.idleDisconnectTimers.delete(acpAgentKey);
27901
- disconnectIdleAcpAgent(ctx, acpAgentKey);
27902
- }, ctx.idleDisconnectMs);
27903
- timer.unref?.();
27904
- ctx.idleDisconnectTimers.set(acpAgentKey, timer);
27905
- }
27906
-
27907
27896
  // src/agents/acp/manager/disconnect-all.ts
27908
27897
  async function disconnectAll(ctx) {
27909
- for (const acpAgentKey of ctx.idleDisconnectTimers.keys()) {
27910
- clearIdleDisconnectTimer(ctx, acpAgentKey);
27911
- }
27912
27898
  await Promise.all(
27913
27899
  [...ctx.acpAgents.values()].map(async (state) => {
27914
27900
  try {
@@ -33245,7 +33231,6 @@ function handlePrompt(ctx, opts) {
33245
33231
  }
33246
33232
  const activeAcpAgentKey = acpAgentKey;
33247
33233
  ctx.pendingCancelRunIds.delete(activeRunId);
33248
- clearIdleDisconnectTimer(ctx, activeAcpAgentKey);
33249
33234
  ctx.promptRouting.registerRun({ sessionId, runId: activeRunId });
33250
33235
  ctx.runDispatch.set(activeRunId, { acpAgentKey: activeAcpAgentKey });
33251
33236
  async function run() {
@@ -33328,7 +33313,6 @@ function handlePrompt(ctx, opts) {
33328
33313
  ctx.promptRouting.unregisterRun(activeRunId);
33329
33314
  ctx.runDispatch.delete(activeRunId);
33330
33315
  ctx.pendingCancelRunIds.delete(activeRunId);
33331
- scheduleIdleDisconnect(ctx, activeAcpAgentKey);
33332
33316
  });
33333
33317
  }
33334
33318
 
@@ -33346,8 +33330,7 @@ function logPromptReceivedFromBridge(ctx, opts) {
33346
33330
  async function createAcpManager(options) {
33347
33331
  const ctx = createAcpManagerContext({
33348
33332
  log: options.log,
33349
- reportAgentCapabilities: options.reportAgentCapabilities,
33350
- idleDisconnectMs: resolveAcpIdleDisconnectMs()
33333
+ reportAgentCapabilities: options.reportAgentCapabilities
33351
33334
  });
33352
33335
  return {
33353
33336
  setPreferredAgentType(agentType) {
@@ -33854,12 +33837,16 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
33854
33837
  }
33855
33838
 
33856
33839
  // src/git/changes/unified-diff-for-file.ts
33840
+ function patchTextFromGitDiffOutput(raw) {
33841
+ if (raw.trim() === "") return void 0;
33842
+ return normalizePatchContent(raw);
33843
+ }
33857
33844
  async function unifiedDiffForFile(repoCwd, pathInRepo, change) {
33858
33845
  const g = cliSimpleGit(repoCwd);
33859
33846
  const args = change === "added" ? ["diff", "--no-color", "HEAD", "--", pathInRepo] : change === "removed" ? ["diff", "--no-color", "HEAD", "--", pathInRepo] : ["diff", "--no-color", "HEAD", "--", pathInRepo];
33860
33847
  const raw = await g.raw([...args]).catch(() => "");
33861
- const t = String(raw).trim();
33862
- return t ? truncatePatch(t) : void 0;
33848
+ const patch = patchTextFromGitDiffOutput(String(raw));
33849
+ return patch ? truncatePatch(patch) : void 0;
33863
33850
  }
33864
33851
 
33865
33852
  // src/git/changes/list-changed-files-for-repo.ts