@adhdev/daemon-core 0.8.29 → 0.8.31

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.
Files changed (63) hide show
  1. package/dist/agent-stream/manager.d.ts +1 -0
  2. package/dist/agent-stream/provider-adapter.d.ts +1 -0
  3. package/dist/agent-stream/types.d.ts +3 -0
  4. package/dist/boot/daemon-lifecycle.d.ts +2 -1
  5. package/dist/cdp/manager.d.ts +2 -0
  6. package/dist/cli-adapter-types.d.ts +34 -5
  7. package/dist/cli-adapters/provider-cli-adapter.d.ts +4 -158
  8. package/dist/cli-adapters/provider-cli-config.d.ts +30 -0
  9. package/dist/cli-adapters/provider-cli-parse.d.ts +42 -0
  10. package/dist/cli-adapters/provider-cli-runtime.d.ts +29 -0
  11. package/dist/cli-adapters/provider-cli-shared.d.ts +158 -0
  12. package/dist/commands/handler.d.ts +4 -3
  13. package/dist/config/config.d.ts +4 -3
  14. package/dist/index.js +1033 -621
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +1035 -624
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/providers/acp-provider-instance.d.ts +1 -0
  19. package/dist/providers/approval-utils.d.ts +7 -0
  20. package/dist/providers/cli-provider-instance.d.ts +2 -0
  21. package/dist/providers/contracts.d.ts +12 -1
  22. package/dist/providers/ide-provider-instance.d.ts +1 -0
  23. package/dist/providers/provider-loader.d.ts +3 -0
  24. package/dist/status/reporter.d.ts +2 -3
  25. package/dist/status/snapshot.d.ts +2 -1
  26. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  27. package/package.json +3 -1
  28. package/src/agent-stream/manager.ts +8 -2
  29. package/src/agent-stream/poller.ts +57 -6
  30. package/src/agent-stream/provider-adapter.ts +11 -7
  31. package/src/agent-stream/types.ts +3 -0
  32. package/src/boot/daemon-lifecycle.ts +7 -6
  33. package/src/cdp/initializer.ts +2 -2
  34. package/src/cdp/manager.ts +5 -0
  35. package/src/cdp/setup.ts +1 -1
  36. package/src/cli-adapter-types.ts +37 -5
  37. package/src/cli-adapters/provider-cli-adapter.ts +212 -795
  38. package/src/cli-adapters/provider-cli-config.ts +66 -0
  39. package/src/cli-adapters/provider-cli-parse.ts +202 -0
  40. package/src/cli-adapters/provider-cli-runtime.ts +142 -0
  41. package/src/cli-adapters/provider-cli-shared.ts +439 -0
  42. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +1 -1
  43. package/src/commands/cdp-commands.ts +6 -1
  44. package/src/commands/chat-commands.ts +45 -29
  45. package/src/commands/cli-manager.ts +28 -9
  46. package/src/commands/handler.ts +14 -10
  47. package/src/commands/router.ts +23 -10
  48. package/src/commands/stream-commands.ts +11 -5
  49. package/src/config/config.ts +4 -10
  50. package/src/daemon/dev-auto-implement.ts +22 -18
  51. package/src/daemon/dev-cli-debug.ts +59 -16
  52. package/src/daemon/dev-server.ts +67 -43
  53. package/src/providers/acp-provider-instance.ts +18 -3
  54. package/src/providers/approval-utils.ts +66 -0
  55. package/src/providers/cli-provider-instance.ts +32 -6
  56. package/src/providers/contracts.d.ts +1 -0
  57. package/src/providers/contracts.ts +15 -2
  58. package/src/providers/extension-provider-instance.ts +1 -1
  59. package/src/providers/ide-provider-instance.ts +67 -41
  60. package/src/providers/provider-loader.ts +110 -55
  61. package/src/providers/version-archive.ts +23 -5
  62. package/src/status/reporter.ts +18 -14
  63. package/src/status/snapshot.ts +5 -4
package/dist/index.mjs CHANGED
@@ -93,12 +93,10 @@ function ensureMachineId(config) {
93
93
  if (isStableMachineId(config.machineId)) {
94
94
  return { config, changed: false };
95
95
  }
96
- const legacyRegisteredMachineId = !config.registeredMachineId && config.machineSecret && config.machineId ? config.machineId : config.registeredMachineId;
97
96
  return {
98
97
  config: {
99
98
  ...config,
100
- machineId: generateMachineId(),
101
- registeredMachineId: legacyRegisteredMachineId
99
+ machineId: generateMachineId()
102
100
  },
103
101
  changed: true
104
102
  };
@@ -450,7 +448,7 @@ var init_logger = __esm({
450
448
  function isModuleNotFoundError(error, ref) {
451
449
  if (!(error instanceof Error)) return false;
452
450
  const message = error.message || "";
453
- const code = error.code;
451
+ const code = "code" in error ? error.code : void 0;
454
452
  return code === "MODULE_NOT_FOUND" && message.includes(ref);
455
453
  }
456
454
  function normalizeBinding(mod, ref) {
@@ -795,12 +793,7 @@ var init_pty_transport = __esm({
795
793
  }
796
794
  });
797
795
 
798
- // src/cli-adapters/provider-cli-adapter.ts
799
- var provider_cli_adapter_exports = {};
800
- __export(provider_cli_adapter_exports, {
801
- ProviderCliAdapter: () => ProviderCliAdapter,
802
- normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
803
- });
796
+ // src/cli-adapters/provider-cli-shared.ts
804
797
  import * as os8 from "os";
805
798
  import * as path9 from "path";
806
799
  import { execSync as execSync3 } from "child_process";
@@ -813,6 +806,10 @@ function stripTerminalNoise(str) {
813
806
  function sanitizeTerminalText(str) {
814
807
  return stripTerminalNoise(stripAnsi(str));
815
808
  }
809
+ function listCliScriptNames(scripts) {
810
+ if (!scripts) return [];
811
+ return Object.entries(scripts).filter(([, fn]) => typeof fn === "function").map(([name]) => name);
812
+ }
816
813
  function splitCliScreenLines(text) {
817
814
  return String(text || "").replace(/\u0007/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.replace(/\s+$/, ""));
818
815
  }
@@ -860,18 +857,6 @@ function buildCliScreenSnapshot(text) {
860
857
  linesBelowPrompt: promptLineIndex >= 0 ? lines.slice(promptLineIndex + 1) : []
861
858
  };
862
859
  }
863
- function computeTerminalQueryTail(buffer) {
864
- const prefixes = ["\x1B[6n", "\x1B[?6n"];
865
- const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
866
- const start = Math.max(0, buffer.length - maxLength);
867
- for (let i = start; i < buffer.length; i++) {
868
- const suffix = buffer.slice(i);
869
- if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
870
- return suffix;
871
- }
872
- }
873
- return "";
874
- }
875
860
  function findBinary(name) {
876
861
  const trimmed = String(name || "").trim();
877
862
  if (!trimmed) return trimmed;
@@ -1021,22 +1006,302 @@ function coercePatternArray(raw) {
1021
1006
  return raw.map(parsePatternEntry).filter((r) => r != null);
1022
1007
  }
1023
1008
  function normalizeCliProviderForRuntime(raw) {
1024
- const patterns = raw?.patterns || {};
1009
+ const patterns = raw && typeof raw === "object" ? raw.patterns : void 0;
1025
1010
  return {
1026
1011
  patterns: {
1027
- approval: coercePatternArray(patterns.approval)
1012
+ approval: coercePatternArray(
1013
+ patterns && typeof patterns === "object" ? patterns.approval : void 0
1014
+ )
1015
+ }
1016
+ };
1017
+ }
1018
+ var buildCliSpawnEnv;
1019
+ var init_provider_cli_shared = __esm({
1020
+ "src/cli-adapters/provider-cli-shared.ts"() {
1021
+ "use strict";
1022
+ init_spawn_env();
1023
+ buildCliSpawnEnv = sanitizeSpawnEnv;
1024
+ }
1025
+ });
1026
+
1027
+ // src/cli-adapters/provider-cli-parse.ts
1028
+ function sliceFromOffset(text, start) {
1029
+ if (!text) return "";
1030
+ if (!Number.isFinite(start) || start <= 0) return text;
1031
+ if (start >= text.length) return "";
1032
+ return text.slice(start);
1033
+ }
1034
+ function hydrateCliParsedMessages(parsedMessages, options) {
1035
+ const { committedMessages, scope, lastOutputAt } = options;
1036
+ const referenceMessages = [...committedMessages];
1037
+ const usedReferenceIndexes = /* @__PURE__ */ new Set();
1038
+ const now = options.now ?? Date.now();
1039
+ const findReferenceTimestamp = (role, content, parsedIndex) => {
1040
+ const normalizedContent = normalizeComparableMessageContent(content);
1041
+ if (!normalizedContent) return void 0;
1042
+ const sameIndex = referenceMessages[parsedIndex];
1043
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1044
+ usedReferenceIndexes.add(parsedIndex);
1045
+ return sameIndex.timestamp;
1046
+ }
1047
+ for (let i = 0; i < referenceMessages.length; i++) {
1048
+ if (usedReferenceIndexes.has(i)) continue;
1049
+ const candidate = referenceMessages[i];
1050
+ if (!candidate || candidate.role !== role) continue;
1051
+ const candidateContent = normalizeComparableMessageContent(candidate.content);
1052
+ if (!candidateContent) continue;
1053
+ const exactMatch = candidateContent === normalizedContent;
1054
+ const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1055
+ if (!exactMatch && !fuzzyMatch) continue;
1056
+ if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1057
+ usedReferenceIndexes.add(i);
1058
+ return candidate.timestamp;
1059
+ }
1028
1060
  }
1061
+ return void 0;
1029
1062
  };
1063
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1064
+ const role = message.role;
1065
+ const content = typeof message.content === "string" ? message.content : String(message.content || "");
1066
+ const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1067
+ const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1068
+ const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
1069
+ const timestamp = referenceTimestamp ?? fallbackTimestamp;
1070
+ return {
1071
+ ...message,
1072
+ role,
1073
+ content,
1074
+ timestamp,
1075
+ receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1076
+ };
1077
+ });
1078
+ }
1079
+ function normalizeCliParsedMessages(parsedMessages, options) {
1080
+ return hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
1081
+ role: message.role,
1082
+ content: message.content,
1083
+ timestamp: message.timestamp,
1084
+ receivedAt: message.receivedAt,
1085
+ kind: message.kind,
1086
+ id: message.id,
1087
+ index: message.index,
1088
+ meta: message.meta,
1089
+ senderName: message.senderName
1090
+ }));
1091
+ }
1092
+ function buildCliParseInput(options) {
1093
+ const {
1094
+ accumulatedBuffer,
1095
+ accumulatedRawBuffer,
1096
+ recentOutputBuffer,
1097
+ terminalScreenText,
1098
+ baseMessages,
1099
+ partialResponse,
1100
+ scope,
1101
+ runtimeSettings
1102
+ } = options;
1103
+ const buffer = scope ? sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer : accumulatedBuffer;
1104
+ const rawBuffer = scope ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer : accumulatedRawBuffer;
1105
+ const screenText = terminalScreenText;
1106
+ const recentBuffer = buffer.slice(-1e3) || recentOutputBuffer;
1107
+ return {
1108
+ buffer,
1109
+ rawBuffer,
1110
+ recentBuffer,
1111
+ screenText,
1112
+ screen: buildCliScreenSnapshot(screenText),
1113
+ bufferScreen: buildCliScreenSnapshot(buffer),
1114
+ recentScreen: buildCliScreenSnapshot(recentBuffer),
1115
+ messages: [...baseMessages],
1116
+ partialResponse,
1117
+ promptText: scope?.prompt || "",
1118
+ settings: { ...runtimeSettings }
1119
+ };
1120
+ }
1121
+ function summarizeCliTraceText(text, max = 800) {
1122
+ const value = sanitizeTerminalText(String(text || ""));
1123
+ if (value.length <= max) return value;
1124
+ return `\u2026${value.slice(-max)}`;
1125
+ }
1126
+ function summarizeCliTraceMessages(messages, limit = 3) {
1127
+ return messages.slice(-limit).map((message) => ({
1128
+ role: message.role,
1129
+ content: summarizeCliTraceText(message.content, 240),
1130
+ timestamp: message.timestamp
1131
+ }));
1132
+ }
1133
+ function buildCliTraceParseSnapshot(options) {
1134
+ const { accumulatedBuffer, accumulatedRawBuffer, responseBuffer, partialResponse, scope } = options;
1135
+ const scopedBuffer = scope ? sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer : accumulatedBuffer;
1136
+ const scopedRawBuffer = scope ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer : accumulatedRawBuffer;
1137
+ return {
1138
+ currentTurnScope: scope || null,
1139
+ responseBuffer: summarizeCliTraceText(responseBuffer, 1200),
1140
+ partialResponse: summarizeCliTraceText(partialResponse || responseBuffer, 1200),
1141
+ turnBuffer: summarizeCliTraceText(scopedBuffer, 1600),
1142
+ turnRawPreview: summarizeCliTraceText(scopedRawBuffer, 1600),
1143
+ turnSanitizedRawPreview: summarizeCliTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
1144
+ };
1145
+ }
1146
+ var init_provider_cli_parse = __esm({
1147
+ "src/cli-adapters/provider-cli-parse.ts"() {
1148
+ "use strict";
1149
+ init_provider_cli_shared();
1150
+ }
1151
+ });
1152
+
1153
+ // src/cli-adapters/provider-cli-config.ts
1154
+ function resolveCliAdapterConfig(provider) {
1155
+ const t = provider.timeouts || {};
1156
+ const rawKeys = provider.approvalKeys;
1157
+ return {
1158
+ timeouts: {
1159
+ ptyFlush: t.ptyFlush ?? 50,
1160
+ dialogAccept: t.dialogAccept ?? 300,
1161
+ approvalCooldown: t.approvalCooldown ?? 3e3,
1162
+ generatingIdle: t.generatingIdle ?? 6e3,
1163
+ idleFinish: t.idleFinish ?? 5e3,
1164
+ maxResponse: t.maxResponse ?? 3e5,
1165
+ shutdownGrace: t.shutdownGrace ?? 1e3,
1166
+ outputSettle: t.outputSettle ?? 300
1167
+ },
1168
+ approvalKeys: rawKeys && typeof rawKeys === "object" ? rawKeys : {},
1169
+ sendDelayMs: typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0,
1170
+ sendKey: typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r",
1171
+ submitStrategy: provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo",
1172
+ providerResolutionMeta: {
1173
+ type: provider.type,
1174
+ name: provider.name,
1175
+ resolvedVersion: provider._resolvedVersion || null,
1176
+ resolvedOs: provider._resolvedOs || null,
1177
+ providerDir: provider._resolvedProviderDir || null,
1178
+ scriptDir: provider._resolvedScriptDir || null,
1179
+ scriptsPath: provider._resolvedScriptsPath || null,
1180
+ scriptsSource: provider._resolvedScriptsSource || null,
1181
+ versionWarning: provider._versionWarning || null
1182
+ }
1183
+ };
1184
+ }
1185
+ var init_provider_cli_config = __esm({
1186
+ "src/cli-adapters/provider-cli-config.ts"() {
1187
+ "use strict";
1188
+ }
1189
+ });
1190
+
1191
+ // src/cli-adapters/provider-cli-runtime.ts
1192
+ import * as os9 from "os";
1193
+ import * as path10 from "path";
1194
+ function resolveCliSpawnPlan(options) {
1195
+ const { provider, runtimeSettings, workingDir, extraArgs } = options;
1196
+ const { spawn: spawnConfig } = provider;
1197
+ const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
1198
+ const binaryPath = findBinary(configuredCommand);
1199
+ const isWin = os9.platform() === "win32";
1200
+ const allArgs = [...spawnConfig.args, ...extraArgs];
1201
+ let shellCmd;
1202
+ let shellArgs;
1203
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path10.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1204
+ const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1205
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path10.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1206
+ const useShell = isWin ? useShellWin : useShellUnix;
1207
+ if (useShell) {
1208
+ shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
1209
+ if (isWin) {
1210
+ shellArgs = ["/c", binaryPath, ...allArgs];
1211
+ } else {
1212
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1213
+ shellArgs = ["-l", "-c", fullCmd];
1214
+ }
1215
+ } else {
1216
+ shellCmd = binaryPath;
1217
+ shellArgs = allArgs;
1218
+ }
1219
+ return {
1220
+ binaryPath,
1221
+ allArgs,
1222
+ shellCmd,
1223
+ shellArgs,
1224
+ isWin,
1225
+ useShell,
1226
+ ptyOptions: {
1227
+ cols: 80,
1228
+ rows: 24,
1229
+ cwd: workingDir,
1230
+ env: buildCliSpawnEnv(process.env, spawnConfig.env)
1231
+ }
1232
+ };
1233
+ }
1234
+ function buildCliLoginShellRetry(plan) {
1235
+ const shellCmd = process.env.SHELL || "/bin/zsh";
1236
+ const fullCmd = [plan.binaryPath, ...plan.allArgs].map(shSingleQuote).join(" ");
1237
+ return {
1238
+ shellCmd,
1239
+ shellArgs: ["-l", "-c", fullCmd]
1240
+ };
1241
+ }
1242
+ function getCliSpawnErrorHint(message, shellCmd, isWin) {
1243
+ if (!isWin) return null;
1244
+ if (/error code 267|ERROR_DIRECTORY/i.test(message)) {
1245
+ return " (working directory does not exist or is not a directory)";
1246
+ }
1247
+ if (/error code 740|elevation/i.test(message)) {
1248
+ return " (requires administrator privileges)";
1249
+ }
1250
+ if (/error code 2|ENOENT|not found/i.test(message)) {
1251
+ return ` (executable not found: ${shellCmd})`;
1252
+ }
1253
+ return null;
1254
+ }
1255
+ function respondToCliTerminalQueries(options) {
1256
+ const { ptyProcess, pendingTail, data, terminalScreen } = options;
1257
+ if (!ptyProcess || !data) return pendingTail;
1258
+ const combined = pendingTail + data;
1259
+ const regex = /\x1b\[(\?)?6n/g;
1260
+ let match;
1261
+ while ((match = regex.exec(combined)) !== null) {
1262
+ const cursor = terminalScreen.getCursorPosition();
1263
+ const row = Math.max(1, (cursor.row | 0) + 1);
1264
+ const col = Math.max(1, (cursor.col | 0) + 1);
1265
+ const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
1266
+ ptyProcess.write(response);
1267
+ }
1268
+ const prefixes = ["\x1B[6n", "\x1B[?6n"];
1269
+ const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
1270
+ const start = Math.max(0, combined.length - maxLength);
1271
+ for (let i = start; i < combined.length; i++) {
1272
+ const suffix = combined.slice(i);
1273
+ if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
1274
+ return suffix;
1275
+ }
1276
+ }
1277
+ return "";
1030
1278
  }
1031
- var buildCliSpawnEnv, ProviderCliAdapter;
1279
+ var init_provider_cli_runtime = __esm({
1280
+ "src/cli-adapters/provider-cli-runtime.ts"() {
1281
+ "use strict";
1282
+ init_provider_cli_shared();
1283
+ }
1284
+ });
1285
+
1286
+ // src/cli-adapters/provider-cli-adapter.ts
1287
+ var provider_cli_adapter_exports = {};
1288
+ __export(provider_cli_adapter_exports, {
1289
+ ProviderCliAdapter: () => ProviderCliAdapter,
1290
+ normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
1291
+ });
1292
+ import * as os10 from "os";
1293
+ var ProviderCliAdapter;
1032
1294
  var init_provider_cli_adapter = __esm({
1033
1295
  "src/cli-adapters/provider-cli-adapter.ts"() {
1034
1296
  "use strict";
1035
1297
  init_logger();
1036
1298
  init_terminal_screen();
1037
1299
  init_pty_transport();
1038
- init_spawn_env();
1039
- buildCliSpawnEnv = sanitizeSpawnEnv;
1300
+ init_provider_cli_shared();
1301
+ init_provider_cli_parse();
1302
+ init_provider_cli_config();
1303
+ init_provider_cli_runtime();
1304
+ init_provider_cli_shared();
1040
1305
  ProviderCliAdapter = class _ProviderCliAdapter {
1041
1306
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
1042
1307
  this.extraArgs = extraArgs;
@@ -1044,36 +1309,16 @@ var init_provider_cli_adapter = __esm({
1044
1309
  this.transportFactory = transportFactory;
1045
1310
  this.cliType = provider.type;
1046
1311
  this.cliName = provider.name;
1047
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os8.homedir()) : workingDir;
1048
- const t = provider.timeouts || {};
1049
- this.timeouts = {
1050
- ptyFlush: t.ptyFlush ?? 50,
1051
- dialogAccept: t.dialogAccept ?? 300,
1052
- approvalCooldown: t.approvalCooldown ?? 3e3,
1053
- generatingIdle: t.generatingIdle ?? 6e3,
1054
- idleFinish: t.idleFinish ?? 5e3,
1055
- maxResponse: t.maxResponse ?? 3e5,
1056
- shutdownGrace: t.shutdownGrace ?? 1e3,
1057
- outputSettle: t.outputSettle ?? 300
1058
- };
1059
- const rawKeys = provider.approvalKeys;
1060
- this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
1061
- this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
1062
- this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
1063
- this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
1064
- this.providerResolutionMeta = {
1065
- type: provider.type,
1066
- name: provider.name,
1067
- resolvedVersion: provider._resolvedVersion || null,
1068
- resolvedOs: provider._resolvedOs || null,
1069
- providerDir: provider._resolvedProviderDir || null,
1070
- scriptDir: provider._resolvedScriptDir || null,
1071
- scriptsPath: provider._resolvedScriptsPath || null,
1072
- scriptsSource: provider._resolvedScriptsSource || null,
1073
- versionWarning: provider._versionWarning || null
1074
- };
1312
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os10.homedir()) : workingDir;
1313
+ const resolvedConfig = resolveCliAdapterConfig(provider);
1314
+ this.timeouts = resolvedConfig.timeouts;
1315
+ this.approvalKeys = resolvedConfig.approvalKeys;
1316
+ this.sendDelayMs = resolvedConfig.sendDelayMs;
1317
+ this.sendKey = resolvedConfig.sendKey;
1318
+ this.submitStrategy = resolvedConfig.submitStrategy;
1319
+ this.providerResolutionMeta = resolvedConfig.providerResolutionMeta;
1075
1320
  this.cliScripts = provider.scripts || {};
1076
- const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
1321
+ const scriptNames = listCliScriptNames(this.cliScripts);
1077
1322
  if (scriptNames.length > 0) {
1078
1323
  LOG.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
1079
1324
  LOG.info(
@@ -1170,88 +1415,6 @@ var init_provider_cli_adapter = __esm({
1170
1415
  this.messages = [...this.committedMessages];
1171
1416
  this.structuredMessages = [...this.committedMessages];
1172
1417
  }
1173
- hydrateParsedMessages(parsedMessages, scope) {
1174
- const referenceMessages = [...this.committedMessages];
1175
- const usedReferenceIndexes = /* @__PURE__ */ new Set();
1176
- const now = Date.now();
1177
- const findReferenceTimestamp = (role, content, parsedIndex) => {
1178
- const normalizedContent = normalizeComparableMessageContent(content);
1179
- if (!normalizedContent) return void 0;
1180
- const sameIndex = referenceMessages[parsedIndex];
1181
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1182
- usedReferenceIndexes.add(parsedIndex);
1183
- return sameIndex.timestamp;
1184
- }
1185
- for (let i = 0; i < referenceMessages.length; i++) {
1186
- if (usedReferenceIndexes.has(i)) continue;
1187
- const candidate = referenceMessages[i];
1188
- if (!candidate || candidate.role !== role) continue;
1189
- const candidateContent = normalizeComparableMessageContent(candidate.content);
1190
- if (!candidateContent) continue;
1191
- const exactMatch = candidateContent === normalizedContent;
1192
- const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1193
- if (!exactMatch && !fuzzyMatch) continue;
1194
- if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1195
- usedReferenceIndexes.add(i);
1196
- return candidate.timestamp;
1197
- }
1198
- }
1199
- return void 0;
1200
- };
1201
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1202
- const role = message.role;
1203
- const content = typeof message.content === "string" ? message.content : String(message.content || "");
1204
- const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1205
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1206
- const fallbackTimestamp = role === "user" ? scope?.startedAt || now : this.lastOutputAt || scope?.startedAt || now;
1207
- const timestamp = referenceTimestamp ?? fallbackTimestamp;
1208
- return {
1209
- ...message,
1210
- role,
1211
- content,
1212
- timestamp,
1213
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1214
- };
1215
- });
1216
- }
1217
- normalizeParsedMessages(parsedMessages, scope) {
1218
- return this.hydrateParsedMessages(parsedMessages, scope).map((message) => ({
1219
- role: message.role,
1220
- content: message.content,
1221
- timestamp: message.timestamp,
1222
- receivedAt: message.receivedAt,
1223
- kind: message.kind,
1224
- id: message.id,
1225
- index: message.index,
1226
- meta: message.meta,
1227
- senderName: message.senderName
1228
- }));
1229
- }
1230
- sliceFromOffset(text, start) {
1231
- if (!text) return "";
1232
- if (!Number.isFinite(start) || start <= 0) return text;
1233
- if (start >= text.length) return "";
1234
- return text.slice(start);
1235
- }
1236
- buildParseInput(baseMessages, partialResponse, scope) {
1237
- const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1238
- const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
1239
- const screenText = this.terminalScreen.getText();
1240
- const recentBuffer = buffer.slice(-1e3) || this.recentOutputBuffer;
1241
- return {
1242
- buffer,
1243
- rawBuffer,
1244
- recentBuffer,
1245
- screenText,
1246
- screen: buildCliScreenSnapshot(screenText),
1247
- bufferScreen: buildCliScreenSnapshot(buffer),
1248
- recentScreen: buildCliScreenSnapshot(recentBuffer),
1249
- messages: [...baseMessages],
1250
- partialResponse,
1251
- promptText: scope?.prompt || "",
1252
- settings: { ...this.runtimeSettings }
1253
- };
1254
- }
1255
1418
  setStatus(status, trigger) {
1256
1419
  const prev = this.currentStatus;
1257
1420
  if (prev === status) return;
@@ -1284,7 +1447,13 @@ var init_provider_cli_adapter = __esm({
1284
1447
  this.recordTrace("idle_candidate_armed", {
1285
1448
  confirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
1286
1449
  candidate: this.idleFinishCandidate,
1287
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
1450
+ ...buildCliTraceParseSnapshot({
1451
+ accumulatedBuffer: this.accumulatedBuffer,
1452
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
1453
+ responseBuffer: this.responseBuffer,
1454
+ partialResponse: this.responseBuffer,
1455
+ scope: this.currentTurnScope
1456
+ })
1288
1457
  });
1289
1458
  if (this.settleTimer) clearTimeout(this.settleTimer);
1290
1459
  this.settleTimer = setTimeout(() => {
@@ -1293,30 +1462,6 @@ var init_provider_cli_adapter = __esm({
1293
1462
  this.evaluateSettled();
1294
1463
  }, _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS);
1295
1464
  }
1296
- summarizeTraceText(text, max = 800) {
1297
- const value = sanitizeTerminalText(String(text || ""));
1298
- if (value.length <= max) return value;
1299
- return `\u2026${value.slice(-max)}`;
1300
- }
1301
- summarizeTraceMessages(messages, limit = 3) {
1302
- return messages.slice(-limit).map((message) => ({
1303
- role: message.role,
1304
- content: this.summarizeTraceText(message.content, 240),
1305
- timestamp: message.timestamp
1306
- }));
1307
- }
1308
- buildTraceParseSnapshot(scope, partialResponse = "") {
1309
- const scopedBuffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1310
- const scopedRawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
1311
- return {
1312
- currentTurnScope: scope || null,
1313
- responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
1314
- partialResponse: this.summarizeTraceText(partialResponse || this.responseBuffer, 1200),
1315
- turnBuffer: this.summarizeTraceText(scopedBuffer, 1600),
1316
- turnRawPreview: this.summarizeTraceText(scopedRawBuffer, 1600),
1317
- turnSanitizedRawPreview: this.summarizeTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
1318
- };
1319
- }
1320
1465
  recordTrace(type, payload = {}) {
1321
1466
  const entry = {
1322
1467
  id: ++this.traceSeq,
@@ -1352,7 +1497,7 @@ var init_provider_cli_adapter = __esm({
1352
1497
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
1353
1498
  setCliScripts(scripts) {
1354
1499
  this.cliScripts = scripts;
1355
- const scriptNames = Object.keys(scripts).filter((k) => typeof scripts[k] === "function");
1500
+ const scriptNames = listCliScriptNames(scripts);
1356
1501
  LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
1357
1502
  }
1358
1503
  updateRuntimeSettings(settings) {
@@ -1384,72 +1529,42 @@ var init_provider_cli_adapter = __esm({
1384
1529
  }
1385
1530
  async spawn() {
1386
1531
  if (this.ptyProcess) return;
1387
- const { spawn: spawnConfig } = this.provider;
1388
- const configuredCommand = typeof this.runtimeSettings.executablePath === "string" && this.runtimeSettings.executablePath.trim() ? this.runtimeSettings.executablePath.trim() : spawnConfig.command;
1389
- const binaryPath = findBinary(configuredCommand);
1390
- const isWin = os8.platform() === "win32";
1391
- const allArgs = [...spawnConfig.args, ...this.extraArgs];
1532
+ const spawnPlan = resolveCliSpawnPlan({
1533
+ provider: this.provider,
1534
+ runtimeSettings: this.runtimeSettings,
1535
+ workingDir: this.workingDir,
1536
+ extraArgs: this.extraArgs
1537
+ });
1392
1538
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1393
1539
  this.resetTraceSession();
1394
- let shellCmd;
1395
- let shellArgs;
1396
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1397
- const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1398
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1399
- const useShell = isWin ? useShellWin : useShellUnix;
1400
- if (useShell) {
1401
- if (!spawnConfig.shell && !isWin) {
1402
- LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
1403
- }
1404
- if (isCmdShim) {
1405
- LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell for .cmd/.bat shim: ${binaryPath}`);
1406
- } else if (isWin) {
1407
- LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell on Windows: ${binaryPath}`);
1408
- }
1409
- shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
1410
- if (isWin) {
1411
- shellArgs = ["/c", binaryPath, ...allArgs];
1412
- } else {
1413
- const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1414
- shellArgs = ["-l", "-c", fullCmd];
1415
- }
1416
- } else {
1417
- if (isWin && spawnConfig.shell) {
1418
- LOG.info("CLI", `[${this.cliType}] Spawning Windows binary directly without cmd.exe: ${binaryPath}`);
1419
- }
1420
- shellCmd = binaryPath;
1421
- shellArgs = allArgs;
1422
- }
1423
- const ptyOpts = {
1424
- cols: 80,
1425
- rows: 24,
1426
- cwd: this.workingDir,
1427
- env: buildCliSpawnEnv(process.env, spawnConfig.env)
1428
- };
1429
1540
  this.recordTrace("spawn", {
1430
- shellCommand: shellCmd,
1431
- shellArgs,
1432
- cwd: ptyOpts.cwd,
1433
- cols: ptyOpts.cols,
1434
- rows: ptyOpts.rows,
1541
+ shellCommand: spawnPlan.shellCmd,
1542
+ shellArgs: spawnPlan.shellArgs,
1543
+ cwd: spawnPlan.ptyOptions.cwd,
1544
+ cols: spawnPlan.ptyOptions.cols,
1545
+ rows: spawnPlan.ptyOptions.rows,
1435
1546
  providerResolution: this.providerResolutionMeta
1436
1547
  });
1437
1548
  try {
1438
- this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1549
+ this.ptyProcess = this.transportFactory.spawn(
1550
+ spawnPlan.shellCmd,
1551
+ spawnPlan.shellArgs,
1552
+ spawnPlan.ptyOptions
1553
+ );
1439
1554
  } catch (err) {
1440
1555
  const msg = err?.message || String(err);
1441
- if (!isWin && !useShell && /posix_spawn|spawn/i.test(msg)) {
1556
+ if (!spawnPlan.isWin && !spawnPlan.useShell && /posix_spawn|spawn/i.test(msg)) {
1442
1557
  LOG.warn("CLI", `[${this.cliType}] Direct spawn failed (${msg}), retrying via login shell`);
1443
- shellCmd = process.env.SHELL || "/bin/zsh";
1444
- const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1445
- shellArgs = ["-l", "-c", fullCmd];
1446
- this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1558
+ const retryPlan = buildCliLoginShellRetry(spawnPlan);
1559
+ this.ptyProcess = this.transportFactory.spawn(
1560
+ retryPlan.shellCmd,
1561
+ retryPlan.shellArgs,
1562
+ spawnPlan.ptyOptions
1563
+ );
1447
1564
  } else {
1448
- if (isWin) {
1449
- const hint = /error code 267|ERROR_DIRECTORY/i.test(msg) ? " (working directory does not exist or is not a directory)" : /error code 740|elevation/i.test(msg) ? " (requires administrator privileges)" : /error code 2|ENOENT|not found/i.test(msg) ? ` (executable not found: ${shellCmd})` : "";
1450
- if (hint) {
1451
- throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1452
- }
1565
+ const hint = getCliSpawnErrorHint(msg, spawnPlan.shellCmd, spawnPlan.isWin);
1566
+ if (hint) {
1567
+ throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1453
1568
  }
1454
1569
  throw err;
1455
1570
  }
@@ -1457,7 +1572,12 @@ var init_provider_cli_adapter = __esm({
1457
1572
  this.ptyProcess.onData((data) => {
1458
1573
  if (Date.now() < this.resizeSuppressUntil) return;
1459
1574
  if (!this.ptyProcess?.terminalQueriesHandled) {
1460
- this.respondToTerminalQueries(data);
1575
+ this.pendingTerminalQueryTail = respondToCliTerminalQueries({
1576
+ ptyProcess: this.ptyProcess,
1577
+ pendingTail: this.pendingTerminalQueryTail,
1578
+ data,
1579
+ terminalScreen: this.terminalScreen
1580
+ });
1461
1581
  }
1462
1582
  this.pendingOutputParseBuffer += data;
1463
1583
  if (!this.pendingOutputParseTimer) {
@@ -1536,9 +1656,9 @@ var init_provider_cli_adapter = __esm({
1536
1656
  this.recordTrace("output", {
1537
1657
  rawLength: rawData.length,
1538
1658
  cleanLength: cleanData.length,
1539
- rawPreview: this.summarizeTraceText(rawData, 300),
1540
- cleanPreview: this.summarizeTraceText(cleanData, 300),
1541
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 1200)
1659
+ rawPreview: summarizeCliTraceText(rawData, 300),
1660
+ cleanPreview: summarizeCliTraceText(cleanData, 300),
1661
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 1200)
1542
1662
  });
1543
1663
  if (this.startupParseGate) {
1544
1664
  this.scheduleStartupSettleCheck();
@@ -1769,7 +1889,7 @@ var init_provider_cli_adapter = __esm({
1769
1889
  loggedWait = true;
1770
1890
  LOG.info(
1771
1891
  "CLI",
1772
- `[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)}`
1892
+ `[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
1773
1893
  );
1774
1894
  }
1775
1895
  await new Promise((resolve12) => setTimeout(resolve12, 50));
@@ -1777,7 +1897,7 @@ var init_provider_cli_adapter = __esm({
1777
1897
  const finalScreenText = this.terminalScreen.getText() || "";
1778
1898
  LOG.warn(
1779
1899
  "CLI",
1780
- `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(this.summarizeTraceText(finalScreenText, 240)).slice(0, 280)}`
1900
+ `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
1781
1901
  );
1782
1902
  }
1783
1903
  evaluateSettled() {
@@ -1807,23 +1927,33 @@ var init_provider_cli_adapter = __esm({
1807
1927
  this.responseBuffer,
1808
1928
  this.currentTurnScope
1809
1929
  );
1810
- const parsedMessages = Array.isArray(parsedTranscript?.messages) ? this.normalizeParsedMessages(parsedTranscript.messages) : [];
1930
+ const parsedMessages = Array.isArray(parsedTranscript?.messages) ? normalizeCliParsedMessages(parsedTranscript.messages, {
1931
+ committedMessages: this.committedMessages,
1932
+ scope: this.currentTurnScope,
1933
+ lastOutputAt: this.lastOutputAt
1934
+ }) : [];
1811
1935
  const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
1812
1936
  this.recordTrace("settled", {
1813
- tail: this.summarizeTraceText(tail, 500),
1814
- screenText: this.summarizeTraceText(screenText, 1200),
1937
+ tail: summarizeCliTraceText(tail, 500),
1938
+ screenText: summarizeCliTraceText(screenText, 1200),
1815
1939
  detectStatus: scriptStatus,
1816
1940
  parsedStatus: parsedTranscript?.status || null,
1817
1941
  parsedMessageCount: parsedMessages.length,
1818
- parsedLastAssistant: lastParsedAssistant ? this.summarizeTraceText(lastParsedAssistant.content, 280) : "",
1942
+ parsedLastAssistant: lastParsedAssistant ? summarizeCliTraceText(lastParsedAssistant.content, 280) : "",
1819
1943
  parsedActiveModal: parsedTranscript?.activeModal ?? null,
1820
1944
  approval: modal,
1821
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
1945
+ ...buildCliTraceParseSnapshot({
1946
+ accumulatedBuffer: this.accumulatedBuffer,
1947
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
1948
+ responseBuffer: this.responseBuffer,
1949
+ partialResponse: this.responseBuffer,
1950
+ scope: this.currentTurnScope
1951
+ })
1822
1952
  });
1823
1953
  if (this.currentTurnScope && !lastParsedAssistant) {
1824
1954
  LOG.info(
1825
1955
  "CLI",
1826
- `[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
1956
+ `[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
1827
1957
  );
1828
1958
  }
1829
1959
  if (!scriptStatus) return;
@@ -1877,7 +2007,13 @@ var init_provider_cli_adapter = __esm({
1877
2007
  lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
1878
2008
  lastScreenChangeAt: this.lastScreenChangeAt,
1879
2009
  holdMs: _ProviderCliAdapter.STATUS_ACTIVITY_HOLD_MS,
1880
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2010
+ ...buildCliTraceParseSnapshot({
2011
+ accumulatedBuffer: this.accumulatedBuffer,
2012
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2013
+ responseBuffer: this.responseBuffer,
2014
+ partialResponse: this.responseBuffer,
2015
+ scope: this.currentTurnScope
2016
+ })
1881
2017
  });
1882
2018
  this.onStatusChange?.();
1883
2019
  return;
@@ -1981,7 +2117,13 @@ var init_provider_cli_adapter = __esm({
1981
2117
  canFinishImmediately,
1982
2118
  submitPendingUntil: this.submitPendingUntil,
1983
2119
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
1984
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2120
+ ...buildCliTraceParseSnapshot({
2121
+ accumulatedBuffer: this.accumulatedBuffer,
2122
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2123
+ responseBuffer: this.responseBuffer,
2124
+ partialResponse: this.responseBuffer,
2125
+ scope: this.currentTurnScope
2126
+ })
1985
2127
  });
1986
2128
  if (canFinishImmediately) {
1987
2129
  this.clearIdleFinishCandidate("finish_response");
@@ -2016,7 +2158,13 @@ var init_provider_cli_adapter = __esm({
2016
2158
  if (this.responseSettleIgnoreUntil > Date.now()) return;
2017
2159
  this.clearIdleFinishCandidate("finish_response_enter");
2018
2160
  this.recordTrace("finish_response", {
2019
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2161
+ ...buildCliTraceParseSnapshot({
2162
+ accumulatedBuffer: this.accumulatedBuffer,
2163
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2164
+ responseBuffer: this.responseBuffer,
2165
+ partialResponse: this.responseBuffer,
2166
+ scope: this.currentTurnScope
2167
+ })
2020
2168
  });
2021
2169
  const commitResult = this.commitCurrentTranscript();
2022
2170
  if (this.shouldRetryFinishResponse(commitResult)) {
@@ -2024,8 +2172,14 @@ var init_provider_cli_adapter = __esm({
2024
2172
  this.recordTrace("finish_response_retry", {
2025
2173
  retryCount: this.finishRetryCount,
2026
2174
  retryDelayMs: _ProviderCliAdapter.FINISH_RETRY_DELAY_MS,
2027
- assistantContent: this.summarizeTraceText(commitResult.assistantContent, 220),
2028
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2175
+ assistantContent: summarizeCliTraceText(commitResult.assistantContent, 220),
2176
+ ...buildCliTraceParseSnapshot({
2177
+ accumulatedBuffer: this.accumulatedBuffer,
2178
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2179
+ responseBuffer: this.responseBuffer,
2180
+ partialResponse: this.responseBuffer,
2181
+ scope: this.currentTurnScope
2182
+ })
2029
2183
  });
2030
2184
  if (this.finishRetryTimer) clearTimeout(this.finishRetryTimer);
2031
2185
  this.finishRetryTimer = setTimeout(() => {
@@ -2074,7 +2228,11 @@ var init_provider_cli_adapter = __esm({
2074
2228
  this.currentTurnScope
2075
2229
  );
2076
2230
  if (parsed && Array.isArray(parsed.messages)) {
2077
- this.committedMessages = this.normalizeParsedMessages(parsed.messages, this.currentTurnScope);
2231
+ this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
2232
+ committedMessages: this.committedMessages,
2233
+ scope: this.currentTurnScope,
2234
+ lastOutputAt: this.lastOutputAt
2235
+ });
2078
2236
  const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
2079
2237
  if (promptForTrim) {
2080
2238
  const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
@@ -2087,14 +2245,20 @@ var init_provider_cli_adapter = __esm({
2087
2245
  this.recordTrace("commit_transcript", {
2088
2246
  parsedStatus: parsed.status || null,
2089
2247
  messageCount: this.committedMessages.length,
2090
- lastAssistant: lastAssistant ? this.summarizeTraceText(lastAssistant.content, 320) : "",
2091
- messages: this.summarizeTraceMessages(this.committedMessages),
2092
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2248
+ lastAssistant: lastAssistant ? summarizeCliTraceText(lastAssistant.content, 320) : "",
2249
+ messages: summarizeCliTraceMessages(this.committedMessages),
2250
+ ...buildCliTraceParseSnapshot({
2251
+ accumulatedBuffer: this.accumulatedBuffer,
2252
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2253
+ responseBuffer: this.responseBuffer,
2254
+ partialResponse: this.responseBuffer,
2255
+ scope: this.currentTurnScope
2256
+ })
2093
2257
  });
2094
2258
  if (!lastAssistant && this.currentTurnScope) {
2095
2259
  LOG.warn(
2096
2260
  "CLI",
2097
- `[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
2261
+ `[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
2098
2262
  );
2099
2263
  }
2100
2264
  return {
@@ -2186,7 +2350,11 @@ var init_provider_cli_adapter = __esm({
2186
2350
  index: typeof message.index === "number" ? message.index : index,
2187
2351
  kind: message.kind || "standard",
2188
2352
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2189
- })) : this.hydrateParsedMessages(parsed.messages, this.currentTurnScope);
2353
+ })) : hydrateCliParsedMessages(parsed.messages, {
2354
+ committedMessages: this.committedMessages,
2355
+ scope: this.currentTurnScope,
2356
+ lastOutputAt: this.lastOutputAt
2357
+ });
2190
2358
  return {
2191
2359
  id: parsed.id || "cli_session",
2192
2360
  status: parsed.status || this.currentStatus,
@@ -2217,11 +2385,16 @@ var init_provider_cli_adapter = __esm({
2217
2385
  if (typeof fn !== "function") {
2218
2386
  throw new Error(`CLI script '${scriptName}' not available`);
2219
2387
  }
2220
- const input = this.buildParseInput(
2221
- this.committedMessages,
2222
- this.responseBuffer,
2223
- this.currentTurnScope
2224
- );
2388
+ const input = buildCliParseInput({
2389
+ accumulatedBuffer: this.accumulatedBuffer,
2390
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2391
+ recentOutputBuffer: this.recentOutputBuffer,
2392
+ terminalScreenText: this.terminalScreen.getText(),
2393
+ baseMessages: this.committedMessages,
2394
+ partialResponse: this.responseBuffer,
2395
+ scope: this.currentTurnScope,
2396
+ runtimeSettings: this.runtimeSettings
2397
+ });
2225
2398
  return await Promise.resolve(fn({
2226
2399
  ...input,
2227
2400
  args: args && typeof args === "object" ? { ...args } : {}
@@ -2230,7 +2403,16 @@ var init_provider_cli_adapter = __esm({
2230
2403
  parseCurrentTranscript(baseMessages, partialResponse, scope) {
2231
2404
  if (!this.cliScripts?.parseOutput) return null;
2232
2405
  try {
2233
- const input = this.buildParseInput(baseMessages, partialResponse, scope);
2406
+ const input = buildCliParseInput({
2407
+ accumulatedBuffer: this.accumulatedBuffer,
2408
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2409
+ recentOutputBuffer: this.recentOutputBuffer,
2410
+ terminalScreenText: this.terminalScreen.getText(),
2411
+ baseMessages,
2412
+ partialResponse,
2413
+ scope,
2414
+ runtimeSettings: this.runtimeSettings
2415
+ });
2234
2416
  const parsed = this.cliScripts.parseOutput(input);
2235
2417
  const refinedStatus = this.refineDetectedStatus(typeof parsed?.status === "string" ? parsed.status : null, input.recentBuffer, input.screenText);
2236
2418
  if (parsed && refinedStatus && parsed.status !== refinedStatus) {
@@ -2320,7 +2502,7 @@ ${data.message || ""}`.trim();
2320
2502
  rawBufferStart: this.accumulatedRawBuffer.length
2321
2503
  };
2322
2504
  this.recordTrace("send_message", {
2323
- text: this.summarizeTraceText(text, 500),
2505
+ text: summarizeCliTraceText(text, 500),
2324
2506
  estimatedLines: estimatePromptDisplayLines(text),
2325
2507
  turnScope: this.currentTurnScope
2326
2508
  });
@@ -2354,7 +2536,7 @@ ${data.message || ""}`.trim();
2354
2536
  this.recordTrace("submit_write", {
2355
2537
  mode: "submit_key",
2356
2538
  sendKey: this.sendKey,
2357
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2539
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2358
2540
  });
2359
2541
  this.ptyProcess.write(this.sendKey);
2360
2542
  const retrySubmitIfStuck = (attempt) => {
@@ -2371,7 +2553,7 @@ ${data.message || ""}`.trim();
2371
2553
  mode: "submit_retry",
2372
2554
  attempt,
2373
2555
  sendKey: this.sendKey,
2374
- screenText: this.summarizeTraceText(screenText, 500)
2556
+ screenText: summarizeCliTraceText(screenText, 500)
2375
2557
  });
2376
2558
  this.ptyProcess.write(this.sendKey);
2377
2559
  if (attempt >= 3) {
@@ -2387,9 +2569,9 @@ ${data.message || ""}`.trim();
2387
2569
  this.submitPendingUntil = 0;
2388
2570
  this.recordTrace("submit_write", {
2389
2571
  mode: "immediate",
2390
- text: this.summarizeTraceText(text, 500),
2572
+ text: summarizeCliTraceText(text, 500),
2391
2573
  sendKey: this.sendKey,
2392
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2574
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2393
2575
  });
2394
2576
  this.ptyProcess.write(text + this.sendKey);
2395
2577
  this.submitRetryTimer = setTimeout(() => {
@@ -2405,7 +2587,7 @@ ${data.message || ""}`.trim();
2405
2587
  mode: "immediate_retry",
2406
2588
  attempt: 1,
2407
2589
  sendKey: this.sendKey,
2408
- screenText: this.summarizeTraceText(screenText, 500)
2590
+ screenText: summarizeCliTraceText(screenText, 500)
2409
2591
  });
2410
2592
  this.ptyProcess.write(this.sendKey);
2411
2593
  this.submitRetryUsed = true;
@@ -2419,9 +2601,9 @@ ${data.message || ""}`.trim();
2419
2601
  this.ptyProcess.write(text);
2420
2602
  this.recordTrace("submit_write", {
2421
2603
  mode: "type_then_submit",
2422
- text: this.summarizeTraceText(text, 500),
2604
+ text: summarizeCliTraceText(text, 500),
2423
2605
  sendKey: this.sendKey,
2424
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2606
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2425
2607
  });
2426
2608
  const submitStartedAt = Date.now();
2427
2609
  let lastNormalizedScreen = "";
@@ -2756,7 +2938,7 @@ ${data.message || ""}`.trim();
2756
2938
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
2757
2939
  resizeSuppressUntil: this.resizeSuppressUntil,
2758
2940
  hasCliScripts: this.hasCliScripts(),
2759
- scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
2941
+ scriptNames: listCliScriptNames(this.cliScripts),
2760
2942
  traceSessionId: this.traceSessionId,
2761
2943
  traceEntryCount: this.traceEntries.length,
2762
2944
  statusHistory: this.statusHistory.slice(-30),
@@ -2773,32 +2955,18 @@ ${data.message || ""}`.trim();
2773
2955
  providerResolution: this.providerResolutionMeta,
2774
2956
  entryCount: this.traceEntries.length,
2775
2957
  entries: this.traceEntries.slice(-cappedLimit),
2776
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 4e3),
2777
- recentOutputBuffer: this.summarizeTraceText(this.recentOutputBuffer, 1e3),
2778
- responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
2958
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 4e3),
2959
+ recentOutputBuffer: summarizeCliTraceText(this.recentOutputBuffer, 1e3),
2960
+ responseBuffer: summarizeCliTraceText(this.responseBuffer, 1200),
2779
2961
  status: this.currentStatus,
2780
2962
  activeModal: this.activeModal,
2781
2963
  currentTurnScope: this.currentTurnScope,
2782
- messages: this.summarizeTraceMessages(this.committedMessages, 5)
2964
+ messages: summarizeCliTraceMessages(this.committedMessages, 5)
2783
2965
  };
2784
2966
  }
2785
2967
  getProviderResolutionMeta() {
2786
2968
  return { ...this.providerResolutionMeta };
2787
2969
  }
2788
- respondToTerminalQueries(data) {
2789
- if (!this.ptyProcess || !data) return;
2790
- const combined = this.pendingTerminalQueryTail + data;
2791
- const regex = /\x1b\[(\?)?6n/g;
2792
- let match;
2793
- while ((match = regex.exec(combined)) !== null) {
2794
- const cursor = this.terminalScreen.getCursorPosition();
2795
- const row = Math.max(1, (cursor.row | 0) + 1);
2796
- const col = Math.max(1, (cursor.col | 0) + 1);
2797
- const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
2798
- this.ptyProcess.write(response);
2799
- }
2800
- this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
2801
- }
2802
2970
  };
2803
2971
  }
2804
2972
  });
@@ -3195,17 +3363,17 @@ function checkPathExists(paths) {
3195
3363
  return null;
3196
3364
  }
3197
3365
  async function detectIDEs(providerLoader) {
3198
- const os18 = platform();
3366
+ const os20 = platform();
3199
3367
  const results = [];
3200
3368
  for (const def of getMergedDefinitions()) {
3201
3369
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
3202
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os18] || []) || []);
3370
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os20] || []) || []);
3203
3371
  let resolvedCli = cliPath;
3204
- if (!resolvedCli && appPath && os18 === "darwin") {
3372
+ if (!resolvedCli && appPath && os20 === "darwin") {
3205
3373
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
3206
3374
  if (existsSync4(bundledCli)) resolvedCli = bundledCli;
3207
3375
  }
3208
- if (!resolvedCli && appPath && os18 === "win32") {
3376
+ if (!resolvedCli && appPath && os20 === "win32") {
3209
3377
  const { dirname: dirname6 } = await import("path");
3210
3378
  const appDir = dirname6(appPath);
3211
3379
  const candidates = [
@@ -3222,7 +3390,7 @@ async function detectIDEs(providerLoader) {
3222
3390
  }
3223
3391
  }
3224
3392
  }
3225
- const installed = os18 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
3393
+ const installed = os20 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
3226
3394
  const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
3227
3395
  results.push({
3228
3396
  id: def.id,
@@ -3283,8 +3451,8 @@ function execAsync(cmd, timeoutMs = 5e3) {
3283
3451
  });
3284
3452
  }
3285
3453
  async function detectCLIs(providerLoader, options) {
3286
- const platform9 = os2.platform();
3287
- const whichCmd = platform9 === "win32" ? "where" : "which";
3454
+ const platform10 = os2.platform();
3455
+ const whichCmd = platform10 === "win32" ? "where" : "which";
3288
3456
  const includeVersion = options?.includeVersion !== false;
3289
3457
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
3290
3458
  const results = await Promise.all(
@@ -3327,8 +3495,8 @@ async function detectCLI(cliId, providerLoader, options) {
3327
3495
  const cliList = providerLoader.getCliDetectionList();
3328
3496
  const target = cliList.find((c) => c.id === resolvedId);
3329
3497
  if (target) {
3330
- const platform9 = os2.platform();
3331
- const whichCmd = platform9 === "win32" ? "where" : "which";
3498
+ const platform10 = os2.platform();
3499
+ const whichCmd = platform10 === "win32" ? "where" : "which";
3332
3500
  try {
3333
3501
  const explicitPath = resolveCommandPath(target.command);
3334
3502
  const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
@@ -3449,6 +3617,10 @@ var DaemonCdpManager = class {
3449
3617
  setTargetFilter(filter) {
3450
3618
  this._targetFilter = filter;
3451
3619
  }
3620
+ /** Clear a previously pinned target so the next connect can reselect a page. */
3621
+ clearTargetId() {
3622
+ this._targetId = null;
3623
+ }
3452
3624
  /**
3453
3625
  * Check if a page title should be excluded (non-main page).
3454
3626
  * Uses provider-configured titleExcludes, falls back to default pattern.
@@ -5714,6 +5886,55 @@ ${effect.notification.body || ""}`.trim();
5714
5886
 
5715
5887
  // src/providers/ide-provider-instance.ts
5716
5888
  init_logger();
5889
+
5890
+ // src/providers/approval-utils.ts
5891
+ var DEFAULT_APPROVAL_POSITIVE_HINTS = [
5892
+ "run",
5893
+ "approve",
5894
+ "accept",
5895
+ "allow once",
5896
+ "always allow",
5897
+ "allow",
5898
+ "yes",
5899
+ "proceed",
5900
+ "continue",
5901
+ "confirm",
5902
+ "save",
5903
+ "ok",
5904
+ "trust"
5905
+ ];
5906
+ function normalizeApprovalLabel(value) {
5907
+ return String(value || "").toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
5908
+ }
5909
+ function getApprovalPositiveHints(provider) {
5910
+ const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
5911
+ return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
5912
+ }
5913
+ function pickApprovalButton(buttons, provider) {
5914
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
5915
+ if (labels.length === 0) {
5916
+ return { index: 0, label: "Approve" };
5917
+ }
5918
+ const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
5919
+ const hints = getApprovalPositiveHints(provider);
5920
+ for (const hint of hints) {
5921
+ const exactIndex = normalizedButtons.findIndex((label) => label === hint);
5922
+ if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
5923
+ const prefixIndex = normalizedButtons.findIndex((label) => label.startsWith(hint));
5924
+ if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
5925
+ const includeIndex = normalizedButtons.findIndex((label) => label.includes(hint));
5926
+ if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
5927
+ }
5928
+ return { index: 0, label: labels[0] };
5929
+ }
5930
+ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
5931
+ const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
5932
+ const cleanMessage = String(modalMessage || "").trim();
5933
+ if (cleanMessage) lines.push(cleanMessage);
5934
+ return lines.join("\n");
5935
+ }
5936
+
5937
+ // src/providers/ide-provider-instance.ts
5717
5938
  var IdeProviderInstance = class {
5718
5939
  type;
5719
5940
  category = "ide";
@@ -5780,6 +6001,8 @@ var IdeProviderInstance = class {
5780
6001
  }
5781
6002
  getState() {
5782
6003
  const cdp = this.context?.cdp;
6004
+ const autoApproveActive = (this.currentStatus === "waiting_approval" || this.cachedChat?.status === "waiting_approval") && this.canAutoApprove();
6005
+ const visibleStatus = autoApproveActive ? "generating" : this.currentStatus;
5783
6006
  const extensionStates = [];
5784
6007
  for (const ext of this.extensions.values()) {
5785
6008
  extensionStates.push(ext.getState());
@@ -5788,13 +6011,13 @@ var IdeProviderInstance = class {
5788
6011
  type: this.type,
5789
6012
  name: this.provider.name,
5790
6013
  category: "ide",
5791
- status: this.currentStatus,
6014
+ status: visibleStatus,
5792
6015
  activeChat: this.cachedChat ? {
5793
6016
  id: this.cachedChat.id || "active_session",
5794
6017
  title: this.cachedChat.title || this.type,
5795
- status: this.cachedChat.status || this.currentStatus,
6018
+ status: autoApproveActive && this.cachedChat.status === "waiting_approval" ? "generating" : this.cachedChat.status || visibleStatus,
5796
6019
  messages: this.mergeConversationMessages(this.cachedChat.messages || []),
5797
- activeModal: this.cachedChat.activeModal || null,
6020
+ activeModal: autoApproveActive ? null : this.cachedChat.activeModal || null,
5798
6021
  inputContent: this.cachedChat.inputContent || ""
5799
6022
  } : null,
5800
6023
  workspace: this.workspace || null,
@@ -5941,7 +6164,8 @@ var IdeProviderInstance = class {
5941
6164
  }
5942
6165
  }
5943
6166
  if (!raw || typeof raw !== "object") return;
5944
- let { activeModal } = raw;
6167
+ const chat = raw;
6168
+ let { activeModal } = chat;
5945
6169
  if (activeModal) {
5946
6170
  const w = activeModal.width ?? Infinity;
5947
6171
  const h = activeModal.height ?? Infinity;
@@ -5961,26 +6185,28 @@ var IdeProviderInstance = class {
5961
6185
  if (pm.receivedAt) prevByHash.set(h, pm.receivedAt);
5962
6186
  }
5963
6187
  const now = Date.now();
5964
- for (const msg of raw.messages || []) {
6188
+ const messages = chat.messages || [];
6189
+ for (const msg of messages) {
5965
6190
  const h = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
5966
6191
  msg.receivedAt = prevByHash.get(h) || now;
5967
6192
  }
5968
- if (raw.messages?.length > 0) {
6193
+ if (messages.length > 0) {
5969
6194
  const hiddenKinds = /* @__PURE__ */ new Set();
5970
6195
  if (this.settings.showThinking === false) hiddenKinds.add("thought");
5971
6196
  if (this.settings.showToolCalls === false) hiddenKinds.add("tool");
5972
6197
  if (this.settings.showTerminal === false) hiddenKinds.add("terminal");
5973
6198
  if (hiddenKinds.size > 0) {
5974
- raw.messages = raw.messages.filter((m) => !hiddenKinds.has(m.kind));
6199
+ chat.messages = messages.filter((m) => !hiddenKinds.has(m.kind || ""));
5975
6200
  }
5976
6201
  }
5977
- const controlValues = extractProviderControlValues(this.provider.controls, raw);
5978
- if (controlValues) raw.controlValues = controlValues;
5979
- this.cachedChat = { ...raw, activeModal };
5980
- this.detectAgentTransitions(raw, now);
5981
- if (raw.messages?.length > 0) {
5982
- let toSave = raw.messages;
5983
- if (raw.status === "generating" || raw.status === "long_generating") {
6202
+ const controlValues = extractProviderControlValues(this.provider.controls, chat);
6203
+ if (controlValues) chat.controlValues = controlValues;
6204
+ this.cachedChat = { ...chat, activeModal };
6205
+ this.detectAgentTransitions(chat, now);
6206
+ const persistedMessages = chat.messages || messages;
6207
+ if (persistedMessages.length > 0) {
6208
+ let toSave = persistedMessages;
6209
+ if (chat.status === "generating" || chat.status === "long_generating") {
5984
6210
  const lastIdx = toSave.length - 1;
5985
6211
  if (lastIdx >= 0 && toSave[lastIdx].role === "assistant") {
5986
6212
  toSave = toSave.slice(0, lastIdx);
@@ -5990,7 +6216,7 @@ var IdeProviderInstance = class {
5990
6216
  this.historyWriter.appendNewMessages(
5991
6217
  this.type,
5992
6218
  toSave,
5993
- raw.title,
6219
+ chat.title,
5994
6220
  this.instanceId
5995
6221
  );
5996
6222
  }
@@ -6006,14 +6232,16 @@ var IdeProviderInstance = class {
6006
6232
  getReadChatScript() {
6007
6233
  const scripts = this.provider.scripts;
6008
6234
  if (!scripts?.readChat) return null;
6009
- return typeof scripts.readChat === "function" ? scripts.readChat({}) : scripts.readChat;
6235
+ return scripts.readChat({});
6010
6236
  }
6011
6237
  // ─── status transition detect ─────────────────────────────
6012
6238
  detectAgentTransitions(chatData, now) {
6013
6239
  const chatStatus = chatData?.status;
6014
6240
  if (!chatStatus) return;
6015
6241
  const agentKey = `${this.type}:native`;
6016
- const agentStatus = chatStatus === "streaming" || chatStatus === "generating" ? "generating" : chatStatus === "waiting_approval" ? "waiting_approval" : "idle";
6242
+ const rawAgentStatus = chatStatus === "streaming" || chatStatus === "generating" ? "generating" : chatStatus === "waiting_approval" ? "waiting_approval" : "idle";
6243
+ const autoApproveActive = rawAgentStatus === "waiting_approval" && this.canAutoApprove();
6244
+ const agentStatus = autoApproveActive ? "generating" : rawAgentStatus;
6017
6245
  const lastMsg = Array.isArray(chatData?.messages) && chatData.messages.length > 0 ? chatData.messages[chatData.messages.length - 1] : null;
6018
6246
  const progressFingerprint = agentStatus === "generating" ? `${lastMsg?.role || ""}:${typeof lastMsg?.content === "string" ? lastMsg.content : JSON.stringify(lastMsg?.content || "")}`.slice(-2e3) : void 0;
6019
6247
  this.currentStatus = agentStatus;
@@ -6045,7 +6273,7 @@ var IdeProviderInstance = class {
6045
6273
  this.applyProviderResponse(chatData, {
6046
6274
  phase: agentStatus === "idle" && (lastStatus === "generating" || lastStatus === "waiting_approval") ? "turn_completed" : "immediate"
6047
6275
  });
6048
- if (agentStatus === "waiting_approval" && this.settings.autoApprove && !this.autoApproveBusy) {
6276
+ if (rawAgentStatus === "waiting_approval" && autoApproveActive && !this.autoApproveBusy) {
6049
6277
  this.autoApproveViaScript(chatData);
6050
6278
  }
6051
6279
  const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint);
@@ -6196,6 +6424,9 @@ ${effect.notification.body || ""}`.trim();
6196
6424
  updateCdp(cdp) {
6197
6425
  if (this.context) this.context.cdp = cdp;
6198
6426
  }
6427
+ canAutoApprove() {
6428
+ return this.settings.autoApprove !== false && typeof this.provider.scripts?.resolveAction === "function" && !!this.context?.cdp?.isConnected;
6429
+ }
6199
6430
  // ─── Auto-approve via CDP script ────────────────────
6200
6431
  async autoApproveViaScript(_chatData) {
6201
6432
  const cdp = this.context?.cdp;
@@ -6207,17 +6438,15 @@ ${effect.notification.body || ""}`.trim();
6207
6438
  }
6208
6439
  this.autoApproveBusy = true;
6209
6440
  try {
6210
- let targetButton = _chatData?.activeModal?.buttons?.[0] || "Run";
6211
- const buttons = _chatData?.activeModal?.buttons || [];
6212
- for (const b of buttons) {
6213
- const lower = String(b).toLowerCase().replace(/[^\w]/g, "");
6214
- if (/^(run|approve|accept|yes|allow|always|proceed|save)/.test(lower)) {
6215
- targetButton = b;
6216
- break;
6217
- }
6218
- }
6441
+ const { label: targetButton } = pickApprovalButton(_chatData?.activeModal?.buttons, this.provider);
6219
6442
  const script = scriptFn({ action: "approve", button: targetButton, buttonText: targetButton });
6220
6443
  if (!script) return;
6444
+ const now = Date.now();
6445
+ this.appendRuntimeSystemMessage(
6446
+ formatAutoApprovalMessage(_chatData?.activeModal?.message, targetButton),
6447
+ `auto_approval:${now}:${targetButton}`,
6448
+ now
6449
+ );
6221
6450
  LOG.info("IdeInstance", `[IdeInstance:${this.type}] autoApprove: executing resolveAction for "${targetButton}"`);
6222
6451
  let rawResult = await cdp.evaluate(script, 1e4);
6223
6452
  if (typeof rawResult === "string") {
@@ -6239,12 +6468,6 @@ ${effect.notification.body || ""}`.trim();
6239
6468
  LOG.warn("IdeInstance", `[IdeInstance:${this.type}] autoApprove: cdp.send() not available for coordinate click`);
6240
6469
  }
6241
6470
  }
6242
- this.pushEvent({
6243
- event: "agent:auto_approved",
6244
- chatTitle: _chatData?.title || this.provider.name,
6245
- timestamp: Date.now(),
6246
- ideType: this.type
6247
- });
6248
6471
  } catch (e) {
6249
6472
  LOG.warn("IdeInstance", `[IdeInstance:${this.type}] autoApprove error: ${e?.message}`);
6250
6473
  } finally {
@@ -7080,7 +7303,7 @@ function getTargetInstance(h, args) {
7080
7303
  const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
7081
7304
  const sessionId = targetSessionId || h.currentSession?.sessionId || "";
7082
7305
  if (!sessionId) return null;
7083
- return h.ctx.instanceManager?.getInstance(sessionId);
7306
+ return h.ctx.instanceManager?.getInstance(sessionId) || null;
7084
7307
  }
7085
7308
  function getTargetTransport(h, provider) {
7086
7309
  if (h.currentSession?.transport) return h.currentSession.transport;
@@ -7118,6 +7341,10 @@ function getHistorySessionId(h, args) {
7118
7341
  const providerSessionId = typeof state?.providerSessionId === "string" ? state.providerSessionId.trim() : "";
7119
7342
  return providerSessionId || targetSessionId;
7120
7343
  }
7344
+ function callLegacyTextScript(script, text) {
7345
+ if (typeof script !== "function") return null;
7346
+ return script(text);
7347
+ }
7121
7348
  function isRecentDuplicateSend(key) {
7122
7349
  const now = Date.now();
7123
7350
  for (const [candidate, ts2] of recentSendByTarget.entries()) {
@@ -7207,7 +7434,7 @@ async function handleReadChat(h, args) {
7207
7434
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7208
7435
  if (adapter) {
7209
7436
  _log(`${transport} adapter: ${adapter.cliType}`);
7210
- const status = adapter.getStatus?.();
7437
+ const status = adapter.getStatus();
7211
7438
  if (status) {
7212
7439
  return {
7213
7440
  success: true,
@@ -7447,7 +7674,7 @@ async function handleSendChat(h, args) {
7447
7674
  }
7448
7675
  if (parsed?.needsTypeAndSend && provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
7449
7676
  try {
7450
- const webviewScript = provider.scripts.webviewSendMessage(text);
7677
+ const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
7451
7678
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
7452
7679
  const matchText = provider.webviewMatchText;
7453
7680
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -7470,7 +7697,7 @@ async function handleSendChat(h, args) {
7470
7697
  }
7471
7698
  if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
7472
7699
  try {
7473
- const webviewScript = provider.scripts.webviewSendMessage(text);
7700
+ const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
7474
7701
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
7475
7702
  const matchText = provider.webviewMatchText;
7476
7703
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -7702,12 +7929,10 @@ async function handleSetMode(h, args) {
7702
7929
  const mode = args?.mode || "agent";
7703
7930
  if (transport === "acp") {
7704
7931
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7705
- if (adapter) {
7706
- const acpInstance = adapter._acpInstance;
7707
- if (acpInstance && typeof acpInstance.setMode === "function") {
7708
- await acpInstance.setMode(mode);
7709
- return { success: true, mode };
7710
- }
7932
+ const acpInstance = adapter?._acpInstance;
7933
+ if (acpInstance && typeof acpInstance.setMode === "function") {
7934
+ await acpInstance.setMode(mode);
7935
+ return { success: true, mode };
7711
7936
  }
7712
7937
  return { success: false, error: "ACP adapter not found" };
7713
7938
  }
@@ -7760,13 +7985,11 @@ async function handleChangeModel(h, args) {
7760
7985
  if (transport === "acp") {
7761
7986
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7762
7987
  LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
7763
- if (adapter) {
7764
- const acpInstance = adapter._acpInstance;
7765
- if (acpInstance && typeof acpInstance.setConfigOption === "function") {
7766
- await acpInstance.setConfigOption("model", model);
7767
- LOG.info("Command", `[change_model] Updated ACP model to ${model}`);
7768
- return { success: true, model };
7769
- }
7988
+ const acpInstance = adapter?._acpInstance;
7989
+ if (acpInstance && typeof acpInstance.setConfigOption === "function") {
7990
+ await acpInstance.setConfigOption("model", model);
7991
+ LOG.info("Command", `[change_model] Updated ACP model to ${model}`);
7992
+ return { success: true, model };
7770
7993
  }
7771
7994
  return { success: false, error: "ACP adapter not found" };
7772
7995
  }
@@ -7823,6 +8046,9 @@ async function handleSetThoughtLevel(h, args) {
7823
8046
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7824
8047
  const acpInstance = adapter?._acpInstance;
7825
8048
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
8049
+ if (typeof acpInstance.setConfigOption !== "function") {
8050
+ return { success: false, error: "ACP setConfigOption not available" };
8051
+ }
7826
8052
  try {
7827
8053
  await acpInstance.setConfigOption(configId, value);
7828
8054
  LOG.info("Command", `[set_thought_level] ${configId}=${value} for ${provider?.type || "unknown_acp"}`);
@@ -7849,7 +8075,7 @@ async function handleResolveAction(h, args) {
7849
8075
  return { success: false, error: `CLI resolveAction failed: ${e.message}` };
7850
8076
  }
7851
8077
  }
7852
- const status = adapter.getStatus?.();
8078
+ const status = adapter.getStatus();
7853
8079
  if (status?.status !== "waiting_approval") {
7854
8080
  return { success: false, error: "Not in approval state" };
7855
8081
  }
@@ -7888,6 +8114,9 @@ async function handleResolveAction(h, args) {
7888
8114
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7889
8115
  const acpInstance = adapter?._acpInstance;
7890
8116
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
8117
+ if (typeof acpInstance.resolvePermission !== "function") {
8118
+ return { success: false, error: "ACP resolvePermission not available" };
8119
+ }
7891
8120
  try {
7892
8121
  await acpInstance.resolvePermission(action === "approve" || action === "accept" || action === "always");
7893
8122
  LOG.info("Command", `[resolveAction] ACP \u2192 ${action}`);
@@ -8049,11 +8278,16 @@ async function handleCdpCommand(h, args) {
8049
8278
  }
8050
8279
  async function handleCdpBatch(h, args) {
8051
8280
  if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
8052
- const commands = args?.commands;
8281
+ const commands = Array.isArray(args?.commands) ? args.commands : null;
8053
8282
  const stopOnError = args?.stopOnError !== false;
8054
8283
  if (!commands?.length) return { success: false, error: "commands array required" };
8055
8284
  const results = [];
8056
8285
  for (const cmd of commands) {
8286
+ if (!cmd || typeof cmd !== "object" || typeof cmd.method !== "string") {
8287
+ results.push({ method: null, success: false, error: "Invalid command entry" });
8288
+ if (stopOnError) break;
8289
+ continue;
8290
+ }
8057
8291
  try {
8058
8292
  const result = await h.getCdp().sendCdpCommand(cmd.method, cmd.params || {});
8059
8293
  results.push({ method: cmd.method, success: true, result });
@@ -8348,11 +8582,12 @@ function handlePtyResize(h, args) {
8348
8582
  if (!adapter || typeof adapter.resize !== "function") {
8349
8583
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
8350
8584
  }
8585
+ const resize = adapter.resize;
8351
8586
  if (force) {
8352
- adapter.resize(cols - 1, rows);
8353
- setTimeout(() => adapter.resize(cols, rows), 50);
8587
+ resize(cols - 1, rows);
8588
+ setTimeout(() => resize(cols, rows), 50);
8354
8589
  } else {
8355
- adapter.resize(cols, rows);
8590
+ resize(cols, rows);
8356
8591
  }
8357
8592
  return { success: true };
8358
8593
  }
@@ -8410,7 +8645,7 @@ function parseScriptResult(result) {
8410
8645
  return { success: true, payload: { result } };
8411
8646
  }
8412
8647
  }
8413
- if (result && typeof result === "object" && result.success === false) {
8648
+ if (result && typeof result === "object" && "success" in result && result.success === false) {
8414
8649
  return { success: false, payload: result };
8415
8650
  }
8416
8651
  return { success: true, payload: result };
@@ -8833,24 +9068,25 @@ var DaemonCommandHandler = class {
8833
9068
  if (provider?.scripts) {
8834
9069
  const fn = provider.scripts[scriptName];
8835
9070
  if (typeof fn === "function") {
9071
+ const callScript = fn;
8836
9072
  if (params && Object.keys(params).length > 0) {
8837
9073
  const firstVal = Object.values(params)[0];
8838
9074
  if (scriptName === "sendMessage" && typeof firstVal === "string") {
8839
- const legacyScript = fn(firstVal);
9075
+ const legacyScript = callScript(firstVal);
8840
9076
  if (legacyScript) return legacyScript;
8841
9077
  }
8842
- const script = fn(params);
9078
+ const script = callScript(params);
8843
9079
  if (script) {
8844
9080
  const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
8845
9081
  if (!likelyLegacyObjectLeak) return script;
8846
9082
  }
8847
9083
  if (firstVal !== void 0) {
8848
- const legacyScript = fn(firstVal);
9084
+ const legacyScript = callScript(firstVal);
8849
9085
  if (legacyScript) return legacyScript;
8850
9086
  }
8851
9087
  if (script) return script;
8852
9088
  } else {
8853
- const script = fn();
9089
+ const script = callScript();
8854
9090
  if (script) return script;
8855
9091
  }
8856
9092
  }
@@ -9231,16 +9467,16 @@ var DaemonCommandHandler = class {
9231
9467
 
9232
9468
  // src/commands/cli-manager.ts
9233
9469
  init_provider_cli_adapter();
9234
- import * as os10 from "os";
9235
- import * as path11 from "path";
9470
+ import * as os12 from "os";
9471
+ import * as path12 from "path";
9236
9472
  import * as crypto4 from "crypto";
9237
9473
  import chalk from "chalk";
9238
9474
  init_config();
9239
9475
 
9240
9476
  // src/providers/cli-provider-instance.ts
9241
9477
  init_provider_cli_adapter();
9242
- import * as os9 from "os";
9243
- import * as path10 from "path";
9478
+ import * as os11 from "os";
9479
+ import * as path11 from "path";
9244
9480
  import * as crypto3 from "crypto";
9245
9481
  import * as fs5 from "fs";
9246
9482
  import { createRequire } from "module";
@@ -9248,7 +9484,7 @@ init_logger();
9248
9484
  var CachedDatabaseSync = null;
9249
9485
  function getDatabaseSync() {
9250
9486
  if (CachedDatabaseSync) return CachedDatabaseSync;
9251
- const requireFn = typeof __require === "function" ? __require : createRequire(path10.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
9487
+ const requireFn = typeof __require === "function" ? __require : createRequire(path11.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
9252
9488
  const sqliteModule = requireFn(`node:${"sqlite"}`);
9253
9489
  CachedDatabaseSync = sqliteModule.DatabaseSync;
9254
9490
  if (!CachedDatabaseSync) {
@@ -9388,7 +9624,7 @@ var CliProviderInstance = class {
9388
9624
  * Replaces the previously duplicated probeOpenCode/Codex/Goose functions.
9389
9625
  */
9390
9626
  probeSessionIdFromConfig(probe) {
9391
- const resolvedDbPath = probe.dbPath.replace(/^~/, os9.homedir());
9627
+ const resolvedDbPath = probe.dbPath.replace(/^~/, os11.homedir());
9392
9628
  if (!fs5.existsSync(resolvedDbPath)) return null;
9393
9629
  const directories = this.getProbeDirectories();
9394
9630
  const minCreatedAt = Math.max(0, this.startedAt - 6e4);
@@ -9412,6 +9648,8 @@ var CliProviderInstance = class {
9412
9648
  getState() {
9413
9649
  const adapterStatus = this.adapter.getStatus();
9414
9650
  const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9651
+ const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
9652
+ const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
9415
9653
  const parsedProviderSessionId = typeof parsedStatus?.providerSessionId === "string" ? parsedStatus.providerSessionId.trim() : "";
9416
9654
  if (parsedProviderSessionId) {
9417
9655
  this.promoteProviderSessionId(parsedProviderSessionId);
@@ -9451,14 +9689,14 @@ var CliProviderInstance = class {
9451
9689
  type: this.type,
9452
9690
  name: this.provider.name,
9453
9691
  category: "cli",
9454
- status: adapterStatus.status,
9692
+ status: visibleStatus,
9455
9693
  mode: this.presentationMode,
9456
9694
  activeChat: {
9457
9695
  id: `${this.type}_${this.workingDir}`,
9458
9696
  title: parsedStatus?.title || dirName,
9459
- status: parsedStatus?.status || adapterStatus.status,
9697
+ status: autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : parsedStatus?.status || visibleStatus,
9460
9698
  messages: mergedMessages,
9461
- activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
9699
+ activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
9462
9700
  inputContent: ""
9463
9701
  },
9464
9702
  workspace: this.workingDir,
@@ -9522,7 +9760,16 @@ var CliProviderInstance = class {
9522
9760
  const now = Date.now();
9523
9761
  const adapterStatus = this.adapter.getStatus();
9524
9762
  const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9525
- const newStatus = adapterStatus.status;
9763
+ const rawStatus = adapterStatus.status;
9764
+ const autoApproveActive = rawStatus === "waiting_approval" && this.shouldAutoApprove();
9765
+ if (autoApproveActive) {
9766
+ const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(adapterStatus.activeModal?.buttons, this.provider);
9767
+ this.recordAutoApproval(adapterStatus.activeModal?.message, buttonLabel, now);
9768
+ setTimeout(() => {
9769
+ this.adapter.resolveModal(buttonIndex);
9770
+ }, 0);
9771
+ }
9772
+ const newStatus = autoApproveActive ? "generating" : rawStatus;
9526
9773
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9527
9774
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
9528
9775
  const partial = this.adapter.getPartialResponse();
@@ -9732,6 +9979,16 @@ ${effect.notification.body || ""}`.trim();
9732
9979
  get cliName() {
9733
9980
  return this.provider.name;
9734
9981
  }
9982
+ shouldAutoApprove() {
9983
+ return this.settings.autoApprove !== false;
9984
+ }
9985
+ recordAutoApproval(modalMessage, buttonLabel, now = Date.now()) {
9986
+ this.appendRuntimeSystemMessage(
9987
+ formatAutoApprovalMessage(modalMessage, buttonLabel),
9988
+ `auto_approval:${now}:${buttonLabel || "approve"}`,
9989
+ now
9990
+ );
9991
+ }
9735
9992
  recordApprovalSelection(buttonText) {
9736
9993
  const cleanButton = String(buttonText || "").trim();
9737
9994
  if (!cleanButton) return;
@@ -10310,8 +10567,10 @@ var AcpProviderInstance = class {
10310
10567
  input: tc.rawInput ? typeof tc.rawInput === "string" ? tc.rawInput : JSON.stringify(tc.rawInput) : void 0
10311
10568
  });
10312
10569
  }
10313
- if (this.settings.autoApprove) {
10314
- this.log.info(`[${this.type}] Auto-approving: ${tc.title || tc.toolCallId}`);
10570
+ if (this.settings.autoApprove !== false) {
10571
+ const toolTitle = tc.title || tc.toolCallId || "tool call";
10572
+ this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
10573
+ this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
10315
10574
  const allowOption = params.options.find((o) => o.kind === "allow_once") || params.options.find((o) => o.kind === "allow_always");
10316
10575
  if (allowOption) {
10317
10576
  return { outcome: { outcome: "selected", optionId: allowOption.optionId } };
@@ -10763,6 +11022,18 @@ var AcpProviderInstance = class {
10763
11022
  this.events.push(event);
10764
11023
  if (this.events.length > 50) this.events = this.events.slice(-50);
10765
11024
  }
11025
+ appendSystemMessage(content, timestamp = Date.now()) {
11026
+ const normalizedContent = String(content || "").trim();
11027
+ if (!normalizedContent) return;
11028
+ this.messages.push({
11029
+ role: "system",
11030
+ content: normalizedContent,
11031
+ timestamp
11032
+ });
11033
+ if (this.messages.length > 200) {
11034
+ this.messages = this.messages.slice(-100);
11035
+ }
11036
+ }
10766
11037
  flushEvents() {
10767
11038
  const events = [...this.events];
10768
11039
  this.events = [];
@@ -10783,7 +11054,8 @@ var AcpProviderInstance = class {
10783
11054
 
10784
11055
  // src/commands/cli-manager.ts
10785
11056
  init_logger();
10786
- var chalkApi = chalk?.yellow ? chalk : chalk?.default || null;
11057
+ var chalkModule = chalk;
11058
+ var chalkApi = typeof chalkModule.yellow === "function" ? chalkModule : chalkModule.default || null;
10787
11059
  function colorize(color, text) {
10788
11060
  const fn = chalkApi?.[color];
10789
11061
  return typeof fn === "function" ? fn(text) : text;
@@ -11033,7 +11305,7 @@ var DaemonCliManager = class {
11033
11305
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
11034
11306
  const trimmed = (workingDir || "").trim();
11035
11307
  if (!trimmed) throw new Error("working directory required");
11036
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path11.resolve(trimmed);
11308
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path12.resolve(trimmed);
11037
11309
  const normalizedType = this.providerLoader.resolveAlias(cliType);
11038
11310
  const provider = this.providerLoader.getByAlias(cliType);
11039
11311
  const key = crypto4.randomUUID();
@@ -11072,6 +11344,7 @@ ${installInfo}`
11072
11344
  });
11073
11345
  this.adapters.set(key, {
11074
11346
  cliType: normalizedType,
11347
+ cliName: provider.name,
11075
11348
  workingDir: resolvedDir,
11076
11349
  _acpInstance: acpInstance,
11077
11350
  spawn: async () => {
@@ -11090,6 +11363,12 @@ ${installInfo}`
11090
11363
  activeModal: state.activeChat?.activeModal || null
11091
11364
  };
11092
11365
  },
11366
+ getPartialResponse: () => "",
11367
+ cancel: () => {
11368
+ instanceManager2.removeInstance(key);
11369
+ },
11370
+ isProcessing: () => false,
11371
+ isReady: () => true,
11093
11372
  setOnStatusChange: () => {
11094
11373
  },
11095
11374
  setOnPtyData: () => {
@@ -11496,13 +11775,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
11496
11775
  // src/launch.ts
11497
11776
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
11498
11777
  import * as net from "net";
11499
- import * as os12 from "os";
11500
- import * as path13 from "path";
11778
+ import * as os14 from "os";
11779
+ import * as path14 from "path";
11501
11780
 
11502
11781
  // src/providers/provider-loader.ts
11503
11782
  import * as fs6 from "fs";
11504
- import * as path12 from "path";
11505
- import * as os11 from "os";
11783
+ import * as path13 from "path";
11784
+ import * as os13 from "os";
11506
11785
  import * as chokidar from "chokidar";
11507
11786
  init_logger();
11508
11787
  var ProviderLoader = class _ProviderLoader {
@@ -11523,12 +11802,12 @@ var ProviderLoader = class _ProviderLoader {
11523
11802
  static META_FILE = ".meta.json";
11524
11803
  constructor(options) {
11525
11804
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
11526
- const defaultProvidersDir = path12.join(os11.homedir(), ".adhdev", "providers");
11805
+ const defaultProvidersDir = path13.join(os13.homedir(), ".adhdev", "providers");
11527
11806
  if (options?.userDir) {
11528
11807
  this.userDir = options.userDir;
11529
11808
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
11530
11809
  } else {
11531
- const localRepoPath = path12.resolve(__dirname, "../../../../../adhdev-providers");
11810
+ const localRepoPath = path13.resolve(__dirname, "../../../../../adhdev-providers");
11532
11811
  if (fs6.existsSync(localRepoPath)) {
11533
11812
  this.userDir = localRepoPath;
11534
11813
  this.log(`Auto-detected local public repository: ${this.userDir} (Dev workspace speedup)`);
@@ -11537,7 +11816,7 @@ var ProviderLoader = class _ProviderLoader {
11537
11816
  this.log(`Using default user providers directory: ${this.userDir}`);
11538
11817
  }
11539
11818
  }
11540
- this.upstreamDir = path12.join(defaultProvidersDir, ".upstream");
11819
+ this.upstreamDir = path13.join(defaultProvidersDir, ".upstream");
11541
11820
  this.disableUpstream = options?.disableUpstream ?? false;
11542
11821
  }
11543
11822
  log(msg) {
@@ -11567,7 +11846,7 @@ var ProviderLoader = class _ProviderLoader {
11567
11846
  * Canonical provider directory shape for a given root.
11568
11847
  */
11569
11848
  getProviderDir(root, category, type) {
11570
- return path12.join(root, category, type);
11849
+ return path13.join(root, category, type);
11571
11850
  }
11572
11851
  /**
11573
11852
  * Canonical user override directory for a provider.
@@ -11594,7 +11873,7 @@ var ProviderLoader = class _ProviderLoader {
11594
11873
  resolveProviderFile(type, ...segments) {
11595
11874
  const dir = this.findProviderDirInternal(type);
11596
11875
  if (!dir) return null;
11597
- return path12.join(dir, ...segments);
11876
+ return path13.join(dir, ...segments);
11598
11877
  }
11599
11878
  /**
11600
11879
  * Load all providers (3-tier priority)
@@ -11633,7 +11912,7 @@ var ProviderLoader = class _ProviderLoader {
11633
11912
  if (!fs6.existsSync(this.upstreamDir)) return false;
11634
11913
  try {
11635
11914
  return fs6.readdirSync(this.upstreamDir).some(
11636
- (d) => fs6.statSync(path12.join(this.upstreamDir, d)).isDirectory()
11915
+ (d) => fs6.statSync(path13.join(this.upstreamDir, d)).isDirectory()
11637
11916
  );
11638
11917
  } catch {
11639
11918
  return false;
@@ -11674,8 +11953,7 @@ var ProviderLoader = class _ProviderLoader {
11674
11953
  const result = [];
11675
11954
  for (const p of this.providers.values()) {
11676
11955
  if ((p.category === "cli" || p.category === "acp") && p.spawn?.command) {
11677
- const verCmdConfig = p.versionCommand;
11678
- const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[process.platform] : verCmdConfig;
11956
+ const versionCommand = this.getPlatformVersionCommand(p.versionCommand);
11679
11957
  const command = this.getSpawnCommand(p.type, p.spawn.command);
11680
11958
  result.push({
11681
11959
  id: p.type,
@@ -11729,8 +12007,8 @@ var ProviderLoader = class _ProviderLoader {
11729
12007
  * that runtime attach/remove uses.
11730
12008
  */
11731
12009
  getIdeExtensionEnabledState(ideType, extensionType) {
11732
- const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
11733
- const config = loadConfig2();
12010
+ const config = this.readConfig();
12011
+ if (!config) return false;
11734
12012
  const baseIdeType = ideType.split("_")[0];
11735
12013
  const val = config.ideSettings?.[baseIdeType]?.extensions?.[extensionType]?.enabled;
11736
12014
  return val === true;
@@ -11739,15 +12017,15 @@ var ProviderLoader = class _ProviderLoader {
11739
12017
  * Save IDE extension enabled setting
11740
12018
  */
11741
12019
  setIdeExtensionEnabled(ideType, extensionType, enabled) {
12020
+ const config = this.readConfig();
12021
+ if (!config) return false;
11742
12022
  try {
11743
- const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
11744
- const config = loadConfig2();
11745
12023
  const baseIdeType = ideType.split("_")[0];
11746
12024
  if (!config.ideSettings) config.ideSettings = {};
11747
12025
  if (!config.ideSettings[baseIdeType]) config.ideSettings[baseIdeType] = {};
11748
12026
  if (!config.ideSettings[baseIdeType].extensions) config.ideSettings[baseIdeType].extensions = {};
11749
12027
  config.ideSettings[baseIdeType].extensions[extensionType] = { enabled };
11750
- saveConfig3(config);
12028
+ this.writeConfig(config);
11751
12029
  this.log(`IDE extension setting: ${ideType}.${extensionType}.enabled = ${enabled}`);
11752
12030
  return true;
11753
12031
  } catch (e) {
@@ -11937,7 +12215,7 @@ var ProviderLoader = class _ProviderLoader {
11937
12215
  }
11938
12216
  if (currentVersion) {
11939
12217
  resolved._resolvedVersion = currentVersion;
11940
- if (Array.isArray(base.compatibility)) {
12218
+ if (base.compatibility) {
11941
12219
  const compat = base.compatibility;
11942
12220
  let matched = false;
11943
12221
  for (const entry of compat) {
@@ -11949,8 +12227,8 @@ var ProviderLoader = class _ProviderLoader {
11949
12227
  resolved._resolvedScriptDir = entry.scriptDir;
11950
12228
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
11951
12229
  if (providerDir) {
11952
- const fullDir = path12.join(providerDir, entry.scriptDir);
11953
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12230
+ const fullDir = path13.join(providerDir, entry.scriptDir);
12231
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
11954
12232
  }
11955
12233
  matched = true;
11956
12234
  }
@@ -11965,8 +12243,8 @@ var ProviderLoader = class _ProviderLoader {
11965
12243
  resolved._resolvedScriptDir = base.defaultScriptDir;
11966
12244
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
11967
12245
  if (providerDir) {
11968
- const fullDir = path12.join(providerDir, base.defaultScriptDir);
11969
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12246
+ const fullDir = path13.join(providerDir, base.defaultScriptDir);
12247
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
11970
12248
  }
11971
12249
  }
11972
12250
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -11983,8 +12261,8 @@ var ProviderLoader = class _ProviderLoader {
11983
12261
  resolved._resolvedScriptDir = dirOverride;
11984
12262
  resolved._resolvedScriptsSource = `versions:${range}`;
11985
12263
  if (providerDir) {
11986
- const fullDir = path12.join(providerDir, dirOverride);
11987
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12264
+ const fullDir = path13.join(providerDir, dirOverride);
12265
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
11988
12266
  }
11989
12267
  }
11990
12268
  } else if (override.scripts) {
@@ -11992,7 +12270,7 @@ var ProviderLoader = class _ProviderLoader {
11992
12270
  }
11993
12271
  }
11994
12272
  }
11995
- } else if (Array.isArray(base.compatibility) && base.defaultScriptDir) {
12273
+ } else if (base.compatibility && base.defaultScriptDir) {
11996
12274
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
11997
12275
  if (loaded) {
11998
12276
  resolved.scripts = loaded;
@@ -12000,8 +12278,8 @@ var ProviderLoader = class _ProviderLoader {
12000
12278
  resolved._resolvedScriptDir = base.defaultScriptDir;
12001
12279
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
12002
12280
  if (providerDir) {
12003
- const fullDir = path12.join(providerDir, base.defaultScriptDir);
12004
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12281
+ const fullDir = path13.join(providerDir, base.defaultScriptDir);
12282
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12005
12283
  }
12006
12284
  }
12007
12285
  }
@@ -12026,14 +12304,14 @@ var ProviderLoader = class _ProviderLoader {
12026
12304
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
12027
12305
  return null;
12028
12306
  }
12029
- const dir = path12.join(providerDir, scriptDir);
12307
+ const dir = path13.join(providerDir, scriptDir);
12030
12308
  if (!fs6.existsSync(dir)) {
12031
12309
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
12032
12310
  return null;
12033
12311
  }
12034
12312
  const cached = this.scriptsCache.get(dir);
12035
12313
  if (cached) return cached;
12036
- const scriptsJs = path12.join(dir, "scripts.js");
12314
+ const scriptsJs = path13.join(dir, "scripts.js");
12037
12315
  if (fs6.existsSync(scriptsJs)) {
12038
12316
  try {
12039
12317
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -12075,7 +12353,7 @@ var ProviderLoader = class _ProviderLoader {
12075
12353
  return;
12076
12354
  }
12077
12355
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
12078
- this.log(`File changed: ${path12.basename(filePath)}, reloading...`);
12356
+ this.log(`File changed: ${path13.basename(filePath)}, reloading...`);
12079
12357
  this.reload();
12080
12358
  }
12081
12359
  };
@@ -12130,7 +12408,7 @@ var ProviderLoader = class _ProviderLoader {
12130
12408
  }
12131
12409
  const https = __require("https");
12132
12410
  const { execSync: execSync7 } = __require("child_process");
12133
- const metaPath = path12.join(this.upstreamDir, _ProviderLoader.META_FILE);
12411
+ const metaPath = path13.join(this.upstreamDir, _ProviderLoader.META_FILE);
12134
12412
  let prevEtag = "";
12135
12413
  let prevTimestamp = 0;
12136
12414
  try {
@@ -12190,17 +12468,17 @@ var ProviderLoader = class _ProviderLoader {
12190
12468
  return { updated: false };
12191
12469
  }
12192
12470
  this.log("Downloading latest providers from GitHub...");
12193
- const tmpTar = path12.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
12194
- const tmpExtract = path12.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
12471
+ const tmpTar = path13.join(os13.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
12472
+ const tmpExtract = path13.join(os13.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
12195
12473
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
12196
12474
  fs6.mkdirSync(tmpExtract, { recursive: true });
12197
12475
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
12198
12476
  const extracted = fs6.readdirSync(tmpExtract);
12199
12477
  const rootDir = extracted.find(
12200
- (d) => fs6.statSync(path12.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
12478
+ (d) => fs6.statSync(path13.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
12201
12479
  );
12202
12480
  if (!rootDir) throw new Error("Unexpected tarball structure");
12203
- const sourceDir = path12.join(tmpExtract, rootDir);
12481
+ const sourceDir = path13.join(tmpExtract, rootDir);
12204
12482
  const backupDir = this.upstreamDir + ".bak";
12205
12483
  if (fs6.existsSync(this.upstreamDir)) {
12206
12484
  if (fs6.existsSync(backupDir)) fs6.rmSync(backupDir, { recursive: true, force: true });
@@ -12275,8 +12553,8 @@ var ProviderLoader = class _ProviderLoader {
12275
12553
  copyDirRecursive(src, dest) {
12276
12554
  fs6.mkdirSync(dest, { recursive: true });
12277
12555
  for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
12278
- const srcPath = path12.join(src, entry.name);
12279
- const destPath = path12.join(dest, entry.name);
12556
+ const srcPath = path13.join(src, entry.name);
12557
+ const destPath = path13.join(dest, entry.name);
12280
12558
  if (entry.isDirectory()) {
12281
12559
  this.copyDirRecursive(srcPath, destPath);
12282
12560
  } else {
@@ -12287,7 +12565,7 @@ var ProviderLoader = class _ProviderLoader {
12287
12565
  /** .meta.json save */
12288
12566
  writeMeta(metaPath, etag, timestamp) {
12289
12567
  try {
12290
- fs6.mkdirSync(path12.dirname(metaPath), { recursive: true });
12568
+ fs6.mkdirSync(path13.dirname(metaPath), { recursive: true });
12291
12569
  fs6.writeFileSync(metaPath, JSON.stringify({
12292
12570
  etag,
12293
12571
  timestamp,
@@ -12304,7 +12582,7 @@ var ProviderLoader = class _ProviderLoader {
12304
12582
  const scan = (d) => {
12305
12583
  try {
12306
12584
  for (const entry of fs6.readdirSync(d, { withFileTypes: true })) {
12307
- if (entry.isDirectory()) scan(path12.join(d, entry.name));
12585
+ if (entry.isDirectory()) scan(path13.join(d, entry.name));
12308
12586
  else if (entry.name === "provider.json") count++;
12309
12587
  }
12310
12588
  } catch {
@@ -12337,15 +12615,10 @@ var ProviderLoader = class _ProviderLoader {
12337
12615
  */
12338
12616
  getSettingValue(type, key) {
12339
12617
  const schemaDef = this.getSettingsSchema(type)[key];
12340
- const defaultVal = schemaDef ? schemaDef.default : void 0;
12341
- try {
12342
- const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
12343
- const config = loadConfig2();
12344
- const userVal = config.providerSettings?.[type]?.[key];
12345
- return userVal !== void 0 ? userVal : defaultVal;
12346
- } catch {
12347
- return defaultVal;
12348
- }
12618
+ const defaultVal = schemaDef ? key === "autoApprove" && schemaDef.type === "boolean" ? true : schemaDef.default : void 0;
12619
+ const config = this.readConfig();
12620
+ const userVal = config?.providerSettings?.[type]?.[key];
12621
+ return userVal !== void 0 ? userVal : defaultVal;
12349
12622
  }
12350
12623
  /**
12351
12624
  * All resolved settings for a provider (default + user override)
@@ -12373,13 +12646,13 @@ var ProviderLoader = class _ProviderLoader {
12373
12646
  if (schemaDef.max !== void 0 && value > schemaDef.max) return false;
12374
12647
  }
12375
12648
  if (schemaDef.type === "select" && schemaDef.options && !schemaDef.options.includes(value)) return false;
12649
+ const config = this.readConfig();
12650
+ if (!config) return false;
12376
12651
  try {
12377
- const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
12378
- const config = loadConfig2();
12379
12652
  if (!config.providerSettings) config.providerSettings = {};
12380
12653
  if (!config.providerSettings[type]) config.providerSettings[type] = {};
12381
12654
  config.providerSettings[type][key] = value;
12382
- saveConfig3(config);
12655
+ this.writeConfig(config);
12383
12656
  this.log(`Setting updated: ${type}.${key} = ${JSON.stringify(value)}`);
12384
12657
  return true;
12385
12658
  } catch (e) {
@@ -12393,16 +12666,63 @@ var ProviderLoader = class _ProviderLoader {
12393
12666
  const trimmed = value.trim();
12394
12667
  return trimmed ? trimmed : null;
12395
12668
  }
12669
+ readConfig() {
12670
+ try {
12671
+ const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
12672
+ return loadConfig2();
12673
+ } catch {
12674
+ return null;
12675
+ }
12676
+ }
12677
+ writeConfig(config) {
12678
+ const { saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
12679
+ saveConfig3(config);
12680
+ }
12681
+ getPlatformVersionCommand(versionCommand) {
12682
+ if (!versionCommand) return void 0;
12683
+ if (typeof versionCommand === "string") {
12684
+ const trimmed = versionCommand.trim();
12685
+ return trimmed || void 0;
12686
+ }
12687
+ const platformValue = versionCommand[process.platform];
12688
+ if (typeof platformValue === "string" && platformValue.trim()) {
12689
+ return platformValue.trim();
12690
+ }
12691
+ const defaultValue = versionCommand.default;
12692
+ if (typeof defaultValue === "string" && defaultValue.trim()) {
12693
+ return defaultValue.trim();
12694
+ }
12695
+ return void 0;
12696
+ }
12396
12697
  getSettingsSchema(type) {
12397
12698
  const provider = this.providers.get(type);
12398
12699
  if (!provider) return {};
12399
- return {
12700
+ const result = {
12400
12701
  ...this.getSyntheticSettings(type, provider),
12401
12702
  ...provider.settings || {}
12402
12703
  };
12704
+ if (result.autoApprove?.type === "boolean") {
12705
+ result.autoApprove = {
12706
+ ...result.autoApprove,
12707
+ default: true,
12708
+ public: true,
12709
+ label: result.autoApprove.label || "Auto Approve",
12710
+ description: result.autoApprove.description || "Automatically approve actionable prompts without sending approval alerts."
12711
+ };
12712
+ }
12713
+ return result;
12403
12714
  }
12404
12715
  getSyntheticSettings(type, provider) {
12405
12716
  const result = {};
12717
+ if (!provider.settings?.autoApprove) {
12718
+ result.autoApprove = {
12719
+ type: "boolean",
12720
+ default: true,
12721
+ public: true,
12722
+ label: "Auto Approve",
12723
+ description: "Automatically approve actionable prompts without sending approval alerts."
12724
+ };
12725
+ }
12406
12726
  if ((provider.category === "cli" || provider.category === "acp") && provider.spawn?.command && !provider.settings?.executablePath) {
12407
12727
  result.executablePath = {
12408
12728
  type: "string",
@@ -12447,17 +12767,17 @@ var ProviderLoader = class _ProviderLoader {
12447
12767
  for (const root of searchRoots) {
12448
12768
  if (!fs6.existsSync(root)) continue;
12449
12769
  const candidate = this.getProviderDir(root, cat, type);
12450
- if (fs6.existsSync(path12.join(candidate, "provider.json"))) return candidate;
12451
- const catDir = path12.join(root, cat);
12770
+ if (fs6.existsSync(path13.join(candidate, "provider.json"))) return candidate;
12771
+ const catDir = path13.join(root, cat);
12452
12772
  if (fs6.existsSync(catDir)) {
12453
12773
  try {
12454
12774
  for (const entry of fs6.readdirSync(catDir, { withFileTypes: true })) {
12455
12775
  if (!entry.isDirectory()) continue;
12456
- const jsonPath = path12.join(catDir, entry.name, "provider.json");
12776
+ const jsonPath = path13.join(catDir, entry.name, "provider.json");
12457
12777
  if (fs6.existsSync(jsonPath)) {
12458
12778
  try {
12459
12779
  const data = JSON.parse(fs6.readFileSync(jsonPath, "utf-8"));
12460
- if (data.type === type) return path12.join(catDir, entry.name);
12780
+ if (data.type === type) return path13.join(catDir, entry.name);
12461
12781
  } catch {
12462
12782
  }
12463
12783
  }
@@ -12474,7 +12794,7 @@ var ProviderLoader = class _ProviderLoader {
12474
12794
  * (template substitution is NOT applied here — scripts.js handles that)
12475
12795
  */
12476
12796
  buildScriptWrappersFromDir(dir) {
12477
- const scriptsJs = path12.join(dir, "scripts.js");
12797
+ const scriptsJs = path13.join(dir, "scripts.js");
12478
12798
  if (fs6.existsSync(scriptsJs)) {
12479
12799
  try {
12480
12800
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -12488,7 +12808,7 @@ var ProviderLoader = class _ProviderLoader {
12488
12808
  for (const file of fs6.readdirSync(dir)) {
12489
12809
  if (!file.endsWith(".js")) continue;
12490
12810
  const scriptName = toCamel(file.replace(".js", ""));
12491
- const filePath = path12.join(dir, file);
12811
+ const filePath = path13.join(dir, file);
12492
12812
  result[scriptName] = (...args) => {
12493
12813
  try {
12494
12814
  let content = fs6.readFileSync(filePath, "utf-8");
@@ -12548,35 +12868,39 @@ var ProviderLoader = class _ProviderLoader {
12548
12868
  }
12549
12869
  const hasJson = entries.some((e) => e.name === "provider.json");
12550
12870
  if (hasJson) {
12551
- const jsonPath = path12.join(d, "provider.json");
12871
+ const jsonPath = path13.join(d, "provider.json");
12552
12872
  try {
12553
12873
  const raw = fs6.readFileSync(jsonPath, "utf-8");
12554
12874
  const mod = JSON.parse(raw);
12555
12875
  if (!mod.type || !mod.name || !mod.category) {
12556
12876
  this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
12557
12877
  } else {
12558
- if (mod.extensionIdPattern && typeof mod.extensionIdPattern === "string") {
12878
+ if (typeof mod.extensionIdPattern === "string") {
12559
12879
  const flags = mod.extensionIdPattern_flags || "";
12560
12880
  mod.extensionIdPattern = new RegExp(mod.extensionIdPattern, flags);
12561
- delete mod.extensionIdPattern_flags;
12562
12881
  }
12563
- const hasCompatibility = Array.isArray(mod.compatibility);
12564
- const scriptsPath = path12.join(d, "scripts.js");
12882
+ const { extensionIdPattern_flags, extensionIdPattern, ...providerFields } = mod;
12883
+ const normalizedProvider = {
12884
+ ...providerFields,
12885
+ ...extensionIdPattern instanceof RegExp ? { extensionIdPattern } : {}
12886
+ };
12887
+ const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
12888
+ const scriptsPath = path13.join(d, "scripts.js");
12565
12889
  if (!hasCompatibility && fs6.existsSync(scriptsPath)) {
12566
12890
  try {
12567
12891
  delete __require.cache[__require.resolve(scriptsPath)];
12568
12892
  const scripts = __require(scriptsPath);
12569
- mod.scripts = scripts;
12893
+ normalizedProvider.scripts = scripts;
12570
12894
  } catch (e) {
12571
12895
  this.log(`\u26A0 Failed to load scripts: ${scriptsPath}: ${e.message}`);
12572
12896
  }
12573
12897
  }
12574
- const existed = this.providers.has(mod.type);
12575
- this.providers.set(mod.type, mod);
12898
+ const existed = this.providers.has(normalizedProvider.type);
12899
+ this.providers.set(normalizedProvider.type, normalizedProvider);
12576
12900
  count++;
12577
12901
  const source = d.startsWith(this.userDir) && !d.includes(".upstream") ? "user" : "upstream";
12578
12902
  const overrideWarning = existed && source === "user" ? " \u26A0 OVERRIDES upstream" : "";
12579
- this.log(` ${existed ? "\u{1F504}" : "\u2705"} ${mod.type} (${mod.category}) \u2014 ${mod.name} [${source}]${overrideWarning}`);
12903
+ this.log(` ${existed ? "\u{1F504}" : "\u2705"} ${normalizedProvider.type} (${normalizedProvider.category}) \u2014 ${normalizedProvider.name} [${source}]${overrideWarning}`);
12580
12904
  }
12581
12905
  } catch (e) {
12582
12906
  this.log(`\u26A0 Failed to load ${jsonPath}: ${e.message}`);
@@ -12587,7 +12911,7 @@ var ProviderLoader = class _ProviderLoader {
12587
12911
  if (!entry.isDirectory()) continue;
12588
12912
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
12589
12913
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
12590
- scan(path12.join(d, entry.name));
12914
+ scan(path13.join(d, entry.name));
12591
12915
  }
12592
12916
  }
12593
12917
  };
@@ -12657,9 +12981,9 @@ function getWinProcessNames() {
12657
12981
  function getProviderMeta(ideId) {
12658
12982
  return getProviderLoader().getMeta(ideId);
12659
12983
  }
12660
- function getPreferredLaunchMethod(ideId, platform9) {
12984
+ function getPreferredLaunchMethod(ideId, platform10) {
12661
12985
  const prefer = getProviderMeta(ideId)?.launch?.prefer;
12662
- const value = prefer?.[platform9];
12986
+ const value = prefer?.[platform10];
12663
12987
  return value === "cli" || value === "app" || value === "auto" ? value : "auto";
12664
12988
  }
12665
12989
  function getCdpStartupTimeoutMs(ideId) {
@@ -12716,7 +13040,7 @@ async function isCdpActive(port) {
12716
13040
  });
12717
13041
  }
12718
13042
  async function killIdeProcess(ideId) {
12719
- const plat = os12.platform();
13043
+ const plat = os14.platform();
12720
13044
  const appName = getMacAppIdentifiers()[ideId];
12721
13045
  const winProcesses = getWinProcessNames()[ideId];
12722
13046
  try {
@@ -12775,7 +13099,7 @@ async function killIdeProcess(ideId) {
12775
13099
  }
12776
13100
  }
12777
13101
  function isIdeRunning(ideId) {
12778
- const plat = os12.platform();
13102
+ const plat = os14.platform();
12779
13103
  try {
12780
13104
  if (plat === "darwin") {
12781
13105
  const appName = getMacAppIdentifiers()[ideId];
@@ -12826,7 +13150,7 @@ function isIdeRunning(ideId) {
12826
13150
  }
12827
13151
  }
12828
13152
  function detectCurrentWorkspace(ideId) {
12829
- const plat = os12.platform();
13153
+ const plat = os14.platform();
12830
13154
  if (plat === "darwin") {
12831
13155
  try {
12832
13156
  const appName = getMacAppIdentifiers()[ideId];
@@ -12845,8 +13169,8 @@ function detectCurrentWorkspace(ideId) {
12845
13169
  const appNameMap = getMacAppIdentifiers();
12846
13170
  const appName = appNameMap[ideId];
12847
13171
  if (appName) {
12848
- const storagePath = path13.join(
12849
- process.env.APPDATA || path13.join(os12.homedir(), "AppData", "Roaming"),
13172
+ const storagePath = path14.join(
13173
+ process.env.APPDATA || path14.join(os14.homedir(), "AppData", "Roaming"),
12850
13174
  appName,
12851
13175
  "storage.json"
12852
13176
  );
@@ -12868,7 +13192,7 @@ function detectCurrentWorkspace(ideId) {
12868
13192
  return void 0;
12869
13193
  }
12870
13194
  async function launchWithCdp(options = {}) {
12871
- const platform9 = os12.platform();
13195
+ const platform10 = os14.platform();
12872
13196
  let targetIde;
12873
13197
  const ides = await detectIDEs(getProviderLoader());
12874
13198
  if (options.ideId) {
@@ -12937,9 +13261,9 @@ async function launchWithCdp(options = {}) {
12937
13261
  }
12938
13262
  const port = await findFreePort(portPair);
12939
13263
  try {
12940
- if (platform9 === "darwin") {
13264
+ if (platform10 === "darwin") {
12941
13265
  await launchMacOS(targetIde, port, workspace, options.newWindow);
12942
- } else if (platform9 === "win32") {
13266
+ } else if (platform10 === "win32") {
12943
13267
  await launchWindows(targetIde, port, workspace, options.newWindow);
12944
13268
  } else {
12945
13269
  await launchLinux(targetIde, port, workspace, options.newWindow);
@@ -13024,9 +13348,9 @@ init_logger();
13024
13348
 
13025
13349
  // src/logging/command-log.ts
13026
13350
  import * as fs7 from "fs";
13027
- import * as path14 from "path";
13028
- import * as os13 from "os";
13029
- var LOG_DIR2 = process.platform === "win32" ? path14.join(process.env.LOCALAPPDATA || process.env.APPDATA || path14.join(os13.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path14.join(os13.homedir(), "Library", "Logs", "adhdev") : path14.join(os13.homedir(), ".local", "share", "adhdev", "logs");
13351
+ import * as path15 from "path";
13352
+ import * as os15 from "os";
13353
+ var LOG_DIR2 = process.platform === "win32" ? path15.join(process.env.LOCALAPPDATA || process.env.APPDATA || path15.join(os15.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path15.join(os15.homedir(), "Library", "Logs", "adhdev") : path15.join(os15.homedir(), ".local", "share", "adhdev", "logs");
13030
13354
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
13031
13355
  var MAX_DAYS = 7;
13032
13356
  try {
@@ -13064,13 +13388,13 @@ function getDateStr2() {
13064
13388
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
13065
13389
  }
13066
13390
  var currentDate2 = getDateStr2();
13067
- var currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13391
+ var currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13068
13392
  var writeCount2 = 0;
13069
13393
  function checkRotation() {
13070
13394
  const today = getDateStr2();
13071
13395
  if (today !== currentDate2) {
13072
13396
  currentDate2 = today;
13073
- currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13397
+ currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13074
13398
  cleanOldFiles();
13075
13399
  }
13076
13400
  }
@@ -13084,7 +13408,7 @@ function cleanOldFiles() {
13084
13408
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
13085
13409
  if (dateMatch && dateMatch[1] < cutoffStr) {
13086
13410
  try {
13087
- fs7.unlinkSync(path14.join(LOG_DIR2, file));
13411
+ fs7.unlinkSync(path15.join(LOG_DIR2, file));
13088
13412
  } catch {
13089
13413
  }
13090
13414
  }
@@ -13162,7 +13486,7 @@ init_logger();
13162
13486
 
13163
13487
  // src/status/snapshot.ts
13164
13488
  init_config();
13165
- import * as os14 from "os";
13489
+ import * as os16 from "os";
13166
13490
  init_terminal_screen();
13167
13491
  init_logger();
13168
13492
  var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
@@ -13281,16 +13605,16 @@ function buildStatusSnapshot(options) {
13281
13605
  version: options.version,
13282
13606
  daemonMode: options.daemonMode,
13283
13607
  machine: {
13284
- hostname: os14.hostname(),
13285
- platform: os14.platform(),
13286
- arch: os14.arch(),
13287
- cpus: os14.cpus().length,
13608
+ hostname: os16.hostname(),
13609
+ platform: os16.platform(),
13610
+ arch: os16.arch(),
13611
+ cpus: os16.cpus().length,
13288
13612
  totalMem: memSnap.totalMem,
13289
13613
  freeMem: memSnap.freeMem,
13290
13614
  availableMem: memSnap.availableMem,
13291
- loadavg: os14.loadavg(),
13292
- uptime: os14.uptime(),
13293
- release: os14.release()
13615
+ loadavg: os16.loadavg(),
13616
+ uptime: os16.uptime(),
13617
+ release: os16.release()
13294
13618
  },
13295
13619
  machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
13296
13620
  timestamp: options.timestamp ?? Date.now(),
@@ -13311,14 +13635,14 @@ function buildStatusSnapshot(options) {
13311
13635
  import { execFileSync } from "child_process";
13312
13636
  import { spawn as spawn3 } from "child_process";
13313
13637
  import * as fs8 from "fs";
13314
- import * as os15 from "os";
13315
- import * as path15 from "path";
13638
+ import * as os17 from "os";
13639
+ import * as path16 from "path";
13316
13640
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
13317
13641
  function getUpgradeLogPath() {
13318
- const home = os15.homedir();
13319
- const dir = path15.join(home, ".adhdev");
13642
+ const home = os17.homedir();
13643
+ const dir = path16.join(home, ".adhdev");
13320
13644
  fs8.mkdirSync(dir, { recursive: true });
13321
- return path15.join(dir, "daemon-upgrade.log");
13645
+ return path16.join(dir, "daemon-upgrade.log");
13322
13646
  }
13323
13647
  function appendUpgradeLog(message) {
13324
13648
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -13358,7 +13682,7 @@ async function waitForPidExit(pid, timeoutMs) {
13358
13682
  }
13359
13683
  }
13360
13684
  function stopSessionHostProcesses(appName) {
13361
- const pidFile = path15.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
13685
+ const pidFile = path16.join(os17.homedir(), ".adhdev", `${appName}-session-host.pid`);
13362
13686
  try {
13363
13687
  if (fs8.existsSync(pidFile)) {
13364
13688
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
@@ -13387,7 +13711,7 @@ function stopSessionHostProcesses(appName) {
13387
13711
  }
13388
13712
  }
13389
13713
  function removeDaemonPidFile() {
13390
- const pidFile = path15.join(os15.homedir(), ".adhdev", "daemon.pid");
13714
+ const pidFile = path16.join(os17.homedir(), ".adhdev", "daemon.pid");
13391
13715
  try {
13392
13716
  fs8.unlinkSync(pidFile);
13393
13717
  } catch {
@@ -13398,7 +13722,7 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
13398
13722
  const npmRoot = execFileSync(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
13399
13723
  if (!npmRoot) return;
13400
13724
  const npmPrefix = execFileSync(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
13401
- const binDir = process.platform === "win32" ? npmPrefix : path15.join(npmPrefix, "bin");
13725
+ const binDir = process.platform === "win32" ? npmPrefix : path16.join(npmPrefix, "bin");
13402
13726
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
13403
13727
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
13404
13728
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -13406,25 +13730,25 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
13406
13730
  }
13407
13731
  if (pkgName.startsWith("@")) {
13408
13732
  const [scope, name] = pkgName.split("/");
13409
- const scopeDir = path15.join(npmRoot, scope);
13733
+ const scopeDir = path16.join(npmRoot, scope);
13410
13734
  if (!fs8.existsSync(scopeDir)) return;
13411
13735
  for (const entry of fs8.readdirSync(scopeDir)) {
13412
13736
  if (!entry.startsWith(`.${name}-`)) continue;
13413
- fs8.rmSync(path15.join(scopeDir, entry), { recursive: true, force: true });
13414
- appendUpgradeLog(`Removed stale scoped staging dir: ${path15.join(scopeDir, entry)}`);
13737
+ fs8.rmSync(path16.join(scopeDir, entry), { recursive: true, force: true });
13738
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path16.join(scopeDir, entry)}`);
13415
13739
  }
13416
13740
  } else {
13417
13741
  for (const entry of fs8.readdirSync(npmRoot)) {
13418
13742
  if (!entry.startsWith(`.${pkgName}-`)) continue;
13419
- fs8.rmSync(path15.join(npmRoot, entry), { recursive: true, force: true });
13420
- appendUpgradeLog(`Removed stale staging dir: ${path15.join(npmRoot, entry)}`);
13743
+ fs8.rmSync(path16.join(npmRoot, entry), { recursive: true, force: true });
13744
+ appendUpgradeLog(`Removed stale staging dir: ${path16.join(npmRoot, entry)}`);
13421
13745
  }
13422
13746
  }
13423
13747
  if (fs8.existsSync(binDir)) {
13424
13748
  for (const entry of fs8.readdirSync(binDir)) {
13425
13749
  if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
13426
- fs8.rmSync(path15.join(binDir, entry), { recursive: true, force: true });
13427
- appendUpgradeLog(`Removed stale bin staging entry: ${path15.join(binDir, entry)}`);
13750
+ fs8.rmSync(path16.join(binDir, entry), { recursive: true, force: true });
13751
+ appendUpgradeLog(`Removed stale bin staging entry: ${path16.join(binDir, entry)}`);
13428
13752
  }
13429
13753
  }
13430
13754
  }
@@ -13510,6 +13834,18 @@ var CHAT_COMMANDS = [
13510
13834
  "change_model"
13511
13835
  ];
13512
13836
  var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
13837
+ function normalizeCommandSource(source) {
13838
+ switch (source) {
13839
+ case "ws":
13840
+ case "p2p":
13841
+ case "ext":
13842
+ case "api":
13843
+ case "standalone":
13844
+ return source;
13845
+ default:
13846
+ return "unknown";
13847
+ }
13848
+ }
13513
13849
  function toHostedCliRuntimeDescriptor(record) {
13514
13850
  if (!record || typeof record !== "object") return null;
13515
13851
  const runtimeId = typeof record.sessionId === "string" ? record.sessionId : "";
@@ -13547,20 +13883,21 @@ var DaemonCommandRouter = class {
13547
13883
  */
13548
13884
  async execute(cmd, args, source = "unknown") {
13549
13885
  const cmdStart = Date.now();
13886
+ const logSource = normalizeCommandSource(source);
13550
13887
  try {
13551
13888
  const daemonResult = await this.executeDaemonCommand(cmd, args);
13552
13889
  if (daemonResult) {
13553
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
13890
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
13554
13891
  return daemonResult;
13555
13892
  }
13556
13893
  const handlerResult = await this.deps.commandHandler.handle(cmd, args);
13557
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
13894
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
13558
13895
  if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
13559
13896
  this.deps.onPostChatCommand();
13560
13897
  }
13561
13898
  return handlerResult;
13562
13899
  } catch (e) {
13563
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
13900
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
13564
13901
  throw e;
13565
13902
  }
13566
13903
  }
@@ -13830,7 +14167,7 @@ var DaemonCommandRouter = class {
13830
14167
  } catch {
13831
14168
  }
13832
14169
  }
13833
- return { success: result.success, ...result };
14170
+ return { ...result };
13834
14171
  }
13835
14172
  // ─── Detect IDEs ───
13836
14173
  case "detect_ides": {
@@ -13960,16 +14297,14 @@ var DaemonCommandRouter = class {
13960
14297
  }
13961
14298
  }
13962
14299
  for (const instanceKey of keysToRemove) {
13963
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
13964
- if (ideInstance) {
14300
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
13965
14301
  this.deps.instanceManager.removeInstance(instanceKey);
13966
14302
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
13967
14303
  }
13968
14304
  }
13969
14305
  if (keysToRemove.length === 0) {
13970
14306
  const instanceKey = `ide:${ideType}`;
13971
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
13972
- if (ideInstance) {
14307
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
13973
14308
  this.deps.instanceManager.removeInstance(instanceKey);
13974
14309
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
13975
14310
  }
@@ -14184,11 +14519,11 @@ var DaemonStatusReporter = class {
14184
14519
  // ─── P2P ─────────────────────────────────────────
14185
14520
  sendP2PPayload(payload) {
14186
14521
  const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
14187
- if (hashTarget.machine) {
14522
+ const hashPayload = hashTarget.machine ? (() => {
14188
14523
  const { freeMem: _f, availableMem: _a, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
14189
- hashTarget.machine = stableMachine;
14190
- }
14191
- const h = this.simpleHash(JSON.stringify(hashTarget));
14524
+ return { ...hashTarget, machine: stableMachine };
14525
+ })() : hashTarget;
14526
+ const h = this.simpleHash(JSON.stringify(hashPayload));
14192
14527
  if (h !== this.lastP2PStatusHash) {
14193
14528
  this.lastP2PStatusHash = h;
14194
14529
  this.deps.p2p?.sendStatus(payload);
@@ -14236,6 +14571,9 @@ var ProviderStreamAdapter = class {
14236
14571
  hasScript(name) {
14237
14572
  return typeof this.provider.scripts?.[name] === "function";
14238
14573
  }
14574
+ getStateTitle(state) {
14575
+ return typeof state.title === "string" ? state.title : "";
14576
+ }
14239
14577
  parseMaybeJson(raw) {
14240
14578
  if (typeof raw !== "string") return raw;
14241
14579
  try {
@@ -14439,7 +14777,7 @@ var ProviderStreamAdapter = class {
14439
14777
  for (let attempt = 0; attempt < 6; attempt += 1) {
14440
14778
  await new Promise((resolve12) => setTimeout(resolve12, 250));
14441
14779
  const state = await this.readChat(evaluate);
14442
- const title = typeof state.title === "string" ? state.title : "";
14780
+ const title = this.getStateTitle(state);
14443
14781
  if (this.titlesMatch(title, sessionId)) return true;
14444
14782
  }
14445
14783
  return false;
@@ -14536,6 +14874,11 @@ var DaemonAgentStreamManager = class {
14536
14874
  const child = (this.sessionRegistry?.listChildren(parentSessionId) || []).find((entry) => entry.transport === "cdp-webview" && entry.providerType === agentType);
14537
14875
  return child?.sessionId || null;
14538
14876
  }
14877
+ getStateError(state) {
14878
+ if (typeof state.error === "string" && state.error.trim()) return state.error.trim();
14879
+ if (typeof state._error === "string" && state._error.trim()) return state._error.trim();
14880
+ return "unknown";
14881
+ }
14539
14882
  async connectManagedSession(cdp, parentSessionId, runtimeSessionId) {
14540
14883
  const target = this.getSessionTarget(runtimeSessionId);
14541
14884
  if (!target || target.transport !== "cdp-webview") return null;
@@ -14598,8 +14941,8 @@ var DaemonAgentStreamManager = class {
14598
14941
  try {
14599
14942
  const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
14600
14943
  const state = await agent.adapter.readChat(evaluate);
14601
- LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${state.model || ""}${state.status === "error" ? " error=" + JSON.stringify(state.error || state._error || "unknown") : ""}`);
14602
- const stateError = String(state.error || state._error || "");
14944
+ const stateError = this.getStateError(state);
14945
+ LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${state.model || ""}${state.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
14603
14946
  if (state.status === "error" && this.isRecoverableSessionError(stateError)) {
14604
14947
  throw new Error(stateError);
14605
14948
  }
@@ -14888,7 +15231,43 @@ var AgentStreamPoller = class {
14888
15231
  }
14889
15232
  try {
14890
15233
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
14891
- const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
15234
+ let stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
15235
+ if (stream?.status === "waiting_approval") {
15236
+ const autoApprove = providerLoader.getSettings(stream.agentType).autoApprove !== false;
15237
+ if (autoApprove && resolvedActiveSessionId) {
15238
+ const provider = providerLoader.getMeta(stream.agentType);
15239
+ const { label: buttonLabel } = pickApprovalButton(stream.activeModal?.buttons, provider);
15240
+ const approved = await agentStreamManager.resolveSessionAction(cdp, resolvedActiveSessionId, "approve", buttonLabel);
15241
+ if (approved) {
15242
+ const effectId = [
15243
+ "auto_approval",
15244
+ resolvedActiveSessionId,
15245
+ String(stream.messages?.length || 0),
15246
+ buttonLabel,
15247
+ String(stream.activeModal?.message || "").trim()
15248
+ ].join(":");
15249
+ stream = {
15250
+ ...stream,
15251
+ status: "streaming",
15252
+ activeModal: void 0,
15253
+ effects: [
15254
+ ...stream.effects || [],
15255
+ {
15256
+ type: "message",
15257
+ id: effectId,
15258
+ persist: true,
15259
+ message: {
15260
+ role: "system",
15261
+ senderName: "System",
15262
+ kind: "system",
15263
+ content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
15264
+ }
15265
+ }
15266
+ ]
15267
+ };
15268
+ }
15269
+ }
15270
+ }
14892
15271
  this.deps.onStreamsUpdated?.(ideType, stream ? [stream] : []);
14893
15272
  } catch {
14894
15273
  }
@@ -15132,11 +15511,11 @@ var ProviderInstanceManager = class {
15132
15511
 
15133
15512
  // src/providers/version-archive.ts
15134
15513
  import * as fs10 from "fs";
15135
- import * as path16 from "path";
15136
- import * as os16 from "os";
15514
+ import * as path17 from "path";
15515
+ import * as os18 from "os";
15137
15516
  import { execSync as execSync5 } from "child_process";
15138
- import { platform as platform7 } from "os";
15139
- var ARCHIVE_PATH = path16.join(os16.homedir(), ".adhdev", "version-history.json");
15517
+ import { platform as platform8 } from "os";
15518
+ var ARCHIVE_PATH = path17.join(os18.homedir(), ".adhdev", "version-history.json");
15140
15519
  var MAX_ENTRIES_PER_PROVIDER = 20;
15141
15520
  var VersionArchive = class {
15142
15521
  history = {};
@@ -15161,7 +15540,7 @@ var VersionArchive = class {
15161
15540
  entries.push({
15162
15541
  version,
15163
15542
  detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
15164
- os: platform7()
15543
+ os: platform8()
15165
15544
  });
15166
15545
  if (entries.length > MAX_ENTRIES_PER_PROVIDER) {
15167
15546
  this.history[type] = entries.slice(-MAX_ENTRIES_PER_PROVIDER);
@@ -15183,7 +15562,7 @@ var VersionArchive = class {
15183
15562
  }
15184
15563
  save() {
15185
15564
  try {
15186
- fs10.mkdirSync(path16.dirname(ARCHIVE_PATH), { recursive: true });
15565
+ fs10.mkdirSync(path17.dirname(ARCHIVE_PATH), { recursive: true });
15187
15566
  fs10.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
15188
15567
  } catch {
15189
15568
  }
@@ -15201,7 +15580,7 @@ function runCommand(cmd, timeout = 1e4) {
15201
15580
  }
15202
15581
  }
15203
15582
  function findBinary2(name) {
15204
- const cmd = platform7() === "win32" ? `where ${name}` : `which ${name}`;
15583
+ const cmd = platform8() === "win32" ? `where ${name}` : `which ${name}`;
15205
15584
  const result = runCommand(cmd, 5e3);
15206
15585
  return result ? result.split("\n")[0] : null;
15207
15586
  }
@@ -15209,6 +15588,22 @@ function parseVersion2(raw) {
15209
15588
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
15210
15589
  return match ? match[1] : raw.split("\n")[0].substring(0, 100);
15211
15590
  }
15591
+ function getPlatformVersionCommand(versionCommand, currentOs) {
15592
+ if (!versionCommand) return void 0;
15593
+ if (typeof versionCommand === "string") {
15594
+ const trimmed = versionCommand.trim();
15595
+ return trimmed || void 0;
15596
+ }
15597
+ const platformValue = versionCommand[currentOs];
15598
+ if (typeof platformValue === "string" && platformValue.trim()) {
15599
+ return platformValue.trim();
15600
+ }
15601
+ const defaultValue = versionCommand.default;
15602
+ if (typeof defaultValue === "string" && defaultValue.trim()) {
15603
+ return defaultValue.trim();
15604
+ }
15605
+ return void 0;
15606
+ }
15212
15607
  function getVersion(binary, versionCommand) {
15213
15608
  if (versionCommand) {
15214
15609
  const raw = runCommand(versionCommand);
@@ -15223,8 +15618,8 @@ function getVersion(binary, versionCommand) {
15223
15618
  function checkPathExists2(paths) {
15224
15619
  for (const p of paths) {
15225
15620
  if (p.includes("*")) {
15226
- const home = os16.homedir();
15227
- const resolved = p.replace(/\*/g, home.split(path16.sep).pop() || "");
15621
+ const home = os18.homedir();
15622
+ const resolved = p.replace(/\*/g, home.split(path17.sep).pop() || "");
15228
15623
  if (fs10.existsSync(resolved)) return resolved;
15229
15624
  } else {
15230
15625
  if (fs10.existsSync(p)) return p;
@@ -15233,15 +15628,15 @@ function checkPathExists2(paths) {
15233
15628
  return null;
15234
15629
  }
15235
15630
  function getMacAppVersion(appPath) {
15236
- if (platform7() !== "darwin" || !appPath.endsWith(".app")) return null;
15237
- const plistPath = path16.join(appPath, "Contents", "Info.plist");
15631
+ if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
15632
+ const plistPath = path17.join(appPath, "Contents", "Info.plist");
15238
15633
  if (!fs10.existsSync(plistPath)) return null;
15239
15634
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
15240
15635
  return raw || null;
15241
15636
  }
15242
15637
  async function detectAllVersions(loader, archive) {
15243
15638
  const results = [];
15244
- const currentOs = platform7();
15639
+ const currentOs = platform8();
15245
15640
  for (const provider of loader.getAll()) {
15246
15641
  const info = {
15247
15642
  type: provider.type,
@@ -15253,15 +15648,14 @@ async function detectAllVersions(loader, archive) {
15253
15648
  binary: null,
15254
15649
  detectedAt: (/* @__PURE__ */ new Date()).toISOString()
15255
15650
  };
15256
- const verCmdConfig = provider.versionCommand;
15257
- const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[currentOs] : verCmdConfig;
15651
+ const versionCommand = getPlatformVersionCommand(provider.versionCommand, currentOs);
15258
15652
  if (provider.category === "ide") {
15259
15653
  const osPaths = provider.paths?.[currentOs] || [];
15260
15654
  const appPath = checkPathExists2(osPaths);
15261
15655
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
15262
15656
  let resolvedBin = cliBin;
15263
15657
  if (!resolvedBin && appPath && currentOs === "darwin") {
15264
- const bundled = path16.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
15658
+ const bundled = path17.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
15265
15659
  if (provider.cli && fs10.existsSync(bundled)) resolvedBin = bundled;
15266
15660
  }
15267
15661
  info.installed = !!(appPath || resolvedBin);
@@ -15302,7 +15696,7 @@ async function detectAllVersions(loader, archive) {
15302
15696
  // src/daemon/dev-server.ts
15303
15697
  import * as http2 from "http";
15304
15698
  import * as fs14 from "fs";
15305
- import * as path20 from "path";
15699
+ import * as path21 from "path";
15306
15700
 
15307
15701
  // src/daemon/scaffold-template.ts
15308
15702
  function generateFiles(type, name, category, opts = {}) {
@@ -15639,7 +16033,7 @@ init_logger();
15639
16033
  // src/daemon/dev-cdp-handlers.ts
15640
16034
  init_logger();
15641
16035
  import * as fs11 from "fs";
15642
- import * as path17 from "path";
16036
+ import * as path18 from "path";
15643
16037
  async function handleCdpEvaluate(ctx, req, res) {
15644
16038
  const body = await ctx.readBody(req);
15645
16039
  const { expression, timeout, ideType } = body;
@@ -15817,17 +16211,17 @@ async function handleScriptHints(ctx, type, _req, res) {
15817
16211
  return;
15818
16212
  }
15819
16213
  let scriptsPath = "";
15820
- const directScripts = path17.join(dir, "scripts.js");
16214
+ const directScripts = path18.join(dir, "scripts.js");
15821
16215
  if (fs11.existsSync(directScripts)) {
15822
16216
  scriptsPath = directScripts;
15823
16217
  } else {
15824
- const scriptsDir = path17.join(dir, "scripts");
16218
+ const scriptsDir = path18.join(dir, "scripts");
15825
16219
  if (fs11.existsSync(scriptsDir)) {
15826
16220
  const versions = fs11.readdirSync(scriptsDir).filter((d) => {
15827
- return fs11.statSync(path17.join(scriptsDir, d)).isDirectory();
16221
+ return fs11.statSync(path18.join(scriptsDir, d)).isDirectory();
15828
16222
  }).sort().reverse();
15829
16223
  for (const ver of versions) {
15830
- const p = path17.join(scriptsDir, ver, "scripts.js");
16224
+ const p = path18.join(scriptsDir, ver, "scripts.js");
15831
16225
  if (fs11.existsSync(p)) {
15832
16226
  scriptsPath = p;
15833
16227
  break;
@@ -16646,7 +17040,7 @@ async function handleDomContext(ctx, type, req, res) {
16646
17040
 
16647
17041
  // src/daemon/dev-cli-debug.ts
16648
17042
  import * as fs12 from "fs";
16649
- import * as path18 from "path";
17043
+ import * as path19 from "path";
16650
17044
  function slugifyFixtureName(value) {
16651
17045
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
16652
17046
  return normalized || `fixture-${Date.now()}`;
@@ -16656,11 +17050,11 @@ function getCliFixtureDir(ctx, type) {
16656
17050
  if (!providerDir) {
16657
17051
  throw new Error(`Provider directory not found for '${type}'`);
16658
17052
  }
16659
- return path18.join(providerDir, "fixtures");
17053
+ return path19.join(providerDir, "fixtures");
16660
17054
  }
16661
17055
  function readCliFixture(ctx, type, name) {
16662
17056
  const fixtureDir = getCliFixtureDir(ctx, type);
16663
- const filePath = path18.join(fixtureDir, `${name}.json`);
17057
+ const filePath = path19.join(fixtureDir, `${name}.json`);
16664
17058
  if (!fs12.existsSync(filePath)) {
16665
17059
  throw new Error(`Fixture not found: ${filePath}`);
16666
17060
  }
@@ -16786,6 +17180,15 @@ function validateCliFixtureResult(result, assertions) {
16786
17180
  }
16787
17181
  return failures;
16788
17182
  }
17183
+ function isCliTargetState(state) {
17184
+ return state.category === "cli" || state.category === "acp";
17185
+ }
17186
+ function getCliAdapterFromInstance(instance) {
17187
+ if (!instance) return null;
17188
+ const candidate = instance;
17189
+ if (typeof candidate.getAdapter === "function") return candidate.getAdapter();
17190
+ return candidate.adapter || null;
17191
+ }
16789
17192
  function getCliProviderResolutionMeta(ctx, type, adapter) {
16790
17193
  const adapterMeta = typeof adapter?.getProviderResolutionMeta === "function" ? adapter.getProviderResolutionMeta() : adapter?.getDebugState?.()?.providerResolution || null;
16791
17194
  const resolvedProvider = ctx.providerLoader.resolve(type);
@@ -16803,7 +17206,7 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
16803
17206
  }
16804
17207
  function findCliTarget(ctx, type, instanceId) {
16805
17208
  if (!ctx.instanceManager) return null;
16806
- const cliStates = ctx.instanceManager.collectAllStates().filter((s) => s.category === "cli" || s.category === "acp");
17209
+ const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
16807
17210
  if (instanceId) return cliStates.find((s) => s.instanceId === instanceId) || null;
16808
17211
  if (!type) return cliStates[cliStates.length - 1] || null;
16809
17212
  const matches = cliStates.filter((s) => s.type === type);
@@ -16815,7 +17218,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
16815
17218
  if (!target) return null;
16816
17219
  const instance = ctx.instanceManager.getInstance(target.instanceId);
16817
17220
  if (!instance) return null;
16818
- const adapter = instance.getAdapter?.() || instance.adapter;
17221
+ const adapter = getCliAdapterFromInstance(instance);
16819
17222
  if (!adapter) return null;
16820
17223
  return { target, instance, adapter };
16821
17224
  }
@@ -17290,7 +17693,7 @@ async function handleCliDebug(ctx, type, _req, res) {
17290
17693
  return;
17291
17694
  }
17292
17695
  try {
17293
- const adapter = instance.getAdapter?.() || instance.adapter;
17696
+ const adapter = getCliAdapterFromInstance(instance);
17294
17697
  if (adapter && typeof adapter.getDebugState === "function") {
17295
17698
  const debugState = adapter.getDebugState();
17296
17699
  ctx.json(res, 200, {
@@ -17337,7 +17740,7 @@ async function handleCliTrace(ctx, type, req, res) {
17337
17740
  return;
17338
17741
  }
17339
17742
  try {
17340
- const adapter = instance.getAdapter?.() || instance.adapter;
17743
+ const adapter = getCliAdapterFromInstance(instance);
17341
17744
  const url = new URL(req.url || "/", "http://127.0.0.1");
17342
17745
  const limit = parseInt(url.searchParams.get("limit") || "120", 10);
17343
17746
  if (adapter && typeof adapter.getTraceState === "function") {
@@ -17419,7 +17822,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
17419
17822
  },
17420
17823
  notes: typeof body?.notes === "string" ? body.notes : void 0
17421
17824
  };
17422
- const filePath = path18.join(fixtureDir, `${name}.json`);
17825
+ const filePath = path19.join(fixtureDir, `${name}.json`);
17423
17826
  fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
17424
17827
  ctx.json(res, 200, {
17425
17828
  saved: true,
@@ -17443,7 +17846,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
17443
17846
  return;
17444
17847
  }
17445
17848
  const fixtures = fs12.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
17446
- const fullPath = path18.join(fixtureDir, file);
17849
+ const fullPath = path19.join(fixtureDir, file);
17447
17850
  try {
17448
17851
  const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
17449
17852
  return {
@@ -17523,7 +17926,7 @@ async function handleCliResolve(ctx, req, res) {
17523
17926
  return;
17524
17927
  }
17525
17928
  const instance = ctx.instanceManager.getInstance(target.instanceId);
17526
- const adapter = instance?.getAdapter?.() || instance?.adapter;
17929
+ const adapter = getCliAdapterFromInstance(instance);
17527
17930
  if (!adapter) {
17528
17931
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
17529
17932
  return;
@@ -17560,7 +17963,7 @@ async function handleCliRaw(ctx, req, res) {
17560
17963
  return;
17561
17964
  }
17562
17965
  const instance = ctx.instanceManager.getInstance(target.instanceId);
17563
- const adapter = instance?.getAdapter?.() || instance?.adapter;
17966
+ const adapter = getCliAdapterFromInstance(instance);
17564
17967
  if (!adapter) {
17565
17968
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
17566
17969
  return;
@@ -17579,11 +17982,11 @@ async function handleCliRaw(ctx, req, res) {
17579
17982
 
17580
17983
  // src/daemon/dev-auto-implement.ts
17581
17984
  import * as fs13 from "fs";
17582
- import * as path19 from "path";
17583
- import * as os17 from "os";
17985
+ import * as path20 from "path";
17986
+ import * as os19 from "os";
17584
17987
  function getAutoImplPid(ctx) {
17585
- const proc = ctx.autoImplProcess;
17586
- return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
17988
+ const pid = ctx.autoImplProcess?.pid;
17989
+ return typeof pid === "number" && pid > 0 ? pid : null;
17587
17990
  }
17588
17991
  function isPidAlive(pid) {
17589
17992
  try {
@@ -17601,6 +18004,13 @@ function clearStaleAutoImplState(ctx, reason) {
17601
18004
  ctx.autoImplProcess = null;
17602
18005
  ctx.autoImplStatus.running = false;
17603
18006
  }
18007
+ function tryKillAutoImplProcess(processRef, signal) {
18008
+ if (!processRef) return;
18009
+ try {
18010
+ processRef.kill(signal);
18011
+ } catch {
18012
+ }
18013
+ }
17604
18014
  function getDefaultAutoImplReference(ctx, category, type) {
17605
18015
  if (category === "cli") {
17606
18016
  return type === "codex-cli" ? "claude-cli" : "codex-cli";
@@ -17619,22 +18029,22 @@ function getLatestScriptVersionDir(scriptsDir) {
17619
18029
  if (!fs13.existsSync(scriptsDir)) return null;
17620
18030
  const versions = fs13.readdirSync(scriptsDir).filter((d) => {
17621
18031
  try {
17622
- return fs13.statSync(path19.join(scriptsDir, d)).isDirectory();
18032
+ return fs13.statSync(path20.join(scriptsDir, d)).isDirectory();
17623
18033
  } catch {
17624
18034
  return false;
17625
18035
  }
17626
18036
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
17627
18037
  if (versions.length === 0) return null;
17628
- return path19.join(scriptsDir, versions[0]);
18038
+ return path20.join(scriptsDir, versions[0]);
17629
18039
  }
17630
18040
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
17631
- const canonicalUserDir = path19.resolve(ctx.providerLoader.getUserProviderDir(category, type));
17632
- const desiredDir = requestedDir ? path19.resolve(requestedDir) : canonicalUserDir;
17633
- const upstreamRoot = path19.resolve(ctx.providerLoader.getUpstreamDir());
17634
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path19.sep}`)) {
18041
+ const canonicalUserDir = path20.resolve(ctx.providerLoader.getUserProviderDir(category, type));
18042
+ const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
18043
+ const upstreamRoot = path20.resolve(ctx.providerLoader.getUpstreamDir());
18044
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
17635
18045
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
17636
18046
  }
17637
- if (path19.basename(desiredDir) !== type) {
18047
+ if (path20.basename(desiredDir) !== type) {
17638
18048
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
17639
18049
  }
17640
18050
  const sourceDir = ctx.findProviderDir(type);
@@ -17642,11 +18052,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
17642
18052
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
17643
18053
  }
17644
18054
  if (!fs13.existsSync(desiredDir)) {
17645
- fs13.mkdirSync(path19.dirname(desiredDir), { recursive: true });
18055
+ fs13.mkdirSync(path20.dirname(desiredDir), { recursive: true });
17646
18056
  fs13.cpSync(sourceDir, desiredDir, { recursive: true });
17647
18057
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
17648
18058
  }
17649
- const providerJson = path19.join(desiredDir, "provider.json");
18059
+ const providerJson = path20.join(desiredDir, "provider.json");
17650
18060
  if (!fs13.existsSync(providerJson)) {
17651
18061
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
17652
18062
  }
@@ -17669,13 +18079,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
17669
18079
  const refDir = ctx.findProviderDir(referenceType);
17670
18080
  if (!refDir || !fs13.existsSync(refDir)) return {};
17671
18081
  const referenceScripts = {};
17672
- const scriptsDir = path19.join(refDir, "scripts");
18082
+ const scriptsDir = path20.join(refDir, "scripts");
17673
18083
  const latestDir = getLatestScriptVersionDir(scriptsDir);
17674
18084
  if (!latestDir) return referenceScripts;
17675
18085
  for (const file of fs13.readdirSync(latestDir)) {
17676
18086
  if (!file.endsWith(".js")) continue;
17677
18087
  try {
17678
- referenceScripts[file] = fs13.readFileSync(path19.join(latestDir, file), "utf-8");
18088
+ referenceScripts[file] = fs13.readFileSync(path20.join(latestDir, file), "utf-8");
17679
18089
  } catch {
17680
18090
  }
17681
18091
  }
@@ -17783,9 +18193,9 @@ async function handleAutoImplement(ctx, type, req, res) {
17783
18193
  });
17784
18194
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
17785
18195
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
17786
- const tmpDir = path19.join(os17.tmpdir(), "adhdev-autoimpl");
18196
+ const tmpDir = path20.join(os19.tmpdir(), "adhdev-autoimpl");
17787
18197
  if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
17788
- const promptFile = path19.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
18198
+ const promptFile = path20.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
17789
18199
  fs13.writeFileSync(promptFile, prompt, "utf-8");
17790
18200
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
17791
18201
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -17937,7 +18347,7 @@ async function handleAutoImplement(ctx, type, req, res) {
17937
18347
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
17938
18348
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
17939
18349
  let shellCmd;
17940
- const isWin = os17.platform() === "win32";
18350
+ const isWin = os19.platform() === "win32";
17941
18351
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
17942
18352
  if (command === "claude") {
17943
18353
  const args = [...baseArgs, "--dangerously-skip-permissions"];
@@ -17981,7 +18391,7 @@ async function handleAutoImplement(ctx, type, req, res) {
17981
18391
  try {
17982
18392
  const pty = __require("node-pty");
17983
18393
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
17984
- const isWin2 = os17.platform() === "win32";
18394
+ const isWin2 = os19.platform() === "win32";
17985
18395
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
17986
18396
  name: "xterm-256color",
17987
18397
  cols: 120,
@@ -18020,10 +18430,12 @@ async function handleAutoImplement(ctx, type, req, res) {
18020
18430
  let autoStopTimer = null;
18021
18431
  let autoStopIssued = false;
18022
18432
  try {
18023
- const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
18024
- const normalized = normalizeCliProviderForRuntime2(agentProvider);
18025
- approvalPatterns = normalized.patterns.approval;
18026
- approvalKeys = agentProvider?.approvalKeys || { 0: "y\r", 1: "a\r" };
18433
+ if (agentProvider?.category === "cli") {
18434
+ const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
18435
+ const normalized = normalizeCliProviderForRuntime2(agentProvider);
18436
+ approvalPatterns = normalized.patterns.approval;
18437
+ approvalKeys = agentProvider.approvalKeys || { 0: "y\r", 1: "a\r" };
18438
+ }
18027
18439
  } catch (err) {
18028
18440
  ctx.log(`Failed to load approval patterns: ${err.message}`);
18029
18441
  }
@@ -18038,10 +18450,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18038
18450
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
18039
18451
  `, stream: "stdout" } });
18040
18452
  approvalBuffer = "";
18041
- try {
18042
- ctx.autoImplProcess.kill("SIGINT");
18043
- } catch {
18044
- }
18453
+ tryKillAutoImplProcess(ctx.autoImplProcess, "SIGINT");
18045
18454
  return;
18046
18455
  }
18047
18456
  if (Date.now() - lastApprovalTime < 2e3) return;
@@ -18078,10 +18487,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18078
18487
  stream: "stdout"
18079
18488
  }
18080
18489
  });
18081
- try {
18082
- ctx.autoImplProcess.kill("SIGINT");
18083
- } catch {
18084
- }
18490
+ tryKillAutoImplProcess(ctx.autoImplProcess, "SIGINT");
18085
18491
  }, 3e4);
18086
18492
  };
18087
18493
  const finalizeCliAutoImpl = async (code) => {
@@ -18212,7 +18618,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18212
18618
  setMode: "set_mode.js"
18213
18619
  };
18214
18620
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
18215
- const scriptsDir = path19.join(providerDir, "scripts");
18621
+ const scriptsDir = path20.join(providerDir, "scripts");
18216
18622
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
18217
18623
  if (latestScriptsDir) {
18218
18624
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -18223,7 +18629,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18223
18629
  for (const file of fs13.readdirSync(latestScriptsDir)) {
18224
18630
  if (file.endsWith(".js") && targetFileNames.has(file)) {
18225
18631
  try {
18226
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18632
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18227
18633
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
18228
18634
  lines.push("```javascript");
18229
18635
  lines.push(content);
@@ -18240,7 +18646,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18240
18646
  lines.push("");
18241
18647
  for (const file of refFiles) {
18242
18648
  try {
18243
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18649
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18244
18650
  lines.push(`### \`${file}\` \u{1F512}`);
18245
18651
  lines.push("```javascript");
18246
18652
  lines.push(content);
@@ -18281,10 +18687,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18281
18687
  lines.push("");
18282
18688
  }
18283
18689
  }
18284
- const docsDir = path19.join(providerDir, "../../docs");
18690
+ const docsDir = path20.join(providerDir, "../../docs");
18285
18691
  const loadGuide = (name) => {
18286
18692
  try {
18287
- const p = path19.join(docsDir, name);
18693
+ const p = path20.join(docsDir, name);
18288
18694
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
18289
18695
  } catch {
18290
18696
  }
@@ -18519,7 +18925,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18519
18925
  parseApproval: "parse_approval.js"
18520
18926
  };
18521
18927
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
18522
- const scriptsDir = path19.join(providerDir, "scripts");
18928
+ const scriptsDir = path20.join(providerDir, "scripts");
18523
18929
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
18524
18930
  if (latestScriptsDir) {
18525
18931
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -18531,7 +18937,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18531
18937
  if (!file.endsWith(".js")) continue;
18532
18938
  if (!targetFileNames.has(file)) continue;
18533
18939
  try {
18534
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18940
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18535
18941
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
18536
18942
  lines.push("```javascript");
18537
18943
  lines.push(content);
@@ -18547,7 +18953,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18547
18953
  lines.push("");
18548
18954
  for (const file of refFiles) {
18549
18955
  try {
18550
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18956
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18551
18957
  lines.push(`### \`${file}\` \u{1F512}`);
18552
18958
  lines.push("```javascript");
18553
18959
  lines.push(content);
@@ -18580,10 +18986,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18580
18986
  lines.push("");
18581
18987
  }
18582
18988
  }
18583
- const docsDir = path19.join(providerDir, "../../docs");
18989
+ const docsDir = path20.join(providerDir, "../../docs");
18584
18990
  const loadGuide = (name) => {
18585
18991
  try {
18586
- const p = path19.join(docsDir, name);
18992
+ const p = path20.join(docsDir, name);
18587
18993
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
18588
18994
  } catch {
18589
18995
  }
@@ -18898,6 +19304,38 @@ data: ${JSON.stringify(msg.data)}
18898
19304
 
18899
19305
  // src/daemon/dev-server.ts
18900
19306
  var DEV_SERVER_PORT = 19280;
19307
+ function getScriptNames(scripts) {
19308
+ if (!scripts) return [];
19309
+ return Object.entries(scripts).filter(([, value]) => typeof value === "function").map(([name]) => name);
19310
+ }
19311
+ function toProviderListEntry(provider) {
19312
+ const base = {
19313
+ type: provider.type,
19314
+ name: provider.name,
19315
+ category: provider.category,
19316
+ icon: provider.icon || null,
19317
+ displayName: provider.displayName || provider.name
19318
+ };
19319
+ if (provider.category === "ide" || provider.category === "extension") {
19320
+ base.scripts = getScriptNames(provider.scripts);
19321
+ base.inputMethod = provider.inputMethod || null;
19322
+ base.inputSelector = provider.inputSelector || null;
19323
+ base.extensionId = provider.extensionId || null;
19324
+ base.cdpPorts = provider.cdpPorts || [];
19325
+ }
19326
+ if (provider.category === "acp") {
19327
+ base.spawn = provider.spawn || null;
19328
+ base.auth = provider.auth || null;
19329
+ base.install = provider.install || null;
19330
+ base.hasSettings = !!provider.settings;
19331
+ base.settingsCount = provider.settings ? Object.keys(provider.settings).length : 0;
19332
+ }
19333
+ if (provider.category === "cli") {
19334
+ base.spawn = provider.spawn || null;
19335
+ base.install = provider.install || null;
19336
+ }
19337
+ return base;
19338
+ }
18901
19339
  var DevServer = class _DevServer {
18902
19340
  server = null;
18903
19341
  providerLoader;
@@ -18994,8 +19432,8 @@ var DevServer = class _DevServer {
18994
19432
  }
18995
19433
  getEndpointList() {
18996
19434
  return this.routes.map((r) => {
18997
- const path21 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
18998
- return `${r.method.padEnd(5)} ${path21}`;
19435
+ const path22 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
19436
+ return `${r.method.padEnd(5)} ${path22}`;
18999
19437
  });
19000
19438
  }
19001
19439
  async start(port = DEV_SERVER_PORT) {
@@ -19047,34 +19485,7 @@ var DevServer = class _DevServer {
19047
19485
  }
19048
19486
  // ─── Handlers ───
19049
19487
  async handleListProviders(_req, res) {
19050
- const providers = this.providerLoader.getAll().map((p) => {
19051
- const base = {
19052
- type: p.type,
19053
- name: p.name,
19054
- category: p.category,
19055
- icon: p.icon || null,
19056
- displayName: p.displayName || p.name
19057
- };
19058
- if (p.category === "ide" || p.category === "extension") {
19059
- base.scripts = p.scripts ? Object.keys(p.scripts).filter((k) => typeof p.scripts[k] === "function") : [];
19060
- base.inputMethod = p.inputMethod || null;
19061
- base.inputSelector = p.inputSelector || null;
19062
- base.extensionId = p.extensionId || null;
19063
- base.cdpPorts = p.cdpPorts || [];
19064
- }
19065
- if (p.category === "acp") {
19066
- base.spawn = p.spawn || null;
19067
- base.auth = p.auth || null;
19068
- base.install = p.install || null;
19069
- base.hasSettings = !!p.settings;
19070
- base.settingsCount = p.settings ? Object.keys(p.settings).length : 0;
19071
- }
19072
- if (p.category === "cli") {
19073
- base.spawn = p.spawn || null;
19074
- base.install = p.install || null;
19075
- }
19076
- return base;
19077
- });
19488
+ const providers = this.providerLoader.getAll().map(toProviderListEntry);
19078
19489
  this.json(res, 200, { providers, count: providers.length });
19079
19490
  }
19080
19491
  async handleProviderConfig(type, _req, res) {
@@ -19266,7 +19677,7 @@ var DevServer = class _DevServer {
19266
19677
  }));
19267
19678
  for (const cdp of this.cdpManagers.values()) {
19268
19679
  if (!cdp.isConnected) {
19269
- cdp._targetId = null;
19680
+ cdp.clearTargetId();
19270
19681
  }
19271
19682
  }
19272
19683
  this.json(res, 200, { reloaded: true, providers });
@@ -19277,12 +19688,12 @@ var DevServer = class _DevServer {
19277
19688
  // ─── DevConsole SPA ───
19278
19689
  getConsoleDistDir() {
19279
19690
  const candidates = [
19280
- path20.resolve(__dirname, "../../web-devconsole/dist"),
19281
- path20.resolve(__dirname, "../../../web-devconsole/dist"),
19282
- path20.join(process.cwd(), "packages/web-devconsole/dist")
19691
+ path21.resolve(__dirname, "../../web-devconsole/dist"),
19692
+ path21.resolve(__dirname, "../../../web-devconsole/dist"),
19693
+ path21.join(process.cwd(), "packages/web-devconsole/dist")
19283
19694
  ];
19284
19695
  for (const dir of candidates) {
19285
- if (fs14.existsSync(path20.join(dir, "index.html"))) return dir;
19696
+ if (fs14.existsSync(path21.join(dir, "index.html"))) return dir;
19286
19697
  }
19287
19698
  return null;
19288
19699
  }
@@ -19292,7 +19703,7 @@ var DevServer = class _DevServer {
19292
19703
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
19293
19704
  return;
19294
19705
  }
19295
- const htmlPath = path20.join(distDir, "index.html");
19706
+ const htmlPath = path21.join(distDir, "index.html");
19296
19707
  try {
19297
19708
  const html = fs14.readFileSync(htmlPath, "utf-8");
19298
19709
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -19317,15 +19728,15 @@ var DevServer = class _DevServer {
19317
19728
  this.json(res, 404, { error: "Not found" });
19318
19729
  return;
19319
19730
  }
19320
- const safePath = path20.normalize(pathname).replace(/^\.\.\//, "");
19321
- const filePath = path20.join(distDir, safePath);
19731
+ const safePath = path21.normalize(pathname).replace(/^\.\.\//, "");
19732
+ const filePath = path21.join(distDir, safePath);
19322
19733
  if (!filePath.startsWith(distDir)) {
19323
19734
  this.json(res, 403, { error: "Forbidden" });
19324
19735
  return;
19325
19736
  }
19326
19737
  try {
19327
19738
  const content = fs14.readFileSync(filePath);
19328
- const ext = path20.extname(filePath);
19739
+ const ext = path21.extname(filePath);
19329
19740
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
19330
19741
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
19331
19742
  res.end(content);
@@ -19438,9 +19849,9 @@ var DevServer = class _DevServer {
19438
19849
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
19439
19850
  if (entry.isDirectory()) {
19440
19851
  files.push({ path: rel, size: 0, type: "dir" });
19441
- scan(path20.join(d, entry.name), rel);
19852
+ scan(path21.join(d, entry.name), rel);
19442
19853
  } else {
19443
- const stat = fs14.statSync(path20.join(d, entry.name));
19854
+ const stat = fs14.statSync(path21.join(d, entry.name));
19444
19855
  files.push({ path: rel, size: stat.size, type: "file" });
19445
19856
  }
19446
19857
  }
@@ -19463,7 +19874,7 @@ var DevServer = class _DevServer {
19463
19874
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
19464
19875
  return;
19465
19876
  }
19466
- const fullPath = path20.resolve(dir, path20.normalize(filePath));
19877
+ const fullPath = path21.resolve(dir, path21.normalize(filePath));
19467
19878
  if (!fullPath.startsWith(dir)) {
19468
19879
  this.json(res, 403, { error: "Forbidden" });
19469
19880
  return;
@@ -19488,14 +19899,14 @@ var DevServer = class _DevServer {
19488
19899
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
19489
19900
  return;
19490
19901
  }
19491
- const fullPath = path20.resolve(dir, path20.normalize(filePath));
19902
+ const fullPath = path21.resolve(dir, path21.normalize(filePath));
19492
19903
  if (!fullPath.startsWith(dir)) {
19493
19904
  this.json(res, 403, { error: "Forbidden" });
19494
19905
  return;
19495
19906
  }
19496
19907
  try {
19497
19908
  if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
19498
- fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
19909
+ fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
19499
19910
  fs14.writeFileSync(fullPath, content, "utf-8");
19500
19911
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
19501
19912
  this.providerLoader.reload();
@@ -19512,7 +19923,7 @@ var DevServer = class _DevServer {
19512
19923
  return;
19513
19924
  }
19514
19925
  for (const name of ["scripts.js", "provider.json"]) {
19515
- const p = path20.join(dir, name);
19926
+ const p = path21.join(dir, name);
19516
19927
  if (fs14.existsSync(p)) {
19517
19928
  const source = fs14.readFileSync(p, "utf-8");
19518
19929
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -19533,8 +19944,8 @@ var DevServer = class _DevServer {
19533
19944
  this.json(res, 404, { error: `Provider not found: ${type}` });
19534
19945
  return;
19535
19946
  }
19536
- const target = fs14.existsSync(path20.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
19537
- const targetPath = path20.join(dir, target);
19947
+ const target = fs14.existsSync(path21.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
19948
+ const targetPath = path21.join(dir, target);
19538
19949
  try {
19539
19950
  if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
19540
19951
  fs14.writeFileSync(targetPath, source, "utf-8");
@@ -19694,7 +20105,7 @@ var DevServer = class _DevServer {
19694
20105
  }
19695
20106
  let targetDir;
19696
20107
  targetDir = this.providerLoader.getUserProviderDir(category, type);
19697
- const jsonPath = path20.join(targetDir, "provider.json");
20108
+ const jsonPath = path21.join(targetDir, "provider.json");
19698
20109
  if (fs14.existsSync(jsonPath)) {
19699
20110
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
19700
20111
  return;
@@ -19706,8 +20117,8 @@ var DevServer = class _DevServer {
19706
20117
  const createdFiles = ["provider.json"];
19707
20118
  if (result.files) {
19708
20119
  for (const [relPath, content] of Object.entries(result.files)) {
19709
- const fullPath = path20.join(targetDir, relPath);
19710
- fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
20120
+ const fullPath = path21.join(targetDir, relPath);
20121
+ fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
19711
20122
  fs14.writeFileSync(fullPath, content, "utf-8");
19712
20123
  createdFiles.push(relPath);
19713
20124
  }
@@ -19760,22 +20171,22 @@ var DevServer = class _DevServer {
19760
20171
  if (!fs14.existsSync(scriptsDir)) return null;
19761
20172
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
19762
20173
  try {
19763
- return fs14.statSync(path20.join(scriptsDir, d)).isDirectory();
20174
+ return fs14.statSync(path21.join(scriptsDir, d)).isDirectory();
19764
20175
  } catch {
19765
20176
  return false;
19766
20177
  }
19767
20178
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
19768
20179
  if (versions.length === 0) return null;
19769
- return path20.join(scriptsDir, versions[0]);
20180
+ return path21.join(scriptsDir, versions[0]);
19770
20181
  }
19771
20182
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
19772
- const canonicalUserDir = path20.resolve(this.providerLoader.getUserProviderDir(category, type));
19773
- const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
19774
- const upstreamRoot = path20.resolve(this.providerLoader.getUpstreamDir());
19775
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
20183
+ const canonicalUserDir = path21.resolve(this.providerLoader.getUserProviderDir(category, type));
20184
+ const desiredDir = requestedDir ? path21.resolve(requestedDir) : canonicalUserDir;
20185
+ const upstreamRoot = path21.resolve(this.providerLoader.getUpstreamDir());
20186
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path21.sep}`)) {
19776
20187
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
19777
20188
  }
19778
- if (path20.basename(desiredDir) !== type) {
20189
+ if (path21.basename(desiredDir) !== type) {
19779
20190
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
19780
20191
  }
19781
20192
  const sourceDir = this.findProviderDir(type);
@@ -19783,11 +20194,11 @@ var DevServer = class _DevServer {
19783
20194
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
19784
20195
  }
19785
20196
  if (!fs14.existsSync(desiredDir)) {
19786
- fs14.mkdirSync(path20.dirname(desiredDir), { recursive: true });
20197
+ fs14.mkdirSync(path21.dirname(desiredDir), { recursive: true });
19787
20198
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
19788
20199
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
19789
20200
  }
19790
- const providerJson = path20.join(desiredDir, "provider.json");
20201
+ const providerJson = path21.join(desiredDir, "provider.json");
19791
20202
  if (!fs14.existsSync(providerJson)) {
19792
20203
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
19793
20204
  }
@@ -19835,7 +20246,7 @@ var DevServer = class _DevServer {
19835
20246
  setMode: "set_mode.js"
19836
20247
  };
19837
20248
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
19838
- const scriptsDir = path20.join(providerDir, "scripts");
20249
+ const scriptsDir = path21.join(providerDir, "scripts");
19839
20250
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
19840
20251
  if (latestScriptsDir) {
19841
20252
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -19846,7 +20257,7 @@ var DevServer = class _DevServer {
19846
20257
  for (const file of fs14.readdirSync(latestScriptsDir)) {
19847
20258
  if (file.endsWith(".js") && targetFileNames.has(file)) {
19848
20259
  try {
19849
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20260
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
19850
20261
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
19851
20262
  lines.push("```javascript");
19852
20263
  lines.push(content);
@@ -19863,7 +20274,7 @@ var DevServer = class _DevServer {
19863
20274
  lines.push("");
19864
20275
  for (const file of refFiles) {
19865
20276
  try {
19866
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20277
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
19867
20278
  lines.push(`### \`${file}\` \u{1F512}`);
19868
20279
  lines.push("```javascript");
19869
20280
  lines.push(content);
@@ -19904,10 +20315,10 @@ var DevServer = class _DevServer {
19904
20315
  lines.push("");
19905
20316
  }
19906
20317
  }
19907
- const docsDir = path20.join(providerDir, "../../docs");
20318
+ const docsDir = path21.join(providerDir, "../../docs");
19908
20319
  const loadGuide = (name) => {
19909
20320
  try {
19910
- const p = path20.join(docsDir, name);
20321
+ const p = path21.join(docsDir, name);
19911
20322
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
19912
20323
  } catch {
19913
20324
  }
@@ -20081,7 +20492,7 @@ var DevServer = class _DevServer {
20081
20492
  parseApproval: "parse_approval.js"
20082
20493
  };
20083
20494
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
20084
- const scriptsDir = path20.join(providerDir, "scripts");
20495
+ const scriptsDir = path21.join(providerDir, "scripts");
20085
20496
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
20086
20497
  if (latestScriptsDir) {
20087
20498
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -20093,7 +20504,7 @@ var DevServer = class _DevServer {
20093
20504
  if (!file.endsWith(".js")) continue;
20094
20505
  if (!targetFileNames.has(file)) continue;
20095
20506
  try {
20096
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20507
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20097
20508
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
20098
20509
  lines.push("```javascript");
20099
20510
  lines.push(content);
@@ -20109,7 +20520,7 @@ var DevServer = class _DevServer {
20109
20520
  lines.push("");
20110
20521
  for (const file of refFiles) {
20111
20522
  try {
20112
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20523
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20113
20524
  lines.push(`### \`${file}\` \u{1F512}`);
20114
20525
  lines.push("```javascript");
20115
20526
  lines.push(content);
@@ -20142,10 +20553,10 @@ var DevServer = class _DevServer {
20142
20553
  lines.push("");
20143
20554
  }
20144
20555
  }
20145
- const docsDir = path20.join(providerDir, "../../docs");
20556
+ const docsDir = path21.join(providerDir, "../../docs");
20146
20557
  const loadGuide = (name) => {
20147
20558
  try {
20148
- const p = path20.join(docsDir, name);
20559
+ const p = path21.join(docsDir, name);
20149
20560
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
20150
20561
  } catch {
20151
20562
  }