@adhdev/daemon-core 0.8.30 → 0.8.32

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 (57) 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 +866 -592
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +868 -595
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/providers/contracts.d.ts +10 -1
  19. package/dist/providers/provider-loader.d.ts +3 -0
  20. package/dist/status/reporter.d.ts +2 -3
  21. package/dist/status/snapshot.d.ts +2 -1
  22. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  23. package/package.json +3 -1
  24. package/src/agent-stream/manager.ts +8 -2
  25. package/src/agent-stream/poller.ts +19 -5
  26. package/src/agent-stream/provider-adapter.ts +11 -7
  27. package/src/agent-stream/types.ts +3 -0
  28. package/src/boot/daemon-lifecycle.ts +7 -6
  29. package/src/cdp/initializer.ts +2 -2
  30. package/src/cdp/manager.ts +5 -0
  31. package/src/cdp/setup.ts +1 -1
  32. package/src/cli-adapter-types.ts +37 -5
  33. package/src/cli-adapters/provider-cli-adapter.ts +212 -795
  34. package/src/cli-adapters/provider-cli-config.ts +66 -0
  35. package/src/cli-adapters/provider-cli-parse.ts +202 -0
  36. package/src/cli-adapters/provider-cli-runtime.ts +142 -0
  37. package/src/cli-adapters/provider-cli-shared.ts +439 -0
  38. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +1 -1
  39. package/src/commands/cdp-commands.ts +6 -1
  40. package/src/commands/chat-commands.ts +45 -29
  41. package/src/commands/cli-manager.ts +28 -9
  42. package/src/commands/handler.ts +14 -10
  43. package/src/commands/router.ts +23 -10
  44. package/src/commands/stream-commands.ts +11 -5
  45. package/src/config/config.ts +4 -10
  46. package/src/daemon/dev-auto-implement.ts +22 -18
  47. package/src/daemon/dev-cli-debug.ts +59 -16
  48. package/src/daemon/dev-server.ts +67 -43
  49. package/src/providers/acp-provider-instance.ts +1 -1
  50. package/src/providers/cli-provider-instance.ts +2 -2
  51. package/src/providers/contracts.ts +12 -1
  52. package/src/providers/extension-provider-instance.ts +1 -1
  53. package/src/providers/ide-provider-instance.ts +39 -18
  54. package/src/providers/provider-loader.ts +85 -54
  55. package/src/providers/version-archive.ts +23 -5
  56. package/src/status/reporter.ts +18 -14
  57. package/src/status/snapshot.ts +5 -4
package/dist/index.js CHANGED
@@ -94,12 +94,10 @@ function ensureMachineId(config) {
94
94
  if (isStableMachineId(config.machineId)) {
95
95
  return { config, changed: false };
96
96
  }
97
- const legacyRegisteredMachineId = !config.registeredMachineId && config.machineSecret && config.machineId ? config.machineId : config.registeredMachineId;
98
97
  return {
99
98
  config: {
100
99
  ...config,
101
- machineId: generateMachineId(),
102
- registeredMachineId: legacyRegisteredMachineId
100
+ machineId: generateMachineId()
103
101
  },
104
102
  changed: true
105
103
  };
@@ -455,7 +453,7 @@ var init_logger = __esm({
455
453
  function isModuleNotFoundError(error, ref) {
456
454
  if (!(error instanceof Error)) return false;
457
455
  const message = error.message || "";
458
- const code = error.code;
456
+ const code = "code" in error ? error.code : void 0;
459
457
  return code === "MODULE_NOT_FOUND" && message.includes(ref);
460
458
  }
461
459
  function normalizeBinding(mod, ref) {
@@ -797,12 +795,7 @@ var init_pty_transport = __esm({
797
795
  }
798
796
  });
799
797
 
800
- // src/cli-adapters/provider-cli-adapter.ts
801
- var provider_cli_adapter_exports = {};
802
- __export(provider_cli_adapter_exports, {
803
- ProviderCliAdapter: () => ProviderCliAdapter,
804
- normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
805
- });
798
+ // src/cli-adapters/provider-cli-shared.ts
806
799
  function stripAnsi(str) {
807
800
  return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
808
801
  }
@@ -812,6 +805,10 @@ function stripTerminalNoise(str) {
812
805
  function sanitizeTerminalText(str) {
813
806
  return stripTerminalNoise(stripAnsi(str));
814
807
  }
808
+ function listCliScriptNames(scripts) {
809
+ if (!scripts) return [];
810
+ return Object.entries(scripts).filter(([, fn]) => typeof fn === "function").map(([name]) => name);
811
+ }
815
812
  function splitCliScreenLines(text) {
816
813
  return String(text || "").replace(/\u0007/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.replace(/\s+$/, ""));
817
814
  }
@@ -859,18 +856,6 @@ function buildCliScreenSnapshot(text) {
859
856
  linesBelowPrompt: promptLineIndex >= 0 ? lines.slice(promptLineIndex + 1) : []
860
857
  };
861
858
  }
862
- function computeTerminalQueryTail(buffer) {
863
- const prefixes = ["\x1B[6n", "\x1B[?6n"];
864
- const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
865
- const start = Math.max(0, buffer.length - maxLength);
866
- for (let i = start; i < buffer.length; i++) {
867
- const suffix = buffer.slice(i);
868
- if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
869
- return suffix;
870
- }
871
- }
872
- return "";
873
- }
874
859
  function findBinary(name) {
875
860
  const trimmed = String(name || "").trim();
876
861
  if (!trimmed) return trimmed;
@@ -1020,25 +1005,306 @@ function coercePatternArray(raw) {
1020
1005
  return raw.map(parsePatternEntry).filter((r) => r != null);
1021
1006
  }
1022
1007
  function normalizeCliProviderForRuntime(raw) {
1023
- const patterns = raw?.patterns || {};
1008
+ const patterns = raw && typeof raw === "object" ? raw.patterns : void 0;
1024
1009
  return {
1025
1010
  patterns: {
1026
- approval: coercePatternArray(patterns.approval)
1011
+ approval: coercePatternArray(
1012
+ patterns && typeof patterns === "object" ? patterns.approval : void 0
1013
+ )
1027
1014
  }
1028
1015
  };
1029
1016
  }
1030
- var os8, path9, import_child_process4, buildCliSpawnEnv, ProviderCliAdapter;
1031
- var init_provider_cli_adapter = __esm({
1032
- "src/cli-adapters/provider-cli-adapter.ts"() {
1017
+ var os8, path9, import_child_process4, buildCliSpawnEnv;
1018
+ var init_provider_cli_shared = __esm({
1019
+ "src/cli-adapters/provider-cli-shared.ts"() {
1033
1020
  "use strict";
1034
1021
  os8 = __toESM(require("os"));
1035
1022
  path9 = __toESM(require("path"));
1036
1023
  import_child_process4 = require("child_process");
1024
+ init_spawn_env();
1025
+ buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
1026
+ }
1027
+ });
1028
+
1029
+ // src/cli-adapters/provider-cli-parse.ts
1030
+ function sliceFromOffset(text, start) {
1031
+ if (!text) return "";
1032
+ if (!Number.isFinite(start) || start <= 0) return text;
1033
+ if (start >= text.length) return "";
1034
+ return text.slice(start);
1035
+ }
1036
+ function hydrateCliParsedMessages(parsedMessages, options) {
1037
+ const { committedMessages, scope, lastOutputAt } = options;
1038
+ const referenceMessages = [...committedMessages];
1039
+ const usedReferenceIndexes = /* @__PURE__ */ new Set();
1040
+ const now = options.now ?? Date.now();
1041
+ const findReferenceTimestamp = (role, content, parsedIndex) => {
1042
+ const normalizedContent = normalizeComparableMessageContent(content);
1043
+ if (!normalizedContent) return void 0;
1044
+ const sameIndex = referenceMessages[parsedIndex];
1045
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1046
+ usedReferenceIndexes.add(parsedIndex);
1047
+ return sameIndex.timestamp;
1048
+ }
1049
+ for (let i = 0; i < referenceMessages.length; i++) {
1050
+ if (usedReferenceIndexes.has(i)) continue;
1051
+ const candidate = referenceMessages[i];
1052
+ if (!candidate || candidate.role !== role) continue;
1053
+ const candidateContent = normalizeComparableMessageContent(candidate.content);
1054
+ if (!candidateContent) continue;
1055
+ const exactMatch = candidateContent === normalizedContent;
1056
+ const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1057
+ if (!exactMatch && !fuzzyMatch) continue;
1058
+ if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1059
+ usedReferenceIndexes.add(i);
1060
+ return candidate.timestamp;
1061
+ }
1062
+ }
1063
+ return void 0;
1064
+ };
1065
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1066
+ const role = message.role;
1067
+ const content = typeof message.content === "string" ? message.content : String(message.content || "");
1068
+ const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1069
+ const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1070
+ const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
1071
+ const timestamp = referenceTimestamp ?? fallbackTimestamp;
1072
+ return {
1073
+ ...message,
1074
+ role,
1075
+ content,
1076
+ timestamp,
1077
+ receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1078
+ };
1079
+ });
1080
+ }
1081
+ function normalizeCliParsedMessages(parsedMessages, options) {
1082
+ return hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
1083
+ role: message.role,
1084
+ content: message.content,
1085
+ timestamp: message.timestamp,
1086
+ receivedAt: message.receivedAt,
1087
+ kind: message.kind,
1088
+ id: message.id,
1089
+ index: message.index,
1090
+ meta: message.meta,
1091
+ senderName: message.senderName
1092
+ }));
1093
+ }
1094
+ function buildCliParseInput(options) {
1095
+ const {
1096
+ accumulatedBuffer,
1097
+ accumulatedRawBuffer,
1098
+ recentOutputBuffer,
1099
+ terminalScreenText,
1100
+ baseMessages,
1101
+ partialResponse,
1102
+ scope,
1103
+ runtimeSettings
1104
+ } = options;
1105
+ const buffer = scope ? sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer : accumulatedBuffer;
1106
+ const rawBuffer = scope ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer : accumulatedRawBuffer;
1107
+ const screenText = terminalScreenText;
1108
+ const recentBuffer = buffer.slice(-1e3) || recentOutputBuffer;
1109
+ return {
1110
+ buffer,
1111
+ rawBuffer,
1112
+ recentBuffer,
1113
+ screenText,
1114
+ screen: buildCliScreenSnapshot(screenText),
1115
+ bufferScreen: buildCliScreenSnapshot(buffer),
1116
+ recentScreen: buildCliScreenSnapshot(recentBuffer),
1117
+ messages: [...baseMessages],
1118
+ partialResponse,
1119
+ promptText: scope?.prompt || "",
1120
+ settings: { ...runtimeSettings }
1121
+ };
1122
+ }
1123
+ function summarizeCliTraceText(text, max = 800) {
1124
+ const value = sanitizeTerminalText(String(text || ""));
1125
+ if (value.length <= max) return value;
1126
+ return `\u2026${value.slice(-max)}`;
1127
+ }
1128
+ function summarizeCliTraceMessages(messages, limit = 3) {
1129
+ return messages.slice(-limit).map((message) => ({
1130
+ role: message.role,
1131
+ content: summarizeCliTraceText(message.content, 240),
1132
+ timestamp: message.timestamp
1133
+ }));
1134
+ }
1135
+ function buildCliTraceParseSnapshot(options) {
1136
+ const { accumulatedBuffer, accumulatedRawBuffer, responseBuffer, partialResponse, scope } = options;
1137
+ const scopedBuffer = scope ? sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer : accumulatedBuffer;
1138
+ const scopedRawBuffer = scope ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer : accumulatedRawBuffer;
1139
+ return {
1140
+ currentTurnScope: scope || null,
1141
+ responseBuffer: summarizeCliTraceText(responseBuffer, 1200),
1142
+ partialResponse: summarizeCliTraceText(partialResponse || responseBuffer, 1200),
1143
+ turnBuffer: summarizeCliTraceText(scopedBuffer, 1600),
1144
+ turnRawPreview: summarizeCliTraceText(scopedRawBuffer, 1600),
1145
+ turnSanitizedRawPreview: summarizeCliTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
1146
+ };
1147
+ }
1148
+ var init_provider_cli_parse = __esm({
1149
+ "src/cli-adapters/provider-cli-parse.ts"() {
1150
+ "use strict";
1151
+ init_provider_cli_shared();
1152
+ }
1153
+ });
1154
+
1155
+ // src/cli-adapters/provider-cli-config.ts
1156
+ function resolveCliAdapterConfig(provider) {
1157
+ const t = provider.timeouts || {};
1158
+ const rawKeys = provider.approvalKeys;
1159
+ return {
1160
+ timeouts: {
1161
+ ptyFlush: t.ptyFlush ?? 50,
1162
+ dialogAccept: t.dialogAccept ?? 300,
1163
+ approvalCooldown: t.approvalCooldown ?? 3e3,
1164
+ generatingIdle: t.generatingIdle ?? 6e3,
1165
+ idleFinish: t.idleFinish ?? 5e3,
1166
+ maxResponse: t.maxResponse ?? 3e5,
1167
+ shutdownGrace: t.shutdownGrace ?? 1e3,
1168
+ outputSettle: t.outputSettle ?? 300
1169
+ },
1170
+ approvalKeys: rawKeys && typeof rawKeys === "object" ? rawKeys : {},
1171
+ sendDelayMs: typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0,
1172
+ sendKey: typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r",
1173
+ submitStrategy: provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo",
1174
+ providerResolutionMeta: {
1175
+ type: provider.type,
1176
+ name: provider.name,
1177
+ resolvedVersion: provider._resolvedVersion || null,
1178
+ resolvedOs: provider._resolvedOs || null,
1179
+ providerDir: provider._resolvedProviderDir || null,
1180
+ scriptDir: provider._resolvedScriptDir || null,
1181
+ scriptsPath: provider._resolvedScriptsPath || null,
1182
+ scriptsSource: provider._resolvedScriptsSource || null,
1183
+ versionWarning: provider._versionWarning || null
1184
+ }
1185
+ };
1186
+ }
1187
+ var init_provider_cli_config = __esm({
1188
+ "src/cli-adapters/provider-cli-config.ts"() {
1189
+ "use strict";
1190
+ }
1191
+ });
1192
+
1193
+ // src/cli-adapters/provider-cli-runtime.ts
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 "";
1278
+ }
1279
+ var os9, path10;
1280
+ var init_provider_cli_runtime = __esm({
1281
+ "src/cli-adapters/provider-cli-runtime.ts"() {
1282
+ "use strict";
1283
+ os9 = __toESM(require("os"));
1284
+ path10 = __toESM(require("path"));
1285
+ init_provider_cli_shared();
1286
+ }
1287
+ });
1288
+
1289
+ // src/cli-adapters/provider-cli-adapter.ts
1290
+ var provider_cli_adapter_exports = {};
1291
+ __export(provider_cli_adapter_exports, {
1292
+ ProviderCliAdapter: () => ProviderCliAdapter,
1293
+ normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
1294
+ });
1295
+ var os10, ProviderCliAdapter;
1296
+ var init_provider_cli_adapter = __esm({
1297
+ "src/cli-adapters/provider-cli-adapter.ts"() {
1298
+ "use strict";
1299
+ os10 = __toESM(require("os"));
1037
1300
  init_logger();
1038
1301
  init_terminal_screen();
1039
1302
  init_pty_transport();
1040
- init_spawn_env();
1041
- buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
1303
+ init_provider_cli_shared();
1304
+ init_provider_cli_parse();
1305
+ init_provider_cli_config();
1306
+ init_provider_cli_runtime();
1307
+ init_provider_cli_shared();
1042
1308
  ProviderCliAdapter = class _ProviderCliAdapter {
1043
1309
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
1044
1310
  this.extraArgs = extraArgs;
@@ -1046,36 +1312,16 @@ var init_provider_cli_adapter = __esm({
1046
1312
  this.transportFactory = transportFactory;
1047
1313
  this.cliType = provider.type;
1048
1314
  this.cliName = provider.name;
1049
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os8.homedir()) : workingDir;
1050
- const t = provider.timeouts || {};
1051
- this.timeouts = {
1052
- ptyFlush: t.ptyFlush ?? 50,
1053
- dialogAccept: t.dialogAccept ?? 300,
1054
- approvalCooldown: t.approvalCooldown ?? 3e3,
1055
- generatingIdle: t.generatingIdle ?? 6e3,
1056
- idleFinish: t.idleFinish ?? 5e3,
1057
- maxResponse: t.maxResponse ?? 3e5,
1058
- shutdownGrace: t.shutdownGrace ?? 1e3,
1059
- outputSettle: t.outputSettle ?? 300
1060
- };
1061
- const rawKeys = provider.approvalKeys;
1062
- this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
1063
- this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
1064
- this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
1065
- this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
1066
- this.providerResolutionMeta = {
1067
- type: provider.type,
1068
- name: provider.name,
1069
- resolvedVersion: provider._resolvedVersion || null,
1070
- resolvedOs: provider._resolvedOs || null,
1071
- providerDir: provider._resolvedProviderDir || null,
1072
- scriptDir: provider._resolvedScriptDir || null,
1073
- scriptsPath: provider._resolvedScriptsPath || null,
1074
- scriptsSource: provider._resolvedScriptsSource || null,
1075
- versionWarning: provider._versionWarning || null
1076
- };
1315
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os10.homedir()) : workingDir;
1316
+ const resolvedConfig = resolveCliAdapterConfig(provider);
1317
+ this.timeouts = resolvedConfig.timeouts;
1318
+ this.approvalKeys = resolvedConfig.approvalKeys;
1319
+ this.sendDelayMs = resolvedConfig.sendDelayMs;
1320
+ this.sendKey = resolvedConfig.sendKey;
1321
+ this.submitStrategy = resolvedConfig.submitStrategy;
1322
+ this.providerResolutionMeta = resolvedConfig.providerResolutionMeta;
1077
1323
  this.cliScripts = provider.scripts || {};
1078
- const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
1324
+ const scriptNames = listCliScriptNames(this.cliScripts);
1079
1325
  if (scriptNames.length > 0) {
1080
1326
  LOG.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
1081
1327
  LOG.info(
@@ -1172,88 +1418,6 @@ var init_provider_cli_adapter = __esm({
1172
1418
  this.messages = [...this.committedMessages];
1173
1419
  this.structuredMessages = [...this.committedMessages];
1174
1420
  }
1175
- hydrateParsedMessages(parsedMessages, scope) {
1176
- const referenceMessages = [...this.committedMessages];
1177
- const usedReferenceIndexes = /* @__PURE__ */ new Set();
1178
- const now = Date.now();
1179
- const findReferenceTimestamp = (role, content, parsedIndex) => {
1180
- const normalizedContent = normalizeComparableMessageContent(content);
1181
- if (!normalizedContent) return void 0;
1182
- const sameIndex = referenceMessages[parsedIndex];
1183
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1184
- usedReferenceIndexes.add(parsedIndex);
1185
- return sameIndex.timestamp;
1186
- }
1187
- for (let i = 0; i < referenceMessages.length; i++) {
1188
- if (usedReferenceIndexes.has(i)) continue;
1189
- const candidate = referenceMessages[i];
1190
- if (!candidate || candidate.role !== role) continue;
1191
- const candidateContent = normalizeComparableMessageContent(candidate.content);
1192
- if (!candidateContent) continue;
1193
- const exactMatch = candidateContent === normalizedContent;
1194
- const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1195
- if (!exactMatch && !fuzzyMatch) continue;
1196
- if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1197
- usedReferenceIndexes.add(i);
1198
- return candidate.timestamp;
1199
- }
1200
- }
1201
- return void 0;
1202
- };
1203
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1204
- const role = message.role;
1205
- const content = typeof message.content === "string" ? message.content : String(message.content || "");
1206
- const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1207
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1208
- const fallbackTimestamp = role === "user" ? scope?.startedAt || now : this.lastOutputAt || scope?.startedAt || now;
1209
- const timestamp = referenceTimestamp ?? fallbackTimestamp;
1210
- return {
1211
- ...message,
1212
- role,
1213
- content,
1214
- timestamp,
1215
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1216
- };
1217
- });
1218
- }
1219
- normalizeParsedMessages(parsedMessages, scope) {
1220
- return this.hydrateParsedMessages(parsedMessages, scope).map((message) => ({
1221
- role: message.role,
1222
- content: message.content,
1223
- timestamp: message.timestamp,
1224
- receivedAt: message.receivedAt,
1225
- kind: message.kind,
1226
- id: message.id,
1227
- index: message.index,
1228
- meta: message.meta,
1229
- senderName: message.senderName
1230
- }));
1231
- }
1232
- sliceFromOffset(text, start) {
1233
- if (!text) return "";
1234
- if (!Number.isFinite(start) || start <= 0) return text;
1235
- if (start >= text.length) return "";
1236
- return text.slice(start);
1237
- }
1238
- buildParseInput(baseMessages, partialResponse, scope) {
1239
- const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1240
- const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
1241
- const screenText = this.terminalScreen.getText();
1242
- const recentBuffer = buffer.slice(-1e3) || this.recentOutputBuffer;
1243
- return {
1244
- buffer,
1245
- rawBuffer,
1246
- recentBuffer,
1247
- screenText,
1248
- screen: buildCliScreenSnapshot(screenText),
1249
- bufferScreen: buildCliScreenSnapshot(buffer),
1250
- recentScreen: buildCliScreenSnapshot(recentBuffer),
1251
- messages: [...baseMessages],
1252
- partialResponse,
1253
- promptText: scope?.prompt || "",
1254
- settings: { ...this.runtimeSettings }
1255
- };
1256
- }
1257
1421
  setStatus(status, trigger) {
1258
1422
  const prev = this.currentStatus;
1259
1423
  if (prev === status) return;
@@ -1286,7 +1450,13 @@ var init_provider_cli_adapter = __esm({
1286
1450
  this.recordTrace("idle_candidate_armed", {
1287
1451
  confirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
1288
1452
  candidate: this.idleFinishCandidate,
1289
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
1453
+ ...buildCliTraceParseSnapshot({
1454
+ accumulatedBuffer: this.accumulatedBuffer,
1455
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
1456
+ responseBuffer: this.responseBuffer,
1457
+ partialResponse: this.responseBuffer,
1458
+ scope: this.currentTurnScope
1459
+ })
1290
1460
  });
1291
1461
  if (this.settleTimer) clearTimeout(this.settleTimer);
1292
1462
  this.settleTimer = setTimeout(() => {
@@ -1295,30 +1465,6 @@ var init_provider_cli_adapter = __esm({
1295
1465
  this.evaluateSettled();
1296
1466
  }, _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS);
1297
1467
  }
1298
- summarizeTraceText(text, max = 800) {
1299
- const value = sanitizeTerminalText(String(text || ""));
1300
- if (value.length <= max) return value;
1301
- return `\u2026${value.slice(-max)}`;
1302
- }
1303
- summarizeTraceMessages(messages, limit = 3) {
1304
- return messages.slice(-limit).map((message) => ({
1305
- role: message.role,
1306
- content: this.summarizeTraceText(message.content, 240),
1307
- timestamp: message.timestamp
1308
- }));
1309
- }
1310
- buildTraceParseSnapshot(scope, partialResponse = "") {
1311
- const scopedBuffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1312
- const scopedRawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
1313
- return {
1314
- currentTurnScope: scope || null,
1315
- responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
1316
- partialResponse: this.summarizeTraceText(partialResponse || this.responseBuffer, 1200),
1317
- turnBuffer: this.summarizeTraceText(scopedBuffer, 1600),
1318
- turnRawPreview: this.summarizeTraceText(scopedRawBuffer, 1600),
1319
- turnSanitizedRawPreview: this.summarizeTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
1320
- };
1321
- }
1322
1468
  recordTrace(type, payload = {}) {
1323
1469
  const entry = {
1324
1470
  id: ++this.traceSeq,
@@ -1354,7 +1500,7 @@ var init_provider_cli_adapter = __esm({
1354
1500
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
1355
1501
  setCliScripts(scripts) {
1356
1502
  this.cliScripts = scripts;
1357
- const scriptNames = Object.keys(scripts).filter((k) => typeof scripts[k] === "function");
1503
+ const scriptNames = listCliScriptNames(scripts);
1358
1504
  LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
1359
1505
  }
1360
1506
  updateRuntimeSettings(settings) {
@@ -1386,72 +1532,42 @@ var init_provider_cli_adapter = __esm({
1386
1532
  }
1387
1533
  async spawn() {
1388
1534
  if (this.ptyProcess) return;
1389
- const { spawn: spawnConfig } = this.provider;
1390
- const configuredCommand = typeof this.runtimeSettings.executablePath === "string" && this.runtimeSettings.executablePath.trim() ? this.runtimeSettings.executablePath.trim() : spawnConfig.command;
1391
- const binaryPath = findBinary(configuredCommand);
1392
- const isWin = os8.platform() === "win32";
1393
- const allArgs = [...spawnConfig.args, ...this.extraArgs];
1535
+ const spawnPlan = resolveCliSpawnPlan({
1536
+ provider: this.provider,
1537
+ runtimeSettings: this.runtimeSettings,
1538
+ workingDir: this.workingDir,
1539
+ extraArgs: this.extraArgs
1540
+ });
1394
1541
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1395
1542
  this.resetTraceSession();
1396
- let shellCmd;
1397
- let shellArgs;
1398
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1399
- const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1400
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1401
- const useShell = isWin ? useShellWin : useShellUnix;
1402
- if (useShell) {
1403
- if (!spawnConfig.shell && !isWin) {
1404
- LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
1405
- }
1406
- if (isCmdShim) {
1407
- LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell for .cmd/.bat shim: ${binaryPath}`);
1408
- } else if (isWin) {
1409
- LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell on Windows: ${binaryPath}`);
1410
- }
1411
- shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
1412
- if (isWin) {
1413
- shellArgs = ["/c", binaryPath, ...allArgs];
1414
- } else {
1415
- const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1416
- shellArgs = ["-l", "-c", fullCmd];
1417
- }
1418
- } else {
1419
- if (isWin && spawnConfig.shell) {
1420
- LOG.info("CLI", `[${this.cliType}] Spawning Windows binary directly without cmd.exe: ${binaryPath}`);
1421
- }
1422
- shellCmd = binaryPath;
1423
- shellArgs = allArgs;
1424
- }
1425
- const ptyOpts = {
1426
- cols: 80,
1427
- rows: 24,
1428
- cwd: this.workingDir,
1429
- env: buildCliSpawnEnv(process.env, spawnConfig.env)
1430
- };
1431
1543
  this.recordTrace("spawn", {
1432
- shellCommand: shellCmd,
1433
- shellArgs,
1434
- cwd: ptyOpts.cwd,
1435
- cols: ptyOpts.cols,
1436
- rows: ptyOpts.rows,
1544
+ shellCommand: spawnPlan.shellCmd,
1545
+ shellArgs: spawnPlan.shellArgs,
1546
+ cwd: spawnPlan.ptyOptions.cwd,
1547
+ cols: spawnPlan.ptyOptions.cols,
1548
+ rows: spawnPlan.ptyOptions.rows,
1437
1549
  providerResolution: this.providerResolutionMeta
1438
1550
  });
1439
1551
  try {
1440
- this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1552
+ this.ptyProcess = this.transportFactory.spawn(
1553
+ spawnPlan.shellCmd,
1554
+ spawnPlan.shellArgs,
1555
+ spawnPlan.ptyOptions
1556
+ );
1441
1557
  } catch (err) {
1442
1558
  const msg = err?.message || String(err);
1443
- if (!isWin && !useShell && /posix_spawn|spawn/i.test(msg)) {
1559
+ if (!spawnPlan.isWin && !spawnPlan.useShell && /posix_spawn|spawn/i.test(msg)) {
1444
1560
  LOG.warn("CLI", `[${this.cliType}] Direct spawn failed (${msg}), retrying via login shell`);
1445
- shellCmd = process.env.SHELL || "/bin/zsh";
1446
- const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1447
- shellArgs = ["-l", "-c", fullCmd];
1448
- this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1561
+ const retryPlan = buildCliLoginShellRetry(spawnPlan);
1562
+ this.ptyProcess = this.transportFactory.spawn(
1563
+ retryPlan.shellCmd,
1564
+ retryPlan.shellArgs,
1565
+ spawnPlan.ptyOptions
1566
+ );
1449
1567
  } else {
1450
- if (isWin) {
1451
- 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})` : "";
1452
- if (hint) {
1453
- throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1454
- }
1568
+ const hint = getCliSpawnErrorHint(msg, spawnPlan.shellCmd, spawnPlan.isWin);
1569
+ if (hint) {
1570
+ throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1455
1571
  }
1456
1572
  throw err;
1457
1573
  }
@@ -1459,7 +1575,12 @@ var init_provider_cli_adapter = __esm({
1459
1575
  this.ptyProcess.onData((data) => {
1460
1576
  if (Date.now() < this.resizeSuppressUntil) return;
1461
1577
  if (!this.ptyProcess?.terminalQueriesHandled) {
1462
- this.respondToTerminalQueries(data);
1578
+ this.pendingTerminalQueryTail = respondToCliTerminalQueries({
1579
+ ptyProcess: this.ptyProcess,
1580
+ pendingTail: this.pendingTerminalQueryTail,
1581
+ data,
1582
+ terminalScreen: this.terminalScreen
1583
+ });
1463
1584
  }
1464
1585
  this.pendingOutputParseBuffer += data;
1465
1586
  if (!this.pendingOutputParseTimer) {
@@ -1538,9 +1659,9 @@ var init_provider_cli_adapter = __esm({
1538
1659
  this.recordTrace("output", {
1539
1660
  rawLength: rawData.length,
1540
1661
  cleanLength: cleanData.length,
1541
- rawPreview: this.summarizeTraceText(rawData, 300),
1542
- cleanPreview: this.summarizeTraceText(cleanData, 300),
1543
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 1200)
1662
+ rawPreview: summarizeCliTraceText(rawData, 300),
1663
+ cleanPreview: summarizeCliTraceText(cleanData, 300),
1664
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 1200)
1544
1665
  });
1545
1666
  if (this.startupParseGate) {
1546
1667
  this.scheduleStartupSettleCheck();
@@ -1771,7 +1892,7 @@ var init_provider_cli_adapter = __esm({
1771
1892
  loggedWait = true;
1772
1893
  LOG.info(
1773
1894
  "CLI",
1774
- `[${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)}`
1895
+ `[${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)}`
1775
1896
  );
1776
1897
  }
1777
1898
  await new Promise((resolve12) => setTimeout(resolve12, 50));
@@ -1779,7 +1900,7 @@ var init_provider_cli_adapter = __esm({
1779
1900
  const finalScreenText = this.terminalScreen.getText() || "";
1780
1901
  LOG.warn(
1781
1902
  "CLI",
1782
- `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(this.summarizeTraceText(finalScreenText, 240)).slice(0, 280)}`
1903
+ `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
1783
1904
  );
1784
1905
  }
1785
1906
  evaluateSettled() {
@@ -1809,23 +1930,33 @@ var init_provider_cli_adapter = __esm({
1809
1930
  this.responseBuffer,
1810
1931
  this.currentTurnScope
1811
1932
  );
1812
- const parsedMessages = Array.isArray(parsedTranscript?.messages) ? this.normalizeParsedMessages(parsedTranscript.messages) : [];
1933
+ const parsedMessages = Array.isArray(parsedTranscript?.messages) ? normalizeCliParsedMessages(parsedTranscript.messages, {
1934
+ committedMessages: this.committedMessages,
1935
+ scope: this.currentTurnScope,
1936
+ lastOutputAt: this.lastOutputAt
1937
+ }) : [];
1813
1938
  const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
1814
1939
  this.recordTrace("settled", {
1815
- tail: this.summarizeTraceText(tail, 500),
1816
- screenText: this.summarizeTraceText(screenText, 1200),
1940
+ tail: summarizeCliTraceText(tail, 500),
1941
+ screenText: summarizeCliTraceText(screenText, 1200),
1817
1942
  detectStatus: scriptStatus,
1818
1943
  parsedStatus: parsedTranscript?.status || null,
1819
1944
  parsedMessageCount: parsedMessages.length,
1820
- parsedLastAssistant: lastParsedAssistant ? this.summarizeTraceText(lastParsedAssistant.content, 280) : "",
1945
+ parsedLastAssistant: lastParsedAssistant ? summarizeCliTraceText(lastParsedAssistant.content, 280) : "",
1821
1946
  parsedActiveModal: parsedTranscript?.activeModal ?? null,
1822
1947
  approval: modal,
1823
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
1948
+ ...buildCliTraceParseSnapshot({
1949
+ accumulatedBuffer: this.accumulatedBuffer,
1950
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
1951
+ responseBuffer: this.responseBuffer,
1952
+ partialResponse: this.responseBuffer,
1953
+ scope: this.currentTurnScope
1954
+ })
1824
1955
  });
1825
1956
  if (this.currentTurnScope && !lastParsedAssistant) {
1826
1957
  LOG.info(
1827
1958
  "CLI",
1828
- `[${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 || "-"}`
1959
+ `[${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 || "-"}`
1829
1960
  );
1830
1961
  }
1831
1962
  if (!scriptStatus) return;
@@ -1879,7 +2010,13 @@ var init_provider_cli_adapter = __esm({
1879
2010
  lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
1880
2011
  lastScreenChangeAt: this.lastScreenChangeAt,
1881
2012
  holdMs: _ProviderCliAdapter.STATUS_ACTIVITY_HOLD_MS,
1882
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2013
+ ...buildCliTraceParseSnapshot({
2014
+ accumulatedBuffer: this.accumulatedBuffer,
2015
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2016
+ responseBuffer: this.responseBuffer,
2017
+ partialResponse: this.responseBuffer,
2018
+ scope: this.currentTurnScope
2019
+ })
1883
2020
  });
1884
2021
  this.onStatusChange?.();
1885
2022
  return;
@@ -1983,7 +2120,13 @@ var init_provider_cli_adapter = __esm({
1983
2120
  canFinishImmediately,
1984
2121
  submitPendingUntil: this.submitPendingUntil,
1985
2122
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
1986
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2123
+ ...buildCliTraceParseSnapshot({
2124
+ accumulatedBuffer: this.accumulatedBuffer,
2125
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2126
+ responseBuffer: this.responseBuffer,
2127
+ partialResponse: this.responseBuffer,
2128
+ scope: this.currentTurnScope
2129
+ })
1987
2130
  });
1988
2131
  if (canFinishImmediately) {
1989
2132
  this.clearIdleFinishCandidate("finish_response");
@@ -2018,7 +2161,13 @@ var init_provider_cli_adapter = __esm({
2018
2161
  if (this.responseSettleIgnoreUntil > Date.now()) return;
2019
2162
  this.clearIdleFinishCandidate("finish_response_enter");
2020
2163
  this.recordTrace("finish_response", {
2021
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2164
+ ...buildCliTraceParseSnapshot({
2165
+ accumulatedBuffer: this.accumulatedBuffer,
2166
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2167
+ responseBuffer: this.responseBuffer,
2168
+ partialResponse: this.responseBuffer,
2169
+ scope: this.currentTurnScope
2170
+ })
2022
2171
  });
2023
2172
  const commitResult = this.commitCurrentTranscript();
2024
2173
  if (this.shouldRetryFinishResponse(commitResult)) {
@@ -2026,8 +2175,14 @@ var init_provider_cli_adapter = __esm({
2026
2175
  this.recordTrace("finish_response_retry", {
2027
2176
  retryCount: this.finishRetryCount,
2028
2177
  retryDelayMs: _ProviderCliAdapter.FINISH_RETRY_DELAY_MS,
2029
- assistantContent: this.summarizeTraceText(commitResult.assistantContent, 220),
2030
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2178
+ assistantContent: summarizeCliTraceText(commitResult.assistantContent, 220),
2179
+ ...buildCliTraceParseSnapshot({
2180
+ accumulatedBuffer: this.accumulatedBuffer,
2181
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2182
+ responseBuffer: this.responseBuffer,
2183
+ partialResponse: this.responseBuffer,
2184
+ scope: this.currentTurnScope
2185
+ })
2031
2186
  });
2032
2187
  if (this.finishRetryTimer) clearTimeout(this.finishRetryTimer);
2033
2188
  this.finishRetryTimer = setTimeout(() => {
@@ -2076,7 +2231,11 @@ var init_provider_cli_adapter = __esm({
2076
2231
  this.currentTurnScope
2077
2232
  );
2078
2233
  if (parsed && Array.isArray(parsed.messages)) {
2079
- this.committedMessages = this.normalizeParsedMessages(parsed.messages, this.currentTurnScope);
2234
+ this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
2235
+ committedMessages: this.committedMessages,
2236
+ scope: this.currentTurnScope,
2237
+ lastOutputAt: this.lastOutputAt
2238
+ });
2080
2239
  const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
2081
2240
  if (promptForTrim) {
2082
2241
  const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
@@ -2089,14 +2248,20 @@ var init_provider_cli_adapter = __esm({
2089
2248
  this.recordTrace("commit_transcript", {
2090
2249
  parsedStatus: parsed.status || null,
2091
2250
  messageCount: this.committedMessages.length,
2092
- lastAssistant: lastAssistant ? this.summarizeTraceText(lastAssistant.content, 320) : "",
2093
- messages: this.summarizeTraceMessages(this.committedMessages),
2094
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2251
+ lastAssistant: lastAssistant ? summarizeCliTraceText(lastAssistant.content, 320) : "",
2252
+ messages: summarizeCliTraceMessages(this.committedMessages),
2253
+ ...buildCliTraceParseSnapshot({
2254
+ accumulatedBuffer: this.accumulatedBuffer,
2255
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2256
+ responseBuffer: this.responseBuffer,
2257
+ partialResponse: this.responseBuffer,
2258
+ scope: this.currentTurnScope
2259
+ })
2095
2260
  });
2096
2261
  if (!lastAssistant && this.currentTurnScope) {
2097
2262
  LOG.warn(
2098
2263
  "CLI",
2099
- `[${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 || "-"}`
2264
+ `[${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 || "-"}`
2100
2265
  );
2101
2266
  }
2102
2267
  return {
@@ -2188,7 +2353,11 @@ var init_provider_cli_adapter = __esm({
2188
2353
  index: typeof message.index === "number" ? message.index : index,
2189
2354
  kind: message.kind || "standard",
2190
2355
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2191
- })) : this.hydrateParsedMessages(parsed.messages, this.currentTurnScope);
2356
+ })) : hydrateCliParsedMessages(parsed.messages, {
2357
+ committedMessages: this.committedMessages,
2358
+ scope: this.currentTurnScope,
2359
+ lastOutputAt: this.lastOutputAt
2360
+ });
2192
2361
  return {
2193
2362
  id: parsed.id || "cli_session",
2194
2363
  status: parsed.status || this.currentStatus,
@@ -2219,11 +2388,16 @@ var init_provider_cli_adapter = __esm({
2219
2388
  if (typeof fn !== "function") {
2220
2389
  throw new Error(`CLI script '${scriptName}' not available`);
2221
2390
  }
2222
- const input = this.buildParseInput(
2223
- this.committedMessages,
2224
- this.responseBuffer,
2225
- this.currentTurnScope
2226
- );
2391
+ const input = buildCliParseInput({
2392
+ accumulatedBuffer: this.accumulatedBuffer,
2393
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2394
+ recentOutputBuffer: this.recentOutputBuffer,
2395
+ terminalScreenText: this.terminalScreen.getText(),
2396
+ baseMessages: this.committedMessages,
2397
+ partialResponse: this.responseBuffer,
2398
+ scope: this.currentTurnScope,
2399
+ runtimeSettings: this.runtimeSettings
2400
+ });
2227
2401
  return await Promise.resolve(fn({
2228
2402
  ...input,
2229
2403
  args: args && typeof args === "object" ? { ...args } : {}
@@ -2232,7 +2406,16 @@ var init_provider_cli_adapter = __esm({
2232
2406
  parseCurrentTranscript(baseMessages, partialResponse, scope) {
2233
2407
  if (!this.cliScripts?.parseOutput) return null;
2234
2408
  try {
2235
- const input = this.buildParseInput(baseMessages, partialResponse, scope);
2409
+ const input = buildCliParseInput({
2410
+ accumulatedBuffer: this.accumulatedBuffer,
2411
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2412
+ recentOutputBuffer: this.recentOutputBuffer,
2413
+ terminalScreenText: this.terminalScreen.getText(),
2414
+ baseMessages,
2415
+ partialResponse,
2416
+ scope,
2417
+ runtimeSettings: this.runtimeSettings
2418
+ });
2236
2419
  const parsed = this.cliScripts.parseOutput(input);
2237
2420
  const refinedStatus = this.refineDetectedStatus(typeof parsed?.status === "string" ? parsed.status : null, input.recentBuffer, input.screenText);
2238
2421
  if (parsed && refinedStatus && parsed.status !== refinedStatus) {
@@ -2322,7 +2505,7 @@ ${data.message || ""}`.trim();
2322
2505
  rawBufferStart: this.accumulatedRawBuffer.length
2323
2506
  };
2324
2507
  this.recordTrace("send_message", {
2325
- text: this.summarizeTraceText(text, 500),
2508
+ text: summarizeCliTraceText(text, 500),
2326
2509
  estimatedLines: estimatePromptDisplayLines(text),
2327
2510
  turnScope: this.currentTurnScope
2328
2511
  });
@@ -2356,7 +2539,7 @@ ${data.message || ""}`.trim();
2356
2539
  this.recordTrace("submit_write", {
2357
2540
  mode: "submit_key",
2358
2541
  sendKey: this.sendKey,
2359
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2542
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2360
2543
  });
2361
2544
  this.ptyProcess.write(this.sendKey);
2362
2545
  const retrySubmitIfStuck = (attempt) => {
@@ -2373,7 +2556,7 @@ ${data.message || ""}`.trim();
2373
2556
  mode: "submit_retry",
2374
2557
  attempt,
2375
2558
  sendKey: this.sendKey,
2376
- screenText: this.summarizeTraceText(screenText, 500)
2559
+ screenText: summarizeCliTraceText(screenText, 500)
2377
2560
  });
2378
2561
  this.ptyProcess.write(this.sendKey);
2379
2562
  if (attempt >= 3) {
@@ -2389,9 +2572,9 @@ ${data.message || ""}`.trim();
2389
2572
  this.submitPendingUntil = 0;
2390
2573
  this.recordTrace("submit_write", {
2391
2574
  mode: "immediate",
2392
- text: this.summarizeTraceText(text, 500),
2575
+ text: summarizeCliTraceText(text, 500),
2393
2576
  sendKey: this.sendKey,
2394
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2577
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2395
2578
  });
2396
2579
  this.ptyProcess.write(text + this.sendKey);
2397
2580
  this.submitRetryTimer = setTimeout(() => {
@@ -2407,7 +2590,7 @@ ${data.message || ""}`.trim();
2407
2590
  mode: "immediate_retry",
2408
2591
  attempt: 1,
2409
2592
  sendKey: this.sendKey,
2410
- screenText: this.summarizeTraceText(screenText, 500)
2593
+ screenText: summarizeCliTraceText(screenText, 500)
2411
2594
  });
2412
2595
  this.ptyProcess.write(this.sendKey);
2413
2596
  this.submitRetryUsed = true;
@@ -2421,9 +2604,9 @@ ${data.message || ""}`.trim();
2421
2604
  this.ptyProcess.write(text);
2422
2605
  this.recordTrace("submit_write", {
2423
2606
  mode: "type_then_submit",
2424
- text: this.summarizeTraceText(text, 500),
2607
+ text: summarizeCliTraceText(text, 500),
2425
2608
  sendKey: this.sendKey,
2426
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2609
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2427
2610
  });
2428
2611
  const submitStartedAt = Date.now();
2429
2612
  let lastNormalizedScreen = "";
@@ -2758,7 +2941,7 @@ ${data.message || ""}`.trim();
2758
2941
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
2759
2942
  resizeSuppressUntil: this.resizeSuppressUntil,
2760
2943
  hasCliScripts: this.hasCliScripts(),
2761
- scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
2944
+ scriptNames: listCliScriptNames(this.cliScripts),
2762
2945
  traceSessionId: this.traceSessionId,
2763
2946
  traceEntryCount: this.traceEntries.length,
2764
2947
  statusHistory: this.statusHistory.slice(-30),
@@ -2775,32 +2958,18 @@ ${data.message || ""}`.trim();
2775
2958
  providerResolution: this.providerResolutionMeta,
2776
2959
  entryCount: this.traceEntries.length,
2777
2960
  entries: this.traceEntries.slice(-cappedLimit),
2778
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 4e3),
2779
- recentOutputBuffer: this.summarizeTraceText(this.recentOutputBuffer, 1e3),
2780
- responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
2961
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 4e3),
2962
+ recentOutputBuffer: summarizeCliTraceText(this.recentOutputBuffer, 1e3),
2963
+ responseBuffer: summarizeCliTraceText(this.responseBuffer, 1200),
2781
2964
  status: this.currentStatus,
2782
2965
  activeModal: this.activeModal,
2783
2966
  currentTurnScope: this.currentTurnScope,
2784
- messages: this.summarizeTraceMessages(this.committedMessages, 5)
2967
+ messages: summarizeCliTraceMessages(this.committedMessages, 5)
2785
2968
  };
2786
2969
  }
2787
2970
  getProviderResolutionMeta() {
2788
2971
  return { ...this.providerResolutionMeta };
2789
2972
  }
2790
- respondToTerminalQueries(data) {
2791
- if (!this.ptyProcess || !data) return;
2792
- const combined = this.pendingTerminalQueryTail + data;
2793
- const regex = /\x1b\[(\?)?6n/g;
2794
- let match;
2795
- while ((match = regex.exec(combined)) !== null) {
2796
- const cursor = this.terminalScreen.getCursorPosition();
2797
- const row = Math.max(1, (cursor.row | 0) + 1);
2798
- const col = Math.max(1, (cursor.col | 0) + 1);
2799
- const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
2800
- this.ptyProcess.write(response);
2801
- }
2802
- this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
2803
- }
2804
2973
  };
2805
2974
  }
2806
2975
  });
@@ -3280,17 +3449,17 @@ function checkPathExists(paths) {
3280
3449
  return null;
3281
3450
  }
3282
3451
  async function detectIDEs(providerLoader) {
3283
- const os18 = (0, import_os2.platform)();
3452
+ const os20 = (0, import_os2.platform)();
3284
3453
  const results = [];
3285
3454
  for (const def of getMergedDefinitions()) {
3286
3455
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
3287
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os18] || []) || []);
3456
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os20] || []) || []);
3288
3457
  let resolvedCli = cliPath;
3289
- if (!resolvedCli && appPath && os18 === "darwin") {
3458
+ if (!resolvedCli && appPath && os20 === "darwin") {
3290
3459
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
3291
3460
  if ((0, import_fs3.existsSync)(bundledCli)) resolvedCli = bundledCli;
3292
3461
  }
3293
- if (!resolvedCli && appPath && os18 === "win32") {
3462
+ if (!resolvedCli && appPath && os20 === "win32") {
3294
3463
  const { dirname: dirname6 } = await import("path");
3295
3464
  const appDir = dirname6(appPath);
3296
3465
  const candidates = [
@@ -3307,7 +3476,7 @@ async function detectIDEs(providerLoader) {
3307
3476
  }
3308
3477
  }
3309
3478
  }
3310
- const installed = os18 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
3479
+ const installed = os20 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
3311
3480
  const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
3312
3481
  results.push({
3313
3482
  id: def.id,
@@ -3368,8 +3537,8 @@ function execAsync(cmd, timeoutMs = 5e3) {
3368
3537
  });
3369
3538
  }
3370
3539
  async function detectCLIs(providerLoader, options) {
3371
- const platform9 = os2.platform();
3372
- const whichCmd = platform9 === "win32" ? "where" : "which";
3540
+ const platform10 = os2.platform();
3541
+ const whichCmd = platform10 === "win32" ? "where" : "which";
3373
3542
  const includeVersion = options?.includeVersion !== false;
3374
3543
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
3375
3544
  const results = await Promise.all(
@@ -3412,8 +3581,8 @@ async function detectCLI(cliId, providerLoader, options) {
3412
3581
  const cliList = providerLoader.getCliDetectionList();
3413
3582
  const target = cliList.find((c) => c.id === resolvedId);
3414
3583
  if (target) {
3415
- const platform9 = os2.platform();
3416
- const whichCmd = platform9 === "win32" ? "where" : "which";
3584
+ const platform10 = os2.platform();
3585
+ const whichCmd = platform10 === "win32" ? "where" : "which";
3417
3586
  try {
3418
3587
  const explicitPath = resolveCommandPath(target.command);
3419
3588
  const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
@@ -3534,6 +3703,10 @@ var DaemonCdpManager = class {
3534
3703
  setTargetFilter(filter) {
3535
3704
  this._targetFilter = filter;
3536
3705
  }
3706
+ /** Clear a previously pinned target so the next connect can reselect a page. */
3707
+ clearTargetId() {
3708
+ this._targetId = null;
3709
+ }
3537
3710
  /**
3538
3711
  * Check if a page title should be excluded (non-main page).
3539
3712
  * Uses provider-configured titleExcludes, falls back to default pattern.
@@ -6077,7 +6250,8 @@ var IdeProviderInstance = class {
6077
6250
  }
6078
6251
  }
6079
6252
  if (!raw || typeof raw !== "object") return;
6080
- let { activeModal } = raw;
6253
+ const chat = raw;
6254
+ let { activeModal } = chat;
6081
6255
  if (activeModal) {
6082
6256
  const w = activeModal.width ?? Infinity;
6083
6257
  const h = activeModal.height ?? Infinity;
@@ -6097,26 +6271,28 @@ var IdeProviderInstance = class {
6097
6271
  if (pm.receivedAt) prevByHash.set(h, pm.receivedAt);
6098
6272
  }
6099
6273
  const now = Date.now();
6100
- for (const msg of raw.messages || []) {
6274
+ const messages = chat.messages || [];
6275
+ for (const msg of messages) {
6101
6276
  const h = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
6102
6277
  msg.receivedAt = prevByHash.get(h) || now;
6103
6278
  }
6104
- if (raw.messages?.length > 0) {
6279
+ if (messages.length > 0) {
6105
6280
  const hiddenKinds = /* @__PURE__ */ new Set();
6106
6281
  if (this.settings.showThinking === false) hiddenKinds.add("thought");
6107
6282
  if (this.settings.showToolCalls === false) hiddenKinds.add("tool");
6108
6283
  if (this.settings.showTerminal === false) hiddenKinds.add("terminal");
6109
6284
  if (hiddenKinds.size > 0) {
6110
- raw.messages = raw.messages.filter((m) => !hiddenKinds.has(m.kind));
6285
+ chat.messages = messages.filter((m) => !hiddenKinds.has(m.kind || ""));
6111
6286
  }
6112
6287
  }
6113
- const controlValues = extractProviderControlValues(this.provider.controls, raw);
6114
- if (controlValues) raw.controlValues = controlValues;
6115
- this.cachedChat = { ...raw, activeModal };
6116
- this.detectAgentTransitions(raw, now);
6117
- if (raw.messages?.length > 0) {
6118
- let toSave = raw.messages;
6119
- if (raw.status === "generating" || raw.status === "long_generating") {
6288
+ const controlValues = extractProviderControlValues(this.provider.controls, chat);
6289
+ if (controlValues) chat.controlValues = controlValues;
6290
+ this.cachedChat = { ...chat, activeModal };
6291
+ this.detectAgentTransitions(chat, now);
6292
+ const persistedMessages = chat.messages || messages;
6293
+ if (persistedMessages.length > 0) {
6294
+ let toSave = persistedMessages;
6295
+ if (chat.status === "generating" || chat.status === "long_generating") {
6120
6296
  const lastIdx = toSave.length - 1;
6121
6297
  if (lastIdx >= 0 && toSave[lastIdx].role === "assistant") {
6122
6298
  toSave = toSave.slice(0, lastIdx);
@@ -6126,7 +6302,7 @@ var IdeProviderInstance = class {
6126
6302
  this.historyWriter.appendNewMessages(
6127
6303
  this.type,
6128
6304
  toSave,
6129
- raw.title,
6305
+ chat.title,
6130
6306
  this.instanceId
6131
6307
  );
6132
6308
  }
@@ -6142,7 +6318,7 @@ var IdeProviderInstance = class {
6142
6318
  getReadChatScript() {
6143
6319
  const scripts = this.provider.scripts;
6144
6320
  if (!scripts?.readChat) return null;
6145
- return typeof scripts.readChat === "function" ? scripts.readChat({}) : scripts.readChat;
6321
+ return scripts.readChat({});
6146
6322
  }
6147
6323
  // ─── status transition detect ─────────────────────────────
6148
6324
  detectAgentTransitions(chatData, now) {
@@ -7213,7 +7389,7 @@ function getTargetInstance(h, args) {
7213
7389
  const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
7214
7390
  const sessionId = targetSessionId || h.currentSession?.sessionId || "";
7215
7391
  if (!sessionId) return null;
7216
- return h.ctx.instanceManager?.getInstance(sessionId);
7392
+ return h.ctx.instanceManager?.getInstance(sessionId) || null;
7217
7393
  }
7218
7394
  function getTargetTransport(h, provider) {
7219
7395
  if (h.currentSession?.transport) return h.currentSession.transport;
@@ -7251,6 +7427,10 @@ function getHistorySessionId(h, args) {
7251
7427
  const providerSessionId = typeof state?.providerSessionId === "string" ? state.providerSessionId.trim() : "";
7252
7428
  return providerSessionId || targetSessionId;
7253
7429
  }
7430
+ function callLegacyTextScript(script, text) {
7431
+ if (typeof script !== "function") return null;
7432
+ return script(text);
7433
+ }
7254
7434
  function isRecentDuplicateSend(key) {
7255
7435
  const now = Date.now();
7256
7436
  for (const [candidate, ts2] of recentSendByTarget.entries()) {
@@ -7340,7 +7520,7 @@ async function handleReadChat(h, args) {
7340
7520
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7341
7521
  if (adapter) {
7342
7522
  _log(`${transport} adapter: ${adapter.cliType}`);
7343
- const status = adapter.getStatus?.();
7523
+ const status = adapter.getStatus();
7344
7524
  if (status) {
7345
7525
  return {
7346
7526
  success: true,
@@ -7580,7 +7760,7 @@ async function handleSendChat(h, args) {
7580
7760
  }
7581
7761
  if (parsed?.needsTypeAndSend && provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
7582
7762
  try {
7583
- const webviewScript = provider.scripts.webviewSendMessage(text);
7763
+ const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
7584
7764
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
7585
7765
  const matchText = provider.webviewMatchText;
7586
7766
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -7603,7 +7783,7 @@ async function handleSendChat(h, args) {
7603
7783
  }
7604
7784
  if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
7605
7785
  try {
7606
- const webviewScript = provider.scripts.webviewSendMessage(text);
7786
+ const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
7607
7787
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
7608
7788
  const matchText = provider.webviewMatchText;
7609
7789
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -7835,12 +8015,10 @@ async function handleSetMode(h, args) {
7835
8015
  const mode = args?.mode || "agent";
7836
8016
  if (transport === "acp") {
7837
8017
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7838
- if (adapter) {
7839
- const acpInstance = adapter._acpInstance;
7840
- if (acpInstance && typeof acpInstance.setMode === "function") {
7841
- await acpInstance.setMode(mode);
7842
- return { success: true, mode };
7843
- }
8018
+ const acpInstance = adapter?._acpInstance;
8019
+ if (acpInstance && typeof acpInstance.setMode === "function") {
8020
+ await acpInstance.setMode(mode);
8021
+ return { success: true, mode };
7844
8022
  }
7845
8023
  return { success: false, error: "ACP adapter not found" };
7846
8024
  }
@@ -7893,13 +8071,11 @@ async function handleChangeModel(h, args) {
7893
8071
  if (transport === "acp") {
7894
8072
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7895
8073
  LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
7896
- if (adapter) {
7897
- const acpInstance = adapter._acpInstance;
7898
- if (acpInstance && typeof acpInstance.setConfigOption === "function") {
7899
- await acpInstance.setConfigOption("model", model);
7900
- LOG.info("Command", `[change_model] Updated ACP model to ${model}`);
7901
- return { success: true, model };
7902
- }
8074
+ const acpInstance = adapter?._acpInstance;
8075
+ if (acpInstance && typeof acpInstance.setConfigOption === "function") {
8076
+ await acpInstance.setConfigOption("model", model);
8077
+ LOG.info("Command", `[change_model] Updated ACP model to ${model}`);
8078
+ return { success: true, model };
7903
8079
  }
7904
8080
  return { success: false, error: "ACP adapter not found" };
7905
8081
  }
@@ -7956,6 +8132,9 @@ async function handleSetThoughtLevel(h, args) {
7956
8132
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7957
8133
  const acpInstance = adapter?._acpInstance;
7958
8134
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
8135
+ if (typeof acpInstance.setConfigOption !== "function") {
8136
+ return { success: false, error: "ACP setConfigOption not available" };
8137
+ }
7959
8138
  try {
7960
8139
  await acpInstance.setConfigOption(configId, value);
7961
8140
  LOG.info("Command", `[set_thought_level] ${configId}=${value} for ${provider?.type || "unknown_acp"}`);
@@ -7982,7 +8161,7 @@ async function handleResolveAction(h, args) {
7982
8161
  return { success: false, error: `CLI resolveAction failed: ${e.message}` };
7983
8162
  }
7984
8163
  }
7985
- const status = adapter.getStatus?.();
8164
+ const status = adapter.getStatus();
7986
8165
  if (status?.status !== "waiting_approval") {
7987
8166
  return { success: false, error: "Not in approval state" };
7988
8167
  }
@@ -8021,6 +8200,9 @@ async function handleResolveAction(h, args) {
8021
8200
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
8022
8201
  const acpInstance = adapter?._acpInstance;
8023
8202
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
8203
+ if (typeof acpInstance.resolvePermission !== "function") {
8204
+ return { success: false, error: "ACP resolvePermission not available" };
8205
+ }
8024
8206
  try {
8025
8207
  await acpInstance.resolvePermission(action === "approve" || action === "accept" || action === "always");
8026
8208
  LOG.info("Command", `[resolveAction] ACP \u2192 ${action}`);
@@ -8182,11 +8364,16 @@ async function handleCdpCommand(h, args) {
8182
8364
  }
8183
8365
  async function handleCdpBatch(h, args) {
8184
8366
  if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
8185
- const commands = args?.commands;
8367
+ const commands = Array.isArray(args?.commands) ? args.commands : null;
8186
8368
  const stopOnError = args?.stopOnError !== false;
8187
8369
  if (!commands?.length) return { success: false, error: "commands array required" };
8188
8370
  const results = [];
8189
8371
  for (const cmd of commands) {
8372
+ if (!cmd || typeof cmd !== "object" || typeof cmd.method !== "string") {
8373
+ results.push({ method: null, success: false, error: "Invalid command entry" });
8374
+ if (stopOnError) break;
8375
+ continue;
8376
+ }
8190
8377
  try {
8191
8378
  const result = await h.getCdp().sendCdpCommand(cmd.method, cmd.params || {});
8192
8379
  results.push({ method: cmd.method, success: true, result });
@@ -8481,11 +8668,12 @@ function handlePtyResize(h, args) {
8481
8668
  if (!adapter || typeof adapter.resize !== "function") {
8482
8669
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
8483
8670
  }
8671
+ const resize = adapter.resize;
8484
8672
  if (force) {
8485
- adapter.resize(cols - 1, rows);
8486
- setTimeout(() => adapter.resize(cols, rows), 50);
8673
+ resize(cols - 1, rows);
8674
+ setTimeout(() => resize(cols, rows), 50);
8487
8675
  } else {
8488
- adapter.resize(cols, rows);
8676
+ resize(cols, rows);
8489
8677
  }
8490
8678
  return { success: true };
8491
8679
  }
@@ -8543,7 +8731,7 @@ function parseScriptResult(result) {
8543
8731
  return { success: true, payload: { result } };
8544
8732
  }
8545
8733
  }
8546
- if (result && typeof result === "object" && result.success === false) {
8734
+ if (result && typeof result === "object" && "success" in result && result.success === false) {
8547
8735
  return { success: false, payload: result };
8548
8736
  }
8549
8737
  return { success: true, payload: result };
@@ -8966,24 +9154,25 @@ var DaemonCommandHandler = class {
8966
9154
  if (provider?.scripts) {
8967
9155
  const fn = provider.scripts[scriptName];
8968
9156
  if (typeof fn === "function") {
9157
+ const callScript = fn;
8969
9158
  if (params && Object.keys(params).length > 0) {
8970
9159
  const firstVal = Object.values(params)[0];
8971
9160
  if (scriptName === "sendMessage" && typeof firstVal === "string") {
8972
- const legacyScript = fn(firstVal);
9161
+ const legacyScript = callScript(firstVal);
8973
9162
  if (legacyScript) return legacyScript;
8974
9163
  }
8975
- const script = fn(params);
9164
+ const script = callScript(params);
8976
9165
  if (script) {
8977
9166
  const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
8978
9167
  if (!likelyLegacyObjectLeak) return script;
8979
9168
  }
8980
9169
  if (firstVal !== void 0) {
8981
- const legacyScript = fn(firstVal);
9170
+ const legacyScript = callScript(firstVal);
8982
9171
  if (legacyScript) return legacyScript;
8983
9172
  }
8984
9173
  if (script) return script;
8985
9174
  } else {
8986
- const script = fn();
9175
+ const script = callScript();
8987
9176
  if (script) return script;
8988
9177
  }
8989
9178
  }
@@ -9363,16 +9552,16 @@ var DaemonCommandHandler = class {
9363
9552
  };
9364
9553
 
9365
9554
  // src/commands/cli-manager.ts
9366
- var os10 = __toESM(require("os"));
9367
- var path11 = __toESM(require("path"));
9555
+ var os12 = __toESM(require("os"));
9556
+ var path12 = __toESM(require("path"));
9368
9557
  var crypto4 = __toESM(require("crypto"));
9369
9558
  var import_chalk = __toESM(require("chalk"));
9370
9559
  init_provider_cli_adapter();
9371
9560
  init_config();
9372
9561
 
9373
9562
  // src/providers/cli-provider-instance.ts
9374
- var os9 = __toESM(require("os"));
9375
- var path10 = __toESM(require("path"));
9563
+ var os11 = __toESM(require("os"));
9564
+ var path11 = __toESM(require("path"));
9376
9565
  var crypto3 = __toESM(require("crypto"));
9377
9566
  var fs5 = __toESM(require("fs"));
9378
9567
  var import_node_module = require("module");
@@ -9381,7 +9570,7 @@ init_logger();
9381
9570
  var CachedDatabaseSync = null;
9382
9571
  function getDatabaseSync() {
9383
9572
  if (CachedDatabaseSync) return CachedDatabaseSync;
9384
- const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path10.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
9573
+ const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path11.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
9385
9574
  const sqliteModule = requireFn(`node:${"sqlite"}`);
9386
9575
  CachedDatabaseSync = sqliteModule.DatabaseSync;
9387
9576
  if (!CachedDatabaseSync) {
@@ -9521,7 +9710,7 @@ var CliProviderInstance = class {
9521
9710
  * Replaces the previously duplicated probeOpenCode/Codex/Goose functions.
9522
9711
  */
9523
9712
  probeSessionIdFromConfig(probe) {
9524
- const resolvedDbPath = probe.dbPath.replace(/^~/, os9.homedir());
9713
+ const resolvedDbPath = probe.dbPath.replace(/^~/, os11.homedir());
9525
9714
  if (!fs5.existsSync(resolvedDbPath)) return null;
9526
9715
  const directories = this.getProbeDirectories();
9527
9716
  const minCreatedAt = Math.max(0, this.startedAt - 6e4);
@@ -10946,7 +11135,8 @@ var AcpProviderInstance = class {
10946
11135
 
10947
11136
  // src/commands/cli-manager.ts
10948
11137
  init_logger();
10949
- var chalkApi = import_chalk.default?.yellow ? import_chalk.default : import_chalk.default?.default || null;
11138
+ var chalkModule = import_chalk.default;
11139
+ var chalkApi = typeof chalkModule.yellow === "function" ? chalkModule : chalkModule.default || null;
10950
11140
  function colorize(color, text) {
10951
11141
  const fn = chalkApi?.[color];
10952
11142
  return typeof fn === "function" ? fn(text) : text;
@@ -11196,7 +11386,7 @@ var DaemonCliManager = class {
11196
11386
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
11197
11387
  const trimmed = (workingDir || "").trim();
11198
11388
  if (!trimmed) throw new Error("working directory required");
11199
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path11.resolve(trimmed);
11389
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path12.resolve(trimmed);
11200
11390
  const normalizedType = this.providerLoader.resolveAlias(cliType);
11201
11391
  const provider = this.providerLoader.getByAlias(cliType);
11202
11392
  const key = crypto4.randomUUID();
@@ -11235,6 +11425,7 @@ ${installInfo}`
11235
11425
  });
11236
11426
  this.adapters.set(key, {
11237
11427
  cliType: normalizedType,
11428
+ cliName: provider.name,
11238
11429
  workingDir: resolvedDir,
11239
11430
  _acpInstance: acpInstance,
11240
11431
  spawn: async () => {
@@ -11253,6 +11444,12 @@ ${installInfo}`
11253
11444
  activeModal: state.activeChat?.activeModal || null
11254
11445
  };
11255
11446
  },
11447
+ getPartialResponse: () => "",
11448
+ cancel: () => {
11449
+ instanceManager2.removeInstance(key);
11450
+ },
11451
+ isProcessing: () => false,
11452
+ isReady: () => true,
11256
11453
  setOnStatusChange: () => {
11257
11454
  },
11258
11455
  setOnPtyData: () => {
@@ -11659,13 +11856,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
11659
11856
  // src/launch.ts
11660
11857
  var import_child_process6 = require("child_process");
11661
11858
  var net = __toESM(require("net"));
11662
- var os12 = __toESM(require("os"));
11663
- var path13 = __toESM(require("path"));
11859
+ var os14 = __toESM(require("os"));
11860
+ var path14 = __toESM(require("path"));
11664
11861
 
11665
11862
  // src/providers/provider-loader.ts
11666
11863
  var fs6 = __toESM(require("fs"));
11667
- var path12 = __toESM(require("path"));
11668
- var os11 = __toESM(require("os"));
11864
+ var path13 = __toESM(require("path"));
11865
+ var os13 = __toESM(require("os"));
11669
11866
  var chokidar = __toESM(require("chokidar"));
11670
11867
  init_logger();
11671
11868
  var ProviderLoader = class _ProviderLoader {
@@ -11686,12 +11883,12 @@ var ProviderLoader = class _ProviderLoader {
11686
11883
  static META_FILE = ".meta.json";
11687
11884
  constructor(options) {
11688
11885
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
11689
- const defaultProvidersDir = path12.join(os11.homedir(), ".adhdev", "providers");
11886
+ const defaultProvidersDir = path13.join(os13.homedir(), ".adhdev", "providers");
11690
11887
  if (options?.userDir) {
11691
11888
  this.userDir = options.userDir;
11692
11889
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
11693
11890
  } else {
11694
- const localRepoPath = path12.resolve(__dirname, "../../../../../adhdev-providers");
11891
+ const localRepoPath = path13.resolve(__dirname, "../../../../../adhdev-providers");
11695
11892
  if (fs6.existsSync(localRepoPath)) {
11696
11893
  this.userDir = localRepoPath;
11697
11894
  this.log(`Auto-detected local public repository: ${this.userDir} (Dev workspace speedup)`);
@@ -11700,7 +11897,7 @@ var ProviderLoader = class _ProviderLoader {
11700
11897
  this.log(`Using default user providers directory: ${this.userDir}`);
11701
11898
  }
11702
11899
  }
11703
- this.upstreamDir = path12.join(defaultProvidersDir, ".upstream");
11900
+ this.upstreamDir = path13.join(defaultProvidersDir, ".upstream");
11704
11901
  this.disableUpstream = options?.disableUpstream ?? false;
11705
11902
  }
11706
11903
  log(msg) {
@@ -11730,7 +11927,7 @@ var ProviderLoader = class _ProviderLoader {
11730
11927
  * Canonical provider directory shape for a given root.
11731
11928
  */
11732
11929
  getProviderDir(root, category, type) {
11733
- return path12.join(root, category, type);
11930
+ return path13.join(root, category, type);
11734
11931
  }
11735
11932
  /**
11736
11933
  * Canonical user override directory for a provider.
@@ -11757,7 +11954,7 @@ var ProviderLoader = class _ProviderLoader {
11757
11954
  resolveProviderFile(type, ...segments) {
11758
11955
  const dir = this.findProviderDirInternal(type);
11759
11956
  if (!dir) return null;
11760
- return path12.join(dir, ...segments);
11957
+ return path13.join(dir, ...segments);
11761
11958
  }
11762
11959
  /**
11763
11960
  * Load all providers (3-tier priority)
@@ -11796,7 +11993,7 @@ var ProviderLoader = class _ProviderLoader {
11796
11993
  if (!fs6.existsSync(this.upstreamDir)) return false;
11797
11994
  try {
11798
11995
  return fs6.readdirSync(this.upstreamDir).some(
11799
- (d) => fs6.statSync(path12.join(this.upstreamDir, d)).isDirectory()
11996
+ (d) => fs6.statSync(path13.join(this.upstreamDir, d)).isDirectory()
11800
11997
  );
11801
11998
  } catch {
11802
11999
  return false;
@@ -11837,8 +12034,7 @@ var ProviderLoader = class _ProviderLoader {
11837
12034
  const result = [];
11838
12035
  for (const p of this.providers.values()) {
11839
12036
  if ((p.category === "cli" || p.category === "acp") && p.spawn?.command) {
11840
- const verCmdConfig = p.versionCommand;
11841
- const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[process.platform] : verCmdConfig;
12037
+ const versionCommand = this.getPlatformVersionCommand(p.versionCommand);
11842
12038
  const command = this.getSpawnCommand(p.type, p.spawn.command);
11843
12039
  result.push({
11844
12040
  id: p.type,
@@ -11892,8 +12088,8 @@ var ProviderLoader = class _ProviderLoader {
11892
12088
  * that runtime attach/remove uses.
11893
12089
  */
11894
12090
  getIdeExtensionEnabledState(ideType, extensionType) {
11895
- const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
11896
- const config = loadConfig2();
12091
+ const config = this.readConfig();
12092
+ if (!config) return false;
11897
12093
  const baseIdeType = ideType.split("_")[0];
11898
12094
  const val = config.ideSettings?.[baseIdeType]?.extensions?.[extensionType]?.enabled;
11899
12095
  return val === true;
@@ -11902,15 +12098,15 @@ var ProviderLoader = class _ProviderLoader {
11902
12098
  * Save IDE extension enabled setting
11903
12099
  */
11904
12100
  setIdeExtensionEnabled(ideType, extensionType, enabled) {
12101
+ const config = this.readConfig();
12102
+ if (!config) return false;
11905
12103
  try {
11906
- const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
11907
- const config = loadConfig2();
11908
12104
  const baseIdeType = ideType.split("_")[0];
11909
12105
  if (!config.ideSettings) config.ideSettings = {};
11910
12106
  if (!config.ideSettings[baseIdeType]) config.ideSettings[baseIdeType] = {};
11911
12107
  if (!config.ideSettings[baseIdeType].extensions) config.ideSettings[baseIdeType].extensions = {};
11912
12108
  config.ideSettings[baseIdeType].extensions[extensionType] = { enabled };
11913
- saveConfig3(config);
12109
+ this.writeConfig(config);
11914
12110
  this.log(`IDE extension setting: ${ideType}.${extensionType}.enabled = ${enabled}`);
11915
12111
  return true;
11916
12112
  } catch (e) {
@@ -12100,7 +12296,7 @@ var ProviderLoader = class _ProviderLoader {
12100
12296
  }
12101
12297
  if (currentVersion) {
12102
12298
  resolved._resolvedVersion = currentVersion;
12103
- if (Array.isArray(base.compatibility)) {
12299
+ if (base.compatibility) {
12104
12300
  const compat = base.compatibility;
12105
12301
  let matched = false;
12106
12302
  for (const entry of compat) {
@@ -12112,8 +12308,8 @@ var ProviderLoader = class _ProviderLoader {
12112
12308
  resolved._resolvedScriptDir = entry.scriptDir;
12113
12309
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
12114
12310
  if (providerDir) {
12115
- const fullDir = path12.join(providerDir, entry.scriptDir);
12116
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12311
+ const fullDir = path13.join(providerDir, entry.scriptDir);
12312
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12117
12313
  }
12118
12314
  matched = true;
12119
12315
  }
@@ -12128,8 +12324,8 @@ var ProviderLoader = class _ProviderLoader {
12128
12324
  resolved._resolvedScriptDir = base.defaultScriptDir;
12129
12325
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
12130
12326
  if (providerDir) {
12131
- const fullDir = path12.join(providerDir, base.defaultScriptDir);
12132
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12327
+ const fullDir = path13.join(providerDir, base.defaultScriptDir);
12328
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12133
12329
  }
12134
12330
  }
12135
12331
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -12146,8 +12342,8 @@ var ProviderLoader = class _ProviderLoader {
12146
12342
  resolved._resolvedScriptDir = dirOverride;
12147
12343
  resolved._resolvedScriptsSource = `versions:${range}`;
12148
12344
  if (providerDir) {
12149
- const fullDir = path12.join(providerDir, dirOverride);
12150
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12345
+ const fullDir = path13.join(providerDir, dirOverride);
12346
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12151
12347
  }
12152
12348
  }
12153
12349
  } else if (override.scripts) {
@@ -12155,7 +12351,7 @@ var ProviderLoader = class _ProviderLoader {
12155
12351
  }
12156
12352
  }
12157
12353
  }
12158
- } else if (Array.isArray(base.compatibility) && base.defaultScriptDir) {
12354
+ } else if (base.compatibility && base.defaultScriptDir) {
12159
12355
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
12160
12356
  if (loaded) {
12161
12357
  resolved.scripts = loaded;
@@ -12163,8 +12359,8 @@ var ProviderLoader = class _ProviderLoader {
12163
12359
  resolved._resolvedScriptDir = base.defaultScriptDir;
12164
12360
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
12165
12361
  if (providerDir) {
12166
- const fullDir = path12.join(providerDir, base.defaultScriptDir);
12167
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12362
+ const fullDir = path13.join(providerDir, base.defaultScriptDir);
12363
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12168
12364
  }
12169
12365
  }
12170
12366
  }
@@ -12189,14 +12385,14 @@ var ProviderLoader = class _ProviderLoader {
12189
12385
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
12190
12386
  return null;
12191
12387
  }
12192
- const dir = path12.join(providerDir, scriptDir);
12388
+ const dir = path13.join(providerDir, scriptDir);
12193
12389
  if (!fs6.existsSync(dir)) {
12194
12390
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
12195
12391
  return null;
12196
12392
  }
12197
12393
  const cached = this.scriptsCache.get(dir);
12198
12394
  if (cached) return cached;
12199
- const scriptsJs = path12.join(dir, "scripts.js");
12395
+ const scriptsJs = path13.join(dir, "scripts.js");
12200
12396
  if (fs6.existsSync(scriptsJs)) {
12201
12397
  try {
12202
12398
  delete require.cache[require.resolve(scriptsJs)];
@@ -12238,7 +12434,7 @@ var ProviderLoader = class _ProviderLoader {
12238
12434
  return;
12239
12435
  }
12240
12436
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
12241
- this.log(`File changed: ${path12.basename(filePath)}, reloading...`);
12437
+ this.log(`File changed: ${path13.basename(filePath)}, reloading...`);
12242
12438
  this.reload();
12243
12439
  }
12244
12440
  };
@@ -12293,7 +12489,7 @@ var ProviderLoader = class _ProviderLoader {
12293
12489
  }
12294
12490
  const https = require("https");
12295
12491
  const { execSync: execSync7 } = require("child_process");
12296
- const metaPath = path12.join(this.upstreamDir, _ProviderLoader.META_FILE);
12492
+ const metaPath = path13.join(this.upstreamDir, _ProviderLoader.META_FILE);
12297
12493
  let prevEtag = "";
12298
12494
  let prevTimestamp = 0;
12299
12495
  try {
@@ -12353,17 +12549,17 @@ var ProviderLoader = class _ProviderLoader {
12353
12549
  return { updated: false };
12354
12550
  }
12355
12551
  this.log("Downloading latest providers from GitHub...");
12356
- const tmpTar = path12.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
12357
- const tmpExtract = path12.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
12552
+ const tmpTar = path13.join(os13.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
12553
+ const tmpExtract = path13.join(os13.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
12358
12554
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
12359
12555
  fs6.mkdirSync(tmpExtract, { recursive: true });
12360
12556
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
12361
12557
  const extracted = fs6.readdirSync(tmpExtract);
12362
12558
  const rootDir = extracted.find(
12363
- (d) => fs6.statSync(path12.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
12559
+ (d) => fs6.statSync(path13.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
12364
12560
  );
12365
12561
  if (!rootDir) throw new Error("Unexpected tarball structure");
12366
- const sourceDir = path12.join(tmpExtract, rootDir);
12562
+ const sourceDir = path13.join(tmpExtract, rootDir);
12367
12563
  const backupDir = this.upstreamDir + ".bak";
12368
12564
  if (fs6.existsSync(this.upstreamDir)) {
12369
12565
  if (fs6.existsSync(backupDir)) fs6.rmSync(backupDir, { recursive: true, force: true });
@@ -12438,8 +12634,8 @@ var ProviderLoader = class _ProviderLoader {
12438
12634
  copyDirRecursive(src, dest) {
12439
12635
  fs6.mkdirSync(dest, { recursive: true });
12440
12636
  for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
12441
- const srcPath = path12.join(src, entry.name);
12442
- const destPath = path12.join(dest, entry.name);
12637
+ const srcPath = path13.join(src, entry.name);
12638
+ const destPath = path13.join(dest, entry.name);
12443
12639
  if (entry.isDirectory()) {
12444
12640
  this.copyDirRecursive(srcPath, destPath);
12445
12641
  } else {
@@ -12450,7 +12646,7 @@ var ProviderLoader = class _ProviderLoader {
12450
12646
  /** .meta.json save */
12451
12647
  writeMeta(metaPath, etag, timestamp) {
12452
12648
  try {
12453
- fs6.mkdirSync(path12.dirname(metaPath), { recursive: true });
12649
+ fs6.mkdirSync(path13.dirname(metaPath), { recursive: true });
12454
12650
  fs6.writeFileSync(metaPath, JSON.stringify({
12455
12651
  etag,
12456
12652
  timestamp,
@@ -12467,7 +12663,7 @@ var ProviderLoader = class _ProviderLoader {
12467
12663
  const scan = (d) => {
12468
12664
  try {
12469
12665
  for (const entry of fs6.readdirSync(d, { withFileTypes: true })) {
12470
- if (entry.isDirectory()) scan(path12.join(d, entry.name));
12666
+ if (entry.isDirectory()) scan(path13.join(d, entry.name));
12471
12667
  else if (entry.name === "provider.json") count++;
12472
12668
  }
12473
12669
  } catch {
@@ -12501,14 +12697,9 @@ var ProviderLoader = class _ProviderLoader {
12501
12697
  getSettingValue(type, key) {
12502
12698
  const schemaDef = this.getSettingsSchema(type)[key];
12503
12699
  const defaultVal = schemaDef ? key === "autoApprove" && schemaDef.type === "boolean" ? true : schemaDef.default : void 0;
12504
- try {
12505
- const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
12506
- const config = loadConfig2();
12507
- const userVal = config.providerSettings?.[type]?.[key];
12508
- return userVal !== void 0 ? userVal : defaultVal;
12509
- } catch {
12510
- return defaultVal;
12511
- }
12700
+ const config = this.readConfig();
12701
+ const userVal = config?.providerSettings?.[type]?.[key];
12702
+ return userVal !== void 0 ? userVal : defaultVal;
12512
12703
  }
12513
12704
  /**
12514
12705
  * All resolved settings for a provider (default + user override)
@@ -12536,13 +12727,13 @@ var ProviderLoader = class _ProviderLoader {
12536
12727
  if (schemaDef.max !== void 0 && value > schemaDef.max) return false;
12537
12728
  }
12538
12729
  if (schemaDef.type === "select" && schemaDef.options && !schemaDef.options.includes(value)) return false;
12730
+ const config = this.readConfig();
12731
+ if (!config) return false;
12539
12732
  try {
12540
- const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
12541
- const config = loadConfig2();
12542
12733
  if (!config.providerSettings) config.providerSettings = {};
12543
12734
  if (!config.providerSettings[type]) config.providerSettings[type] = {};
12544
12735
  config.providerSettings[type][key] = value;
12545
- saveConfig3(config);
12736
+ this.writeConfig(config);
12546
12737
  this.log(`Setting updated: ${type}.${key} = ${JSON.stringify(value)}`);
12547
12738
  return true;
12548
12739
  } catch (e) {
@@ -12556,6 +12747,34 @@ var ProviderLoader = class _ProviderLoader {
12556
12747
  const trimmed = value.trim();
12557
12748
  return trimmed ? trimmed : null;
12558
12749
  }
12750
+ readConfig() {
12751
+ try {
12752
+ const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
12753
+ return loadConfig2();
12754
+ } catch {
12755
+ return null;
12756
+ }
12757
+ }
12758
+ writeConfig(config) {
12759
+ const { saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
12760
+ saveConfig3(config);
12761
+ }
12762
+ getPlatformVersionCommand(versionCommand) {
12763
+ if (!versionCommand) return void 0;
12764
+ if (typeof versionCommand === "string") {
12765
+ const trimmed = versionCommand.trim();
12766
+ return trimmed || void 0;
12767
+ }
12768
+ const platformValue = versionCommand[process.platform];
12769
+ if (typeof platformValue === "string" && platformValue.trim()) {
12770
+ return platformValue.trim();
12771
+ }
12772
+ const defaultValue = versionCommand.default;
12773
+ if (typeof defaultValue === "string" && defaultValue.trim()) {
12774
+ return defaultValue.trim();
12775
+ }
12776
+ return void 0;
12777
+ }
12559
12778
  getSettingsSchema(type) {
12560
12779
  const provider = this.providers.get(type);
12561
12780
  if (!provider) return {};
@@ -12629,17 +12848,17 @@ var ProviderLoader = class _ProviderLoader {
12629
12848
  for (const root of searchRoots) {
12630
12849
  if (!fs6.existsSync(root)) continue;
12631
12850
  const candidate = this.getProviderDir(root, cat, type);
12632
- if (fs6.existsSync(path12.join(candidate, "provider.json"))) return candidate;
12633
- const catDir = path12.join(root, cat);
12851
+ if (fs6.existsSync(path13.join(candidate, "provider.json"))) return candidate;
12852
+ const catDir = path13.join(root, cat);
12634
12853
  if (fs6.existsSync(catDir)) {
12635
12854
  try {
12636
12855
  for (const entry of fs6.readdirSync(catDir, { withFileTypes: true })) {
12637
12856
  if (!entry.isDirectory()) continue;
12638
- const jsonPath = path12.join(catDir, entry.name, "provider.json");
12857
+ const jsonPath = path13.join(catDir, entry.name, "provider.json");
12639
12858
  if (fs6.existsSync(jsonPath)) {
12640
12859
  try {
12641
12860
  const data = JSON.parse(fs6.readFileSync(jsonPath, "utf-8"));
12642
- if (data.type === type) return path12.join(catDir, entry.name);
12861
+ if (data.type === type) return path13.join(catDir, entry.name);
12643
12862
  } catch {
12644
12863
  }
12645
12864
  }
@@ -12656,7 +12875,7 @@ var ProviderLoader = class _ProviderLoader {
12656
12875
  * (template substitution is NOT applied here — scripts.js handles that)
12657
12876
  */
12658
12877
  buildScriptWrappersFromDir(dir) {
12659
- const scriptsJs = path12.join(dir, "scripts.js");
12878
+ const scriptsJs = path13.join(dir, "scripts.js");
12660
12879
  if (fs6.existsSync(scriptsJs)) {
12661
12880
  try {
12662
12881
  delete require.cache[require.resolve(scriptsJs)];
@@ -12670,7 +12889,7 @@ var ProviderLoader = class _ProviderLoader {
12670
12889
  for (const file of fs6.readdirSync(dir)) {
12671
12890
  if (!file.endsWith(".js")) continue;
12672
12891
  const scriptName = toCamel(file.replace(".js", ""));
12673
- const filePath = path12.join(dir, file);
12892
+ const filePath = path13.join(dir, file);
12674
12893
  result[scriptName] = (...args) => {
12675
12894
  try {
12676
12895
  let content = fs6.readFileSync(filePath, "utf-8");
@@ -12730,35 +12949,39 @@ var ProviderLoader = class _ProviderLoader {
12730
12949
  }
12731
12950
  const hasJson = entries.some((e) => e.name === "provider.json");
12732
12951
  if (hasJson) {
12733
- const jsonPath = path12.join(d, "provider.json");
12952
+ const jsonPath = path13.join(d, "provider.json");
12734
12953
  try {
12735
12954
  const raw = fs6.readFileSync(jsonPath, "utf-8");
12736
12955
  const mod = JSON.parse(raw);
12737
12956
  if (!mod.type || !mod.name || !mod.category) {
12738
12957
  this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
12739
12958
  } else {
12740
- if (mod.extensionIdPattern && typeof mod.extensionIdPattern === "string") {
12959
+ if (typeof mod.extensionIdPattern === "string") {
12741
12960
  const flags = mod.extensionIdPattern_flags || "";
12742
12961
  mod.extensionIdPattern = new RegExp(mod.extensionIdPattern, flags);
12743
- delete mod.extensionIdPattern_flags;
12744
12962
  }
12745
- const hasCompatibility = Array.isArray(mod.compatibility);
12746
- const scriptsPath = path12.join(d, "scripts.js");
12963
+ const { extensionIdPattern_flags, extensionIdPattern, ...providerFields } = mod;
12964
+ const normalizedProvider = {
12965
+ ...providerFields,
12966
+ ...extensionIdPattern instanceof RegExp ? { extensionIdPattern } : {}
12967
+ };
12968
+ const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
12969
+ const scriptsPath = path13.join(d, "scripts.js");
12747
12970
  if (!hasCompatibility && fs6.existsSync(scriptsPath)) {
12748
12971
  try {
12749
12972
  delete require.cache[require.resolve(scriptsPath)];
12750
12973
  const scripts = require(scriptsPath);
12751
- mod.scripts = scripts;
12974
+ normalizedProvider.scripts = scripts;
12752
12975
  } catch (e) {
12753
12976
  this.log(`\u26A0 Failed to load scripts: ${scriptsPath}: ${e.message}`);
12754
12977
  }
12755
12978
  }
12756
- const existed = this.providers.has(mod.type);
12757
- this.providers.set(mod.type, mod);
12979
+ const existed = this.providers.has(normalizedProvider.type);
12980
+ this.providers.set(normalizedProvider.type, normalizedProvider);
12758
12981
  count++;
12759
12982
  const source = d.startsWith(this.userDir) && !d.includes(".upstream") ? "user" : "upstream";
12760
12983
  const overrideWarning = existed && source === "user" ? " \u26A0 OVERRIDES upstream" : "";
12761
- this.log(` ${existed ? "\u{1F504}" : "\u2705"} ${mod.type} (${mod.category}) \u2014 ${mod.name} [${source}]${overrideWarning}`);
12984
+ this.log(` ${existed ? "\u{1F504}" : "\u2705"} ${normalizedProvider.type} (${normalizedProvider.category}) \u2014 ${normalizedProvider.name} [${source}]${overrideWarning}`);
12762
12985
  }
12763
12986
  } catch (e) {
12764
12987
  this.log(`\u26A0 Failed to load ${jsonPath}: ${e.message}`);
@@ -12769,7 +12992,7 @@ var ProviderLoader = class _ProviderLoader {
12769
12992
  if (!entry.isDirectory()) continue;
12770
12993
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
12771
12994
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
12772
- scan(path12.join(d, entry.name));
12995
+ scan(path13.join(d, entry.name));
12773
12996
  }
12774
12997
  }
12775
12998
  };
@@ -12839,9 +13062,9 @@ function getWinProcessNames() {
12839
13062
  function getProviderMeta(ideId) {
12840
13063
  return getProviderLoader().getMeta(ideId);
12841
13064
  }
12842
- function getPreferredLaunchMethod(ideId, platform9) {
13065
+ function getPreferredLaunchMethod(ideId, platform10) {
12843
13066
  const prefer = getProviderMeta(ideId)?.launch?.prefer;
12844
- const value = prefer?.[platform9];
13067
+ const value = prefer?.[platform10];
12845
13068
  return value === "cli" || value === "app" || value === "auto" ? value : "auto";
12846
13069
  }
12847
13070
  function getCdpStartupTimeoutMs(ideId) {
@@ -12898,7 +13121,7 @@ async function isCdpActive(port) {
12898
13121
  });
12899
13122
  }
12900
13123
  async function killIdeProcess(ideId) {
12901
- const plat = os12.platform();
13124
+ const plat = os14.platform();
12902
13125
  const appName = getMacAppIdentifiers()[ideId];
12903
13126
  const winProcesses = getWinProcessNames()[ideId];
12904
13127
  try {
@@ -12957,7 +13180,7 @@ async function killIdeProcess(ideId) {
12957
13180
  }
12958
13181
  }
12959
13182
  function isIdeRunning(ideId) {
12960
- const plat = os12.platform();
13183
+ const plat = os14.platform();
12961
13184
  try {
12962
13185
  if (plat === "darwin") {
12963
13186
  const appName = getMacAppIdentifiers()[ideId];
@@ -13008,7 +13231,7 @@ function isIdeRunning(ideId) {
13008
13231
  }
13009
13232
  }
13010
13233
  function detectCurrentWorkspace(ideId) {
13011
- const plat = os12.platform();
13234
+ const plat = os14.platform();
13012
13235
  if (plat === "darwin") {
13013
13236
  try {
13014
13237
  const appName = getMacAppIdentifiers()[ideId];
@@ -13027,8 +13250,8 @@ function detectCurrentWorkspace(ideId) {
13027
13250
  const appNameMap = getMacAppIdentifiers();
13028
13251
  const appName = appNameMap[ideId];
13029
13252
  if (appName) {
13030
- const storagePath = path13.join(
13031
- process.env.APPDATA || path13.join(os12.homedir(), "AppData", "Roaming"),
13253
+ const storagePath = path14.join(
13254
+ process.env.APPDATA || path14.join(os14.homedir(), "AppData", "Roaming"),
13032
13255
  appName,
13033
13256
  "storage.json"
13034
13257
  );
@@ -13050,7 +13273,7 @@ function detectCurrentWorkspace(ideId) {
13050
13273
  return void 0;
13051
13274
  }
13052
13275
  async function launchWithCdp(options = {}) {
13053
- const platform9 = os12.platform();
13276
+ const platform10 = os14.platform();
13054
13277
  let targetIde;
13055
13278
  const ides = await detectIDEs(getProviderLoader());
13056
13279
  if (options.ideId) {
@@ -13119,9 +13342,9 @@ async function launchWithCdp(options = {}) {
13119
13342
  }
13120
13343
  const port = await findFreePort(portPair);
13121
13344
  try {
13122
- if (platform9 === "darwin") {
13345
+ if (platform10 === "darwin") {
13123
13346
  await launchMacOS(targetIde, port, workspace, options.newWindow);
13124
- } else if (platform9 === "win32") {
13347
+ } else if (platform10 === "win32") {
13125
13348
  await launchWindows(targetIde, port, workspace, options.newWindow);
13126
13349
  } else {
13127
13350
  await launchLinux(targetIde, port, workspace, options.newWindow);
@@ -13206,9 +13429,9 @@ init_logger();
13206
13429
 
13207
13430
  // src/logging/command-log.ts
13208
13431
  var fs7 = __toESM(require("fs"));
13209
- var path14 = __toESM(require("path"));
13210
- var os13 = __toESM(require("os"));
13211
- 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");
13432
+ var path15 = __toESM(require("path"));
13433
+ var os15 = __toESM(require("os"));
13434
+ 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");
13212
13435
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
13213
13436
  var MAX_DAYS = 7;
13214
13437
  try {
@@ -13246,13 +13469,13 @@ function getDateStr2() {
13246
13469
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
13247
13470
  }
13248
13471
  var currentDate2 = getDateStr2();
13249
- var currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13472
+ var currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13250
13473
  var writeCount2 = 0;
13251
13474
  function checkRotation() {
13252
13475
  const today = getDateStr2();
13253
13476
  if (today !== currentDate2) {
13254
13477
  currentDate2 = today;
13255
- currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13478
+ currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13256
13479
  cleanOldFiles();
13257
13480
  }
13258
13481
  }
@@ -13266,7 +13489,7 @@ function cleanOldFiles() {
13266
13489
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
13267
13490
  if (dateMatch && dateMatch[1] < cutoffStr) {
13268
13491
  try {
13269
- fs7.unlinkSync(path14.join(LOG_DIR2, file));
13492
+ fs7.unlinkSync(path15.join(LOG_DIR2, file));
13270
13493
  } catch {
13271
13494
  }
13272
13495
  }
@@ -13343,7 +13566,7 @@ cleanOldFiles();
13343
13566
  init_logger();
13344
13567
 
13345
13568
  // src/status/snapshot.ts
13346
- var os14 = __toESM(require("os"));
13569
+ var os16 = __toESM(require("os"));
13347
13570
  init_config();
13348
13571
  init_terminal_screen();
13349
13572
  init_logger();
@@ -13463,16 +13686,16 @@ function buildStatusSnapshot(options) {
13463
13686
  version: options.version,
13464
13687
  daemonMode: options.daemonMode,
13465
13688
  machine: {
13466
- hostname: os14.hostname(),
13467
- platform: os14.platform(),
13468
- arch: os14.arch(),
13469
- cpus: os14.cpus().length,
13689
+ hostname: os16.hostname(),
13690
+ platform: os16.platform(),
13691
+ arch: os16.arch(),
13692
+ cpus: os16.cpus().length,
13470
13693
  totalMem: memSnap.totalMem,
13471
13694
  freeMem: memSnap.freeMem,
13472
13695
  availableMem: memSnap.availableMem,
13473
- loadavg: os14.loadavg(),
13474
- uptime: os14.uptime(),
13475
- release: os14.release()
13696
+ loadavg: os16.loadavg(),
13697
+ uptime: os16.uptime(),
13698
+ release: os16.release()
13476
13699
  },
13477
13700
  machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
13478
13701
  timestamp: options.timestamp ?? Date.now(),
@@ -13493,14 +13716,14 @@ function buildStatusSnapshot(options) {
13493
13716
  var import_child_process7 = require("child_process");
13494
13717
  var import_child_process8 = require("child_process");
13495
13718
  var fs8 = __toESM(require("fs"));
13496
- var os15 = __toESM(require("os"));
13497
- var path15 = __toESM(require("path"));
13719
+ var os17 = __toESM(require("os"));
13720
+ var path16 = __toESM(require("path"));
13498
13721
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
13499
13722
  function getUpgradeLogPath() {
13500
- const home = os15.homedir();
13501
- const dir = path15.join(home, ".adhdev");
13723
+ const home = os17.homedir();
13724
+ const dir = path16.join(home, ".adhdev");
13502
13725
  fs8.mkdirSync(dir, { recursive: true });
13503
- return path15.join(dir, "daemon-upgrade.log");
13726
+ return path16.join(dir, "daemon-upgrade.log");
13504
13727
  }
13505
13728
  function appendUpgradeLog(message) {
13506
13729
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -13540,7 +13763,7 @@ async function waitForPidExit(pid, timeoutMs) {
13540
13763
  }
13541
13764
  }
13542
13765
  function stopSessionHostProcesses(appName) {
13543
- const pidFile = path15.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
13766
+ const pidFile = path16.join(os17.homedir(), ".adhdev", `${appName}-session-host.pid`);
13544
13767
  try {
13545
13768
  if (fs8.existsSync(pidFile)) {
13546
13769
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
@@ -13569,7 +13792,7 @@ function stopSessionHostProcesses(appName) {
13569
13792
  }
13570
13793
  }
13571
13794
  function removeDaemonPidFile() {
13572
- const pidFile = path15.join(os15.homedir(), ".adhdev", "daemon.pid");
13795
+ const pidFile = path16.join(os17.homedir(), ".adhdev", "daemon.pid");
13573
13796
  try {
13574
13797
  fs8.unlinkSync(pidFile);
13575
13798
  } catch {
@@ -13580,7 +13803,7 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
13580
13803
  const npmRoot = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
13581
13804
  if (!npmRoot) return;
13582
13805
  const npmPrefix = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
13583
- const binDir = process.platform === "win32" ? npmPrefix : path15.join(npmPrefix, "bin");
13806
+ const binDir = process.platform === "win32" ? npmPrefix : path16.join(npmPrefix, "bin");
13584
13807
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
13585
13808
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
13586
13809
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -13588,25 +13811,25 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
13588
13811
  }
13589
13812
  if (pkgName.startsWith("@")) {
13590
13813
  const [scope, name] = pkgName.split("/");
13591
- const scopeDir = path15.join(npmRoot, scope);
13814
+ const scopeDir = path16.join(npmRoot, scope);
13592
13815
  if (!fs8.existsSync(scopeDir)) return;
13593
13816
  for (const entry of fs8.readdirSync(scopeDir)) {
13594
13817
  if (!entry.startsWith(`.${name}-`)) continue;
13595
- fs8.rmSync(path15.join(scopeDir, entry), { recursive: true, force: true });
13596
- appendUpgradeLog(`Removed stale scoped staging dir: ${path15.join(scopeDir, entry)}`);
13818
+ fs8.rmSync(path16.join(scopeDir, entry), { recursive: true, force: true });
13819
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path16.join(scopeDir, entry)}`);
13597
13820
  }
13598
13821
  } else {
13599
13822
  for (const entry of fs8.readdirSync(npmRoot)) {
13600
13823
  if (!entry.startsWith(`.${pkgName}-`)) continue;
13601
- fs8.rmSync(path15.join(npmRoot, entry), { recursive: true, force: true });
13602
- appendUpgradeLog(`Removed stale staging dir: ${path15.join(npmRoot, entry)}`);
13824
+ fs8.rmSync(path16.join(npmRoot, entry), { recursive: true, force: true });
13825
+ appendUpgradeLog(`Removed stale staging dir: ${path16.join(npmRoot, entry)}`);
13603
13826
  }
13604
13827
  }
13605
13828
  if (fs8.existsSync(binDir)) {
13606
13829
  for (const entry of fs8.readdirSync(binDir)) {
13607
13830
  if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
13608
- fs8.rmSync(path15.join(binDir, entry), { recursive: true, force: true });
13609
- appendUpgradeLog(`Removed stale bin staging entry: ${path15.join(binDir, entry)}`);
13831
+ fs8.rmSync(path16.join(binDir, entry), { recursive: true, force: true });
13832
+ appendUpgradeLog(`Removed stale bin staging entry: ${path16.join(binDir, entry)}`);
13610
13833
  }
13611
13834
  }
13612
13835
  }
@@ -13692,6 +13915,18 @@ var CHAT_COMMANDS = [
13692
13915
  "change_model"
13693
13916
  ];
13694
13917
  var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
13918
+ function normalizeCommandSource(source) {
13919
+ switch (source) {
13920
+ case "ws":
13921
+ case "p2p":
13922
+ case "ext":
13923
+ case "api":
13924
+ case "standalone":
13925
+ return source;
13926
+ default:
13927
+ return "unknown";
13928
+ }
13929
+ }
13695
13930
  function toHostedCliRuntimeDescriptor(record) {
13696
13931
  if (!record || typeof record !== "object") return null;
13697
13932
  const runtimeId = typeof record.sessionId === "string" ? record.sessionId : "";
@@ -13729,20 +13964,21 @@ var DaemonCommandRouter = class {
13729
13964
  */
13730
13965
  async execute(cmd, args, source = "unknown") {
13731
13966
  const cmdStart = Date.now();
13967
+ const logSource = normalizeCommandSource(source);
13732
13968
  try {
13733
13969
  const daemonResult = await this.executeDaemonCommand(cmd, args);
13734
13970
  if (daemonResult) {
13735
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
13971
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
13736
13972
  return daemonResult;
13737
13973
  }
13738
13974
  const handlerResult = await this.deps.commandHandler.handle(cmd, args);
13739
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
13975
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
13740
13976
  if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
13741
13977
  this.deps.onPostChatCommand();
13742
13978
  }
13743
13979
  return handlerResult;
13744
13980
  } catch (e) {
13745
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
13981
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
13746
13982
  throw e;
13747
13983
  }
13748
13984
  }
@@ -14012,7 +14248,7 @@ var DaemonCommandRouter = class {
14012
14248
  } catch {
14013
14249
  }
14014
14250
  }
14015
- return { success: result.success, ...result };
14251
+ return { ...result };
14016
14252
  }
14017
14253
  // ─── Detect IDEs ───
14018
14254
  case "detect_ides": {
@@ -14142,16 +14378,14 @@ var DaemonCommandRouter = class {
14142
14378
  }
14143
14379
  }
14144
14380
  for (const instanceKey of keysToRemove) {
14145
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
14146
- if (ideInstance) {
14381
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
14147
14382
  this.deps.instanceManager.removeInstance(instanceKey);
14148
14383
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
14149
14384
  }
14150
14385
  }
14151
14386
  if (keysToRemove.length === 0) {
14152
14387
  const instanceKey = `ide:${ideType}`;
14153
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
14154
- if (ideInstance) {
14388
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
14155
14389
  this.deps.instanceManager.removeInstance(instanceKey);
14156
14390
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
14157
14391
  }
@@ -14366,11 +14600,11 @@ var DaemonStatusReporter = class {
14366
14600
  // ─── P2P ─────────────────────────────────────────
14367
14601
  sendP2PPayload(payload) {
14368
14602
  const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
14369
- if (hashTarget.machine) {
14603
+ const hashPayload = hashTarget.machine ? (() => {
14370
14604
  const { freeMem: _f, availableMem: _a, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
14371
- hashTarget.machine = stableMachine;
14372
- }
14373
- const h = this.simpleHash(JSON.stringify(hashTarget));
14605
+ return { ...hashTarget, machine: stableMachine };
14606
+ })() : hashTarget;
14607
+ const h = this.simpleHash(JSON.stringify(hashPayload));
14374
14608
  if (h !== this.lastP2PStatusHash) {
14375
14609
  this.lastP2PStatusHash = h;
14376
14610
  this.deps.p2p?.sendStatus(payload);
@@ -14418,6 +14652,9 @@ var ProviderStreamAdapter = class {
14418
14652
  hasScript(name) {
14419
14653
  return typeof this.provider.scripts?.[name] === "function";
14420
14654
  }
14655
+ getStateTitle(state) {
14656
+ return typeof state.title === "string" ? state.title : "";
14657
+ }
14421
14658
  parseMaybeJson(raw) {
14422
14659
  if (typeof raw !== "string") return raw;
14423
14660
  try {
@@ -14621,7 +14858,7 @@ var ProviderStreamAdapter = class {
14621
14858
  for (let attempt = 0; attempt < 6; attempt += 1) {
14622
14859
  await new Promise((resolve12) => setTimeout(resolve12, 250));
14623
14860
  const state = await this.readChat(evaluate);
14624
- const title = typeof state.title === "string" ? state.title : "";
14861
+ const title = this.getStateTitle(state);
14625
14862
  if (this.titlesMatch(title, sessionId)) return true;
14626
14863
  }
14627
14864
  return false;
@@ -14718,6 +14955,11 @@ var DaemonAgentStreamManager = class {
14718
14955
  const child = (this.sessionRegistry?.listChildren(parentSessionId) || []).find((entry) => entry.transport === "cdp-webview" && entry.providerType === agentType);
14719
14956
  return child?.sessionId || null;
14720
14957
  }
14958
+ getStateError(state) {
14959
+ if (typeof state.error === "string" && state.error.trim()) return state.error.trim();
14960
+ if (typeof state._error === "string" && state._error.trim()) return state._error.trim();
14961
+ return "unknown";
14962
+ }
14721
14963
  async connectManagedSession(cdp, parentSessionId, runtimeSessionId) {
14722
14964
  const target = this.getSessionTarget(runtimeSessionId);
14723
14965
  if (!target || target.transport !== "cdp-webview") return null;
@@ -14780,8 +15022,8 @@ var DaemonAgentStreamManager = class {
14780
15022
  try {
14781
15023
  const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
14782
15024
  const state = await agent.adapter.readChat(evaluate);
14783
- 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") : ""}`);
14784
- const stateError = String(state.error || state._error || "");
15025
+ const stateError = this.getStateError(state);
15026
+ 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) : ""}`);
14785
15027
  if (state.status === "error" && this.isRecoverableSessionError(stateError)) {
14786
15028
  throw new Error(stateError);
14787
15029
  }
@@ -15350,11 +15592,11 @@ var ProviderInstanceManager = class {
15350
15592
 
15351
15593
  // src/providers/version-archive.ts
15352
15594
  var fs10 = __toESM(require("fs"));
15353
- var path16 = __toESM(require("path"));
15354
- var os16 = __toESM(require("os"));
15595
+ var path17 = __toESM(require("path"));
15596
+ var os18 = __toESM(require("os"));
15355
15597
  var import_child_process9 = require("child_process");
15356
15598
  var import_os3 = require("os");
15357
- var ARCHIVE_PATH = path16.join(os16.homedir(), ".adhdev", "version-history.json");
15599
+ var ARCHIVE_PATH = path17.join(os18.homedir(), ".adhdev", "version-history.json");
15358
15600
  var MAX_ENTRIES_PER_PROVIDER = 20;
15359
15601
  var VersionArchive = class {
15360
15602
  history = {};
@@ -15401,7 +15643,7 @@ var VersionArchive = class {
15401
15643
  }
15402
15644
  save() {
15403
15645
  try {
15404
- fs10.mkdirSync(path16.dirname(ARCHIVE_PATH), { recursive: true });
15646
+ fs10.mkdirSync(path17.dirname(ARCHIVE_PATH), { recursive: true });
15405
15647
  fs10.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
15406
15648
  } catch {
15407
15649
  }
@@ -15427,6 +15669,22 @@ function parseVersion2(raw) {
15427
15669
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
15428
15670
  return match ? match[1] : raw.split("\n")[0].substring(0, 100);
15429
15671
  }
15672
+ function getPlatformVersionCommand(versionCommand, currentOs) {
15673
+ if (!versionCommand) return void 0;
15674
+ if (typeof versionCommand === "string") {
15675
+ const trimmed = versionCommand.trim();
15676
+ return trimmed || void 0;
15677
+ }
15678
+ const platformValue = versionCommand[currentOs];
15679
+ if (typeof platformValue === "string" && platformValue.trim()) {
15680
+ return platformValue.trim();
15681
+ }
15682
+ const defaultValue = versionCommand.default;
15683
+ if (typeof defaultValue === "string" && defaultValue.trim()) {
15684
+ return defaultValue.trim();
15685
+ }
15686
+ return void 0;
15687
+ }
15430
15688
  function getVersion(binary, versionCommand) {
15431
15689
  if (versionCommand) {
15432
15690
  const raw = runCommand(versionCommand);
@@ -15441,8 +15699,8 @@ function getVersion(binary, versionCommand) {
15441
15699
  function checkPathExists2(paths) {
15442
15700
  for (const p of paths) {
15443
15701
  if (p.includes("*")) {
15444
- const home = os16.homedir();
15445
- const resolved = p.replace(/\*/g, home.split(path16.sep).pop() || "");
15702
+ const home = os18.homedir();
15703
+ const resolved = p.replace(/\*/g, home.split(path17.sep).pop() || "");
15446
15704
  if (fs10.existsSync(resolved)) return resolved;
15447
15705
  } else {
15448
15706
  if (fs10.existsSync(p)) return p;
@@ -15452,7 +15710,7 @@ function checkPathExists2(paths) {
15452
15710
  }
15453
15711
  function getMacAppVersion(appPath) {
15454
15712
  if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
15455
- const plistPath = path16.join(appPath, "Contents", "Info.plist");
15713
+ const plistPath = path17.join(appPath, "Contents", "Info.plist");
15456
15714
  if (!fs10.existsSync(plistPath)) return null;
15457
15715
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
15458
15716
  return raw || null;
@@ -15471,15 +15729,14 @@ async function detectAllVersions(loader, archive) {
15471
15729
  binary: null,
15472
15730
  detectedAt: (/* @__PURE__ */ new Date()).toISOString()
15473
15731
  };
15474
- const verCmdConfig = provider.versionCommand;
15475
- const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[currentOs] : verCmdConfig;
15732
+ const versionCommand = getPlatformVersionCommand(provider.versionCommand, currentOs);
15476
15733
  if (provider.category === "ide") {
15477
15734
  const osPaths = provider.paths?.[currentOs] || [];
15478
15735
  const appPath = checkPathExists2(osPaths);
15479
15736
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
15480
15737
  let resolvedBin = cliBin;
15481
15738
  if (!resolvedBin && appPath && currentOs === "darwin") {
15482
- const bundled = path16.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
15739
+ const bundled = path17.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
15483
15740
  if (provider.cli && fs10.existsSync(bundled)) resolvedBin = bundled;
15484
15741
  }
15485
15742
  info.installed = !!(appPath || resolvedBin);
@@ -15520,7 +15777,7 @@ async function detectAllVersions(loader, archive) {
15520
15777
  // src/daemon/dev-server.ts
15521
15778
  var http2 = __toESM(require("http"));
15522
15779
  var fs14 = __toESM(require("fs"));
15523
- var path20 = __toESM(require("path"));
15780
+ var path21 = __toESM(require("path"));
15524
15781
 
15525
15782
  // src/daemon/scaffold-template.ts
15526
15783
  function generateFiles(type, name, category, opts = {}) {
@@ -15856,7 +16113,7 @@ init_logger();
15856
16113
 
15857
16114
  // src/daemon/dev-cdp-handlers.ts
15858
16115
  var fs11 = __toESM(require("fs"));
15859
- var path17 = __toESM(require("path"));
16116
+ var path18 = __toESM(require("path"));
15860
16117
  init_logger();
15861
16118
  async function handleCdpEvaluate(ctx, req, res) {
15862
16119
  const body = await ctx.readBody(req);
@@ -16035,17 +16292,17 @@ async function handleScriptHints(ctx, type, _req, res) {
16035
16292
  return;
16036
16293
  }
16037
16294
  let scriptsPath = "";
16038
- const directScripts = path17.join(dir, "scripts.js");
16295
+ const directScripts = path18.join(dir, "scripts.js");
16039
16296
  if (fs11.existsSync(directScripts)) {
16040
16297
  scriptsPath = directScripts;
16041
16298
  } else {
16042
- const scriptsDir = path17.join(dir, "scripts");
16299
+ const scriptsDir = path18.join(dir, "scripts");
16043
16300
  if (fs11.existsSync(scriptsDir)) {
16044
16301
  const versions = fs11.readdirSync(scriptsDir).filter((d) => {
16045
- return fs11.statSync(path17.join(scriptsDir, d)).isDirectory();
16302
+ return fs11.statSync(path18.join(scriptsDir, d)).isDirectory();
16046
16303
  }).sort().reverse();
16047
16304
  for (const ver of versions) {
16048
- const p = path17.join(scriptsDir, ver, "scripts.js");
16305
+ const p = path18.join(scriptsDir, ver, "scripts.js");
16049
16306
  if (fs11.existsSync(p)) {
16050
16307
  scriptsPath = p;
16051
16308
  break;
@@ -16864,7 +17121,7 @@ async function handleDomContext(ctx, type, req, res) {
16864
17121
 
16865
17122
  // src/daemon/dev-cli-debug.ts
16866
17123
  var fs12 = __toESM(require("fs"));
16867
- var path18 = __toESM(require("path"));
17124
+ var path19 = __toESM(require("path"));
16868
17125
  function slugifyFixtureName(value) {
16869
17126
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
16870
17127
  return normalized || `fixture-${Date.now()}`;
@@ -16874,11 +17131,11 @@ function getCliFixtureDir(ctx, type) {
16874
17131
  if (!providerDir) {
16875
17132
  throw new Error(`Provider directory not found for '${type}'`);
16876
17133
  }
16877
- return path18.join(providerDir, "fixtures");
17134
+ return path19.join(providerDir, "fixtures");
16878
17135
  }
16879
17136
  function readCliFixture(ctx, type, name) {
16880
17137
  const fixtureDir = getCliFixtureDir(ctx, type);
16881
- const filePath = path18.join(fixtureDir, `${name}.json`);
17138
+ const filePath = path19.join(fixtureDir, `${name}.json`);
16882
17139
  if (!fs12.existsSync(filePath)) {
16883
17140
  throw new Error(`Fixture not found: ${filePath}`);
16884
17141
  }
@@ -17004,6 +17261,15 @@ function validateCliFixtureResult(result, assertions) {
17004
17261
  }
17005
17262
  return failures;
17006
17263
  }
17264
+ function isCliTargetState(state) {
17265
+ return state.category === "cli" || state.category === "acp";
17266
+ }
17267
+ function getCliAdapterFromInstance(instance) {
17268
+ if (!instance) return null;
17269
+ const candidate = instance;
17270
+ if (typeof candidate.getAdapter === "function") return candidate.getAdapter();
17271
+ return candidate.adapter || null;
17272
+ }
17007
17273
  function getCliProviderResolutionMeta(ctx, type, adapter) {
17008
17274
  const adapterMeta = typeof adapter?.getProviderResolutionMeta === "function" ? adapter.getProviderResolutionMeta() : adapter?.getDebugState?.()?.providerResolution || null;
17009
17275
  const resolvedProvider = ctx.providerLoader.resolve(type);
@@ -17021,7 +17287,7 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
17021
17287
  }
17022
17288
  function findCliTarget(ctx, type, instanceId) {
17023
17289
  if (!ctx.instanceManager) return null;
17024
- const cliStates = ctx.instanceManager.collectAllStates().filter((s) => s.category === "cli" || s.category === "acp");
17290
+ const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
17025
17291
  if (instanceId) return cliStates.find((s) => s.instanceId === instanceId) || null;
17026
17292
  if (!type) return cliStates[cliStates.length - 1] || null;
17027
17293
  const matches = cliStates.filter((s) => s.type === type);
@@ -17033,7 +17299,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
17033
17299
  if (!target) return null;
17034
17300
  const instance = ctx.instanceManager.getInstance(target.instanceId);
17035
17301
  if (!instance) return null;
17036
- const adapter = instance.getAdapter?.() || instance.adapter;
17302
+ const adapter = getCliAdapterFromInstance(instance);
17037
17303
  if (!adapter) return null;
17038
17304
  return { target, instance, adapter };
17039
17305
  }
@@ -17508,7 +17774,7 @@ async function handleCliDebug(ctx, type, _req, res) {
17508
17774
  return;
17509
17775
  }
17510
17776
  try {
17511
- const adapter = instance.getAdapter?.() || instance.adapter;
17777
+ const adapter = getCliAdapterFromInstance(instance);
17512
17778
  if (adapter && typeof adapter.getDebugState === "function") {
17513
17779
  const debugState = adapter.getDebugState();
17514
17780
  ctx.json(res, 200, {
@@ -17555,7 +17821,7 @@ async function handleCliTrace(ctx, type, req, res) {
17555
17821
  return;
17556
17822
  }
17557
17823
  try {
17558
- const adapter = instance.getAdapter?.() || instance.adapter;
17824
+ const adapter = getCliAdapterFromInstance(instance);
17559
17825
  const url = new URL(req.url || "/", "http://127.0.0.1");
17560
17826
  const limit = parseInt(url.searchParams.get("limit") || "120", 10);
17561
17827
  if (adapter && typeof adapter.getTraceState === "function") {
@@ -17637,7 +17903,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
17637
17903
  },
17638
17904
  notes: typeof body?.notes === "string" ? body.notes : void 0
17639
17905
  };
17640
- const filePath = path18.join(fixtureDir, `${name}.json`);
17906
+ const filePath = path19.join(fixtureDir, `${name}.json`);
17641
17907
  fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
17642
17908
  ctx.json(res, 200, {
17643
17909
  saved: true,
@@ -17661,7 +17927,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
17661
17927
  return;
17662
17928
  }
17663
17929
  const fixtures = fs12.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
17664
- const fullPath = path18.join(fixtureDir, file);
17930
+ const fullPath = path19.join(fixtureDir, file);
17665
17931
  try {
17666
17932
  const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
17667
17933
  return {
@@ -17741,7 +18007,7 @@ async function handleCliResolve(ctx, req, res) {
17741
18007
  return;
17742
18008
  }
17743
18009
  const instance = ctx.instanceManager.getInstance(target.instanceId);
17744
- const adapter = instance?.getAdapter?.() || instance?.adapter;
18010
+ const adapter = getCliAdapterFromInstance(instance);
17745
18011
  if (!adapter) {
17746
18012
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
17747
18013
  return;
@@ -17778,7 +18044,7 @@ async function handleCliRaw(ctx, req, res) {
17778
18044
  return;
17779
18045
  }
17780
18046
  const instance = ctx.instanceManager.getInstance(target.instanceId);
17781
- const adapter = instance?.getAdapter?.() || instance?.adapter;
18047
+ const adapter = getCliAdapterFromInstance(instance);
17782
18048
  if (!adapter) {
17783
18049
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
17784
18050
  return;
@@ -17797,11 +18063,11 @@ async function handleCliRaw(ctx, req, res) {
17797
18063
 
17798
18064
  // src/daemon/dev-auto-implement.ts
17799
18065
  var fs13 = __toESM(require("fs"));
17800
- var path19 = __toESM(require("path"));
17801
- var os17 = __toESM(require("os"));
18066
+ var path20 = __toESM(require("path"));
18067
+ var os19 = __toESM(require("os"));
17802
18068
  function getAutoImplPid(ctx) {
17803
- const proc = ctx.autoImplProcess;
17804
- return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
18069
+ const pid = ctx.autoImplProcess?.pid;
18070
+ return typeof pid === "number" && pid > 0 ? pid : null;
17805
18071
  }
17806
18072
  function isPidAlive(pid) {
17807
18073
  try {
@@ -17819,6 +18085,13 @@ function clearStaleAutoImplState(ctx, reason) {
17819
18085
  ctx.autoImplProcess = null;
17820
18086
  ctx.autoImplStatus.running = false;
17821
18087
  }
18088
+ function tryKillAutoImplProcess(processRef, signal) {
18089
+ if (!processRef) return;
18090
+ try {
18091
+ processRef.kill(signal);
18092
+ } catch {
18093
+ }
18094
+ }
17822
18095
  function getDefaultAutoImplReference(ctx, category, type) {
17823
18096
  if (category === "cli") {
17824
18097
  return type === "codex-cli" ? "claude-cli" : "codex-cli";
@@ -17837,22 +18110,22 @@ function getLatestScriptVersionDir(scriptsDir) {
17837
18110
  if (!fs13.existsSync(scriptsDir)) return null;
17838
18111
  const versions = fs13.readdirSync(scriptsDir).filter((d) => {
17839
18112
  try {
17840
- return fs13.statSync(path19.join(scriptsDir, d)).isDirectory();
18113
+ return fs13.statSync(path20.join(scriptsDir, d)).isDirectory();
17841
18114
  } catch {
17842
18115
  return false;
17843
18116
  }
17844
18117
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
17845
18118
  if (versions.length === 0) return null;
17846
- return path19.join(scriptsDir, versions[0]);
18119
+ return path20.join(scriptsDir, versions[0]);
17847
18120
  }
17848
18121
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
17849
- const canonicalUserDir = path19.resolve(ctx.providerLoader.getUserProviderDir(category, type));
17850
- const desiredDir = requestedDir ? path19.resolve(requestedDir) : canonicalUserDir;
17851
- const upstreamRoot = path19.resolve(ctx.providerLoader.getUpstreamDir());
17852
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path19.sep}`)) {
18122
+ const canonicalUserDir = path20.resolve(ctx.providerLoader.getUserProviderDir(category, type));
18123
+ const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
18124
+ const upstreamRoot = path20.resolve(ctx.providerLoader.getUpstreamDir());
18125
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
17853
18126
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
17854
18127
  }
17855
- if (path19.basename(desiredDir) !== type) {
18128
+ if (path20.basename(desiredDir) !== type) {
17856
18129
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
17857
18130
  }
17858
18131
  const sourceDir = ctx.findProviderDir(type);
@@ -17860,11 +18133,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
17860
18133
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
17861
18134
  }
17862
18135
  if (!fs13.existsSync(desiredDir)) {
17863
- fs13.mkdirSync(path19.dirname(desiredDir), { recursive: true });
18136
+ fs13.mkdirSync(path20.dirname(desiredDir), { recursive: true });
17864
18137
  fs13.cpSync(sourceDir, desiredDir, { recursive: true });
17865
18138
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
17866
18139
  }
17867
- const providerJson = path19.join(desiredDir, "provider.json");
18140
+ const providerJson = path20.join(desiredDir, "provider.json");
17868
18141
  if (!fs13.existsSync(providerJson)) {
17869
18142
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
17870
18143
  }
@@ -17887,13 +18160,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
17887
18160
  const refDir = ctx.findProviderDir(referenceType);
17888
18161
  if (!refDir || !fs13.existsSync(refDir)) return {};
17889
18162
  const referenceScripts = {};
17890
- const scriptsDir = path19.join(refDir, "scripts");
18163
+ const scriptsDir = path20.join(refDir, "scripts");
17891
18164
  const latestDir = getLatestScriptVersionDir(scriptsDir);
17892
18165
  if (!latestDir) return referenceScripts;
17893
18166
  for (const file of fs13.readdirSync(latestDir)) {
17894
18167
  if (!file.endsWith(".js")) continue;
17895
18168
  try {
17896
- referenceScripts[file] = fs13.readFileSync(path19.join(latestDir, file), "utf-8");
18169
+ referenceScripts[file] = fs13.readFileSync(path20.join(latestDir, file), "utf-8");
17897
18170
  } catch {
17898
18171
  }
17899
18172
  }
@@ -18001,9 +18274,9 @@ async function handleAutoImplement(ctx, type, req, res) {
18001
18274
  });
18002
18275
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
18003
18276
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
18004
- const tmpDir = path19.join(os17.tmpdir(), "adhdev-autoimpl");
18277
+ const tmpDir = path20.join(os19.tmpdir(), "adhdev-autoimpl");
18005
18278
  if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
18006
- const promptFile = path19.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
18279
+ const promptFile = path20.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
18007
18280
  fs13.writeFileSync(promptFile, prompt, "utf-8");
18008
18281
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
18009
18282
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -18155,7 +18428,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18155
18428
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
18156
18429
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
18157
18430
  let shellCmd;
18158
- const isWin = os17.platform() === "win32";
18431
+ const isWin = os19.platform() === "win32";
18159
18432
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
18160
18433
  if (command === "claude") {
18161
18434
  const args = [...baseArgs, "--dangerously-skip-permissions"];
@@ -18199,7 +18472,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18199
18472
  try {
18200
18473
  const pty = require("node-pty");
18201
18474
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
18202
- const isWin2 = os17.platform() === "win32";
18475
+ const isWin2 = os19.platform() === "win32";
18203
18476
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
18204
18477
  name: "xterm-256color",
18205
18478
  cols: 120,
@@ -18238,10 +18511,12 @@ async function handleAutoImplement(ctx, type, req, res) {
18238
18511
  let autoStopTimer = null;
18239
18512
  let autoStopIssued = false;
18240
18513
  try {
18241
- const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
18242
- const normalized = normalizeCliProviderForRuntime2(agentProvider);
18243
- approvalPatterns = normalized.patterns.approval;
18244
- approvalKeys = agentProvider?.approvalKeys || { 0: "y\r", 1: "a\r" };
18514
+ if (agentProvider?.category === "cli") {
18515
+ const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
18516
+ const normalized = normalizeCliProviderForRuntime2(agentProvider);
18517
+ approvalPatterns = normalized.patterns.approval;
18518
+ approvalKeys = agentProvider.approvalKeys || { 0: "y\r", 1: "a\r" };
18519
+ }
18245
18520
  } catch (err) {
18246
18521
  ctx.log(`Failed to load approval patterns: ${err.message}`);
18247
18522
  }
@@ -18256,10 +18531,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18256
18531
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
18257
18532
  `, stream: "stdout" } });
18258
18533
  approvalBuffer = "";
18259
- try {
18260
- ctx.autoImplProcess.kill("SIGINT");
18261
- } catch {
18262
- }
18534
+ tryKillAutoImplProcess(ctx.autoImplProcess, "SIGINT");
18263
18535
  return;
18264
18536
  }
18265
18537
  if (Date.now() - lastApprovalTime < 2e3) return;
@@ -18296,10 +18568,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18296
18568
  stream: "stdout"
18297
18569
  }
18298
18570
  });
18299
- try {
18300
- ctx.autoImplProcess.kill("SIGINT");
18301
- } catch {
18302
- }
18571
+ tryKillAutoImplProcess(ctx.autoImplProcess, "SIGINT");
18303
18572
  }, 3e4);
18304
18573
  };
18305
18574
  const finalizeCliAutoImpl = async (code) => {
@@ -18430,7 +18699,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18430
18699
  setMode: "set_mode.js"
18431
18700
  };
18432
18701
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
18433
- const scriptsDir = path19.join(providerDir, "scripts");
18702
+ const scriptsDir = path20.join(providerDir, "scripts");
18434
18703
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
18435
18704
  if (latestScriptsDir) {
18436
18705
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -18441,7 +18710,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18441
18710
  for (const file of fs13.readdirSync(latestScriptsDir)) {
18442
18711
  if (file.endsWith(".js") && targetFileNames.has(file)) {
18443
18712
  try {
18444
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18713
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18445
18714
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
18446
18715
  lines.push("```javascript");
18447
18716
  lines.push(content);
@@ -18458,7 +18727,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18458
18727
  lines.push("");
18459
18728
  for (const file of refFiles) {
18460
18729
  try {
18461
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18730
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18462
18731
  lines.push(`### \`${file}\` \u{1F512}`);
18463
18732
  lines.push("```javascript");
18464
18733
  lines.push(content);
@@ -18499,10 +18768,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18499
18768
  lines.push("");
18500
18769
  }
18501
18770
  }
18502
- const docsDir = path19.join(providerDir, "../../docs");
18771
+ const docsDir = path20.join(providerDir, "../../docs");
18503
18772
  const loadGuide = (name) => {
18504
18773
  try {
18505
- const p = path19.join(docsDir, name);
18774
+ const p = path20.join(docsDir, name);
18506
18775
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
18507
18776
  } catch {
18508
18777
  }
@@ -18737,7 +19006,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18737
19006
  parseApproval: "parse_approval.js"
18738
19007
  };
18739
19008
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
18740
- const scriptsDir = path19.join(providerDir, "scripts");
19009
+ const scriptsDir = path20.join(providerDir, "scripts");
18741
19010
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
18742
19011
  if (latestScriptsDir) {
18743
19012
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -18749,7 +19018,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18749
19018
  if (!file.endsWith(".js")) continue;
18750
19019
  if (!targetFileNames.has(file)) continue;
18751
19020
  try {
18752
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
19021
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18753
19022
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
18754
19023
  lines.push("```javascript");
18755
19024
  lines.push(content);
@@ -18765,7 +19034,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18765
19034
  lines.push("");
18766
19035
  for (const file of refFiles) {
18767
19036
  try {
18768
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
19037
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18769
19038
  lines.push(`### \`${file}\` \u{1F512}`);
18770
19039
  lines.push("```javascript");
18771
19040
  lines.push(content);
@@ -18798,10 +19067,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18798
19067
  lines.push("");
18799
19068
  }
18800
19069
  }
18801
- const docsDir = path19.join(providerDir, "../../docs");
19070
+ const docsDir = path20.join(providerDir, "../../docs");
18802
19071
  const loadGuide = (name) => {
18803
19072
  try {
18804
- const p = path19.join(docsDir, name);
19073
+ const p = path20.join(docsDir, name);
18805
19074
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
18806
19075
  } catch {
18807
19076
  }
@@ -19116,6 +19385,38 @@ data: ${JSON.stringify(msg.data)}
19116
19385
 
19117
19386
  // src/daemon/dev-server.ts
19118
19387
  var DEV_SERVER_PORT = 19280;
19388
+ function getScriptNames(scripts) {
19389
+ if (!scripts) return [];
19390
+ return Object.entries(scripts).filter(([, value]) => typeof value === "function").map(([name]) => name);
19391
+ }
19392
+ function toProviderListEntry(provider) {
19393
+ const base = {
19394
+ type: provider.type,
19395
+ name: provider.name,
19396
+ category: provider.category,
19397
+ icon: provider.icon || null,
19398
+ displayName: provider.displayName || provider.name
19399
+ };
19400
+ if (provider.category === "ide" || provider.category === "extension") {
19401
+ base.scripts = getScriptNames(provider.scripts);
19402
+ base.inputMethod = provider.inputMethod || null;
19403
+ base.inputSelector = provider.inputSelector || null;
19404
+ base.extensionId = provider.extensionId || null;
19405
+ base.cdpPorts = provider.cdpPorts || [];
19406
+ }
19407
+ if (provider.category === "acp") {
19408
+ base.spawn = provider.spawn || null;
19409
+ base.auth = provider.auth || null;
19410
+ base.install = provider.install || null;
19411
+ base.hasSettings = !!provider.settings;
19412
+ base.settingsCount = provider.settings ? Object.keys(provider.settings).length : 0;
19413
+ }
19414
+ if (provider.category === "cli") {
19415
+ base.spawn = provider.spawn || null;
19416
+ base.install = provider.install || null;
19417
+ }
19418
+ return base;
19419
+ }
19119
19420
  var DevServer = class _DevServer {
19120
19421
  server = null;
19121
19422
  providerLoader;
@@ -19212,8 +19513,8 @@ var DevServer = class _DevServer {
19212
19513
  }
19213
19514
  getEndpointList() {
19214
19515
  return this.routes.map((r) => {
19215
- const path21 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
19216
- return `${r.method.padEnd(5)} ${path21}`;
19516
+ const path22 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
19517
+ return `${r.method.padEnd(5)} ${path22}`;
19217
19518
  });
19218
19519
  }
19219
19520
  async start(port = DEV_SERVER_PORT) {
@@ -19265,34 +19566,7 @@ var DevServer = class _DevServer {
19265
19566
  }
19266
19567
  // ─── Handlers ───
19267
19568
  async handleListProviders(_req, res) {
19268
- const providers = this.providerLoader.getAll().map((p) => {
19269
- const base = {
19270
- type: p.type,
19271
- name: p.name,
19272
- category: p.category,
19273
- icon: p.icon || null,
19274
- displayName: p.displayName || p.name
19275
- };
19276
- if (p.category === "ide" || p.category === "extension") {
19277
- base.scripts = p.scripts ? Object.keys(p.scripts).filter((k) => typeof p.scripts[k] === "function") : [];
19278
- base.inputMethod = p.inputMethod || null;
19279
- base.inputSelector = p.inputSelector || null;
19280
- base.extensionId = p.extensionId || null;
19281
- base.cdpPorts = p.cdpPorts || [];
19282
- }
19283
- if (p.category === "acp") {
19284
- base.spawn = p.spawn || null;
19285
- base.auth = p.auth || null;
19286
- base.install = p.install || null;
19287
- base.hasSettings = !!p.settings;
19288
- base.settingsCount = p.settings ? Object.keys(p.settings).length : 0;
19289
- }
19290
- if (p.category === "cli") {
19291
- base.spawn = p.spawn || null;
19292
- base.install = p.install || null;
19293
- }
19294
- return base;
19295
- });
19569
+ const providers = this.providerLoader.getAll().map(toProviderListEntry);
19296
19570
  this.json(res, 200, { providers, count: providers.length });
19297
19571
  }
19298
19572
  async handleProviderConfig(type, _req, res) {
@@ -19484,7 +19758,7 @@ var DevServer = class _DevServer {
19484
19758
  }));
19485
19759
  for (const cdp of this.cdpManagers.values()) {
19486
19760
  if (!cdp.isConnected) {
19487
- cdp._targetId = null;
19761
+ cdp.clearTargetId();
19488
19762
  }
19489
19763
  }
19490
19764
  this.json(res, 200, { reloaded: true, providers });
@@ -19495,12 +19769,12 @@ var DevServer = class _DevServer {
19495
19769
  // ─── DevConsole SPA ───
19496
19770
  getConsoleDistDir() {
19497
19771
  const candidates = [
19498
- path20.resolve(__dirname, "../../web-devconsole/dist"),
19499
- path20.resolve(__dirname, "../../../web-devconsole/dist"),
19500
- path20.join(process.cwd(), "packages/web-devconsole/dist")
19772
+ path21.resolve(__dirname, "../../web-devconsole/dist"),
19773
+ path21.resolve(__dirname, "../../../web-devconsole/dist"),
19774
+ path21.join(process.cwd(), "packages/web-devconsole/dist")
19501
19775
  ];
19502
19776
  for (const dir of candidates) {
19503
- if (fs14.existsSync(path20.join(dir, "index.html"))) return dir;
19777
+ if (fs14.existsSync(path21.join(dir, "index.html"))) return dir;
19504
19778
  }
19505
19779
  return null;
19506
19780
  }
@@ -19510,7 +19784,7 @@ var DevServer = class _DevServer {
19510
19784
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
19511
19785
  return;
19512
19786
  }
19513
- const htmlPath = path20.join(distDir, "index.html");
19787
+ const htmlPath = path21.join(distDir, "index.html");
19514
19788
  try {
19515
19789
  const html = fs14.readFileSync(htmlPath, "utf-8");
19516
19790
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -19535,15 +19809,15 @@ var DevServer = class _DevServer {
19535
19809
  this.json(res, 404, { error: "Not found" });
19536
19810
  return;
19537
19811
  }
19538
- const safePath = path20.normalize(pathname).replace(/^\.\.\//, "");
19539
- const filePath = path20.join(distDir, safePath);
19812
+ const safePath = path21.normalize(pathname).replace(/^\.\.\//, "");
19813
+ const filePath = path21.join(distDir, safePath);
19540
19814
  if (!filePath.startsWith(distDir)) {
19541
19815
  this.json(res, 403, { error: "Forbidden" });
19542
19816
  return;
19543
19817
  }
19544
19818
  try {
19545
19819
  const content = fs14.readFileSync(filePath);
19546
- const ext = path20.extname(filePath);
19820
+ const ext = path21.extname(filePath);
19547
19821
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
19548
19822
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
19549
19823
  res.end(content);
@@ -19656,9 +19930,9 @@ var DevServer = class _DevServer {
19656
19930
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
19657
19931
  if (entry.isDirectory()) {
19658
19932
  files.push({ path: rel, size: 0, type: "dir" });
19659
- scan(path20.join(d, entry.name), rel);
19933
+ scan(path21.join(d, entry.name), rel);
19660
19934
  } else {
19661
- const stat = fs14.statSync(path20.join(d, entry.name));
19935
+ const stat = fs14.statSync(path21.join(d, entry.name));
19662
19936
  files.push({ path: rel, size: stat.size, type: "file" });
19663
19937
  }
19664
19938
  }
@@ -19681,7 +19955,7 @@ var DevServer = class _DevServer {
19681
19955
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
19682
19956
  return;
19683
19957
  }
19684
- const fullPath = path20.resolve(dir, path20.normalize(filePath));
19958
+ const fullPath = path21.resolve(dir, path21.normalize(filePath));
19685
19959
  if (!fullPath.startsWith(dir)) {
19686
19960
  this.json(res, 403, { error: "Forbidden" });
19687
19961
  return;
@@ -19706,14 +19980,14 @@ var DevServer = class _DevServer {
19706
19980
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
19707
19981
  return;
19708
19982
  }
19709
- const fullPath = path20.resolve(dir, path20.normalize(filePath));
19983
+ const fullPath = path21.resolve(dir, path21.normalize(filePath));
19710
19984
  if (!fullPath.startsWith(dir)) {
19711
19985
  this.json(res, 403, { error: "Forbidden" });
19712
19986
  return;
19713
19987
  }
19714
19988
  try {
19715
19989
  if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
19716
- fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
19990
+ fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
19717
19991
  fs14.writeFileSync(fullPath, content, "utf-8");
19718
19992
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
19719
19993
  this.providerLoader.reload();
@@ -19730,7 +20004,7 @@ var DevServer = class _DevServer {
19730
20004
  return;
19731
20005
  }
19732
20006
  for (const name of ["scripts.js", "provider.json"]) {
19733
- const p = path20.join(dir, name);
20007
+ const p = path21.join(dir, name);
19734
20008
  if (fs14.existsSync(p)) {
19735
20009
  const source = fs14.readFileSync(p, "utf-8");
19736
20010
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -19751,8 +20025,8 @@ var DevServer = class _DevServer {
19751
20025
  this.json(res, 404, { error: `Provider not found: ${type}` });
19752
20026
  return;
19753
20027
  }
19754
- const target = fs14.existsSync(path20.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
19755
- const targetPath = path20.join(dir, target);
20028
+ const target = fs14.existsSync(path21.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
20029
+ const targetPath = path21.join(dir, target);
19756
20030
  try {
19757
20031
  if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
19758
20032
  fs14.writeFileSync(targetPath, source, "utf-8");
@@ -19912,7 +20186,7 @@ var DevServer = class _DevServer {
19912
20186
  }
19913
20187
  let targetDir;
19914
20188
  targetDir = this.providerLoader.getUserProviderDir(category, type);
19915
- const jsonPath = path20.join(targetDir, "provider.json");
20189
+ const jsonPath = path21.join(targetDir, "provider.json");
19916
20190
  if (fs14.existsSync(jsonPath)) {
19917
20191
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
19918
20192
  return;
@@ -19924,8 +20198,8 @@ var DevServer = class _DevServer {
19924
20198
  const createdFiles = ["provider.json"];
19925
20199
  if (result.files) {
19926
20200
  for (const [relPath, content] of Object.entries(result.files)) {
19927
- const fullPath = path20.join(targetDir, relPath);
19928
- fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
20201
+ const fullPath = path21.join(targetDir, relPath);
20202
+ fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
19929
20203
  fs14.writeFileSync(fullPath, content, "utf-8");
19930
20204
  createdFiles.push(relPath);
19931
20205
  }
@@ -19978,22 +20252,22 @@ var DevServer = class _DevServer {
19978
20252
  if (!fs14.existsSync(scriptsDir)) return null;
19979
20253
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
19980
20254
  try {
19981
- return fs14.statSync(path20.join(scriptsDir, d)).isDirectory();
20255
+ return fs14.statSync(path21.join(scriptsDir, d)).isDirectory();
19982
20256
  } catch {
19983
20257
  return false;
19984
20258
  }
19985
20259
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
19986
20260
  if (versions.length === 0) return null;
19987
- return path20.join(scriptsDir, versions[0]);
20261
+ return path21.join(scriptsDir, versions[0]);
19988
20262
  }
19989
20263
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
19990
- const canonicalUserDir = path20.resolve(this.providerLoader.getUserProviderDir(category, type));
19991
- const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
19992
- const upstreamRoot = path20.resolve(this.providerLoader.getUpstreamDir());
19993
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
20264
+ const canonicalUserDir = path21.resolve(this.providerLoader.getUserProviderDir(category, type));
20265
+ const desiredDir = requestedDir ? path21.resolve(requestedDir) : canonicalUserDir;
20266
+ const upstreamRoot = path21.resolve(this.providerLoader.getUpstreamDir());
20267
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path21.sep}`)) {
19994
20268
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
19995
20269
  }
19996
- if (path20.basename(desiredDir) !== type) {
20270
+ if (path21.basename(desiredDir) !== type) {
19997
20271
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
19998
20272
  }
19999
20273
  const sourceDir = this.findProviderDir(type);
@@ -20001,11 +20275,11 @@ var DevServer = class _DevServer {
20001
20275
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
20002
20276
  }
20003
20277
  if (!fs14.existsSync(desiredDir)) {
20004
- fs14.mkdirSync(path20.dirname(desiredDir), { recursive: true });
20278
+ fs14.mkdirSync(path21.dirname(desiredDir), { recursive: true });
20005
20279
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
20006
20280
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
20007
20281
  }
20008
- const providerJson = path20.join(desiredDir, "provider.json");
20282
+ const providerJson = path21.join(desiredDir, "provider.json");
20009
20283
  if (!fs14.existsSync(providerJson)) {
20010
20284
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
20011
20285
  }
@@ -20053,7 +20327,7 @@ var DevServer = class _DevServer {
20053
20327
  setMode: "set_mode.js"
20054
20328
  };
20055
20329
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
20056
- const scriptsDir = path20.join(providerDir, "scripts");
20330
+ const scriptsDir = path21.join(providerDir, "scripts");
20057
20331
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
20058
20332
  if (latestScriptsDir) {
20059
20333
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -20064,7 +20338,7 @@ var DevServer = class _DevServer {
20064
20338
  for (const file of fs14.readdirSync(latestScriptsDir)) {
20065
20339
  if (file.endsWith(".js") && targetFileNames.has(file)) {
20066
20340
  try {
20067
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20341
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20068
20342
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
20069
20343
  lines.push("```javascript");
20070
20344
  lines.push(content);
@@ -20081,7 +20355,7 @@ var DevServer = class _DevServer {
20081
20355
  lines.push("");
20082
20356
  for (const file of refFiles) {
20083
20357
  try {
20084
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20358
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20085
20359
  lines.push(`### \`${file}\` \u{1F512}`);
20086
20360
  lines.push("```javascript");
20087
20361
  lines.push(content);
@@ -20122,10 +20396,10 @@ var DevServer = class _DevServer {
20122
20396
  lines.push("");
20123
20397
  }
20124
20398
  }
20125
- const docsDir = path20.join(providerDir, "../../docs");
20399
+ const docsDir = path21.join(providerDir, "../../docs");
20126
20400
  const loadGuide = (name) => {
20127
20401
  try {
20128
- const p = path20.join(docsDir, name);
20402
+ const p = path21.join(docsDir, name);
20129
20403
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
20130
20404
  } catch {
20131
20405
  }
@@ -20299,7 +20573,7 @@ var DevServer = class _DevServer {
20299
20573
  parseApproval: "parse_approval.js"
20300
20574
  };
20301
20575
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
20302
- const scriptsDir = path20.join(providerDir, "scripts");
20576
+ const scriptsDir = path21.join(providerDir, "scripts");
20303
20577
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
20304
20578
  if (latestScriptsDir) {
20305
20579
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -20311,7 +20585,7 @@ var DevServer = class _DevServer {
20311
20585
  if (!file.endsWith(".js")) continue;
20312
20586
  if (!targetFileNames.has(file)) continue;
20313
20587
  try {
20314
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20588
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20315
20589
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
20316
20590
  lines.push("```javascript");
20317
20591
  lines.push(content);
@@ -20327,7 +20601,7 @@ var DevServer = class _DevServer {
20327
20601
  lines.push("");
20328
20602
  for (const file of refFiles) {
20329
20603
  try {
20330
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20604
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20331
20605
  lines.push(`### \`${file}\` \u{1F512}`);
20332
20606
  lines.push("```javascript");
20333
20607
  lines.push(content);
@@ -20360,10 +20634,10 @@ var DevServer = class _DevServer {
20360
20634
  lines.push("");
20361
20635
  }
20362
20636
  }
20363
- const docsDir = path20.join(providerDir, "../../docs");
20637
+ const docsDir = path21.join(providerDir, "../../docs");
20364
20638
  const loadGuide = (name) => {
20365
20639
  try {
20366
- const p = path20.join(docsDir, name);
20640
+ const p = path21.join(docsDir, name);
20367
20641
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
20368
20642
  } catch {
20369
20643
  }