@adhdev/daemon-core 0.8.25 → 0.8.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-stream/provider-adapter.d.ts +1 -0
- package/dist/boot/daemon-lifecycle.d.ts +2 -0
- package/dist/cli-adapters/pty-transport.d.ts +3 -0
- package/dist/commands/handler.d.ts +1 -0
- package/dist/commands/router.d.ts +24 -0
- package/dist/commands/stream-commands.d.ts +1 -1
- package/dist/detection/cli-detector.d.ts +6 -2
- package/dist/detection/ide-detector.d.ts +2 -1
- package/dist/index.js +824 -369
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +822 -367
- package/dist/index.mjs.map +1 -1
- package/dist/providers/acp-provider-instance.d.ts +1 -1
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/dist/providers/extension-provider-instance.d.ts +7 -0
- package/dist/providers/provider-loader.d.ts +26 -0
- package/dist/shared-types.d.ts +2 -0
- package/dist/status/normalize.js +14 -2
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +14 -2
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/snapshot.d.ts +8 -2
- package/node_modules/@adhdev/session-host-core/dist/index.d.mts +72 -1
- package/node_modules/@adhdev/session-host-core/dist/index.d.ts +72 -1
- package/node_modules/@adhdev/session-host-core/dist/index.js.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/agent-stream/provider-adapter.ts +45 -3
- package/src/boot/daemon-lifecycle.ts +31 -1
- package/src/cli-adapters/provider-cli-adapter.ts +14 -3
- package/src/cli-adapters/pty-transport.ts +3 -0
- package/src/cli-adapters/session-host-transport.ts +8 -0
- package/src/commands/chat-commands.ts +38 -9
- package/src/commands/cli-manager.ts +2 -2
- package/src/commands/handler.ts +26 -3
- package/src/commands/router.ts +144 -1
- package/src/commands/stream-commands.ts +6 -3
- package/src/detection/cli-detector.ts +72 -29
- package/src/detection/ide-detector.ts +24 -8
- package/src/launch.ts +1 -1
- package/src/providers/acp-provider-instance.ts +19 -10
- package/src/providers/cli-provider-instance.ts +29 -1
- package/src/providers/extension-provider-instance.ts +24 -1
- package/src/providers/provider-loader.ts +144 -11
- package/src/shared-types.ts +2 -0
- package/src/status/normalize.ts +19 -2
- package/src/status/snapshot.ts +25 -14
package/dist/index.mjs
CHANGED
|
@@ -233,7 +233,7 @@ var init_config = __esm({
|
|
|
233
233
|
|
|
234
234
|
// src/logging/logger.ts
|
|
235
235
|
import * as fs2 from "fs";
|
|
236
|
-
import * as
|
|
236
|
+
import * as path6 from "path";
|
|
237
237
|
import * as os4 from "os";
|
|
238
238
|
function setLogLevel(level) {
|
|
239
239
|
currentLevel = level;
|
|
@@ -249,13 +249,13 @@ function getDaemonLogDir() {
|
|
|
249
249
|
return LOG_DIR;
|
|
250
250
|
}
|
|
251
251
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
252
|
-
return
|
|
252
|
+
return path6.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
253
253
|
}
|
|
254
254
|
function checkDateRotation() {
|
|
255
255
|
const today = getDateStr();
|
|
256
256
|
if (today !== currentDate) {
|
|
257
257
|
currentDate = today;
|
|
258
|
-
currentLogFile =
|
|
258
|
+
currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
259
259
|
cleanOldLogs();
|
|
260
260
|
}
|
|
261
261
|
}
|
|
@@ -269,7 +269,7 @@ function cleanOldLogs() {
|
|
|
269
269
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
270
270
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
271
271
|
try {
|
|
272
|
-
fs2.unlinkSync(
|
|
272
|
+
fs2.unlinkSync(path6.join(LOG_DIR, file));
|
|
273
273
|
} catch {
|
|
274
274
|
}
|
|
275
275
|
}
|
|
@@ -393,7 +393,7 @@ var init_logger = __esm({
|
|
|
393
393
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
394
394
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
395
395
|
currentLevel = "info";
|
|
396
|
-
LOG_DIR = process.platform === "win32" ?
|
|
396
|
+
LOG_DIR = process.platform === "win32" ? path6.join(process.env.LOCALAPPDATA || process.env.APPDATA || path6.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path6.join(os4.homedir(), "Library", "Logs", "adhdev") : path6.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
397
397
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
398
398
|
MAX_LOG_DAYS = 7;
|
|
399
399
|
try {
|
|
@@ -401,16 +401,16 @@ var init_logger = __esm({
|
|
|
401
401
|
} catch {
|
|
402
402
|
}
|
|
403
403
|
currentDate = getDateStr();
|
|
404
|
-
currentLogFile =
|
|
404
|
+
currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
405
405
|
cleanOldLogs();
|
|
406
406
|
try {
|
|
407
|
-
const oldLog =
|
|
407
|
+
const oldLog = path6.join(LOG_DIR, "daemon.log");
|
|
408
408
|
if (fs2.existsSync(oldLog)) {
|
|
409
409
|
const stat = fs2.statSync(oldLog);
|
|
410
410
|
const oldDate = stat.mtime.toISOString().slice(0, 10);
|
|
411
|
-
fs2.renameSync(oldLog,
|
|
411
|
+
fs2.renameSync(oldLog, path6.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
412
412
|
}
|
|
413
|
-
const oldLogBackup =
|
|
413
|
+
const oldLogBackup = path6.join(LOG_DIR, "daemon.log.old");
|
|
414
414
|
if (fs2.existsSync(oldLogBackup)) {
|
|
415
415
|
fs2.unlinkSync(oldLogBackup);
|
|
416
416
|
}
|
|
@@ -442,7 +442,7 @@ var init_logger = __esm({
|
|
|
442
442
|
}
|
|
443
443
|
};
|
|
444
444
|
interceptorInstalled = false;
|
|
445
|
-
LOG_PATH =
|
|
445
|
+
LOG_PATH = path6.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
446
446
|
}
|
|
447
447
|
});
|
|
448
448
|
|
|
@@ -802,7 +802,7 @@ __export(provider_cli_adapter_exports, {
|
|
|
802
802
|
normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
|
|
803
803
|
});
|
|
804
804
|
import * as os8 from "os";
|
|
805
|
-
import * as
|
|
805
|
+
import * as path9 from "path";
|
|
806
806
|
import { execSync as execSync3 } from "child_process";
|
|
807
807
|
function stripAnsi(str) {
|
|
808
808
|
return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
|
|
@@ -873,16 +873,22 @@ function computeTerminalQueryTail(buffer) {
|
|
|
873
873
|
return "";
|
|
874
874
|
}
|
|
875
875
|
function findBinary(name) {
|
|
876
|
+
const trimmed = String(name || "").trim();
|
|
877
|
+
if (!trimmed) return trimmed;
|
|
878
|
+
const expanded = trimmed.startsWith("~") ? path9.join(os8.homedir(), trimmed.slice(1)) : trimmed;
|
|
879
|
+
if (path9.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
880
|
+
return path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
881
|
+
}
|
|
876
882
|
const isWin = os8.platform() === "win32";
|
|
877
883
|
try {
|
|
878
|
-
const cmd = isWin ? `where ${
|
|
884
|
+
const cmd = isWin ? `where ${trimmed}` : `which ${trimmed}`;
|
|
879
885
|
return execSync3(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
|
|
880
886
|
} catch {
|
|
881
|
-
return isWin ? `${
|
|
887
|
+
return isWin ? `${trimmed}.cmd` : trimmed;
|
|
882
888
|
}
|
|
883
889
|
}
|
|
884
890
|
function isScriptBinary(binaryPath) {
|
|
885
|
-
if (!
|
|
891
|
+
if (!path9.isAbsolute(binaryPath)) return false;
|
|
886
892
|
try {
|
|
887
893
|
const fs15 = __require("fs");
|
|
888
894
|
const resolved = fs15.realpathSync(binaryPath);
|
|
@@ -898,7 +904,7 @@ function isScriptBinary(binaryPath) {
|
|
|
898
904
|
}
|
|
899
905
|
}
|
|
900
906
|
function looksLikeMachOOrElf(filePath) {
|
|
901
|
-
if (!
|
|
907
|
+
if (!path9.isAbsolute(filePath)) return false;
|
|
902
908
|
try {
|
|
903
909
|
const fs15 = __require("fs");
|
|
904
910
|
const resolved = fs15.realpathSync(filePath);
|
|
@@ -1379,16 +1385,17 @@ var init_provider_cli_adapter = __esm({
|
|
|
1379
1385
|
async spawn() {
|
|
1380
1386
|
if (this.ptyProcess) return;
|
|
1381
1387
|
const { spawn: spawnConfig } = this.provider;
|
|
1382
|
-
const
|
|
1388
|
+
const configuredCommand = typeof this.runtimeSettings.executablePath === "string" && this.runtimeSettings.executablePath.trim() ? this.runtimeSettings.executablePath.trim() : spawnConfig.command;
|
|
1389
|
+
const binaryPath = findBinary(configuredCommand);
|
|
1383
1390
|
const isWin = os8.platform() === "win32";
|
|
1384
1391
|
const allArgs = [...spawnConfig.args, ...this.extraArgs];
|
|
1385
1392
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1386
1393
|
this.resetTraceSession();
|
|
1387
1394
|
let shellCmd;
|
|
1388
1395
|
let shellArgs;
|
|
1389
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1396
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1390
1397
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1391
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1398
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1392
1399
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1393
1400
|
if (useShell) {
|
|
1394
1401
|
if (!spawnConfig.shell && !isWin) {
|
|
@@ -1762,7 +1769,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
1762
1769
|
`[${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)}`
|
|
1763
1770
|
);
|
|
1764
1771
|
}
|
|
1765
|
-
await new Promise((
|
|
1772
|
+
await new Promise((resolve12) => setTimeout(resolve12, 50));
|
|
1766
1773
|
}
|
|
1767
1774
|
const finalScreenText = this.terminalScreen.getText() || "";
|
|
1768
1775
|
LOG.warn(
|
|
@@ -2273,7 +2280,7 @@ ${data.message || ""}`.trim();
|
|
|
2273
2280
|
const deadline = Date.now() + 1e4;
|
|
2274
2281
|
while (this.startupParseGate && Date.now() < deadline) {
|
|
2275
2282
|
this.resolveStartupState("send_wait");
|
|
2276
|
-
await new Promise((
|
|
2283
|
+
await new Promise((resolve12) => setTimeout(resolve12, 50));
|
|
2277
2284
|
}
|
|
2278
2285
|
}
|
|
2279
2286
|
await this.waitForInteractivePrompt();
|
|
@@ -2498,17 +2505,17 @@ ${data.message || ""}`.trim();
|
|
|
2498
2505
|
}
|
|
2499
2506
|
}
|
|
2500
2507
|
waitForStopped(timeoutMs) {
|
|
2501
|
-
return new Promise((
|
|
2508
|
+
return new Promise((resolve12) => {
|
|
2502
2509
|
const startedAt = Date.now();
|
|
2503
2510
|
const timer = setInterval(() => {
|
|
2504
2511
|
if (!this.ptyProcess || this.currentStatus === "stopped") {
|
|
2505
2512
|
clearInterval(timer);
|
|
2506
|
-
|
|
2513
|
+
resolve12(true);
|
|
2507
2514
|
return;
|
|
2508
2515
|
}
|
|
2509
2516
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
2510
2517
|
clearInterval(timer);
|
|
2511
|
-
|
|
2518
|
+
resolve12(false);
|
|
2512
2519
|
}
|
|
2513
2520
|
}, 100);
|
|
2514
2521
|
});
|
|
@@ -3124,6 +3131,7 @@ function resetState() {
|
|
|
3124
3131
|
import { execSync } from "child_process";
|
|
3125
3132
|
import { existsSync as existsSync4 } from "fs";
|
|
3126
3133
|
import { platform, homedir as homedir3 } from "os";
|
|
3134
|
+
import * as path4 from "path";
|
|
3127
3135
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
3128
3136
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
3129
3137
|
function registerIDEDefinition(def) {
|
|
@@ -3140,9 +3148,16 @@ function getMergedDefinitions() {
|
|
|
3140
3148
|
return [...merged.values()];
|
|
3141
3149
|
}
|
|
3142
3150
|
function findCliCommand(command) {
|
|
3151
|
+
const trimmed = String(command || "").trim();
|
|
3152
|
+
if (!trimmed) return null;
|
|
3153
|
+
if (path4.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
3154
|
+
const candidate = trimmed.startsWith("~") ? path4.join(homedir3(), trimmed.slice(1)) : trimmed;
|
|
3155
|
+
const resolved = path4.isAbsolute(candidate) ? candidate : path4.resolve(candidate);
|
|
3156
|
+
return existsSync4(resolved) ? resolved : null;
|
|
3157
|
+
}
|
|
3143
3158
|
try {
|
|
3144
3159
|
const result = execSync(
|
|
3145
|
-
platform() === "win32" ? `where ${
|
|
3160
|
+
platform() === "win32" ? `where ${trimmed}` : `which ${trimmed}`,
|
|
3146
3161
|
{ encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }
|
|
3147
3162
|
).trim();
|
|
3148
3163
|
return result.split("\n")[0] || null;
|
|
@@ -3165,23 +3180,23 @@ function getIdeVersion(cliCommand) {
|
|
|
3165
3180
|
function checkPathExists(paths) {
|
|
3166
3181
|
const home = homedir3();
|
|
3167
3182
|
for (const p of paths) {
|
|
3168
|
-
|
|
3183
|
+
const normalized = p.startsWith("~") ? path4.join(home, p.slice(1)) : p;
|
|
3184
|
+
if (normalized.includes("*")) {
|
|
3169
3185
|
const username = home.split(/[\\/]/).pop() || "";
|
|
3170
|
-
const resolved =
|
|
3186
|
+
const resolved = normalized.replace("*", username);
|
|
3171
3187
|
if (existsSync4(resolved)) return resolved;
|
|
3172
3188
|
} else {
|
|
3173
|
-
if (existsSync4(
|
|
3189
|
+
if (existsSync4(normalized)) return normalized;
|
|
3174
3190
|
}
|
|
3175
3191
|
}
|
|
3176
3192
|
return null;
|
|
3177
3193
|
}
|
|
3178
|
-
async function detectIDEs() {
|
|
3194
|
+
async function detectIDEs(providerLoader) {
|
|
3179
3195
|
const os18 = platform();
|
|
3180
3196
|
const results = [];
|
|
3181
3197
|
for (const def of getMergedDefinitions()) {
|
|
3182
|
-
const cliPath = findCliCommand(def.cli);
|
|
3183
|
-
const appPath = checkPathExists(def.paths[os18] || []);
|
|
3184
|
-
const installed = !!(cliPath || appPath);
|
|
3198
|
+
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
3199
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os18] || []) || []);
|
|
3185
3200
|
let resolvedCli = cliPath;
|
|
3186
3201
|
if (!resolvedCli && appPath && os18 === "darwin") {
|
|
3187
3202
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
@@ -3204,6 +3219,7 @@ async function detectIDEs() {
|
|
|
3204
3219
|
}
|
|
3205
3220
|
}
|
|
3206
3221
|
}
|
|
3222
|
+
const installed = os18 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
3207
3223
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
3208
3224
|
results.push({
|
|
3209
3225
|
id: def.id,
|
|
@@ -3222,48 +3238,77 @@ async function detectIDEs() {
|
|
|
3222
3238
|
// src/detection/cli-detector.ts
|
|
3223
3239
|
import { exec } from "child_process";
|
|
3224
3240
|
import * as os2 from "os";
|
|
3241
|
+
import * as path5 from "path";
|
|
3242
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3225
3243
|
function parseVersion(raw) {
|
|
3226
3244
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
3227
3245
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
3228
3246
|
}
|
|
3247
|
+
function shellQuote(value) {
|
|
3248
|
+
if (/^[a-zA-Z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
3249
|
+
return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
3250
|
+
}
|
|
3251
|
+
function expandHome(value) {
|
|
3252
|
+
const trimmed = value.trim();
|
|
3253
|
+
if (!trimmed.startsWith("~")) return trimmed;
|
|
3254
|
+
return path5.join(os2.homedir(), trimmed.slice(1));
|
|
3255
|
+
}
|
|
3256
|
+
function isExplicitCommandPath(command) {
|
|
3257
|
+
const trimmed = command.trim();
|
|
3258
|
+
return path5.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
3259
|
+
}
|
|
3260
|
+
function resolveCommandPath(command) {
|
|
3261
|
+
const trimmed = command.trim();
|
|
3262
|
+
if (!trimmed) return null;
|
|
3263
|
+
if (isExplicitCommandPath(trimmed)) {
|
|
3264
|
+
const expanded = expandHome(trimmed);
|
|
3265
|
+
const candidate = path5.isAbsolute(expanded) ? expanded : path5.resolve(expanded);
|
|
3266
|
+
return existsSync5(candidate) ? candidate : null;
|
|
3267
|
+
}
|
|
3268
|
+
return null;
|
|
3269
|
+
}
|
|
3229
3270
|
function execAsync(cmd, timeoutMs = 5e3) {
|
|
3230
|
-
return new Promise((
|
|
3271
|
+
return new Promise((resolve12) => {
|
|
3231
3272
|
const child = exec(cmd, { encoding: "utf-8", timeout: timeoutMs }, (err, stdout) => {
|
|
3232
3273
|
if (err || !stdout?.trim()) {
|
|
3233
|
-
|
|
3274
|
+
resolve12(null);
|
|
3234
3275
|
} else {
|
|
3235
|
-
|
|
3276
|
+
resolve12(stdout.trim());
|
|
3236
3277
|
}
|
|
3237
3278
|
});
|
|
3238
|
-
child.on("error", () =>
|
|
3279
|
+
child.on("error", () => resolve12(null));
|
|
3239
3280
|
});
|
|
3240
3281
|
}
|
|
3241
|
-
async function detectCLIs(providerLoader) {
|
|
3282
|
+
async function detectCLIs(providerLoader, options) {
|
|
3242
3283
|
const platform9 = os2.platform();
|
|
3243
3284
|
const whichCmd = platform9 === "win32" ? "where" : "which";
|
|
3285
|
+
const includeVersion = options?.includeVersion !== false;
|
|
3244
3286
|
const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
|
|
3245
3287
|
const results = await Promise.all(
|
|
3246
3288
|
cliList.map(async (cli) => {
|
|
3247
3289
|
try {
|
|
3248
|
-
const
|
|
3290
|
+
const explicitPath = resolveCommandPath(cli.command);
|
|
3291
|
+
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(cli.command)}`);
|
|
3249
3292
|
if (!pathResult) return { ...cli, installed: false };
|
|
3250
|
-
const firstPath = pathResult.split("\n")[0];
|
|
3293
|
+
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
3251
3294
|
let version;
|
|
3252
|
-
|
|
3295
|
+
if (includeVersion) {
|
|
3253
3296
|
const versionCommands = [
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3297
|
+
`"${firstPath}" --version`,
|
|
3298
|
+
`"${firstPath}" -V`,
|
|
3299
|
+
`"${firstPath}" -v`,
|
|
3300
|
+
cli.versionCommand
|
|
3258
3301
|
].filter((v) => !!v);
|
|
3259
|
-
|
|
3260
|
-
const
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3302
|
+
try {
|
|
3303
|
+
for (const versionCommand of versionCommands) {
|
|
3304
|
+
const versionResult = await execAsync(versionCommand, 3e3);
|
|
3305
|
+
if (versionResult) {
|
|
3306
|
+
version = parseVersion(versionResult);
|
|
3307
|
+
break;
|
|
3308
|
+
}
|
|
3264
3309
|
}
|
|
3310
|
+
} catch {
|
|
3265
3311
|
}
|
|
3266
|
-
} catch {
|
|
3267
3312
|
}
|
|
3268
3313
|
return { ...cli, installed: true, version, path: firstPath };
|
|
3269
3314
|
} catch {
|
|
@@ -3273,7 +3318,7 @@ async function detectCLIs(providerLoader) {
|
|
|
3273
3318
|
);
|
|
3274
3319
|
return results;
|
|
3275
3320
|
}
|
|
3276
|
-
async function detectCLI(cliId, providerLoader) {
|
|
3321
|
+
async function detectCLI(cliId, providerLoader, options) {
|
|
3277
3322
|
const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
|
|
3278
3323
|
if (providerLoader) {
|
|
3279
3324
|
const cliList = providerLoader.getCliDetectionList();
|
|
@@ -3282,25 +3327,28 @@ async function detectCLI(cliId, providerLoader) {
|
|
|
3282
3327
|
const platform9 = os2.platform();
|
|
3283
3328
|
const whichCmd = platform9 === "win32" ? "where" : "which";
|
|
3284
3329
|
try {
|
|
3285
|
-
const
|
|
3330
|
+
const explicitPath = resolveCommandPath(target.command);
|
|
3331
|
+
const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
|
|
3286
3332
|
if (!pathResult) return null;
|
|
3287
|
-
const firstPath = pathResult.split("\n")[0];
|
|
3333
|
+
const firstPath = explicitPath || pathResult.split("\n")[0];
|
|
3288
3334
|
let version;
|
|
3289
|
-
|
|
3335
|
+
if (options?.includeVersion !== false) {
|
|
3290
3336
|
const versionCommands = [
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3337
|
+
`"${firstPath}" --version`,
|
|
3338
|
+
`"${firstPath}" -V`,
|
|
3339
|
+
`"${firstPath}" -v`,
|
|
3340
|
+
target.versionCommand
|
|
3295
3341
|
].filter((v) => !!v);
|
|
3296
|
-
|
|
3297
|
-
const
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3342
|
+
try {
|
|
3343
|
+
for (const versionCommand of versionCommands) {
|
|
3344
|
+
const versionResult = await execAsync(versionCommand, 3e3);
|
|
3345
|
+
if (versionResult) {
|
|
3346
|
+
version = parseVersion(versionResult);
|
|
3347
|
+
break;
|
|
3348
|
+
}
|
|
3301
3349
|
}
|
|
3350
|
+
} catch {
|
|
3302
3351
|
}
|
|
3303
|
-
} catch {
|
|
3304
3352
|
}
|
|
3305
3353
|
return { ...target, installed: true, version, path: firstPath };
|
|
3306
3354
|
} catch {
|
|
@@ -3308,7 +3356,7 @@ async function detectCLI(cliId, providerLoader) {
|
|
|
3308
3356
|
}
|
|
3309
3357
|
}
|
|
3310
3358
|
}
|
|
3311
|
-
const all = await detectCLIs(providerLoader);
|
|
3359
|
+
const all = await detectCLIs(providerLoader, options);
|
|
3312
3360
|
return all.find((c) => c.id === resolvedId && c.installed) || null;
|
|
3313
3361
|
}
|
|
3314
3362
|
|
|
@@ -3435,7 +3483,7 @@ var DaemonCdpManager = class {
|
|
|
3435
3483
|
* Returns multiple entries if multiple IDE windows are open on same port
|
|
3436
3484
|
*/
|
|
3437
3485
|
static listAllTargets(port) {
|
|
3438
|
-
return new Promise((
|
|
3486
|
+
return new Promise((resolve12) => {
|
|
3439
3487
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
3440
3488
|
let data = "";
|
|
3441
3489
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -3451,16 +3499,16 @@ var DaemonCdpManager = class {
|
|
|
3451
3499
|
(t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
|
|
3452
3500
|
);
|
|
3453
3501
|
const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
|
|
3454
|
-
|
|
3502
|
+
resolve12(mainPages.length > 0 ? mainPages : fallbackPages);
|
|
3455
3503
|
} catch {
|
|
3456
|
-
|
|
3504
|
+
resolve12([]);
|
|
3457
3505
|
}
|
|
3458
3506
|
});
|
|
3459
3507
|
});
|
|
3460
|
-
req.on("error", () =>
|
|
3508
|
+
req.on("error", () => resolve12([]));
|
|
3461
3509
|
req.setTimeout(2e3, () => {
|
|
3462
3510
|
req.destroy();
|
|
3463
|
-
|
|
3511
|
+
resolve12([]);
|
|
3464
3512
|
});
|
|
3465
3513
|
});
|
|
3466
3514
|
}
|
|
@@ -3500,7 +3548,7 @@ var DaemonCdpManager = class {
|
|
|
3500
3548
|
}
|
|
3501
3549
|
}
|
|
3502
3550
|
findTargetOnPort(port) {
|
|
3503
|
-
return new Promise((
|
|
3551
|
+
return new Promise((resolve12) => {
|
|
3504
3552
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
3505
3553
|
let data = "";
|
|
3506
3554
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -3511,7 +3559,7 @@ var DaemonCdpManager = class {
|
|
|
3511
3559
|
(t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
|
|
3512
3560
|
);
|
|
3513
3561
|
if (pages.length === 0) {
|
|
3514
|
-
|
|
3562
|
+
resolve12(targets.find((t) => t.webSocketDebuggerUrl) || null);
|
|
3515
3563
|
return;
|
|
3516
3564
|
}
|
|
3517
3565
|
const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
|
|
@@ -3521,24 +3569,24 @@ var DaemonCdpManager = class {
|
|
|
3521
3569
|
const specific = list.find((t) => t.id === this._targetId);
|
|
3522
3570
|
if (specific) {
|
|
3523
3571
|
this._pageTitle = specific.title || "";
|
|
3524
|
-
|
|
3572
|
+
resolve12(specific);
|
|
3525
3573
|
} else {
|
|
3526
3574
|
this.log(`[CDP] Target ${this._targetId} not found in page list`);
|
|
3527
|
-
|
|
3575
|
+
resolve12(null);
|
|
3528
3576
|
}
|
|
3529
3577
|
return;
|
|
3530
3578
|
}
|
|
3531
3579
|
this._pageTitle = list[0]?.title || "";
|
|
3532
|
-
|
|
3580
|
+
resolve12(list[0]);
|
|
3533
3581
|
} catch {
|
|
3534
|
-
|
|
3582
|
+
resolve12(null);
|
|
3535
3583
|
}
|
|
3536
3584
|
});
|
|
3537
3585
|
});
|
|
3538
|
-
req.on("error", () =>
|
|
3586
|
+
req.on("error", () => resolve12(null));
|
|
3539
3587
|
req.setTimeout(2e3, () => {
|
|
3540
3588
|
req.destroy();
|
|
3541
|
-
|
|
3589
|
+
resolve12(null);
|
|
3542
3590
|
});
|
|
3543
3591
|
});
|
|
3544
3592
|
}
|
|
@@ -3549,7 +3597,7 @@ var DaemonCdpManager = class {
|
|
|
3549
3597
|
this.extensionProviders = providers;
|
|
3550
3598
|
}
|
|
3551
3599
|
connectToTarget(wsUrl) {
|
|
3552
|
-
return new Promise((
|
|
3600
|
+
return new Promise((resolve12) => {
|
|
3553
3601
|
this.ws = new WebSocket(wsUrl);
|
|
3554
3602
|
this.ws.on("open", async () => {
|
|
3555
3603
|
this._connected = true;
|
|
@@ -3559,17 +3607,17 @@ var DaemonCdpManager = class {
|
|
|
3559
3607
|
}
|
|
3560
3608
|
this.connectBrowserWs().catch(() => {
|
|
3561
3609
|
});
|
|
3562
|
-
|
|
3610
|
+
resolve12(true);
|
|
3563
3611
|
});
|
|
3564
3612
|
this.ws.on("message", (data) => {
|
|
3565
3613
|
try {
|
|
3566
3614
|
const msg = JSON.parse(data.toString());
|
|
3567
3615
|
if (msg.id && this.pending.has(msg.id)) {
|
|
3568
|
-
const { resolve:
|
|
3616
|
+
const { resolve: resolve13, reject } = this.pending.get(msg.id);
|
|
3569
3617
|
this.pending.delete(msg.id);
|
|
3570
3618
|
this.failureCount = 0;
|
|
3571
3619
|
if (msg.error) reject(new Error(msg.error.message));
|
|
3572
|
-
else
|
|
3620
|
+
else resolve13(msg.result);
|
|
3573
3621
|
} else if (msg.method === "Runtime.executionContextCreated") {
|
|
3574
3622
|
this.contexts.add(msg.params.context.id);
|
|
3575
3623
|
} else if (msg.method === "Runtime.executionContextDestroyed") {
|
|
@@ -3592,7 +3640,7 @@ var DaemonCdpManager = class {
|
|
|
3592
3640
|
this.ws.on("error", (err) => {
|
|
3593
3641
|
this.log(`[CDP] WebSocket error: ${err.message}`);
|
|
3594
3642
|
this._connected = false;
|
|
3595
|
-
|
|
3643
|
+
resolve12(false);
|
|
3596
3644
|
});
|
|
3597
3645
|
});
|
|
3598
3646
|
}
|
|
@@ -3606,7 +3654,7 @@ var DaemonCdpManager = class {
|
|
|
3606
3654
|
return;
|
|
3607
3655
|
}
|
|
3608
3656
|
this.log(`[CDP] Connecting browser WS for target discovery...`);
|
|
3609
|
-
await new Promise((
|
|
3657
|
+
await new Promise((resolve12, reject) => {
|
|
3610
3658
|
this.browserWs = new WebSocket(browserWsUrl);
|
|
3611
3659
|
this.browserWs.on("open", async () => {
|
|
3612
3660
|
this._browserConnected = true;
|
|
@@ -3616,16 +3664,16 @@ var DaemonCdpManager = class {
|
|
|
3616
3664
|
} catch (e) {
|
|
3617
3665
|
this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
|
|
3618
3666
|
}
|
|
3619
|
-
|
|
3667
|
+
resolve12();
|
|
3620
3668
|
});
|
|
3621
3669
|
this.browserWs.on("message", (data) => {
|
|
3622
3670
|
try {
|
|
3623
3671
|
const msg = JSON.parse(data.toString());
|
|
3624
3672
|
if (msg.id && this.browserPending.has(msg.id)) {
|
|
3625
|
-
const { resolve:
|
|
3673
|
+
const { resolve: resolve13, reject: reject2 } = this.browserPending.get(msg.id);
|
|
3626
3674
|
this.browserPending.delete(msg.id);
|
|
3627
3675
|
if (msg.error) reject2(new Error(msg.error.message));
|
|
3628
|
-
else
|
|
3676
|
+
else resolve13(msg.result);
|
|
3629
3677
|
}
|
|
3630
3678
|
} catch {
|
|
3631
3679
|
}
|
|
@@ -3645,31 +3693,31 @@ var DaemonCdpManager = class {
|
|
|
3645
3693
|
}
|
|
3646
3694
|
}
|
|
3647
3695
|
getBrowserWsUrl() {
|
|
3648
|
-
return new Promise((
|
|
3696
|
+
return new Promise((resolve12) => {
|
|
3649
3697
|
const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
|
|
3650
3698
|
let data = "";
|
|
3651
3699
|
res.on("data", (chunk) => data += chunk.toString());
|
|
3652
3700
|
res.on("end", () => {
|
|
3653
3701
|
try {
|
|
3654
3702
|
const info = JSON.parse(data);
|
|
3655
|
-
|
|
3703
|
+
resolve12(info.webSocketDebuggerUrl || null);
|
|
3656
3704
|
} catch {
|
|
3657
|
-
|
|
3705
|
+
resolve12(null);
|
|
3658
3706
|
}
|
|
3659
3707
|
});
|
|
3660
3708
|
});
|
|
3661
|
-
req.on("error", () =>
|
|
3709
|
+
req.on("error", () => resolve12(null));
|
|
3662
3710
|
req.setTimeout(3e3, () => {
|
|
3663
3711
|
req.destroy();
|
|
3664
|
-
|
|
3712
|
+
resolve12(null);
|
|
3665
3713
|
});
|
|
3666
3714
|
});
|
|
3667
3715
|
}
|
|
3668
3716
|
sendBrowser(method, params = {}, timeoutMs = 15e3) {
|
|
3669
|
-
return new Promise((
|
|
3717
|
+
return new Promise((resolve12, reject) => {
|
|
3670
3718
|
if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
|
|
3671
3719
|
const id = this.browserMsgId++;
|
|
3672
|
-
this.browserPending.set(id, { resolve:
|
|
3720
|
+
this.browserPending.set(id, { resolve: resolve12, reject });
|
|
3673
3721
|
this.browserWs.send(JSON.stringify({ id, method, params }));
|
|
3674
3722
|
setTimeout(() => {
|
|
3675
3723
|
if (this.browserPending.has(id)) {
|
|
@@ -3709,11 +3757,11 @@ var DaemonCdpManager = class {
|
|
|
3709
3757
|
}
|
|
3710
3758
|
// ─── CDP Protocol ────────────────────────────────────────
|
|
3711
3759
|
sendInternal(method, params = {}, timeoutMs = 15e3) {
|
|
3712
|
-
return new Promise((
|
|
3760
|
+
return new Promise((resolve12, reject) => {
|
|
3713
3761
|
if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
|
|
3714
3762
|
if (this.ws.readyState !== WebSocket.OPEN) return reject(new Error("WebSocket not open"));
|
|
3715
3763
|
const id = this.msgId++;
|
|
3716
|
-
this.pending.set(id, { resolve:
|
|
3764
|
+
this.pending.set(id, { resolve: resolve12, reject });
|
|
3717
3765
|
this.ws.send(JSON.stringify({ id, method, params }));
|
|
3718
3766
|
setTimeout(() => {
|
|
3719
3767
|
if (this.pending.has(id)) {
|
|
@@ -3962,7 +4010,7 @@ var DaemonCdpManager = class {
|
|
|
3962
4010
|
const browserWs = this.browserWs;
|
|
3963
4011
|
let msgId = this.browserMsgId;
|
|
3964
4012
|
const sendWs = (method, params = {}, sessionId) => {
|
|
3965
|
-
return new Promise((
|
|
4013
|
+
return new Promise((resolve12, reject) => {
|
|
3966
4014
|
const mid = msgId++;
|
|
3967
4015
|
this.browserMsgId = msgId;
|
|
3968
4016
|
const handler = (raw) => {
|
|
@@ -3971,7 +4019,7 @@ var DaemonCdpManager = class {
|
|
|
3971
4019
|
if (msg.id === mid) {
|
|
3972
4020
|
browserWs.removeListener("message", handler);
|
|
3973
4021
|
if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
|
|
3974
|
-
else
|
|
4022
|
+
else resolve12(msg.result);
|
|
3975
4023
|
}
|
|
3976
4024
|
} catch {
|
|
3977
4025
|
}
|
|
@@ -4162,14 +4210,14 @@ var DaemonCdpManager = class {
|
|
|
4162
4210
|
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
4163
4211
|
throw new Error("CDP not connected");
|
|
4164
4212
|
}
|
|
4165
|
-
return new Promise((
|
|
4213
|
+
return new Promise((resolve12, reject) => {
|
|
4166
4214
|
const id = getNextId();
|
|
4167
4215
|
pendingMap.set(id, {
|
|
4168
4216
|
resolve: (result) => {
|
|
4169
4217
|
if (result?.result?.subtype === "error") {
|
|
4170
4218
|
reject(new Error(result.result.description));
|
|
4171
4219
|
} else {
|
|
4172
|
-
|
|
4220
|
+
resolve12(result?.result?.value);
|
|
4173
4221
|
}
|
|
4174
4222
|
},
|
|
4175
4223
|
reject
|
|
@@ -4201,10 +4249,10 @@ var DaemonCdpManager = class {
|
|
|
4201
4249
|
throw new Error("CDP not connected");
|
|
4202
4250
|
}
|
|
4203
4251
|
const sendViaSession = (method, params = {}) => {
|
|
4204
|
-
return new Promise((
|
|
4252
|
+
return new Promise((resolve12, reject) => {
|
|
4205
4253
|
const pendingMap = this._browserConnected ? this.browserPending : this.pending;
|
|
4206
4254
|
const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
|
|
4207
|
-
pendingMap.set(id, { resolve:
|
|
4255
|
+
pendingMap.set(id, { resolve: resolve12, reject });
|
|
4208
4256
|
ws.send(JSON.stringify({ id, sessionId, method, params }));
|
|
4209
4257
|
setTimeout(() => {
|
|
4210
4258
|
if (pendingMap.has(id)) {
|
|
@@ -4832,9 +4880,9 @@ function normalizeControlValue(value) {
|
|
|
4832
4880
|
|
|
4833
4881
|
// src/config/chat-history.ts
|
|
4834
4882
|
import * as fs3 from "fs";
|
|
4835
|
-
import * as
|
|
4883
|
+
import * as path7 from "path";
|
|
4836
4884
|
import * as os5 from "os";
|
|
4837
|
-
var HISTORY_DIR =
|
|
4885
|
+
var HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
|
|
4838
4886
|
var RETAIN_DAYS = 30;
|
|
4839
4887
|
var ChatHistoryWriter = class {
|
|
4840
4888
|
/** Last seen message count per agent (deduplication) */
|
|
@@ -4879,11 +4927,11 @@ var ChatHistoryWriter = class {
|
|
|
4879
4927
|
});
|
|
4880
4928
|
}
|
|
4881
4929
|
if (newMessages.length === 0) return;
|
|
4882
|
-
const dir =
|
|
4930
|
+
const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
|
|
4883
4931
|
fs3.mkdirSync(dir, { recursive: true });
|
|
4884
4932
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4885
4933
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
4886
|
-
const filePath =
|
|
4934
|
+
const filePath = path7.join(dir, `${filePrefix}${date}.jsonl`);
|
|
4887
4935
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
4888
4936
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
4889
4937
|
const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
|
|
@@ -4937,14 +4985,14 @@ var ChatHistoryWriter = class {
|
|
|
4937
4985
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
4938
4986
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
4939
4987
|
}
|
|
4940
|
-
const dir =
|
|
4988
|
+
const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
|
|
4941
4989
|
if (!fs3.existsSync(dir)) return;
|
|
4942
4990
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
4943
4991
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
4944
4992
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
4945
4993
|
for (const file of files) {
|
|
4946
|
-
const sourcePath =
|
|
4947
|
-
const targetPath =
|
|
4994
|
+
const sourcePath = path7.join(dir, file);
|
|
4995
|
+
const targetPath = path7.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
4948
4996
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
4949
4997
|
const rewritten = sourceLines.map((line) => {
|
|
4950
4998
|
try {
|
|
@@ -4985,10 +5033,10 @@ var ChatHistoryWriter = class {
|
|
|
4985
5033
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
4986
5034
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
4987
5035
|
for (const dir of agentDirs) {
|
|
4988
|
-
const dirPath =
|
|
5036
|
+
const dirPath = path7.join(HISTORY_DIR, dir.name);
|
|
4989
5037
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
4990
5038
|
for (const file of files) {
|
|
4991
|
-
const filePath =
|
|
5039
|
+
const filePath = path7.join(dirPath, file);
|
|
4992
5040
|
const stat = fs3.statSync(filePath);
|
|
4993
5041
|
if (stat.mtimeMs < cutoff) {
|
|
4994
5042
|
fs3.unlinkSync(filePath);
|
|
@@ -5006,7 +5054,7 @@ var ChatHistoryWriter = class {
|
|
|
5006
5054
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId) {
|
|
5007
5055
|
try {
|
|
5008
5056
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5009
|
-
const dir =
|
|
5057
|
+
const dir = path7.join(HISTORY_DIR, sanitized);
|
|
5010
5058
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
5011
5059
|
const sanitizedInstance = historySessionId?.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5012
5060
|
const files = fs3.readdirSync(dir).filter((f) => {
|
|
@@ -5020,7 +5068,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId) {
|
|
|
5020
5068
|
const needed = offset + limit + 1;
|
|
5021
5069
|
for (const file of files) {
|
|
5022
5070
|
if (allMessages.length >= needed) break;
|
|
5023
|
-
const filePath =
|
|
5071
|
+
const filePath = path7.join(dir, file);
|
|
5024
5072
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
5025
5073
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
5026
5074
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -5042,7 +5090,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId) {
|
|
|
5042
5090
|
function listSavedHistorySessions(agentType, options = {}) {
|
|
5043
5091
|
try {
|
|
5044
5092
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5045
|
-
const dir =
|
|
5093
|
+
const dir = path7.join(HISTORY_DIR, sanitized);
|
|
5046
5094
|
if (!fs3.existsSync(dir)) return { sessions: [], hasMore: false };
|
|
5047
5095
|
const groupedFiles = /* @__PURE__ */ new Map();
|
|
5048
5096
|
const filePattern = /^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/;
|
|
@@ -5063,7 +5111,7 @@ function listSavedHistorySessions(agentType, options = {}) {
|
|
|
5063
5111
|
let sessionTitle = "";
|
|
5064
5112
|
let preview = "";
|
|
5065
5113
|
for (const file of files.sort()) {
|
|
5066
|
-
const filePath =
|
|
5114
|
+
const filePath = path7.join(dir, file);
|
|
5067
5115
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
5068
5116
|
const lines = content.split("\n").filter(Boolean);
|
|
5069
5117
|
for (const line of lines) {
|
|
@@ -5116,6 +5164,7 @@ var ExtensionProviderInstance = class {
|
|
|
5116
5164
|
currentStatus = "idle";
|
|
5117
5165
|
agentStreams = [];
|
|
5118
5166
|
messages = [];
|
|
5167
|
+
prevMessageHashes = /* @__PURE__ */ new Map();
|
|
5119
5168
|
activeModal = null;
|
|
5120
5169
|
currentModel = "";
|
|
5121
5170
|
currentMode = "";
|
|
@@ -5181,7 +5230,7 @@ var ExtensionProviderInstance = class {
|
|
|
5181
5230
|
onEvent(event, data) {
|
|
5182
5231
|
if (event === "stream_update") {
|
|
5183
5232
|
if (data?.streams) this.agentStreams = data.streams;
|
|
5184
|
-
if (data?.messages) this.messages = data.messages;
|
|
5233
|
+
if (data?.messages) this.messages = this.assignReceivedAt(data.messages);
|
|
5185
5234
|
if (data?.activeModal !== void 0) this.activeModal = data.activeModal;
|
|
5186
5235
|
if (data?.model) this.currentModel = data.model;
|
|
5187
5236
|
if (data?.mode) this.currentMode = data.mode;
|
|
@@ -5207,6 +5256,7 @@ var ExtensionProviderInstance = class {
|
|
|
5207
5256
|
dispose() {
|
|
5208
5257
|
this.agentStreams = [];
|
|
5209
5258
|
this.messages = [];
|
|
5259
|
+
this.prevMessageHashes.clear();
|
|
5210
5260
|
this.monitor.reset();
|
|
5211
5261
|
this.appliedEffectKeys.clear();
|
|
5212
5262
|
this.runtimeMessages = [];
|
|
@@ -5362,6 +5412,23 @@ var ExtensionProviderInstance = class {
|
|
|
5362
5412
|
this.chatId || this.instanceId
|
|
5363
5413
|
);
|
|
5364
5414
|
}
|
|
5415
|
+
/**
|
|
5416
|
+
* Assign stable receivedAt to extension messages.
|
|
5417
|
+
* Same pattern as IdeProviderInstance.readChat() prevByHash —
|
|
5418
|
+
* preserves first-seen timestamp across polling cycles.
|
|
5419
|
+
*/
|
|
5420
|
+
assignReceivedAt(messages) {
|
|
5421
|
+
const now = Date.now();
|
|
5422
|
+
const nextHashes = /* @__PURE__ */ new Map();
|
|
5423
|
+
for (const msg of messages) {
|
|
5424
|
+
const hash = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
|
|
5425
|
+
const prevTime = this.prevMessageHashes.get(hash);
|
|
5426
|
+
msg.receivedAt = prevTime || now;
|
|
5427
|
+
nextHashes.set(hash, msg.receivedAt);
|
|
5428
|
+
}
|
|
5429
|
+
this.prevMessageHashes = nextHashes;
|
|
5430
|
+
return messages;
|
|
5431
|
+
}
|
|
5365
5432
|
mergeConversationMessages(messages) {
|
|
5366
5433
|
if (this.runtimeMessages.length === 0) return messages;
|
|
5367
5434
|
return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
|
|
@@ -5418,6 +5485,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
5418
5485
|
}
|
|
5419
5486
|
this.agentStreams = [];
|
|
5420
5487
|
this.messages = [];
|
|
5488
|
+
this.prevMessageHashes.clear();
|
|
5421
5489
|
this.activeModal = null;
|
|
5422
5490
|
this.currentModel = "";
|
|
5423
5491
|
this.currentMode = "";
|
|
@@ -6403,16 +6471,28 @@ function trimMessageForStatus(message, stringLimit) {
|
|
|
6403
6471
|
if (!message || typeof message !== "object") return message;
|
|
6404
6472
|
return trimStructuredStrings(message, stringLimit);
|
|
6405
6473
|
}
|
|
6474
|
+
function normalizeMessageTime(message) {
|
|
6475
|
+
if (!message || typeof message !== "object") return message;
|
|
6476
|
+
const msg = message;
|
|
6477
|
+
if (msg.receivedAt == null) {
|
|
6478
|
+
const fallback = msg.timestamp ?? msg.createdAt;
|
|
6479
|
+
if (fallback != null) {
|
|
6480
|
+
const ts2 = typeof fallback === "string" ? Date.parse(fallback) : Number(fallback);
|
|
6481
|
+
if (Number.isFinite(ts2) && ts2 > 0) msg.receivedAt = ts2;
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6484
|
+
return msg;
|
|
6485
|
+
}
|
|
6406
6486
|
function trimMessagesForStatus(messages) {
|
|
6407
6487
|
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
6408
6488
|
const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
|
|
6409
6489
|
const kept = [];
|
|
6410
6490
|
let totalBytes = 0;
|
|
6411
6491
|
for (let i = recent.length - 1; i >= 0; i -= 1) {
|
|
6412
|
-
let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
|
|
6492
|
+
let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
|
|
6413
6493
|
let size = estimateBytes(normalized);
|
|
6414
6494
|
if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
6415
|
-
normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
|
|
6495
|
+
normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
|
|
6416
6496
|
size = estimateBytes(normalized);
|
|
6417
6497
|
}
|
|
6418
6498
|
if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
@@ -7035,7 +7115,7 @@ async function handleSendChat(h, args) {
|
|
|
7035
7115
|
if (isExtensionTransport(transport)) {
|
|
7036
7116
|
_log(`Extension: ${provider?.type || "unknown_extension"}`);
|
|
7037
7117
|
try {
|
|
7038
|
-
const evalResult = await h.evaluateProviderScript("sendMessage", {
|
|
7118
|
+
const evalResult = await h.evaluateProviderScript("sendMessage", { message: text }, 3e4);
|
|
7039
7119
|
if (evalResult?.result) {
|
|
7040
7120
|
const parsed = parseMaybeJson(evalResult.result);
|
|
7041
7121
|
if (didProviderConfirmSend(parsed)) {
|
|
@@ -7066,7 +7146,7 @@ async function handleSendChat(h, args) {
|
|
|
7066
7146
|
return { success: false, error: `CDP for ${managerKey || "unknown"} not connected` };
|
|
7067
7147
|
}
|
|
7068
7148
|
_log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
|
|
7069
|
-
const sendScript = h.getProviderScript("sendMessage", {
|
|
7149
|
+
const sendScript = h.getProviderScript("sendMessage", { message: text });
|
|
7070
7150
|
if (sendScript) {
|
|
7071
7151
|
try {
|
|
7072
7152
|
const result = await targetCdp.evaluate(sendScript, 3e4);
|
|
@@ -7206,6 +7286,14 @@ async function handleListChats(h, args) {
|
|
|
7206
7286
|
} catch {
|
|
7207
7287
|
}
|
|
7208
7288
|
}
|
|
7289
|
+
if (parsed?.sessions && Array.isArray(parsed.sessions)) {
|
|
7290
|
+
LOG.info("Command", `[list_chats] OK: ${parsed.sessions.length} chats`);
|
|
7291
|
+
return { success: true, chats: parsed.sessions };
|
|
7292
|
+
}
|
|
7293
|
+
if (parsed?.chats && Array.isArray(parsed.chats)) {
|
|
7294
|
+
LOG.info("Command", `[list_chats] OK: ${parsed.chats.length} chats`);
|
|
7295
|
+
return { success: true, chats: parsed.chats };
|
|
7296
|
+
}
|
|
7209
7297
|
if (Array.isArray(parsed)) {
|
|
7210
7298
|
LOG.info("Command", `[list_chats] OK: ${parsed.length} chats`);
|
|
7211
7299
|
return { success: true, chats: parsed };
|
|
@@ -7275,7 +7363,13 @@ async function handleSwitchChat(h, args) {
|
|
|
7275
7363
|
} catch (e) {
|
|
7276
7364
|
return { success: false, error: `webviewSwitchSession failed: ${e.message}` };
|
|
7277
7365
|
}
|
|
7278
|
-
const
|
|
7366
|
+
const switchParams = {
|
|
7367
|
+
sessionId,
|
|
7368
|
+
title: sessionId,
|
|
7369
|
+
id: sessionId,
|
|
7370
|
+
SESSION_ID: JSON.stringify(sessionId)
|
|
7371
|
+
};
|
|
7372
|
+
const script = h.getProviderScript("switchSession", switchParams) || h.getProviderScript("switch_session", switchParams);
|
|
7279
7373
|
if (!script) return { success: false, error: "switch_session script not available" };
|
|
7280
7374
|
try {
|
|
7281
7375
|
const raw = await cdp.evaluate(script, 15e3);
|
|
@@ -7354,8 +7448,8 @@ async function handleSetMode(h, args) {
|
|
|
7354
7448
|
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
7355
7449
|
if (adapter) {
|
|
7356
7450
|
const acpInstance = adapter._acpInstance;
|
|
7357
|
-
if (acpInstance && typeof acpInstance.
|
|
7358
|
-
acpInstance.
|
|
7451
|
+
if (acpInstance && typeof acpInstance.setMode === "function") {
|
|
7452
|
+
await acpInstance.setMode(mode);
|
|
7359
7453
|
return { success: true, mode };
|
|
7360
7454
|
}
|
|
7361
7455
|
}
|
|
@@ -7412,9 +7506,9 @@ async function handleChangeModel(h, args) {
|
|
|
7412
7506
|
LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
|
|
7413
7507
|
if (adapter) {
|
|
7414
7508
|
const acpInstance = adapter._acpInstance;
|
|
7415
|
-
if (acpInstance && typeof acpInstance.
|
|
7416
|
-
acpInstance.
|
|
7417
|
-
LOG.info("Command", `[change_model]
|
|
7509
|
+
if (acpInstance && typeof acpInstance.setConfigOption === "function") {
|
|
7510
|
+
await acpInstance.setConfigOption("model", model);
|
|
7511
|
+
LOG.info("Command", `[change_model] Updated ACP model to ${model}`);
|
|
7418
7512
|
return { success: true, model };
|
|
7419
7513
|
}
|
|
7420
7514
|
}
|
|
@@ -7534,6 +7628,18 @@ async function handleResolveAction(h, args) {
|
|
|
7534
7628
|
const ok = await h.agentStream.resolveSessionAction(h.getCdp(), h.currentSession.sessionId, action);
|
|
7535
7629
|
return { success: ok };
|
|
7536
7630
|
}
|
|
7631
|
+
if (transport === "acp") {
|
|
7632
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
7633
|
+
const acpInstance = adapter?._acpInstance;
|
|
7634
|
+
if (!acpInstance) return { success: false, error: "ACP instance not found" };
|
|
7635
|
+
try {
|
|
7636
|
+
await acpInstance.resolvePermission(action === "approve" || action === "accept" || action === "always");
|
|
7637
|
+
LOG.info("Command", `[resolveAction] ACP \u2192 ${action}`);
|
|
7638
|
+
return { success: true, action };
|
|
7639
|
+
} catch (e) {
|
|
7640
|
+
return { success: false, error: e?.message || "ACP resolve action failed" };
|
|
7641
|
+
}
|
|
7642
|
+
}
|
|
7537
7643
|
if (provider?.scripts?.webviewResolveAction || provider?.scripts?.webview_resolve_action) {
|
|
7538
7644
|
const script = h.getProviderScript("webviewResolveAction", { action, button, buttonText: button }) || h.getProviderScript("webview_resolve_action", { action, button, buttonText: button });
|
|
7539
7645
|
if (script) {
|
|
@@ -7612,7 +7718,7 @@ async function handleResolveAction(h, args) {
|
|
|
7612
7718
|
|
|
7613
7719
|
// src/commands/cdp-commands.ts
|
|
7614
7720
|
import * as fs4 from "fs";
|
|
7615
|
-
import * as
|
|
7721
|
+
import * as path8 from "path";
|
|
7616
7722
|
import * as os6 from "os";
|
|
7617
7723
|
var KEY_TO_VK = {
|
|
7618
7724
|
Backspace: 8,
|
|
@@ -7864,25 +7970,25 @@ function resolveSafePath(requestedPath) {
|
|
|
7864
7970
|
const inputPath = rawPath || ".";
|
|
7865
7971
|
const home = os6.homedir();
|
|
7866
7972
|
if (inputPath.startsWith("~")) {
|
|
7867
|
-
return
|
|
7973
|
+
return path8.resolve(path8.join(home, inputPath.slice(1)));
|
|
7868
7974
|
}
|
|
7869
7975
|
if (process.platform === "win32") {
|
|
7870
7976
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
7871
|
-
if (
|
|
7872
|
-
return
|
|
7977
|
+
if (path8.win32.isAbsolute(normalized)) {
|
|
7978
|
+
return path8.win32.normalize(normalized);
|
|
7873
7979
|
}
|
|
7874
|
-
return
|
|
7980
|
+
return path8.win32.resolve(normalized);
|
|
7875
7981
|
}
|
|
7876
|
-
if (
|
|
7877
|
-
return
|
|
7982
|
+
if (path8.isAbsolute(inputPath)) {
|
|
7983
|
+
return path8.normalize(inputPath);
|
|
7878
7984
|
}
|
|
7879
|
-
return
|
|
7985
|
+
return path8.resolve(inputPath);
|
|
7880
7986
|
}
|
|
7881
7987
|
function listDirectoryEntriesSafe(dirPath) {
|
|
7882
7988
|
const entries = fs4.readdirSync(dirPath, { withFileTypes: true });
|
|
7883
7989
|
const files = [];
|
|
7884
7990
|
for (const entry of entries) {
|
|
7885
|
-
const entryPath =
|
|
7991
|
+
const entryPath = path8.join(dirPath, entry.name);
|
|
7886
7992
|
try {
|
|
7887
7993
|
if (entry.isDirectory()) {
|
|
7888
7994
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -7921,7 +8027,7 @@ async function handleFileRead(h, args) {
|
|
|
7921
8027
|
async function handleFileWrite(h, args) {
|
|
7922
8028
|
try {
|
|
7923
8029
|
const filePath = resolveSafePath(args?.path);
|
|
7924
|
-
fs4.mkdirSync(
|
|
8030
|
+
fs4.mkdirSync(path8.dirname(filePath), { recursive: true });
|
|
7925
8031
|
fs4.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
7926
8032
|
return { success: true, path: filePath };
|
|
7927
8033
|
} catch (e) {
|
|
@@ -8009,7 +8115,7 @@ function handleGetProviderSettings(h, args) {
|
|
|
8009
8115
|
}
|
|
8010
8116
|
return { success: true, settings: allSettings, values: allValues };
|
|
8011
8117
|
}
|
|
8012
|
-
function handleSetProviderSetting(h, args) {
|
|
8118
|
+
async function handleSetProviderSetting(h, args) {
|
|
8013
8119
|
const loader = h.ctx.providerLoader;
|
|
8014
8120
|
const { providerType, key, value } = args || {};
|
|
8015
8121
|
if (!providerType || !key || value === void 0) {
|
|
@@ -8022,6 +8128,7 @@ function handleSetProviderSetting(h, args) {
|
|
|
8022
8128
|
const updated = h.ctx.instanceManager.updateInstanceSettings(providerType, allSettings);
|
|
8023
8129
|
LOG.info("Command", `[set_provider_setting] ${providerType}.${key}=${JSON.stringify(value)} \u2192 ${updated} instance(s) updated`);
|
|
8024
8130
|
}
|
|
8131
|
+
await h.ctx.onProviderSettingChanged?.(providerType, key, value);
|
|
8025
8132
|
return { success: true, providerType, key, value };
|
|
8026
8133
|
}
|
|
8027
8134
|
return { success: false, error: `Failed to set ${providerType}.${key} \u2014 invalid key, value, or not a public setting` };
|
|
@@ -8059,10 +8166,10 @@ function getCliScriptCommand(payload) {
|
|
|
8059
8166
|
}
|
|
8060
8167
|
const command = payload.command;
|
|
8061
8168
|
if (!command || typeof command !== "object") return null;
|
|
8062
|
-
if (command.type !== "send_message") return null;
|
|
8169
|
+
if (command.type !== "send_message" && command.type !== "pty_write") return null;
|
|
8063
8170
|
const text = typeof command.text === "string" ? command.text.trim() : typeof command.message === "string" ? command.message.trim() : "";
|
|
8064
8171
|
if (!text) return null;
|
|
8065
|
-
return { type:
|
|
8172
|
+
return { type: command.type, text };
|
|
8066
8173
|
}
|
|
8067
8174
|
function applyProviderPatch(h, args, payload) {
|
|
8068
8175
|
if (!payload || typeof payload !== "object") return;
|
|
@@ -8103,6 +8210,8 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
8103
8210
|
const cliCommand = getCliScriptCommand(parsed.payload);
|
|
8104
8211
|
if (cliCommand?.type === "send_message" && cliCommand.text) {
|
|
8105
8212
|
await adapter.sendMessage(cliCommand.text);
|
|
8213
|
+
} else if (cliCommand?.type === "pty_write" && cliCommand.text && adapter.writeRaw) {
|
|
8214
|
+
adapter.writeRaw(cliCommand.text + "\r");
|
|
8106
8215
|
}
|
|
8107
8216
|
applyProviderPatch(h, args, parsed.payload);
|
|
8108
8217
|
return { success: true, ...parsed.payload && typeof parsed.payload === "object" ? parsed.payload : { result: parsed.payload } };
|
|
@@ -8468,9 +8577,26 @@ var DaemonCommandHandler = class {
|
|
|
8468
8577
|
if (provider?.scripts) {
|
|
8469
8578
|
const fn = provider.scripts[scriptName];
|
|
8470
8579
|
if (typeof fn === "function") {
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8580
|
+
if (params && Object.keys(params).length > 0) {
|
|
8581
|
+
const firstVal = Object.values(params)[0];
|
|
8582
|
+
if (scriptName === "sendMessage" && typeof firstVal === "string") {
|
|
8583
|
+
const legacyScript = fn(firstVal);
|
|
8584
|
+
if (legacyScript) return legacyScript;
|
|
8585
|
+
}
|
|
8586
|
+
const script = fn(params);
|
|
8587
|
+
if (script) {
|
|
8588
|
+
const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
|
|
8589
|
+
if (!likelyLegacyObjectLeak) return script;
|
|
8590
|
+
}
|
|
8591
|
+
if (firstVal !== void 0) {
|
|
8592
|
+
const legacyScript = fn(firstVal);
|
|
8593
|
+
if (legacyScript) return legacyScript;
|
|
8594
|
+
}
|
|
8595
|
+
if (script) return script;
|
|
8596
|
+
} else {
|
|
8597
|
+
const script = fn();
|
|
8598
|
+
if (script) return script;
|
|
8599
|
+
}
|
|
8474
8600
|
}
|
|
8475
8601
|
}
|
|
8476
8602
|
return null;
|
|
@@ -8764,7 +8890,7 @@ var DaemonCommandHandler = class {
|
|
|
8764
8890
|
try {
|
|
8765
8891
|
const http3 = await import("http");
|
|
8766
8892
|
const postData = JSON.stringify(body);
|
|
8767
|
-
const result = await new Promise((
|
|
8893
|
+
const result = await new Promise((resolve12, reject) => {
|
|
8768
8894
|
const req = http3.request({
|
|
8769
8895
|
hostname: "127.0.0.1",
|
|
8770
8896
|
port: 19280,
|
|
@@ -8776,9 +8902,9 @@ var DaemonCommandHandler = class {
|
|
|
8776
8902
|
res.on("data", (chunk) => data += chunk);
|
|
8777
8903
|
res.on("end", () => {
|
|
8778
8904
|
try {
|
|
8779
|
-
|
|
8905
|
+
resolve12(JSON.parse(data));
|
|
8780
8906
|
} catch {
|
|
8781
|
-
|
|
8907
|
+
resolve12({ raw: data });
|
|
8782
8908
|
}
|
|
8783
8909
|
});
|
|
8784
8910
|
});
|
|
@@ -8796,15 +8922,15 @@ var DaemonCommandHandler = class {
|
|
|
8796
8922
|
if (!providerType) return { success: false, error: "providerType required" };
|
|
8797
8923
|
try {
|
|
8798
8924
|
const http3 = await import("http");
|
|
8799
|
-
const result = await new Promise((
|
|
8925
|
+
const result = await new Promise((resolve12, reject) => {
|
|
8800
8926
|
http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
|
|
8801
8927
|
let data = "";
|
|
8802
8928
|
res.on("data", (chunk) => data += chunk);
|
|
8803
8929
|
res.on("end", () => {
|
|
8804
8930
|
try {
|
|
8805
|
-
|
|
8931
|
+
resolve12(JSON.parse(data));
|
|
8806
8932
|
} catch {
|
|
8807
|
-
|
|
8933
|
+
resolve12({ raw: data });
|
|
8808
8934
|
}
|
|
8809
8935
|
});
|
|
8810
8936
|
}).on("error", reject);
|
|
@@ -8818,7 +8944,7 @@ var DaemonCommandHandler = class {
|
|
|
8818
8944
|
try {
|
|
8819
8945
|
const http3 = await import("http");
|
|
8820
8946
|
const postData = JSON.stringify(args || {});
|
|
8821
|
-
const result = await new Promise((
|
|
8947
|
+
const result = await new Promise((resolve12, reject) => {
|
|
8822
8948
|
const req = http3.request({
|
|
8823
8949
|
hostname: "127.0.0.1",
|
|
8824
8950
|
port: 19280,
|
|
@@ -8830,9 +8956,9 @@ var DaemonCommandHandler = class {
|
|
|
8830
8956
|
res.on("data", (chunk) => data += chunk);
|
|
8831
8957
|
res.on("end", () => {
|
|
8832
8958
|
try {
|
|
8833
|
-
|
|
8959
|
+
resolve12(JSON.parse(data));
|
|
8834
8960
|
} catch {
|
|
8835
|
-
|
|
8961
|
+
resolve12({ raw: data });
|
|
8836
8962
|
}
|
|
8837
8963
|
});
|
|
8838
8964
|
});
|
|
@@ -8850,7 +8976,7 @@ var DaemonCommandHandler = class {
|
|
|
8850
8976
|
// src/commands/cli-manager.ts
|
|
8851
8977
|
init_provider_cli_adapter();
|
|
8852
8978
|
import * as os10 from "os";
|
|
8853
|
-
import * as
|
|
8979
|
+
import * as path11 from "path";
|
|
8854
8980
|
import * as crypto4 from "crypto";
|
|
8855
8981
|
import chalk from "chalk";
|
|
8856
8982
|
init_config();
|
|
@@ -8858,7 +8984,7 @@ init_config();
|
|
|
8858
8984
|
// src/providers/cli-provider-instance.ts
|
|
8859
8985
|
init_provider_cli_adapter();
|
|
8860
8986
|
import * as os9 from "os";
|
|
8861
|
-
import * as
|
|
8987
|
+
import * as path10 from "path";
|
|
8862
8988
|
import * as crypto3 from "crypto";
|
|
8863
8989
|
import * as fs5 from "fs";
|
|
8864
8990
|
import { createRequire } from "module";
|
|
@@ -8866,7 +8992,7 @@ init_logger();
|
|
|
8866
8992
|
var CachedDatabaseSync = null;
|
|
8867
8993
|
function getDatabaseSync() {
|
|
8868
8994
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
8869
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
8995
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path10.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
8870
8996
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
8871
8997
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
8872
8998
|
if (!CachedDatabaseSync) {
|
|
@@ -8931,6 +9057,7 @@ var CliProviderInstance = class {
|
|
|
8931
9057
|
this.detectStatusTransition();
|
|
8932
9058
|
});
|
|
8933
9059
|
await this.adapter.spawn();
|
|
9060
|
+
this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
|
|
8934
9061
|
if (this.providerSessionId) {
|
|
8935
9062
|
const restoredHistory = readChatHistory(this.type, 0, 200, this.providerSessionId);
|
|
8936
9063
|
if (restoredHistory.messages.length > 0) {
|
|
@@ -9025,6 +9152,7 @@ var CliProviderInstance = class {
|
|
|
9025
9152
|
this.promoteProviderSessionId(parsedProviderSessionId);
|
|
9026
9153
|
}
|
|
9027
9154
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
9155
|
+
this.maybeAppendRuntimeRecoveryMessage(runtime);
|
|
9028
9156
|
const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
|
|
9029
9157
|
const controlValues = extractProviderControlValues(this.provider.controls, parsedStatus);
|
|
9030
9158
|
if (controlValues) {
|
|
@@ -9351,6 +9479,28 @@ ${effect.notification.body || ""}`.trim();
|
|
|
9351
9479
|
const pad = (value) => String(value).padStart(2, "0");
|
|
9352
9480
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
9353
9481
|
}
|
|
9482
|
+
maybeAppendRuntimeRecoveryMessage(runtime) {
|
|
9483
|
+
if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
|
|
9484
|
+
const recoveryState = String(runtime.recoveryState || "").trim();
|
|
9485
|
+
if (!recoveryState) return;
|
|
9486
|
+
let content = "";
|
|
9487
|
+
if (recoveryState === "auto_resumed") {
|
|
9488
|
+
content = "Session host restored this CLI after restart and reattached it from a saved snapshot.";
|
|
9489
|
+
} else if (recoveryState === "resume_failed") {
|
|
9490
|
+
const errorSuffix = runtime.recoveryError ? ` Resume failed: ${runtime.recoveryError}` : "";
|
|
9491
|
+
content = `Session host found this CLI after restart, but automatic resume failed.${errorSuffix}`;
|
|
9492
|
+
} else if (recoveryState === "host_restart_interrupted") {
|
|
9493
|
+
content = "Session host found this CLI in interrupted state after restart and is attempting to resume it.";
|
|
9494
|
+
} else if (recoveryState === "orphan_snapshot") {
|
|
9495
|
+
content = "Session host restored the last snapshot for this CLI, but the original runtime was not resumed automatically.";
|
|
9496
|
+
} else {
|
|
9497
|
+
content = `Session host restored this CLI after restart (${recoveryState}).`;
|
|
9498
|
+
}
|
|
9499
|
+
this.appendRuntimeSystemMessage(
|
|
9500
|
+
content,
|
|
9501
|
+
`runtime_recovery:${runtime.runtimeId}:${recoveryState}`
|
|
9502
|
+
);
|
|
9503
|
+
}
|
|
9354
9504
|
appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
|
|
9355
9505
|
const normalizedContent = String(content || "").trim();
|
|
9356
9506
|
if (!normalizedContent) return;
|
|
@@ -9676,8 +9826,9 @@ var AcpProviderInstance = class {
|
|
|
9676
9826
|
async setConfigOption(category, value) {
|
|
9677
9827
|
const opt = this.configOptions.find((c) => c.category === category);
|
|
9678
9828
|
if (!opt) {
|
|
9679
|
-
|
|
9680
|
-
|
|
9829
|
+
const message = `[${this.type}] No config option for category: ${category}`;
|
|
9830
|
+
this.log.warn(message);
|
|
9831
|
+
throw new Error(message);
|
|
9681
9832
|
}
|
|
9682
9833
|
if (this.useStaticConfig) {
|
|
9683
9834
|
opt.currentValue = value;
|
|
@@ -9689,8 +9840,9 @@ var AcpProviderInstance = class {
|
|
|
9689
9840
|
return;
|
|
9690
9841
|
}
|
|
9691
9842
|
if (!this.connection || !this.sessionId) {
|
|
9692
|
-
|
|
9693
|
-
|
|
9843
|
+
const message = `[${this.type}] Cannot set config: no active connection/session`;
|
|
9844
|
+
this.log.warn(message);
|
|
9845
|
+
throw new Error(message);
|
|
9694
9846
|
}
|
|
9695
9847
|
try {
|
|
9696
9848
|
this.log.info(`[${this.type}] Sending session/set_config_option: configId=${opt.configId} value=${value} sessionId=${this.sessionId}`);
|
|
@@ -9704,7 +9856,9 @@ var AcpProviderInstance = class {
|
|
|
9704
9856
|
if (result?.configOptions) this.parseConfigOptions(result.configOptions);
|
|
9705
9857
|
this.log.info(`[${this.type}] Config ${category} set to: ${value} | response: ${JSON.stringify(result)?.slice(0, 300)}`);
|
|
9706
9858
|
} catch (e) {
|
|
9707
|
-
|
|
9859
|
+
const message = e?.message || "Unknown ACP config error";
|
|
9860
|
+
this.log.warn(`[${this.type}] set_config_option failed: ${message}`);
|
|
9861
|
+
throw new Error(message);
|
|
9708
9862
|
}
|
|
9709
9863
|
}
|
|
9710
9864
|
async setMode(modeId) {
|
|
@@ -9720,8 +9874,9 @@ var AcpProviderInstance = class {
|
|
|
9720
9874
|
return;
|
|
9721
9875
|
}
|
|
9722
9876
|
if (!this.connection || !this.sessionId) {
|
|
9723
|
-
|
|
9724
|
-
|
|
9877
|
+
const message = `[${this.type}] Cannot set mode: no active connection/session`;
|
|
9878
|
+
this.log.warn(message);
|
|
9879
|
+
throw new Error(message);
|
|
9725
9880
|
}
|
|
9726
9881
|
try {
|
|
9727
9882
|
await this.connection.setSessionMode({
|
|
@@ -9731,7 +9886,9 @@ var AcpProviderInstance = class {
|
|
|
9731
9886
|
this.currentMode = modeId;
|
|
9732
9887
|
this.log.info(`[${this.type}] Mode set to: ${modeId}`);
|
|
9733
9888
|
} catch (e) {
|
|
9734
|
-
|
|
9889
|
+
const message = e?.message || "Unknown ACP mode error";
|
|
9890
|
+
this.log.warn(`[${this.type}] set_mode failed: ${message}`);
|
|
9891
|
+
throw new Error(message);
|
|
9735
9892
|
}
|
|
9736
9893
|
}
|
|
9737
9894
|
/** Static config: kill process and restart with new args */
|
|
@@ -9779,7 +9936,7 @@ var AcpProviderInstance = class {
|
|
|
9779
9936
|
if (!spawnConfig) {
|
|
9780
9937
|
throw new Error(`[ACP:${this.type}] No spawn config defined`);
|
|
9781
9938
|
}
|
|
9782
|
-
const command = spawnConfig.command;
|
|
9939
|
+
const command = typeof this.settings.executablePath === "string" && this.settings.executablePath.trim() ? this.settings.executablePath.trim() : spawnConfig.command;
|
|
9783
9940
|
let baseArgs = spawnConfig.args || [];
|
|
9784
9941
|
if (this.provider.spawnArgBuilder && Object.keys(this.selectedConfig).length > 0) {
|
|
9785
9942
|
baseArgs = this.provider.spawnArgBuilder(this.selectedConfig);
|
|
@@ -9895,13 +10052,13 @@ var AcpProviderInstance = class {
|
|
|
9895
10052
|
}
|
|
9896
10053
|
this.currentStatus = "waiting_approval";
|
|
9897
10054
|
this.detectStatusTransition();
|
|
9898
|
-
const approved = await new Promise((
|
|
9899
|
-
this.permissionResolvers.push(
|
|
10055
|
+
const approved = await new Promise((resolve12) => {
|
|
10056
|
+
this.permissionResolvers.push(resolve12);
|
|
9900
10057
|
setTimeout(() => {
|
|
9901
|
-
const idx = this.permissionResolvers.indexOf(
|
|
10058
|
+
const idx = this.permissionResolvers.indexOf(resolve12);
|
|
9902
10059
|
if (idx >= 0) {
|
|
9903
10060
|
this.permissionResolvers.splice(idx, 1);
|
|
9904
|
-
|
|
10061
|
+
resolve12(false);
|
|
9905
10062
|
}
|
|
9906
10063
|
}, 3e5);
|
|
9907
10064
|
});
|
|
@@ -10608,7 +10765,7 @@ var DaemonCliManager = class {
|
|
|
10608
10765
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
10609
10766
|
const trimmed = (workingDir || "").trim();
|
|
10610
10767
|
if (!trimmed) throw new Error("working directory required");
|
|
10611
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) :
|
|
10768
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path11.resolve(trimmed);
|
|
10612
10769
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
10613
10770
|
const provider = this.providerLoader.getByAlias(cliType);
|
|
10614
10771
|
const key = crypto4.randomUUID();
|
|
@@ -10695,10 +10852,10 @@ ${installInfo}`
|
|
|
10695
10852
|
if (!cliInfo) {
|
|
10696
10853
|
const installHint = provider?.install || "";
|
|
10697
10854
|
const displayName = provider?.displayName || provider?.name || cliType;
|
|
10698
|
-
const spawnCmd = provider?.spawn?.command || cliType;
|
|
10855
|
+
const spawnCmd = this.providerLoader.getSpawnCommand(normalizedType, provider?.spawn?.command || cliType);
|
|
10699
10856
|
throw new Error(
|
|
10700
10857
|
`${displayName} is not installed.
|
|
10701
|
-
Command '${spawnCmd}' not
|
|
10858
|
+
Command '${spawnCmd}' is not available.
|
|
10702
10859
|
` + (installHint ? `
|
|
10703
10860
|
${installHint}
|
|
10704
10861
|
` : "") + `
|
|
@@ -11058,16 +11215,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
11058
11215
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
11059
11216
|
import * as net from "net";
|
|
11060
11217
|
import * as os12 from "os";
|
|
11061
|
-
import * as
|
|
11218
|
+
import * as path13 from "path";
|
|
11062
11219
|
|
|
11063
11220
|
// src/providers/provider-loader.ts
|
|
11064
11221
|
import * as fs6 from "fs";
|
|
11065
|
-
import * as
|
|
11222
|
+
import * as path12 from "path";
|
|
11066
11223
|
import * as os11 from "os";
|
|
11067
11224
|
import * as chokidar from "chokidar";
|
|
11068
11225
|
init_logger();
|
|
11069
11226
|
var ProviderLoader = class _ProviderLoader {
|
|
11070
11227
|
providers = /* @__PURE__ */ new Map();
|
|
11228
|
+
providerAvailability = /* @__PURE__ */ new Map();
|
|
11071
11229
|
userDir;
|
|
11072
11230
|
upstreamDir;
|
|
11073
11231
|
disableUpstream;
|
|
@@ -11083,12 +11241,12 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11083
11241
|
static META_FILE = ".meta.json";
|
|
11084
11242
|
constructor(options) {
|
|
11085
11243
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
11086
|
-
const defaultProvidersDir =
|
|
11244
|
+
const defaultProvidersDir = path12.join(os11.homedir(), ".adhdev", "providers");
|
|
11087
11245
|
if (options?.userDir) {
|
|
11088
11246
|
this.userDir = options.userDir;
|
|
11089
11247
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
11090
11248
|
} else {
|
|
11091
|
-
const localRepoPath =
|
|
11249
|
+
const localRepoPath = path12.resolve(__dirname, "../../../../../adhdev-providers");
|
|
11092
11250
|
if (fs6.existsSync(localRepoPath)) {
|
|
11093
11251
|
this.userDir = localRepoPath;
|
|
11094
11252
|
this.log(`Auto-detected local public repository: ${this.userDir} (Dev workspace speedup)`);
|
|
@@ -11097,7 +11255,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11097
11255
|
this.log(`Using default user providers directory: ${this.userDir}`);
|
|
11098
11256
|
}
|
|
11099
11257
|
}
|
|
11100
|
-
this.upstreamDir =
|
|
11258
|
+
this.upstreamDir = path12.join(defaultProvidersDir, ".upstream");
|
|
11101
11259
|
this.disableUpstream = options?.disableUpstream ?? false;
|
|
11102
11260
|
}
|
|
11103
11261
|
log(msg) {
|
|
@@ -11127,7 +11285,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11127
11285
|
* Canonical provider directory shape for a given root.
|
|
11128
11286
|
*/
|
|
11129
11287
|
getProviderDir(root, category, type) {
|
|
11130
|
-
return
|
|
11288
|
+
return path12.join(root, category, type);
|
|
11131
11289
|
}
|
|
11132
11290
|
/**
|
|
11133
11291
|
* Canonical user override directory for a provider.
|
|
@@ -11154,7 +11312,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11154
11312
|
resolveProviderFile(type, ...segments) {
|
|
11155
11313
|
const dir = this.findProviderDirInternal(type);
|
|
11156
11314
|
if (!dir) return null;
|
|
11157
|
-
return
|
|
11315
|
+
return path12.join(dir, ...segments);
|
|
11158
11316
|
}
|
|
11159
11317
|
/**
|
|
11160
11318
|
* Load all providers (3-tier priority)
|
|
@@ -11165,6 +11323,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11165
11323
|
*/
|
|
11166
11324
|
loadAll() {
|
|
11167
11325
|
this.providers.clear();
|
|
11326
|
+
this.providerAvailability.clear();
|
|
11168
11327
|
let upstreamCount = 0;
|
|
11169
11328
|
if (!this.disableUpstream && fs6.existsSync(this.upstreamDir)) {
|
|
11170
11329
|
upstreamCount = this.loadDir(this.upstreamDir);
|
|
@@ -11192,7 +11351,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11192
11351
|
if (!fs6.existsSync(this.upstreamDir)) return false;
|
|
11193
11352
|
try {
|
|
11194
11353
|
return fs6.readdirSync(this.upstreamDir).some(
|
|
11195
|
-
(d) => fs6.statSync(
|
|
11354
|
+
(d) => fs6.statSync(path12.join(this.upstreamDir, d)).isDirectory()
|
|
11196
11355
|
);
|
|
11197
11356
|
} catch {
|
|
11198
11357
|
return false;
|
|
@@ -11235,11 +11394,12 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11235
11394
|
if ((p.category === "cli" || p.category === "acp") && p.spawn?.command) {
|
|
11236
11395
|
const verCmdConfig = p.versionCommand;
|
|
11237
11396
|
const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[process.platform] : verCmdConfig;
|
|
11397
|
+
const command = this.getSpawnCommand(p.type, p.spawn.command);
|
|
11238
11398
|
result.push({
|
|
11239
11399
|
id: p.type,
|
|
11240
11400
|
displayName: p.displayName || p.name,
|
|
11241
11401
|
icon: p.icon || "\u{1F527}",
|
|
11242
|
-
command
|
|
11402
|
+
command,
|
|
11243
11403
|
category: p.category,
|
|
11244
11404
|
...typeof versionCommand === "string" && versionCommand.trim() ? { versionCommand: versionCommand.trim() } : {}
|
|
11245
11405
|
});
|
|
@@ -11368,6 +11528,71 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11368
11528
|
getAvailableIdeTypes() {
|
|
11369
11529
|
return [...this.providers.values()].filter((p) => p.category === "ide" && p.cdpPorts).map((p) => p.type);
|
|
11370
11530
|
}
|
|
11531
|
+
getSpawnCommand(type, fallback) {
|
|
11532
|
+
const override = this.getOptionalStringSetting(type, "executablePath");
|
|
11533
|
+
if (override) return override;
|
|
11534
|
+
return fallback || this.providers.get(type)?.spawn?.command || type;
|
|
11535
|
+
}
|
|
11536
|
+
getIdeCliCommand(type, fallback) {
|
|
11537
|
+
const override = this.getOptionalStringSetting(type, "cliPathOverride");
|
|
11538
|
+
if (override) return override;
|
|
11539
|
+
return fallback || this.providers.get(type)?.cli || null;
|
|
11540
|
+
}
|
|
11541
|
+
getIdePathCandidates(type, fallback) {
|
|
11542
|
+
const override = this.getOptionalStringSetting(type, "appPathOverride");
|
|
11543
|
+
if (override) return [override];
|
|
11544
|
+
if (fallback && fallback.length > 0) return fallback;
|
|
11545
|
+
const osPaths = this.providers.get(type)?.paths?.[process.platform];
|
|
11546
|
+
return Array.isArray(osPaths) ? [...osPaths] : [];
|
|
11547
|
+
}
|
|
11548
|
+
setProviderAvailability(type, state) {
|
|
11549
|
+
this.providerAvailability.set(type, {
|
|
11550
|
+
installed: !!state.installed,
|
|
11551
|
+
detectedPath: state.detectedPath ?? null
|
|
11552
|
+
});
|
|
11553
|
+
}
|
|
11554
|
+
setCliDetectionResults(results, replace = true) {
|
|
11555
|
+
if (replace) {
|
|
11556
|
+
for (const provider of this.providers.values()) {
|
|
11557
|
+
if (provider.category === "cli" || provider.category === "acp") {
|
|
11558
|
+
this.providerAvailability.set(provider.type, { installed: false, detectedPath: null });
|
|
11559
|
+
}
|
|
11560
|
+
}
|
|
11561
|
+
}
|
|
11562
|
+
for (const result of results) {
|
|
11563
|
+
this.setProviderAvailability(result.id, {
|
|
11564
|
+
installed: !!result.installed,
|
|
11565
|
+
detectedPath: result.path || null
|
|
11566
|
+
});
|
|
11567
|
+
}
|
|
11568
|
+
}
|
|
11569
|
+
setIdeDetectionResults(results, replace = true) {
|
|
11570
|
+
if (replace) {
|
|
11571
|
+
for (const provider of this.providers.values()) {
|
|
11572
|
+
if (provider.category === "ide") {
|
|
11573
|
+
this.providerAvailability.set(provider.type, { installed: false, detectedPath: null });
|
|
11574
|
+
}
|
|
11575
|
+
}
|
|
11576
|
+
}
|
|
11577
|
+
for (const result of results) {
|
|
11578
|
+
this.setProviderAvailability(result.id, {
|
|
11579
|
+
installed: !!result.installed,
|
|
11580
|
+
detectedPath: result.cliCommand || result.path || null
|
|
11581
|
+
});
|
|
11582
|
+
}
|
|
11583
|
+
}
|
|
11584
|
+
getAvailableProviderInfos() {
|
|
11585
|
+
return this.getAll().map((provider) => {
|
|
11586
|
+
const availability = this.providerAvailability.get(provider.type);
|
|
11587
|
+
return {
|
|
11588
|
+
...provider,
|
|
11589
|
+
...availability ? {
|
|
11590
|
+
installed: availability.installed,
|
|
11591
|
+
detectedPath: availability.detectedPath
|
|
11592
|
+
} : {}
|
|
11593
|
+
};
|
|
11594
|
+
});
|
|
11595
|
+
}
|
|
11371
11596
|
/**
|
|
11372
11597
|
* Register IDE providers to core/detector registry
|
|
11373
11598
|
* → Enables detectIDEs() to detect provider.js-based IDEs
|
|
@@ -11442,8 +11667,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11442
11667
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
11443
11668
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
11444
11669
|
if (providerDir) {
|
|
11445
|
-
const fullDir =
|
|
11446
|
-
resolved._resolvedScriptsPath = fs6.existsSync(
|
|
11670
|
+
const fullDir = path12.join(providerDir, entry.scriptDir);
|
|
11671
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
|
|
11447
11672
|
}
|
|
11448
11673
|
matched = true;
|
|
11449
11674
|
}
|
|
@@ -11458,8 +11683,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11458
11683
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
11459
11684
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
11460
11685
|
if (providerDir) {
|
|
11461
|
-
const fullDir =
|
|
11462
|
-
resolved._resolvedScriptsPath = fs6.existsSync(
|
|
11686
|
+
const fullDir = path12.join(providerDir, base.defaultScriptDir);
|
|
11687
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
|
|
11463
11688
|
}
|
|
11464
11689
|
}
|
|
11465
11690
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -11476,8 +11701,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11476
11701
|
resolved._resolvedScriptDir = dirOverride;
|
|
11477
11702
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
11478
11703
|
if (providerDir) {
|
|
11479
|
-
const fullDir =
|
|
11480
|
-
resolved._resolvedScriptsPath = fs6.existsSync(
|
|
11704
|
+
const fullDir = path12.join(providerDir, dirOverride);
|
|
11705
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
|
|
11481
11706
|
}
|
|
11482
11707
|
}
|
|
11483
11708
|
} else if (override.scripts) {
|
|
@@ -11493,8 +11718,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11493
11718
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
11494
11719
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
11495
11720
|
if (providerDir) {
|
|
11496
|
-
const fullDir =
|
|
11497
|
-
resolved._resolvedScriptsPath = fs6.existsSync(
|
|
11721
|
+
const fullDir = path12.join(providerDir, base.defaultScriptDir);
|
|
11722
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
|
|
11498
11723
|
}
|
|
11499
11724
|
}
|
|
11500
11725
|
}
|
|
@@ -11519,14 +11744,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11519
11744
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
11520
11745
|
return null;
|
|
11521
11746
|
}
|
|
11522
|
-
const dir =
|
|
11747
|
+
const dir = path12.join(providerDir, scriptDir);
|
|
11523
11748
|
if (!fs6.existsSync(dir)) {
|
|
11524
11749
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
11525
11750
|
return null;
|
|
11526
11751
|
}
|
|
11527
11752
|
const cached = this.scriptsCache.get(dir);
|
|
11528
11753
|
if (cached) return cached;
|
|
11529
|
-
const scriptsJs =
|
|
11754
|
+
const scriptsJs = path12.join(dir, "scripts.js");
|
|
11530
11755
|
if (fs6.existsSync(scriptsJs)) {
|
|
11531
11756
|
try {
|
|
11532
11757
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -11568,7 +11793,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11568
11793
|
return;
|
|
11569
11794
|
}
|
|
11570
11795
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
11571
|
-
this.log(`File changed: ${
|
|
11796
|
+
this.log(`File changed: ${path12.basename(filePath)}, reloading...`);
|
|
11572
11797
|
this.reload();
|
|
11573
11798
|
}
|
|
11574
11799
|
};
|
|
@@ -11623,7 +11848,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11623
11848
|
}
|
|
11624
11849
|
const https = __require("https");
|
|
11625
11850
|
const { execSync: execSync7 } = __require("child_process");
|
|
11626
|
-
const metaPath =
|
|
11851
|
+
const metaPath = path12.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
11627
11852
|
let prevEtag = "";
|
|
11628
11853
|
let prevTimestamp = 0;
|
|
11629
11854
|
try {
|
|
@@ -11640,7 +11865,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11640
11865
|
return { updated: false };
|
|
11641
11866
|
}
|
|
11642
11867
|
try {
|
|
11643
|
-
const etag = await new Promise((
|
|
11868
|
+
const etag = await new Promise((resolve12, reject) => {
|
|
11644
11869
|
const options = {
|
|
11645
11870
|
method: "HEAD",
|
|
11646
11871
|
hostname: "github.com",
|
|
@@ -11658,7 +11883,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11658
11883
|
headers: { "User-Agent": "adhdev-launcher" },
|
|
11659
11884
|
timeout: 1e4
|
|
11660
11885
|
}, (res2) => {
|
|
11661
|
-
|
|
11886
|
+
resolve12(res2.headers.etag || res2.headers["last-modified"] || "");
|
|
11662
11887
|
});
|
|
11663
11888
|
req2.on("error", reject);
|
|
11664
11889
|
req2.on("timeout", () => {
|
|
@@ -11667,7 +11892,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11667
11892
|
});
|
|
11668
11893
|
req2.end();
|
|
11669
11894
|
} else {
|
|
11670
|
-
|
|
11895
|
+
resolve12(res.headers.etag || res.headers["last-modified"] || "");
|
|
11671
11896
|
}
|
|
11672
11897
|
});
|
|
11673
11898
|
req.on("error", reject);
|
|
@@ -11683,17 +11908,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11683
11908
|
return { updated: false };
|
|
11684
11909
|
}
|
|
11685
11910
|
this.log("Downloading latest providers from GitHub...");
|
|
11686
|
-
const tmpTar =
|
|
11687
|
-
const tmpExtract =
|
|
11911
|
+
const tmpTar = path12.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
11912
|
+
const tmpExtract = path12.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
11688
11913
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
11689
11914
|
fs6.mkdirSync(tmpExtract, { recursive: true });
|
|
11690
11915
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
11691
11916
|
const extracted = fs6.readdirSync(tmpExtract);
|
|
11692
11917
|
const rootDir = extracted.find(
|
|
11693
|
-
(d) => fs6.statSync(
|
|
11918
|
+
(d) => fs6.statSync(path12.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
11694
11919
|
);
|
|
11695
11920
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
11696
|
-
const sourceDir =
|
|
11921
|
+
const sourceDir = path12.join(tmpExtract, rootDir);
|
|
11697
11922
|
const backupDir = this.upstreamDir + ".bak";
|
|
11698
11923
|
if (fs6.existsSync(this.upstreamDir)) {
|
|
11699
11924
|
if (fs6.existsSync(backupDir)) fs6.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -11731,7 +11956,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11731
11956
|
downloadFile(url, destPath) {
|
|
11732
11957
|
const https = __require("https");
|
|
11733
11958
|
const http3 = __require("http");
|
|
11734
|
-
return new Promise((
|
|
11959
|
+
return new Promise((resolve12, reject) => {
|
|
11735
11960
|
const doRequest = (reqUrl, redirectCount = 0) => {
|
|
11736
11961
|
if (redirectCount > 5) {
|
|
11737
11962
|
reject(new Error("Too many redirects"));
|
|
@@ -11751,7 +11976,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11751
11976
|
res.pipe(ws);
|
|
11752
11977
|
ws.on("finish", () => {
|
|
11753
11978
|
ws.close();
|
|
11754
|
-
|
|
11979
|
+
resolve12();
|
|
11755
11980
|
});
|
|
11756
11981
|
ws.on("error", reject);
|
|
11757
11982
|
});
|
|
@@ -11768,8 +11993,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11768
11993
|
copyDirRecursive(src, dest) {
|
|
11769
11994
|
fs6.mkdirSync(dest, { recursive: true });
|
|
11770
11995
|
for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
|
|
11771
|
-
const srcPath =
|
|
11772
|
-
const destPath =
|
|
11996
|
+
const srcPath = path12.join(src, entry.name);
|
|
11997
|
+
const destPath = path12.join(dest, entry.name);
|
|
11773
11998
|
if (entry.isDirectory()) {
|
|
11774
11999
|
this.copyDirRecursive(srcPath, destPath);
|
|
11775
12000
|
} else {
|
|
@@ -11780,7 +12005,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11780
12005
|
/** .meta.json save */
|
|
11781
12006
|
writeMeta(metaPath, etag, timestamp) {
|
|
11782
12007
|
try {
|
|
11783
|
-
fs6.mkdirSync(
|
|
12008
|
+
fs6.mkdirSync(path12.dirname(metaPath), { recursive: true });
|
|
11784
12009
|
fs6.writeFileSync(metaPath, JSON.stringify({
|
|
11785
12010
|
etag,
|
|
11786
12011
|
timestamp,
|
|
@@ -11797,7 +12022,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11797
12022
|
const scan = (d) => {
|
|
11798
12023
|
try {
|
|
11799
12024
|
for (const entry of fs6.readdirSync(d, { withFileTypes: true })) {
|
|
11800
|
-
if (entry.isDirectory()) scan(
|
|
12025
|
+
if (entry.isDirectory()) scan(path12.join(d, entry.name));
|
|
11801
12026
|
else if (entry.name === "provider.json") count++;
|
|
11802
12027
|
}
|
|
11803
12028
|
} catch {
|
|
@@ -11811,9 +12036,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11811
12036
|
* Get public settings schema for a provider (for dashboard UI rendering)
|
|
11812
12037
|
*/
|
|
11813
12038
|
getPublicSettings(type) {
|
|
11814
|
-
const
|
|
11815
|
-
|
|
11816
|
-
return Object.entries(provider.settings).filter(([, def]) => def.public === true).map(([key, def]) => ({ key, ...def }));
|
|
12039
|
+
const settings = this.getSettingsSchema(type);
|
|
12040
|
+
return Object.entries(settings).filter(([, def]) => def.public === true).map(([key, def]) => ({ key, ...def }));
|
|
11817
12041
|
}
|
|
11818
12042
|
/**
|
|
11819
12043
|
* Get public settings schema for all providers
|
|
@@ -11830,8 +12054,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11830
12054
|
* Resolved setting value for a provider (default + user override)
|
|
11831
12055
|
*/
|
|
11832
12056
|
getSettingValue(type, key) {
|
|
11833
|
-
const
|
|
11834
|
-
const schemaDef = provider?.settings?.[key];
|
|
12057
|
+
const schemaDef = this.getSettingsSchema(type)[key];
|
|
11835
12058
|
const defaultVal = schemaDef ? schemaDef.default : void 0;
|
|
11836
12059
|
try {
|
|
11837
12060
|
const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
|
|
@@ -11846,10 +12069,9 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11846
12069
|
* All resolved settings for a provider (default + user override)
|
|
11847
12070
|
*/
|
|
11848
12071
|
getSettings(type) {
|
|
11849
|
-
const
|
|
11850
|
-
if (!provider?.settings) return {};
|
|
12072
|
+
const settings = this.getSettingsSchema(type);
|
|
11851
12073
|
const result = {};
|
|
11852
|
-
for (const [key
|
|
12074
|
+
for (const [key] of Object.entries(settings)) {
|
|
11853
12075
|
result[key] = this.getSettingValue(type, key);
|
|
11854
12076
|
}
|
|
11855
12077
|
return result;
|
|
@@ -11858,11 +12080,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11858
12080
|
* Save provider setting value (writes to config.json)
|
|
11859
12081
|
*/
|
|
11860
12082
|
setSetting(type, key, value) {
|
|
11861
|
-
const
|
|
11862
|
-
const schemaDef = provider?.settings?.[key];
|
|
12083
|
+
const schemaDef = this.getSettingsSchema(type)[key];
|
|
11863
12084
|
if (!schemaDef) return false;
|
|
11864
12085
|
if (!schemaDef.public) return false;
|
|
11865
12086
|
if (schemaDef.type === "boolean" && typeof value !== "boolean") return false;
|
|
12087
|
+
if (schemaDef.type === "string" && typeof value !== "string") return false;
|
|
11866
12088
|
if (schemaDef.type === "number") {
|
|
11867
12089
|
if (typeof value !== "number") return false;
|
|
11868
12090
|
if (schemaDef.min !== void 0 && value < schemaDef.min) return false;
|
|
@@ -11883,6 +12105,53 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11883
12105
|
return false;
|
|
11884
12106
|
}
|
|
11885
12107
|
}
|
|
12108
|
+
getOptionalStringSetting(type, key) {
|
|
12109
|
+
const value = this.getSettingValue(type, key);
|
|
12110
|
+
if (typeof value !== "string") return null;
|
|
12111
|
+
const trimmed = value.trim();
|
|
12112
|
+
return trimmed ? trimmed : null;
|
|
12113
|
+
}
|
|
12114
|
+
getSettingsSchema(type) {
|
|
12115
|
+
const provider = this.providers.get(type);
|
|
12116
|
+
if (!provider) return {};
|
|
12117
|
+
return {
|
|
12118
|
+
...this.getSyntheticSettings(type, provider),
|
|
12119
|
+
...provider.settings || {}
|
|
12120
|
+
};
|
|
12121
|
+
}
|
|
12122
|
+
getSyntheticSettings(type, provider) {
|
|
12123
|
+
const result = {};
|
|
12124
|
+
if ((provider.category === "cli" || provider.category === "acp") && provider.spawn?.command && !provider.settings?.executablePath) {
|
|
12125
|
+
result.executablePath = {
|
|
12126
|
+
type: "string",
|
|
12127
|
+
default: "",
|
|
12128
|
+
public: true,
|
|
12129
|
+
label: "Executable path",
|
|
12130
|
+
description: "Optional absolute path for this provider binary. Leave blank to use the default PATH lookup."
|
|
12131
|
+
};
|
|
12132
|
+
}
|
|
12133
|
+
if (provider.category === "ide") {
|
|
12134
|
+
if (provider.cli && !provider.settings?.cliPathOverride) {
|
|
12135
|
+
result.cliPathOverride = {
|
|
12136
|
+
type: "string",
|
|
12137
|
+
default: "",
|
|
12138
|
+
public: true,
|
|
12139
|
+
label: "CLI path override",
|
|
12140
|
+
description: "Optional absolute path for the IDE CLI launcher. Leave blank to use the detected default."
|
|
12141
|
+
};
|
|
12142
|
+
}
|
|
12143
|
+
if (provider.paths && !provider.settings?.appPathOverride) {
|
|
12144
|
+
result.appPathOverride = {
|
|
12145
|
+
type: "string",
|
|
12146
|
+
default: "",
|
|
12147
|
+
public: true,
|
|
12148
|
+
label: "App path override",
|
|
12149
|
+
description: "Optional absolute path for the IDE app bundle or executable. Leave blank to use the default install locations."
|
|
12150
|
+
};
|
|
12151
|
+
}
|
|
12152
|
+
}
|
|
12153
|
+
return result;
|
|
12154
|
+
}
|
|
11886
12155
|
// ─── Private ───────────────────────────────────
|
|
11887
12156
|
/**
|
|
11888
12157
|
* Find the on-disk directory for a provider by type.
|
|
@@ -11896,17 +12165,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11896
12165
|
for (const root of searchRoots) {
|
|
11897
12166
|
if (!fs6.existsSync(root)) continue;
|
|
11898
12167
|
const candidate = this.getProviderDir(root, cat, type);
|
|
11899
|
-
if (fs6.existsSync(
|
|
11900
|
-
const catDir =
|
|
12168
|
+
if (fs6.existsSync(path12.join(candidate, "provider.json"))) return candidate;
|
|
12169
|
+
const catDir = path12.join(root, cat);
|
|
11901
12170
|
if (fs6.existsSync(catDir)) {
|
|
11902
12171
|
try {
|
|
11903
12172
|
for (const entry of fs6.readdirSync(catDir, { withFileTypes: true })) {
|
|
11904
12173
|
if (!entry.isDirectory()) continue;
|
|
11905
|
-
const jsonPath =
|
|
12174
|
+
const jsonPath = path12.join(catDir, entry.name, "provider.json");
|
|
11906
12175
|
if (fs6.existsSync(jsonPath)) {
|
|
11907
12176
|
try {
|
|
11908
12177
|
const data = JSON.parse(fs6.readFileSync(jsonPath, "utf-8"));
|
|
11909
|
-
if (data.type === type) return
|
|
12178
|
+
if (data.type === type) return path12.join(catDir, entry.name);
|
|
11910
12179
|
} catch {
|
|
11911
12180
|
}
|
|
11912
12181
|
}
|
|
@@ -11923,7 +12192,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11923
12192
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
11924
12193
|
*/
|
|
11925
12194
|
buildScriptWrappersFromDir(dir) {
|
|
11926
|
-
const scriptsJs =
|
|
12195
|
+
const scriptsJs = path12.join(dir, "scripts.js");
|
|
11927
12196
|
if (fs6.existsSync(scriptsJs)) {
|
|
11928
12197
|
try {
|
|
11929
12198
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -11937,7 +12206,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11937
12206
|
for (const file of fs6.readdirSync(dir)) {
|
|
11938
12207
|
if (!file.endsWith(".js")) continue;
|
|
11939
12208
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
11940
|
-
const filePath =
|
|
12209
|
+
const filePath = path12.join(dir, file);
|
|
11941
12210
|
result[scriptName] = (...args) => {
|
|
11942
12211
|
try {
|
|
11943
12212
|
let content = fs6.readFileSync(filePath, "utf-8");
|
|
@@ -11997,7 +12266,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
11997
12266
|
}
|
|
11998
12267
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
11999
12268
|
if (hasJson) {
|
|
12000
|
-
const jsonPath =
|
|
12269
|
+
const jsonPath = path12.join(d, "provider.json");
|
|
12001
12270
|
try {
|
|
12002
12271
|
const raw = fs6.readFileSync(jsonPath, "utf-8");
|
|
12003
12272
|
const mod = JSON.parse(raw);
|
|
@@ -12010,7 +12279,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
12010
12279
|
delete mod.extensionIdPattern_flags;
|
|
12011
12280
|
}
|
|
12012
12281
|
const hasCompatibility = Array.isArray(mod.compatibility);
|
|
12013
|
-
const scriptsPath =
|
|
12282
|
+
const scriptsPath = path12.join(d, "scripts.js");
|
|
12014
12283
|
if (!hasCompatibility && fs6.existsSync(scriptsPath)) {
|
|
12015
12284
|
try {
|
|
12016
12285
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -12036,7 +12305,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
12036
12305
|
if (!entry.isDirectory()) continue;
|
|
12037
12306
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
12038
12307
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
12039
|
-
scan(
|
|
12308
|
+
scan(path12.join(d, entry.name));
|
|
12040
12309
|
}
|
|
12041
12310
|
}
|
|
12042
12311
|
};
|
|
@@ -12132,17 +12401,17 @@ async function findFreePort(ports) {
|
|
|
12132
12401
|
throw new Error("No free port found");
|
|
12133
12402
|
}
|
|
12134
12403
|
function checkPortFree(port) {
|
|
12135
|
-
return new Promise((
|
|
12404
|
+
return new Promise((resolve12) => {
|
|
12136
12405
|
const server = net.createServer();
|
|
12137
12406
|
server.unref();
|
|
12138
|
-
server.on("error", () =>
|
|
12407
|
+
server.on("error", () => resolve12(false));
|
|
12139
12408
|
server.listen(port, "127.0.0.1", () => {
|
|
12140
|
-
server.close(() =>
|
|
12409
|
+
server.close(() => resolve12(true));
|
|
12141
12410
|
});
|
|
12142
12411
|
});
|
|
12143
12412
|
}
|
|
12144
12413
|
async function isCdpActive(port) {
|
|
12145
|
-
return new Promise((
|
|
12414
|
+
return new Promise((resolve12) => {
|
|
12146
12415
|
const req = __require("http").get(`http://127.0.0.1:${port}/json/version`, {
|
|
12147
12416
|
timeout: 2e3
|
|
12148
12417
|
}, (res) => {
|
|
@@ -12151,16 +12420,16 @@ async function isCdpActive(port) {
|
|
|
12151
12420
|
res.on("end", () => {
|
|
12152
12421
|
try {
|
|
12153
12422
|
const info = JSON.parse(data);
|
|
12154
|
-
|
|
12423
|
+
resolve12(!!info["WebKit-Version"] || !!info["Browser"]);
|
|
12155
12424
|
} catch {
|
|
12156
|
-
|
|
12425
|
+
resolve12(false);
|
|
12157
12426
|
}
|
|
12158
12427
|
});
|
|
12159
12428
|
});
|
|
12160
|
-
req.on("error", () =>
|
|
12429
|
+
req.on("error", () => resolve12(false));
|
|
12161
12430
|
req.on("timeout", () => {
|
|
12162
12431
|
req.destroy();
|
|
12163
|
-
|
|
12432
|
+
resolve12(false);
|
|
12164
12433
|
});
|
|
12165
12434
|
});
|
|
12166
12435
|
}
|
|
@@ -12294,8 +12563,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
12294
12563
|
const appNameMap = getMacAppIdentifiers();
|
|
12295
12564
|
const appName = appNameMap[ideId];
|
|
12296
12565
|
if (appName) {
|
|
12297
|
-
const storagePath =
|
|
12298
|
-
process.env.APPDATA ||
|
|
12566
|
+
const storagePath = path13.join(
|
|
12567
|
+
process.env.APPDATA || path13.join(os12.homedir(), "AppData", "Roaming"),
|
|
12299
12568
|
appName,
|
|
12300
12569
|
"storage.json"
|
|
12301
12570
|
);
|
|
@@ -12319,7 +12588,7 @@ function detectCurrentWorkspace(ideId) {
|
|
|
12319
12588
|
async function launchWithCdp(options = {}) {
|
|
12320
12589
|
const platform9 = os12.platform();
|
|
12321
12590
|
let targetIde;
|
|
12322
|
-
const ides = await detectIDEs();
|
|
12591
|
+
const ides = await detectIDEs(getProviderLoader());
|
|
12323
12592
|
if (options.ideId) {
|
|
12324
12593
|
targetIde = ides.find((i) => i.id === options.ideId && i.installed);
|
|
12325
12594
|
if (!targetIde) {
|
|
@@ -12473,9 +12742,9 @@ init_logger();
|
|
|
12473
12742
|
|
|
12474
12743
|
// src/logging/command-log.ts
|
|
12475
12744
|
import * as fs7 from "fs";
|
|
12476
|
-
import * as
|
|
12745
|
+
import * as path14 from "path";
|
|
12477
12746
|
import * as os13 from "os";
|
|
12478
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
12747
|
+
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");
|
|
12479
12748
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
12480
12749
|
var MAX_DAYS = 7;
|
|
12481
12750
|
try {
|
|
@@ -12513,13 +12782,13 @@ function getDateStr2() {
|
|
|
12513
12782
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
12514
12783
|
}
|
|
12515
12784
|
var currentDate2 = getDateStr2();
|
|
12516
|
-
var currentFile =
|
|
12785
|
+
var currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
12517
12786
|
var writeCount2 = 0;
|
|
12518
12787
|
function checkRotation() {
|
|
12519
12788
|
const today = getDateStr2();
|
|
12520
12789
|
if (today !== currentDate2) {
|
|
12521
12790
|
currentDate2 = today;
|
|
12522
|
-
currentFile =
|
|
12791
|
+
currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
12523
12792
|
cleanOldFiles();
|
|
12524
12793
|
}
|
|
12525
12794
|
}
|
|
@@ -12533,7 +12802,7 @@ function cleanOldFiles() {
|
|
|
12533
12802
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
12534
12803
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
12535
12804
|
try {
|
|
12536
|
-
fs7.unlinkSync(
|
|
12805
|
+
fs7.unlinkSync(path14.join(LOG_DIR2, file));
|
|
12537
12806
|
} catch {
|
|
12538
12807
|
}
|
|
12539
12808
|
}
|
|
@@ -12625,12 +12894,15 @@ function buildDetectedIdeInfos(detectedIdes, cdpManagers) {
|
|
|
12625
12894
|
}));
|
|
12626
12895
|
}
|
|
12627
12896
|
function buildAvailableProviders(providerLoader) {
|
|
12628
|
-
|
|
12897
|
+
const providers = providerLoader.getAvailableProviderInfos?.() || providerLoader.getAll();
|
|
12898
|
+
return providers.map((provider) => ({
|
|
12629
12899
|
type: provider.type,
|
|
12630
12900
|
name: provider.displayName || provider.type,
|
|
12631
12901
|
displayName: provider.displayName || provider.type,
|
|
12632
12902
|
icon: provider.icon || "\u{1F4BB}",
|
|
12633
|
-
category: provider.category
|
|
12903
|
+
category: provider.category,
|
|
12904
|
+
...provider.installed !== void 0 ? { installed: provider.installed } : {},
|
|
12905
|
+
...provider.detectedPath !== void 0 ? { detectedPath: provider.detectedPath } : {}
|
|
12634
12906
|
}));
|
|
12635
12907
|
}
|
|
12636
12908
|
function parseMessageTime(value) {
|
|
@@ -12644,17 +12916,17 @@ function parseMessageTime(value) {
|
|
|
12644
12916
|
function getSessionMessageUpdatedAt(session) {
|
|
12645
12917
|
const lastMessage = session.activeChat?.messages?.at?.(-1);
|
|
12646
12918
|
if (!lastMessage) return 0;
|
|
12647
|
-
return parseMessageTime(lastMessage.
|
|
12919
|
+
return parseMessageTime(lastMessage.receivedAt) || 0;
|
|
12648
12920
|
}
|
|
12649
12921
|
function getSessionCompletionMarker(session) {
|
|
12650
12922
|
const lastMessage = session.activeChat?.messages?.at?.(-1);
|
|
12651
12923
|
if (!lastMessage) return "";
|
|
12652
12924
|
const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
|
|
12653
|
-
if (role === "user" || role === "human") return "";
|
|
12925
|
+
if (role === "user" || role === "human" || role === "system") return "";
|
|
12654
12926
|
if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
|
|
12655
12927
|
if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
|
|
12656
12928
|
if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
|
|
12657
|
-
const timestamp = parseMessageTime(lastMessage.
|
|
12929
|
+
const timestamp = parseMessageTime(lastMessage.receivedAt);
|
|
12658
12930
|
return timestamp > 0 ? `ts:${timestamp}` : "";
|
|
12659
12931
|
}
|
|
12660
12932
|
function getSessionLastUsedAt(session) {
|
|
@@ -12671,7 +12943,7 @@ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRo
|
|
|
12671
12943
|
if (status === "generating" || status === "starting") {
|
|
12672
12944
|
return { unread: false, inboxBucket: "working" };
|
|
12673
12945
|
}
|
|
12674
|
-
const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
|
|
12946
|
+
const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human" && lastRole !== "system";
|
|
12675
12947
|
return { unread, inboxBucket: unread ? "task_complete" : "idle" };
|
|
12676
12948
|
}
|
|
12677
12949
|
function buildRecentLaunches(recentActivity) {
|
|
@@ -12758,13 +13030,13 @@ import { execFileSync } from "child_process";
|
|
|
12758
13030
|
import { spawn as spawn3 } from "child_process";
|
|
12759
13031
|
import * as fs8 from "fs";
|
|
12760
13032
|
import * as os15 from "os";
|
|
12761
|
-
import * as
|
|
13033
|
+
import * as path15 from "path";
|
|
12762
13034
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
12763
13035
|
function getUpgradeLogPath() {
|
|
12764
13036
|
const home = os15.homedir();
|
|
12765
|
-
const dir =
|
|
13037
|
+
const dir = path15.join(home, ".adhdev");
|
|
12766
13038
|
fs8.mkdirSync(dir, { recursive: true });
|
|
12767
|
-
return
|
|
13039
|
+
return path15.join(dir, "daemon-upgrade.log");
|
|
12768
13040
|
}
|
|
12769
13041
|
function appendUpgradeLog(message) {
|
|
12770
13042
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -12797,14 +13069,14 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
12797
13069
|
while (Date.now() - start < timeoutMs) {
|
|
12798
13070
|
try {
|
|
12799
13071
|
process.kill(pid, 0);
|
|
12800
|
-
await new Promise((
|
|
13072
|
+
await new Promise((resolve12) => setTimeout(resolve12, 250));
|
|
12801
13073
|
} catch {
|
|
12802
13074
|
return;
|
|
12803
13075
|
}
|
|
12804
13076
|
}
|
|
12805
13077
|
}
|
|
12806
13078
|
function stopSessionHostProcesses(appName) {
|
|
12807
|
-
const pidFile =
|
|
13079
|
+
const pidFile = path15.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
12808
13080
|
try {
|
|
12809
13081
|
if (fs8.existsSync(pidFile)) {
|
|
12810
13082
|
const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -12833,7 +13105,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
12833
13105
|
}
|
|
12834
13106
|
}
|
|
12835
13107
|
function removeDaemonPidFile() {
|
|
12836
|
-
const pidFile =
|
|
13108
|
+
const pidFile = path15.join(os15.homedir(), ".adhdev", "daemon.pid");
|
|
12837
13109
|
try {
|
|
12838
13110
|
fs8.unlinkSync(pidFile);
|
|
12839
13111
|
} catch {
|
|
@@ -12844,7 +13116,7 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
|
|
|
12844
13116
|
const npmRoot = execFileSync(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
|
|
12845
13117
|
if (!npmRoot) return;
|
|
12846
13118
|
const npmPrefix = execFileSync(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
|
|
12847
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
13119
|
+
const binDir = process.platform === "win32" ? npmPrefix : path15.join(npmPrefix, "bin");
|
|
12848
13120
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
12849
13121
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
12850
13122
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -12852,25 +13124,25 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
|
|
|
12852
13124
|
}
|
|
12853
13125
|
if (pkgName.startsWith("@")) {
|
|
12854
13126
|
const [scope, name] = pkgName.split("/");
|
|
12855
|
-
const scopeDir =
|
|
13127
|
+
const scopeDir = path15.join(npmRoot, scope);
|
|
12856
13128
|
if (!fs8.existsSync(scopeDir)) return;
|
|
12857
13129
|
for (const entry of fs8.readdirSync(scopeDir)) {
|
|
12858
13130
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
12859
|
-
fs8.rmSync(
|
|
12860
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
13131
|
+
fs8.rmSync(path15.join(scopeDir, entry), { recursive: true, force: true });
|
|
13132
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path15.join(scopeDir, entry)}`);
|
|
12861
13133
|
}
|
|
12862
13134
|
} else {
|
|
12863
13135
|
for (const entry of fs8.readdirSync(npmRoot)) {
|
|
12864
13136
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
12865
|
-
fs8.rmSync(
|
|
12866
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
13137
|
+
fs8.rmSync(path15.join(npmRoot, entry), { recursive: true, force: true });
|
|
13138
|
+
appendUpgradeLog(`Removed stale staging dir: ${path15.join(npmRoot, entry)}`);
|
|
12867
13139
|
}
|
|
12868
13140
|
}
|
|
12869
13141
|
if (fs8.existsSync(binDir)) {
|
|
12870
13142
|
for (const entry of fs8.readdirSync(binDir)) {
|
|
12871
13143
|
if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
12872
|
-
fs8.rmSync(
|
|
12873
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
13144
|
+
fs8.rmSync(path15.join(binDir, entry), { recursive: true, force: true });
|
|
13145
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path15.join(binDir, entry)}`);
|
|
12874
13146
|
}
|
|
12875
13147
|
}
|
|
12876
13148
|
}
|
|
@@ -12912,7 +13184,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
12912
13184
|
appendUpgradeLog(installOutput.trim());
|
|
12913
13185
|
}
|
|
12914
13186
|
if (process.platform === "win32") {
|
|
12915
|
-
await new Promise((
|
|
13187
|
+
await new Promise((resolve12) => setTimeout(resolve12, 500));
|
|
12916
13188
|
cleanupStaleGlobalInstallDirs(payload.packageName);
|
|
12917
13189
|
appendUpgradeLog("Post-install staging cleanup complete");
|
|
12918
13190
|
}
|
|
@@ -12956,6 +13228,25 @@ var CHAT_COMMANDS = [
|
|
|
12956
13228
|
"change_model"
|
|
12957
13229
|
];
|
|
12958
13230
|
var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
13231
|
+
function toHostedCliRuntimeDescriptor(record) {
|
|
13232
|
+
if (!record || typeof record !== "object") return null;
|
|
13233
|
+
const runtimeId = typeof record.sessionId === "string" ? record.sessionId : "";
|
|
13234
|
+
const cliType = typeof record.providerType === "string" ? record.providerType : "";
|
|
13235
|
+
const workspace = typeof record.workspace === "string" ? record.workspace : "";
|
|
13236
|
+
if (!runtimeId || !cliType || !workspace) return null;
|
|
13237
|
+
return {
|
|
13238
|
+
runtimeId,
|
|
13239
|
+
runtimeKey: typeof record.runtimeKey === "string" ? record.runtimeKey : void 0,
|
|
13240
|
+
displayName: typeof record.displayName === "string" ? record.displayName : void 0,
|
|
13241
|
+
workspaceLabel: typeof record.workspaceLabel === "string" ? record.workspaceLabel : void 0,
|
|
13242
|
+
lifecycle: typeof record.lifecycle === "string" ? record.lifecycle : void 0,
|
|
13243
|
+
recoveryState: typeof record.meta?.runtimeRecoveryState === "string" ? String(record.meta.runtimeRecoveryState) : null,
|
|
13244
|
+
cliType,
|
|
13245
|
+
workspace,
|
|
13246
|
+
cliArgs: Array.isArray(record.meta?.cliArgs) ? record.meta.cliArgs : [],
|
|
13247
|
+
providerSessionId: typeof record.meta?.providerSessionId === "string" ? String(record.meta.providerSessionId) : void 0
|
|
13248
|
+
};
|
|
13249
|
+
}
|
|
12959
13250
|
var DaemonCommandRouter = class {
|
|
12960
13251
|
deps;
|
|
12961
13252
|
constructor(deps) {
|
|
@@ -13029,6 +13320,90 @@ var DaemonCommandRouter = class {
|
|
|
13029
13320
|
return { success: false, error: e.message };
|
|
13030
13321
|
}
|
|
13031
13322
|
}
|
|
13323
|
+
case "session_host_get_diagnostics": {
|
|
13324
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13325
|
+
const diagnostics = await this.deps.sessionHostControl.getDiagnostics({
|
|
13326
|
+
includeSessions: args?.includeSessions !== false,
|
|
13327
|
+
limit: Number(args?.limit) || void 0
|
|
13328
|
+
});
|
|
13329
|
+
return { success: true, diagnostics };
|
|
13330
|
+
}
|
|
13331
|
+
case "session_host_list_sessions": {
|
|
13332
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13333
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
13334
|
+
return { success: true, sessions };
|
|
13335
|
+
}
|
|
13336
|
+
case "session_host_stop_session": {
|
|
13337
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13338
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13339
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13340
|
+
const record = await this.deps.sessionHostControl.stopSession(sessionId);
|
|
13341
|
+
return { success: true, record };
|
|
13342
|
+
}
|
|
13343
|
+
case "session_host_resume_session": {
|
|
13344
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13345
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13346
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13347
|
+
const record = await this.deps.sessionHostControl.resumeSession(sessionId);
|
|
13348
|
+
const hosted = toHostedCliRuntimeDescriptor(record);
|
|
13349
|
+
if (hosted) {
|
|
13350
|
+
await this.deps.cliManager.restoreHostedSessions([hosted]);
|
|
13351
|
+
}
|
|
13352
|
+
return { success: true, record };
|
|
13353
|
+
}
|
|
13354
|
+
case "session_host_restart_session": {
|
|
13355
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13356
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13357
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13358
|
+
const record = await this.deps.sessionHostControl.restartSession(sessionId);
|
|
13359
|
+
const hosted = toHostedCliRuntimeDescriptor(record);
|
|
13360
|
+
if (hosted) {
|
|
13361
|
+
await this.deps.cliManager.restoreHostedSessions([hosted]);
|
|
13362
|
+
}
|
|
13363
|
+
return { success: true, record };
|
|
13364
|
+
}
|
|
13365
|
+
case "session_host_send_signal": {
|
|
13366
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13367
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13368
|
+
const signal = typeof args?.signal === "string" ? args.signal : "";
|
|
13369
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13370
|
+
if (!signal) return { success: false, error: "signal required" };
|
|
13371
|
+
const record = await this.deps.sessionHostControl.sendSignal(sessionId, signal);
|
|
13372
|
+
return { success: true, record };
|
|
13373
|
+
}
|
|
13374
|
+
case "session_host_force_detach_client": {
|
|
13375
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13376
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13377
|
+
const clientId = typeof args?.clientId === "string" ? args.clientId : "";
|
|
13378
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13379
|
+
if (!clientId) return { success: false, error: "clientId required" };
|
|
13380
|
+
const record = await this.deps.sessionHostControl.forceDetachClient(sessionId, clientId);
|
|
13381
|
+
return { success: true, record };
|
|
13382
|
+
}
|
|
13383
|
+
case "session_host_acquire_write": {
|
|
13384
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13385
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13386
|
+
const clientId = typeof args?.clientId === "string" ? args.clientId : "";
|
|
13387
|
+
const ownerType = args?.ownerType === "agent" ? "agent" : "user";
|
|
13388
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13389
|
+
if (!clientId) return { success: false, error: "clientId required" };
|
|
13390
|
+
const record = await this.deps.sessionHostControl.acquireWrite({
|
|
13391
|
+
sessionId,
|
|
13392
|
+
clientId,
|
|
13393
|
+
ownerType,
|
|
13394
|
+
force: args?.force !== false
|
|
13395
|
+
});
|
|
13396
|
+
return { success: true, record };
|
|
13397
|
+
}
|
|
13398
|
+
case "session_host_release_write": {
|
|
13399
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13400
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13401
|
+
const clientId = typeof args?.clientId === "string" ? args.clientId : "";
|
|
13402
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13403
|
+
if (!clientId) return { success: false, error: "clientId required" };
|
|
13404
|
+
const record = await this.deps.sessionHostControl.releaseWrite({ sessionId, clientId });
|
|
13405
|
+
return { success: true, record };
|
|
13406
|
+
}
|
|
13032
13407
|
case "list_saved_sessions": {
|
|
13033
13408
|
const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : typeof args?.agentType === "string" ? args.agentType.trim() : "";
|
|
13034
13409
|
const kind = args?.kind === "acp" ? "acp" : "cli";
|
|
@@ -13087,6 +13462,12 @@ var DaemonCommandRouter = class {
|
|
|
13087
13462
|
if (!ideType) throw new Error("ideType required");
|
|
13088
13463
|
const killProcess = args?.killProcess !== false;
|
|
13089
13464
|
await this.stopIde(ideType, killProcess);
|
|
13465
|
+
try {
|
|
13466
|
+
const results = await detectIDEs(this.deps.providerLoader);
|
|
13467
|
+
this.deps.detectedIdes.value = results;
|
|
13468
|
+
this.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
13469
|
+
} catch {
|
|
13470
|
+
}
|
|
13090
13471
|
return { success: true, ideType, stopped: true, processKilled: killProcess };
|
|
13091
13472
|
}
|
|
13092
13473
|
// ─── IDE restart ───
|
|
@@ -13129,6 +13510,12 @@ var DaemonCommandRouter = class {
|
|
|
13129
13510
|
}
|
|
13130
13511
|
}
|
|
13131
13512
|
this.deps.onIdeConnected?.();
|
|
13513
|
+
try {
|
|
13514
|
+
const results = await detectIDEs(this.deps.providerLoader);
|
|
13515
|
+
this.deps.detectedIdes.value = results;
|
|
13516
|
+
this.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
13517
|
+
} catch {
|
|
13518
|
+
}
|
|
13132
13519
|
if (result.success && resolvedWorkspace) {
|
|
13133
13520
|
try {
|
|
13134
13521
|
const next = appendRecentActivity(loadState(), {
|
|
@@ -13156,8 +13543,9 @@ var DaemonCommandRouter = class {
|
|
|
13156
13543
|
}
|
|
13157
13544
|
// ─── Detect IDEs ───
|
|
13158
13545
|
case "detect_ides": {
|
|
13159
|
-
const results = await detectIDEs();
|
|
13546
|
+
const results = await detectIDEs(this.deps.providerLoader);
|
|
13160
13547
|
this.deps.detectedIdes.value = results;
|
|
13548
|
+
this.deps.providerLoader.setIdeDetectionResults(results, true);
|
|
13161
13549
|
return { success: true, detectedInfo: results };
|
|
13162
13550
|
}
|
|
13163
13551
|
// ─── Set User Name ───
|
|
@@ -13557,6 +13945,14 @@ var ProviderStreamAdapter = class {
|
|
|
13557
13945
|
hasScript(name) {
|
|
13558
13946
|
return typeof this.provider.scripts?.[name] === "function";
|
|
13559
13947
|
}
|
|
13948
|
+
parseMaybeJson(raw) {
|
|
13949
|
+
if (typeof raw !== "string") return raw;
|
|
13950
|
+
try {
|
|
13951
|
+
return JSON.parse(raw);
|
|
13952
|
+
} catch {
|
|
13953
|
+
return raw;
|
|
13954
|
+
}
|
|
13955
|
+
}
|
|
13560
13956
|
summarizeRaw(raw) {
|
|
13561
13957
|
try {
|
|
13562
13958
|
if (typeof raw === "string") return raw.replace(/\s+/g, " ").trim().slice(0, 240);
|
|
@@ -13617,12 +14013,30 @@ var ProviderStreamAdapter = class {
|
|
|
13617
14013
|
}
|
|
13618
14014
|
}
|
|
13619
14015
|
async sendMessage(evaluate, text) {
|
|
13620
|
-
const
|
|
14016
|
+
const params = { message: text };
|
|
14017
|
+
const script = this.callScript("sendMessage", params) || this.callScript("sendMessage", text);
|
|
13621
14018
|
if (!script) throw new Error(`[${this.agentName}] sendMessage script not available`);
|
|
13622
14019
|
const result = await evaluate(script);
|
|
13623
14020
|
if (result && typeof result === "string" && result.startsWith("error:")) {
|
|
13624
14021
|
throw new Error(`[${this.agentName}] sendMessage failed: ${result}`);
|
|
13625
14022
|
}
|
|
14023
|
+
const parsed = this.parseMaybeJson(result);
|
|
14024
|
+
if (parsed === true) return;
|
|
14025
|
+
if (typeof parsed === "string") {
|
|
14026
|
+
const normalized = parsed.trim().toLowerCase();
|
|
14027
|
+
if (normalized === "ok" || normalized === "sent" || normalized === "success" || normalized === "true") {
|
|
14028
|
+
return;
|
|
14029
|
+
}
|
|
14030
|
+
}
|
|
14031
|
+
if (parsed && typeof parsed === "object") {
|
|
14032
|
+
if (parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true) {
|
|
14033
|
+
return;
|
|
14034
|
+
}
|
|
14035
|
+
if (typeof parsed.error === "string" && parsed.error.trim()) {
|
|
14036
|
+
throw new Error(`[${this.agentName}] sendMessage failed: ${parsed.error}`);
|
|
14037
|
+
}
|
|
14038
|
+
}
|
|
14039
|
+
throw new Error(`[${this.agentName}] sendMessage was not confirmed`);
|
|
13626
14040
|
}
|
|
13627
14041
|
async resolveAction(evaluate, action, button) {
|
|
13628
14042
|
const script = this.callScript("resolveAction", { action, button });
|
|
@@ -13645,7 +14059,10 @@ var ProviderStreamAdapter = class {
|
|
|
13645
14059
|
const raw = await evaluate(script, 1e4);
|
|
13646
14060
|
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
13647
14061
|
if (data?.error) return [];
|
|
13648
|
-
|
|
14062
|
+
if (Array.isArray(data)) return data;
|
|
14063
|
+
if (Array.isArray(data?.sessions)) return data.sessions;
|
|
14064
|
+
if (Array.isArray(data?.chats)) return data.chats;
|
|
14065
|
+
return [];
|
|
13649
14066
|
} catch {
|
|
13650
14067
|
return [];
|
|
13651
14068
|
}
|
|
@@ -13653,7 +14070,17 @@ var ProviderStreamAdapter = class {
|
|
|
13653
14070
|
async switchSession(evaluate, sessionId) {
|
|
13654
14071
|
const script = this.callScript("switchSession", sessionId);
|
|
13655
14072
|
if (!script) return false;
|
|
13656
|
-
|
|
14073
|
+
const raw = await evaluate(script, 1e4);
|
|
14074
|
+
const data = this.parseMaybeJson(raw);
|
|
14075
|
+
if (data === true) return true;
|
|
14076
|
+
if (typeof data === "string") {
|
|
14077
|
+
const normalized = data.trim().toLowerCase();
|
|
14078
|
+
return normalized === "true" || normalized === "ok" || normalized === "switched" || normalized === "success";
|
|
14079
|
+
}
|
|
14080
|
+
if (data && typeof data === "object") {
|
|
14081
|
+
return data.switched === true || data.success === true || data.ok === true;
|
|
14082
|
+
}
|
|
14083
|
+
return false;
|
|
13657
14084
|
}
|
|
13658
14085
|
async focusEditor(evaluate) {
|
|
13659
14086
|
const script = this.callScript("focusEditor");
|
|
@@ -14343,11 +14770,11 @@ var ProviderInstanceManager = class {
|
|
|
14343
14770
|
|
|
14344
14771
|
// src/providers/version-archive.ts
|
|
14345
14772
|
import * as fs10 from "fs";
|
|
14346
|
-
import * as
|
|
14773
|
+
import * as path16 from "path";
|
|
14347
14774
|
import * as os16 from "os";
|
|
14348
14775
|
import { execSync as execSync5 } from "child_process";
|
|
14349
14776
|
import { platform as platform7 } from "os";
|
|
14350
|
-
var ARCHIVE_PATH =
|
|
14777
|
+
var ARCHIVE_PATH = path16.join(os16.homedir(), ".adhdev", "version-history.json");
|
|
14351
14778
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
14352
14779
|
var VersionArchive = class {
|
|
14353
14780
|
history = {};
|
|
@@ -14394,7 +14821,7 @@ var VersionArchive = class {
|
|
|
14394
14821
|
}
|
|
14395
14822
|
save() {
|
|
14396
14823
|
try {
|
|
14397
|
-
fs10.mkdirSync(
|
|
14824
|
+
fs10.mkdirSync(path16.dirname(ARCHIVE_PATH), { recursive: true });
|
|
14398
14825
|
fs10.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
14399
14826
|
} catch {
|
|
14400
14827
|
}
|
|
@@ -14435,7 +14862,7 @@ function checkPathExists2(paths) {
|
|
|
14435
14862
|
for (const p of paths) {
|
|
14436
14863
|
if (p.includes("*")) {
|
|
14437
14864
|
const home = os16.homedir();
|
|
14438
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
14865
|
+
const resolved = p.replace(/\*/g, home.split(path16.sep).pop() || "");
|
|
14439
14866
|
if (fs10.existsSync(resolved)) return resolved;
|
|
14440
14867
|
} else {
|
|
14441
14868
|
if (fs10.existsSync(p)) return p;
|
|
@@ -14445,7 +14872,7 @@ function checkPathExists2(paths) {
|
|
|
14445
14872
|
}
|
|
14446
14873
|
function getMacAppVersion(appPath) {
|
|
14447
14874
|
if (platform7() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
14448
|
-
const plistPath =
|
|
14875
|
+
const plistPath = path16.join(appPath, "Contents", "Info.plist");
|
|
14449
14876
|
if (!fs10.existsSync(plistPath)) return null;
|
|
14450
14877
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
14451
14878
|
return raw || null;
|
|
@@ -14472,7 +14899,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
14472
14899
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
14473
14900
|
let resolvedBin = cliBin;
|
|
14474
14901
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
14475
|
-
const bundled =
|
|
14902
|
+
const bundled = path16.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
14476
14903
|
if (provider.cli && fs10.existsSync(bundled)) resolvedBin = bundled;
|
|
14477
14904
|
}
|
|
14478
14905
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -14513,7 +14940,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
14513
14940
|
// src/daemon/dev-server.ts
|
|
14514
14941
|
import * as http2 from "http";
|
|
14515
14942
|
import * as fs14 from "fs";
|
|
14516
|
-
import * as
|
|
14943
|
+
import * as path20 from "path";
|
|
14517
14944
|
|
|
14518
14945
|
// src/daemon/scaffold-template.ts
|
|
14519
14946
|
function generateFiles(type, name, category, opts = {}) {
|
|
@@ -14850,7 +15277,7 @@ init_logger();
|
|
|
14850
15277
|
// src/daemon/dev-cdp-handlers.ts
|
|
14851
15278
|
init_logger();
|
|
14852
15279
|
import * as fs11 from "fs";
|
|
14853
|
-
import * as
|
|
15280
|
+
import * as path17 from "path";
|
|
14854
15281
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
14855
15282
|
const body = await ctx.readBody(req);
|
|
14856
15283
|
const { expression, timeout, ideType } = body;
|
|
@@ -15028,17 +15455,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
15028
15455
|
return;
|
|
15029
15456
|
}
|
|
15030
15457
|
let scriptsPath = "";
|
|
15031
|
-
const directScripts =
|
|
15458
|
+
const directScripts = path17.join(dir, "scripts.js");
|
|
15032
15459
|
if (fs11.existsSync(directScripts)) {
|
|
15033
15460
|
scriptsPath = directScripts;
|
|
15034
15461
|
} else {
|
|
15035
|
-
const scriptsDir =
|
|
15462
|
+
const scriptsDir = path17.join(dir, "scripts");
|
|
15036
15463
|
if (fs11.existsSync(scriptsDir)) {
|
|
15037
15464
|
const versions = fs11.readdirSync(scriptsDir).filter((d) => {
|
|
15038
|
-
return fs11.statSync(
|
|
15465
|
+
return fs11.statSync(path17.join(scriptsDir, d)).isDirectory();
|
|
15039
15466
|
}).sort().reverse();
|
|
15040
15467
|
for (const ver of versions) {
|
|
15041
|
-
const p =
|
|
15468
|
+
const p = path17.join(scriptsDir, ver, "scripts.js");
|
|
15042
15469
|
if (fs11.existsSync(p)) {
|
|
15043
15470
|
scriptsPath = p;
|
|
15044
15471
|
break;
|
|
@@ -15857,7 +16284,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
15857
16284
|
|
|
15858
16285
|
// src/daemon/dev-cli-debug.ts
|
|
15859
16286
|
import * as fs12 from "fs";
|
|
15860
|
-
import * as
|
|
16287
|
+
import * as path18 from "path";
|
|
15861
16288
|
function slugifyFixtureName(value) {
|
|
15862
16289
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
15863
16290
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -15867,11 +16294,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
15867
16294
|
if (!providerDir) {
|
|
15868
16295
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
15869
16296
|
}
|
|
15870
|
-
return
|
|
16297
|
+
return path18.join(providerDir, "fixtures");
|
|
15871
16298
|
}
|
|
15872
16299
|
function readCliFixture(ctx, type, name) {
|
|
15873
16300
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
15874
|
-
const filePath =
|
|
16301
|
+
const filePath = path18.join(fixtureDir, `${name}.json`);
|
|
15875
16302
|
if (!fs12.existsSync(filePath)) {
|
|
15876
16303
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
15877
16304
|
}
|
|
@@ -16031,7 +16458,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
16031
16458
|
return { target, instance, adapter };
|
|
16032
16459
|
}
|
|
16033
16460
|
function sleep(ms) {
|
|
16034
|
-
return new Promise((
|
|
16461
|
+
return new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
16035
16462
|
}
|
|
16036
16463
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
16037
16464
|
const startedAt = Date.now();
|
|
@@ -16630,7 +17057,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
16630
17057
|
},
|
|
16631
17058
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
16632
17059
|
};
|
|
16633
|
-
const filePath =
|
|
17060
|
+
const filePath = path18.join(fixtureDir, `${name}.json`);
|
|
16634
17061
|
fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
16635
17062
|
ctx.json(res, 200, {
|
|
16636
17063
|
saved: true,
|
|
@@ -16654,7 +17081,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
16654
17081
|
return;
|
|
16655
17082
|
}
|
|
16656
17083
|
const fixtures = fs12.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
16657
|
-
const fullPath =
|
|
17084
|
+
const fullPath = path18.join(fixtureDir, file);
|
|
16658
17085
|
try {
|
|
16659
17086
|
const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
|
|
16660
17087
|
return {
|
|
@@ -16790,7 +17217,7 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
16790
17217
|
|
|
16791
17218
|
// src/daemon/dev-auto-implement.ts
|
|
16792
17219
|
import * as fs13 from "fs";
|
|
16793
|
-
import * as
|
|
17220
|
+
import * as path19 from "path";
|
|
16794
17221
|
import * as os17 from "os";
|
|
16795
17222
|
function getAutoImplPid(ctx) {
|
|
16796
17223
|
const proc = ctx.autoImplProcess;
|
|
@@ -16830,22 +17257,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
16830
17257
|
if (!fs13.existsSync(scriptsDir)) return null;
|
|
16831
17258
|
const versions = fs13.readdirSync(scriptsDir).filter((d) => {
|
|
16832
17259
|
try {
|
|
16833
|
-
return fs13.statSync(
|
|
17260
|
+
return fs13.statSync(path19.join(scriptsDir, d)).isDirectory();
|
|
16834
17261
|
} catch {
|
|
16835
17262
|
return false;
|
|
16836
17263
|
}
|
|
16837
17264
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
16838
17265
|
if (versions.length === 0) return null;
|
|
16839
|
-
return
|
|
17266
|
+
return path19.join(scriptsDir, versions[0]);
|
|
16840
17267
|
}
|
|
16841
17268
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
16842
|
-
const canonicalUserDir =
|
|
16843
|
-
const desiredDir = requestedDir ?
|
|
16844
|
-
const upstreamRoot =
|
|
16845
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
17269
|
+
const canonicalUserDir = path19.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
17270
|
+
const desiredDir = requestedDir ? path19.resolve(requestedDir) : canonicalUserDir;
|
|
17271
|
+
const upstreamRoot = path19.resolve(ctx.providerLoader.getUpstreamDir());
|
|
17272
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path19.sep}`)) {
|
|
16846
17273
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
16847
17274
|
}
|
|
16848
|
-
if (
|
|
17275
|
+
if (path19.basename(desiredDir) !== type) {
|
|
16849
17276
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
16850
17277
|
}
|
|
16851
17278
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -16853,11 +17280,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
16853
17280
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
16854
17281
|
}
|
|
16855
17282
|
if (!fs13.existsSync(desiredDir)) {
|
|
16856
|
-
fs13.mkdirSync(
|
|
17283
|
+
fs13.mkdirSync(path19.dirname(desiredDir), { recursive: true });
|
|
16857
17284
|
fs13.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
16858
17285
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
16859
17286
|
}
|
|
16860
|
-
const providerJson =
|
|
17287
|
+
const providerJson = path19.join(desiredDir, "provider.json");
|
|
16861
17288
|
if (!fs13.existsSync(providerJson)) {
|
|
16862
17289
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
16863
17290
|
}
|
|
@@ -16880,13 +17307,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
16880
17307
|
const refDir = ctx.findProviderDir(referenceType);
|
|
16881
17308
|
if (!refDir || !fs13.existsSync(refDir)) return {};
|
|
16882
17309
|
const referenceScripts = {};
|
|
16883
|
-
const scriptsDir =
|
|
17310
|
+
const scriptsDir = path19.join(refDir, "scripts");
|
|
16884
17311
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
16885
17312
|
if (!latestDir) return referenceScripts;
|
|
16886
17313
|
for (const file of fs13.readdirSync(latestDir)) {
|
|
16887
17314
|
if (!file.endsWith(".js")) continue;
|
|
16888
17315
|
try {
|
|
16889
|
-
referenceScripts[file] = fs13.readFileSync(
|
|
17316
|
+
referenceScripts[file] = fs13.readFileSync(path19.join(latestDir, file), "utf-8");
|
|
16890
17317
|
} catch {
|
|
16891
17318
|
}
|
|
16892
17319
|
}
|
|
@@ -16994,9 +17421,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
16994
17421
|
});
|
|
16995
17422
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
16996
17423
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
16997
|
-
const tmpDir =
|
|
17424
|
+
const tmpDir = path19.join(os17.tmpdir(), "adhdev-autoimpl");
|
|
16998
17425
|
if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
|
|
16999
|
-
const promptFile =
|
|
17426
|
+
const promptFile = path19.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
17000
17427
|
fs13.writeFileSync(promptFile, prompt, "utf-8");
|
|
17001
17428
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
17002
17429
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -17423,7 +17850,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
17423
17850
|
setMode: "set_mode.js"
|
|
17424
17851
|
};
|
|
17425
17852
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
17426
|
-
const scriptsDir =
|
|
17853
|
+
const scriptsDir = path19.join(providerDir, "scripts");
|
|
17427
17854
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
17428
17855
|
if (latestScriptsDir) {
|
|
17429
17856
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -17434,7 +17861,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
17434
17861
|
for (const file of fs13.readdirSync(latestScriptsDir)) {
|
|
17435
17862
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
17436
17863
|
try {
|
|
17437
|
-
const content = fs13.readFileSync(
|
|
17864
|
+
const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
|
|
17438
17865
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
17439
17866
|
lines.push("```javascript");
|
|
17440
17867
|
lines.push(content);
|
|
@@ -17451,7 +17878,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
17451
17878
|
lines.push("");
|
|
17452
17879
|
for (const file of refFiles) {
|
|
17453
17880
|
try {
|
|
17454
|
-
const content = fs13.readFileSync(
|
|
17881
|
+
const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
|
|
17455
17882
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
17456
17883
|
lines.push("```javascript");
|
|
17457
17884
|
lines.push(content);
|
|
@@ -17492,10 +17919,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
17492
17919
|
lines.push("");
|
|
17493
17920
|
}
|
|
17494
17921
|
}
|
|
17495
|
-
const docsDir =
|
|
17922
|
+
const docsDir = path19.join(providerDir, "../../docs");
|
|
17496
17923
|
const loadGuide = (name) => {
|
|
17497
17924
|
try {
|
|
17498
|
-
const p =
|
|
17925
|
+
const p = path19.join(docsDir, name);
|
|
17499
17926
|
if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
|
|
17500
17927
|
} catch {
|
|
17501
17928
|
}
|
|
@@ -17730,7 +18157,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
17730
18157
|
parseApproval: "parse_approval.js"
|
|
17731
18158
|
};
|
|
17732
18159
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
17733
|
-
const scriptsDir =
|
|
18160
|
+
const scriptsDir = path19.join(providerDir, "scripts");
|
|
17734
18161
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
17735
18162
|
if (latestScriptsDir) {
|
|
17736
18163
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -17742,7 +18169,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
17742
18169
|
if (!file.endsWith(".js")) continue;
|
|
17743
18170
|
if (!targetFileNames.has(file)) continue;
|
|
17744
18171
|
try {
|
|
17745
|
-
const content = fs13.readFileSync(
|
|
18172
|
+
const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
|
|
17746
18173
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
17747
18174
|
lines.push("```javascript");
|
|
17748
18175
|
lines.push(content);
|
|
@@ -17758,7 +18185,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
17758
18185
|
lines.push("");
|
|
17759
18186
|
for (const file of refFiles) {
|
|
17760
18187
|
try {
|
|
17761
|
-
const content = fs13.readFileSync(
|
|
18188
|
+
const content = fs13.readFileSync(path19.join(latestScriptsDir, file), "utf-8");
|
|
17762
18189
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
17763
18190
|
lines.push("```javascript");
|
|
17764
18191
|
lines.push(content);
|
|
@@ -17791,10 +18218,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
17791
18218
|
lines.push("");
|
|
17792
18219
|
}
|
|
17793
18220
|
}
|
|
17794
|
-
const docsDir =
|
|
18221
|
+
const docsDir = path19.join(providerDir, "../../docs");
|
|
17795
18222
|
const loadGuide = (name) => {
|
|
17796
18223
|
try {
|
|
17797
|
-
const p =
|
|
18224
|
+
const p = path19.join(docsDir, name);
|
|
17798
18225
|
if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
|
|
17799
18226
|
} catch {
|
|
17800
18227
|
}
|
|
@@ -18205,8 +18632,8 @@ var DevServer = class _DevServer {
|
|
|
18205
18632
|
}
|
|
18206
18633
|
getEndpointList() {
|
|
18207
18634
|
return this.routes.map((r) => {
|
|
18208
|
-
const
|
|
18209
|
-
return `${r.method.padEnd(5)} ${
|
|
18635
|
+
const path21 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
18636
|
+
return `${r.method.padEnd(5)} ${path21}`;
|
|
18210
18637
|
});
|
|
18211
18638
|
}
|
|
18212
18639
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -18237,15 +18664,15 @@ var DevServer = class _DevServer {
|
|
|
18237
18664
|
this.json(res, 500, { error: e.message });
|
|
18238
18665
|
}
|
|
18239
18666
|
});
|
|
18240
|
-
return new Promise((
|
|
18667
|
+
return new Promise((resolve12, reject) => {
|
|
18241
18668
|
this.server.listen(port, "127.0.0.1", () => {
|
|
18242
18669
|
this.log(`Dev server listening on http://127.0.0.1:${port}`);
|
|
18243
|
-
|
|
18670
|
+
resolve12();
|
|
18244
18671
|
});
|
|
18245
18672
|
this.server.on("error", (e) => {
|
|
18246
18673
|
if (e.code === "EADDRINUSE") {
|
|
18247
18674
|
this.log(`Port ${port} in use, skipping dev server`);
|
|
18248
|
-
|
|
18675
|
+
resolve12();
|
|
18249
18676
|
} else {
|
|
18250
18677
|
reject(e);
|
|
18251
18678
|
}
|
|
@@ -18328,20 +18755,20 @@ var DevServer = class _DevServer {
|
|
|
18328
18755
|
child.stderr?.on("data", (d) => {
|
|
18329
18756
|
stderr += d.toString().slice(0, 2e3);
|
|
18330
18757
|
});
|
|
18331
|
-
await new Promise((
|
|
18758
|
+
await new Promise((resolve12) => {
|
|
18332
18759
|
const timer = setTimeout(() => {
|
|
18333
18760
|
child.kill();
|
|
18334
|
-
|
|
18761
|
+
resolve12();
|
|
18335
18762
|
}, 3e3);
|
|
18336
18763
|
child.on("exit", () => {
|
|
18337
18764
|
clearTimeout(timer);
|
|
18338
|
-
|
|
18765
|
+
resolve12();
|
|
18339
18766
|
});
|
|
18340
18767
|
child.stdout?.once("data", () => {
|
|
18341
18768
|
setTimeout(() => {
|
|
18342
18769
|
child.kill();
|
|
18343
18770
|
clearTimeout(timer);
|
|
18344
|
-
|
|
18771
|
+
resolve12();
|
|
18345
18772
|
}, 500);
|
|
18346
18773
|
});
|
|
18347
18774
|
});
|
|
@@ -18488,12 +18915,12 @@ var DevServer = class _DevServer {
|
|
|
18488
18915
|
// ─── DevConsole SPA ───
|
|
18489
18916
|
getConsoleDistDir() {
|
|
18490
18917
|
const candidates = [
|
|
18491
|
-
|
|
18492
|
-
|
|
18493
|
-
|
|
18918
|
+
path20.resolve(__dirname, "../../web-devconsole/dist"),
|
|
18919
|
+
path20.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
18920
|
+
path20.join(process.cwd(), "packages/web-devconsole/dist")
|
|
18494
18921
|
];
|
|
18495
18922
|
for (const dir of candidates) {
|
|
18496
|
-
if (fs14.existsSync(
|
|
18923
|
+
if (fs14.existsSync(path20.join(dir, "index.html"))) return dir;
|
|
18497
18924
|
}
|
|
18498
18925
|
return null;
|
|
18499
18926
|
}
|
|
@@ -18503,7 +18930,7 @@ var DevServer = class _DevServer {
|
|
|
18503
18930
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
18504
18931
|
return;
|
|
18505
18932
|
}
|
|
18506
|
-
const htmlPath =
|
|
18933
|
+
const htmlPath = path20.join(distDir, "index.html");
|
|
18507
18934
|
try {
|
|
18508
18935
|
const html = fs14.readFileSync(htmlPath, "utf-8");
|
|
18509
18936
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -18528,15 +18955,15 @@ var DevServer = class _DevServer {
|
|
|
18528
18955
|
this.json(res, 404, { error: "Not found" });
|
|
18529
18956
|
return;
|
|
18530
18957
|
}
|
|
18531
|
-
const safePath =
|
|
18532
|
-
const filePath =
|
|
18958
|
+
const safePath = path20.normalize(pathname).replace(/^\.\.\//, "");
|
|
18959
|
+
const filePath = path20.join(distDir, safePath);
|
|
18533
18960
|
if (!filePath.startsWith(distDir)) {
|
|
18534
18961
|
this.json(res, 403, { error: "Forbidden" });
|
|
18535
18962
|
return;
|
|
18536
18963
|
}
|
|
18537
18964
|
try {
|
|
18538
18965
|
const content = fs14.readFileSync(filePath);
|
|
18539
|
-
const ext =
|
|
18966
|
+
const ext = path20.extname(filePath);
|
|
18540
18967
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
18541
18968
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
18542
18969
|
res.end(content);
|
|
@@ -18649,9 +19076,9 @@ var DevServer = class _DevServer {
|
|
|
18649
19076
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
18650
19077
|
if (entry.isDirectory()) {
|
|
18651
19078
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
18652
|
-
scan(
|
|
19079
|
+
scan(path20.join(d, entry.name), rel);
|
|
18653
19080
|
} else {
|
|
18654
|
-
const stat = fs14.statSync(
|
|
19081
|
+
const stat = fs14.statSync(path20.join(d, entry.name));
|
|
18655
19082
|
files.push({ path: rel, size: stat.size, type: "file" });
|
|
18656
19083
|
}
|
|
18657
19084
|
}
|
|
@@ -18674,7 +19101,7 @@ var DevServer = class _DevServer {
|
|
|
18674
19101
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
18675
19102
|
return;
|
|
18676
19103
|
}
|
|
18677
|
-
const fullPath =
|
|
19104
|
+
const fullPath = path20.resolve(dir, path20.normalize(filePath));
|
|
18678
19105
|
if (!fullPath.startsWith(dir)) {
|
|
18679
19106
|
this.json(res, 403, { error: "Forbidden" });
|
|
18680
19107
|
return;
|
|
@@ -18699,14 +19126,14 @@ var DevServer = class _DevServer {
|
|
|
18699
19126
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
18700
19127
|
return;
|
|
18701
19128
|
}
|
|
18702
|
-
const fullPath =
|
|
19129
|
+
const fullPath = path20.resolve(dir, path20.normalize(filePath));
|
|
18703
19130
|
if (!fullPath.startsWith(dir)) {
|
|
18704
19131
|
this.json(res, 403, { error: "Forbidden" });
|
|
18705
19132
|
return;
|
|
18706
19133
|
}
|
|
18707
19134
|
try {
|
|
18708
19135
|
if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
|
|
18709
|
-
fs14.mkdirSync(
|
|
19136
|
+
fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
|
|
18710
19137
|
fs14.writeFileSync(fullPath, content, "utf-8");
|
|
18711
19138
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
18712
19139
|
this.providerLoader.reload();
|
|
@@ -18723,7 +19150,7 @@ var DevServer = class _DevServer {
|
|
|
18723
19150
|
return;
|
|
18724
19151
|
}
|
|
18725
19152
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
18726
|
-
const p =
|
|
19153
|
+
const p = path20.join(dir, name);
|
|
18727
19154
|
if (fs14.existsSync(p)) {
|
|
18728
19155
|
const source = fs14.readFileSync(p, "utf-8");
|
|
18729
19156
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -18744,8 +19171,8 @@ var DevServer = class _DevServer {
|
|
|
18744
19171
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
18745
19172
|
return;
|
|
18746
19173
|
}
|
|
18747
|
-
const target = fs14.existsSync(
|
|
18748
|
-
const targetPath =
|
|
19174
|
+
const target = fs14.existsSync(path20.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
19175
|
+
const targetPath = path20.join(dir, target);
|
|
18749
19176
|
try {
|
|
18750
19177
|
if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
|
|
18751
19178
|
fs14.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -18850,14 +19277,14 @@ var DevServer = class _DevServer {
|
|
|
18850
19277
|
child.stderr?.on("data", (d) => {
|
|
18851
19278
|
stderr += d.toString();
|
|
18852
19279
|
});
|
|
18853
|
-
await new Promise((
|
|
19280
|
+
await new Promise((resolve12) => {
|
|
18854
19281
|
const timer = setTimeout(() => {
|
|
18855
19282
|
child.kill();
|
|
18856
|
-
|
|
19283
|
+
resolve12();
|
|
18857
19284
|
}, timeout);
|
|
18858
19285
|
child.on("exit", () => {
|
|
18859
19286
|
clearTimeout(timer);
|
|
18860
|
-
|
|
19287
|
+
resolve12();
|
|
18861
19288
|
});
|
|
18862
19289
|
});
|
|
18863
19290
|
const elapsed = Date.now() - start;
|
|
@@ -18905,7 +19332,7 @@ var DevServer = class _DevServer {
|
|
|
18905
19332
|
}
|
|
18906
19333
|
let targetDir;
|
|
18907
19334
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
18908
|
-
const jsonPath =
|
|
19335
|
+
const jsonPath = path20.join(targetDir, "provider.json");
|
|
18909
19336
|
if (fs14.existsSync(jsonPath)) {
|
|
18910
19337
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
18911
19338
|
return;
|
|
@@ -18917,8 +19344,8 @@ var DevServer = class _DevServer {
|
|
|
18917
19344
|
const createdFiles = ["provider.json"];
|
|
18918
19345
|
if (result.files) {
|
|
18919
19346
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
18920
|
-
const fullPath =
|
|
18921
|
-
fs14.mkdirSync(
|
|
19347
|
+
const fullPath = path20.join(targetDir, relPath);
|
|
19348
|
+
fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
|
|
18922
19349
|
fs14.writeFileSync(fullPath, content, "utf-8");
|
|
18923
19350
|
createdFiles.push(relPath);
|
|
18924
19351
|
}
|
|
@@ -18971,22 +19398,22 @@ var DevServer = class _DevServer {
|
|
|
18971
19398
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
18972
19399
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
18973
19400
|
try {
|
|
18974
|
-
return fs14.statSync(
|
|
19401
|
+
return fs14.statSync(path20.join(scriptsDir, d)).isDirectory();
|
|
18975
19402
|
} catch {
|
|
18976
19403
|
return false;
|
|
18977
19404
|
}
|
|
18978
19405
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
18979
19406
|
if (versions.length === 0) return null;
|
|
18980
|
-
return
|
|
19407
|
+
return path20.join(scriptsDir, versions[0]);
|
|
18981
19408
|
}
|
|
18982
19409
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
18983
|
-
const canonicalUserDir =
|
|
18984
|
-
const desiredDir = requestedDir ?
|
|
18985
|
-
const upstreamRoot =
|
|
18986
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
19410
|
+
const canonicalUserDir = path20.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
19411
|
+
const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
|
|
19412
|
+
const upstreamRoot = path20.resolve(this.providerLoader.getUpstreamDir());
|
|
19413
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
|
|
18987
19414
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
18988
19415
|
}
|
|
18989
|
-
if (
|
|
19416
|
+
if (path20.basename(desiredDir) !== type) {
|
|
18990
19417
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
18991
19418
|
}
|
|
18992
19419
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -18994,11 +19421,11 @@ var DevServer = class _DevServer {
|
|
|
18994
19421
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
18995
19422
|
}
|
|
18996
19423
|
if (!fs14.existsSync(desiredDir)) {
|
|
18997
|
-
fs14.mkdirSync(
|
|
19424
|
+
fs14.mkdirSync(path20.dirname(desiredDir), { recursive: true });
|
|
18998
19425
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
18999
19426
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
19000
19427
|
}
|
|
19001
|
-
const providerJson =
|
|
19428
|
+
const providerJson = path20.join(desiredDir, "provider.json");
|
|
19002
19429
|
if (!fs14.existsSync(providerJson)) {
|
|
19003
19430
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
19004
19431
|
}
|
|
@@ -19046,7 +19473,7 @@ var DevServer = class _DevServer {
|
|
|
19046
19473
|
setMode: "set_mode.js"
|
|
19047
19474
|
};
|
|
19048
19475
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
19049
|
-
const scriptsDir =
|
|
19476
|
+
const scriptsDir = path20.join(providerDir, "scripts");
|
|
19050
19477
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
19051
19478
|
if (latestScriptsDir) {
|
|
19052
19479
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -19057,7 +19484,7 @@ var DevServer = class _DevServer {
|
|
|
19057
19484
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
19058
19485
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
19059
19486
|
try {
|
|
19060
|
-
const content = fs14.readFileSync(
|
|
19487
|
+
const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
|
|
19061
19488
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
19062
19489
|
lines.push("```javascript");
|
|
19063
19490
|
lines.push(content);
|
|
@@ -19074,7 +19501,7 @@ var DevServer = class _DevServer {
|
|
|
19074
19501
|
lines.push("");
|
|
19075
19502
|
for (const file of refFiles) {
|
|
19076
19503
|
try {
|
|
19077
|
-
const content = fs14.readFileSync(
|
|
19504
|
+
const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
|
|
19078
19505
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
19079
19506
|
lines.push("```javascript");
|
|
19080
19507
|
lines.push(content);
|
|
@@ -19115,10 +19542,10 @@ var DevServer = class _DevServer {
|
|
|
19115
19542
|
lines.push("");
|
|
19116
19543
|
}
|
|
19117
19544
|
}
|
|
19118
|
-
const docsDir =
|
|
19545
|
+
const docsDir = path20.join(providerDir, "../../docs");
|
|
19119
19546
|
const loadGuide = (name) => {
|
|
19120
19547
|
try {
|
|
19121
|
-
const p =
|
|
19548
|
+
const p = path20.join(docsDir, name);
|
|
19122
19549
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
19123
19550
|
} catch {
|
|
19124
19551
|
}
|
|
@@ -19292,7 +19719,7 @@ var DevServer = class _DevServer {
|
|
|
19292
19719
|
parseApproval: "parse_approval.js"
|
|
19293
19720
|
};
|
|
19294
19721
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
19295
|
-
const scriptsDir =
|
|
19722
|
+
const scriptsDir = path20.join(providerDir, "scripts");
|
|
19296
19723
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
19297
19724
|
if (latestScriptsDir) {
|
|
19298
19725
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -19304,7 +19731,7 @@ var DevServer = class _DevServer {
|
|
|
19304
19731
|
if (!file.endsWith(".js")) continue;
|
|
19305
19732
|
if (!targetFileNames.has(file)) continue;
|
|
19306
19733
|
try {
|
|
19307
|
-
const content = fs14.readFileSync(
|
|
19734
|
+
const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
|
|
19308
19735
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
19309
19736
|
lines.push("```javascript");
|
|
19310
19737
|
lines.push(content);
|
|
@@ -19320,7 +19747,7 @@ var DevServer = class _DevServer {
|
|
|
19320
19747
|
lines.push("");
|
|
19321
19748
|
for (const file of refFiles) {
|
|
19322
19749
|
try {
|
|
19323
|
-
const content = fs14.readFileSync(
|
|
19750
|
+
const content = fs14.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
|
|
19324
19751
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
19325
19752
|
lines.push("```javascript");
|
|
19326
19753
|
lines.push(content);
|
|
@@ -19353,10 +19780,10 @@ var DevServer = class _DevServer {
|
|
|
19353
19780
|
lines.push("");
|
|
19354
19781
|
}
|
|
19355
19782
|
}
|
|
19356
|
-
const docsDir =
|
|
19783
|
+
const docsDir = path20.join(providerDir, "../../docs");
|
|
19357
19784
|
const loadGuide = (name) => {
|
|
19358
19785
|
try {
|
|
19359
|
-
const p =
|
|
19786
|
+
const p = path20.join(docsDir, name);
|
|
19360
19787
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
19361
19788
|
} catch {
|
|
19362
19789
|
}
|
|
@@ -19532,14 +19959,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
19532
19959
|
res.end(JSON.stringify(data, null, 2));
|
|
19533
19960
|
}
|
|
19534
19961
|
async readBody(req) {
|
|
19535
|
-
return new Promise((
|
|
19962
|
+
return new Promise((resolve12) => {
|
|
19536
19963
|
let body = "";
|
|
19537
19964
|
req.on("data", (chunk) => body += chunk);
|
|
19538
19965
|
req.on("end", () => {
|
|
19539
19966
|
try {
|
|
19540
|
-
|
|
19967
|
+
resolve12(JSON.parse(body));
|
|
19541
19968
|
} catch {
|
|
19542
|
-
|
|
19969
|
+
resolve12({});
|
|
19543
19970
|
}
|
|
19544
19971
|
});
|
|
19545
19972
|
});
|
|
@@ -19875,6 +20302,7 @@ var SessionHostRuntimeTransport = class {
|
|
|
19875
20302
|
}
|
|
19876
20303
|
}
|
|
19877
20304
|
handleEvent(event) {
|
|
20305
|
+
if (!("sessionId" in event)) return;
|
|
19878
20306
|
if (event.sessionId !== this.options.runtimeId) return;
|
|
19879
20307
|
if ((event.type === "session_started" || event.type === "session_resumed") && typeof event.pid === "number") {
|
|
19880
20308
|
this.currentPid = event.pid;
|
|
@@ -19950,7 +20378,10 @@ var SessionHostRuntimeTransport = class {
|
|
|
19950
20378
|
clientId: client.clientId,
|
|
19951
20379
|
type: client.type,
|
|
19952
20380
|
readOnly: client.readOnly
|
|
19953
|
-
}))
|
|
20381
|
+
})),
|
|
20382
|
+
restoredFromStorage: record.meta?.restoredFromStorage === true,
|
|
20383
|
+
recoveryState: typeof record.meta?.runtimeRecoveryState === "string" ? String(record.meta.runtimeRecoveryState) : null,
|
|
20384
|
+
recoveryError: typeof record.meta?.runtimeRecoveryError === "string" ? String(record.meta.runtimeRecoveryError) : null
|
|
19954
20385
|
};
|
|
19955
20386
|
}
|
|
19956
20387
|
enqueue(action) {
|
|
@@ -20008,7 +20439,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
|
20008
20439
|
const deadline = Date.now() + timeoutMs;
|
|
20009
20440
|
while (Date.now() < deadline) {
|
|
20010
20441
|
if (await canConnect(endpoint)) return;
|
|
20011
|
-
await new Promise((
|
|
20442
|
+
await new Promise((resolve12) => setTimeout(resolve12, STARTUP_POLL_MS));
|
|
20012
20443
|
}
|
|
20013
20444
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
20014
20445
|
}
|
|
@@ -20164,10 +20595,10 @@ async function installExtension(ide, extension) {
|
|
|
20164
20595
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
20165
20596
|
const fs15 = await import("fs");
|
|
20166
20597
|
fs15.writeFileSync(vsixPath, buffer);
|
|
20167
|
-
return new Promise((
|
|
20598
|
+
return new Promise((resolve12) => {
|
|
20168
20599
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
20169
20600
|
exec2(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
20170
|
-
|
|
20601
|
+
resolve12({
|
|
20171
20602
|
extensionId: extension.id,
|
|
20172
20603
|
marketplaceId: extension.marketplaceId,
|
|
20173
20604
|
success: !error,
|
|
@@ -20180,11 +20611,11 @@ async function installExtension(ide, extension) {
|
|
|
20180
20611
|
} catch (e) {
|
|
20181
20612
|
}
|
|
20182
20613
|
}
|
|
20183
|
-
return new Promise((
|
|
20614
|
+
return new Promise((resolve12) => {
|
|
20184
20615
|
const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
|
|
20185
20616
|
exec2(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
|
|
20186
20617
|
if (error) {
|
|
20187
|
-
|
|
20618
|
+
resolve12({
|
|
20188
20619
|
extensionId: extension.id,
|
|
20189
20620
|
marketplaceId: extension.marketplaceId,
|
|
20190
20621
|
success: false,
|
|
@@ -20192,7 +20623,7 @@ async function installExtension(ide, extension) {
|
|
|
20192
20623
|
error: stderr || error.message
|
|
20193
20624
|
});
|
|
20194
20625
|
} else {
|
|
20195
|
-
|
|
20626
|
+
resolve12({
|
|
20196
20627
|
extensionId: extension.id,
|
|
20197
20628
|
marketplaceId: extension.marketplaceId,
|
|
20198
20629
|
success: true,
|
|
@@ -20328,13 +20759,32 @@ async function initDaemonComponents(config) {
|
|
|
20328
20759
|
const detectedIdesRef = { value: [] };
|
|
20329
20760
|
let agentStreamManager = null;
|
|
20330
20761
|
let poller = null;
|
|
20762
|
+
const refreshProviderAvailability = async (providerType) => {
|
|
20763
|
+
const targetProvider = providerType ? providerLoader.getMeta(providerLoader.resolveAlias(providerType)) : null;
|
|
20764
|
+
const targetCategory = targetProvider?.category;
|
|
20765
|
+
if (!providerType || targetCategory === "cli" || targetCategory === "acp") {
|
|
20766
|
+
if (providerType && targetProvider) {
|
|
20767
|
+
const detected = await detectCLI(targetProvider.type, providerLoader, { includeVersion: false });
|
|
20768
|
+
providerLoader.setProviderAvailability(targetProvider.type, {
|
|
20769
|
+
installed: !!detected,
|
|
20770
|
+
detectedPath: detected?.path || null
|
|
20771
|
+
});
|
|
20772
|
+
} else {
|
|
20773
|
+
providerLoader.setCliDetectionResults(await detectCLIs(providerLoader, { includeVersion: false }), true);
|
|
20774
|
+
}
|
|
20775
|
+
}
|
|
20776
|
+
if (!providerType || targetCategory === "ide") {
|
|
20777
|
+
detectedIdesRef.value = await detectIDEs(providerLoader);
|
|
20778
|
+
providerLoader.setIdeDetectionResults(detectedIdesRef.value, true);
|
|
20779
|
+
}
|
|
20780
|
+
};
|
|
20331
20781
|
const cliManager = new DaemonCliManager({
|
|
20332
20782
|
...config.cliManagerDeps,
|
|
20333
20783
|
getInstanceManager: () => instanceManager,
|
|
20334
20784
|
getSessionRegistry: () => sessionRegistry
|
|
20335
20785
|
}, providerLoader);
|
|
20336
20786
|
LOG.info("Init", "Detecting IDEs...");
|
|
20337
|
-
|
|
20787
|
+
await refreshProviderAvailability();
|
|
20338
20788
|
const installed = detectedIdesRef.value.filter((i) => i.installed);
|
|
20339
20789
|
LOG.info("Init", `Found ${installed.length} IDE(s): ${installed.map((i) => i.id).join(", ") || "none"}`);
|
|
20340
20790
|
const cdpSetupContext = {
|
|
@@ -20374,7 +20824,11 @@ async function initDaemonComponents(config) {
|
|
|
20374
20824
|
adapters: cliManager.adapters,
|
|
20375
20825
|
providerLoader,
|
|
20376
20826
|
instanceManager,
|
|
20377
|
-
sessionRegistry
|
|
20827
|
+
sessionRegistry,
|
|
20828
|
+
onProviderSettingChanged: async (providerType) => {
|
|
20829
|
+
await refreshProviderAvailability(providerType);
|
|
20830
|
+
config.onStatusChange?.();
|
|
20831
|
+
}
|
|
20378
20832
|
});
|
|
20379
20833
|
agentStreamManager = new DaemonAgentStreamManager(
|
|
20380
20834
|
LOG.forComponent("AgentStream").asLogFn(),
|
|
@@ -20397,6 +20851,7 @@ async function initDaemonComponents(config) {
|
|
|
20397
20851
|
onIdeConnected: () => poller?.start(),
|
|
20398
20852
|
onStatusChange: config.onStatusChange,
|
|
20399
20853
|
onPostChatCommand: config.onPostChatCommand,
|
|
20854
|
+
sessionHostControl: config.sessionHostControl,
|
|
20400
20855
|
getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
|
|
20401
20856
|
});
|
|
20402
20857
|
poller = new AgentStreamPoller({
|