@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.mjs CHANGED
@@ -93,12 +93,10 @@ function ensureMachineId(config) {
93
93
  if (isStableMachineId(config.machineId)) {
94
94
  return { config, changed: false };
95
95
  }
96
- const legacyRegisteredMachineId = !config.registeredMachineId && config.machineSecret && config.machineId ? config.machineId : config.registeredMachineId;
97
96
  return {
98
97
  config: {
99
98
  ...config,
100
- machineId: generateMachineId(),
101
- registeredMachineId: legacyRegisteredMachineId
99
+ machineId: generateMachineId()
102
100
  },
103
101
  changed: true
104
102
  };
@@ -450,7 +448,7 @@ var init_logger = __esm({
450
448
  function isModuleNotFoundError(error, ref) {
451
449
  if (!(error instanceof Error)) return false;
452
450
  const message = error.message || "";
453
- const code = error.code;
451
+ const code = "code" in error ? error.code : void 0;
454
452
  return code === "MODULE_NOT_FOUND" && message.includes(ref);
455
453
  }
456
454
  function normalizeBinding(mod, ref) {
@@ -795,12 +793,7 @@ var init_pty_transport = __esm({
795
793
  }
796
794
  });
797
795
 
798
- // src/cli-adapters/provider-cli-adapter.ts
799
- var provider_cli_adapter_exports = {};
800
- __export(provider_cli_adapter_exports, {
801
- ProviderCliAdapter: () => ProviderCliAdapter,
802
- normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
803
- });
796
+ // src/cli-adapters/provider-cli-shared.ts
804
797
  import * as os8 from "os";
805
798
  import * as path9 from "path";
806
799
  import { execSync as execSync3 } from "child_process";
@@ -813,6 +806,10 @@ function stripTerminalNoise(str) {
813
806
  function sanitizeTerminalText(str) {
814
807
  return stripTerminalNoise(stripAnsi(str));
815
808
  }
809
+ function listCliScriptNames(scripts) {
810
+ if (!scripts) return [];
811
+ return Object.entries(scripts).filter(([, fn]) => typeof fn === "function").map(([name]) => name);
812
+ }
816
813
  function splitCliScreenLines(text) {
817
814
  return String(text || "").replace(/\u0007/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.replace(/\s+$/, ""));
818
815
  }
@@ -860,18 +857,6 @@ function buildCliScreenSnapshot(text) {
860
857
  linesBelowPrompt: promptLineIndex >= 0 ? lines.slice(promptLineIndex + 1) : []
861
858
  };
862
859
  }
863
- function computeTerminalQueryTail(buffer) {
864
- const prefixes = ["\x1B[6n", "\x1B[?6n"];
865
- const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
866
- const start = Math.max(0, buffer.length - maxLength);
867
- for (let i = start; i < buffer.length; i++) {
868
- const suffix = buffer.slice(i);
869
- if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
870
- return suffix;
871
- }
872
- }
873
- return "";
874
- }
875
860
  function findBinary(name) {
876
861
  const trimmed = String(name || "").trim();
877
862
  if (!trimmed) return trimmed;
@@ -1021,22 +1006,302 @@ function coercePatternArray(raw) {
1021
1006
  return raw.map(parsePatternEntry).filter((r) => r != null);
1022
1007
  }
1023
1008
  function normalizeCliProviderForRuntime(raw) {
1024
- const patterns = raw?.patterns || {};
1009
+ const patterns = raw && typeof raw === "object" ? raw.patterns : void 0;
1025
1010
  return {
1026
1011
  patterns: {
1027
- approval: coercePatternArray(patterns.approval)
1012
+ approval: coercePatternArray(
1013
+ patterns && typeof patterns === "object" ? patterns.approval : void 0
1014
+ )
1028
1015
  }
1029
1016
  };
1030
1017
  }
1031
- var buildCliSpawnEnv, ProviderCliAdapter;
1018
+ var buildCliSpawnEnv;
1019
+ var init_provider_cli_shared = __esm({
1020
+ "src/cli-adapters/provider-cli-shared.ts"() {
1021
+ "use strict";
1022
+ init_spawn_env();
1023
+ buildCliSpawnEnv = sanitizeSpawnEnv;
1024
+ }
1025
+ });
1026
+
1027
+ // src/cli-adapters/provider-cli-parse.ts
1028
+ function sliceFromOffset(text, start) {
1029
+ if (!text) return "";
1030
+ if (!Number.isFinite(start) || start <= 0) return text;
1031
+ if (start >= text.length) return "";
1032
+ return text.slice(start);
1033
+ }
1034
+ function hydrateCliParsedMessages(parsedMessages, options) {
1035
+ const { committedMessages, scope, lastOutputAt } = options;
1036
+ const referenceMessages = [...committedMessages];
1037
+ const usedReferenceIndexes = /* @__PURE__ */ new Set();
1038
+ const now = options.now ?? Date.now();
1039
+ const findReferenceTimestamp = (role, content, parsedIndex) => {
1040
+ const normalizedContent = normalizeComparableMessageContent(content);
1041
+ if (!normalizedContent) return void 0;
1042
+ const sameIndex = referenceMessages[parsedIndex];
1043
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1044
+ usedReferenceIndexes.add(parsedIndex);
1045
+ return sameIndex.timestamp;
1046
+ }
1047
+ for (let i = 0; i < referenceMessages.length; i++) {
1048
+ if (usedReferenceIndexes.has(i)) continue;
1049
+ const candidate = referenceMessages[i];
1050
+ if (!candidate || candidate.role !== role) continue;
1051
+ const candidateContent = normalizeComparableMessageContent(candidate.content);
1052
+ if (!candidateContent) continue;
1053
+ const exactMatch = candidateContent === normalizedContent;
1054
+ const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1055
+ if (!exactMatch && !fuzzyMatch) continue;
1056
+ if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1057
+ usedReferenceIndexes.add(i);
1058
+ return candidate.timestamp;
1059
+ }
1060
+ }
1061
+ return void 0;
1062
+ };
1063
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1064
+ const role = message.role;
1065
+ const content = typeof message.content === "string" ? message.content : String(message.content || "");
1066
+ const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1067
+ const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1068
+ const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
1069
+ const timestamp = referenceTimestamp ?? fallbackTimestamp;
1070
+ return {
1071
+ ...message,
1072
+ role,
1073
+ content,
1074
+ timestamp,
1075
+ receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1076
+ };
1077
+ });
1078
+ }
1079
+ function normalizeCliParsedMessages(parsedMessages, options) {
1080
+ return hydrateCliParsedMessages(parsedMessages, options).map((message) => ({
1081
+ role: message.role,
1082
+ content: message.content,
1083
+ timestamp: message.timestamp,
1084
+ receivedAt: message.receivedAt,
1085
+ kind: message.kind,
1086
+ id: message.id,
1087
+ index: message.index,
1088
+ meta: message.meta,
1089
+ senderName: message.senderName
1090
+ }));
1091
+ }
1092
+ function buildCliParseInput(options) {
1093
+ const {
1094
+ accumulatedBuffer,
1095
+ accumulatedRawBuffer,
1096
+ recentOutputBuffer,
1097
+ terminalScreenText,
1098
+ baseMessages,
1099
+ partialResponse,
1100
+ scope,
1101
+ runtimeSettings
1102
+ } = options;
1103
+ const buffer = scope ? sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer : accumulatedBuffer;
1104
+ const rawBuffer = scope ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer : accumulatedRawBuffer;
1105
+ const screenText = terminalScreenText;
1106
+ const recentBuffer = buffer.slice(-1e3) || recentOutputBuffer;
1107
+ return {
1108
+ buffer,
1109
+ rawBuffer,
1110
+ recentBuffer,
1111
+ screenText,
1112
+ screen: buildCliScreenSnapshot(screenText),
1113
+ bufferScreen: buildCliScreenSnapshot(buffer),
1114
+ recentScreen: buildCliScreenSnapshot(recentBuffer),
1115
+ messages: [...baseMessages],
1116
+ partialResponse,
1117
+ promptText: scope?.prompt || "",
1118
+ settings: { ...runtimeSettings }
1119
+ };
1120
+ }
1121
+ function summarizeCliTraceText(text, max = 800) {
1122
+ const value = sanitizeTerminalText(String(text || ""));
1123
+ if (value.length <= max) return value;
1124
+ return `\u2026${value.slice(-max)}`;
1125
+ }
1126
+ function summarizeCliTraceMessages(messages, limit = 3) {
1127
+ return messages.slice(-limit).map((message) => ({
1128
+ role: message.role,
1129
+ content: summarizeCliTraceText(message.content, 240),
1130
+ timestamp: message.timestamp
1131
+ }));
1132
+ }
1133
+ function buildCliTraceParseSnapshot(options) {
1134
+ const { accumulatedBuffer, accumulatedRawBuffer, responseBuffer, partialResponse, scope } = options;
1135
+ const scopedBuffer = scope ? sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer : accumulatedBuffer;
1136
+ const scopedRawBuffer = scope ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer : accumulatedRawBuffer;
1137
+ return {
1138
+ currentTurnScope: scope || null,
1139
+ responseBuffer: summarizeCliTraceText(responseBuffer, 1200),
1140
+ partialResponse: summarizeCliTraceText(partialResponse || responseBuffer, 1200),
1141
+ turnBuffer: summarizeCliTraceText(scopedBuffer, 1600),
1142
+ turnRawPreview: summarizeCliTraceText(scopedRawBuffer, 1600),
1143
+ turnSanitizedRawPreview: summarizeCliTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
1144
+ };
1145
+ }
1146
+ var init_provider_cli_parse = __esm({
1147
+ "src/cli-adapters/provider-cli-parse.ts"() {
1148
+ "use strict";
1149
+ init_provider_cli_shared();
1150
+ }
1151
+ });
1152
+
1153
+ // src/cli-adapters/provider-cli-config.ts
1154
+ function resolveCliAdapterConfig(provider) {
1155
+ const t = provider.timeouts || {};
1156
+ const rawKeys = provider.approvalKeys;
1157
+ return {
1158
+ timeouts: {
1159
+ ptyFlush: t.ptyFlush ?? 50,
1160
+ dialogAccept: t.dialogAccept ?? 300,
1161
+ approvalCooldown: t.approvalCooldown ?? 3e3,
1162
+ generatingIdle: t.generatingIdle ?? 6e3,
1163
+ idleFinish: t.idleFinish ?? 5e3,
1164
+ maxResponse: t.maxResponse ?? 3e5,
1165
+ shutdownGrace: t.shutdownGrace ?? 1e3,
1166
+ outputSettle: t.outputSettle ?? 300
1167
+ },
1168
+ approvalKeys: rawKeys && typeof rawKeys === "object" ? rawKeys : {},
1169
+ sendDelayMs: typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0,
1170
+ sendKey: typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r",
1171
+ submitStrategy: provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo",
1172
+ providerResolutionMeta: {
1173
+ type: provider.type,
1174
+ name: provider.name,
1175
+ resolvedVersion: provider._resolvedVersion || null,
1176
+ resolvedOs: provider._resolvedOs || null,
1177
+ providerDir: provider._resolvedProviderDir || null,
1178
+ scriptDir: provider._resolvedScriptDir || null,
1179
+ scriptsPath: provider._resolvedScriptsPath || null,
1180
+ scriptsSource: provider._resolvedScriptsSource || null,
1181
+ versionWarning: provider._versionWarning || null
1182
+ }
1183
+ };
1184
+ }
1185
+ var init_provider_cli_config = __esm({
1186
+ "src/cli-adapters/provider-cli-config.ts"() {
1187
+ "use strict";
1188
+ }
1189
+ });
1190
+
1191
+ // src/cli-adapters/provider-cli-runtime.ts
1192
+ import * as os9 from "os";
1193
+ import * as path10 from "path";
1194
+ function resolveCliSpawnPlan(options) {
1195
+ const { provider, runtimeSettings, workingDir, extraArgs } = options;
1196
+ const { spawn: spawnConfig } = provider;
1197
+ const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
1198
+ const binaryPath = findBinary(configuredCommand);
1199
+ const isWin = os9.platform() === "win32";
1200
+ const allArgs = [...spawnConfig.args, ...extraArgs];
1201
+ let shellCmd;
1202
+ let shellArgs;
1203
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path10.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1204
+ const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1205
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path10.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1206
+ const useShell = isWin ? useShellWin : useShellUnix;
1207
+ if (useShell) {
1208
+ shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
1209
+ if (isWin) {
1210
+ shellArgs = ["/c", binaryPath, ...allArgs];
1211
+ } else {
1212
+ const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1213
+ shellArgs = ["-l", "-c", fullCmd];
1214
+ }
1215
+ } else {
1216
+ shellCmd = binaryPath;
1217
+ shellArgs = allArgs;
1218
+ }
1219
+ return {
1220
+ binaryPath,
1221
+ allArgs,
1222
+ shellCmd,
1223
+ shellArgs,
1224
+ isWin,
1225
+ useShell,
1226
+ ptyOptions: {
1227
+ cols: 80,
1228
+ rows: 24,
1229
+ cwd: workingDir,
1230
+ env: buildCliSpawnEnv(process.env, spawnConfig.env)
1231
+ }
1232
+ };
1233
+ }
1234
+ function buildCliLoginShellRetry(plan) {
1235
+ const shellCmd = process.env.SHELL || "/bin/zsh";
1236
+ const fullCmd = [plan.binaryPath, ...plan.allArgs].map(shSingleQuote).join(" ");
1237
+ return {
1238
+ shellCmd,
1239
+ shellArgs: ["-l", "-c", fullCmd]
1240
+ };
1241
+ }
1242
+ function getCliSpawnErrorHint(message, shellCmd, isWin) {
1243
+ if (!isWin) return null;
1244
+ if (/error code 267|ERROR_DIRECTORY/i.test(message)) {
1245
+ return " (working directory does not exist or is not a directory)";
1246
+ }
1247
+ if (/error code 740|elevation/i.test(message)) {
1248
+ return " (requires administrator privileges)";
1249
+ }
1250
+ if (/error code 2|ENOENT|not found/i.test(message)) {
1251
+ return ` (executable not found: ${shellCmd})`;
1252
+ }
1253
+ return null;
1254
+ }
1255
+ function respondToCliTerminalQueries(options) {
1256
+ const { ptyProcess, pendingTail, data, terminalScreen } = options;
1257
+ if (!ptyProcess || !data) return pendingTail;
1258
+ const combined = pendingTail + data;
1259
+ const regex = /\x1b\[(\?)?6n/g;
1260
+ let match;
1261
+ while ((match = regex.exec(combined)) !== null) {
1262
+ const cursor = terminalScreen.getCursorPosition();
1263
+ const row = Math.max(1, (cursor.row | 0) + 1);
1264
+ const col = Math.max(1, (cursor.col | 0) + 1);
1265
+ const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
1266
+ ptyProcess.write(response);
1267
+ }
1268
+ const prefixes = ["\x1B[6n", "\x1B[?6n"];
1269
+ const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
1270
+ const start = Math.max(0, combined.length - maxLength);
1271
+ for (let i = start; i < combined.length; i++) {
1272
+ const suffix = combined.slice(i);
1273
+ if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
1274
+ return suffix;
1275
+ }
1276
+ }
1277
+ return "";
1278
+ }
1279
+ var init_provider_cli_runtime = __esm({
1280
+ "src/cli-adapters/provider-cli-runtime.ts"() {
1281
+ "use strict";
1282
+ init_provider_cli_shared();
1283
+ }
1284
+ });
1285
+
1286
+ // src/cli-adapters/provider-cli-adapter.ts
1287
+ var provider_cli_adapter_exports = {};
1288
+ __export(provider_cli_adapter_exports, {
1289
+ ProviderCliAdapter: () => ProviderCliAdapter,
1290
+ normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
1291
+ });
1292
+ import * as os10 from "os";
1293
+ var ProviderCliAdapter;
1032
1294
  var init_provider_cli_adapter = __esm({
1033
1295
  "src/cli-adapters/provider-cli-adapter.ts"() {
1034
1296
  "use strict";
1035
1297
  init_logger();
1036
1298
  init_terminal_screen();
1037
1299
  init_pty_transport();
1038
- init_spawn_env();
1039
- buildCliSpawnEnv = sanitizeSpawnEnv;
1300
+ init_provider_cli_shared();
1301
+ init_provider_cli_parse();
1302
+ init_provider_cli_config();
1303
+ init_provider_cli_runtime();
1304
+ init_provider_cli_shared();
1040
1305
  ProviderCliAdapter = class _ProviderCliAdapter {
1041
1306
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
1042
1307
  this.extraArgs = extraArgs;
@@ -1044,36 +1309,16 @@ var init_provider_cli_adapter = __esm({
1044
1309
  this.transportFactory = transportFactory;
1045
1310
  this.cliType = provider.type;
1046
1311
  this.cliName = provider.name;
1047
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os8.homedir()) : workingDir;
1048
- const t = provider.timeouts || {};
1049
- this.timeouts = {
1050
- ptyFlush: t.ptyFlush ?? 50,
1051
- dialogAccept: t.dialogAccept ?? 300,
1052
- approvalCooldown: t.approvalCooldown ?? 3e3,
1053
- generatingIdle: t.generatingIdle ?? 6e3,
1054
- idleFinish: t.idleFinish ?? 5e3,
1055
- maxResponse: t.maxResponse ?? 3e5,
1056
- shutdownGrace: t.shutdownGrace ?? 1e3,
1057
- outputSettle: t.outputSettle ?? 300
1058
- };
1059
- const rawKeys = provider.approvalKeys;
1060
- this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
1061
- this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
1062
- this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
1063
- this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
1064
- this.providerResolutionMeta = {
1065
- type: provider.type,
1066
- name: provider.name,
1067
- resolvedVersion: provider._resolvedVersion || null,
1068
- resolvedOs: provider._resolvedOs || null,
1069
- providerDir: provider._resolvedProviderDir || null,
1070
- scriptDir: provider._resolvedScriptDir || null,
1071
- scriptsPath: provider._resolvedScriptsPath || null,
1072
- scriptsSource: provider._resolvedScriptsSource || null,
1073
- versionWarning: provider._versionWarning || null
1074
- };
1312
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os10.homedir()) : workingDir;
1313
+ const resolvedConfig = resolveCliAdapterConfig(provider);
1314
+ this.timeouts = resolvedConfig.timeouts;
1315
+ this.approvalKeys = resolvedConfig.approvalKeys;
1316
+ this.sendDelayMs = resolvedConfig.sendDelayMs;
1317
+ this.sendKey = resolvedConfig.sendKey;
1318
+ this.submitStrategy = resolvedConfig.submitStrategy;
1319
+ this.providerResolutionMeta = resolvedConfig.providerResolutionMeta;
1075
1320
  this.cliScripts = provider.scripts || {};
1076
- const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
1321
+ const scriptNames = listCliScriptNames(this.cliScripts);
1077
1322
  if (scriptNames.length > 0) {
1078
1323
  LOG.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
1079
1324
  LOG.info(
@@ -1170,88 +1415,6 @@ var init_provider_cli_adapter = __esm({
1170
1415
  this.messages = [...this.committedMessages];
1171
1416
  this.structuredMessages = [...this.committedMessages];
1172
1417
  }
1173
- hydrateParsedMessages(parsedMessages, scope) {
1174
- const referenceMessages = [...this.committedMessages];
1175
- const usedReferenceIndexes = /* @__PURE__ */ new Set();
1176
- const now = Date.now();
1177
- const findReferenceTimestamp = (role, content, parsedIndex) => {
1178
- const normalizedContent = normalizeComparableMessageContent(content);
1179
- if (!normalizedContent) return void 0;
1180
- const sameIndex = referenceMessages[parsedIndex];
1181
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1182
- usedReferenceIndexes.add(parsedIndex);
1183
- return sameIndex.timestamp;
1184
- }
1185
- for (let i = 0; i < referenceMessages.length; i++) {
1186
- if (usedReferenceIndexes.has(i)) continue;
1187
- const candidate = referenceMessages[i];
1188
- if (!candidate || candidate.role !== role) continue;
1189
- const candidateContent = normalizeComparableMessageContent(candidate.content);
1190
- if (!candidateContent) continue;
1191
- const exactMatch = candidateContent === normalizedContent;
1192
- const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1193
- if (!exactMatch && !fuzzyMatch) continue;
1194
- if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1195
- usedReferenceIndexes.add(i);
1196
- return candidate.timestamp;
1197
- }
1198
- }
1199
- return void 0;
1200
- };
1201
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1202
- const role = message.role;
1203
- const content = typeof message.content === "string" ? message.content : String(message.content || "");
1204
- const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1205
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1206
- const fallbackTimestamp = role === "user" ? scope?.startedAt || now : this.lastOutputAt || scope?.startedAt || now;
1207
- const timestamp = referenceTimestamp ?? fallbackTimestamp;
1208
- return {
1209
- ...message,
1210
- role,
1211
- content,
1212
- timestamp,
1213
- receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp
1214
- };
1215
- });
1216
- }
1217
- normalizeParsedMessages(parsedMessages, scope) {
1218
- return this.hydrateParsedMessages(parsedMessages, scope).map((message) => ({
1219
- role: message.role,
1220
- content: message.content,
1221
- timestamp: message.timestamp,
1222
- receivedAt: message.receivedAt,
1223
- kind: message.kind,
1224
- id: message.id,
1225
- index: message.index,
1226
- meta: message.meta,
1227
- senderName: message.senderName
1228
- }));
1229
- }
1230
- sliceFromOffset(text, start) {
1231
- if (!text) return "";
1232
- if (!Number.isFinite(start) || start <= 0) return text;
1233
- if (start >= text.length) return "";
1234
- return text.slice(start);
1235
- }
1236
- buildParseInput(baseMessages, partialResponse, scope) {
1237
- const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1238
- const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
1239
- const screenText = this.terminalScreen.getText();
1240
- const recentBuffer = buffer.slice(-1e3) || this.recentOutputBuffer;
1241
- return {
1242
- buffer,
1243
- rawBuffer,
1244
- recentBuffer,
1245
- screenText,
1246
- screen: buildCliScreenSnapshot(screenText),
1247
- bufferScreen: buildCliScreenSnapshot(buffer),
1248
- recentScreen: buildCliScreenSnapshot(recentBuffer),
1249
- messages: [...baseMessages],
1250
- partialResponse,
1251
- promptText: scope?.prompt || "",
1252
- settings: { ...this.runtimeSettings }
1253
- };
1254
- }
1255
1418
  setStatus(status, trigger) {
1256
1419
  const prev = this.currentStatus;
1257
1420
  if (prev === status) return;
@@ -1284,7 +1447,13 @@ var init_provider_cli_adapter = __esm({
1284
1447
  this.recordTrace("idle_candidate_armed", {
1285
1448
  confirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
1286
1449
  candidate: this.idleFinishCandidate,
1287
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
1450
+ ...buildCliTraceParseSnapshot({
1451
+ accumulatedBuffer: this.accumulatedBuffer,
1452
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
1453
+ responseBuffer: this.responseBuffer,
1454
+ partialResponse: this.responseBuffer,
1455
+ scope: this.currentTurnScope
1456
+ })
1288
1457
  });
1289
1458
  if (this.settleTimer) clearTimeout(this.settleTimer);
1290
1459
  this.settleTimer = setTimeout(() => {
@@ -1293,30 +1462,6 @@ var init_provider_cli_adapter = __esm({
1293
1462
  this.evaluateSettled();
1294
1463
  }, _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS);
1295
1464
  }
1296
- summarizeTraceText(text, max = 800) {
1297
- const value = sanitizeTerminalText(String(text || ""));
1298
- if (value.length <= max) return value;
1299
- return `\u2026${value.slice(-max)}`;
1300
- }
1301
- summarizeTraceMessages(messages, limit = 3) {
1302
- return messages.slice(-limit).map((message) => ({
1303
- role: message.role,
1304
- content: this.summarizeTraceText(message.content, 240),
1305
- timestamp: message.timestamp
1306
- }));
1307
- }
1308
- buildTraceParseSnapshot(scope, partialResponse = "") {
1309
- const scopedBuffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1310
- const scopedRawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
1311
- return {
1312
- currentTurnScope: scope || null,
1313
- responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
1314
- partialResponse: this.summarizeTraceText(partialResponse || this.responseBuffer, 1200),
1315
- turnBuffer: this.summarizeTraceText(scopedBuffer, 1600),
1316
- turnRawPreview: this.summarizeTraceText(scopedRawBuffer, 1600),
1317
- turnSanitizedRawPreview: this.summarizeTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
1318
- };
1319
- }
1320
1465
  recordTrace(type, payload = {}) {
1321
1466
  const entry = {
1322
1467
  id: ++this.traceSeq,
@@ -1352,7 +1497,7 @@ var init_provider_cli_adapter = __esm({
1352
1497
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
1353
1498
  setCliScripts(scripts) {
1354
1499
  this.cliScripts = scripts;
1355
- const scriptNames = Object.keys(scripts).filter((k) => typeof scripts[k] === "function");
1500
+ const scriptNames = listCliScriptNames(scripts);
1356
1501
  LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
1357
1502
  }
1358
1503
  updateRuntimeSettings(settings) {
@@ -1384,72 +1529,42 @@ var init_provider_cli_adapter = __esm({
1384
1529
  }
1385
1530
  async spawn() {
1386
1531
  if (this.ptyProcess) return;
1387
- const { spawn: spawnConfig } = this.provider;
1388
- const configuredCommand = typeof this.runtimeSettings.executablePath === "string" && this.runtimeSettings.executablePath.trim() ? this.runtimeSettings.executablePath.trim() : spawnConfig.command;
1389
- const binaryPath = findBinary(configuredCommand);
1390
- const isWin = os8.platform() === "win32";
1391
- const allArgs = [...spawnConfig.args, ...this.extraArgs];
1532
+ const spawnPlan = resolveCliSpawnPlan({
1533
+ provider: this.provider,
1534
+ runtimeSettings: this.runtimeSettings,
1535
+ workingDir: this.workingDir,
1536
+ extraArgs: this.extraArgs
1537
+ });
1392
1538
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1393
1539
  this.resetTraceSession();
1394
- let shellCmd;
1395
- let shellArgs;
1396
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1397
- const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1398
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1399
- const useShell = isWin ? useShellWin : useShellUnix;
1400
- if (useShell) {
1401
- if (!spawnConfig.shell && !isWin) {
1402
- LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
1403
- }
1404
- if (isCmdShim) {
1405
- LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell for .cmd/.bat shim: ${binaryPath}`);
1406
- } else if (isWin) {
1407
- LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell on Windows: ${binaryPath}`);
1408
- }
1409
- shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
1410
- if (isWin) {
1411
- shellArgs = ["/c", binaryPath, ...allArgs];
1412
- } else {
1413
- const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1414
- shellArgs = ["-l", "-c", fullCmd];
1415
- }
1416
- } else {
1417
- if (isWin && spawnConfig.shell) {
1418
- LOG.info("CLI", `[${this.cliType}] Spawning Windows binary directly without cmd.exe: ${binaryPath}`);
1419
- }
1420
- shellCmd = binaryPath;
1421
- shellArgs = allArgs;
1422
- }
1423
- const ptyOpts = {
1424
- cols: 80,
1425
- rows: 24,
1426
- cwd: this.workingDir,
1427
- env: buildCliSpawnEnv(process.env, spawnConfig.env)
1428
- };
1429
1540
  this.recordTrace("spawn", {
1430
- shellCommand: shellCmd,
1431
- shellArgs,
1432
- cwd: ptyOpts.cwd,
1433
- cols: ptyOpts.cols,
1434
- rows: ptyOpts.rows,
1541
+ shellCommand: spawnPlan.shellCmd,
1542
+ shellArgs: spawnPlan.shellArgs,
1543
+ cwd: spawnPlan.ptyOptions.cwd,
1544
+ cols: spawnPlan.ptyOptions.cols,
1545
+ rows: spawnPlan.ptyOptions.rows,
1435
1546
  providerResolution: this.providerResolutionMeta
1436
1547
  });
1437
1548
  try {
1438
- this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1549
+ this.ptyProcess = this.transportFactory.spawn(
1550
+ spawnPlan.shellCmd,
1551
+ spawnPlan.shellArgs,
1552
+ spawnPlan.ptyOptions
1553
+ );
1439
1554
  } catch (err) {
1440
1555
  const msg = err?.message || String(err);
1441
- if (!isWin && !useShell && /posix_spawn|spawn/i.test(msg)) {
1556
+ if (!spawnPlan.isWin && !spawnPlan.useShell && /posix_spawn|spawn/i.test(msg)) {
1442
1557
  LOG.warn("CLI", `[${this.cliType}] Direct spawn failed (${msg}), retrying via login shell`);
1443
- shellCmd = process.env.SHELL || "/bin/zsh";
1444
- const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
1445
- shellArgs = ["-l", "-c", fullCmd];
1446
- this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1558
+ const retryPlan = buildCliLoginShellRetry(spawnPlan);
1559
+ this.ptyProcess = this.transportFactory.spawn(
1560
+ retryPlan.shellCmd,
1561
+ retryPlan.shellArgs,
1562
+ spawnPlan.ptyOptions
1563
+ );
1447
1564
  } else {
1448
- if (isWin) {
1449
- const hint = /error code 267|ERROR_DIRECTORY/i.test(msg) ? " (working directory does not exist or is not a directory)" : /error code 740|elevation/i.test(msg) ? " (requires administrator privileges)" : /error code 2|ENOENT|not found/i.test(msg) ? ` (executable not found: ${shellCmd})` : "";
1450
- if (hint) {
1451
- throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1452
- }
1565
+ const hint = getCliSpawnErrorHint(msg, spawnPlan.shellCmd, spawnPlan.isWin);
1566
+ if (hint) {
1567
+ throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1453
1568
  }
1454
1569
  throw err;
1455
1570
  }
@@ -1457,7 +1572,12 @@ var init_provider_cli_adapter = __esm({
1457
1572
  this.ptyProcess.onData((data) => {
1458
1573
  if (Date.now() < this.resizeSuppressUntil) return;
1459
1574
  if (!this.ptyProcess?.terminalQueriesHandled) {
1460
- this.respondToTerminalQueries(data);
1575
+ this.pendingTerminalQueryTail = respondToCliTerminalQueries({
1576
+ ptyProcess: this.ptyProcess,
1577
+ pendingTail: this.pendingTerminalQueryTail,
1578
+ data,
1579
+ terminalScreen: this.terminalScreen
1580
+ });
1461
1581
  }
1462
1582
  this.pendingOutputParseBuffer += data;
1463
1583
  if (!this.pendingOutputParseTimer) {
@@ -1536,9 +1656,9 @@ var init_provider_cli_adapter = __esm({
1536
1656
  this.recordTrace("output", {
1537
1657
  rawLength: rawData.length,
1538
1658
  cleanLength: cleanData.length,
1539
- rawPreview: this.summarizeTraceText(rawData, 300),
1540
- cleanPreview: this.summarizeTraceText(cleanData, 300),
1541
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 1200)
1659
+ rawPreview: summarizeCliTraceText(rawData, 300),
1660
+ cleanPreview: summarizeCliTraceText(cleanData, 300),
1661
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 1200)
1542
1662
  });
1543
1663
  if (this.startupParseGate) {
1544
1664
  this.scheduleStartupSettleCheck();
@@ -1769,7 +1889,7 @@ var init_provider_cli_adapter = __esm({
1769
1889
  loggedWait = true;
1770
1890
  LOG.info(
1771
1891
  "CLI",
1772
- `[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)}`
1892
+ `[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
1773
1893
  );
1774
1894
  }
1775
1895
  await new Promise((resolve12) => setTimeout(resolve12, 50));
@@ -1777,7 +1897,7 @@ var init_provider_cli_adapter = __esm({
1777
1897
  const finalScreenText = this.terminalScreen.getText() || "";
1778
1898
  LOG.warn(
1779
1899
  "CLI",
1780
- `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(this.summarizeTraceText(finalScreenText, 240)).slice(0, 280)}`
1900
+ `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
1781
1901
  );
1782
1902
  }
1783
1903
  evaluateSettled() {
@@ -1807,23 +1927,33 @@ var init_provider_cli_adapter = __esm({
1807
1927
  this.responseBuffer,
1808
1928
  this.currentTurnScope
1809
1929
  );
1810
- const parsedMessages = Array.isArray(parsedTranscript?.messages) ? this.normalizeParsedMessages(parsedTranscript.messages) : [];
1930
+ const parsedMessages = Array.isArray(parsedTranscript?.messages) ? normalizeCliParsedMessages(parsedTranscript.messages, {
1931
+ committedMessages: this.committedMessages,
1932
+ scope: this.currentTurnScope,
1933
+ lastOutputAt: this.lastOutputAt
1934
+ }) : [];
1811
1935
  const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
1812
1936
  this.recordTrace("settled", {
1813
- tail: this.summarizeTraceText(tail, 500),
1814
- screenText: this.summarizeTraceText(screenText, 1200),
1937
+ tail: summarizeCliTraceText(tail, 500),
1938
+ screenText: summarizeCliTraceText(screenText, 1200),
1815
1939
  detectStatus: scriptStatus,
1816
1940
  parsedStatus: parsedTranscript?.status || null,
1817
1941
  parsedMessageCount: parsedMessages.length,
1818
- parsedLastAssistant: lastParsedAssistant ? this.summarizeTraceText(lastParsedAssistant.content, 280) : "",
1942
+ parsedLastAssistant: lastParsedAssistant ? summarizeCliTraceText(lastParsedAssistant.content, 280) : "",
1819
1943
  parsedActiveModal: parsedTranscript?.activeModal ?? null,
1820
1944
  approval: modal,
1821
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
1945
+ ...buildCliTraceParseSnapshot({
1946
+ accumulatedBuffer: this.accumulatedBuffer,
1947
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
1948
+ responseBuffer: this.responseBuffer,
1949
+ partialResponse: this.responseBuffer,
1950
+ scope: this.currentTurnScope
1951
+ })
1822
1952
  });
1823
1953
  if (this.currentTurnScope && !lastParsedAssistant) {
1824
1954
  LOG.info(
1825
1955
  "CLI",
1826
- `[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
1956
+ `[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
1827
1957
  );
1828
1958
  }
1829
1959
  if (!scriptStatus) return;
@@ -1877,7 +2007,13 @@ var init_provider_cli_adapter = __esm({
1877
2007
  lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
1878
2008
  lastScreenChangeAt: this.lastScreenChangeAt,
1879
2009
  holdMs: _ProviderCliAdapter.STATUS_ACTIVITY_HOLD_MS,
1880
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2010
+ ...buildCliTraceParseSnapshot({
2011
+ accumulatedBuffer: this.accumulatedBuffer,
2012
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2013
+ responseBuffer: this.responseBuffer,
2014
+ partialResponse: this.responseBuffer,
2015
+ scope: this.currentTurnScope
2016
+ })
1881
2017
  });
1882
2018
  this.onStatusChange?.();
1883
2019
  return;
@@ -1981,7 +2117,13 @@ var init_provider_cli_adapter = __esm({
1981
2117
  canFinishImmediately,
1982
2118
  submitPendingUntil: this.submitPendingUntil,
1983
2119
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
1984
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2120
+ ...buildCliTraceParseSnapshot({
2121
+ accumulatedBuffer: this.accumulatedBuffer,
2122
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2123
+ responseBuffer: this.responseBuffer,
2124
+ partialResponse: this.responseBuffer,
2125
+ scope: this.currentTurnScope
2126
+ })
1985
2127
  });
1986
2128
  if (canFinishImmediately) {
1987
2129
  this.clearIdleFinishCandidate("finish_response");
@@ -2016,7 +2158,13 @@ var init_provider_cli_adapter = __esm({
2016
2158
  if (this.responseSettleIgnoreUntil > Date.now()) return;
2017
2159
  this.clearIdleFinishCandidate("finish_response_enter");
2018
2160
  this.recordTrace("finish_response", {
2019
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2161
+ ...buildCliTraceParseSnapshot({
2162
+ accumulatedBuffer: this.accumulatedBuffer,
2163
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2164
+ responseBuffer: this.responseBuffer,
2165
+ partialResponse: this.responseBuffer,
2166
+ scope: this.currentTurnScope
2167
+ })
2020
2168
  });
2021
2169
  const commitResult = this.commitCurrentTranscript();
2022
2170
  if (this.shouldRetryFinishResponse(commitResult)) {
@@ -2024,8 +2172,14 @@ var init_provider_cli_adapter = __esm({
2024
2172
  this.recordTrace("finish_response_retry", {
2025
2173
  retryCount: this.finishRetryCount,
2026
2174
  retryDelayMs: _ProviderCliAdapter.FINISH_RETRY_DELAY_MS,
2027
- assistantContent: this.summarizeTraceText(commitResult.assistantContent, 220),
2028
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2175
+ assistantContent: summarizeCliTraceText(commitResult.assistantContent, 220),
2176
+ ...buildCliTraceParseSnapshot({
2177
+ accumulatedBuffer: this.accumulatedBuffer,
2178
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2179
+ responseBuffer: this.responseBuffer,
2180
+ partialResponse: this.responseBuffer,
2181
+ scope: this.currentTurnScope
2182
+ })
2029
2183
  });
2030
2184
  if (this.finishRetryTimer) clearTimeout(this.finishRetryTimer);
2031
2185
  this.finishRetryTimer = setTimeout(() => {
@@ -2074,7 +2228,11 @@ var init_provider_cli_adapter = __esm({
2074
2228
  this.currentTurnScope
2075
2229
  );
2076
2230
  if (parsed && Array.isArray(parsed.messages)) {
2077
- this.committedMessages = this.normalizeParsedMessages(parsed.messages, this.currentTurnScope);
2231
+ this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
2232
+ committedMessages: this.committedMessages,
2233
+ scope: this.currentTurnScope,
2234
+ lastOutputAt: this.lastOutputAt
2235
+ });
2078
2236
  const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
2079
2237
  if (promptForTrim) {
2080
2238
  const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
@@ -2087,14 +2245,20 @@ var init_provider_cli_adapter = __esm({
2087
2245
  this.recordTrace("commit_transcript", {
2088
2246
  parsedStatus: parsed.status || null,
2089
2247
  messageCount: this.committedMessages.length,
2090
- lastAssistant: lastAssistant ? this.summarizeTraceText(lastAssistant.content, 320) : "",
2091
- messages: this.summarizeTraceMessages(this.committedMessages),
2092
- ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
2248
+ lastAssistant: lastAssistant ? summarizeCliTraceText(lastAssistant.content, 320) : "",
2249
+ messages: summarizeCliTraceMessages(this.committedMessages),
2250
+ ...buildCliTraceParseSnapshot({
2251
+ accumulatedBuffer: this.accumulatedBuffer,
2252
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2253
+ responseBuffer: this.responseBuffer,
2254
+ partialResponse: this.responseBuffer,
2255
+ scope: this.currentTurnScope
2256
+ })
2093
2257
  });
2094
2258
  if (!lastAssistant && this.currentTurnScope) {
2095
2259
  LOG.warn(
2096
2260
  "CLI",
2097
- `[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
2261
+ `[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
2098
2262
  );
2099
2263
  }
2100
2264
  return {
@@ -2186,7 +2350,11 @@ var init_provider_cli_adapter = __esm({
2186
2350
  index: typeof message.index === "number" ? message.index : index,
2187
2351
  kind: message.kind || "standard",
2188
2352
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2189
- })) : this.hydrateParsedMessages(parsed.messages, this.currentTurnScope);
2353
+ })) : hydrateCliParsedMessages(parsed.messages, {
2354
+ committedMessages: this.committedMessages,
2355
+ scope: this.currentTurnScope,
2356
+ lastOutputAt: this.lastOutputAt
2357
+ });
2190
2358
  return {
2191
2359
  id: parsed.id || "cli_session",
2192
2360
  status: parsed.status || this.currentStatus,
@@ -2217,11 +2385,16 @@ var init_provider_cli_adapter = __esm({
2217
2385
  if (typeof fn !== "function") {
2218
2386
  throw new Error(`CLI script '${scriptName}' not available`);
2219
2387
  }
2220
- const input = this.buildParseInput(
2221
- this.committedMessages,
2222
- this.responseBuffer,
2223
- this.currentTurnScope
2224
- );
2388
+ const input = buildCliParseInput({
2389
+ accumulatedBuffer: this.accumulatedBuffer,
2390
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2391
+ recentOutputBuffer: this.recentOutputBuffer,
2392
+ terminalScreenText: this.terminalScreen.getText(),
2393
+ baseMessages: this.committedMessages,
2394
+ partialResponse: this.responseBuffer,
2395
+ scope: this.currentTurnScope,
2396
+ runtimeSettings: this.runtimeSettings
2397
+ });
2225
2398
  return await Promise.resolve(fn({
2226
2399
  ...input,
2227
2400
  args: args && typeof args === "object" ? { ...args } : {}
@@ -2230,7 +2403,16 @@ var init_provider_cli_adapter = __esm({
2230
2403
  parseCurrentTranscript(baseMessages, partialResponse, scope) {
2231
2404
  if (!this.cliScripts?.parseOutput) return null;
2232
2405
  try {
2233
- const input = this.buildParseInput(baseMessages, partialResponse, scope);
2406
+ const input = buildCliParseInput({
2407
+ accumulatedBuffer: this.accumulatedBuffer,
2408
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
2409
+ recentOutputBuffer: this.recentOutputBuffer,
2410
+ terminalScreenText: this.terminalScreen.getText(),
2411
+ baseMessages,
2412
+ partialResponse,
2413
+ scope,
2414
+ runtimeSettings: this.runtimeSettings
2415
+ });
2234
2416
  const parsed = this.cliScripts.parseOutput(input);
2235
2417
  const refinedStatus = this.refineDetectedStatus(typeof parsed?.status === "string" ? parsed.status : null, input.recentBuffer, input.screenText);
2236
2418
  if (parsed && refinedStatus && parsed.status !== refinedStatus) {
@@ -2320,7 +2502,7 @@ ${data.message || ""}`.trim();
2320
2502
  rawBufferStart: this.accumulatedRawBuffer.length
2321
2503
  };
2322
2504
  this.recordTrace("send_message", {
2323
- text: this.summarizeTraceText(text, 500),
2505
+ text: summarizeCliTraceText(text, 500),
2324
2506
  estimatedLines: estimatePromptDisplayLines(text),
2325
2507
  turnScope: this.currentTurnScope
2326
2508
  });
@@ -2354,7 +2536,7 @@ ${data.message || ""}`.trim();
2354
2536
  this.recordTrace("submit_write", {
2355
2537
  mode: "submit_key",
2356
2538
  sendKey: this.sendKey,
2357
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2539
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2358
2540
  });
2359
2541
  this.ptyProcess.write(this.sendKey);
2360
2542
  const retrySubmitIfStuck = (attempt) => {
@@ -2371,7 +2553,7 @@ ${data.message || ""}`.trim();
2371
2553
  mode: "submit_retry",
2372
2554
  attempt,
2373
2555
  sendKey: this.sendKey,
2374
- screenText: this.summarizeTraceText(screenText, 500)
2556
+ screenText: summarizeCliTraceText(screenText, 500)
2375
2557
  });
2376
2558
  this.ptyProcess.write(this.sendKey);
2377
2559
  if (attempt >= 3) {
@@ -2387,9 +2569,9 @@ ${data.message || ""}`.trim();
2387
2569
  this.submitPendingUntil = 0;
2388
2570
  this.recordTrace("submit_write", {
2389
2571
  mode: "immediate",
2390
- text: this.summarizeTraceText(text, 500),
2572
+ text: summarizeCliTraceText(text, 500),
2391
2573
  sendKey: this.sendKey,
2392
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2574
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2393
2575
  });
2394
2576
  this.ptyProcess.write(text + this.sendKey);
2395
2577
  this.submitRetryTimer = setTimeout(() => {
@@ -2405,7 +2587,7 @@ ${data.message || ""}`.trim();
2405
2587
  mode: "immediate_retry",
2406
2588
  attempt: 1,
2407
2589
  sendKey: this.sendKey,
2408
- screenText: this.summarizeTraceText(screenText, 500)
2590
+ screenText: summarizeCliTraceText(screenText, 500)
2409
2591
  });
2410
2592
  this.ptyProcess.write(this.sendKey);
2411
2593
  this.submitRetryUsed = true;
@@ -2419,9 +2601,9 @@ ${data.message || ""}`.trim();
2419
2601
  this.ptyProcess.write(text);
2420
2602
  this.recordTrace("submit_write", {
2421
2603
  mode: "type_then_submit",
2422
- text: this.summarizeTraceText(text, 500),
2604
+ text: summarizeCliTraceText(text, 500),
2423
2605
  sendKey: this.sendKey,
2424
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
2606
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
2425
2607
  });
2426
2608
  const submitStartedAt = Date.now();
2427
2609
  let lastNormalizedScreen = "";
@@ -2756,7 +2938,7 @@ ${data.message || ""}`.trim();
2756
2938
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
2757
2939
  resizeSuppressUntil: this.resizeSuppressUntil,
2758
2940
  hasCliScripts: this.hasCliScripts(),
2759
- scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
2941
+ scriptNames: listCliScriptNames(this.cliScripts),
2760
2942
  traceSessionId: this.traceSessionId,
2761
2943
  traceEntryCount: this.traceEntries.length,
2762
2944
  statusHistory: this.statusHistory.slice(-30),
@@ -2773,32 +2955,18 @@ ${data.message || ""}`.trim();
2773
2955
  providerResolution: this.providerResolutionMeta,
2774
2956
  entryCount: this.traceEntries.length,
2775
2957
  entries: this.traceEntries.slice(-cappedLimit),
2776
- screenText: this.summarizeTraceText(this.terminalScreen.getText(), 4e3),
2777
- recentOutputBuffer: this.summarizeTraceText(this.recentOutputBuffer, 1e3),
2778
- responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
2958
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 4e3),
2959
+ recentOutputBuffer: summarizeCliTraceText(this.recentOutputBuffer, 1e3),
2960
+ responseBuffer: summarizeCliTraceText(this.responseBuffer, 1200),
2779
2961
  status: this.currentStatus,
2780
2962
  activeModal: this.activeModal,
2781
2963
  currentTurnScope: this.currentTurnScope,
2782
- messages: this.summarizeTraceMessages(this.committedMessages, 5)
2964
+ messages: summarizeCliTraceMessages(this.committedMessages, 5)
2783
2965
  };
2784
2966
  }
2785
2967
  getProviderResolutionMeta() {
2786
2968
  return { ...this.providerResolutionMeta };
2787
2969
  }
2788
- respondToTerminalQueries(data) {
2789
- if (!this.ptyProcess || !data) return;
2790
- const combined = this.pendingTerminalQueryTail + data;
2791
- const regex = /\x1b\[(\?)?6n/g;
2792
- let match;
2793
- while ((match = regex.exec(combined)) !== null) {
2794
- const cursor = this.terminalScreen.getCursorPosition();
2795
- const row = Math.max(1, (cursor.row | 0) + 1);
2796
- const col = Math.max(1, (cursor.col | 0) + 1);
2797
- const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
2798
- this.ptyProcess.write(response);
2799
- }
2800
- this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
2801
- }
2802
2970
  };
2803
2971
  }
2804
2972
  });
@@ -3195,17 +3363,17 @@ function checkPathExists(paths) {
3195
3363
  return null;
3196
3364
  }
3197
3365
  async function detectIDEs(providerLoader) {
3198
- const os18 = platform();
3366
+ const os20 = platform();
3199
3367
  const results = [];
3200
3368
  for (const def of getMergedDefinitions()) {
3201
3369
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
3202
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os18] || []) || []);
3370
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os20] || []) || []);
3203
3371
  let resolvedCli = cliPath;
3204
- if (!resolvedCli && appPath && os18 === "darwin") {
3372
+ if (!resolvedCli && appPath && os20 === "darwin") {
3205
3373
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
3206
3374
  if (existsSync4(bundledCli)) resolvedCli = bundledCli;
3207
3375
  }
3208
- if (!resolvedCli && appPath && os18 === "win32") {
3376
+ if (!resolvedCli && appPath && os20 === "win32") {
3209
3377
  const { dirname: dirname6 } = await import("path");
3210
3378
  const appDir = dirname6(appPath);
3211
3379
  const candidates = [
@@ -3222,7 +3390,7 @@ async function detectIDEs(providerLoader) {
3222
3390
  }
3223
3391
  }
3224
3392
  }
3225
- const installed = os18 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
3393
+ const installed = os20 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
3226
3394
  const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
3227
3395
  results.push({
3228
3396
  id: def.id,
@@ -3283,8 +3451,8 @@ function execAsync(cmd, timeoutMs = 5e3) {
3283
3451
  });
3284
3452
  }
3285
3453
  async function detectCLIs(providerLoader, options) {
3286
- const platform9 = os2.platform();
3287
- const whichCmd = platform9 === "win32" ? "where" : "which";
3454
+ const platform10 = os2.platform();
3455
+ const whichCmd = platform10 === "win32" ? "where" : "which";
3288
3456
  const includeVersion = options?.includeVersion !== false;
3289
3457
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
3290
3458
  const results = await Promise.all(
@@ -3327,8 +3495,8 @@ async function detectCLI(cliId, providerLoader, options) {
3327
3495
  const cliList = providerLoader.getCliDetectionList();
3328
3496
  const target = cliList.find((c) => c.id === resolvedId);
3329
3497
  if (target) {
3330
- const platform9 = os2.platform();
3331
- const whichCmd = platform9 === "win32" ? "where" : "which";
3498
+ const platform10 = os2.platform();
3499
+ const whichCmd = platform10 === "win32" ? "where" : "which";
3332
3500
  try {
3333
3501
  const explicitPath = resolveCommandPath(target.command);
3334
3502
  const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
@@ -3449,6 +3617,10 @@ var DaemonCdpManager = class {
3449
3617
  setTargetFilter(filter) {
3450
3618
  this._targetFilter = filter;
3451
3619
  }
3620
+ /** Clear a previously pinned target so the next connect can reselect a page. */
3621
+ clearTargetId() {
3622
+ this._targetId = null;
3623
+ }
3452
3624
  /**
3453
3625
  * Check if a page title should be excluded (non-main page).
3454
3626
  * Uses provider-configured titleExcludes, falls back to default pattern.
@@ -5992,7 +6164,8 @@ var IdeProviderInstance = class {
5992
6164
  }
5993
6165
  }
5994
6166
  if (!raw || typeof raw !== "object") return;
5995
- let { activeModal } = raw;
6167
+ const chat = raw;
6168
+ let { activeModal } = chat;
5996
6169
  if (activeModal) {
5997
6170
  const w = activeModal.width ?? Infinity;
5998
6171
  const h = activeModal.height ?? Infinity;
@@ -6012,26 +6185,28 @@ var IdeProviderInstance = class {
6012
6185
  if (pm.receivedAt) prevByHash.set(h, pm.receivedAt);
6013
6186
  }
6014
6187
  const now = Date.now();
6015
- for (const msg of raw.messages || []) {
6188
+ const messages = chat.messages || [];
6189
+ for (const msg of messages) {
6016
6190
  const h = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
6017
6191
  msg.receivedAt = prevByHash.get(h) || now;
6018
6192
  }
6019
- if (raw.messages?.length > 0) {
6193
+ if (messages.length > 0) {
6020
6194
  const hiddenKinds = /* @__PURE__ */ new Set();
6021
6195
  if (this.settings.showThinking === false) hiddenKinds.add("thought");
6022
6196
  if (this.settings.showToolCalls === false) hiddenKinds.add("tool");
6023
6197
  if (this.settings.showTerminal === false) hiddenKinds.add("terminal");
6024
6198
  if (hiddenKinds.size > 0) {
6025
- raw.messages = raw.messages.filter((m) => !hiddenKinds.has(m.kind));
6199
+ chat.messages = messages.filter((m) => !hiddenKinds.has(m.kind || ""));
6026
6200
  }
6027
6201
  }
6028
- const controlValues = extractProviderControlValues(this.provider.controls, raw);
6029
- if (controlValues) raw.controlValues = controlValues;
6030
- this.cachedChat = { ...raw, activeModal };
6031
- this.detectAgentTransitions(raw, now);
6032
- if (raw.messages?.length > 0) {
6033
- let toSave = raw.messages;
6034
- if (raw.status === "generating" || raw.status === "long_generating") {
6202
+ const controlValues = extractProviderControlValues(this.provider.controls, chat);
6203
+ if (controlValues) chat.controlValues = controlValues;
6204
+ this.cachedChat = { ...chat, activeModal };
6205
+ this.detectAgentTransitions(chat, now);
6206
+ const persistedMessages = chat.messages || messages;
6207
+ if (persistedMessages.length > 0) {
6208
+ let toSave = persistedMessages;
6209
+ if (chat.status === "generating" || chat.status === "long_generating") {
6035
6210
  const lastIdx = toSave.length - 1;
6036
6211
  if (lastIdx >= 0 && toSave[lastIdx].role === "assistant") {
6037
6212
  toSave = toSave.slice(0, lastIdx);
@@ -6041,7 +6216,7 @@ var IdeProviderInstance = class {
6041
6216
  this.historyWriter.appendNewMessages(
6042
6217
  this.type,
6043
6218
  toSave,
6044
- raw.title,
6219
+ chat.title,
6045
6220
  this.instanceId
6046
6221
  );
6047
6222
  }
@@ -6057,7 +6232,7 @@ var IdeProviderInstance = class {
6057
6232
  getReadChatScript() {
6058
6233
  const scripts = this.provider.scripts;
6059
6234
  if (!scripts?.readChat) return null;
6060
- return typeof scripts.readChat === "function" ? scripts.readChat({}) : scripts.readChat;
6235
+ return scripts.readChat({});
6061
6236
  }
6062
6237
  // ─── status transition detect ─────────────────────────────
6063
6238
  detectAgentTransitions(chatData, now) {
@@ -7128,7 +7303,7 @@ function getTargetInstance(h, args) {
7128
7303
  const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
7129
7304
  const sessionId = targetSessionId || h.currentSession?.sessionId || "";
7130
7305
  if (!sessionId) return null;
7131
- return h.ctx.instanceManager?.getInstance(sessionId);
7306
+ return h.ctx.instanceManager?.getInstance(sessionId) || null;
7132
7307
  }
7133
7308
  function getTargetTransport(h, provider) {
7134
7309
  if (h.currentSession?.transport) return h.currentSession.transport;
@@ -7166,6 +7341,10 @@ function getHistorySessionId(h, args) {
7166
7341
  const providerSessionId = typeof state?.providerSessionId === "string" ? state.providerSessionId.trim() : "";
7167
7342
  return providerSessionId || targetSessionId;
7168
7343
  }
7344
+ function callLegacyTextScript(script, text) {
7345
+ if (typeof script !== "function") return null;
7346
+ return script(text);
7347
+ }
7169
7348
  function isRecentDuplicateSend(key) {
7170
7349
  const now = Date.now();
7171
7350
  for (const [candidate, ts2] of recentSendByTarget.entries()) {
@@ -7255,7 +7434,7 @@ async function handleReadChat(h, args) {
7255
7434
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7256
7435
  if (adapter) {
7257
7436
  _log(`${transport} adapter: ${adapter.cliType}`);
7258
- const status = adapter.getStatus?.();
7437
+ const status = adapter.getStatus();
7259
7438
  if (status) {
7260
7439
  return {
7261
7440
  success: true,
@@ -7495,7 +7674,7 @@ async function handleSendChat(h, args) {
7495
7674
  }
7496
7675
  if (parsed?.needsTypeAndSend && provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
7497
7676
  try {
7498
- const webviewScript = provider.scripts.webviewSendMessage(text);
7677
+ const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
7499
7678
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
7500
7679
  const matchText = provider.webviewMatchText;
7501
7680
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -7518,7 +7697,7 @@ async function handleSendChat(h, args) {
7518
7697
  }
7519
7698
  if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
7520
7699
  try {
7521
- const webviewScript = provider.scripts.webviewSendMessage(text);
7700
+ const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
7522
7701
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
7523
7702
  const matchText = provider.webviewMatchText;
7524
7703
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -7750,12 +7929,10 @@ async function handleSetMode(h, args) {
7750
7929
  const mode = args?.mode || "agent";
7751
7930
  if (transport === "acp") {
7752
7931
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7753
- if (adapter) {
7754
- const acpInstance = adapter._acpInstance;
7755
- if (acpInstance && typeof acpInstance.setMode === "function") {
7756
- await acpInstance.setMode(mode);
7757
- return { success: true, mode };
7758
- }
7932
+ const acpInstance = adapter?._acpInstance;
7933
+ if (acpInstance && typeof acpInstance.setMode === "function") {
7934
+ await acpInstance.setMode(mode);
7935
+ return { success: true, mode };
7759
7936
  }
7760
7937
  return { success: false, error: "ACP adapter not found" };
7761
7938
  }
@@ -7808,13 +7985,11 @@ async function handleChangeModel(h, args) {
7808
7985
  if (transport === "acp") {
7809
7986
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7810
7987
  LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
7811
- if (adapter) {
7812
- const acpInstance = adapter._acpInstance;
7813
- if (acpInstance && typeof acpInstance.setConfigOption === "function") {
7814
- await acpInstance.setConfigOption("model", model);
7815
- LOG.info("Command", `[change_model] Updated ACP model to ${model}`);
7816
- return { success: true, model };
7817
- }
7988
+ const acpInstance = adapter?._acpInstance;
7989
+ if (acpInstance && typeof acpInstance.setConfigOption === "function") {
7990
+ await acpInstance.setConfigOption("model", model);
7991
+ LOG.info("Command", `[change_model] Updated ACP model to ${model}`);
7992
+ return { success: true, model };
7818
7993
  }
7819
7994
  return { success: false, error: "ACP adapter not found" };
7820
7995
  }
@@ -7871,6 +8046,9 @@ async function handleSetThoughtLevel(h, args) {
7871
8046
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7872
8047
  const acpInstance = adapter?._acpInstance;
7873
8048
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
8049
+ if (typeof acpInstance.setConfigOption !== "function") {
8050
+ return { success: false, error: "ACP setConfigOption not available" };
8051
+ }
7874
8052
  try {
7875
8053
  await acpInstance.setConfigOption(configId, value);
7876
8054
  LOG.info("Command", `[set_thought_level] ${configId}=${value} for ${provider?.type || "unknown_acp"}`);
@@ -7897,7 +8075,7 @@ async function handleResolveAction(h, args) {
7897
8075
  return { success: false, error: `CLI resolveAction failed: ${e.message}` };
7898
8076
  }
7899
8077
  }
7900
- const status = adapter.getStatus?.();
8078
+ const status = adapter.getStatus();
7901
8079
  if (status?.status !== "waiting_approval") {
7902
8080
  return { success: false, error: "Not in approval state" };
7903
8081
  }
@@ -7936,6 +8114,9 @@ async function handleResolveAction(h, args) {
7936
8114
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
7937
8115
  const acpInstance = adapter?._acpInstance;
7938
8116
  if (!acpInstance) return { success: false, error: "ACP instance not found" };
8117
+ if (typeof acpInstance.resolvePermission !== "function") {
8118
+ return { success: false, error: "ACP resolvePermission not available" };
8119
+ }
7939
8120
  try {
7940
8121
  await acpInstance.resolvePermission(action === "approve" || action === "accept" || action === "always");
7941
8122
  LOG.info("Command", `[resolveAction] ACP \u2192 ${action}`);
@@ -8097,11 +8278,16 @@ async function handleCdpCommand(h, args) {
8097
8278
  }
8098
8279
  async function handleCdpBatch(h, args) {
8099
8280
  if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
8100
- const commands = args?.commands;
8281
+ const commands = Array.isArray(args?.commands) ? args.commands : null;
8101
8282
  const stopOnError = args?.stopOnError !== false;
8102
8283
  if (!commands?.length) return { success: false, error: "commands array required" };
8103
8284
  const results = [];
8104
8285
  for (const cmd of commands) {
8286
+ if (!cmd || typeof cmd !== "object" || typeof cmd.method !== "string") {
8287
+ results.push({ method: null, success: false, error: "Invalid command entry" });
8288
+ if (stopOnError) break;
8289
+ continue;
8290
+ }
8105
8291
  try {
8106
8292
  const result = await h.getCdp().sendCdpCommand(cmd.method, cmd.params || {});
8107
8293
  results.push({ method: cmd.method, success: true, result });
@@ -8396,11 +8582,12 @@ function handlePtyResize(h, args) {
8396
8582
  if (!adapter || typeof adapter.resize !== "function") {
8397
8583
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
8398
8584
  }
8585
+ const resize = adapter.resize;
8399
8586
  if (force) {
8400
- adapter.resize(cols - 1, rows);
8401
- setTimeout(() => adapter.resize(cols, rows), 50);
8587
+ resize(cols - 1, rows);
8588
+ setTimeout(() => resize(cols, rows), 50);
8402
8589
  } else {
8403
- adapter.resize(cols, rows);
8590
+ resize(cols, rows);
8404
8591
  }
8405
8592
  return { success: true };
8406
8593
  }
@@ -8458,7 +8645,7 @@ function parseScriptResult(result) {
8458
8645
  return { success: true, payload: { result } };
8459
8646
  }
8460
8647
  }
8461
- if (result && typeof result === "object" && result.success === false) {
8648
+ if (result && typeof result === "object" && "success" in result && result.success === false) {
8462
8649
  return { success: false, payload: result };
8463
8650
  }
8464
8651
  return { success: true, payload: result };
@@ -8881,24 +9068,25 @@ var DaemonCommandHandler = class {
8881
9068
  if (provider?.scripts) {
8882
9069
  const fn = provider.scripts[scriptName];
8883
9070
  if (typeof fn === "function") {
9071
+ const callScript = fn;
8884
9072
  if (params && Object.keys(params).length > 0) {
8885
9073
  const firstVal = Object.values(params)[0];
8886
9074
  if (scriptName === "sendMessage" && typeof firstVal === "string") {
8887
- const legacyScript = fn(firstVal);
9075
+ const legacyScript = callScript(firstVal);
8888
9076
  if (legacyScript) return legacyScript;
8889
9077
  }
8890
- const script = fn(params);
9078
+ const script = callScript(params);
8891
9079
  if (script) {
8892
9080
  const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
8893
9081
  if (!likelyLegacyObjectLeak) return script;
8894
9082
  }
8895
9083
  if (firstVal !== void 0) {
8896
- const legacyScript = fn(firstVal);
9084
+ const legacyScript = callScript(firstVal);
8897
9085
  if (legacyScript) return legacyScript;
8898
9086
  }
8899
9087
  if (script) return script;
8900
9088
  } else {
8901
- const script = fn();
9089
+ const script = callScript();
8902
9090
  if (script) return script;
8903
9091
  }
8904
9092
  }
@@ -9279,16 +9467,16 @@ var DaemonCommandHandler = class {
9279
9467
 
9280
9468
  // src/commands/cli-manager.ts
9281
9469
  init_provider_cli_adapter();
9282
- import * as os10 from "os";
9283
- import * as path11 from "path";
9470
+ import * as os12 from "os";
9471
+ import * as path12 from "path";
9284
9472
  import * as crypto4 from "crypto";
9285
9473
  import chalk from "chalk";
9286
9474
  init_config();
9287
9475
 
9288
9476
  // src/providers/cli-provider-instance.ts
9289
9477
  init_provider_cli_adapter();
9290
- import * as os9 from "os";
9291
- import * as path10 from "path";
9478
+ import * as os11 from "os";
9479
+ import * as path11 from "path";
9292
9480
  import * as crypto3 from "crypto";
9293
9481
  import * as fs5 from "fs";
9294
9482
  import { createRequire } from "module";
@@ -9296,7 +9484,7 @@ init_logger();
9296
9484
  var CachedDatabaseSync = null;
9297
9485
  function getDatabaseSync() {
9298
9486
  if (CachedDatabaseSync) return CachedDatabaseSync;
9299
- const requireFn = typeof __require === "function" ? __require : createRequire(path10.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
9487
+ const requireFn = typeof __require === "function" ? __require : createRequire(path11.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
9300
9488
  const sqliteModule = requireFn(`node:${"sqlite"}`);
9301
9489
  CachedDatabaseSync = sqliteModule.DatabaseSync;
9302
9490
  if (!CachedDatabaseSync) {
@@ -9436,7 +9624,7 @@ var CliProviderInstance = class {
9436
9624
  * Replaces the previously duplicated probeOpenCode/Codex/Goose functions.
9437
9625
  */
9438
9626
  probeSessionIdFromConfig(probe) {
9439
- const resolvedDbPath = probe.dbPath.replace(/^~/, os9.homedir());
9627
+ const resolvedDbPath = probe.dbPath.replace(/^~/, os11.homedir());
9440
9628
  if (!fs5.existsSync(resolvedDbPath)) return null;
9441
9629
  const directories = this.getProbeDirectories();
9442
9630
  const minCreatedAt = Math.max(0, this.startedAt - 6e4);
@@ -10866,7 +11054,8 @@ var AcpProviderInstance = class {
10866
11054
 
10867
11055
  // src/commands/cli-manager.ts
10868
11056
  init_logger();
10869
- var chalkApi = chalk?.yellow ? chalk : chalk?.default || null;
11057
+ var chalkModule = chalk;
11058
+ var chalkApi = typeof chalkModule.yellow === "function" ? chalkModule : chalkModule.default || null;
10870
11059
  function colorize(color, text) {
10871
11060
  const fn = chalkApi?.[color];
10872
11061
  return typeof fn === "function" ? fn(text) : text;
@@ -11116,7 +11305,7 @@ var DaemonCliManager = class {
11116
11305
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
11117
11306
  const trimmed = (workingDir || "").trim();
11118
11307
  if (!trimmed) throw new Error("working directory required");
11119
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path11.resolve(trimmed);
11308
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path12.resolve(trimmed);
11120
11309
  const normalizedType = this.providerLoader.resolveAlias(cliType);
11121
11310
  const provider = this.providerLoader.getByAlias(cliType);
11122
11311
  const key = crypto4.randomUUID();
@@ -11155,6 +11344,7 @@ ${installInfo}`
11155
11344
  });
11156
11345
  this.adapters.set(key, {
11157
11346
  cliType: normalizedType,
11347
+ cliName: provider.name,
11158
11348
  workingDir: resolvedDir,
11159
11349
  _acpInstance: acpInstance,
11160
11350
  spawn: async () => {
@@ -11173,6 +11363,12 @@ ${installInfo}`
11173
11363
  activeModal: state.activeChat?.activeModal || null
11174
11364
  };
11175
11365
  },
11366
+ getPartialResponse: () => "",
11367
+ cancel: () => {
11368
+ instanceManager2.removeInstance(key);
11369
+ },
11370
+ isProcessing: () => false,
11371
+ isReady: () => true,
11176
11372
  setOnStatusChange: () => {
11177
11373
  },
11178
11374
  setOnPtyData: () => {
@@ -11579,13 +11775,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
11579
11775
  // src/launch.ts
11580
11776
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
11581
11777
  import * as net from "net";
11582
- import * as os12 from "os";
11583
- import * as path13 from "path";
11778
+ import * as os14 from "os";
11779
+ import * as path14 from "path";
11584
11780
 
11585
11781
  // src/providers/provider-loader.ts
11586
11782
  import * as fs6 from "fs";
11587
- import * as path12 from "path";
11588
- import * as os11 from "os";
11783
+ import * as path13 from "path";
11784
+ import * as os13 from "os";
11589
11785
  import * as chokidar from "chokidar";
11590
11786
  init_logger();
11591
11787
  var ProviderLoader = class _ProviderLoader {
@@ -11606,12 +11802,12 @@ var ProviderLoader = class _ProviderLoader {
11606
11802
  static META_FILE = ".meta.json";
11607
11803
  constructor(options) {
11608
11804
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
11609
- const defaultProvidersDir = path12.join(os11.homedir(), ".adhdev", "providers");
11805
+ const defaultProvidersDir = path13.join(os13.homedir(), ".adhdev", "providers");
11610
11806
  if (options?.userDir) {
11611
11807
  this.userDir = options.userDir;
11612
11808
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
11613
11809
  } else {
11614
- const localRepoPath = path12.resolve(__dirname, "../../../../../adhdev-providers");
11810
+ const localRepoPath = path13.resolve(__dirname, "../../../../../adhdev-providers");
11615
11811
  if (fs6.existsSync(localRepoPath)) {
11616
11812
  this.userDir = localRepoPath;
11617
11813
  this.log(`Auto-detected local public repository: ${this.userDir} (Dev workspace speedup)`);
@@ -11620,7 +11816,7 @@ var ProviderLoader = class _ProviderLoader {
11620
11816
  this.log(`Using default user providers directory: ${this.userDir}`);
11621
11817
  }
11622
11818
  }
11623
- this.upstreamDir = path12.join(defaultProvidersDir, ".upstream");
11819
+ this.upstreamDir = path13.join(defaultProvidersDir, ".upstream");
11624
11820
  this.disableUpstream = options?.disableUpstream ?? false;
11625
11821
  }
11626
11822
  log(msg) {
@@ -11650,7 +11846,7 @@ var ProviderLoader = class _ProviderLoader {
11650
11846
  * Canonical provider directory shape for a given root.
11651
11847
  */
11652
11848
  getProviderDir(root, category, type) {
11653
- return path12.join(root, category, type);
11849
+ return path13.join(root, category, type);
11654
11850
  }
11655
11851
  /**
11656
11852
  * Canonical user override directory for a provider.
@@ -11677,7 +11873,7 @@ var ProviderLoader = class _ProviderLoader {
11677
11873
  resolveProviderFile(type, ...segments) {
11678
11874
  const dir = this.findProviderDirInternal(type);
11679
11875
  if (!dir) return null;
11680
- return path12.join(dir, ...segments);
11876
+ return path13.join(dir, ...segments);
11681
11877
  }
11682
11878
  /**
11683
11879
  * Load all providers (3-tier priority)
@@ -11716,7 +11912,7 @@ var ProviderLoader = class _ProviderLoader {
11716
11912
  if (!fs6.existsSync(this.upstreamDir)) return false;
11717
11913
  try {
11718
11914
  return fs6.readdirSync(this.upstreamDir).some(
11719
- (d) => fs6.statSync(path12.join(this.upstreamDir, d)).isDirectory()
11915
+ (d) => fs6.statSync(path13.join(this.upstreamDir, d)).isDirectory()
11720
11916
  );
11721
11917
  } catch {
11722
11918
  return false;
@@ -11757,8 +11953,7 @@ var ProviderLoader = class _ProviderLoader {
11757
11953
  const result = [];
11758
11954
  for (const p of this.providers.values()) {
11759
11955
  if ((p.category === "cli" || p.category === "acp") && p.spawn?.command) {
11760
- const verCmdConfig = p.versionCommand;
11761
- const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[process.platform] : verCmdConfig;
11956
+ const versionCommand = this.getPlatformVersionCommand(p.versionCommand);
11762
11957
  const command = this.getSpawnCommand(p.type, p.spawn.command);
11763
11958
  result.push({
11764
11959
  id: p.type,
@@ -11812,8 +12007,8 @@ var ProviderLoader = class _ProviderLoader {
11812
12007
  * that runtime attach/remove uses.
11813
12008
  */
11814
12009
  getIdeExtensionEnabledState(ideType, extensionType) {
11815
- const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
11816
- const config = loadConfig2();
12010
+ const config = this.readConfig();
12011
+ if (!config) return false;
11817
12012
  const baseIdeType = ideType.split("_")[0];
11818
12013
  const val = config.ideSettings?.[baseIdeType]?.extensions?.[extensionType]?.enabled;
11819
12014
  return val === true;
@@ -11822,15 +12017,15 @@ var ProviderLoader = class _ProviderLoader {
11822
12017
  * Save IDE extension enabled setting
11823
12018
  */
11824
12019
  setIdeExtensionEnabled(ideType, extensionType, enabled) {
12020
+ const config = this.readConfig();
12021
+ if (!config) return false;
11825
12022
  try {
11826
- const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
11827
- const config = loadConfig2();
11828
12023
  const baseIdeType = ideType.split("_")[0];
11829
12024
  if (!config.ideSettings) config.ideSettings = {};
11830
12025
  if (!config.ideSettings[baseIdeType]) config.ideSettings[baseIdeType] = {};
11831
12026
  if (!config.ideSettings[baseIdeType].extensions) config.ideSettings[baseIdeType].extensions = {};
11832
12027
  config.ideSettings[baseIdeType].extensions[extensionType] = { enabled };
11833
- saveConfig3(config);
12028
+ this.writeConfig(config);
11834
12029
  this.log(`IDE extension setting: ${ideType}.${extensionType}.enabled = ${enabled}`);
11835
12030
  return true;
11836
12031
  } catch (e) {
@@ -12020,7 +12215,7 @@ var ProviderLoader = class _ProviderLoader {
12020
12215
  }
12021
12216
  if (currentVersion) {
12022
12217
  resolved._resolvedVersion = currentVersion;
12023
- if (Array.isArray(base.compatibility)) {
12218
+ if (base.compatibility) {
12024
12219
  const compat = base.compatibility;
12025
12220
  let matched = false;
12026
12221
  for (const entry of compat) {
@@ -12032,8 +12227,8 @@ var ProviderLoader = class _ProviderLoader {
12032
12227
  resolved._resolvedScriptDir = entry.scriptDir;
12033
12228
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
12034
12229
  if (providerDir) {
12035
- const fullDir = path12.join(providerDir, entry.scriptDir);
12036
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12230
+ const fullDir = path13.join(providerDir, entry.scriptDir);
12231
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12037
12232
  }
12038
12233
  matched = true;
12039
12234
  }
@@ -12048,8 +12243,8 @@ var ProviderLoader = class _ProviderLoader {
12048
12243
  resolved._resolvedScriptDir = base.defaultScriptDir;
12049
12244
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
12050
12245
  if (providerDir) {
12051
- const fullDir = path12.join(providerDir, base.defaultScriptDir);
12052
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12246
+ const fullDir = path13.join(providerDir, base.defaultScriptDir);
12247
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12053
12248
  }
12054
12249
  }
12055
12250
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -12066,8 +12261,8 @@ var ProviderLoader = class _ProviderLoader {
12066
12261
  resolved._resolvedScriptDir = dirOverride;
12067
12262
  resolved._resolvedScriptsSource = `versions:${range}`;
12068
12263
  if (providerDir) {
12069
- const fullDir = path12.join(providerDir, dirOverride);
12070
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12264
+ const fullDir = path13.join(providerDir, dirOverride);
12265
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12071
12266
  }
12072
12267
  }
12073
12268
  } else if (override.scripts) {
@@ -12075,7 +12270,7 @@ var ProviderLoader = class _ProviderLoader {
12075
12270
  }
12076
12271
  }
12077
12272
  }
12078
- } else if (Array.isArray(base.compatibility) && base.defaultScriptDir) {
12273
+ } else if (base.compatibility && base.defaultScriptDir) {
12079
12274
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
12080
12275
  if (loaded) {
12081
12276
  resolved.scripts = loaded;
@@ -12083,8 +12278,8 @@ var ProviderLoader = class _ProviderLoader {
12083
12278
  resolved._resolvedScriptDir = base.defaultScriptDir;
12084
12279
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
12085
12280
  if (providerDir) {
12086
- const fullDir = path12.join(providerDir, base.defaultScriptDir);
12087
- resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
12281
+ const fullDir = path13.join(providerDir, base.defaultScriptDir);
12282
+ resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
12088
12283
  }
12089
12284
  }
12090
12285
  }
@@ -12109,14 +12304,14 @@ var ProviderLoader = class _ProviderLoader {
12109
12304
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
12110
12305
  return null;
12111
12306
  }
12112
- const dir = path12.join(providerDir, scriptDir);
12307
+ const dir = path13.join(providerDir, scriptDir);
12113
12308
  if (!fs6.existsSync(dir)) {
12114
12309
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
12115
12310
  return null;
12116
12311
  }
12117
12312
  const cached = this.scriptsCache.get(dir);
12118
12313
  if (cached) return cached;
12119
- const scriptsJs = path12.join(dir, "scripts.js");
12314
+ const scriptsJs = path13.join(dir, "scripts.js");
12120
12315
  if (fs6.existsSync(scriptsJs)) {
12121
12316
  try {
12122
12317
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -12158,7 +12353,7 @@ var ProviderLoader = class _ProviderLoader {
12158
12353
  return;
12159
12354
  }
12160
12355
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
12161
- this.log(`File changed: ${path12.basename(filePath)}, reloading...`);
12356
+ this.log(`File changed: ${path13.basename(filePath)}, reloading...`);
12162
12357
  this.reload();
12163
12358
  }
12164
12359
  };
@@ -12213,7 +12408,7 @@ var ProviderLoader = class _ProviderLoader {
12213
12408
  }
12214
12409
  const https = __require("https");
12215
12410
  const { execSync: execSync7 } = __require("child_process");
12216
- const metaPath = path12.join(this.upstreamDir, _ProviderLoader.META_FILE);
12411
+ const metaPath = path13.join(this.upstreamDir, _ProviderLoader.META_FILE);
12217
12412
  let prevEtag = "";
12218
12413
  let prevTimestamp = 0;
12219
12414
  try {
@@ -12273,17 +12468,17 @@ var ProviderLoader = class _ProviderLoader {
12273
12468
  return { updated: false };
12274
12469
  }
12275
12470
  this.log("Downloading latest providers from GitHub...");
12276
- const tmpTar = path12.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
12277
- const tmpExtract = path12.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
12471
+ const tmpTar = path13.join(os13.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
12472
+ const tmpExtract = path13.join(os13.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
12278
12473
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
12279
12474
  fs6.mkdirSync(tmpExtract, { recursive: true });
12280
12475
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
12281
12476
  const extracted = fs6.readdirSync(tmpExtract);
12282
12477
  const rootDir = extracted.find(
12283
- (d) => fs6.statSync(path12.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
12478
+ (d) => fs6.statSync(path13.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
12284
12479
  );
12285
12480
  if (!rootDir) throw new Error("Unexpected tarball structure");
12286
- const sourceDir = path12.join(tmpExtract, rootDir);
12481
+ const sourceDir = path13.join(tmpExtract, rootDir);
12287
12482
  const backupDir = this.upstreamDir + ".bak";
12288
12483
  if (fs6.existsSync(this.upstreamDir)) {
12289
12484
  if (fs6.existsSync(backupDir)) fs6.rmSync(backupDir, { recursive: true, force: true });
@@ -12358,8 +12553,8 @@ var ProviderLoader = class _ProviderLoader {
12358
12553
  copyDirRecursive(src, dest) {
12359
12554
  fs6.mkdirSync(dest, { recursive: true });
12360
12555
  for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
12361
- const srcPath = path12.join(src, entry.name);
12362
- const destPath = path12.join(dest, entry.name);
12556
+ const srcPath = path13.join(src, entry.name);
12557
+ const destPath = path13.join(dest, entry.name);
12363
12558
  if (entry.isDirectory()) {
12364
12559
  this.copyDirRecursive(srcPath, destPath);
12365
12560
  } else {
@@ -12370,7 +12565,7 @@ var ProviderLoader = class _ProviderLoader {
12370
12565
  /** .meta.json save */
12371
12566
  writeMeta(metaPath, etag, timestamp) {
12372
12567
  try {
12373
- fs6.mkdirSync(path12.dirname(metaPath), { recursive: true });
12568
+ fs6.mkdirSync(path13.dirname(metaPath), { recursive: true });
12374
12569
  fs6.writeFileSync(metaPath, JSON.stringify({
12375
12570
  etag,
12376
12571
  timestamp,
@@ -12387,7 +12582,7 @@ var ProviderLoader = class _ProviderLoader {
12387
12582
  const scan = (d) => {
12388
12583
  try {
12389
12584
  for (const entry of fs6.readdirSync(d, { withFileTypes: true })) {
12390
- if (entry.isDirectory()) scan(path12.join(d, entry.name));
12585
+ if (entry.isDirectory()) scan(path13.join(d, entry.name));
12391
12586
  else if (entry.name === "provider.json") count++;
12392
12587
  }
12393
12588
  } catch {
@@ -12421,14 +12616,9 @@ var ProviderLoader = class _ProviderLoader {
12421
12616
  getSettingValue(type, key) {
12422
12617
  const schemaDef = this.getSettingsSchema(type)[key];
12423
12618
  const defaultVal = schemaDef ? key === "autoApprove" && schemaDef.type === "boolean" ? true : schemaDef.default : void 0;
12424
- try {
12425
- const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
12426
- const config = loadConfig2();
12427
- const userVal = config.providerSettings?.[type]?.[key];
12428
- return userVal !== void 0 ? userVal : defaultVal;
12429
- } catch {
12430
- return defaultVal;
12431
- }
12619
+ const config = this.readConfig();
12620
+ const userVal = config?.providerSettings?.[type]?.[key];
12621
+ return userVal !== void 0 ? userVal : defaultVal;
12432
12622
  }
12433
12623
  /**
12434
12624
  * All resolved settings for a provider (default + user override)
@@ -12456,13 +12646,13 @@ var ProviderLoader = class _ProviderLoader {
12456
12646
  if (schemaDef.max !== void 0 && value > schemaDef.max) return false;
12457
12647
  }
12458
12648
  if (schemaDef.type === "select" && schemaDef.options && !schemaDef.options.includes(value)) return false;
12649
+ const config = this.readConfig();
12650
+ if (!config) return false;
12459
12651
  try {
12460
- const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
12461
- const config = loadConfig2();
12462
12652
  if (!config.providerSettings) config.providerSettings = {};
12463
12653
  if (!config.providerSettings[type]) config.providerSettings[type] = {};
12464
12654
  config.providerSettings[type][key] = value;
12465
- saveConfig3(config);
12655
+ this.writeConfig(config);
12466
12656
  this.log(`Setting updated: ${type}.${key} = ${JSON.stringify(value)}`);
12467
12657
  return true;
12468
12658
  } catch (e) {
@@ -12476,6 +12666,34 @@ var ProviderLoader = class _ProviderLoader {
12476
12666
  const trimmed = value.trim();
12477
12667
  return trimmed ? trimmed : null;
12478
12668
  }
12669
+ readConfig() {
12670
+ try {
12671
+ const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
12672
+ return loadConfig2();
12673
+ } catch {
12674
+ return null;
12675
+ }
12676
+ }
12677
+ writeConfig(config) {
12678
+ const { saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
12679
+ saveConfig3(config);
12680
+ }
12681
+ getPlatformVersionCommand(versionCommand) {
12682
+ if (!versionCommand) return void 0;
12683
+ if (typeof versionCommand === "string") {
12684
+ const trimmed = versionCommand.trim();
12685
+ return trimmed || void 0;
12686
+ }
12687
+ const platformValue = versionCommand[process.platform];
12688
+ if (typeof platformValue === "string" && platformValue.trim()) {
12689
+ return platformValue.trim();
12690
+ }
12691
+ const defaultValue = versionCommand.default;
12692
+ if (typeof defaultValue === "string" && defaultValue.trim()) {
12693
+ return defaultValue.trim();
12694
+ }
12695
+ return void 0;
12696
+ }
12479
12697
  getSettingsSchema(type) {
12480
12698
  const provider = this.providers.get(type);
12481
12699
  if (!provider) return {};
@@ -12549,17 +12767,17 @@ var ProviderLoader = class _ProviderLoader {
12549
12767
  for (const root of searchRoots) {
12550
12768
  if (!fs6.existsSync(root)) continue;
12551
12769
  const candidate = this.getProviderDir(root, cat, type);
12552
- if (fs6.existsSync(path12.join(candidate, "provider.json"))) return candidate;
12553
- const catDir = path12.join(root, cat);
12770
+ if (fs6.existsSync(path13.join(candidate, "provider.json"))) return candidate;
12771
+ const catDir = path13.join(root, cat);
12554
12772
  if (fs6.existsSync(catDir)) {
12555
12773
  try {
12556
12774
  for (const entry of fs6.readdirSync(catDir, { withFileTypes: true })) {
12557
12775
  if (!entry.isDirectory()) continue;
12558
- const jsonPath = path12.join(catDir, entry.name, "provider.json");
12776
+ const jsonPath = path13.join(catDir, entry.name, "provider.json");
12559
12777
  if (fs6.existsSync(jsonPath)) {
12560
12778
  try {
12561
12779
  const data = JSON.parse(fs6.readFileSync(jsonPath, "utf-8"));
12562
- if (data.type === type) return path12.join(catDir, entry.name);
12780
+ if (data.type === type) return path13.join(catDir, entry.name);
12563
12781
  } catch {
12564
12782
  }
12565
12783
  }
@@ -12576,7 +12794,7 @@ var ProviderLoader = class _ProviderLoader {
12576
12794
  * (template substitution is NOT applied here — scripts.js handles that)
12577
12795
  */
12578
12796
  buildScriptWrappersFromDir(dir) {
12579
- const scriptsJs = path12.join(dir, "scripts.js");
12797
+ const scriptsJs = path13.join(dir, "scripts.js");
12580
12798
  if (fs6.existsSync(scriptsJs)) {
12581
12799
  try {
12582
12800
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -12590,7 +12808,7 @@ var ProviderLoader = class _ProviderLoader {
12590
12808
  for (const file of fs6.readdirSync(dir)) {
12591
12809
  if (!file.endsWith(".js")) continue;
12592
12810
  const scriptName = toCamel(file.replace(".js", ""));
12593
- const filePath = path12.join(dir, file);
12811
+ const filePath = path13.join(dir, file);
12594
12812
  result[scriptName] = (...args) => {
12595
12813
  try {
12596
12814
  let content = fs6.readFileSync(filePath, "utf-8");
@@ -12650,35 +12868,39 @@ var ProviderLoader = class _ProviderLoader {
12650
12868
  }
12651
12869
  const hasJson = entries.some((e) => e.name === "provider.json");
12652
12870
  if (hasJson) {
12653
- const jsonPath = path12.join(d, "provider.json");
12871
+ const jsonPath = path13.join(d, "provider.json");
12654
12872
  try {
12655
12873
  const raw = fs6.readFileSync(jsonPath, "utf-8");
12656
12874
  const mod = JSON.parse(raw);
12657
12875
  if (!mod.type || !mod.name || !mod.category) {
12658
12876
  this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
12659
12877
  } else {
12660
- if (mod.extensionIdPattern && typeof mod.extensionIdPattern === "string") {
12878
+ if (typeof mod.extensionIdPattern === "string") {
12661
12879
  const flags = mod.extensionIdPattern_flags || "";
12662
12880
  mod.extensionIdPattern = new RegExp(mod.extensionIdPattern, flags);
12663
- delete mod.extensionIdPattern_flags;
12664
12881
  }
12665
- const hasCompatibility = Array.isArray(mod.compatibility);
12666
- const scriptsPath = path12.join(d, "scripts.js");
12882
+ const { extensionIdPattern_flags, extensionIdPattern, ...providerFields } = mod;
12883
+ const normalizedProvider = {
12884
+ ...providerFields,
12885
+ ...extensionIdPattern instanceof RegExp ? { extensionIdPattern } : {}
12886
+ };
12887
+ const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
12888
+ const scriptsPath = path13.join(d, "scripts.js");
12667
12889
  if (!hasCompatibility && fs6.existsSync(scriptsPath)) {
12668
12890
  try {
12669
12891
  delete __require.cache[__require.resolve(scriptsPath)];
12670
12892
  const scripts = __require(scriptsPath);
12671
- mod.scripts = scripts;
12893
+ normalizedProvider.scripts = scripts;
12672
12894
  } catch (e) {
12673
12895
  this.log(`\u26A0 Failed to load scripts: ${scriptsPath}: ${e.message}`);
12674
12896
  }
12675
12897
  }
12676
- const existed = this.providers.has(mod.type);
12677
- this.providers.set(mod.type, mod);
12898
+ const existed = this.providers.has(normalizedProvider.type);
12899
+ this.providers.set(normalizedProvider.type, normalizedProvider);
12678
12900
  count++;
12679
12901
  const source = d.startsWith(this.userDir) && !d.includes(".upstream") ? "user" : "upstream";
12680
12902
  const overrideWarning = existed && source === "user" ? " \u26A0 OVERRIDES upstream" : "";
12681
- this.log(` ${existed ? "\u{1F504}" : "\u2705"} ${mod.type} (${mod.category}) \u2014 ${mod.name} [${source}]${overrideWarning}`);
12903
+ this.log(` ${existed ? "\u{1F504}" : "\u2705"} ${normalizedProvider.type} (${normalizedProvider.category}) \u2014 ${normalizedProvider.name} [${source}]${overrideWarning}`);
12682
12904
  }
12683
12905
  } catch (e) {
12684
12906
  this.log(`\u26A0 Failed to load ${jsonPath}: ${e.message}`);
@@ -12689,7 +12911,7 @@ var ProviderLoader = class _ProviderLoader {
12689
12911
  if (!entry.isDirectory()) continue;
12690
12912
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
12691
12913
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
12692
- scan(path12.join(d, entry.name));
12914
+ scan(path13.join(d, entry.name));
12693
12915
  }
12694
12916
  }
12695
12917
  };
@@ -12759,9 +12981,9 @@ function getWinProcessNames() {
12759
12981
  function getProviderMeta(ideId) {
12760
12982
  return getProviderLoader().getMeta(ideId);
12761
12983
  }
12762
- function getPreferredLaunchMethod(ideId, platform9) {
12984
+ function getPreferredLaunchMethod(ideId, platform10) {
12763
12985
  const prefer = getProviderMeta(ideId)?.launch?.prefer;
12764
- const value = prefer?.[platform9];
12986
+ const value = prefer?.[platform10];
12765
12987
  return value === "cli" || value === "app" || value === "auto" ? value : "auto";
12766
12988
  }
12767
12989
  function getCdpStartupTimeoutMs(ideId) {
@@ -12818,7 +13040,7 @@ async function isCdpActive(port) {
12818
13040
  });
12819
13041
  }
12820
13042
  async function killIdeProcess(ideId) {
12821
- const plat = os12.platform();
13043
+ const plat = os14.platform();
12822
13044
  const appName = getMacAppIdentifiers()[ideId];
12823
13045
  const winProcesses = getWinProcessNames()[ideId];
12824
13046
  try {
@@ -12877,7 +13099,7 @@ async function killIdeProcess(ideId) {
12877
13099
  }
12878
13100
  }
12879
13101
  function isIdeRunning(ideId) {
12880
- const plat = os12.platform();
13102
+ const plat = os14.platform();
12881
13103
  try {
12882
13104
  if (plat === "darwin") {
12883
13105
  const appName = getMacAppIdentifiers()[ideId];
@@ -12928,7 +13150,7 @@ function isIdeRunning(ideId) {
12928
13150
  }
12929
13151
  }
12930
13152
  function detectCurrentWorkspace(ideId) {
12931
- const plat = os12.platform();
13153
+ const plat = os14.platform();
12932
13154
  if (plat === "darwin") {
12933
13155
  try {
12934
13156
  const appName = getMacAppIdentifiers()[ideId];
@@ -12947,8 +13169,8 @@ function detectCurrentWorkspace(ideId) {
12947
13169
  const appNameMap = getMacAppIdentifiers();
12948
13170
  const appName = appNameMap[ideId];
12949
13171
  if (appName) {
12950
- const storagePath = path13.join(
12951
- process.env.APPDATA || path13.join(os12.homedir(), "AppData", "Roaming"),
13172
+ const storagePath = path14.join(
13173
+ process.env.APPDATA || path14.join(os14.homedir(), "AppData", "Roaming"),
12952
13174
  appName,
12953
13175
  "storage.json"
12954
13176
  );
@@ -12970,7 +13192,7 @@ function detectCurrentWorkspace(ideId) {
12970
13192
  return void 0;
12971
13193
  }
12972
13194
  async function launchWithCdp(options = {}) {
12973
- const platform9 = os12.platform();
13195
+ const platform10 = os14.platform();
12974
13196
  let targetIde;
12975
13197
  const ides = await detectIDEs(getProviderLoader());
12976
13198
  if (options.ideId) {
@@ -13039,9 +13261,9 @@ async function launchWithCdp(options = {}) {
13039
13261
  }
13040
13262
  const port = await findFreePort(portPair);
13041
13263
  try {
13042
- if (platform9 === "darwin") {
13264
+ if (platform10 === "darwin") {
13043
13265
  await launchMacOS(targetIde, port, workspace, options.newWindow);
13044
- } else if (platform9 === "win32") {
13266
+ } else if (platform10 === "win32") {
13045
13267
  await launchWindows(targetIde, port, workspace, options.newWindow);
13046
13268
  } else {
13047
13269
  await launchLinux(targetIde, port, workspace, options.newWindow);
@@ -13126,9 +13348,9 @@ init_logger();
13126
13348
 
13127
13349
  // src/logging/command-log.ts
13128
13350
  import * as fs7 from "fs";
13129
- import * as path14 from "path";
13130
- import * as os13 from "os";
13131
- var LOG_DIR2 = process.platform === "win32" ? path14.join(process.env.LOCALAPPDATA || process.env.APPDATA || path14.join(os13.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path14.join(os13.homedir(), "Library", "Logs", "adhdev") : path14.join(os13.homedir(), ".local", "share", "adhdev", "logs");
13351
+ import * as path15 from "path";
13352
+ import * as os15 from "os";
13353
+ var LOG_DIR2 = process.platform === "win32" ? path15.join(process.env.LOCALAPPDATA || process.env.APPDATA || path15.join(os15.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path15.join(os15.homedir(), "Library", "Logs", "adhdev") : path15.join(os15.homedir(), ".local", "share", "adhdev", "logs");
13132
13354
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
13133
13355
  var MAX_DAYS = 7;
13134
13356
  try {
@@ -13166,13 +13388,13 @@ function getDateStr2() {
13166
13388
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
13167
13389
  }
13168
13390
  var currentDate2 = getDateStr2();
13169
- var currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13391
+ var currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13170
13392
  var writeCount2 = 0;
13171
13393
  function checkRotation() {
13172
13394
  const today = getDateStr2();
13173
13395
  if (today !== currentDate2) {
13174
13396
  currentDate2 = today;
13175
- currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13397
+ currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13176
13398
  cleanOldFiles();
13177
13399
  }
13178
13400
  }
@@ -13186,7 +13408,7 @@ function cleanOldFiles() {
13186
13408
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
13187
13409
  if (dateMatch && dateMatch[1] < cutoffStr) {
13188
13410
  try {
13189
- fs7.unlinkSync(path14.join(LOG_DIR2, file));
13411
+ fs7.unlinkSync(path15.join(LOG_DIR2, file));
13190
13412
  } catch {
13191
13413
  }
13192
13414
  }
@@ -13264,7 +13486,7 @@ init_logger();
13264
13486
 
13265
13487
  // src/status/snapshot.ts
13266
13488
  init_config();
13267
- import * as os14 from "os";
13489
+ import * as os16 from "os";
13268
13490
  init_terminal_screen();
13269
13491
  init_logger();
13270
13492
  var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
@@ -13383,16 +13605,16 @@ function buildStatusSnapshot(options) {
13383
13605
  version: options.version,
13384
13606
  daemonMode: options.daemonMode,
13385
13607
  machine: {
13386
- hostname: os14.hostname(),
13387
- platform: os14.platform(),
13388
- arch: os14.arch(),
13389
- cpus: os14.cpus().length,
13608
+ hostname: os16.hostname(),
13609
+ platform: os16.platform(),
13610
+ arch: os16.arch(),
13611
+ cpus: os16.cpus().length,
13390
13612
  totalMem: memSnap.totalMem,
13391
13613
  freeMem: memSnap.freeMem,
13392
13614
  availableMem: memSnap.availableMem,
13393
- loadavg: os14.loadavg(),
13394
- uptime: os14.uptime(),
13395
- release: os14.release()
13615
+ loadavg: os16.loadavg(),
13616
+ uptime: os16.uptime(),
13617
+ release: os16.release()
13396
13618
  },
13397
13619
  machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
13398
13620
  timestamp: options.timestamp ?? Date.now(),
@@ -13413,14 +13635,14 @@ function buildStatusSnapshot(options) {
13413
13635
  import { execFileSync } from "child_process";
13414
13636
  import { spawn as spawn3 } from "child_process";
13415
13637
  import * as fs8 from "fs";
13416
- import * as os15 from "os";
13417
- import * as path15 from "path";
13638
+ import * as os17 from "os";
13639
+ import * as path16 from "path";
13418
13640
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
13419
13641
  function getUpgradeLogPath() {
13420
- const home = os15.homedir();
13421
- const dir = path15.join(home, ".adhdev");
13642
+ const home = os17.homedir();
13643
+ const dir = path16.join(home, ".adhdev");
13422
13644
  fs8.mkdirSync(dir, { recursive: true });
13423
- return path15.join(dir, "daemon-upgrade.log");
13645
+ return path16.join(dir, "daemon-upgrade.log");
13424
13646
  }
13425
13647
  function appendUpgradeLog(message) {
13426
13648
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -13460,7 +13682,7 @@ async function waitForPidExit(pid, timeoutMs) {
13460
13682
  }
13461
13683
  }
13462
13684
  function stopSessionHostProcesses(appName) {
13463
- const pidFile = path15.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
13685
+ const pidFile = path16.join(os17.homedir(), ".adhdev", `${appName}-session-host.pid`);
13464
13686
  try {
13465
13687
  if (fs8.existsSync(pidFile)) {
13466
13688
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
@@ -13489,7 +13711,7 @@ function stopSessionHostProcesses(appName) {
13489
13711
  }
13490
13712
  }
13491
13713
  function removeDaemonPidFile() {
13492
- const pidFile = path15.join(os15.homedir(), ".adhdev", "daemon.pid");
13714
+ const pidFile = path16.join(os17.homedir(), ".adhdev", "daemon.pid");
13493
13715
  try {
13494
13716
  fs8.unlinkSync(pidFile);
13495
13717
  } catch {
@@ -13500,7 +13722,7 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
13500
13722
  const npmRoot = execFileSync(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
13501
13723
  if (!npmRoot) return;
13502
13724
  const npmPrefix = execFileSync(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
13503
- const binDir = process.platform === "win32" ? npmPrefix : path15.join(npmPrefix, "bin");
13725
+ const binDir = process.platform === "win32" ? npmPrefix : path16.join(npmPrefix, "bin");
13504
13726
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
13505
13727
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
13506
13728
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -13508,25 +13730,25 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
13508
13730
  }
13509
13731
  if (pkgName.startsWith("@")) {
13510
13732
  const [scope, name] = pkgName.split("/");
13511
- const scopeDir = path15.join(npmRoot, scope);
13733
+ const scopeDir = path16.join(npmRoot, scope);
13512
13734
  if (!fs8.existsSync(scopeDir)) return;
13513
13735
  for (const entry of fs8.readdirSync(scopeDir)) {
13514
13736
  if (!entry.startsWith(`.${name}-`)) continue;
13515
- fs8.rmSync(path15.join(scopeDir, entry), { recursive: true, force: true });
13516
- appendUpgradeLog(`Removed stale scoped staging dir: ${path15.join(scopeDir, entry)}`);
13737
+ fs8.rmSync(path16.join(scopeDir, entry), { recursive: true, force: true });
13738
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path16.join(scopeDir, entry)}`);
13517
13739
  }
13518
13740
  } else {
13519
13741
  for (const entry of fs8.readdirSync(npmRoot)) {
13520
13742
  if (!entry.startsWith(`.${pkgName}-`)) continue;
13521
- fs8.rmSync(path15.join(npmRoot, entry), { recursive: true, force: true });
13522
- appendUpgradeLog(`Removed stale staging dir: ${path15.join(npmRoot, entry)}`);
13743
+ fs8.rmSync(path16.join(npmRoot, entry), { recursive: true, force: true });
13744
+ appendUpgradeLog(`Removed stale staging dir: ${path16.join(npmRoot, entry)}`);
13523
13745
  }
13524
13746
  }
13525
13747
  if (fs8.existsSync(binDir)) {
13526
13748
  for (const entry of fs8.readdirSync(binDir)) {
13527
13749
  if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
13528
- fs8.rmSync(path15.join(binDir, entry), { recursive: true, force: true });
13529
- appendUpgradeLog(`Removed stale bin staging entry: ${path15.join(binDir, entry)}`);
13750
+ fs8.rmSync(path16.join(binDir, entry), { recursive: true, force: true });
13751
+ appendUpgradeLog(`Removed stale bin staging entry: ${path16.join(binDir, entry)}`);
13530
13752
  }
13531
13753
  }
13532
13754
  }
@@ -13612,6 +13834,18 @@ var CHAT_COMMANDS = [
13612
13834
  "change_model"
13613
13835
  ];
13614
13836
  var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
13837
+ function normalizeCommandSource(source) {
13838
+ switch (source) {
13839
+ case "ws":
13840
+ case "p2p":
13841
+ case "ext":
13842
+ case "api":
13843
+ case "standalone":
13844
+ return source;
13845
+ default:
13846
+ return "unknown";
13847
+ }
13848
+ }
13615
13849
  function toHostedCliRuntimeDescriptor(record) {
13616
13850
  if (!record || typeof record !== "object") return null;
13617
13851
  const runtimeId = typeof record.sessionId === "string" ? record.sessionId : "";
@@ -13649,20 +13883,21 @@ var DaemonCommandRouter = class {
13649
13883
  */
13650
13884
  async execute(cmd, args, source = "unknown") {
13651
13885
  const cmdStart = Date.now();
13886
+ const logSource = normalizeCommandSource(source);
13652
13887
  try {
13653
13888
  const daemonResult = await this.executeDaemonCommand(cmd, args);
13654
13889
  if (daemonResult) {
13655
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
13890
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
13656
13891
  return daemonResult;
13657
13892
  }
13658
13893
  const handlerResult = await this.deps.commandHandler.handle(cmd, args);
13659
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
13894
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
13660
13895
  if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
13661
13896
  this.deps.onPostChatCommand();
13662
13897
  }
13663
13898
  return handlerResult;
13664
13899
  } catch (e) {
13665
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
13900
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source: logSource, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
13666
13901
  throw e;
13667
13902
  }
13668
13903
  }
@@ -13932,7 +14167,7 @@ var DaemonCommandRouter = class {
13932
14167
  } catch {
13933
14168
  }
13934
14169
  }
13935
- return { success: result.success, ...result };
14170
+ return { ...result };
13936
14171
  }
13937
14172
  // ─── Detect IDEs ───
13938
14173
  case "detect_ides": {
@@ -14062,16 +14297,14 @@ var DaemonCommandRouter = class {
14062
14297
  }
14063
14298
  }
14064
14299
  for (const instanceKey of keysToRemove) {
14065
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
14066
- if (ideInstance) {
14300
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
14067
14301
  this.deps.instanceManager.removeInstance(instanceKey);
14068
14302
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
14069
14303
  }
14070
14304
  }
14071
14305
  if (keysToRemove.length === 0) {
14072
14306
  const instanceKey = `ide:${ideType}`;
14073
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
14074
- if (ideInstance) {
14307
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
14075
14308
  this.deps.instanceManager.removeInstance(instanceKey);
14076
14309
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
14077
14310
  }
@@ -14286,11 +14519,11 @@ var DaemonStatusReporter = class {
14286
14519
  // ─── P2P ─────────────────────────────────────────
14287
14520
  sendP2PPayload(payload) {
14288
14521
  const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
14289
- if (hashTarget.machine) {
14522
+ const hashPayload = hashTarget.machine ? (() => {
14290
14523
  const { freeMem: _f, availableMem: _a, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
14291
- hashTarget.machine = stableMachine;
14292
- }
14293
- const h = this.simpleHash(JSON.stringify(hashTarget));
14524
+ return { ...hashTarget, machine: stableMachine };
14525
+ })() : hashTarget;
14526
+ const h = this.simpleHash(JSON.stringify(hashPayload));
14294
14527
  if (h !== this.lastP2PStatusHash) {
14295
14528
  this.lastP2PStatusHash = h;
14296
14529
  this.deps.p2p?.sendStatus(payload);
@@ -14338,6 +14571,9 @@ var ProviderStreamAdapter = class {
14338
14571
  hasScript(name) {
14339
14572
  return typeof this.provider.scripts?.[name] === "function";
14340
14573
  }
14574
+ getStateTitle(state) {
14575
+ return typeof state.title === "string" ? state.title : "";
14576
+ }
14341
14577
  parseMaybeJson(raw) {
14342
14578
  if (typeof raw !== "string") return raw;
14343
14579
  try {
@@ -14541,7 +14777,7 @@ var ProviderStreamAdapter = class {
14541
14777
  for (let attempt = 0; attempt < 6; attempt += 1) {
14542
14778
  await new Promise((resolve12) => setTimeout(resolve12, 250));
14543
14779
  const state = await this.readChat(evaluate);
14544
- const title = typeof state.title === "string" ? state.title : "";
14780
+ const title = this.getStateTitle(state);
14545
14781
  if (this.titlesMatch(title, sessionId)) return true;
14546
14782
  }
14547
14783
  return false;
@@ -14638,6 +14874,11 @@ var DaemonAgentStreamManager = class {
14638
14874
  const child = (this.sessionRegistry?.listChildren(parentSessionId) || []).find((entry) => entry.transport === "cdp-webview" && entry.providerType === agentType);
14639
14875
  return child?.sessionId || null;
14640
14876
  }
14877
+ getStateError(state) {
14878
+ if (typeof state.error === "string" && state.error.trim()) return state.error.trim();
14879
+ if (typeof state._error === "string" && state._error.trim()) return state._error.trim();
14880
+ return "unknown";
14881
+ }
14641
14882
  async connectManagedSession(cdp, parentSessionId, runtimeSessionId) {
14642
14883
  const target = this.getSessionTarget(runtimeSessionId);
14643
14884
  if (!target || target.transport !== "cdp-webview") return null;
@@ -14700,8 +14941,8 @@ var DaemonAgentStreamManager = class {
14700
14941
  try {
14701
14942
  const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
14702
14943
  const state = await agent.adapter.readChat(evaluate);
14703
- 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") : ""}`);
14704
- const stateError = String(state.error || state._error || "");
14944
+ const stateError = this.getStateError(state);
14945
+ LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${state.model || ""}${state.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
14705
14946
  if (state.status === "error" && this.isRecoverableSessionError(stateError)) {
14706
14947
  throw new Error(stateError);
14707
14948
  }
@@ -15270,11 +15511,11 @@ var ProviderInstanceManager = class {
15270
15511
 
15271
15512
  // src/providers/version-archive.ts
15272
15513
  import * as fs10 from "fs";
15273
- import * as path16 from "path";
15274
- import * as os16 from "os";
15514
+ import * as path17 from "path";
15515
+ import * as os18 from "os";
15275
15516
  import { execSync as execSync5 } from "child_process";
15276
- import { platform as platform7 } from "os";
15277
- var ARCHIVE_PATH = path16.join(os16.homedir(), ".adhdev", "version-history.json");
15517
+ import { platform as platform8 } from "os";
15518
+ var ARCHIVE_PATH = path17.join(os18.homedir(), ".adhdev", "version-history.json");
15278
15519
  var MAX_ENTRIES_PER_PROVIDER = 20;
15279
15520
  var VersionArchive = class {
15280
15521
  history = {};
@@ -15299,7 +15540,7 @@ var VersionArchive = class {
15299
15540
  entries.push({
15300
15541
  version,
15301
15542
  detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
15302
- os: platform7()
15543
+ os: platform8()
15303
15544
  });
15304
15545
  if (entries.length > MAX_ENTRIES_PER_PROVIDER) {
15305
15546
  this.history[type] = entries.slice(-MAX_ENTRIES_PER_PROVIDER);
@@ -15321,7 +15562,7 @@ var VersionArchive = class {
15321
15562
  }
15322
15563
  save() {
15323
15564
  try {
15324
- fs10.mkdirSync(path16.dirname(ARCHIVE_PATH), { recursive: true });
15565
+ fs10.mkdirSync(path17.dirname(ARCHIVE_PATH), { recursive: true });
15325
15566
  fs10.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
15326
15567
  } catch {
15327
15568
  }
@@ -15339,7 +15580,7 @@ function runCommand(cmd, timeout = 1e4) {
15339
15580
  }
15340
15581
  }
15341
15582
  function findBinary2(name) {
15342
- const cmd = platform7() === "win32" ? `where ${name}` : `which ${name}`;
15583
+ const cmd = platform8() === "win32" ? `where ${name}` : `which ${name}`;
15343
15584
  const result = runCommand(cmd, 5e3);
15344
15585
  return result ? result.split("\n")[0] : null;
15345
15586
  }
@@ -15347,6 +15588,22 @@ function parseVersion2(raw) {
15347
15588
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
15348
15589
  return match ? match[1] : raw.split("\n")[0].substring(0, 100);
15349
15590
  }
15591
+ function getPlatformVersionCommand(versionCommand, currentOs) {
15592
+ if (!versionCommand) return void 0;
15593
+ if (typeof versionCommand === "string") {
15594
+ const trimmed = versionCommand.trim();
15595
+ return trimmed || void 0;
15596
+ }
15597
+ const platformValue = versionCommand[currentOs];
15598
+ if (typeof platformValue === "string" && platformValue.trim()) {
15599
+ return platformValue.trim();
15600
+ }
15601
+ const defaultValue = versionCommand.default;
15602
+ if (typeof defaultValue === "string" && defaultValue.trim()) {
15603
+ return defaultValue.trim();
15604
+ }
15605
+ return void 0;
15606
+ }
15350
15607
  function getVersion(binary, versionCommand) {
15351
15608
  if (versionCommand) {
15352
15609
  const raw = runCommand(versionCommand);
@@ -15361,8 +15618,8 @@ function getVersion(binary, versionCommand) {
15361
15618
  function checkPathExists2(paths) {
15362
15619
  for (const p of paths) {
15363
15620
  if (p.includes("*")) {
15364
- const home = os16.homedir();
15365
- const resolved = p.replace(/\*/g, home.split(path16.sep).pop() || "");
15621
+ const home = os18.homedir();
15622
+ const resolved = p.replace(/\*/g, home.split(path17.sep).pop() || "");
15366
15623
  if (fs10.existsSync(resolved)) return resolved;
15367
15624
  } else {
15368
15625
  if (fs10.existsSync(p)) return p;
@@ -15371,15 +15628,15 @@ function checkPathExists2(paths) {
15371
15628
  return null;
15372
15629
  }
15373
15630
  function getMacAppVersion(appPath) {
15374
- if (platform7() !== "darwin" || !appPath.endsWith(".app")) return null;
15375
- const plistPath = path16.join(appPath, "Contents", "Info.plist");
15631
+ if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
15632
+ const plistPath = path17.join(appPath, "Contents", "Info.plist");
15376
15633
  if (!fs10.existsSync(plistPath)) return null;
15377
15634
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
15378
15635
  return raw || null;
15379
15636
  }
15380
15637
  async function detectAllVersions(loader, archive) {
15381
15638
  const results = [];
15382
- const currentOs = platform7();
15639
+ const currentOs = platform8();
15383
15640
  for (const provider of loader.getAll()) {
15384
15641
  const info = {
15385
15642
  type: provider.type,
@@ -15391,15 +15648,14 @@ async function detectAllVersions(loader, archive) {
15391
15648
  binary: null,
15392
15649
  detectedAt: (/* @__PURE__ */ new Date()).toISOString()
15393
15650
  };
15394
- const verCmdConfig = provider.versionCommand;
15395
- const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[currentOs] : verCmdConfig;
15651
+ const versionCommand = getPlatformVersionCommand(provider.versionCommand, currentOs);
15396
15652
  if (provider.category === "ide") {
15397
15653
  const osPaths = provider.paths?.[currentOs] || [];
15398
15654
  const appPath = checkPathExists2(osPaths);
15399
15655
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
15400
15656
  let resolvedBin = cliBin;
15401
15657
  if (!resolvedBin && appPath && currentOs === "darwin") {
15402
- const bundled = path16.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
15658
+ const bundled = path17.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
15403
15659
  if (provider.cli && fs10.existsSync(bundled)) resolvedBin = bundled;
15404
15660
  }
15405
15661
  info.installed = !!(appPath || resolvedBin);
@@ -15440,7 +15696,7 @@ async function detectAllVersions(loader, archive) {
15440
15696
  // src/daemon/dev-server.ts
15441
15697
  import * as http2 from "http";
15442
15698
  import * as fs14 from "fs";
15443
- import * as path20 from "path";
15699
+ import * as path21 from "path";
15444
15700
 
15445
15701
  // src/daemon/scaffold-template.ts
15446
15702
  function generateFiles(type, name, category, opts = {}) {
@@ -15777,7 +16033,7 @@ init_logger();
15777
16033
  // src/daemon/dev-cdp-handlers.ts
15778
16034
  init_logger();
15779
16035
  import * as fs11 from "fs";
15780
- import * as path17 from "path";
16036
+ import * as path18 from "path";
15781
16037
  async function handleCdpEvaluate(ctx, req, res) {
15782
16038
  const body = await ctx.readBody(req);
15783
16039
  const { expression, timeout, ideType } = body;
@@ -15955,17 +16211,17 @@ async function handleScriptHints(ctx, type, _req, res) {
15955
16211
  return;
15956
16212
  }
15957
16213
  let scriptsPath = "";
15958
- const directScripts = path17.join(dir, "scripts.js");
16214
+ const directScripts = path18.join(dir, "scripts.js");
15959
16215
  if (fs11.existsSync(directScripts)) {
15960
16216
  scriptsPath = directScripts;
15961
16217
  } else {
15962
- const scriptsDir = path17.join(dir, "scripts");
16218
+ const scriptsDir = path18.join(dir, "scripts");
15963
16219
  if (fs11.existsSync(scriptsDir)) {
15964
16220
  const versions = fs11.readdirSync(scriptsDir).filter((d) => {
15965
- return fs11.statSync(path17.join(scriptsDir, d)).isDirectory();
16221
+ return fs11.statSync(path18.join(scriptsDir, d)).isDirectory();
15966
16222
  }).sort().reverse();
15967
16223
  for (const ver of versions) {
15968
- const p = path17.join(scriptsDir, ver, "scripts.js");
16224
+ const p = path18.join(scriptsDir, ver, "scripts.js");
15969
16225
  if (fs11.existsSync(p)) {
15970
16226
  scriptsPath = p;
15971
16227
  break;
@@ -16784,7 +17040,7 @@ async function handleDomContext(ctx, type, req, res) {
16784
17040
 
16785
17041
  // src/daemon/dev-cli-debug.ts
16786
17042
  import * as fs12 from "fs";
16787
- import * as path18 from "path";
17043
+ import * as path19 from "path";
16788
17044
  function slugifyFixtureName(value) {
16789
17045
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
16790
17046
  return normalized || `fixture-${Date.now()}`;
@@ -16794,11 +17050,11 @@ function getCliFixtureDir(ctx, type) {
16794
17050
  if (!providerDir) {
16795
17051
  throw new Error(`Provider directory not found for '${type}'`);
16796
17052
  }
16797
- return path18.join(providerDir, "fixtures");
17053
+ return path19.join(providerDir, "fixtures");
16798
17054
  }
16799
17055
  function readCliFixture(ctx, type, name) {
16800
17056
  const fixtureDir = getCliFixtureDir(ctx, type);
16801
- const filePath = path18.join(fixtureDir, `${name}.json`);
17057
+ const filePath = path19.join(fixtureDir, `${name}.json`);
16802
17058
  if (!fs12.existsSync(filePath)) {
16803
17059
  throw new Error(`Fixture not found: ${filePath}`);
16804
17060
  }
@@ -16924,6 +17180,15 @@ function validateCliFixtureResult(result, assertions) {
16924
17180
  }
16925
17181
  return failures;
16926
17182
  }
17183
+ function isCliTargetState(state) {
17184
+ return state.category === "cli" || state.category === "acp";
17185
+ }
17186
+ function getCliAdapterFromInstance(instance) {
17187
+ if (!instance) return null;
17188
+ const candidate = instance;
17189
+ if (typeof candidate.getAdapter === "function") return candidate.getAdapter();
17190
+ return candidate.adapter || null;
17191
+ }
16927
17192
  function getCliProviderResolutionMeta(ctx, type, adapter) {
16928
17193
  const adapterMeta = typeof adapter?.getProviderResolutionMeta === "function" ? adapter.getProviderResolutionMeta() : adapter?.getDebugState?.()?.providerResolution || null;
16929
17194
  const resolvedProvider = ctx.providerLoader.resolve(type);
@@ -16941,7 +17206,7 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
16941
17206
  }
16942
17207
  function findCliTarget(ctx, type, instanceId) {
16943
17208
  if (!ctx.instanceManager) return null;
16944
- const cliStates = ctx.instanceManager.collectAllStates().filter((s) => s.category === "cli" || s.category === "acp");
17209
+ const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
16945
17210
  if (instanceId) return cliStates.find((s) => s.instanceId === instanceId) || null;
16946
17211
  if (!type) return cliStates[cliStates.length - 1] || null;
16947
17212
  const matches = cliStates.filter((s) => s.type === type);
@@ -16953,7 +17218,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
16953
17218
  if (!target) return null;
16954
17219
  const instance = ctx.instanceManager.getInstance(target.instanceId);
16955
17220
  if (!instance) return null;
16956
- const adapter = instance.getAdapter?.() || instance.adapter;
17221
+ const adapter = getCliAdapterFromInstance(instance);
16957
17222
  if (!adapter) return null;
16958
17223
  return { target, instance, adapter };
16959
17224
  }
@@ -17428,7 +17693,7 @@ async function handleCliDebug(ctx, type, _req, res) {
17428
17693
  return;
17429
17694
  }
17430
17695
  try {
17431
- const adapter = instance.getAdapter?.() || instance.adapter;
17696
+ const adapter = getCliAdapterFromInstance(instance);
17432
17697
  if (adapter && typeof adapter.getDebugState === "function") {
17433
17698
  const debugState = adapter.getDebugState();
17434
17699
  ctx.json(res, 200, {
@@ -17475,7 +17740,7 @@ async function handleCliTrace(ctx, type, req, res) {
17475
17740
  return;
17476
17741
  }
17477
17742
  try {
17478
- const adapter = instance.getAdapter?.() || instance.adapter;
17743
+ const adapter = getCliAdapterFromInstance(instance);
17479
17744
  const url = new URL(req.url || "/", "http://127.0.0.1");
17480
17745
  const limit = parseInt(url.searchParams.get("limit") || "120", 10);
17481
17746
  if (adapter && typeof adapter.getTraceState === "function") {
@@ -17557,7 +17822,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
17557
17822
  },
17558
17823
  notes: typeof body?.notes === "string" ? body.notes : void 0
17559
17824
  };
17560
- const filePath = path18.join(fixtureDir, `${name}.json`);
17825
+ const filePath = path19.join(fixtureDir, `${name}.json`);
17561
17826
  fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
17562
17827
  ctx.json(res, 200, {
17563
17828
  saved: true,
@@ -17581,7 +17846,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
17581
17846
  return;
17582
17847
  }
17583
17848
  const fixtures = fs12.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
17584
- const fullPath = path18.join(fixtureDir, file);
17849
+ const fullPath = path19.join(fixtureDir, file);
17585
17850
  try {
17586
17851
  const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
17587
17852
  return {
@@ -17661,7 +17926,7 @@ async function handleCliResolve(ctx, req, res) {
17661
17926
  return;
17662
17927
  }
17663
17928
  const instance = ctx.instanceManager.getInstance(target.instanceId);
17664
- const adapter = instance?.getAdapter?.() || instance?.adapter;
17929
+ const adapter = getCliAdapterFromInstance(instance);
17665
17930
  if (!adapter) {
17666
17931
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
17667
17932
  return;
@@ -17698,7 +17963,7 @@ async function handleCliRaw(ctx, req, res) {
17698
17963
  return;
17699
17964
  }
17700
17965
  const instance = ctx.instanceManager.getInstance(target.instanceId);
17701
- const adapter = instance?.getAdapter?.() || instance?.adapter;
17966
+ const adapter = getCliAdapterFromInstance(instance);
17702
17967
  if (!adapter) {
17703
17968
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
17704
17969
  return;
@@ -17717,11 +17982,11 @@ async function handleCliRaw(ctx, req, res) {
17717
17982
 
17718
17983
  // src/daemon/dev-auto-implement.ts
17719
17984
  import * as fs13 from "fs";
17720
- import * as path19 from "path";
17721
- import * as os17 from "os";
17985
+ import * as path20 from "path";
17986
+ import * as os19 from "os";
17722
17987
  function getAutoImplPid(ctx) {
17723
- const proc = ctx.autoImplProcess;
17724
- return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
17988
+ const pid = ctx.autoImplProcess?.pid;
17989
+ return typeof pid === "number" && pid > 0 ? pid : null;
17725
17990
  }
17726
17991
  function isPidAlive(pid) {
17727
17992
  try {
@@ -17739,6 +18004,13 @@ function clearStaleAutoImplState(ctx, reason) {
17739
18004
  ctx.autoImplProcess = null;
17740
18005
  ctx.autoImplStatus.running = false;
17741
18006
  }
18007
+ function tryKillAutoImplProcess(processRef, signal) {
18008
+ if (!processRef) return;
18009
+ try {
18010
+ processRef.kill(signal);
18011
+ } catch {
18012
+ }
18013
+ }
17742
18014
  function getDefaultAutoImplReference(ctx, category, type) {
17743
18015
  if (category === "cli") {
17744
18016
  return type === "codex-cli" ? "claude-cli" : "codex-cli";
@@ -17757,22 +18029,22 @@ function getLatestScriptVersionDir(scriptsDir) {
17757
18029
  if (!fs13.existsSync(scriptsDir)) return null;
17758
18030
  const versions = fs13.readdirSync(scriptsDir).filter((d) => {
17759
18031
  try {
17760
- return fs13.statSync(path19.join(scriptsDir, d)).isDirectory();
18032
+ return fs13.statSync(path20.join(scriptsDir, d)).isDirectory();
17761
18033
  } catch {
17762
18034
  return false;
17763
18035
  }
17764
18036
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
17765
18037
  if (versions.length === 0) return null;
17766
- return path19.join(scriptsDir, versions[0]);
18038
+ return path20.join(scriptsDir, versions[0]);
17767
18039
  }
17768
18040
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
17769
- const canonicalUserDir = path19.resolve(ctx.providerLoader.getUserProviderDir(category, type));
17770
- const desiredDir = requestedDir ? path19.resolve(requestedDir) : canonicalUserDir;
17771
- const upstreamRoot = path19.resolve(ctx.providerLoader.getUpstreamDir());
17772
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path19.sep}`)) {
18041
+ const canonicalUserDir = path20.resolve(ctx.providerLoader.getUserProviderDir(category, type));
18042
+ const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
18043
+ const upstreamRoot = path20.resolve(ctx.providerLoader.getUpstreamDir());
18044
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
17773
18045
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
17774
18046
  }
17775
- if (path19.basename(desiredDir) !== type) {
18047
+ if (path20.basename(desiredDir) !== type) {
17776
18048
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
17777
18049
  }
17778
18050
  const sourceDir = ctx.findProviderDir(type);
@@ -17780,11 +18052,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
17780
18052
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
17781
18053
  }
17782
18054
  if (!fs13.existsSync(desiredDir)) {
17783
- fs13.mkdirSync(path19.dirname(desiredDir), { recursive: true });
18055
+ fs13.mkdirSync(path20.dirname(desiredDir), { recursive: true });
17784
18056
  fs13.cpSync(sourceDir, desiredDir, { recursive: true });
17785
18057
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
17786
18058
  }
17787
- const providerJson = path19.join(desiredDir, "provider.json");
18059
+ const providerJson = path20.join(desiredDir, "provider.json");
17788
18060
  if (!fs13.existsSync(providerJson)) {
17789
18061
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
17790
18062
  }
@@ -17807,13 +18079,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
17807
18079
  const refDir = ctx.findProviderDir(referenceType);
17808
18080
  if (!refDir || !fs13.existsSync(refDir)) return {};
17809
18081
  const referenceScripts = {};
17810
- const scriptsDir = path19.join(refDir, "scripts");
18082
+ const scriptsDir = path20.join(refDir, "scripts");
17811
18083
  const latestDir = getLatestScriptVersionDir(scriptsDir);
17812
18084
  if (!latestDir) return referenceScripts;
17813
18085
  for (const file of fs13.readdirSync(latestDir)) {
17814
18086
  if (!file.endsWith(".js")) continue;
17815
18087
  try {
17816
- referenceScripts[file] = fs13.readFileSync(path19.join(latestDir, file), "utf-8");
18088
+ referenceScripts[file] = fs13.readFileSync(path20.join(latestDir, file), "utf-8");
17817
18089
  } catch {
17818
18090
  }
17819
18091
  }
@@ -17921,9 +18193,9 @@ async function handleAutoImplement(ctx, type, req, res) {
17921
18193
  });
17922
18194
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
17923
18195
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
17924
- const tmpDir = path19.join(os17.tmpdir(), "adhdev-autoimpl");
18196
+ const tmpDir = path20.join(os19.tmpdir(), "adhdev-autoimpl");
17925
18197
  if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
17926
- const promptFile = path19.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
18198
+ const promptFile = path20.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
17927
18199
  fs13.writeFileSync(promptFile, prompt, "utf-8");
17928
18200
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
17929
18201
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -18075,7 +18347,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18075
18347
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
18076
18348
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
18077
18349
  let shellCmd;
18078
- const isWin = os17.platform() === "win32";
18350
+ const isWin = os19.platform() === "win32";
18079
18351
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
18080
18352
  if (command === "claude") {
18081
18353
  const args = [...baseArgs, "--dangerously-skip-permissions"];
@@ -18119,7 +18391,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18119
18391
  try {
18120
18392
  const pty = __require("node-pty");
18121
18393
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
18122
- const isWin2 = os17.platform() === "win32";
18394
+ const isWin2 = os19.platform() === "win32";
18123
18395
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
18124
18396
  name: "xterm-256color",
18125
18397
  cols: 120,
@@ -18158,10 +18430,12 @@ async function handleAutoImplement(ctx, type, req, res) {
18158
18430
  let autoStopTimer = null;
18159
18431
  let autoStopIssued = false;
18160
18432
  try {
18161
- const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
18162
- const normalized = normalizeCliProviderForRuntime2(agentProvider);
18163
- approvalPatterns = normalized.patterns.approval;
18164
- approvalKeys = agentProvider?.approvalKeys || { 0: "y\r", 1: "a\r" };
18433
+ if (agentProvider?.category === "cli") {
18434
+ const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
18435
+ const normalized = normalizeCliProviderForRuntime2(agentProvider);
18436
+ approvalPatterns = normalized.patterns.approval;
18437
+ approvalKeys = agentProvider.approvalKeys || { 0: "y\r", 1: "a\r" };
18438
+ }
18165
18439
  } catch (err) {
18166
18440
  ctx.log(`Failed to load approval patterns: ${err.message}`);
18167
18441
  }
@@ -18176,10 +18450,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18176
18450
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
18177
18451
  `, stream: "stdout" } });
18178
18452
  approvalBuffer = "";
18179
- try {
18180
- ctx.autoImplProcess.kill("SIGINT");
18181
- } catch {
18182
- }
18453
+ tryKillAutoImplProcess(ctx.autoImplProcess, "SIGINT");
18183
18454
  return;
18184
18455
  }
18185
18456
  if (Date.now() - lastApprovalTime < 2e3) return;
@@ -18216,10 +18487,7 @@ async function handleAutoImplement(ctx, type, req, res) {
18216
18487
  stream: "stdout"
18217
18488
  }
18218
18489
  });
18219
- try {
18220
- ctx.autoImplProcess.kill("SIGINT");
18221
- } catch {
18222
- }
18490
+ tryKillAutoImplProcess(ctx.autoImplProcess, "SIGINT");
18223
18491
  }, 3e4);
18224
18492
  };
18225
18493
  const finalizeCliAutoImpl = async (code) => {
@@ -18350,7 +18618,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18350
18618
  setMode: "set_mode.js"
18351
18619
  };
18352
18620
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
18353
- const scriptsDir = path19.join(providerDir, "scripts");
18621
+ const scriptsDir = path20.join(providerDir, "scripts");
18354
18622
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
18355
18623
  if (latestScriptsDir) {
18356
18624
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -18361,7 +18629,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18361
18629
  for (const file of fs13.readdirSync(latestScriptsDir)) {
18362
18630
  if (file.endsWith(".js") && targetFileNames.has(file)) {
18363
18631
  try {
18364
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18632
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18365
18633
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
18366
18634
  lines.push("```javascript");
18367
18635
  lines.push(content);
@@ -18378,7 +18646,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18378
18646
  lines.push("");
18379
18647
  for (const file of refFiles) {
18380
18648
  try {
18381
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18649
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18382
18650
  lines.push(`### \`${file}\` \u{1F512}`);
18383
18651
  lines.push("```javascript");
18384
18652
  lines.push(content);
@@ -18419,10 +18687,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
18419
18687
  lines.push("");
18420
18688
  }
18421
18689
  }
18422
- const docsDir = path19.join(providerDir, "../../docs");
18690
+ const docsDir = path20.join(providerDir, "../../docs");
18423
18691
  const loadGuide = (name) => {
18424
18692
  try {
18425
- const p = path19.join(docsDir, name);
18693
+ const p = path20.join(docsDir, name);
18426
18694
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
18427
18695
  } catch {
18428
18696
  }
@@ -18657,7 +18925,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18657
18925
  parseApproval: "parse_approval.js"
18658
18926
  };
18659
18927
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
18660
- const scriptsDir = path19.join(providerDir, "scripts");
18928
+ const scriptsDir = path20.join(providerDir, "scripts");
18661
18929
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
18662
18930
  if (latestScriptsDir) {
18663
18931
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -18669,7 +18937,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18669
18937
  if (!file.endsWith(".js")) continue;
18670
18938
  if (!targetFileNames.has(file)) continue;
18671
18939
  try {
18672
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18940
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18673
18941
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
18674
18942
  lines.push("```javascript");
18675
18943
  lines.push(content);
@@ -18685,7 +18953,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18685
18953
  lines.push("");
18686
18954
  for (const file of refFiles) {
18687
18955
  try {
18688
- const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
18956
+ const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
18689
18957
  lines.push(`### \`${file}\` \u{1F512}`);
18690
18958
  lines.push("```javascript");
18691
18959
  lines.push(content);
@@ -18718,10 +18986,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
18718
18986
  lines.push("");
18719
18987
  }
18720
18988
  }
18721
- const docsDir = path19.join(providerDir, "../../docs");
18989
+ const docsDir = path20.join(providerDir, "../../docs");
18722
18990
  const loadGuide = (name) => {
18723
18991
  try {
18724
- const p = path19.join(docsDir, name);
18992
+ const p = path20.join(docsDir, name);
18725
18993
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
18726
18994
  } catch {
18727
18995
  }
@@ -19036,6 +19304,38 @@ data: ${JSON.stringify(msg.data)}
19036
19304
 
19037
19305
  // src/daemon/dev-server.ts
19038
19306
  var DEV_SERVER_PORT = 19280;
19307
+ function getScriptNames(scripts) {
19308
+ if (!scripts) return [];
19309
+ return Object.entries(scripts).filter(([, value]) => typeof value === "function").map(([name]) => name);
19310
+ }
19311
+ function toProviderListEntry(provider) {
19312
+ const base = {
19313
+ type: provider.type,
19314
+ name: provider.name,
19315
+ category: provider.category,
19316
+ icon: provider.icon || null,
19317
+ displayName: provider.displayName || provider.name
19318
+ };
19319
+ if (provider.category === "ide" || provider.category === "extension") {
19320
+ base.scripts = getScriptNames(provider.scripts);
19321
+ base.inputMethod = provider.inputMethod || null;
19322
+ base.inputSelector = provider.inputSelector || null;
19323
+ base.extensionId = provider.extensionId || null;
19324
+ base.cdpPorts = provider.cdpPorts || [];
19325
+ }
19326
+ if (provider.category === "acp") {
19327
+ base.spawn = provider.spawn || null;
19328
+ base.auth = provider.auth || null;
19329
+ base.install = provider.install || null;
19330
+ base.hasSettings = !!provider.settings;
19331
+ base.settingsCount = provider.settings ? Object.keys(provider.settings).length : 0;
19332
+ }
19333
+ if (provider.category === "cli") {
19334
+ base.spawn = provider.spawn || null;
19335
+ base.install = provider.install || null;
19336
+ }
19337
+ return base;
19338
+ }
19039
19339
  var DevServer = class _DevServer {
19040
19340
  server = null;
19041
19341
  providerLoader;
@@ -19132,8 +19432,8 @@ var DevServer = class _DevServer {
19132
19432
  }
19133
19433
  getEndpointList() {
19134
19434
  return this.routes.map((r) => {
19135
- const path21 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
19136
- return `${r.method.padEnd(5)} ${path21}`;
19435
+ const path22 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
19436
+ return `${r.method.padEnd(5)} ${path22}`;
19137
19437
  });
19138
19438
  }
19139
19439
  async start(port = DEV_SERVER_PORT) {
@@ -19185,34 +19485,7 @@ var DevServer = class _DevServer {
19185
19485
  }
19186
19486
  // ─── Handlers ───
19187
19487
  async handleListProviders(_req, res) {
19188
- const providers = this.providerLoader.getAll().map((p) => {
19189
- const base = {
19190
- type: p.type,
19191
- name: p.name,
19192
- category: p.category,
19193
- icon: p.icon || null,
19194
- displayName: p.displayName || p.name
19195
- };
19196
- if (p.category === "ide" || p.category === "extension") {
19197
- base.scripts = p.scripts ? Object.keys(p.scripts).filter((k) => typeof p.scripts[k] === "function") : [];
19198
- base.inputMethod = p.inputMethod || null;
19199
- base.inputSelector = p.inputSelector || null;
19200
- base.extensionId = p.extensionId || null;
19201
- base.cdpPorts = p.cdpPorts || [];
19202
- }
19203
- if (p.category === "acp") {
19204
- base.spawn = p.spawn || null;
19205
- base.auth = p.auth || null;
19206
- base.install = p.install || null;
19207
- base.hasSettings = !!p.settings;
19208
- base.settingsCount = p.settings ? Object.keys(p.settings).length : 0;
19209
- }
19210
- if (p.category === "cli") {
19211
- base.spawn = p.spawn || null;
19212
- base.install = p.install || null;
19213
- }
19214
- return base;
19215
- });
19488
+ const providers = this.providerLoader.getAll().map(toProviderListEntry);
19216
19489
  this.json(res, 200, { providers, count: providers.length });
19217
19490
  }
19218
19491
  async handleProviderConfig(type, _req, res) {
@@ -19404,7 +19677,7 @@ var DevServer = class _DevServer {
19404
19677
  }));
19405
19678
  for (const cdp of this.cdpManagers.values()) {
19406
19679
  if (!cdp.isConnected) {
19407
- cdp._targetId = null;
19680
+ cdp.clearTargetId();
19408
19681
  }
19409
19682
  }
19410
19683
  this.json(res, 200, { reloaded: true, providers });
@@ -19415,12 +19688,12 @@ var DevServer = class _DevServer {
19415
19688
  // ─── DevConsole SPA ───
19416
19689
  getConsoleDistDir() {
19417
19690
  const candidates = [
19418
- path20.resolve(__dirname, "../../web-devconsole/dist"),
19419
- path20.resolve(__dirname, "../../../web-devconsole/dist"),
19420
- path20.join(process.cwd(), "packages/web-devconsole/dist")
19691
+ path21.resolve(__dirname, "../../web-devconsole/dist"),
19692
+ path21.resolve(__dirname, "../../../web-devconsole/dist"),
19693
+ path21.join(process.cwd(), "packages/web-devconsole/dist")
19421
19694
  ];
19422
19695
  for (const dir of candidates) {
19423
- if (fs14.existsSync(path20.join(dir, "index.html"))) return dir;
19696
+ if (fs14.existsSync(path21.join(dir, "index.html"))) return dir;
19424
19697
  }
19425
19698
  return null;
19426
19699
  }
@@ -19430,7 +19703,7 @@ var DevServer = class _DevServer {
19430
19703
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
19431
19704
  return;
19432
19705
  }
19433
- const htmlPath = path20.join(distDir, "index.html");
19706
+ const htmlPath = path21.join(distDir, "index.html");
19434
19707
  try {
19435
19708
  const html = fs14.readFileSync(htmlPath, "utf-8");
19436
19709
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -19455,15 +19728,15 @@ var DevServer = class _DevServer {
19455
19728
  this.json(res, 404, { error: "Not found" });
19456
19729
  return;
19457
19730
  }
19458
- const safePath = path20.normalize(pathname).replace(/^\.\.\//, "");
19459
- const filePath = path20.join(distDir, safePath);
19731
+ const safePath = path21.normalize(pathname).replace(/^\.\.\//, "");
19732
+ const filePath = path21.join(distDir, safePath);
19460
19733
  if (!filePath.startsWith(distDir)) {
19461
19734
  this.json(res, 403, { error: "Forbidden" });
19462
19735
  return;
19463
19736
  }
19464
19737
  try {
19465
19738
  const content = fs14.readFileSync(filePath);
19466
- const ext = path20.extname(filePath);
19739
+ const ext = path21.extname(filePath);
19467
19740
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
19468
19741
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
19469
19742
  res.end(content);
@@ -19576,9 +19849,9 @@ var DevServer = class _DevServer {
19576
19849
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
19577
19850
  if (entry.isDirectory()) {
19578
19851
  files.push({ path: rel, size: 0, type: "dir" });
19579
- scan(path20.join(d, entry.name), rel);
19852
+ scan(path21.join(d, entry.name), rel);
19580
19853
  } else {
19581
- const stat = fs14.statSync(path20.join(d, entry.name));
19854
+ const stat = fs14.statSync(path21.join(d, entry.name));
19582
19855
  files.push({ path: rel, size: stat.size, type: "file" });
19583
19856
  }
19584
19857
  }
@@ -19601,7 +19874,7 @@ var DevServer = class _DevServer {
19601
19874
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
19602
19875
  return;
19603
19876
  }
19604
- const fullPath = path20.resolve(dir, path20.normalize(filePath));
19877
+ const fullPath = path21.resolve(dir, path21.normalize(filePath));
19605
19878
  if (!fullPath.startsWith(dir)) {
19606
19879
  this.json(res, 403, { error: "Forbidden" });
19607
19880
  return;
@@ -19626,14 +19899,14 @@ var DevServer = class _DevServer {
19626
19899
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
19627
19900
  return;
19628
19901
  }
19629
- const fullPath = path20.resolve(dir, path20.normalize(filePath));
19902
+ const fullPath = path21.resolve(dir, path21.normalize(filePath));
19630
19903
  if (!fullPath.startsWith(dir)) {
19631
19904
  this.json(res, 403, { error: "Forbidden" });
19632
19905
  return;
19633
19906
  }
19634
19907
  try {
19635
19908
  if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
19636
- fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
19909
+ fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
19637
19910
  fs14.writeFileSync(fullPath, content, "utf-8");
19638
19911
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
19639
19912
  this.providerLoader.reload();
@@ -19650,7 +19923,7 @@ var DevServer = class _DevServer {
19650
19923
  return;
19651
19924
  }
19652
19925
  for (const name of ["scripts.js", "provider.json"]) {
19653
- const p = path20.join(dir, name);
19926
+ const p = path21.join(dir, name);
19654
19927
  if (fs14.existsSync(p)) {
19655
19928
  const source = fs14.readFileSync(p, "utf-8");
19656
19929
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -19671,8 +19944,8 @@ var DevServer = class _DevServer {
19671
19944
  this.json(res, 404, { error: `Provider not found: ${type}` });
19672
19945
  return;
19673
19946
  }
19674
- const target = fs14.existsSync(path20.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
19675
- const targetPath = path20.join(dir, target);
19947
+ const target = fs14.existsSync(path21.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
19948
+ const targetPath = path21.join(dir, target);
19676
19949
  try {
19677
19950
  if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
19678
19951
  fs14.writeFileSync(targetPath, source, "utf-8");
@@ -19832,7 +20105,7 @@ var DevServer = class _DevServer {
19832
20105
  }
19833
20106
  let targetDir;
19834
20107
  targetDir = this.providerLoader.getUserProviderDir(category, type);
19835
- const jsonPath = path20.join(targetDir, "provider.json");
20108
+ const jsonPath = path21.join(targetDir, "provider.json");
19836
20109
  if (fs14.existsSync(jsonPath)) {
19837
20110
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
19838
20111
  return;
@@ -19844,8 +20117,8 @@ var DevServer = class _DevServer {
19844
20117
  const createdFiles = ["provider.json"];
19845
20118
  if (result.files) {
19846
20119
  for (const [relPath, content] of Object.entries(result.files)) {
19847
- const fullPath = path20.join(targetDir, relPath);
19848
- fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
20120
+ const fullPath = path21.join(targetDir, relPath);
20121
+ fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
19849
20122
  fs14.writeFileSync(fullPath, content, "utf-8");
19850
20123
  createdFiles.push(relPath);
19851
20124
  }
@@ -19898,22 +20171,22 @@ var DevServer = class _DevServer {
19898
20171
  if (!fs14.existsSync(scriptsDir)) return null;
19899
20172
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
19900
20173
  try {
19901
- return fs14.statSync(path20.join(scriptsDir, d)).isDirectory();
20174
+ return fs14.statSync(path21.join(scriptsDir, d)).isDirectory();
19902
20175
  } catch {
19903
20176
  return false;
19904
20177
  }
19905
20178
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
19906
20179
  if (versions.length === 0) return null;
19907
- return path20.join(scriptsDir, versions[0]);
20180
+ return path21.join(scriptsDir, versions[0]);
19908
20181
  }
19909
20182
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
19910
- const canonicalUserDir = path20.resolve(this.providerLoader.getUserProviderDir(category, type));
19911
- const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
19912
- const upstreamRoot = path20.resolve(this.providerLoader.getUpstreamDir());
19913
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
20183
+ const canonicalUserDir = path21.resolve(this.providerLoader.getUserProviderDir(category, type));
20184
+ const desiredDir = requestedDir ? path21.resolve(requestedDir) : canonicalUserDir;
20185
+ const upstreamRoot = path21.resolve(this.providerLoader.getUpstreamDir());
20186
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path21.sep}`)) {
19914
20187
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
19915
20188
  }
19916
- if (path20.basename(desiredDir) !== type) {
20189
+ if (path21.basename(desiredDir) !== type) {
19917
20190
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
19918
20191
  }
19919
20192
  const sourceDir = this.findProviderDir(type);
@@ -19921,11 +20194,11 @@ var DevServer = class _DevServer {
19921
20194
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
19922
20195
  }
19923
20196
  if (!fs14.existsSync(desiredDir)) {
19924
- fs14.mkdirSync(path20.dirname(desiredDir), { recursive: true });
20197
+ fs14.mkdirSync(path21.dirname(desiredDir), { recursive: true });
19925
20198
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
19926
20199
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
19927
20200
  }
19928
- const providerJson = path20.join(desiredDir, "provider.json");
20201
+ const providerJson = path21.join(desiredDir, "provider.json");
19929
20202
  if (!fs14.existsSync(providerJson)) {
19930
20203
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
19931
20204
  }
@@ -19973,7 +20246,7 @@ var DevServer = class _DevServer {
19973
20246
  setMode: "set_mode.js"
19974
20247
  };
19975
20248
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
19976
- const scriptsDir = path20.join(providerDir, "scripts");
20249
+ const scriptsDir = path21.join(providerDir, "scripts");
19977
20250
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
19978
20251
  if (latestScriptsDir) {
19979
20252
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -19984,7 +20257,7 @@ var DevServer = class _DevServer {
19984
20257
  for (const file of fs14.readdirSync(latestScriptsDir)) {
19985
20258
  if (file.endsWith(".js") && targetFileNames.has(file)) {
19986
20259
  try {
19987
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20260
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
19988
20261
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
19989
20262
  lines.push("```javascript");
19990
20263
  lines.push(content);
@@ -20001,7 +20274,7 @@ var DevServer = class _DevServer {
20001
20274
  lines.push("");
20002
20275
  for (const file of refFiles) {
20003
20276
  try {
20004
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20277
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20005
20278
  lines.push(`### \`${file}\` \u{1F512}`);
20006
20279
  lines.push("```javascript");
20007
20280
  lines.push(content);
@@ -20042,10 +20315,10 @@ var DevServer = class _DevServer {
20042
20315
  lines.push("");
20043
20316
  }
20044
20317
  }
20045
- const docsDir = path20.join(providerDir, "../../docs");
20318
+ const docsDir = path21.join(providerDir, "../../docs");
20046
20319
  const loadGuide = (name) => {
20047
20320
  try {
20048
- const p = path20.join(docsDir, name);
20321
+ const p = path21.join(docsDir, name);
20049
20322
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
20050
20323
  } catch {
20051
20324
  }
@@ -20219,7 +20492,7 @@ var DevServer = class _DevServer {
20219
20492
  parseApproval: "parse_approval.js"
20220
20493
  };
20221
20494
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
20222
- const scriptsDir = path20.join(providerDir, "scripts");
20495
+ const scriptsDir = path21.join(providerDir, "scripts");
20223
20496
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
20224
20497
  if (latestScriptsDir) {
20225
20498
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -20231,7 +20504,7 @@ var DevServer = class _DevServer {
20231
20504
  if (!file.endsWith(".js")) continue;
20232
20505
  if (!targetFileNames.has(file)) continue;
20233
20506
  try {
20234
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20507
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20235
20508
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
20236
20509
  lines.push("```javascript");
20237
20510
  lines.push(content);
@@ -20247,7 +20520,7 @@ var DevServer = class _DevServer {
20247
20520
  lines.push("");
20248
20521
  for (const file of refFiles) {
20249
20522
  try {
20250
- const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20523
+ const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
20251
20524
  lines.push(`### \`${file}\` \u{1F512}`);
20252
20525
  lines.push("```javascript");
20253
20526
  lines.push(content);
@@ -20280,10 +20553,10 @@ var DevServer = class _DevServer {
20280
20553
  lines.push("");
20281
20554
  }
20282
20555
  }
20283
- const docsDir = path20.join(providerDir, "../../docs");
20556
+ const docsDir = path21.join(providerDir, "../../docs");
20284
20557
  const loadGuide = (name) => {
20285
20558
  try {
20286
- const p = path20.join(docsDir, name);
20559
+ const p = path21.join(docsDir, name);
20287
20560
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
20288
20561
  } catch {
20289
20562
  }