@adhdev/daemon-core 0.5.3 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +88 -2
- package/dist/index.js +1230 -439
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/providers/_builtin/extension/cline/scripts/read_chat.js +14 -1
- package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +24 -1
- package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +24 -1
- package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +3 -3
- package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +1 -1
- package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +1 -1
- package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +4 -4
- package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +5 -1
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/dismiss_notification.js +30 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/focus_editor.js +13 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_models.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_modes.js +40 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_notifications.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_sessions.js +42 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/new_session.js +20 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/open_panel.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/read_chat.js +79 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/resolve_action.js +19 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/scripts.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/send_message.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/set_mode.js +38 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/set_model.js +81 -0
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/switch_session.js +28 -0
- package/providers/_builtin/ide/windsurf/scripts/read_chat.js +18 -1
- package/src/cli-adapters/provider-cli-adapter.ts +231 -12
- package/src/commands/chat-commands.ts +36 -0
- package/src/commands/cli-manager.ts +128 -30
- package/src/commands/handler.ts +47 -3
- package/src/commands/router.ts +32 -2
- package/src/commands/workspace-commands.ts +108 -0
- package/src/config/config.ts +29 -1
- package/src/config/workspace-activity.ts +65 -0
- package/src/config/workspaces.ts +250 -0
- package/src/daemon/dev-server.ts +1 -1
- package/src/index.ts +5 -0
- package/src/launch.ts +1 -1
- package/src/providers/cli-provider-instance.ts +7 -2
- package/src/providers/ide-provider-instance.ts +11 -0
- package/src/status/reporter.ts +23 -4
- package/src/system/host-memory.ts +65 -0
- package/src/types.ts +8 -1
package/dist/index.js
CHANGED
|
@@ -30,6 +30,188 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
+
// src/config/workspaces.ts
|
|
34
|
+
function expandPath(p) {
|
|
35
|
+
const t = (p || "").trim();
|
|
36
|
+
if (!t) return "";
|
|
37
|
+
if (t.startsWith("~")) return path.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
38
|
+
return path.resolve(t);
|
|
39
|
+
}
|
|
40
|
+
function validateWorkspacePath(absPath) {
|
|
41
|
+
try {
|
|
42
|
+
if (!absPath) return { ok: false, error: "Path required" };
|
|
43
|
+
if (!fs.existsSync(absPath)) return { ok: false, error: "Path does not exist" };
|
|
44
|
+
const st = fs.statSync(absPath);
|
|
45
|
+
if (!st.isDirectory()) return { ok: false, error: "Not a directory" };
|
|
46
|
+
return { ok: true };
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return { ok: false, error: e?.message || "Invalid path" };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function defaultWorkspaceLabel(absPath) {
|
|
52
|
+
const base = path.basename(absPath) || absPath;
|
|
53
|
+
return base;
|
|
54
|
+
}
|
|
55
|
+
function migrateWorkspacesFromRecent(config) {
|
|
56
|
+
if (!config.workspaces) config.workspaces = [];
|
|
57
|
+
if (config.workspaces.length > 0) return config;
|
|
58
|
+
const recent = config.recentCliWorkspaces || [];
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
for (const raw of recent) {
|
|
61
|
+
const abs = expandPath(raw);
|
|
62
|
+
if (!abs || validateWorkspacePath(abs).ok !== true) continue;
|
|
63
|
+
if (config.workspaces.some((w) => path.resolve(w.path) === abs)) continue;
|
|
64
|
+
config.workspaces.push({
|
|
65
|
+
id: (0, import_crypto.randomUUID)(),
|
|
66
|
+
path: abs,
|
|
67
|
+
label: defaultWorkspaceLabel(abs),
|
|
68
|
+
addedAt: now
|
|
69
|
+
});
|
|
70
|
+
if (config.workspaces.length >= MAX_WORKSPACES) break;
|
|
71
|
+
}
|
|
72
|
+
return config;
|
|
73
|
+
}
|
|
74
|
+
function getDefaultWorkspacePath(config) {
|
|
75
|
+
const id = config.defaultWorkspaceId;
|
|
76
|
+
if (!id) return null;
|
|
77
|
+
const w = (config.workspaces || []).find((x) => x.id === id);
|
|
78
|
+
if (!w) return null;
|
|
79
|
+
const abs = expandPath(w.path);
|
|
80
|
+
if (validateWorkspacePath(abs).ok !== true) return null;
|
|
81
|
+
return abs;
|
|
82
|
+
}
|
|
83
|
+
function getWorkspaceState(config) {
|
|
84
|
+
const workspaces = [...config.workspaces || []].sort((a, b) => b.addedAt - a.addedAt);
|
|
85
|
+
const defaultWorkspacePath = getDefaultWorkspacePath(config);
|
|
86
|
+
return {
|
|
87
|
+
workspaces,
|
|
88
|
+
defaultWorkspaceId: config.defaultWorkspaceId ?? null,
|
|
89
|
+
defaultWorkspacePath
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function resolveLaunchDirectory(args, config) {
|
|
93
|
+
const a = args || {};
|
|
94
|
+
if (a.dir != null && String(a.dir).trim()) {
|
|
95
|
+
const abs = expandPath(String(a.dir).trim());
|
|
96
|
+
if (abs && validateWorkspacePath(abs).ok === true) {
|
|
97
|
+
return { ok: true, path: abs, source: "dir" };
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
ok: false,
|
|
101
|
+
code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
|
|
102
|
+
message: abs ? "Directory path is not valid or does not exist" : "Invalid directory path"
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (a.workspaceId) {
|
|
106
|
+
const w = (config.workspaces || []).find((x) => x.id === a.workspaceId);
|
|
107
|
+
if (w) {
|
|
108
|
+
const abs = expandPath(w.path);
|
|
109
|
+
if (validateWorkspacePath(abs).ok === true) {
|
|
110
|
+
return { ok: true, path: abs, source: "workspaceId" };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
|
|
116
|
+
message: "Saved workspace not found or path is no longer valid"
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (a.useDefaultWorkspace === true) {
|
|
120
|
+
const d = getDefaultWorkspacePath(config);
|
|
121
|
+
if (d) return { ok: true, path: d, source: "defaultWorkspace" };
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
|
|
125
|
+
message: "No default workspace is set"
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (a.useHome === true) {
|
|
129
|
+
return { ok: true, path: os.homedir(), source: "home" };
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
code: "WORKSPACE_LAUNCH_CONTEXT_REQUIRED",
|
|
134
|
+
message: "Choose a directory, saved workspace, default workspace, or home before launching."
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function resolveIdeWorkspaceFromArgs(args, config) {
|
|
138
|
+
const ar = args || {};
|
|
139
|
+
if (ar.workspace) {
|
|
140
|
+
const abs = expandPath(ar.workspace);
|
|
141
|
+
if (abs && validateWorkspacePath(abs).ok === true) return abs;
|
|
142
|
+
}
|
|
143
|
+
if (ar.workspaceId) {
|
|
144
|
+
const w = (config.workspaces || []).find((x) => x.id === ar.workspaceId);
|
|
145
|
+
if (w) {
|
|
146
|
+
const abs = expandPath(w.path);
|
|
147
|
+
if (validateWorkspacePath(abs).ok === true) return abs;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (ar.useDefaultWorkspace === true) {
|
|
151
|
+
return getDefaultWorkspacePath(config) || void 0;
|
|
152
|
+
}
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
function resolveIdeLaunchWorkspace(args, config) {
|
|
156
|
+
const direct = resolveIdeWorkspaceFromArgs(args, config);
|
|
157
|
+
if (direct) return direct;
|
|
158
|
+
if (args?.useDefaultWorkspace === false) return void 0;
|
|
159
|
+
return getDefaultWorkspacePath(config) || void 0;
|
|
160
|
+
}
|
|
161
|
+
function findWorkspaceByPath(config, rawPath) {
|
|
162
|
+
const abs = path.resolve(expandPath(rawPath));
|
|
163
|
+
if (!abs) return void 0;
|
|
164
|
+
return (config.workspaces || []).find((w) => path.resolve(expandPath(w.path)) === abs);
|
|
165
|
+
}
|
|
166
|
+
function addWorkspaceEntry(config, rawPath, label) {
|
|
167
|
+
const abs = expandPath(rawPath);
|
|
168
|
+
const v = validateWorkspacePath(abs);
|
|
169
|
+
if (!v.ok) return { error: v.error };
|
|
170
|
+
const list = [...config.workspaces || []];
|
|
171
|
+
if (list.some((w) => path.resolve(w.path) === abs)) {
|
|
172
|
+
return { error: "Workspace already in list" };
|
|
173
|
+
}
|
|
174
|
+
if (list.length >= MAX_WORKSPACES) {
|
|
175
|
+
return { error: `Maximum ${MAX_WORKSPACES} workspaces` };
|
|
176
|
+
}
|
|
177
|
+
const entry = {
|
|
178
|
+
id: (0, import_crypto.randomUUID)(),
|
|
179
|
+
path: abs,
|
|
180
|
+
label: (label || "").trim() || defaultWorkspaceLabel(abs),
|
|
181
|
+
addedAt: Date.now()
|
|
182
|
+
};
|
|
183
|
+
list.push(entry);
|
|
184
|
+
return { config: { ...config, workspaces: list }, entry };
|
|
185
|
+
}
|
|
186
|
+
function removeWorkspaceEntry(config, id) {
|
|
187
|
+
const list = (config.workspaces || []).filter((w) => w.id !== id);
|
|
188
|
+
if (list.length === (config.workspaces || []).length) return { error: "Workspace not found" };
|
|
189
|
+
let defaultWorkspaceId = config.defaultWorkspaceId;
|
|
190
|
+
if (defaultWorkspaceId === id) defaultWorkspaceId = null;
|
|
191
|
+
return { config: { ...config, workspaces: list, defaultWorkspaceId } };
|
|
192
|
+
}
|
|
193
|
+
function setDefaultWorkspaceId(config, id) {
|
|
194
|
+
if (id === null) {
|
|
195
|
+
return { config: { ...config, defaultWorkspaceId: null } };
|
|
196
|
+
}
|
|
197
|
+
const w = (config.workspaces || []).find((x) => x.id === id);
|
|
198
|
+
if (!w) return { error: "Workspace not found" };
|
|
199
|
+
const abs = expandPath(w.path);
|
|
200
|
+
if (validateWorkspacePath(abs).ok !== true) return { error: "Workspace path is no longer valid" };
|
|
201
|
+
return { config: { ...config, defaultWorkspaceId: id } };
|
|
202
|
+
}
|
|
203
|
+
var fs, os, path, import_crypto, MAX_WORKSPACES;
|
|
204
|
+
var init_workspaces = __esm({
|
|
205
|
+
"src/config/workspaces.ts"() {
|
|
206
|
+
"use strict";
|
|
207
|
+
fs = __toESM(require("fs"));
|
|
208
|
+
os = __toESM(require("os"));
|
|
209
|
+
path = __toESM(require("path"));
|
|
210
|
+
import_crypto = require("crypto");
|
|
211
|
+
MAX_WORKSPACES = 50;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
33
215
|
// src/config/config.ts
|
|
34
216
|
var config_exports = {};
|
|
35
217
|
__export(config_exports, {
|
|
@@ -61,7 +243,20 @@ function loadConfig() {
|
|
|
61
243
|
try {
|
|
62
244
|
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
63
245
|
const parsed = JSON.parse(raw);
|
|
64
|
-
|
|
246
|
+
const merged = { ...DEFAULT_CONFIG, ...parsed };
|
|
247
|
+
if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
|
|
248
|
+
merged.defaultWorkspaceId = merged.activeWorkspaceId;
|
|
249
|
+
}
|
|
250
|
+
delete merged.activeWorkspaceId;
|
|
251
|
+
const hadStoredWorkspaces = Array.isArray(parsed.workspaces) && parsed.workspaces.length > 0;
|
|
252
|
+
migrateWorkspacesFromRecent(merged);
|
|
253
|
+
if (!hadStoredWorkspaces && (merged.workspaces?.length || 0) > 0) {
|
|
254
|
+
try {
|
|
255
|
+
saveConfig(merged);
|
|
256
|
+
} catch {
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return merged;
|
|
65
260
|
} catch {
|
|
66
261
|
return { ...DEFAULT_CONFIG };
|
|
67
262
|
}
|
|
@@ -132,6 +327,7 @@ var init_config = __esm({
|
|
|
132
327
|
import_os = require("os");
|
|
133
328
|
import_path = require("path");
|
|
134
329
|
import_fs = require("fs");
|
|
330
|
+
init_workspaces();
|
|
135
331
|
DEFAULT_CONFIG = {
|
|
136
332
|
serverUrl: "https://api.adhf.dev",
|
|
137
333
|
apiToken: null,
|
|
@@ -148,6 +344,9 @@ var init_config = __esm({
|
|
|
148
344
|
configuredCLIs: [],
|
|
149
345
|
enabledIdes: [],
|
|
150
346
|
recentCliWorkspaces: [],
|
|
347
|
+
workspaces: [],
|
|
348
|
+
defaultWorkspaceId: null,
|
|
349
|
+
recentWorkspaceActivity: [],
|
|
151
350
|
machineNickname: null,
|
|
152
351
|
cliHistory: [],
|
|
153
352
|
providerSettings: {},
|
|
@@ -187,9 +386,12 @@ __export(index_exports, {
|
|
|
187
386
|
detectIDEs: () => detectIDEs,
|
|
188
387
|
getAIExtensions: () => getAIExtensions,
|
|
189
388
|
getAvailableIdeIds: () => getAvailableIdeIds,
|
|
389
|
+
getHostMemorySnapshot: () => getHostMemorySnapshot,
|
|
190
390
|
getLogLevel: () => getLogLevel,
|
|
191
391
|
getRecentCommands: () => getRecentCommands,
|
|
192
392
|
getRecentLogs: () => getRecentLogs,
|
|
393
|
+
getWorkspaceActivity: () => getWorkspaceActivity,
|
|
394
|
+
getWorkspaceState: () => getWorkspaceState,
|
|
193
395
|
initDaemonComponents: () => initDaemonComponents,
|
|
194
396
|
installExtensions: () => installExtensions,
|
|
195
397
|
installGlobalInterceptor: () => installGlobalInterceptor,
|
|
@@ -212,6 +414,47 @@ __export(index_exports, {
|
|
|
212
414
|
});
|
|
213
415
|
module.exports = __toCommonJS(index_exports);
|
|
214
416
|
init_config();
|
|
417
|
+
init_workspaces();
|
|
418
|
+
|
|
419
|
+
// src/config/workspace-activity.ts
|
|
420
|
+
var path2 = __toESM(require("path"));
|
|
421
|
+
init_workspaces();
|
|
422
|
+
var MAX_ACTIVITY = 30;
|
|
423
|
+
function normWorkspacePath(p) {
|
|
424
|
+
try {
|
|
425
|
+
return path2.resolve(expandPath(p));
|
|
426
|
+
} catch {
|
|
427
|
+
return path2.resolve(p);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function appendWorkspaceActivity(config, rawPath, meta) {
|
|
431
|
+
const abs = normWorkspacePath(rawPath);
|
|
432
|
+
if (!abs) return config;
|
|
433
|
+
const prev = config.recentWorkspaceActivity || [];
|
|
434
|
+
const filtered = prev.filter((e) => normWorkspacePath(e.path) !== abs);
|
|
435
|
+
const entry = {
|
|
436
|
+
path: abs,
|
|
437
|
+
lastUsedAt: Date.now(),
|
|
438
|
+
kind: meta?.kind,
|
|
439
|
+
agentType: meta?.agentType
|
|
440
|
+
};
|
|
441
|
+
const recentWorkspaceActivity = [entry, ...filtered].slice(0, MAX_ACTIVITY);
|
|
442
|
+
return { ...config, recentWorkspaceActivity };
|
|
443
|
+
}
|
|
444
|
+
function getWorkspaceActivity(config, limit = 20) {
|
|
445
|
+
const list = [...config.recentWorkspaceActivity || []];
|
|
446
|
+
list.sort((a, b) => b.lastUsedAt - a.lastUsedAt);
|
|
447
|
+
return list.slice(0, limit);
|
|
448
|
+
}
|
|
449
|
+
function removeActivityForPath(config, rawPath) {
|
|
450
|
+
const n = normWorkspacePath(rawPath);
|
|
451
|
+
return {
|
|
452
|
+
...config,
|
|
453
|
+
recentWorkspaceActivity: (config.recentWorkspaceActivity || []).filter(
|
|
454
|
+
(e) => normWorkspacePath(e.path) !== n
|
|
455
|
+
)
|
|
456
|
+
};
|
|
457
|
+
}
|
|
215
458
|
|
|
216
459
|
// src/detection/ide-detector.ts
|
|
217
460
|
var import_child_process = require("child_process");
|
|
@@ -271,20 +514,20 @@ function checkPathExists(paths) {
|
|
|
271
514
|
return null;
|
|
272
515
|
}
|
|
273
516
|
async function detectIDEs() {
|
|
274
|
-
const
|
|
517
|
+
const os15 = (0, import_os2.platform)();
|
|
275
518
|
const results = [];
|
|
276
519
|
for (const def of getMergedDefinitions()) {
|
|
277
520
|
const cliPath = findCliCommand(def.cli);
|
|
278
|
-
const appPath = checkPathExists(def.paths[
|
|
521
|
+
const appPath = checkPathExists(def.paths[os15] || []);
|
|
279
522
|
const installed = !!(cliPath || appPath);
|
|
280
523
|
let resolvedCli = cliPath;
|
|
281
|
-
if (!resolvedCli && appPath &&
|
|
524
|
+
if (!resolvedCli && appPath && os15 === "darwin") {
|
|
282
525
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
283
526
|
if ((0, import_fs2.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
284
527
|
}
|
|
285
|
-
if (!resolvedCli && appPath &&
|
|
286
|
-
const { dirname:
|
|
287
|
-
const appDir =
|
|
528
|
+
if (!resolvedCli && appPath && os15 === "win32") {
|
|
529
|
+
const { dirname: dirname6 } = await import("path");
|
|
530
|
+
const appDir = dirname6(appPath);
|
|
288
531
|
const candidates = [
|
|
289
532
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
290
533
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -317,22 +560,22 @@ async function detectIDEs() {
|
|
|
317
560
|
|
|
318
561
|
// src/detection/cli-detector.ts
|
|
319
562
|
var import_child_process2 = require("child_process");
|
|
320
|
-
var
|
|
563
|
+
var os2 = __toESM(require("os"));
|
|
321
564
|
function execAsync(cmd, timeoutMs = 5e3) {
|
|
322
|
-
return new Promise((
|
|
565
|
+
return new Promise((resolve7) => {
|
|
323
566
|
const child = (0, import_child_process2.exec)(cmd, { encoding: "utf-8", timeout: timeoutMs }, (err, stdout) => {
|
|
324
567
|
if (err || !stdout?.trim()) {
|
|
325
|
-
|
|
568
|
+
resolve7(null);
|
|
326
569
|
} else {
|
|
327
|
-
|
|
570
|
+
resolve7(stdout.trim());
|
|
328
571
|
}
|
|
329
572
|
});
|
|
330
|
-
child.on("error", () =>
|
|
573
|
+
child.on("error", () => resolve7(null));
|
|
331
574
|
});
|
|
332
575
|
}
|
|
333
576
|
async function detectCLIs(providerLoader) {
|
|
334
|
-
const
|
|
335
|
-
const whichCmd =
|
|
577
|
+
const platform8 = os2.platform();
|
|
578
|
+
const whichCmd = platform8 === "win32" ? "where" : "which";
|
|
336
579
|
const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
|
|
337
580
|
const results = await Promise.all(
|
|
338
581
|
cliList.map(async (cli) => {
|
|
@@ -363,14 +606,56 @@ async function detectCLI(cliId, providerLoader) {
|
|
|
363
606
|
return all.find((c) => c.id === resolvedId && c.installed) || null;
|
|
364
607
|
}
|
|
365
608
|
|
|
609
|
+
// src/system/host-memory.ts
|
|
610
|
+
var os3 = __toESM(require("os"));
|
|
611
|
+
var import_child_process3 = require("child_process");
|
|
612
|
+
function parseDarwinAvailableBytes(totalMem) {
|
|
613
|
+
if (os3.platform() !== "darwin") return null;
|
|
614
|
+
try {
|
|
615
|
+
const out = (0, import_child_process3.execSync)("vm_stat", {
|
|
616
|
+
encoding: "utf-8",
|
|
617
|
+
timeout: 4e3,
|
|
618
|
+
maxBuffer: 256 * 1024
|
|
619
|
+
});
|
|
620
|
+
const pageSizeMatch = out.match(/page size of (\d+)\s*bytes/i);
|
|
621
|
+
const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 4096;
|
|
622
|
+
const counts = {};
|
|
623
|
+
for (const line of out.split("\n")) {
|
|
624
|
+
const m = line.match(/^\s*Pages\s+([^:]+):\s+([\d,]+)\s*\.?/);
|
|
625
|
+
if (!m) continue;
|
|
626
|
+
const key = m[1].trim().toLowerCase().replace(/\s+/g, "_");
|
|
627
|
+
const n = parseInt(m[2].replace(/,/g, ""), 10);
|
|
628
|
+
if (!Number.isNaN(n)) counts[key] = n;
|
|
629
|
+
}
|
|
630
|
+
const free = counts["free"] ?? 0;
|
|
631
|
+
const inactive = counts["inactive"] ?? 0;
|
|
632
|
+
const speculative = counts["speculative"] ?? 0;
|
|
633
|
+
const purgeable = counts["purgeable"] ?? 0;
|
|
634
|
+
const fileBacked = counts["file_backed"] ?? 0;
|
|
635
|
+
const availPages = free + inactive + speculative + purgeable + fileBacked;
|
|
636
|
+
const bytes = availPages * pageSize;
|
|
637
|
+
if (!Number.isFinite(bytes) || bytes < 0) return null;
|
|
638
|
+
return Math.min(bytes, totalMem);
|
|
639
|
+
} catch {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function getHostMemorySnapshot() {
|
|
644
|
+
const totalMem = os3.totalmem();
|
|
645
|
+
const freeMem = os3.freemem();
|
|
646
|
+
const darwinAvail = parseDarwinAvailableBytes(totalMem);
|
|
647
|
+
const availableMem = darwinAvail != null ? darwinAvail : freeMem;
|
|
648
|
+
return { totalMem, freeMem, availableMem };
|
|
649
|
+
}
|
|
650
|
+
|
|
366
651
|
// src/cdp/manager.ts
|
|
367
652
|
var import_ws = __toESM(require("ws"));
|
|
368
653
|
var http = __toESM(require("http"));
|
|
369
654
|
|
|
370
655
|
// src/logging/logger.ts
|
|
371
|
-
var
|
|
372
|
-
var
|
|
373
|
-
var
|
|
656
|
+
var fs2 = __toESM(require("fs"));
|
|
657
|
+
var path3 = __toESM(require("path"));
|
|
658
|
+
var os4 = __toESM(require("os"));
|
|
374
659
|
var LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
375
660
|
var LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
376
661
|
var currentLevel = "info";
|
|
@@ -381,29 +666,29 @@ function setLogLevel(level) {
|
|
|
381
666
|
function getLogLevel() {
|
|
382
667
|
return currentLevel;
|
|
383
668
|
}
|
|
384
|
-
var LOG_DIR = process.platform === "darwin" ?
|
|
669
|
+
var LOG_DIR = process.platform === "darwin" ? path3.join(os4.homedir(), "Library", "Logs", "adhdev") : path3.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
385
670
|
var MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
386
671
|
var MAX_LOG_DAYS = 7;
|
|
387
672
|
try {
|
|
388
|
-
|
|
673
|
+
fs2.mkdirSync(LOG_DIR, { recursive: true });
|
|
389
674
|
} catch {
|
|
390
675
|
}
|
|
391
676
|
function getDateStr() {
|
|
392
677
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
393
678
|
}
|
|
394
679
|
var currentDate = getDateStr();
|
|
395
|
-
var currentLogFile =
|
|
680
|
+
var currentLogFile = path3.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
396
681
|
function checkDateRotation() {
|
|
397
682
|
const today = getDateStr();
|
|
398
683
|
if (today !== currentDate) {
|
|
399
684
|
currentDate = today;
|
|
400
|
-
currentLogFile =
|
|
685
|
+
currentLogFile = path3.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
401
686
|
cleanOldLogs();
|
|
402
687
|
}
|
|
403
688
|
}
|
|
404
689
|
function cleanOldLogs() {
|
|
405
690
|
try {
|
|
406
|
-
const files =
|
|
691
|
+
const files = fs2.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
|
|
407
692
|
const cutoff = /* @__PURE__ */ new Date();
|
|
408
693
|
cutoff.setDate(cutoff.getDate() - MAX_LOG_DAYS);
|
|
409
694
|
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
@@ -411,7 +696,7 @@ function cleanOldLogs() {
|
|
|
411
696
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
412
697
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
413
698
|
try {
|
|
414
|
-
|
|
699
|
+
fs2.unlinkSync(path3.join(LOG_DIR, file));
|
|
415
700
|
} catch {
|
|
416
701
|
}
|
|
417
702
|
}
|
|
@@ -421,29 +706,29 @@ function cleanOldLogs() {
|
|
|
421
706
|
}
|
|
422
707
|
function rotateSizeIfNeeded() {
|
|
423
708
|
try {
|
|
424
|
-
const stat =
|
|
709
|
+
const stat = fs2.statSync(currentLogFile);
|
|
425
710
|
if (stat.size > MAX_LOG_SIZE) {
|
|
426
711
|
const backup = currentLogFile.replace(".log", ".1.log");
|
|
427
712
|
try {
|
|
428
|
-
|
|
713
|
+
fs2.unlinkSync(backup);
|
|
429
714
|
} catch {
|
|
430
715
|
}
|
|
431
|
-
|
|
716
|
+
fs2.renameSync(currentLogFile, backup);
|
|
432
717
|
}
|
|
433
718
|
} catch {
|
|
434
719
|
}
|
|
435
720
|
}
|
|
436
721
|
cleanOldLogs();
|
|
437
722
|
try {
|
|
438
|
-
const oldLog =
|
|
439
|
-
if (
|
|
440
|
-
const stat =
|
|
723
|
+
const oldLog = path3.join(LOG_DIR, "daemon.log");
|
|
724
|
+
if (fs2.existsSync(oldLog)) {
|
|
725
|
+
const stat = fs2.statSync(oldLog);
|
|
441
726
|
const oldDate = stat.mtime.toISOString().slice(0, 10);
|
|
442
|
-
|
|
727
|
+
fs2.renameSync(oldLog, path3.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
443
728
|
}
|
|
444
|
-
const oldLogBackup =
|
|
445
|
-
if (
|
|
446
|
-
|
|
729
|
+
const oldLogBackup = path3.join(LOG_DIR, "daemon.log.old");
|
|
730
|
+
if (fs2.existsSync(oldLogBackup)) {
|
|
731
|
+
fs2.unlinkSync(oldLogBackup);
|
|
447
732
|
}
|
|
448
733
|
} catch {
|
|
449
734
|
}
|
|
@@ -454,7 +739,7 @@ function writeToFile(line) {
|
|
|
454
739
|
checkDateRotation();
|
|
455
740
|
rotateSizeIfNeeded();
|
|
456
741
|
}
|
|
457
|
-
|
|
742
|
+
fs2.appendFileSync(currentLogFile, line + "\n");
|
|
458
743
|
} catch {
|
|
459
744
|
}
|
|
460
745
|
}
|
|
@@ -568,7 +853,7 @@ function installGlobalInterceptor() {
|
|
|
568
853
|
writeToFile(`Log file: ${currentLogFile}`);
|
|
569
854
|
writeToFile(`Log level: ${currentLevel}`);
|
|
570
855
|
}
|
|
571
|
-
var LOG_PATH =
|
|
856
|
+
var LOG_PATH = path3.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
572
857
|
|
|
573
858
|
// src/cdp/manager.ts
|
|
574
859
|
var DaemonCdpManager = class {
|
|
@@ -643,7 +928,7 @@ var DaemonCdpManager = class {
|
|
|
643
928
|
* Returns multiple entries if multiple IDE windows are open on same port
|
|
644
929
|
*/
|
|
645
930
|
static listAllTargets(port) {
|
|
646
|
-
return new Promise((
|
|
931
|
+
return new Promise((resolve7) => {
|
|
647
932
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
648
933
|
let data = "";
|
|
649
934
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -659,16 +944,16 @@ var DaemonCdpManager = class {
|
|
|
659
944
|
(t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
|
|
660
945
|
);
|
|
661
946
|
const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
|
|
662
|
-
|
|
947
|
+
resolve7(mainPages.length > 0 ? mainPages : fallbackPages);
|
|
663
948
|
} catch {
|
|
664
|
-
|
|
949
|
+
resolve7([]);
|
|
665
950
|
}
|
|
666
951
|
});
|
|
667
952
|
});
|
|
668
|
-
req.on("error", () =>
|
|
953
|
+
req.on("error", () => resolve7([]));
|
|
669
954
|
req.setTimeout(2e3, () => {
|
|
670
955
|
req.destroy();
|
|
671
|
-
|
|
956
|
+
resolve7([]);
|
|
672
957
|
});
|
|
673
958
|
});
|
|
674
959
|
}
|
|
@@ -708,7 +993,7 @@ var DaemonCdpManager = class {
|
|
|
708
993
|
}
|
|
709
994
|
}
|
|
710
995
|
findTargetOnPort(port) {
|
|
711
|
-
return new Promise((
|
|
996
|
+
return new Promise((resolve7) => {
|
|
712
997
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
713
998
|
let data = "";
|
|
714
999
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -719,7 +1004,7 @@ var DaemonCdpManager = class {
|
|
|
719
1004
|
(t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
|
|
720
1005
|
);
|
|
721
1006
|
if (pages.length === 0) {
|
|
722
|
-
|
|
1007
|
+
resolve7(targets.find((t) => t.webSocketDebuggerUrl) || null);
|
|
723
1008
|
return;
|
|
724
1009
|
}
|
|
725
1010
|
const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
|
|
@@ -729,24 +1014,24 @@ var DaemonCdpManager = class {
|
|
|
729
1014
|
const specific = list.find((t) => t.id === this._targetId);
|
|
730
1015
|
if (specific) {
|
|
731
1016
|
this._pageTitle = specific.title || "";
|
|
732
|
-
|
|
1017
|
+
resolve7(specific);
|
|
733
1018
|
} else {
|
|
734
1019
|
this.log(`[CDP] Target ${this._targetId} not found in page list`);
|
|
735
|
-
|
|
1020
|
+
resolve7(null);
|
|
736
1021
|
}
|
|
737
1022
|
return;
|
|
738
1023
|
}
|
|
739
1024
|
this._pageTitle = list[0]?.title || "";
|
|
740
|
-
|
|
1025
|
+
resolve7(list[0]);
|
|
741
1026
|
} catch {
|
|
742
|
-
|
|
1027
|
+
resolve7(null);
|
|
743
1028
|
}
|
|
744
1029
|
});
|
|
745
1030
|
});
|
|
746
|
-
req.on("error", () =>
|
|
1031
|
+
req.on("error", () => resolve7(null));
|
|
747
1032
|
req.setTimeout(2e3, () => {
|
|
748
1033
|
req.destroy();
|
|
749
|
-
|
|
1034
|
+
resolve7(null);
|
|
750
1035
|
});
|
|
751
1036
|
});
|
|
752
1037
|
}
|
|
@@ -757,7 +1042,7 @@ var DaemonCdpManager = class {
|
|
|
757
1042
|
this.extensionProviders = providers;
|
|
758
1043
|
}
|
|
759
1044
|
connectToTarget(wsUrl) {
|
|
760
|
-
return new Promise((
|
|
1045
|
+
return new Promise((resolve7) => {
|
|
761
1046
|
this.ws = new import_ws.default(wsUrl);
|
|
762
1047
|
this.ws.on("open", async () => {
|
|
763
1048
|
this._connected = true;
|
|
@@ -767,17 +1052,17 @@ var DaemonCdpManager = class {
|
|
|
767
1052
|
}
|
|
768
1053
|
this.connectBrowserWs().catch(() => {
|
|
769
1054
|
});
|
|
770
|
-
|
|
1055
|
+
resolve7(true);
|
|
771
1056
|
});
|
|
772
1057
|
this.ws.on("message", (data) => {
|
|
773
1058
|
try {
|
|
774
1059
|
const msg = JSON.parse(data.toString());
|
|
775
1060
|
if (msg.id && this.pending.has(msg.id)) {
|
|
776
|
-
const { resolve:
|
|
1061
|
+
const { resolve: resolve8, reject } = this.pending.get(msg.id);
|
|
777
1062
|
this.pending.delete(msg.id);
|
|
778
1063
|
this.failureCount = 0;
|
|
779
1064
|
if (msg.error) reject(new Error(msg.error.message));
|
|
780
|
-
else
|
|
1065
|
+
else resolve8(msg.result);
|
|
781
1066
|
} else if (msg.method === "Runtime.executionContextCreated") {
|
|
782
1067
|
this.contexts.add(msg.params.context.id);
|
|
783
1068
|
} else if (msg.method === "Runtime.executionContextDestroyed") {
|
|
@@ -800,7 +1085,7 @@ var DaemonCdpManager = class {
|
|
|
800
1085
|
this.ws.on("error", (err) => {
|
|
801
1086
|
this.log(`[CDP] WebSocket error: ${err.message}`);
|
|
802
1087
|
this._connected = false;
|
|
803
|
-
|
|
1088
|
+
resolve7(false);
|
|
804
1089
|
});
|
|
805
1090
|
});
|
|
806
1091
|
}
|
|
@@ -814,7 +1099,7 @@ var DaemonCdpManager = class {
|
|
|
814
1099
|
return;
|
|
815
1100
|
}
|
|
816
1101
|
this.log(`[CDP] Connecting browser WS for target discovery...`);
|
|
817
|
-
await new Promise((
|
|
1102
|
+
await new Promise((resolve7, reject) => {
|
|
818
1103
|
this.browserWs = new import_ws.default(browserWsUrl);
|
|
819
1104
|
this.browserWs.on("open", async () => {
|
|
820
1105
|
this._browserConnected = true;
|
|
@@ -824,16 +1109,16 @@ var DaemonCdpManager = class {
|
|
|
824
1109
|
} catch (e) {
|
|
825
1110
|
this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
|
|
826
1111
|
}
|
|
827
|
-
|
|
1112
|
+
resolve7();
|
|
828
1113
|
});
|
|
829
1114
|
this.browserWs.on("message", (data) => {
|
|
830
1115
|
try {
|
|
831
1116
|
const msg = JSON.parse(data.toString());
|
|
832
1117
|
if (msg.id && this.browserPending.has(msg.id)) {
|
|
833
|
-
const { resolve:
|
|
1118
|
+
const { resolve: resolve8, reject: reject2 } = this.browserPending.get(msg.id);
|
|
834
1119
|
this.browserPending.delete(msg.id);
|
|
835
1120
|
if (msg.error) reject2(new Error(msg.error.message));
|
|
836
|
-
else
|
|
1121
|
+
else resolve8(msg.result);
|
|
837
1122
|
}
|
|
838
1123
|
} catch {
|
|
839
1124
|
}
|
|
@@ -853,31 +1138,31 @@ var DaemonCdpManager = class {
|
|
|
853
1138
|
}
|
|
854
1139
|
}
|
|
855
1140
|
getBrowserWsUrl() {
|
|
856
|
-
return new Promise((
|
|
1141
|
+
return new Promise((resolve7) => {
|
|
857
1142
|
const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
|
|
858
1143
|
let data = "";
|
|
859
1144
|
res.on("data", (chunk) => data += chunk.toString());
|
|
860
1145
|
res.on("end", () => {
|
|
861
1146
|
try {
|
|
862
1147
|
const info = JSON.parse(data);
|
|
863
|
-
|
|
1148
|
+
resolve7(info.webSocketDebuggerUrl || null);
|
|
864
1149
|
} catch {
|
|
865
|
-
|
|
1150
|
+
resolve7(null);
|
|
866
1151
|
}
|
|
867
1152
|
});
|
|
868
1153
|
});
|
|
869
|
-
req.on("error", () =>
|
|
1154
|
+
req.on("error", () => resolve7(null));
|
|
870
1155
|
req.setTimeout(3e3, () => {
|
|
871
1156
|
req.destroy();
|
|
872
|
-
|
|
1157
|
+
resolve7(null);
|
|
873
1158
|
});
|
|
874
1159
|
});
|
|
875
1160
|
}
|
|
876
1161
|
sendBrowser(method, params = {}, timeoutMs = 15e3) {
|
|
877
|
-
return new Promise((
|
|
1162
|
+
return new Promise((resolve7, reject) => {
|
|
878
1163
|
if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
|
|
879
1164
|
const id = this.browserMsgId++;
|
|
880
|
-
this.browserPending.set(id, { resolve:
|
|
1165
|
+
this.browserPending.set(id, { resolve: resolve7, reject });
|
|
881
1166
|
this.browserWs.send(JSON.stringify({ id, method, params }));
|
|
882
1167
|
setTimeout(() => {
|
|
883
1168
|
if (this.browserPending.has(id)) {
|
|
@@ -917,11 +1202,11 @@ var DaemonCdpManager = class {
|
|
|
917
1202
|
}
|
|
918
1203
|
// ─── CDP Protocol ────────────────────────────────────────
|
|
919
1204
|
sendInternal(method, params = {}, timeoutMs = 15e3) {
|
|
920
|
-
return new Promise((
|
|
1205
|
+
return new Promise((resolve7, reject) => {
|
|
921
1206
|
if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
|
|
922
1207
|
if (this.ws.readyState !== import_ws.default.OPEN) return reject(new Error("WebSocket not open"));
|
|
923
1208
|
const id = this.msgId++;
|
|
924
|
-
this.pending.set(id, { resolve:
|
|
1209
|
+
this.pending.set(id, { resolve: resolve7, reject });
|
|
925
1210
|
this.ws.send(JSON.stringify({ id, method, params }));
|
|
926
1211
|
setTimeout(() => {
|
|
927
1212
|
if (this.pending.has(id)) {
|
|
@@ -1130,7 +1415,7 @@ var DaemonCdpManager = class {
|
|
|
1130
1415
|
const browserWs = this.browserWs;
|
|
1131
1416
|
let msgId = this.browserMsgId;
|
|
1132
1417
|
const sendWs = (method, params = {}, sessionId) => {
|
|
1133
|
-
return new Promise((
|
|
1418
|
+
return new Promise((resolve7, reject) => {
|
|
1134
1419
|
const mid = msgId++;
|
|
1135
1420
|
this.browserMsgId = msgId;
|
|
1136
1421
|
const handler = (raw) => {
|
|
@@ -1139,7 +1424,7 @@ var DaemonCdpManager = class {
|
|
|
1139
1424
|
if (msg.id === mid) {
|
|
1140
1425
|
browserWs.removeListener("message", handler);
|
|
1141
1426
|
if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
|
|
1142
|
-
else
|
|
1427
|
+
else resolve7(msg.result);
|
|
1143
1428
|
}
|
|
1144
1429
|
} catch {
|
|
1145
1430
|
}
|
|
@@ -1313,14 +1598,14 @@ var DaemonCdpManager = class {
|
|
|
1313
1598
|
if (!ws || ws.readyState !== import_ws.default.OPEN) {
|
|
1314
1599
|
throw new Error("CDP not connected");
|
|
1315
1600
|
}
|
|
1316
|
-
return new Promise((
|
|
1601
|
+
return new Promise((resolve7, reject) => {
|
|
1317
1602
|
const id = getNextId();
|
|
1318
1603
|
pendingMap.set(id, {
|
|
1319
1604
|
resolve: (result) => {
|
|
1320
1605
|
if (result?.result?.subtype === "error") {
|
|
1321
1606
|
reject(new Error(result.result.description));
|
|
1322
1607
|
} else {
|
|
1323
|
-
|
|
1608
|
+
resolve7(result?.result?.value);
|
|
1324
1609
|
}
|
|
1325
1610
|
},
|
|
1326
1611
|
reject
|
|
@@ -1901,10 +2186,10 @@ var ExtensionProviderInstance = class {
|
|
|
1901
2186
|
};
|
|
1902
2187
|
|
|
1903
2188
|
// src/config/chat-history.ts
|
|
1904
|
-
var
|
|
1905
|
-
var
|
|
1906
|
-
var
|
|
1907
|
-
var HISTORY_DIR =
|
|
2189
|
+
var fs3 = __toESM(require("fs"));
|
|
2190
|
+
var path4 = __toESM(require("path"));
|
|
2191
|
+
var os5 = __toESM(require("os"));
|
|
2192
|
+
var HISTORY_DIR = path4.join(os5.homedir(), ".adhdev", "history");
|
|
1908
2193
|
var RETAIN_DAYS = 30;
|
|
1909
2194
|
var ChatHistoryWriter = class {
|
|
1910
2195
|
/** Last seen message count per agent (deduplication) */
|
|
@@ -1945,13 +2230,13 @@ var ChatHistoryWriter = class {
|
|
|
1945
2230
|
});
|
|
1946
2231
|
}
|
|
1947
2232
|
if (newMessages.length === 0) return;
|
|
1948
|
-
const dir =
|
|
1949
|
-
|
|
2233
|
+
const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
|
|
2234
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1950
2235
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1951
2236
|
const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
|
|
1952
|
-
const filePath =
|
|
2237
|
+
const filePath = path4.join(dir, `${filePrefix}${date}.jsonl`);
|
|
1953
2238
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
1954
|
-
|
|
2239
|
+
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
1955
2240
|
const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
|
|
1956
2241
|
if (messages.length < prevCount * 0.5 && prevCount > 3) {
|
|
1957
2242
|
seenHashes.clear();
|
|
@@ -1976,17 +2261,17 @@ var ChatHistoryWriter = class {
|
|
|
1976
2261
|
/** Delete history files older than 30 days */
|
|
1977
2262
|
async rotateOldFiles() {
|
|
1978
2263
|
try {
|
|
1979
|
-
if (!
|
|
2264
|
+
if (!fs3.existsSync(HISTORY_DIR)) return;
|
|
1980
2265
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
1981
|
-
const agentDirs =
|
|
2266
|
+
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1982
2267
|
for (const dir of agentDirs) {
|
|
1983
|
-
const dirPath =
|
|
1984
|
-
const files =
|
|
2268
|
+
const dirPath = path4.join(HISTORY_DIR, dir.name);
|
|
2269
|
+
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
1985
2270
|
for (const file of files) {
|
|
1986
|
-
const filePath =
|
|
1987
|
-
const stat =
|
|
2271
|
+
const filePath = path4.join(dirPath, file);
|
|
2272
|
+
const stat = fs3.statSync(filePath);
|
|
1988
2273
|
if (stat.mtimeMs < cutoff) {
|
|
1989
|
-
|
|
2274
|
+
fs3.unlinkSync(filePath);
|
|
1990
2275
|
}
|
|
1991
2276
|
}
|
|
1992
2277
|
}
|
|
@@ -2001,10 +2286,10 @@ var ChatHistoryWriter = class {
|
|
|
2001
2286
|
function readChatHistory(agentType, offset = 0, limit = 30, instanceId) {
|
|
2002
2287
|
try {
|
|
2003
2288
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2004
|
-
const dir =
|
|
2005
|
-
if (!
|
|
2289
|
+
const dir = path4.join(HISTORY_DIR, sanitized);
|
|
2290
|
+
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
2006
2291
|
const sanitizedInstance = instanceId?.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2007
|
-
const files =
|
|
2292
|
+
const files = fs3.readdirSync(dir).filter((f) => {
|
|
2008
2293
|
if (!f.endsWith(".jsonl")) return false;
|
|
2009
2294
|
if (sanitizedInstance) {
|
|
2010
2295
|
return f.startsWith(`${sanitizedInstance}_`);
|
|
@@ -2015,8 +2300,8 @@ function readChatHistory(agentType, offset = 0, limit = 30, instanceId) {
|
|
|
2015
2300
|
const needed = offset + limit + 1;
|
|
2016
2301
|
for (const file of files) {
|
|
2017
2302
|
if (allMessages.length >= needed) break;
|
|
2018
|
-
const filePath =
|
|
2019
|
-
const content =
|
|
2303
|
+
const filePath = path4.join(dir, file);
|
|
2304
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
2020
2305
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
2021
2306
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2022
2307
|
if (allMessages.length >= needed) break;
|
|
@@ -2256,6 +2541,15 @@ var IdeProviderInstance = class {
|
|
|
2256
2541
|
const h = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
|
|
2257
2542
|
msg.receivedAt = prevByHash.get(h) || now;
|
|
2258
2543
|
}
|
|
2544
|
+
if (raw.messages?.length > 0) {
|
|
2545
|
+
const hiddenKinds = /* @__PURE__ */ new Set();
|
|
2546
|
+
if (this.settings.showThinking === false) hiddenKinds.add("thought");
|
|
2547
|
+
if (this.settings.showToolCalls === false) hiddenKinds.add("tool");
|
|
2548
|
+
if (this.settings.showTerminal === false) hiddenKinds.add("terminal");
|
|
2549
|
+
if (hiddenKinds.size > 0) {
|
|
2550
|
+
raw.messages = raw.messages.filter((m) => !hiddenKinds.has(m.kind));
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2259
2553
|
this.cachedChat = { ...raw, activeModal };
|
|
2260
2554
|
this.detectAgentTransitions(raw, now);
|
|
2261
2555
|
if (raw.messages?.length > 0) {
|
|
@@ -3274,6 +3568,39 @@ async function handleResolveAction(h, args) {
|
|
|
3274
3568
|
const action = args?.action || "approve";
|
|
3275
3569
|
const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
|
|
3276
3570
|
LOG.info("Command", `[resolveAction] action=${action} button="${button}" provider=${provider?.type}`);
|
|
3571
|
+
if (provider?.category === "cli") {
|
|
3572
|
+
const adapter = h.getCliAdapter(provider.type);
|
|
3573
|
+
if (!adapter) return { success: false, error: "CLI adapter not running" };
|
|
3574
|
+
const status = adapter.getStatus?.();
|
|
3575
|
+
if (status?.status !== "waiting_approval") {
|
|
3576
|
+
return { success: false, error: "Not in approval state" };
|
|
3577
|
+
}
|
|
3578
|
+
const buttons = status.activeModal?.buttons || ["Allow once", "Always allow", "Deny"];
|
|
3579
|
+
let buttonIndex = typeof args?.buttonIndex === "number" ? args.buttonIndex : -1;
|
|
3580
|
+
if (buttonIndex < 0) {
|
|
3581
|
+
const btnLower = button.toLowerCase();
|
|
3582
|
+
buttonIndex = buttons.findIndex((b) => b.toLowerCase().includes(btnLower));
|
|
3583
|
+
}
|
|
3584
|
+
if (buttonIndex < 0) {
|
|
3585
|
+
if (action === "reject" || action === "deny") {
|
|
3586
|
+
buttonIndex = buttons.findIndex((b) => /deny|reject|no/i.test(b));
|
|
3587
|
+
if (buttonIndex < 0) buttonIndex = buttons.length - 1;
|
|
3588
|
+
} else if (action === "always" || /always/i.test(button)) {
|
|
3589
|
+
buttonIndex = buttons.findIndex((b) => /always/i.test(b));
|
|
3590
|
+
if (buttonIndex < 0) buttonIndex = 1;
|
|
3591
|
+
} else {
|
|
3592
|
+
buttonIndex = 0;
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
if (typeof adapter.resolveModal === "function") {
|
|
3596
|
+
adapter.resolveModal(buttonIndex);
|
|
3597
|
+
} else {
|
|
3598
|
+
const keys = "\x1B[B".repeat(Math.max(0, buttonIndex)) + "\r";
|
|
3599
|
+
adapter.writeRaw?.(keys);
|
|
3600
|
+
}
|
|
3601
|
+
LOG.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
|
|
3602
|
+
return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
|
|
3603
|
+
}
|
|
3277
3604
|
if (provider?.category === "extension" && h.agentStream && h.getCdp()) {
|
|
3278
3605
|
const ok = await h.agentStream.resolveAgentAction(
|
|
3279
3606
|
h.getCdp(),
|
|
@@ -3360,9 +3687,9 @@ async function handleResolveAction(h, args) {
|
|
|
3360
3687
|
}
|
|
3361
3688
|
|
|
3362
3689
|
// src/commands/cdp-commands.ts
|
|
3363
|
-
var
|
|
3364
|
-
var
|
|
3365
|
-
var
|
|
3690
|
+
var fs4 = __toESM(require("fs"));
|
|
3691
|
+
var path5 = __toESM(require("path"));
|
|
3692
|
+
var os6 = __toESM(require("os"));
|
|
3366
3693
|
async function handleCdpEval(h, args) {
|
|
3367
3694
|
if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
|
|
3368
3695
|
const expression = args?.expression || args?.script;
|
|
@@ -3514,21 +3841,21 @@ async function handleDiscoverAgents(h, args) {
|
|
|
3514
3841
|
return { success: true, agents };
|
|
3515
3842
|
}
|
|
3516
3843
|
function resolveSafePath(requestedPath) {
|
|
3517
|
-
const home =
|
|
3844
|
+
const home = os6.homedir();
|
|
3518
3845
|
let resolved;
|
|
3519
3846
|
if (requestedPath.startsWith("~")) {
|
|
3520
|
-
resolved =
|
|
3521
|
-
} else if (
|
|
3847
|
+
resolved = path5.join(home, requestedPath.slice(1));
|
|
3848
|
+
} else if (path5.isAbsolute(requestedPath)) {
|
|
3522
3849
|
resolved = requestedPath;
|
|
3523
3850
|
} else {
|
|
3524
|
-
resolved =
|
|
3851
|
+
resolved = path5.resolve(requestedPath);
|
|
3525
3852
|
}
|
|
3526
3853
|
return resolved;
|
|
3527
3854
|
}
|
|
3528
3855
|
async function handleFileRead(h, args) {
|
|
3529
3856
|
try {
|
|
3530
3857
|
const filePath = resolveSafePath(args?.path);
|
|
3531
|
-
const content =
|
|
3858
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
3532
3859
|
return { success: true, content, path: filePath };
|
|
3533
3860
|
} catch (e) {
|
|
3534
3861
|
return { success: false, error: e.message };
|
|
@@ -3537,8 +3864,8 @@ async function handleFileRead(h, args) {
|
|
|
3537
3864
|
async function handleFileWrite(h, args) {
|
|
3538
3865
|
try {
|
|
3539
3866
|
const filePath = resolveSafePath(args?.path);
|
|
3540
|
-
|
|
3541
|
-
|
|
3867
|
+
fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
|
|
3868
|
+
fs4.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
3542
3869
|
return { success: true, path: filePath };
|
|
3543
3870
|
} catch (e) {
|
|
3544
3871
|
return { success: false, error: e.message };
|
|
@@ -3547,11 +3874,11 @@ async function handleFileWrite(h, args) {
|
|
|
3547
3874
|
async function handleFileList(h, args) {
|
|
3548
3875
|
try {
|
|
3549
3876
|
const dirPath = resolveSafePath(args?.path || ".");
|
|
3550
|
-
const entries =
|
|
3877
|
+
const entries = fs4.readdirSync(dirPath, { withFileTypes: true });
|
|
3551
3878
|
const files = entries.map((e) => ({
|
|
3552
3879
|
name: e.name,
|
|
3553
3880
|
type: e.isDirectory() ? "directory" : "file",
|
|
3554
|
-
size: e.isFile() ?
|
|
3881
|
+
size: e.isFile() ? fs4.statSync(path5.join(dirPath, e.name)).size : void 0
|
|
3555
3882
|
}));
|
|
3556
3883
|
return { success: true, files, path: dirPath };
|
|
3557
3884
|
} catch (e) {
|
|
@@ -3841,7 +4168,95 @@ function handleSetIdeExtension(h, args) {
|
|
|
3841
4168
|
return { success: false, error: "Failed to save setting" };
|
|
3842
4169
|
}
|
|
3843
4170
|
|
|
4171
|
+
// src/commands/workspace-commands.ts
|
|
4172
|
+
init_config();
|
|
4173
|
+
init_workspaces();
|
|
4174
|
+
function handleWorkspaceList() {
|
|
4175
|
+
const config = loadConfig();
|
|
4176
|
+
const state = getWorkspaceState(config);
|
|
4177
|
+
return {
|
|
4178
|
+
success: true,
|
|
4179
|
+
workspaces: state.workspaces,
|
|
4180
|
+
defaultWorkspaceId: state.defaultWorkspaceId,
|
|
4181
|
+
defaultWorkspacePath: state.defaultWorkspacePath,
|
|
4182
|
+
legacyRecentPaths: config.recentCliWorkspaces || [],
|
|
4183
|
+
activity: getWorkspaceActivity(config, 25)
|
|
4184
|
+
};
|
|
4185
|
+
}
|
|
4186
|
+
function handleWorkspaceAdd(args) {
|
|
4187
|
+
const rawPath = (args?.path || args?.dir || "").trim();
|
|
4188
|
+
const label = (args?.label || "").trim() || void 0;
|
|
4189
|
+
if (!rawPath) return { success: false, error: "path required" };
|
|
4190
|
+
const config = loadConfig();
|
|
4191
|
+
const result = addWorkspaceEntry(config, rawPath, label);
|
|
4192
|
+
if ("error" in result) return { success: false, error: result.error };
|
|
4193
|
+
let cfg = appendWorkspaceActivity(result.config, result.entry.path, {});
|
|
4194
|
+
saveConfig(cfg);
|
|
4195
|
+
const state = getWorkspaceState(cfg);
|
|
4196
|
+
return { success: true, entry: result.entry, ...state, activity: getWorkspaceActivity(cfg, 25) };
|
|
4197
|
+
}
|
|
4198
|
+
function handleWorkspaceRemove(args) {
|
|
4199
|
+
const id = (args?.id || "").trim();
|
|
4200
|
+
if (!id) return { success: false, error: "id required" };
|
|
4201
|
+
const config = loadConfig();
|
|
4202
|
+
const removed = (config.workspaces || []).find((w) => w.id === id);
|
|
4203
|
+
const result = removeWorkspaceEntry(config, id);
|
|
4204
|
+
if ("error" in result) return { success: false, error: result.error };
|
|
4205
|
+
let cfg = result.config;
|
|
4206
|
+
if (removed) {
|
|
4207
|
+
cfg = removeActivityForPath(cfg, removed.path);
|
|
4208
|
+
}
|
|
4209
|
+
saveConfig(cfg);
|
|
4210
|
+
const state = getWorkspaceState(cfg);
|
|
4211
|
+
return { success: true, removedId: id, ...state, activity: getWorkspaceActivity(cfg, 25) };
|
|
4212
|
+
}
|
|
4213
|
+
function handleWorkspaceSetDefault(args) {
|
|
4214
|
+
const clear = args?.clear === true || args?.id === null || args?.id === "";
|
|
4215
|
+
if (clear) {
|
|
4216
|
+
const config2 = loadConfig();
|
|
4217
|
+
const result2 = setDefaultWorkspaceId(config2, null);
|
|
4218
|
+
if ("error" in result2) return { success: false, error: result2.error };
|
|
4219
|
+
saveConfig(result2.config);
|
|
4220
|
+
const state2 = getWorkspaceState(result2.config);
|
|
4221
|
+
return {
|
|
4222
|
+
success: true,
|
|
4223
|
+
...state2,
|
|
4224
|
+
activity: getWorkspaceActivity(result2.config, 25)
|
|
4225
|
+
};
|
|
4226
|
+
}
|
|
4227
|
+
const pathArg = args?.path != null && String(args.path).trim() ? String(args.path).trim() : "";
|
|
4228
|
+
const idArg = args?.id !== void 0 && args?.id !== null && String(args.id).trim() ? String(args.id).trim() : "";
|
|
4229
|
+
if (!pathArg && !idArg) {
|
|
4230
|
+
return { success: false, error: "id or path required (or clear: true)" };
|
|
4231
|
+
}
|
|
4232
|
+
let config = loadConfig();
|
|
4233
|
+
let nextId;
|
|
4234
|
+
if (pathArg) {
|
|
4235
|
+
let w = findWorkspaceByPath(config, pathArg);
|
|
4236
|
+
if (!w) {
|
|
4237
|
+
const add = addWorkspaceEntry(config, pathArg);
|
|
4238
|
+
if ("error" in add) return { success: false, error: add.error };
|
|
4239
|
+
config = add.config;
|
|
4240
|
+
w = add.entry;
|
|
4241
|
+
}
|
|
4242
|
+
nextId = w.id;
|
|
4243
|
+
} else {
|
|
4244
|
+
nextId = idArg;
|
|
4245
|
+
}
|
|
4246
|
+
const result = setDefaultWorkspaceId(config, nextId);
|
|
4247
|
+
if ("error" in result) return { success: false, error: result.error };
|
|
4248
|
+
let out = result.config;
|
|
4249
|
+
const ap = getDefaultWorkspacePath(out);
|
|
4250
|
+
if (ap) {
|
|
4251
|
+
out = appendWorkspaceActivity(out, ap, { kind: "default" });
|
|
4252
|
+
}
|
|
4253
|
+
saveConfig(out);
|
|
4254
|
+
const state = getWorkspaceState(out);
|
|
4255
|
+
return { success: true, ...state, activity: getWorkspaceActivity(out, 25) };
|
|
4256
|
+
}
|
|
4257
|
+
|
|
3844
4258
|
// src/commands/handler.ts
|
|
4259
|
+
init_workspaces();
|
|
3845
4260
|
var DaemonCommandHandler = class {
|
|
3846
4261
|
_ctx;
|
|
3847
4262
|
_agentStream = null;
|
|
@@ -3950,6 +4365,9 @@ var DaemonCommandHandler = class {
|
|
|
3950
4365
|
}
|
|
3951
4366
|
/** Extract ideType from _targetInstance */
|
|
3952
4367
|
extractIdeType(args) {
|
|
4368
|
+
if (args?.ideType && this._ctx.cdpManagers.has(args.ideType)) {
|
|
4369
|
+
return args.ideType;
|
|
4370
|
+
}
|
|
3953
4371
|
if (args?._targetInstance) {
|
|
3954
4372
|
let raw = args._targetInstance;
|
|
3955
4373
|
const ideMatch = raw.match(/:ide:(.+)$/);
|
|
@@ -3961,8 +4379,19 @@ var DaemonCommandHandler = class {
|
|
|
3961
4379
|
if (this._ctx.instanceIdMap?.has(raw)) {
|
|
3962
4380
|
return this._ctx.instanceIdMap.get(raw);
|
|
3963
4381
|
}
|
|
4382
|
+
if (this._ctx.cdpManagers.has(raw)) {
|
|
4383
|
+
return raw;
|
|
4384
|
+
}
|
|
4385
|
+
if (!ideMatch && !cliMatch && !acpMatch) {
|
|
4386
|
+
for (const [key, mgr] of this._ctx.cdpManagers.entries()) {
|
|
4387
|
+
if (mgr.isConnected) return key;
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
3964
4390
|
const lastUnderscore = raw.lastIndexOf("_");
|
|
3965
|
-
if (lastUnderscore > 0)
|
|
4391
|
+
if (lastUnderscore > 0) {
|
|
4392
|
+
const stripped = raw.substring(0, lastUnderscore);
|
|
4393
|
+
if (this._ctx.cdpManagers.has(stripped)) return stripped;
|
|
4394
|
+
}
|
|
3966
4395
|
return raw;
|
|
3967
4396
|
}
|
|
3968
4397
|
return void 0;
|
|
@@ -4058,6 +4487,19 @@ var DaemonCommandHandler = class {
|
|
|
4058
4487
|
return { success: false, error: `${cmd} requires bridge-extension (removed)` };
|
|
4059
4488
|
case "get_recent_workspaces":
|
|
4060
4489
|
return this.handleGetRecentWorkspaces(args);
|
|
4490
|
+
case "get_cli_history": {
|
|
4491
|
+
const config = loadConfig();
|
|
4492
|
+
return { success: true, history: config.cliHistory || [] };
|
|
4493
|
+
}
|
|
4494
|
+
case "workspace_list":
|
|
4495
|
+
return handleWorkspaceList();
|
|
4496
|
+
case "workspace_add":
|
|
4497
|
+
return handleWorkspaceAdd(args);
|
|
4498
|
+
case "workspace_remove":
|
|
4499
|
+
return handleWorkspaceRemove(args);
|
|
4500
|
+
case "workspace_set_default":
|
|
4501
|
+
case "workspace_set_active":
|
|
4502
|
+
return handleWorkspaceSetDefault(args);
|
|
4061
4503
|
// ─── Script manage ───────────────────
|
|
4062
4504
|
case "refresh_scripts":
|
|
4063
4505
|
return this.handleRefreshScripts(args);
|
|
@@ -4107,10 +4549,18 @@ var DaemonCommandHandler = class {
|
|
|
4107
4549
|
}
|
|
4108
4550
|
}
|
|
4109
4551
|
// ─── Misc (kept in handler — too small to extract) ───────
|
|
4110
|
-
async handleGetRecentWorkspaces(
|
|
4552
|
+
async handleGetRecentWorkspaces(_args) {
|
|
4111
4553
|
const config = loadConfig();
|
|
4112
4554
|
const cliRecent = config.recentCliWorkspaces || [];
|
|
4113
|
-
|
|
4555
|
+
const ws = getWorkspaceState(config);
|
|
4556
|
+
return {
|
|
4557
|
+
success: true,
|
|
4558
|
+
result: cliRecent,
|
|
4559
|
+
workspaces: ws.workspaces,
|
|
4560
|
+
defaultWorkspaceId: ws.defaultWorkspaceId,
|
|
4561
|
+
defaultWorkspacePath: ws.defaultWorkspacePath,
|
|
4562
|
+
activity: getWorkspaceActivity(config, 25)
|
|
4563
|
+
};
|
|
4114
4564
|
}
|
|
4115
4565
|
async handleRefreshScripts(_args) {
|
|
4116
4566
|
if (this._ctx.providerLoader) {
|
|
@@ -4122,15 +4572,15 @@ var DaemonCommandHandler = class {
|
|
|
4122
4572
|
};
|
|
4123
4573
|
|
|
4124
4574
|
// src/launch.ts
|
|
4125
|
-
var
|
|
4575
|
+
var import_child_process4 = require("child_process");
|
|
4126
4576
|
var net = __toESM(require("net"));
|
|
4127
|
-
var
|
|
4128
|
-
var
|
|
4577
|
+
var os8 = __toESM(require("os"));
|
|
4578
|
+
var path7 = __toESM(require("path"));
|
|
4129
4579
|
|
|
4130
4580
|
// src/providers/provider-loader.ts
|
|
4131
|
-
var
|
|
4132
|
-
var
|
|
4133
|
-
var
|
|
4581
|
+
var fs5 = __toESM(require("fs"));
|
|
4582
|
+
var path6 = __toESM(require("path"));
|
|
4583
|
+
var os7 = __toESM(require("os"));
|
|
4134
4584
|
var ProviderLoader = class _ProviderLoader {
|
|
4135
4585
|
providers = /* @__PURE__ */ new Map();
|
|
4136
4586
|
builtinDirs;
|
|
@@ -4150,10 +4600,10 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4150
4600
|
if (options?.builtinDir) {
|
|
4151
4601
|
this.builtinDirs = Array.isArray(options.builtinDir) ? options.builtinDir : [options.builtinDir];
|
|
4152
4602
|
} else {
|
|
4153
|
-
this.builtinDirs = [
|
|
4603
|
+
this.builtinDirs = [path6.resolve(__dirname, "../providers/_builtin")];
|
|
4154
4604
|
}
|
|
4155
|
-
this.userDir = options?.userDir ||
|
|
4156
|
-
this.upstreamDir =
|
|
4605
|
+
this.userDir = options?.userDir || path6.join(os7.homedir(), ".adhdev", "providers");
|
|
4606
|
+
this.upstreamDir = path6.join(this.userDir, ".upstream");
|
|
4157
4607
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
4158
4608
|
}
|
|
4159
4609
|
log(msg) {
|
|
@@ -4171,19 +4621,19 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4171
4621
|
this.providers.clear();
|
|
4172
4622
|
let builtinCount = 0;
|
|
4173
4623
|
for (const dir of this.builtinDirs) {
|
|
4174
|
-
if (
|
|
4624
|
+
if (fs5.existsSync(dir)) {
|
|
4175
4625
|
builtinCount += this.loadDir(dir);
|
|
4176
4626
|
}
|
|
4177
4627
|
}
|
|
4178
4628
|
this.log(`Loaded ${builtinCount} builtin providers`);
|
|
4179
4629
|
let upstreamCount = 0;
|
|
4180
|
-
if (
|
|
4630
|
+
if (fs5.existsSync(this.upstreamDir)) {
|
|
4181
4631
|
upstreamCount = this.loadDir(this.upstreamDir);
|
|
4182
4632
|
if (upstreamCount > 0) {
|
|
4183
4633
|
this.log(`Loaded ${upstreamCount} upstream providers (auto-updated)`);
|
|
4184
4634
|
}
|
|
4185
4635
|
}
|
|
4186
|
-
if (
|
|
4636
|
+
if (fs5.existsSync(this.userDir)) {
|
|
4187
4637
|
const userCount = this.loadDir(this.userDir, [".upstream"]);
|
|
4188
4638
|
if (userCount > 0) {
|
|
4189
4639
|
this.log(`Loaded ${userCount} user custom providers (never auto-updated)`);
|
|
@@ -4487,15 +4937,15 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4487
4937
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
4488
4938
|
return null;
|
|
4489
4939
|
}
|
|
4490
|
-
const dir =
|
|
4491
|
-
if (!
|
|
4940
|
+
const dir = path6.join(providerDir, scriptDir);
|
|
4941
|
+
if (!fs5.existsSync(dir)) {
|
|
4492
4942
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
4493
4943
|
return null;
|
|
4494
4944
|
}
|
|
4495
4945
|
const cached = this.scriptsCache.get(dir);
|
|
4496
4946
|
if (cached) return cached;
|
|
4497
|
-
const scriptsJs =
|
|
4498
|
-
if (
|
|
4947
|
+
const scriptsJs = path6.join(dir, "scripts.js");
|
|
4948
|
+
if (fs5.existsSync(scriptsJs)) {
|
|
4499
4949
|
try {
|
|
4500
4950
|
delete require.cache[require.resolve(scriptsJs)];
|
|
4501
4951
|
const loaded = require(scriptsJs);
|
|
@@ -4517,15 +4967,15 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4517
4967
|
watch() {
|
|
4518
4968
|
this.stopWatch();
|
|
4519
4969
|
const watchDir = (dir) => {
|
|
4520
|
-
if (!
|
|
4970
|
+
if (!fs5.existsSync(dir)) {
|
|
4521
4971
|
try {
|
|
4522
|
-
|
|
4972
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
4523
4973
|
} catch {
|
|
4524
4974
|
return;
|
|
4525
4975
|
}
|
|
4526
4976
|
}
|
|
4527
4977
|
try {
|
|
4528
|
-
const watcher =
|
|
4978
|
+
const watcher = fs5.watch(dir, { recursive: true }, (event, filename) => {
|
|
4529
4979
|
if (filename?.endsWith(".js") || filename?.endsWith(".json")) {
|
|
4530
4980
|
this.log(`File changed: ${filename}, reloading...`);
|
|
4531
4981
|
this.loadAll();
|
|
@@ -4575,13 +5025,13 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4575
5025
|
*/
|
|
4576
5026
|
async fetchLatest() {
|
|
4577
5027
|
const https = require("https");
|
|
4578
|
-
const { execSync:
|
|
4579
|
-
const metaPath =
|
|
5028
|
+
const { execSync: execSync7 } = require("child_process");
|
|
5029
|
+
const metaPath = path6.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
4580
5030
|
let prevEtag = "";
|
|
4581
5031
|
let prevTimestamp = 0;
|
|
4582
5032
|
try {
|
|
4583
|
-
if (
|
|
4584
|
-
const meta = JSON.parse(
|
|
5033
|
+
if (fs5.existsSync(metaPath)) {
|
|
5034
|
+
const meta = JSON.parse(fs5.readFileSync(metaPath, "utf-8"));
|
|
4585
5035
|
prevEtag = meta.etag || "";
|
|
4586
5036
|
prevTimestamp = meta.timestamp || 0;
|
|
4587
5037
|
}
|
|
@@ -4593,7 +5043,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4593
5043
|
return { updated: false };
|
|
4594
5044
|
}
|
|
4595
5045
|
try {
|
|
4596
|
-
const etag = await new Promise((
|
|
5046
|
+
const etag = await new Promise((resolve7, reject) => {
|
|
4597
5047
|
const options = {
|
|
4598
5048
|
method: "HEAD",
|
|
4599
5049
|
hostname: "github.com",
|
|
@@ -4611,7 +5061,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4611
5061
|
headers: { "User-Agent": "adhdev-launcher" },
|
|
4612
5062
|
timeout: 1e4
|
|
4613
5063
|
}, (res2) => {
|
|
4614
|
-
|
|
5064
|
+
resolve7(res2.headers.etag || res2.headers["last-modified"] || "");
|
|
4615
5065
|
});
|
|
4616
5066
|
req2.on("error", reject);
|
|
4617
5067
|
req2.on("timeout", () => {
|
|
@@ -4620,7 +5070,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4620
5070
|
});
|
|
4621
5071
|
req2.end();
|
|
4622
5072
|
} else {
|
|
4623
|
-
|
|
5073
|
+
resolve7(res.headers.etag || res.headers["last-modified"] || "");
|
|
4624
5074
|
}
|
|
4625
5075
|
});
|
|
4626
5076
|
req.on("error", reject);
|
|
@@ -4636,39 +5086,39 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4636
5086
|
return { updated: false };
|
|
4637
5087
|
}
|
|
4638
5088
|
this.log("Downloading latest providers from GitHub...");
|
|
4639
|
-
const tmpTar =
|
|
4640
|
-
const tmpExtract =
|
|
5089
|
+
const tmpTar = path6.join(os7.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
5090
|
+
const tmpExtract = path6.join(os7.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
4641
5091
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
const extracted =
|
|
5092
|
+
fs5.mkdirSync(tmpExtract, { recursive: true });
|
|
5093
|
+
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
5094
|
+
const extracted = fs5.readdirSync(tmpExtract);
|
|
4645
5095
|
const rootDir = extracted.find(
|
|
4646
|
-
(d) =>
|
|
5096
|
+
(d) => fs5.statSync(path6.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
4647
5097
|
);
|
|
4648
5098
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
4649
|
-
const sourceDir =
|
|
5099
|
+
const sourceDir = path6.join(tmpExtract, rootDir);
|
|
4650
5100
|
const backupDir = this.upstreamDir + ".bak";
|
|
4651
|
-
if (
|
|
4652
|
-
if (
|
|
4653
|
-
|
|
5101
|
+
if (fs5.existsSync(this.upstreamDir)) {
|
|
5102
|
+
if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
|
|
5103
|
+
fs5.renameSync(this.upstreamDir, backupDir);
|
|
4654
5104
|
}
|
|
4655
5105
|
try {
|
|
4656
5106
|
this.copyDirRecursive(sourceDir, this.upstreamDir);
|
|
4657
5107
|
this.writeMeta(metaPath, etag || `ts-${Date.now()}`, Date.now());
|
|
4658
|
-
if (
|
|
5108
|
+
if (fs5.existsSync(backupDir)) fs5.rmSync(backupDir, { recursive: true, force: true });
|
|
4659
5109
|
} catch (e) {
|
|
4660
|
-
if (
|
|
4661
|
-
if (
|
|
4662
|
-
|
|
5110
|
+
if (fs5.existsSync(backupDir)) {
|
|
5111
|
+
if (fs5.existsSync(this.upstreamDir)) fs5.rmSync(this.upstreamDir, { recursive: true, force: true });
|
|
5112
|
+
fs5.renameSync(backupDir, this.upstreamDir);
|
|
4663
5113
|
}
|
|
4664
5114
|
throw e;
|
|
4665
5115
|
}
|
|
4666
5116
|
try {
|
|
4667
|
-
|
|
5117
|
+
fs5.rmSync(tmpTar, { force: true });
|
|
4668
5118
|
} catch {
|
|
4669
5119
|
}
|
|
4670
5120
|
try {
|
|
4671
|
-
|
|
5121
|
+
fs5.rmSync(tmpExtract, { recursive: true, force: true });
|
|
4672
5122
|
} catch {
|
|
4673
5123
|
}
|
|
4674
5124
|
const upstreamCount = this.countProviders(this.upstreamDir);
|
|
@@ -4684,7 +5134,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4684
5134
|
downloadFile(url, destPath) {
|
|
4685
5135
|
const https = require("https");
|
|
4686
5136
|
const http3 = require("http");
|
|
4687
|
-
return new Promise((
|
|
5137
|
+
return new Promise((resolve7, reject) => {
|
|
4688
5138
|
const doRequest = (reqUrl, redirectCount = 0) => {
|
|
4689
5139
|
if (redirectCount > 5) {
|
|
4690
5140
|
reject(new Error("Too many redirects"));
|
|
@@ -4700,11 +5150,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4700
5150
|
reject(new Error(`HTTP ${res.statusCode}`));
|
|
4701
5151
|
return;
|
|
4702
5152
|
}
|
|
4703
|
-
const ws =
|
|
5153
|
+
const ws = fs5.createWriteStream(destPath);
|
|
4704
5154
|
res.pipe(ws);
|
|
4705
5155
|
ws.on("finish", () => {
|
|
4706
5156
|
ws.close();
|
|
4707
|
-
|
|
5157
|
+
resolve7();
|
|
4708
5158
|
});
|
|
4709
5159
|
ws.on("error", reject);
|
|
4710
5160
|
});
|
|
@@ -4719,22 +5169,22 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4719
5169
|
}
|
|
4720
5170
|
/** Recursive directory copy */
|
|
4721
5171
|
copyDirRecursive(src, dest) {
|
|
4722
|
-
|
|
4723
|
-
for (const entry of
|
|
4724
|
-
const srcPath =
|
|
4725
|
-
const destPath =
|
|
5172
|
+
fs5.mkdirSync(dest, { recursive: true });
|
|
5173
|
+
for (const entry of fs5.readdirSync(src, { withFileTypes: true })) {
|
|
5174
|
+
const srcPath = path6.join(src, entry.name);
|
|
5175
|
+
const destPath = path6.join(dest, entry.name);
|
|
4726
5176
|
if (entry.isDirectory()) {
|
|
4727
5177
|
this.copyDirRecursive(srcPath, destPath);
|
|
4728
5178
|
} else {
|
|
4729
|
-
|
|
5179
|
+
fs5.copyFileSync(srcPath, destPath);
|
|
4730
5180
|
}
|
|
4731
5181
|
}
|
|
4732
5182
|
}
|
|
4733
5183
|
/** .meta.json save */
|
|
4734
5184
|
writeMeta(metaPath, etag, timestamp) {
|
|
4735
5185
|
try {
|
|
4736
|
-
|
|
4737
|
-
|
|
5186
|
+
fs5.mkdirSync(path6.dirname(metaPath), { recursive: true });
|
|
5187
|
+
fs5.writeFileSync(metaPath, JSON.stringify({
|
|
4738
5188
|
etag,
|
|
4739
5189
|
timestamp,
|
|
4740
5190
|
lastCheck: new Date(timestamp).toISOString(),
|
|
@@ -4745,12 +5195,12 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4745
5195
|
}
|
|
4746
5196
|
/** Count provider files (provider.js or provider.json) */
|
|
4747
5197
|
countProviders(dir) {
|
|
4748
|
-
if (!
|
|
5198
|
+
if (!fs5.existsSync(dir)) return 0;
|
|
4749
5199
|
let count = 0;
|
|
4750
5200
|
const scan = (d) => {
|
|
4751
5201
|
try {
|
|
4752
|
-
for (const entry of
|
|
4753
|
-
if (entry.isDirectory()) scan(
|
|
5202
|
+
for (const entry of fs5.readdirSync(d, { withFileTypes: true })) {
|
|
5203
|
+
if (entry.isDirectory()) scan(path6.join(d, entry.name));
|
|
4754
5204
|
else if (entry.name === "provider.json") count++;
|
|
4755
5205
|
}
|
|
4756
5206
|
} catch {
|
|
@@ -4847,20 +5297,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4847
5297
|
const cat = provider.category;
|
|
4848
5298
|
const searchRoots = [this.userDir, this.upstreamDir, ...this.builtinDirs];
|
|
4849
5299
|
for (const root of searchRoots) {
|
|
4850
|
-
if (!
|
|
4851
|
-
for (const candidate of [
|
|
4852
|
-
if (
|
|
5300
|
+
if (!fs5.existsSync(root)) continue;
|
|
5301
|
+
for (const candidate of [path6.join(root, type), path6.join(root, cat, type)]) {
|
|
5302
|
+
if (fs5.existsSync(path6.join(candidate, "provider.json"))) return candidate;
|
|
4853
5303
|
}
|
|
4854
|
-
const catDir =
|
|
4855
|
-
if (
|
|
5304
|
+
const catDir = path6.join(root, cat);
|
|
5305
|
+
if (fs5.existsSync(catDir)) {
|
|
4856
5306
|
try {
|
|
4857
|
-
for (const entry of
|
|
5307
|
+
for (const entry of fs5.readdirSync(catDir, { withFileTypes: true })) {
|
|
4858
5308
|
if (!entry.isDirectory()) continue;
|
|
4859
|
-
const jsonPath =
|
|
4860
|
-
if (
|
|
5309
|
+
const jsonPath = path6.join(catDir, entry.name, "provider.json");
|
|
5310
|
+
if (fs5.existsSync(jsonPath)) {
|
|
4861
5311
|
try {
|
|
4862
|
-
const data = JSON.parse(
|
|
4863
|
-
if (data.type === type) return
|
|
5312
|
+
const data = JSON.parse(fs5.readFileSync(jsonPath, "utf-8"));
|
|
5313
|
+
if (data.type === type) return path6.join(catDir, entry.name);
|
|
4864
5314
|
} catch {
|
|
4865
5315
|
}
|
|
4866
5316
|
}
|
|
@@ -4877,8 +5327,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4877
5327
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
4878
5328
|
*/
|
|
4879
5329
|
buildScriptWrappersFromDir(dir) {
|
|
4880
|
-
const scriptsJs =
|
|
4881
|
-
if (
|
|
5330
|
+
const scriptsJs = path6.join(dir, "scripts.js");
|
|
5331
|
+
if (fs5.existsSync(scriptsJs)) {
|
|
4882
5332
|
try {
|
|
4883
5333
|
delete require.cache[require.resolve(scriptsJs)];
|
|
4884
5334
|
return require(scriptsJs);
|
|
@@ -4888,13 +5338,13 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4888
5338
|
const toCamel = (name) => name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
4889
5339
|
const result = {};
|
|
4890
5340
|
try {
|
|
4891
|
-
for (const file of
|
|
5341
|
+
for (const file of fs5.readdirSync(dir)) {
|
|
4892
5342
|
if (!file.endsWith(".js")) continue;
|
|
4893
5343
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
4894
|
-
const filePath =
|
|
5344
|
+
const filePath = path6.join(dir, file);
|
|
4895
5345
|
result[scriptName] = (..._args) => {
|
|
4896
5346
|
try {
|
|
4897
|
-
return
|
|
5347
|
+
return fs5.readFileSync(filePath, "utf-8");
|
|
4898
5348
|
} catch {
|
|
4899
5349
|
return "";
|
|
4900
5350
|
}
|
|
@@ -4912,20 +5362,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4912
5362
|
* Structure: dir/category/agent-name/provider.{json,js}
|
|
4913
5363
|
*/
|
|
4914
5364
|
loadDir(dir, excludeDirs) {
|
|
4915
|
-
if (!
|
|
5365
|
+
if (!fs5.existsSync(dir)) return 0;
|
|
4916
5366
|
let count = 0;
|
|
4917
5367
|
const scan = (d) => {
|
|
4918
5368
|
let entries;
|
|
4919
5369
|
try {
|
|
4920
|
-
entries =
|
|
5370
|
+
entries = fs5.readdirSync(d, { withFileTypes: true });
|
|
4921
5371
|
} catch {
|
|
4922
5372
|
return;
|
|
4923
5373
|
}
|
|
4924
5374
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
4925
5375
|
if (hasJson) {
|
|
4926
|
-
const jsonPath =
|
|
5376
|
+
const jsonPath = path6.join(d, "provider.json");
|
|
4927
5377
|
try {
|
|
4928
|
-
const raw =
|
|
5378
|
+
const raw = fs5.readFileSync(jsonPath, "utf-8");
|
|
4929
5379
|
const mod = JSON.parse(raw);
|
|
4930
5380
|
if (!mod.type || !mod.name || !mod.category) {
|
|
4931
5381
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
|
|
@@ -4936,8 +5386,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4936
5386
|
delete mod.extensionIdPattern_flags;
|
|
4937
5387
|
}
|
|
4938
5388
|
const hasCompatibility = Array.isArray(mod.compatibility);
|
|
4939
|
-
const scriptsPath =
|
|
4940
|
-
if (!hasCompatibility &&
|
|
5389
|
+
const scriptsPath = path6.join(d, "scripts.js");
|
|
5390
|
+
if (!hasCompatibility && fs5.existsSync(scriptsPath)) {
|
|
4941
5391
|
try {
|
|
4942
5392
|
delete require.cache[require.resolve(scriptsPath)];
|
|
4943
5393
|
const scripts = require(scriptsPath);
|
|
@@ -4962,7 +5412,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
4962
5412
|
if (!entry.isDirectory()) continue;
|
|
4963
5413
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
4964
5414
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
4965
|
-
scan(
|
|
5415
|
+
scan(path6.join(d, entry.name));
|
|
4966
5416
|
}
|
|
4967
5417
|
}
|
|
4968
5418
|
};
|
|
@@ -5041,17 +5491,17 @@ async function findFreePort(ports) {
|
|
|
5041
5491
|
throw new Error("No free port found");
|
|
5042
5492
|
}
|
|
5043
5493
|
function checkPortFree(port) {
|
|
5044
|
-
return new Promise((
|
|
5494
|
+
return new Promise((resolve7) => {
|
|
5045
5495
|
const server = net.createServer();
|
|
5046
5496
|
server.unref();
|
|
5047
|
-
server.on("error", () =>
|
|
5497
|
+
server.on("error", () => resolve7(false));
|
|
5048
5498
|
server.listen(port, "127.0.0.1", () => {
|
|
5049
|
-
server.close(() =>
|
|
5499
|
+
server.close(() => resolve7(true));
|
|
5050
5500
|
});
|
|
5051
5501
|
});
|
|
5052
5502
|
}
|
|
5053
5503
|
async function isCdpActive(port) {
|
|
5054
|
-
return new Promise((
|
|
5504
|
+
return new Promise((resolve7) => {
|
|
5055
5505
|
const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
|
|
5056
5506
|
timeout: 2e3
|
|
5057
5507
|
}, (res) => {
|
|
@@ -5060,52 +5510,52 @@ async function isCdpActive(port) {
|
|
|
5060
5510
|
res.on("end", () => {
|
|
5061
5511
|
try {
|
|
5062
5512
|
const info = JSON.parse(data);
|
|
5063
|
-
|
|
5513
|
+
resolve7(!!info["WebKit-Version"] || !!info["Browser"]);
|
|
5064
5514
|
} catch {
|
|
5065
|
-
|
|
5515
|
+
resolve7(false);
|
|
5066
5516
|
}
|
|
5067
5517
|
});
|
|
5068
5518
|
});
|
|
5069
|
-
req.on("error", () =>
|
|
5519
|
+
req.on("error", () => resolve7(false));
|
|
5070
5520
|
req.on("timeout", () => {
|
|
5071
5521
|
req.destroy();
|
|
5072
|
-
|
|
5522
|
+
resolve7(false);
|
|
5073
5523
|
});
|
|
5074
5524
|
});
|
|
5075
5525
|
}
|
|
5076
5526
|
async function killIdeProcess(ideId) {
|
|
5077
|
-
const plat =
|
|
5527
|
+
const plat = os8.platform();
|
|
5078
5528
|
const appName = getMacAppIdentifiers()[ideId];
|
|
5079
5529
|
const winProcesses = getWinProcessNames()[ideId];
|
|
5080
5530
|
try {
|
|
5081
5531
|
if (plat === "darwin" && appName) {
|
|
5082
5532
|
try {
|
|
5083
|
-
(0,
|
|
5533
|
+
(0, import_child_process4.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
|
|
5084
5534
|
timeout: 5e3
|
|
5085
5535
|
});
|
|
5086
5536
|
} catch {
|
|
5087
5537
|
try {
|
|
5088
|
-
(0,
|
|
5538
|
+
(0, import_child_process4.execSync)(`pkill -f "${appName}" 2>/dev/null`);
|
|
5089
5539
|
} catch {
|
|
5090
5540
|
}
|
|
5091
5541
|
}
|
|
5092
5542
|
} else if (plat === "win32" && winProcesses) {
|
|
5093
5543
|
for (const proc of winProcesses) {
|
|
5094
5544
|
try {
|
|
5095
|
-
(0,
|
|
5545
|
+
(0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
|
|
5096
5546
|
} catch {
|
|
5097
5547
|
}
|
|
5098
5548
|
}
|
|
5099
5549
|
try {
|
|
5100
5550
|
const exeName = winProcesses[0].replace(".exe", "");
|
|
5101
|
-
(0,
|
|
5551
|
+
(0, import_child_process4.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
|
|
5102
5552
|
timeout: 1e4
|
|
5103
5553
|
});
|
|
5104
5554
|
} catch {
|
|
5105
5555
|
}
|
|
5106
5556
|
} else {
|
|
5107
5557
|
try {
|
|
5108
|
-
(0,
|
|
5558
|
+
(0, import_child_process4.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
|
|
5109
5559
|
} catch {
|
|
5110
5560
|
}
|
|
5111
5561
|
}
|
|
@@ -5115,13 +5565,13 @@ async function killIdeProcess(ideId) {
|
|
|
5115
5565
|
}
|
|
5116
5566
|
if (plat === "darwin" && appName) {
|
|
5117
5567
|
try {
|
|
5118
|
-
(0,
|
|
5568
|
+
(0, import_child_process4.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
|
|
5119
5569
|
} catch {
|
|
5120
5570
|
}
|
|
5121
5571
|
} else if (plat === "win32" && winProcesses) {
|
|
5122
5572
|
for (const proc of winProcesses) {
|
|
5123
5573
|
try {
|
|
5124
|
-
(0,
|
|
5574
|
+
(0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
|
|
5125
5575
|
} catch {
|
|
5126
5576
|
}
|
|
5127
5577
|
}
|
|
@@ -5133,26 +5583,26 @@ async function killIdeProcess(ideId) {
|
|
|
5133
5583
|
}
|
|
5134
5584
|
}
|
|
5135
5585
|
function isIdeRunning(ideId) {
|
|
5136
|
-
const plat =
|
|
5586
|
+
const plat = os8.platform();
|
|
5137
5587
|
try {
|
|
5138
5588
|
if (plat === "darwin") {
|
|
5139
5589
|
const appName = getMacAppIdentifiers()[ideId];
|
|
5140
5590
|
if (!appName) return false;
|
|
5141
|
-
const result = (0,
|
|
5591
|
+
const result = (0, import_child_process4.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
|
|
5142
5592
|
return result.trim().length > 0;
|
|
5143
5593
|
} else if (plat === "win32") {
|
|
5144
5594
|
const winProcesses = getWinProcessNames()[ideId];
|
|
5145
5595
|
if (!winProcesses) return false;
|
|
5146
5596
|
for (const proc of winProcesses) {
|
|
5147
5597
|
try {
|
|
5148
|
-
const result = (0,
|
|
5598
|
+
const result = (0, import_child_process4.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
|
|
5149
5599
|
if (result.includes(proc)) return true;
|
|
5150
5600
|
} catch {
|
|
5151
5601
|
}
|
|
5152
5602
|
}
|
|
5153
5603
|
try {
|
|
5154
5604
|
const exeName = winProcesses[0].replace(".exe", "");
|
|
5155
|
-
const result = (0,
|
|
5605
|
+
const result = (0, import_child_process4.execSync)(
|
|
5156
5606
|
`powershell -Command "(Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue).Count"`,
|
|
5157
5607
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
5158
5608
|
);
|
|
@@ -5161,7 +5611,7 @@ function isIdeRunning(ideId) {
|
|
|
5161
5611
|
}
|
|
5162
5612
|
return false;
|
|
5163
5613
|
} else {
|
|
5164
|
-
const result = (0,
|
|
5614
|
+
const result = (0, import_child_process4.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
|
|
5165
5615
|
return result.trim().length > 0;
|
|
5166
5616
|
}
|
|
5167
5617
|
} catch {
|
|
@@ -5169,12 +5619,12 @@ function isIdeRunning(ideId) {
|
|
|
5169
5619
|
}
|
|
5170
5620
|
}
|
|
5171
5621
|
function detectCurrentWorkspace(ideId) {
|
|
5172
|
-
const plat =
|
|
5622
|
+
const plat = os8.platform();
|
|
5173
5623
|
if (plat === "darwin") {
|
|
5174
5624
|
try {
|
|
5175
5625
|
const appName = getMacAppIdentifiers()[ideId];
|
|
5176
5626
|
if (!appName) return void 0;
|
|
5177
|
-
const result = (0,
|
|
5627
|
+
const result = (0, import_child_process4.execSync)(
|
|
5178
5628
|
`lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
|
|
5179
5629
|
{ encoding: "utf-8", timeout: 3e3 }
|
|
5180
5630
|
);
|
|
@@ -5184,17 +5634,17 @@ function detectCurrentWorkspace(ideId) {
|
|
|
5184
5634
|
}
|
|
5185
5635
|
} else if (plat === "win32") {
|
|
5186
5636
|
try {
|
|
5187
|
-
const
|
|
5637
|
+
const fs10 = require("fs");
|
|
5188
5638
|
const appNameMap = getMacAppIdentifiers();
|
|
5189
5639
|
const appName = appNameMap[ideId];
|
|
5190
5640
|
if (appName) {
|
|
5191
|
-
const storagePath =
|
|
5192
|
-
process.env.APPDATA ||
|
|
5641
|
+
const storagePath = path7.join(
|
|
5642
|
+
process.env.APPDATA || path7.join(os8.homedir(), "AppData", "Roaming"),
|
|
5193
5643
|
appName,
|
|
5194
5644
|
"storage.json"
|
|
5195
5645
|
);
|
|
5196
|
-
if (
|
|
5197
|
-
const data = JSON.parse(
|
|
5646
|
+
if (fs10.existsSync(storagePath)) {
|
|
5647
|
+
const data = JSON.parse(fs10.readFileSync(storagePath, "utf-8"));
|
|
5198
5648
|
const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
|
|
5199
5649
|
if (workspaces.length > 0) {
|
|
5200
5650
|
const recent = workspaces[0];
|
|
@@ -5211,7 +5661,7 @@ function detectCurrentWorkspace(ideId) {
|
|
|
5211
5661
|
return void 0;
|
|
5212
5662
|
}
|
|
5213
5663
|
async function launchWithCdp(options = {}) {
|
|
5214
|
-
const
|
|
5664
|
+
const platform8 = os8.platform();
|
|
5215
5665
|
let targetIde;
|
|
5216
5666
|
const ides = await detectIDEs();
|
|
5217
5667
|
if (options.ideId) {
|
|
@@ -5280,9 +5730,9 @@ async function launchWithCdp(options = {}) {
|
|
|
5280
5730
|
}
|
|
5281
5731
|
const port = await findFreePort(portPair);
|
|
5282
5732
|
try {
|
|
5283
|
-
if (
|
|
5733
|
+
if (platform8 === "darwin") {
|
|
5284
5734
|
await launchMacOS(targetIde, port, workspace, options.newWindow);
|
|
5285
|
-
} else if (
|
|
5735
|
+
} else if (platform8 === "win32") {
|
|
5286
5736
|
await launchWindows(targetIde, port, workspace, options.newWindow);
|
|
5287
5737
|
} else {
|
|
5288
5738
|
await launchLinux(targetIde, port, workspace, options.newWindow);
|
|
@@ -5322,9 +5772,9 @@ async function launchMacOS(ide, port, workspace, newWindow) {
|
|
|
5322
5772
|
if (workspace) args.push(workspace);
|
|
5323
5773
|
if (appName) {
|
|
5324
5774
|
const openArgs = ["-a", appName, "--args", ...args];
|
|
5325
|
-
(0,
|
|
5775
|
+
(0, import_child_process4.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
|
|
5326
5776
|
} else if (ide.cliCommand) {
|
|
5327
|
-
(0,
|
|
5777
|
+
(0, import_child_process4.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
|
|
5328
5778
|
} else {
|
|
5329
5779
|
throw new Error(`No app identifier or CLI for ${ide.displayName}`);
|
|
5330
5780
|
}
|
|
@@ -5350,21 +5800,25 @@ async function launchLinux(ide, port, workspace, newWindow) {
|
|
|
5350
5800
|
const args = ["--remote-debugging-port=" + port];
|
|
5351
5801
|
if (newWindow) args.push("--new-window");
|
|
5352
5802
|
if (workspace) args.push(workspace);
|
|
5353
|
-
(0,
|
|
5803
|
+
(0, import_child_process4.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
|
|
5354
5804
|
}
|
|
5355
5805
|
function getAvailableIdeIds() {
|
|
5356
5806
|
return getProviderLoader().getAvailableIdeTypes();
|
|
5357
5807
|
}
|
|
5358
5808
|
|
|
5809
|
+
// src/commands/router.ts
|
|
5810
|
+
init_config();
|
|
5811
|
+
init_workspaces();
|
|
5812
|
+
|
|
5359
5813
|
// src/logging/command-log.ts
|
|
5360
|
-
var
|
|
5361
|
-
var
|
|
5362
|
-
var
|
|
5363
|
-
var LOG_DIR2 = process.platform === "darwin" ?
|
|
5814
|
+
var fs6 = __toESM(require("fs"));
|
|
5815
|
+
var path8 = __toESM(require("path"));
|
|
5816
|
+
var os9 = __toESM(require("os"));
|
|
5817
|
+
var LOG_DIR2 = process.platform === "darwin" ? path8.join(os9.homedir(), "Library", "Logs", "adhdev") : path8.join(os9.homedir(), ".local", "share", "adhdev", "logs");
|
|
5364
5818
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
5365
5819
|
var MAX_DAYS = 7;
|
|
5366
5820
|
try {
|
|
5367
|
-
|
|
5821
|
+
fs6.mkdirSync(LOG_DIR2, { recursive: true });
|
|
5368
5822
|
} catch {
|
|
5369
5823
|
}
|
|
5370
5824
|
var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -5398,19 +5852,19 @@ function getDateStr2() {
|
|
|
5398
5852
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5399
5853
|
}
|
|
5400
5854
|
var currentDate2 = getDateStr2();
|
|
5401
|
-
var currentFile =
|
|
5855
|
+
var currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
5402
5856
|
var writeCount2 = 0;
|
|
5403
5857
|
function checkRotation() {
|
|
5404
5858
|
const today = getDateStr2();
|
|
5405
5859
|
if (today !== currentDate2) {
|
|
5406
5860
|
currentDate2 = today;
|
|
5407
|
-
currentFile =
|
|
5861
|
+
currentFile = path8.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
5408
5862
|
cleanOldFiles();
|
|
5409
5863
|
}
|
|
5410
5864
|
}
|
|
5411
5865
|
function cleanOldFiles() {
|
|
5412
5866
|
try {
|
|
5413
|
-
const files =
|
|
5867
|
+
const files = fs6.readdirSync(LOG_DIR2).filter((f) => f.startsWith("commands-") && f.endsWith(".jsonl"));
|
|
5414
5868
|
const cutoff = /* @__PURE__ */ new Date();
|
|
5415
5869
|
cutoff.setDate(cutoff.getDate() - MAX_DAYS);
|
|
5416
5870
|
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
@@ -5418,7 +5872,7 @@ function cleanOldFiles() {
|
|
|
5418
5872
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
5419
5873
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
5420
5874
|
try {
|
|
5421
|
-
|
|
5875
|
+
fs6.unlinkSync(path8.join(LOG_DIR2, file));
|
|
5422
5876
|
} catch {
|
|
5423
5877
|
}
|
|
5424
5878
|
}
|
|
@@ -5428,14 +5882,14 @@ function cleanOldFiles() {
|
|
|
5428
5882
|
}
|
|
5429
5883
|
function checkSize() {
|
|
5430
5884
|
try {
|
|
5431
|
-
const stat =
|
|
5885
|
+
const stat = fs6.statSync(currentFile);
|
|
5432
5886
|
if (stat.size > MAX_FILE_SIZE) {
|
|
5433
5887
|
const backup = currentFile.replace(".jsonl", ".1.jsonl");
|
|
5434
5888
|
try {
|
|
5435
|
-
|
|
5889
|
+
fs6.unlinkSync(backup);
|
|
5436
5890
|
} catch {
|
|
5437
5891
|
}
|
|
5438
|
-
|
|
5892
|
+
fs6.renameSync(currentFile, backup);
|
|
5439
5893
|
}
|
|
5440
5894
|
} catch {
|
|
5441
5895
|
}
|
|
@@ -5460,14 +5914,14 @@ function logCommand(entry) {
|
|
|
5460
5914
|
...entry.error ? { err: entry.error } : {},
|
|
5461
5915
|
...entry.durationMs !== void 0 ? { ms: entry.durationMs } : {}
|
|
5462
5916
|
});
|
|
5463
|
-
|
|
5917
|
+
fs6.appendFileSync(currentFile, line + "\n");
|
|
5464
5918
|
} catch {
|
|
5465
5919
|
}
|
|
5466
5920
|
}
|
|
5467
5921
|
function getRecentCommands(count = 50) {
|
|
5468
5922
|
try {
|
|
5469
|
-
if (!
|
|
5470
|
-
const content =
|
|
5923
|
+
if (!fs6.existsSync(currentFile)) return [];
|
|
5924
|
+
const content = fs6.readFileSync(currentFile, "utf-8");
|
|
5471
5925
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
5472
5926
|
return lines.slice(-count).map((line) => {
|
|
5473
5927
|
try {
|
|
@@ -5492,7 +5946,7 @@ function getRecentCommands(count = 50) {
|
|
|
5492
5946
|
cleanOldFiles();
|
|
5493
5947
|
|
|
5494
5948
|
// src/commands/router.ts
|
|
5495
|
-
var
|
|
5949
|
+
var fs7 = __toESM(require("fs"));
|
|
5496
5950
|
var CHAT_COMMANDS = [
|
|
5497
5951
|
"send_chat",
|
|
5498
5952
|
"new_chat",
|
|
@@ -5562,8 +6016,8 @@ var DaemonCommandRouter = class {
|
|
|
5562
6016
|
if (logs.length > 0) {
|
|
5563
6017
|
return { success: true, logs, totalBuffered: logs.length };
|
|
5564
6018
|
}
|
|
5565
|
-
if (
|
|
5566
|
-
const content =
|
|
6019
|
+
if (fs7.existsSync(LOG_PATH)) {
|
|
6020
|
+
const content = fs7.readFileSync(LOG_PATH, "utf-8");
|
|
5567
6021
|
const allLines = content.split("\n");
|
|
5568
6022
|
const recent = allLines.slice(-count).join("\n");
|
|
5569
6023
|
return { success: true, logs: recent, totalLines: allLines.length };
|
|
@@ -5602,8 +6056,20 @@ var DaemonCommandRouter = class {
|
|
|
5602
6056
|
}
|
|
5603
6057
|
// ─── IDE launch + CDP connect ───
|
|
5604
6058
|
case "launch_ide": {
|
|
5605
|
-
const
|
|
5606
|
-
const
|
|
6059
|
+
const ideKey = args?.ideId || args?.ideType;
|
|
6060
|
+
const resolvedWorkspace = resolveIdeLaunchWorkspace(
|
|
6061
|
+
{
|
|
6062
|
+
workspace: args?.workspace,
|
|
6063
|
+
workspaceId: args?.workspaceId,
|
|
6064
|
+
useDefaultWorkspace: args?.useDefaultWorkspace
|
|
6065
|
+
},
|
|
6066
|
+
loadConfig()
|
|
6067
|
+
);
|
|
6068
|
+
const launchArgs = {
|
|
6069
|
+
ideId: ideKey,
|
|
6070
|
+
workspace: resolvedWorkspace,
|
|
6071
|
+
newWindow: args?.newWindow
|
|
6072
|
+
};
|
|
5607
6073
|
LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
|
|
5608
6074
|
const result = await launchWithCdp(launchArgs);
|
|
5609
6075
|
if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
|
|
@@ -5620,6 +6086,15 @@ var DaemonCommandRouter = class {
|
|
|
5620
6086
|
}
|
|
5621
6087
|
}
|
|
5622
6088
|
this.deps.onIdeConnected?.();
|
|
6089
|
+
if (result.success && resolvedWorkspace) {
|
|
6090
|
+
try {
|
|
6091
|
+
saveConfig(appendWorkspaceActivity(loadConfig(), resolvedWorkspace, {
|
|
6092
|
+
kind: "ide",
|
|
6093
|
+
agentType: result.ideId
|
|
6094
|
+
}));
|
|
6095
|
+
} catch {
|
|
6096
|
+
}
|
|
6097
|
+
}
|
|
5623
6098
|
return { success: result.success, ...result };
|
|
5624
6099
|
}
|
|
5625
6100
|
// ─── IDE detection ───
|
|
@@ -5627,6 +6102,12 @@ var DaemonCommandRouter = class {
|
|
|
5627
6102
|
this.deps.detectedIdes.value = await detectIDEs();
|
|
5628
6103
|
return { success: true, ides: this.deps.detectedIdes.value };
|
|
5629
6104
|
}
|
|
6105
|
+
// ─── Machine Settings ───
|
|
6106
|
+
case "set_machine_nickname": {
|
|
6107
|
+
const nickname = args?.nickname;
|
|
6108
|
+
updateConfig({ machineNickname: nickname || null });
|
|
6109
|
+
return { success: true };
|
|
6110
|
+
}
|
|
5630
6111
|
}
|
|
5631
6112
|
return null;
|
|
5632
6113
|
}
|
|
@@ -5663,8 +6144,9 @@ var DaemonCommandRouter = class {
|
|
|
5663
6144
|
};
|
|
5664
6145
|
|
|
5665
6146
|
// src/status/reporter.ts
|
|
5666
|
-
var
|
|
6147
|
+
var os10 = __toESM(require("os"));
|
|
5667
6148
|
init_config();
|
|
6149
|
+
init_workspaces();
|
|
5668
6150
|
var DaemonStatusReporter = class {
|
|
5669
6151
|
deps;
|
|
5670
6152
|
log;
|
|
@@ -5731,6 +6213,10 @@ var DaemonStatusReporter = class {
|
|
|
5731
6213
|
// (agent-stream polling backward compat)
|
|
5732
6214
|
updateAgentStreams(_ideType, _streams) {
|
|
5733
6215
|
}
|
|
6216
|
+
/** Reset P2P dedup hash — forces next send to transmit even if content unchanged */
|
|
6217
|
+
resetP2PHash() {
|
|
6218
|
+
this.lastP2PStatusHash = "";
|
|
6219
|
+
}
|
|
5734
6220
|
// ─── Core ────────────────────────────────────────
|
|
5735
6221
|
ts() {
|
|
5736
6222
|
return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
@@ -5810,18 +6296,26 @@ var DaemonStatusReporter = class {
|
|
|
5810
6296
|
acpConfigOptions: s.acpConfigOptions,
|
|
5811
6297
|
acpModes: s.acpModes
|
|
5812
6298
|
}));
|
|
6299
|
+
const cfg = loadConfig();
|
|
6300
|
+
const wsState = getWorkspaceState(cfg);
|
|
6301
|
+
const memSnap = getHostMemorySnapshot();
|
|
5813
6302
|
const payload = {
|
|
5814
6303
|
daemonMode: true,
|
|
5815
|
-
machineNickname:
|
|
6304
|
+
machineNickname: cfg.machineNickname || null,
|
|
6305
|
+
workspaces: wsState.workspaces,
|
|
6306
|
+
defaultWorkspaceId: wsState.defaultWorkspaceId,
|
|
6307
|
+
defaultWorkspacePath: wsState.defaultWorkspacePath,
|
|
6308
|
+
workspaceActivity: getWorkspaceActivity(cfg, 15),
|
|
5816
6309
|
machine: {
|
|
5817
|
-
hostname:
|
|
5818
|
-
platform:
|
|
5819
|
-
arch:
|
|
5820
|
-
cpus:
|
|
5821
|
-
totalMem:
|
|
5822
|
-
freeMem:
|
|
5823
|
-
|
|
5824
|
-
|
|
6310
|
+
hostname: os10.hostname(),
|
|
6311
|
+
platform: os10.platform(),
|
|
6312
|
+
arch: os10.arch(),
|
|
6313
|
+
cpus: os10.cpus().length,
|
|
6314
|
+
totalMem: memSnap.totalMem,
|
|
6315
|
+
freeMem: memSnap.freeMem,
|
|
6316
|
+
availableMem: memSnap.availableMem,
|
|
6317
|
+
loadavg: os10.loadavg(),
|
|
6318
|
+
uptime: os10.uptime()
|
|
5825
6319
|
},
|
|
5826
6320
|
managedIdes,
|
|
5827
6321
|
managedClis,
|
|
@@ -5853,6 +6347,8 @@ var DaemonStatusReporter = class {
|
|
|
5853
6347
|
const wsPayload = {
|
|
5854
6348
|
daemonMode: true,
|
|
5855
6349
|
machineNickname: payload.machineNickname,
|
|
6350
|
+
defaultWorkspaceId: wsState.defaultWorkspaceId,
|
|
6351
|
+
workspaceCount: (wsState.workspaces || []).length,
|
|
5856
6352
|
// managedIdes: server only saves id, type, cdpConnected
|
|
5857
6353
|
managedIdes: managedIdes.map((ide) => ({
|
|
5858
6354
|
ideType: ide.ideType,
|
|
@@ -5883,7 +6379,7 @@ var DaemonStatusReporter = class {
|
|
|
5883
6379
|
sendP2PPayload(payload) {
|
|
5884
6380
|
const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
|
|
5885
6381
|
if (hashTarget.machine) {
|
|
5886
|
-
const { freeMem: _f, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
|
|
6382
|
+
const { freeMem: _f, availableMem: _a, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
|
|
5887
6383
|
hashTarget.machine = stableMachine;
|
|
5888
6384
|
}
|
|
5889
6385
|
const h = this.simpleHash(JSON.stringify(hashTarget));
|
|
@@ -5905,17 +6401,34 @@ var DaemonStatusReporter = class {
|
|
|
5905
6401
|
};
|
|
5906
6402
|
|
|
5907
6403
|
// src/commands/cli-manager.ts
|
|
5908
|
-
var
|
|
5909
|
-
var
|
|
6404
|
+
var os12 = __toESM(require("os"));
|
|
6405
|
+
var path10 = __toESM(require("path"));
|
|
5910
6406
|
var crypto4 = __toESM(require("crypto"));
|
|
5911
6407
|
var import_chalk = __toESM(require("chalk"));
|
|
5912
6408
|
|
|
5913
6409
|
// src/cli-adapters/provider-cli-adapter.ts
|
|
5914
|
-
var
|
|
5915
|
-
var
|
|
6410
|
+
var os11 = __toESM(require("os"));
|
|
6411
|
+
var path9 = __toESM(require("path"));
|
|
6412
|
+
var import_child_process5 = require("child_process");
|
|
5916
6413
|
var pty;
|
|
5917
6414
|
try {
|
|
5918
6415
|
pty = require("node-pty");
|
|
6416
|
+
if (os11.platform() !== "win32") {
|
|
6417
|
+
try {
|
|
6418
|
+
const fs10 = require("fs");
|
|
6419
|
+
const ptyDir = path9.dirname(require.resolve("node-pty"));
|
|
6420
|
+
const arch3 = os11.arch() === "arm64" ? "darwin-arm64" : "darwin-x64";
|
|
6421
|
+
const helper = path9.join(ptyDir, "prebuilds", arch3, "spawn-helper");
|
|
6422
|
+
if (fs10.existsSync(helper)) {
|
|
6423
|
+
const stat = fs10.statSync(helper);
|
|
6424
|
+
if (!(stat.mode & 73)) {
|
|
6425
|
+
fs10.chmodSync(helper, stat.mode | 493);
|
|
6426
|
+
LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6429
|
+
} catch {
|
|
6430
|
+
}
|
|
6431
|
+
}
|
|
5919
6432
|
} catch {
|
|
5920
6433
|
LOG.error("CLI", "[ProviderCliAdapter] node-pty not found. Install: npm install node-pty@1.0.0");
|
|
5921
6434
|
}
|
|
@@ -5923,21 +6436,125 @@ function stripAnsi(str) {
|
|
|
5923
6436
|
return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
|
|
5924
6437
|
}
|
|
5925
6438
|
function findBinary(name) {
|
|
5926
|
-
const isWin =
|
|
6439
|
+
const isWin = os11.platform() === "win32";
|
|
5927
6440
|
try {
|
|
5928
6441
|
const cmd = isWin ? `where ${name}` : `which ${name}`;
|
|
5929
|
-
return (0,
|
|
6442
|
+
return (0, import_child_process5.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
|
|
5930
6443
|
} catch {
|
|
5931
6444
|
return isWin ? `${name}.cmd` : name;
|
|
5932
6445
|
}
|
|
5933
6446
|
}
|
|
6447
|
+
function isScriptBinary(binaryPath) {
|
|
6448
|
+
if (!path9.isAbsolute(binaryPath)) return false;
|
|
6449
|
+
try {
|
|
6450
|
+
const fs10 = require("fs");
|
|
6451
|
+
const resolved = fs10.realpathSync(binaryPath);
|
|
6452
|
+
const head = Buffer.alloc(8);
|
|
6453
|
+
const fd = fs10.openSync(resolved, "r");
|
|
6454
|
+
fs10.readSync(fd, head, 0, 8, 0);
|
|
6455
|
+
fs10.closeSync(fd);
|
|
6456
|
+
let i = 0;
|
|
6457
|
+
if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
|
|
6458
|
+
return head[i] === 35 && head[i + 1] === 33;
|
|
6459
|
+
} catch {
|
|
6460
|
+
return false;
|
|
6461
|
+
}
|
|
6462
|
+
}
|
|
6463
|
+
function looksLikeMachOOrElf(filePath) {
|
|
6464
|
+
if (!path9.isAbsolute(filePath)) return false;
|
|
6465
|
+
try {
|
|
6466
|
+
const fs10 = require("fs");
|
|
6467
|
+
const resolved = fs10.realpathSync(filePath);
|
|
6468
|
+
const buf = Buffer.alloc(8);
|
|
6469
|
+
const fd = fs10.openSync(resolved, "r");
|
|
6470
|
+
fs10.readSync(fd, buf, 0, 8, 0);
|
|
6471
|
+
fs10.closeSync(fd);
|
|
6472
|
+
let i = 0;
|
|
6473
|
+
if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
|
|
6474
|
+
const b = buf.subarray(i);
|
|
6475
|
+
if (b.length < 4) return false;
|
|
6476
|
+
if (b[0] === 127 && b[1] === 69 && b[2] === 76 && b[3] === 70) return true;
|
|
6477
|
+
const le = b.readUInt32LE(0);
|
|
6478
|
+
const be = b.readUInt32BE(0);
|
|
6479
|
+
const magics = [4277009102, 4277009103, 3405691582, 3199925962];
|
|
6480
|
+
return magics.some((m) => m === le || m === be);
|
|
6481
|
+
} catch {
|
|
6482
|
+
return false;
|
|
6483
|
+
}
|
|
6484
|
+
}
|
|
6485
|
+
function shSingleQuote(arg) {
|
|
6486
|
+
if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
|
|
6487
|
+
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
6488
|
+
}
|
|
6489
|
+
function parsePatternEntry(x) {
|
|
6490
|
+
if (x instanceof RegExp) return x;
|
|
6491
|
+
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
6492
|
+
try {
|
|
6493
|
+
const s = x;
|
|
6494
|
+
return new RegExp(s.source, s.flags || "");
|
|
6495
|
+
} catch {
|
|
6496
|
+
return null;
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
return null;
|
|
6500
|
+
}
|
|
6501
|
+
function coercePatternArray(raw, fallbacks) {
|
|
6502
|
+
if (!Array.isArray(raw)) return [...fallbacks];
|
|
6503
|
+
const parsed = raw.map(parsePatternEntry).filter((r) => r != null);
|
|
6504
|
+
return parsed.length > 0 ? parsed : [...fallbacks];
|
|
6505
|
+
}
|
|
6506
|
+
var FALLBACK_PROMPT = [
|
|
6507
|
+
/Type your message/i,
|
|
6508
|
+
/^>\s*$/m,
|
|
6509
|
+
// '>' alone on its own line
|
|
6510
|
+
/[›➤]\s*$/,
|
|
6511
|
+
/for shortcuts/i,
|
|
6512
|
+
/\?\s*for help/i,
|
|
6513
|
+
/Press enter/i
|
|
6514
|
+
// NOTE: removed /^[\s\u2500-\u257f]*>\s*$/m — the box-drawing char range is too wide and
|
|
6515
|
+
// can match dialog-clearing ANSI output, causing false prompt detection in approval state.
|
|
6516
|
+
];
|
|
6517
|
+
var FALLBACK_GENERATING = [
|
|
6518
|
+
/[\u2800-\u28ff]/,
|
|
6519
|
+
// Braille spinner blocks (universal TUI)
|
|
6520
|
+
/esc to (cancel|interrupt|stop)/i,
|
|
6521
|
+
// Common TUI generation status line
|
|
6522
|
+
/generating\.\.\./i,
|
|
6523
|
+
/Claude is (?:thinking|processing|working)/i
|
|
6524
|
+
// Specific Claude Code status
|
|
6525
|
+
];
|
|
6526
|
+
var FALLBACK_APPROVAL = [
|
|
6527
|
+
/Allow\s+once/i,
|
|
6528
|
+
/Always\s+allow/i,
|
|
6529
|
+
/\(y\/n\)/i,
|
|
6530
|
+
/\[Y\/n\]/i,
|
|
6531
|
+
/Run\s+this\s+command/i
|
|
6532
|
+
// NOTE: removed /Do you want to (?:run|execute|allow)/i — too broad, matches AI explanation
|
|
6533
|
+
// text like "Do you want to allow this feature?" causing false approval notifications.
|
|
6534
|
+
];
|
|
6535
|
+
function defaultCleanOutput(raw, _lastUserInput) {
|
|
6536
|
+
return stripAnsi(raw).trim();
|
|
6537
|
+
}
|
|
6538
|
+
function normalizeCliProviderForRuntime(raw) {
|
|
6539
|
+
const patterns = raw?.patterns || {};
|
|
6540
|
+
return {
|
|
6541
|
+
...raw,
|
|
6542
|
+
patterns: {
|
|
6543
|
+
prompt: coercePatternArray(patterns.prompt, FALLBACK_PROMPT),
|
|
6544
|
+
generating: coercePatternArray(patterns.generating, FALLBACK_GENERATING),
|
|
6545
|
+
approval: coercePatternArray(patterns.approval, FALLBACK_APPROVAL),
|
|
6546
|
+
ready: coercePatternArray(patterns.ready, [])
|
|
6547
|
+
},
|
|
6548
|
+
cleanOutput: typeof raw?.cleanOutput === "function" ? raw.cleanOutput : defaultCleanOutput
|
|
6549
|
+
};
|
|
6550
|
+
}
|
|
5934
6551
|
var ProviderCliAdapter = class {
|
|
5935
6552
|
constructor(provider, workingDir, extraArgs = []) {
|
|
5936
6553
|
this.extraArgs = extraArgs;
|
|
5937
|
-
this.provider = provider;
|
|
6554
|
+
this.provider = normalizeCliProviderForRuntime(provider);
|
|
5938
6555
|
this.cliType = provider.type;
|
|
5939
6556
|
this.cliName = provider.name;
|
|
5940
|
-
this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/,
|
|
6557
|
+
this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os11.homedir()) : workingDir;
|
|
5941
6558
|
const t = provider.timeouts || {};
|
|
5942
6559
|
this.timeouts = {
|
|
5943
6560
|
ptyFlush: t.ptyFlush ?? 50,
|
|
@@ -5974,6 +6591,11 @@ var ProviderCliAdapter = class {
|
|
|
5974
6591
|
logBuffer = [];
|
|
5975
6592
|
// Approval cooldown
|
|
5976
6593
|
lastApprovalResolvedAt = 0;
|
|
6594
|
+
// Approval state machine
|
|
6595
|
+
approvalTransitionBuffer = "";
|
|
6596
|
+
approvalExitTimeout = null;
|
|
6597
|
+
// Resize redraw suppression
|
|
6598
|
+
resizeSuppressUntil = 0;
|
|
5977
6599
|
// Resolved timeouts (provider defaults + overrides)
|
|
5978
6600
|
timeouts;
|
|
5979
6601
|
// ─── Lifecycle ─────────────────────────────────
|
|
@@ -5995,20 +6617,25 @@ var ProviderCliAdapter = class {
|
|
|
5995
6617
|
if (!pty) throw new Error("node-pty is not installed");
|
|
5996
6618
|
const { spawn: spawnConfig } = this.provider;
|
|
5997
6619
|
const binaryPath = findBinary(spawnConfig.command);
|
|
5998
|
-
const isWin =
|
|
6620
|
+
const isWin = os11.platform() === "win32";
|
|
5999
6621
|
const allArgs = [...spawnConfig.args, ...this.extraArgs];
|
|
6000
6622
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
6001
6623
|
let shellCmd;
|
|
6002
6624
|
let shellArgs;
|
|
6003
|
-
|
|
6625
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
6626
|
+
const useShell = isWin ? !!spawnConfig.shell : useShellUnix;
|
|
6627
|
+
if (useShell) {
|
|
6628
|
+
if (!spawnConfig.shell && !isWin) {
|
|
6629
|
+
LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
|
|
6630
|
+
}
|
|
6004
6631
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
6005
|
-
const fullCmd = [binaryPath, ...allArgs].join(" ");
|
|
6632
|
+
const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
|
|
6006
6633
|
shellArgs = isWin ? ["/c", fullCmd] : ["-l", "-c", fullCmd];
|
|
6007
6634
|
} else {
|
|
6008
6635
|
shellCmd = binaryPath;
|
|
6009
6636
|
shellArgs = allArgs;
|
|
6010
6637
|
}
|
|
6011
|
-
|
|
6638
|
+
const ptyOpts = {
|
|
6012
6639
|
name: "xterm-256color",
|
|
6013
6640
|
cols: 120,
|
|
6014
6641
|
rows: 40,
|
|
@@ -6017,7 +6644,21 @@ var ProviderCliAdapter = class {
|
|
|
6017
6644
|
...process.env,
|
|
6018
6645
|
...spawnConfig.env
|
|
6019
6646
|
}
|
|
6020
|
-
}
|
|
6647
|
+
};
|
|
6648
|
+
try {
|
|
6649
|
+
this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
|
|
6650
|
+
} catch (err) {
|
|
6651
|
+
const msg = err?.message || String(err);
|
|
6652
|
+
if (!isWin && !useShell && /posix_spawn|spawn/i.test(msg)) {
|
|
6653
|
+
LOG.warn("CLI", `[${this.cliType}] Direct spawn failed (${msg}), retrying via login shell`);
|
|
6654
|
+
shellCmd = process.env.SHELL || "/bin/zsh";
|
|
6655
|
+
const fullCmd = [binaryPath, ...allArgs].map(shSingleQuote).join(" ");
|
|
6656
|
+
shellArgs = ["-l", "-c", fullCmd];
|
|
6657
|
+
this.ptyProcess = pty.spawn(shellCmd, shellArgs, ptyOpts);
|
|
6658
|
+
} else {
|
|
6659
|
+
throw err;
|
|
6660
|
+
}
|
|
6661
|
+
}
|
|
6021
6662
|
this.ptyProcess.onData((data) => {
|
|
6022
6663
|
this.handleOutput(data);
|
|
6023
6664
|
if (this.onPtyDataCallback) {
|
|
@@ -6045,6 +6686,7 @@ var ProviderCliAdapter = class {
|
|
|
6045
6686
|
}
|
|
6046
6687
|
// ─── Output state machine ────────────────────────────
|
|
6047
6688
|
handleOutput(rawData) {
|
|
6689
|
+
if (Date.now() < this.resizeSuppressUntil) return;
|
|
6048
6690
|
const cleanData = stripAnsi(rawData);
|
|
6049
6691
|
const { patterns } = this.provider;
|
|
6050
6692
|
if (cleanData.trim()) {
|
|
@@ -6077,30 +6719,55 @@ var ProviderCliAdapter = class {
|
|
|
6077
6719
|
const hasApproval = patterns.approval.some((p) => p.test(this.recentOutputBuffer));
|
|
6078
6720
|
if (hasApproval && this.currentStatus !== "waiting_approval") {
|
|
6079
6721
|
if (this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown) return;
|
|
6722
|
+
const ctxLines = this.recentOutputBuffer.split("\n").map((l) => l.trim()).filter((l) => l && !/^[─═╭╮╰╯│]+$/.test(l));
|
|
6080
6723
|
this.isWaitingForResponse = true;
|
|
6081
6724
|
this.currentStatus = "waiting_approval";
|
|
6082
6725
|
this.recentOutputBuffer = "";
|
|
6083
|
-
|
|
6726
|
+
this.approvalTransitionBuffer = "";
|
|
6084
6727
|
this.activeModal = {
|
|
6085
6728
|
message: ctxLines.slice(-5).join(" ").slice(0, 200) || "Approval required",
|
|
6086
6729
|
buttons: ["Allow once", "Always allow", "Deny"]
|
|
6087
6730
|
};
|
|
6088
6731
|
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
6732
|
+
if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
|
|
6733
|
+
this.approvalExitTimeout = setTimeout(() => {
|
|
6734
|
+
if (this.currentStatus === "waiting_approval") {
|
|
6735
|
+
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-exiting waiting_approval`);
|
|
6736
|
+
this.activeModal = null;
|
|
6737
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
6738
|
+
this.recentOutputBuffer = "";
|
|
6739
|
+
this.approvalTransitionBuffer = "";
|
|
6740
|
+
this.approvalExitTimeout = null;
|
|
6741
|
+
this.currentStatus = this.isWaitingForResponse ? "generating" : "idle";
|
|
6742
|
+
this.onStatusChange?.();
|
|
6743
|
+
}
|
|
6744
|
+
}, 6e4);
|
|
6089
6745
|
this.onStatusChange?.();
|
|
6090
6746
|
return;
|
|
6091
6747
|
}
|
|
6092
6748
|
if (this.currentStatus === "waiting_approval") {
|
|
6093
|
-
|
|
6094
|
-
const
|
|
6749
|
+
this.approvalTransitionBuffer = (this.approvalTransitionBuffer + cleanData).slice(-500);
|
|
6750
|
+
const genResume = patterns.generating.some((p) => p.test(this.approvalTransitionBuffer));
|
|
6751
|
+
const promptResume = patterns.prompt.some((p) => p.test(this.approvalTransitionBuffer));
|
|
6095
6752
|
if (genResume) {
|
|
6753
|
+
if (this.approvalExitTimeout) {
|
|
6754
|
+
clearTimeout(this.approvalExitTimeout);
|
|
6755
|
+
this.approvalExitTimeout = null;
|
|
6756
|
+
}
|
|
6096
6757
|
this.currentStatus = "generating";
|
|
6097
6758
|
this.activeModal = null;
|
|
6098
6759
|
this.recentOutputBuffer = "";
|
|
6760
|
+
this.approvalTransitionBuffer = "";
|
|
6099
6761
|
this.lastApprovalResolvedAt = Date.now();
|
|
6100
6762
|
this.onStatusChange?.();
|
|
6101
6763
|
} else if (promptResume) {
|
|
6764
|
+
if (this.approvalExitTimeout) {
|
|
6765
|
+
clearTimeout(this.approvalExitTimeout);
|
|
6766
|
+
this.approvalExitTimeout = null;
|
|
6767
|
+
}
|
|
6102
6768
|
this.activeModal = null;
|
|
6103
6769
|
this.recentOutputBuffer = "";
|
|
6770
|
+
this.approvalTransitionBuffer = "";
|
|
6104
6771
|
this.lastApprovalResolvedAt = Date.now();
|
|
6105
6772
|
this.finishResponse();
|
|
6106
6773
|
}
|
|
@@ -6126,7 +6793,8 @@ var ProviderCliAdapter = class {
|
|
|
6126
6793
|
this.onStatusChange?.();
|
|
6127
6794
|
return;
|
|
6128
6795
|
}
|
|
6129
|
-
|
|
6796
|
+
const trailingLines = cleanData.split("\n").slice(-2).join("\n");
|
|
6797
|
+
if (patterns.prompt.some((p) => p.test(trailingLines))) {
|
|
6130
6798
|
this.finishResponse();
|
|
6131
6799
|
} else {
|
|
6132
6800
|
this.idleTimeout = setTimeout(() => {
|
|
@@ -6147,6 +6815,10 @@ var ProviderCliAdapter = class {
|
|
|
6147
6815
|
clearTimeout(this.idleTimeout);
|
|
6148
6816
|
this.idleTimeout = null;
|
|
6149
6817
|
}
|
|
6818
|
+
if (this.approvalExitTimeout) {
|
|
6819
|
+
clearTimeout(this.approvalExitTimeout);
|
|
6820
|
+
this.approvalExitTimeout = null;
|
|
6821
|
+
}
|
|
6150
6822
|
const lastUserText = this.messages.filter((m) => m.role === "user").pop()?.content;
|
|
6151
6823
|
let response = this.provider.cleanOutput(this.responseBuffer, lastUserText);
|
|
6152
6824
|
if (lastUserText && response) {
|
|
@@ -6196,6 +6868,10 @@ var ProviderCliAdapter = class {
|
|
|
6196
6868
|
this.shutdown();
|
|
6197
6869
|
}
|
|
6198
6870
|
shutdown() {
|
|
6871
|
+
if (this.approvalExitTimeout) {
|
|
6872
|
+
clearTimeout(this.approvalExitTimeout);
|
|
6873
|
+
this.approvalExitTimeout = null;
|
|
6874
|
+
}
|
|
6199
6875
|
if (this.ptyProcess) {
|
|
6200
6876
|
this.ptyProcess.write("");
|
|
6201
6877
|
setTimeout(() => {
|
|
@@ -6223,10 +6899,22 @@ var ProviderCliAdapter = class {
|
|
|
6223
6899
|
writeRaw(data) {
|
|
6224
6900
|
this.ptyProcess?.write(data);
|
|
6225
6901
|
}
|
|
6902
|
+
/**
|
|
6903
|
+
* Resolve an approval modal by navigating to the button at `buttonIndex` and pressing Enter.
|
|
6904
|
+
* Index 0 = first option (already selected by default — just Enter).
|
|
6905
|
+
* Index N = press Arrow Down N times, then Enter.
|
|
6906
|
+
*/
|
|
6907
|
+
resolveModal(buttonIndex) {
|
|
6908
|
+
if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
|
|
6909
|
+
const DOWN = "\x1B[B";
|
|
6910
|
+
const keys = DOWN.repeat(Math.max(0, buttonIndex)) + "\r";
|
|
6911
|
+
this.ptyProcess.write(keys);
|
|
6912
|
+
}
|
|
6226
6913
|
resize(cols, rows) {
|
|
6227
6914
|
if (this.ptyProcess) {
|
|
6228
6915
|
try {
|
|
6229
6916
|
this.ptyProcess.resize(cols, rows);
|
|
6917
|
+
this.resizeSuppressUntil = Date.now() + 300;
|
|
6230
6918
|
} catch {
|
|
6231
6919
|
}
|
|
6232
6920
|
}
|
|
@@ -6235,6 +6923,7 @@ var ProviderCliAdapter = class {
|
|
|
6235
6923
|
|
|
6236
6924
|
// src/commands/cli-manager.ts
|
|
6237
6925
|
init_config();
|
|
6926
|
+
init_workspaces();
|
|
6238
6927
|
|
|
6239
6928
|
// src/providers/cli-provider-instance.ts
|
|
6240
6929
|
var crypto3 = __toESM(require("crypto"));
|
|
@@ -6350,20 +7039,24 @@ var CliProviderInstance = class {
|
|
|
6350
7039
|
const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
6351
7040
|
const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
|
|
6352
7041
|
if (newStatus !== this.lastStatus) {
|
|
7042
|
+
LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
|
|
6353
7043
|
if (this.lastStatus === "idle" && newStatus === "generating") {
|
|
6354
7044
|
this.generatingStartedAt = now;
|
|
6355
7045
|
this.pushEvent({ event: "agent:generating_started", chatTitle, timestamp: now });
|
|
6356
7046
|
} else if (newStatus === "waiting_approval") {
|
|
6357
7047
|
if (!this.generatingStartedAt) this.generatingStartedAt = now;
|
|
7048
|
+
const modal = adapterStatus.activeModal;
|
|
7049
|
+
LOG.info("CLI", `[${this.type}] approval modal: "${modal?.message?.slice(0, 80) ?? "none"}"`);
|
|
6358
7050
|
this.pushEvent({
|
|
6359
7051
|
event: "agent:waiting_approval",
|
|
6360
7052
|
chatTitle,
|
|
6361
7053
|
timestamp: now,
|
|
6362
|
-
modalMessage:
|
|
6363
|
-
modalButtons:
|
|
7054
|
+
modalMessage: modal?.message,
|
|
7055
|
+
modalButtons: modal?.buttons
|
|
6364
7056
|
});
|
|
6365
7057
|
} else if (newStatus === "idle" && (this.lastStatus === "generating" || this.lastStatus === "waiting_approval")) {
|
|
6366
7058
|
const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
|
|
7059
|
+
LOG.info("CLI", `[${this.type}] completed in ${duration}s`);
|
|
6367
7060
|
this.pushEvent({ event: "agent:generating_completed", chatTitle, duration, timestamp: now });
|
|
6368
7061
|
this.generatingStartedAt = 0;
|
|
6369
7062
|
} else if (newStatus === "stopped") {
|
|
@@ -6400,7 +7093,7 @@ var CliProviderInstance = class {
|
|
|
6400
7093
|
|
|
6401
7094
|
// src/providers/acp-provider-instance.ts
|
|
6402
7095
|
var import_stream = require("stream");
|
|
6403
|
-
var
|
|
7096
|
+
var import_child_process6 = require("child_process");
|
|
6404
7097
|
var import_sdk = require("@agentclientprotocol/sdk");
|
|
6405
7098
|
|
|
6406
7099
|
// src/providers/contracts.ts
|
|
@@ -6721,7 +7414,7 @@ var AcpProviderInstance = class {
|
|
|
6721
7414
|
this.errorMessage = null;
|
|
6722
7415
|
this.errorReason = null;
|
|
6723
7416
|
this.stderrBuffer = [];
|
|
6724
|
-
this.process = (0,
|
|
7417
|
+
this.process = (0, import_child_process6.spawn)(command, args, {
|
|
6725
7418
|
cwd: this.workingDir,
|
|
6726
7419
|
env,
|
|
6727
7420
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -6825,13 +7518,13 @@ var AcpProviderInstance = class {
|
|
|
6825
7518
|
}
|
|
6826
7519
|
this.currentStatus = "waiting_approval";
|
|
6827
7520
|
this.detectStatusTransition();
|
|
6828
|
-
const approved = await new Promise((
|
|
6829
|
-
this.permissionResolvers.push(
|
|
7521
|
+
const approved = await new Promise((resolve7) => {
|
|
7522
|
+
this.permissionResolvers.push(resolve7);
|
|
6830
7523
|
setTimeout(() => {
|
|
6831
|
-
const idx = this.permissionResolvers.indexOf(
|
|
7524
|
+
const idx = this.permissionResolvers.indexOf(resolve7);
|
|
6832
7525
|
if (idx >= 0) {
|
|
6833
7526
|
this.permissionResolvers.splice(idx, 1);
|
|
6834
|
-
|
|
7527
|
+
resolve7(false);
|
|
6835
7528
|
}
|
|
6836
7529
|
}, 3e5);
|
|
6837
7530
|
});
|
|
@@ -7301,6 +7994,24 @@ var DaemonCliManager = class {
|
|
|
7301
7994
|
const hash = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
|
|
7302
7995
|
return `${cliType}_${hash}`;
|
|
7303
7996
|
}
|
|
7997
|
+
persistRecentDir(cliType, dir) {
|
|
7998
|
+
try {
|
|
7999
|
+
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
8000
|
+
const provider = this.providerLoader.getByAlias(cliType);
|
|
8001
|
+
const actKind = provider?.category === "acp" ? "acp" : "cli";
|
|
8002
|
+
let next = loadConfig();
|
|
8003
|
+
console.log(import_chalk.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
|
|
8004
|
+
const recent = next.recentCliWorkspaces || [];
|
|
8005
|
+
if (!recent.includes(dir)) {
|
|
8006
|
+
next = { ...next, recentCliWorkspaces: [dir, ...recent].slice(0, 10) };
|
|
8007
|
+
}
|
|
8008
|
+
next = appendWorkspaceActivity(next, dir, { kind: actKind, agentType: normalizedType });
|
|
8009
|
+
saveConfig(next);
|
|
8010
|
+
console.log(import_chalk.default.green(` \u2713 Recent workspace saved: ${dir}`));
|
|
8011
|
+
} catch (e) {
|
|
8012
|
+
console.error(import_chalk.default.red(` \u2717 Failed to save recent workspace: ${e}`));
|
|
8013
|
+
}
|
|
8014
|
+
}
|
|
7304
8015
|
createAdapter(cliType, workingDir, cliArgs) {
|
|
7305
8016
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
7306
8017
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
@@ -7312,8 +8023,9 @@ var DaemonCliManager = class {
|
|
|
7312
8023
|
}
|
|
7313
8024
|
// ─── Session start/management ──────────────────────────────
|
|
7314
8025
|
async startSession(cliType, workingDir, cliArgs, initialModel) {
|
|
7315
|
-
const trimmed = (workingDir ||
|
|
7316
|
-
|
|
8026
|
+
const trimmed = (workingDir || "").trim();
|
|
8027
|
+
if (!trimmed) throw new Error("working directory required");
|
|
8028
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path10.resolve(trimmed);
|
|
7317
8029
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
7318
8030
|
const provider = this.providerLoader.getByAlias(cliType);
|
|
7319
8031
|
const key = crypto4.randomUUID();
|
|
@@ -7323,8 +8035,8 @@ var DaemonCliManager = class {
|
|
|
7323
8035
|
const spawnCmd = provider.spawn?.command;
|
|
7324
8036
|
if (spawnCmd) {
|
|
7325
8037
|
try {
|
|
7326
|
-
const { execSync:
|
|
7327
|
-
|
|
8038
|
+
const { execSync: execSync7 } = require("child_process");
|
|
8039
|
+
execSync7(`which ${spawnCmd}`, { stdio: "ignore" });
|
|
7328
8040
|
} catch {
|
|
7329
8041
|
const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
|
|
7330
8042
|
throw new Error(
|
|
@@ -7391,18 +8103,52 @@ ${installInfo}`
|
|
|
7391
8103
|
const instanceManager = this.deps.getInstanceManager();
|
|
7392
8104
|
if (provider && instanceManager) {
|
|
7393
8105
|
const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key);
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
8106
|
+
try {
|
|
8107
|
+
await instanceManager.addInstance(key, cliInstance, {
|
|
8108
|
+
serverConn: this.deps.getServerConn(),
|
|
8109
|
+
settings: {},
|
|
8110
|
+
onPtyData: (data) => {
|
|
8111
|
+
this.deps.getP2p()?.broadcastPtyOutput(key, data);
|
|
8112
|
+
}
|
|
8113
|
+
});
|
|
8114
|
+
} catch (spawnErr) {
|
|
8115
|
+
LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
|
|
8116
|
+
instanceManager.removeInstance(key);
|
|
8117
|
+
throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
|
|
8118
|
+
}
|
|
7401
8119
|
this.adapters.set(key, cliInstance.getAdapter());
|
|
7402
8120
|
console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
|
|
8121
|
+
const checkStopped = setInterval(() => {
|
|
8122
|
+
try {
|
|
8123
|
+
const adapter = this.adapters.get(key);
|
|
8124
|
+
if (!adapter) {
|
|
8125
|
+
clearInterval(checkStopped);
|
|
8126
|
+
return;
|
|
8127
|
+
}
|
|
8128
|
+
const status = adapter.getStatus?.();
|
|
8129
|
+
if (status?.status === "stopped" || status?.status === "error") {
|
|
8130
|
+
clearInterval(checkStopped);
|
|
8131
|
+
setTimeout(() => {
|
|
8132
|
+
if (this.adapters.has(key)) {
|
|
8133
|
+
this.adapters.delete(key);
|
|
8134
|
+
this.deps.removeAgentTracking(key);
|
|
8135
|
+
instanceManager.removeInstance(key);
|
|
8136
|
+
LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${cliType}`);
|
|
8137
|
+
this.deps.onStatusChange();
|
|
8138
|
+
}
|
|
8139
|
+
}, 5e3);
|
|
8140
|
+
}
|
|
8141
|
+
} catch {
|
|
8142
|
+
}
|
|
8143
|
+
}, 3e3);
|
|
7403
8144
|
} else {
|
|
7404
8145
|
const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
|
|
7405
|
-
|
|
8146
|
+
try {
|
|
8147
|
+
await adapter.spawn();
|
|
8148
|
+
} catch (spawnErr) {
|
|
8149
|
+
LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
|
|
8150
|
+
throw new Error(`Failed to start ${cliInfo.displayName}: ${spawnErr?.message}`);
|
|
8151
|
+
}
|
|
7406
8152
|
const serverConn = this.deps.getServerConn();
|
|
7407
8153
|
if (serverConn && typeof adapter.setServerConn === "function") {
|
|
7408
8154
|
adapter.setServerConn(serverConn);
|
|
@@ -7410,12 +8156,12 @@ ${installInfo}`
|
|
|
7410
8156
|
adapter.setOnStatusChange(() => {
|
|
7411
8157
|
this.deps.onStatusChange();
|
|
7412
8158
|
const status = adapter.getStatus?.();
|
|
7413
|
-
if (status?.status === "stopped") {
|
|
8159
|
+
if (status?.status === "stopped" || status?.status === "error") {
|
|
7414
8160
|
setTimeout(() => {
|
|
7415
8161
|
if (this.adapters.get(key) === adapter) {
|
|
7416
8162
|
this.adapters.delete(key);
|
|
7417
8163
|
this.deps.removeAgentTracking(key);
|
|
7418
|
-
|
|
8164
|
+
LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${adapter.cliType}`);
|
|
7419
8165
|
this.deps.onStatusChange();
|
|
7420
8166
|
}
|
|
7421
8167
|
}, 3e3);
|
|
@@ -7439,12 +8185,24 @@ ${installInfo}`
|
|
|
7439
8185
|
async stopSession(key) {
|
|
7440
8186
|
const adapter = this.adapters.get(key);
|
|
7441
8187
|
if (adapter) {
|
|
7442
|
-
|
|
8188
|
+
try {
|
|
8189
|
+
adapter.shutdown();
|
|
8190
|
+
} catch (e) {
|
|
8191
|
+
LOG.warn("CLI", `Shutdown error for ${adapter.cliType}: ${e?.message} (force-cleaning)`);
|
|
8192
|
+
}
|
|
7443
8193
|
this.adapters.delete(key);
|
|
7444
8194
|
this.deps.removeAgentTracking(key);
|
|
7445
8195
|
this.deps.getInstanceManager()?.removeInstance(key);
|
|
7446
|
-
|
|
8196
|
+
LOG.info("CLI", `\u{1F6D1} Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
|
|
7447
8197
|
this.deps.onStatusChange();
|
|
8198
|
+
} else {
|
|
8199
|
+
const im = this.deps.getInstanceManager();
|
|
8200
|
+
if (im) {
|
|
8201
|
+
im.removeInstance(key);
|
|
8202
|
+
this.deps.removeAgentTracking(key);
|
|
8203
|
+
LOG.warn("CLI", `\u{1F9F9} Force-removed orphan entry: ${key}`);
|
|
8204
|
+
this.deps.onStatusChange();
|
|
8205
|
+
}
|
|
7448
8206
|
}
|
|
7449
8207
|
}
|
|
7450
8208
|
shutdownAll() {
|
|
@@ -7485,8 +8243,28 @@ ${installInfo}`
|
|
|
7485
8243
|
switch (cmd) {
|
|
7486
8244
|
case "launch_cli": {
|
|
7487
8245
|
const cliType = args?.cliType;
|
|
7488
|
-
const
|
|
7489
|
-
const
|
|
8246
|
+
const config = loadConfig();
|
|
8247
|
+
const resolved = resolveLaunchDirectory(
|
|
8248
|
+
{
|
|
8249
|
+
dir: args?.dir,
|
|
8250
|
+
workspaceId: args?.workspaceId,
|
|
8251
|
+
useDefaultWorkspace: args?.useDefaultWorkspace === true,
|
|
8252
|
+
useHome: args?.useHome === true
|
|
8253
|
+
},
|
|
8254
|
+
config
|
|
8255
|
+
);
|
|
8256
|
+
if (!resolved.ok) {
|
|
8257
|
+
const ws = getWorkspaceState(config);
|
|
8258
|
+
return {
|
|
8259
|
+
success: false,
|
|
8260
|
+
error: resolved.message,
|
|
8261
|
+
code: resolved.code,
|
|
8262
|
+
workspaces: ws.workspaces,
|
|
8263
|
+
defaultWorkspacePath: ws.defaultWorkspacePath
|
|
8264
|
+
};
|
|
8265
|
+
}
|
|
8266
|
+
const dir = resolved.path;
|
|
8267
|
+
const launchSource = resolved.source;
|
|
7490
8268
|
if (!cliType) throw new Error("cliType required");
|
|
7491
8269
|
await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
|
|
7492
8270
|
let newKey = null;
|
|
@@ -7495,19 +8273,8 @@ ${installInfo}`
|
|
|
7495
8273
|
newKey = k;
|
|
7496
8274
|
}
|
|
7497
8275
|
}
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
console.log(import_chalk.default.cyan(` \u{1F4C2} Saving recent workspace: ${dir}`));
|
|
7501
|
-
const recent = config.recentCliWorkspaces || [];
|
|
7502
|
-
if (!recent.includes(dir)) {
|
|
7503
|
-
const updated = [dir, ...recent].slice(0, 10);
|
|
7504
|
-
saveConfig({ ...config, recentCliWorkspaces: updated });
|
|
7505
|
-
console.log(import_chalk.default.green(` \u2713 Recent workspace saved: ${dir}`));
|
|
7506
|
-
}
|
|
7507
|
-
} catch (e) {
|
|
7508
|
-
console.error(import_chalk.default.red(` \u2717 Failed to save recent workspace: ${e}`));
|
|
7509
|
-
}
|
|
7510
|
-
return { success: true, cliType, dir, id: newKey, defaultedToHome };
|
|
8276
|
+
this.persistRecentDir(cliType, dir);
|
|
8277
|
+
return { success: true, cliType, dir, id: newKey, launchSource };
|
|
7511
8278
|
}
|
|
7512
8279
|
case "stop_cli": {
|
|
7513
8280
|
const cliType = args?.cliType;
|
|
@@ -7523,11 +8290,32 @@ ${installInfo}`
|
|
|
7523
8290
|
}
|
|
7524
8291
|
case "restart_session": {
|
|
7525
8292
|
const cliType = args?.cliType || args?.agentType || args?.ideType;
|
|
7526
|
-
const
|
|
8293
|
+
const cfg = loadConfig();
|
|
8294
|
+
const rdir = resolveLaunchDirectory(
|
|
8295
|
+
{
|
|
8296
|
+
dir: args?.dir,
|
|
8297
|
+
workspaceId: args?.workspaceId,
|
|
8298
|
+
useDefaultWorkspace: args?.useDefaultWorkspace === true,
|
|
8299
|
+
useHome: args?.useHome === true
|
|
8300
|
+
},
|
|
8301
|
+
cfg
|
|
8302
|
+
);
|
|
8303
|
+
if (!rdir.ok) {
|
|
8304
|
+
const ws = getWorkspaceState(cfg);
|
|
8305
|
+
return {
|
|
8306
|
+
success: false,
|
|
8307
|
+
error: rdir.message,
|
|
8308
|
+
code: rdir.code,
|
|
8309
|
+
workspaces: ws.workspaces,
|
|
8310
|
+
defaultWorkspacePath: ws.defaultWorkspacePath
|
|
8311
|
+
};
|
|
8312
|
+
}
|
|
8313
|
+
const dir = rdir.path;
|
|
7527
8314
|
if (!cliType) throw new Error("cliType required");
|
|
7528
8315
|
const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
|
|
7529
8316
|
if (found) await this.stopSession(found.key);
|
|
7530
8317
|
await this.startSession(cliType, dir);
|
|
8318
|
+
this.persistRecentDir(cliType, dir);
|
|
7531
8319
|
return { success: true, restarted: true };
|
|
7532
8320
|
}
|
|
7533
8321
|
case "agent_command": {
|
|
@@ -8167,12 +8955,12 @@ var ProviderInstanceManager = class {
|
|
|
8167
8955
|
};
|
|
8168
8956
|
|
|
8169
8957
|
// src/providers/version-archive.ts
|
|
8170
|
-
var
|
|
8171
|
-
var
|
|
8172
|
-
var
|
|
8173
|
-
var
|
|
8958
|
+
var fs8 = __toESM(require("fs"));
|
|
8959
|
+
var path11 = __toESM(require("path"));
|
|
8960
|
+
var os13 = __toESM(require("os"));
|
|
8961
|
+
var import_child_process7 = require("child_process");
|
|
8174
8962
|
var import_os3 = require("os");
|
|
8175
|
-
var ARCHIVE_PATH =
|
|
8963
|
+
var ARCHIVE_PATH = path11.join(os13.homedir(), ".adhdev", "version-history.json");
|
|
8176
8964
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
8177
8965
|
var VersionArchive = class {
|
|
8178
8966
|
history = {};
|
|
@@ -8181,8 +8969,8 @@ var VersionArchive = class {
|
|
|
8181
8969
|
}
|
|
8182
8970
|
load() {
|
|
8183
8971
|
try {
|
|
8184
|
-
if (
|
|
8185
|
-
this.history = JSON.parse(
|
|
8972
|
+
if (fs8.existsSync(ARCHIVE_PATH)) {
|
|
8973
|
+
this.history = JSON.parse(fs8.readFileSync(ARCHIVE_PATH, "utf-8"));
|
|
8186
8974
|
}
|
|
8187
8975
|
} catch {
|
|
8188
8976
|
this.history = {};
|
|
@@ -8219,15 +9007,15 @@ var VersionArchive = class {
|
|
|
8219
9007
|
}
|
|
8220
9008
|
save() {
|
|
8221
9009
|
try {
|
|
8222
|
-
|
|
8223
|
-
|
|
9010
|
+
fs8.mkdirSync(path11.dirname(ARCHIVE_PATH), { recursive: true });
|
|
9011
|
+
fs8.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
8224
9012
|
} catch {
|
|
8225
9013
|
}
|
|
8226
9014
|
}
|
|
8227
9015
|
};
|
|
8228
9016
|
function runCommand(cmd, timeout = 1e4) {
|
|
8229
9017
|
try {
|
|
8230
|
-
return (0,
|
|
9018
|
+
return (0, import_child_process7.execSync)(cmd, {
|
|
8231
9019
|
encoding: "utf-8",
|
|
8232
9020
|
timeout,
|
|
8233
9021
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -8259,19 +9047,19 @@ function getVersion(binary, versionCommand) {
|
|
|
8259
9047
|
function checkPathExists2(paths) {
|
|
8260
9048
|
for (const p of paths) {
|
|
8261
9049
|
if (p.includes("*")) {
|
|
8262
|
-
const home =
|
|
8263
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
8264
|
-
if (
|
|
9050
|
+
const home = os13.homedir();
|
|
9051
|
+
const resolved = p.replace(/\*/g, home.split(path11.sep).pop() || "");
|
|
9052
|
+
if (fs8.existsSync(resolved)) return resolved;
|
|
8265
9053
|
} else {
|
|
8266
|
-
if (
|
|
9054
|
+
if (fs8.existsSync(p)) return p;
|
|
8267
9055
|
}
|
|
8268
9056
|
}
|
|
8269
9057
|
return null;
|
|
8270
9058
|
}
|
|
8271
9059
|
function getMacAppVersion(appPath) {
|
|
8272
9060
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
8273
|
-
const plistPath =
|
|
8274
|
-
if (!
|
|
9061
|
+
const plistPath = path11.join(appPath, "Contents", "Info.plist");
|
|
9062
|
+
if (!fs8.existsSync(plistPath)) return null;
|
|
8275
9063
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
8276
9064
|
return raw || null;
|
|
8277
9065
|
}
|
|
@@ -8296,8 +9084,8 @@ async function detectAllVersions(loader, archive) {
|
|
|
8296
9084
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
8297
9085
|
let resolvedBin = cliBin;
|
|
8298
9086
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
8299
|
-
const bundled =
|
|
8300
|
-
if (provider.cli &&
|
|
9087
|
+
const bundled = path11.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
9088
|
+
if (provider.cli && fs8.existsSync(bundled)) resolvedBin = bundled;
|
|
8301
9089
|
}
|
|
8302
9090
|
info.installed = !!(appPath || resolvedBin);
|
|
8303
9091
|
info.path = appPath || null;
|
|
@@ -8336,9 +9124,9 @@ async function detectAllVersions(loader, archive) {
|
|
|
8336
9124
|
|
|
8337
9125
|
// src/daemon/dev-server.ts
|
|
8338
9126
|
var http2 = __toESM(require("http"));
|
|
8339
|
-
var
|
|
8340
|
-
var
|
|
8341
|
-
var
|
|
9127
|
+
var fs9 = __toESM(require("fs"));
|
|
9128
|
+
var path12 = __toESM(require("path"));
|
|
9129
|
+
var os14 = __toESM(require("os"));
|
|
8342
9130
|
|
|
8343
9131
|
// src/daemon/scaffold-template.ts
|
|
8344
9132
|
function generateFiles(type, name, category, opts = {}) {
|
|
@@ -8741,8 +9529,8 @@ var DevServer = class _DevServer {
|
|
|
8741
9529
|
}
|
|
8742
9530
|
getEndpointList() {
|
|
8743
9531
|
return this.routes.map((r) => {
|
|
8744
|
-
const
|
|
8745
|
-
return `${r.method.padEnd(5)} ${
|
|
9532
|
+
const path13 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
9533
|
+
return `${r.method.padEnd(5)} ${path13}`;
|
|
8746
9534
|
});
|
|
8747
9535
|
}
|
|
8748
9536
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -8773,15 +9561,15 @@ var DevServer = class _DevServer {
|
|
|
8773
9561
|
this.json(res, 500, { error: e.message });
|
|
8774
9562
|
}
|
|
8775
9563
|
});
|
|
8776
|
-
return new Promise((
|
|
9564
|
+
return new Promise((resolve7, reject) => {
|
|
8777
9565
|
this.server.listen(port, "127.0.0.1", () => {
|
|
8778
9566
|
this.log(`Dev server listening on http://127.0.0.1:${port}`);
|
|
8779
|
-
|
|
9567
|
+
resolve7();
|
|
8780
9568
|
});
|
|
8781
9569
|
this.server.on("error", (e) => {
|
|
8782
9570
|
if (e.code === "EADDRINUSE") {
|
|
8783
9571
|
this.log(`Port ${port} in use, skipping dev server`);
|
|
8784
|
-
|
|
9572
|
+
resolve7();
|
|
8785
9573
|
} else {
|
|
8786
9574
|
reject(e);
|
|
8787
9575
|
}
|
|
@@ -8864,20 +9652,20 @@ var DevServer = class _DevServer {
|
|
|
8864
9652
|
child.stderr?.on("data", (d) => {
|
|
8865
9653
|
stderr += d.toString().slice(0, 2e3);
|
|
8866
9654
|
});
|
|
8867
|
-
await new Promise((
|
|
9655
|
+
await new Promise((resolve7) => {
|
|
8868
9656
|
const timer = setTimeout(() => {
|
|
8869
9657
|
child.kill();
|
|
8870
|
-
|
|
9658
|
+
resolve7();
|
|
8871
9659
|
}, 3e3);
|
|
8872
9660
|
child.on("exit", () => {
|
|
8873
9661
|
clearTimeout(timer);
|
|
8874
|
-
|
|
9662
|
+
resolve7();
|
|
8875
9663
|
});
|
|
8876
9664
|
child.stdout?.once("data", () => {
|
|
8877
9665
|
setTimeout(() => {
|
|
8878
9666
|
child.kill();
|
|
8879
9667
|
clearTimeout(timer);
|
|
8880
|
-
|
|
9668
|
+
resolve7();
|
|
8881
9669
|
}, 500);
|
|
8882
9670
|
});
|
|
8883
9671
|
});
|
|
@@ -9087,12 +9875,12 @@ var DevServer = class _DevServer {
|
|
|
9087
9875
|
// ─── DevConsole SPA ───
|
|
9088
9876
|
getConsoleDistDir() {
|
|
9089
9877
|
const candidates = [
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9878
|
+
path12.resolve(__dirname, "../../web-devconsole/dist"),
|
|
9879
|
+
path12.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
9880
|
+
path12.join(process.cwd(), "packages/web-devconsole/dist")
|
|
9093
9881
|
];
|
|
9094
9882
|
for (const dir of candidates) {
|
|
9095
|
-
if (
|
|
9883
|
+
if (fs9.existsSync(path12.join(dir, "index.html"))) return dir;
|
|
9096
9884
|
}
|
|
9097
9885
|
return null;
|
|
9098
9886
|
}
|
|
@@ -9102,9 +9890,9 @@ var DevServer = class _DevServer {
|
|
|
9102
9890
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
9103
9891
|
return;
|
|
9104
9892
|
}
|
|
9105
|
-
const htmlPath =
|
|
9893
|
+
const htmlPath = path12.join(distDir, "index.html");
|
|
9106
9894
|
try {
|
|
9107
|
-
const html =
|
|
9895
|
+
const html = fs9.readFileSync(htmlPath, "utf-8");
|
|
9108
9896
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
9109
9897
|
res.end(html);
|
|
9110
9898
|
} catch (e) {
|
|
@@ -9127,15 +9915,15 @@ var DevServer = class _DevServer {
|
|
|
9127
9915
|
this.json(res, 404, { error: "Not found" });
|
|
9128
9916
|
return;
|
|
9129
9917
|
}
|
|
9130
|
-
const safePath =
|
|
9131
|
-
const filePath =
|
|
9918
|
+
const safePath = path12.normalize(pathname).replace(/^\.\.\//, "");
|
|
9919
|
+
const filePath = path12.join(distDir, safePath);
|
|
9132
9920
|
if (!filePath.startsWith(distDir)) {
|
|
9133
9921
|
this.json(res, 403, { error: "Forbidden" });
|
|
9134
9922
|
return;
|
|
9135
9923
|
}
|
|
9136
9924
|
try {
|
|
9137
|
-
const content =
|
|
9138
|
-
const ext =
|
|
9925
|
+
const content = fs9.readFileSync(filePath);
|
|
9926
|
+
const ext = path12.extname(filePath);
|
|
9139
9927
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
9140
9928
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
9141
9929
|
res.end(content);
|
|
@@ -9234,26 +10022,26 @@ var DevServer = class _DevServer {
|
|
|
9234
10022
|
const provider = this.providerLoader.getMeta(type);
|
|
9235
10023
|
if (!provider) return null;
|
|
9236
10024
|
const cat = provider.category;
|
|
9237
|
-
const builtinDir = this.providerLoader.builtinDir ||
|
|
9238
|
-
const userDir =
|
|
10025
|
+
const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
|
|
10026
|
+
const userDir = path12.join(os14.homedir(), ".adhdev", "providers");
|
|
9239
10027
|
const directCandidates = [
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
10028
|
+
path12.join(userDir, type),
|
|
10029
|
+
path12.join(builtinDir, cat, type),
|
|
10030
|
+
path12.join(builtinDir, type)
|
|
9243
10031
|
];
|
|
9244
10032
|
for (const d of directCandidates) {
|
|
9245
|
-
if (
|
|
10033
|
+
if (fs9.existsSync(path12.join(d, "provider.json"))) return d;
|
|
9246
10034
|
}
|
|
9247
|
-
const catDir =
|
|
9248
|
-
if (
|
|
10035
|
+
const catDir = path12.join(builtinDir, cat);
|
|
10036
|
+
if (fs9.existsSync(catDir)) {
|
|
9249
10037
|
try {
|
|
9250
|
-
for (const entry of
|
|
10038
|
+
for (const entry of fs9.readdirSync(catDir, { withFileTypes: true })) {
|
|
9251
10039
|
if (!entry.isDirectory()) continue;
|
|
9252
|
-
const jsonPath =
|
|
9253
|
-
if (
|
|
10040
|
+
const jsonPath = path12.join(catDir, entry.name, "provider.json");
|
|
10041
|
+
if (fs9.existsSync(jsonPath)) {
|
|
9254
10042
|
try {
|
|
9255
|
-
const data = JSON.parse(
|
|
9256
|
-
if (data.type === type) return
|
|
10043
|
+
const data = JSON.parse(fs9.readFileSync(jsonPath, "utf-8"));
|
|
10044
|
+
if (data.type === type) return path12.join(catDir, entry.name);
|
|
9257
10045
|
} catch {
|
|
9258
10046
|
}
|
|
9259
10047
|
}
|
|
@@ -9273,14 +10061,14 @@ var DevServer = class _DevServer {
|
|
|
9273
10061
|
const files = [];
|
|
9274
10062
|
const scan = (d, prefix) => {
|
|
9275
10063
|
try {
|
|
9276
|
-
for (const entry of
|
|
10064
|
+
for (const entry of fs9.readdirSync(d, { withFileTypes: true })) {
|
|
9277
10065
|
if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
|
|
9278
10066
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
9279
10067
|
if (entry.isDirectory()) {
|
|
9280
10068
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
9281
|
-
scan(
|
|
10069
|
+
scan(path12.join(d, entry.name), rel);
|
|
9282
10070
|
} else {
|
|
9283
|
-
const stat =
|
|
10071
|
+
const stat = fs9.statSync(path12.join(d, entry.name));
|
|
9284
10072
|
files.push({ path: rel, size: stat.size, type: "file" });
|
|
9285
10073
|
}
|
|
9286
10074
|
}
|
|
@@ -9303,16 +10091,16 @@ var DevServer = class _DevServer {
|
|
|
9303
10091
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
9304
10092
|
return;
|
|
9305
10093
|
}
|
|
9306
|
-
const fullPath =
|
|
10094
|
+
const fullPath = path12.resolve(dir, path12.normalize(filePath));
|
|
9307
10095
|
if (!fullPath.startsWith(dir)) {
|
|
9308
10096
|
this.json(res, 403, { error: "Forbidden" });
|
|
9309
10097
|
return;
|
|
9310
10098
|
}
|
|
9311
|
-
if (!
|
|
10099
|
+
if (!fs9.existsSync(fullPath) || fs9.statSync(fullPath).isDirectory()) {
|
|
9312
10100
|
this.json(res, 404, { error: `File not found: ${filePath}` });
|
|
9313
10101
|
return;
|
|
9314
10102
|
}
|
|
9315
|
-
const content =
|
|
10103
|
+
const content = fs9.readFileSync(fullPath, "utf-8");
|
|
9316
10104
|
this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
|
|
9317
10105
|
}
|
|
9318
10106
|
/** POST /api/providers/:type/file — write a file { path, content } */
|
|
@@ -9328,15 +10116,15 @@ var DevServer = class _DevServer {
|
|
|
9328
10116
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
9329
10117
|
return;
|
|
9330
10118
|
}
|
|
9331
|
-
const fullPath =
|
|
10119
|
+
const fullPath = path12.resolve(dir, path12.normalize(filePath));
|
|
9332
10120
|
if (!fullPath.startsWith(dir)) {
|
|
9333
10121
|
this.json(res, 403, { error: "Forbidden" });
|
|
9334
10122
|
return;
|
|
9335
10123
|
}
|
|
9336
10124
|
try {
|
|
9337
|
-
if (
|
|
9338
|
-
|
|
9339
|
-
|
|
10125
|
+
if (fs9.existsSync(fullPath)) fs9.copyFileSync(fullPath, fullPath + ".bak");
|
|
10126
|
+
fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
|
|
10127
|
+
fs9.writeFileSync(fullPath, content, "utf-8");
|
|
9340
10128
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
9341
10129
|
this.providerLoader.reload();
|
|
9342
10130
|
this.json(res, 200, { saved: true, path: filePath, chars: content.length });
|
|
@@ -9352,9 +10140,9 @@ var DevServer = class _DevServer {
|
|
|
9352
10140
|
return;
|
|
9353
10141
|
}
|
|
9354
10142
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
9355
|
-
const p =
|
|
9356
|
-
if (
|
|
9357
|
-
const source =
|
|
10143
|
+
const p = path12.join(dir, name);
|
|
10144
|
+
if (fs9.existsSync(p)) {
|
|
10145
|
+
const source = fs9.readFileSync(p, "utf-8");
|
|
9358
10146
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
9359
10147
|
return;
|
|
9360
10148
|
}
|
|
@@ -9373,11 +10161,11 @@ var DevServer = class _DevServer {
|
|
|
9373
10161
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
9374
10162
|
return;
|
|
9375
10163
|
}
|
|
9376
|
-
const target =
|
|
9377
|
-
const targetPath =
|
|
10164
|
+
const target = fs9.existsSync(path12.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
10165
|
+
const targetPath = path12.join(dir, target);
|
|
9378
10166
|
try {
|
|
9379
|
-
if (
|
|
9380
|
-
|
|
10167
|
+
if (fs9.existsSync(targetPath)) fs9.copyFileSync(targetPath, targetPath + ".bak");
|
|
10168
|
+
fs9.writeFileSync(targetPath, source, "utf-8");
|
|
9381
10169
|
this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
|
|
9382
10170
|
this.providerLoader.reload();
|
|
9383
10171
|
this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
|
|
@@ -9392,18 +10180,18 @@ var DevServer = class _DevServer {
|
|
|
9392
10180
|
return;
|
|
9393
10181
|
}
|
|
9394
10182
|
let scriptsPath = "";
|
|
9395
|
-
const directScripts =
|
|
9396
|
-
if (
|
|
10183
|
+
const directScripts = path12.join(dir, "scripts.js");
|
|
10184
|
+
if (fs9.existsSync(directScripts)) {
|
|
9397
10185
|
scriptsPath = directScripts;
|
|
9398
10186
|
} else {
|
|
9399
|
-
const scriptsDir =
|
|
9400
|
-
if (
|
|
9401
|
-
const versions =
|
|
9402
|
-
return
|
|
10187
|
+
const scriptsDir = path12.join(dir, "scripts");
|
|
10188
|
+
if (fs9.existsSync(scriptsDir)) {
|
|
10189
|
+
const versions = fs9.readdirSync(scriptsDir).filter((d) => {
|
|
10190
|
+
return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
|
|
9403
10191
|
}).sort().reverse();
|
|
9404
10192
|
for (const ver of versions) {
|
|
9405
|
-
const p =
|
|
9406
|
-
if (
|
|
10193
|
+
const p = path12.join(scriptsDir, ver, "scripts.js");
|
|
10194
|
+
if (fs9.existsSync(p)) {
|
|
9407
10195
|
scriptsPath = p;
|
|
9408
10196
|
break;
|
|
9409
10197
|
}
|
|
@@ -9415,7 +10203,7 @@ var DevServer = class _DevServer {
|
|
|
9415
10203
|
return;
|
|
9416
10204
|
}
|
|
9417
10205
|
try {
|
|
9418
|
-
const source =
|
|
10206
|
+
const source = fs9.readFileSync(scriptsPath, "utf-8");
|
|
9419
10207
|
const hints = {};
|
|
9420
10208
|
const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
|
|
9421
10209
|
let match;
|
|
@@ -9559,14 +10347,14 @@ var DevServer = class _DevServer {
|
|
|
9559
10347
|
child.stderr?.on("data", (d) => {
|
|
9560
10348
|
stderr += d.toString();
|
|
9561
10349
|
});
|
|
9562
|
-
await new Promise((
|
|
10350
|
+
await new Promise((resolve7) => {
|
|
9563
10351
|
const timer = setTimeout(() => {
|
|
9564
10352
|
child.kill();
|
|
9565
|
-
|
|
10353
|
+
resolve7();
|
|
9566
10354
|
}, timeout);
|
|
9567
10355
|
child.on("exit", () => {
|
|
9568
10356
|
clearTimeout(timer);
|
|
9569
|
-
|
|
10357
|
+
resolve7();
|
|
9570
10358
|
});
|
|
9571
10359
|
});
|
|
9572
10360
|
const elapsed = Date.now() - start;
|
|
@@ -9616,26 +10404,26 @@ var DevServer = class _DevServer {
|
|
|
9616
10404
|
}
|
|
9617
10405
|
let targetDir;
|
|
9618
10406
|
if (location === "user") {
|
|
9619
|
-
targetDir =
|
|
10407
|
+
targetDir = path12.join(os14.homedir(), ".adhdev", "providers", type);
|
|
9620
10408
|
} else {
|
|
9621
|
-
const builtinDir =
|
|
9622
|
-
targetDir =
|
|
10409
|
+
const builtinDir = path12.resolve(__dirname, "../providers/_builtin");
|
|
10410
|
+
targetDir = path12.join(builtinDir, category, type);
|
|
9623
10411
|
}
|
|
9624
|
-
const jsonPath =
|
|
9625
|
-
if (
|
|
10412
|
+
const jsonPath = path12.join(targetDir, "provider.json");
|
|
10413
|
+
if (fs9.existsSync(jsonPath)) {
|
|
9626
10414
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
9627
10415
|
return;
|
|
9628
10416
|
}
|
|
9629
10417
|
try {
|
|
9630
10418
|
const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version });
|
|
9631
|
-
|
|
9632
|
-
|
|
10419
|
+
fs9.mkdirSync(targetDir, { recursive: true });
|
|
10420
|
+
fs9.writeFileSync(jsonPath, result["provider.json"], "utf-8");
|
|
9633
10421
|
const createdFiles = ["provider.json"];
|
|
9634
10422
|
if (result.files) {
|
|
9635
10423
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
9636
|
-
const fullPath =
|
|
9637
|
-
|
|
9638
|
-
|
|
10424
|
+
const fullPath = path12.join(targetDir, relPath);
|
|
10425
|
+
fs9.mkdirSync(path12.dirname(fullPath), { recursive: true });
|
|
10426
|
+
fs9.writeFileSync(fullPath, content, "utf-8");
|
|
9639
10427
|
createdFiles.push(relPath);
|
|
9640
10428
|
}
|
|
9641
10429
|
}
|
|
@@ -10470,24 +11258,24 @@ var DevServer = class _DevServer {
|
|
|
10470
11258
|
}
|
|
10471
11259
|
this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "loading_reference", message: `\uB808\uD37C\uB7F0\uC2A4 \uC2A4\uD06C\uB9BD\uD2B8 \uB85C\uB4DC \uC911 (${reference})...` } });
|
|
10472
11260
|
let referenceScripts = {};
|
|
10473
|
-
const builtinDir = this.providerLoader.builtinDir ||
|
|
10474
|
-
const refDir =
|
|
10475
|
-
if (
|
|
10476
|
-
const scriptsDir =
|
|
10477
|
-
if (
|
|
10478
|
-
const versions =
|
|
11261
|
+
const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
|
|
11262
|
+
const refDir = path12.join(builtinDir, "ide", reference);
|
|
11263
|
+
if (fs9.existsSync(refDir)) {
|
|
11264
|
+
const scriptsDir = path12.join(refDir, "scripts");
|
|
11265
|
+
if (fs9.existsSync(scriptsDir)) {
|
|
11266
|
+
const versions = fs9.readdirSync(scriptsDir).filter((d) => {
|
|
10479
11267
|
try {
|
|
10480
|
-
return
|
|
11268
|
+
return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
|
|
10481
11269
|
} catch {
|
|
10482
11270
|
return false;
|
|
10483
11271
|
}
|
|
10484
11272
|
}).sort().reverse();
|
|
10485
11273
|
if (versions.length > 0) {
|
|
10486
|
-
const latestDir =
|
|
10487
|
-
for (const file of
|
|
11274
|
+
const latestDir = path12.join(scriptsDir, versions[0]);
|
|
11275
|
+
for (const file of fs9.readdirSync(latestDir)) {
|
|
10488
11276
|
if (file.endsWith(".js")) {
|
|
10489
11277
|
try {
|
|
10490
|
-
referenceScripts[file] =
|
|
11278
|
+
referenceScripts[file] = fs9.readFileSync(path12.join(latestDir, file), "utf-8");
|
|
10491
11279
|
} catch {
|
|
10492
11280
|
}
|
|
10493
11281
|
}
|
|
@@ -10496,16 +11284,16 @@ var DevServer = class _DevServer {
|
|
|
10496
11284
|
}
|
|
10497
11285
|
}
|
|
10498
11286
|
const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts);
|
|
10499
|
-
const tmpDir =
|
|
10500
|
-
if (!
|
|
10501
|
-
const promptFile =
|
|
10502
|
-
|
|
11287
|
+
const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
|
|
11288
|
+
if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
|
|
11289
|
+
const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
11290
|
+
fs9.writeFileSync(promptFile, prompt, "utf-8");
|
|
10503
11291
|
this.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
10504
11292
|
const agentProvider = this.providerLoader.resolve(agent) || this.providerLoader.getMeta(agent);
|
|
10505
11293
|
const spawn3 = agentProvider?.spawn;
|
|
10506
11294
|
if (!spawn3?.command) {
|
|
10507
11295
|
try {
|
|
10508
|
-
|
|
11296
|
+
fs9.unlinkSync(promptFile);
|
|
10509
11297
|
} catch {
|
|
10510
11298
|
}
|
|
10511
11299
|
this.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
|
|
@@ -10606,7 +11394,7 @@ var DevServer = class _DevServer {
|
|
|
10606
11394
|
} catch {
|
|
10607
11395
|
}
|
|
10608
11396
|
try {
|
|
10609
|
-
|
|
11397
|
+
fs9.unlinkSync(promptFile);
|
|
10610
11398
|
} catch {
|
|
10611
11399
|
}
|
|
10612
11400
|
this.log(`Auto-implement (ACP) ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
@@ -10662,12 +11450,12 @@ var DevServer = class _DevServer {
|
|
|
10662
11450
|
} else {
|
|
10663
11451
|
args = [...baseArgs];
|
|
10664
11452
|
}
|
|
10665
|
-
const { execSync:
|
|
11453
|
+
const { execSync: execSync7 } = await import("child_process");
|
|
10666
11454
|
try {
|
|
10667
|
-
|
|
11455
|
+
execSync7(`which ${command}`, { stdio: "pipe" });
|
|
10668
11456
|
} catch {
|
|
10669
11457
|
try {
|
|
10670
|
-
|
|
11458
|
+
fs9.unlinkSync(promptFile);
|
|
10671
11459
|
} catch {
|
|
10672
11460
|
}
|
|
10673
11461
|
this.json(res, 400, { error: `Agent binary '${command}' not found on PATH. Install it first: ${agentProvider?.install || "check provider docs"}` });
|
|
@@ -10723,7 +11511,7 @@ var DevServer = class _DevServer {
|
|
|
10723
11511
|
} catch {
|
|
10724
11512
|
}
|
|
10725
11513
|
try {
|
|
10726
|
-
|
|
11514
|
+
fs9.unlinkSync(promptFile);
|
|
10727
11515
|
} catch {
|
|
10728
11516
|
}
|
|
10729
11517
|
this.log(`Auto-implement ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
@@ -10753,23 +11541,23 @@ var DevServer = class _DevServer {
|
|
|
10753
11541
|
lines.push("## Current Target Files");
|
|
10754
11542
|
lines.push("These are the files you need to EDIT. They contain TODO stubs \u2014 replace them with working implementations.");
|
|
10755
11543
|
lines.push("");
|
|
10756
|
-
const scriptsDir =
|
|
10757
|
-
if (
|
|
10758
|
-
const versions =
|
|
11544
|
+
const scriptsDir = path12.join(providerDir, "scripts");
|
|
11545
|
+
if (fs9.existsSync(scriptsDir)) {
|
|
11546
|
+
const versions = fs9.readdirSync(scriptsDir).filter((d) => {
|
|
10759
11547
|
try {
|
|
10760
|
-
return
|
|
11548
|
+
return fs9.statSync(path12.join(scriptsDir, d)).isDirectory();
|
|
10761
11549
|
} catch {
|
|
10762
11550
|
return false;
|
|
10763
11551
|
}
|
|
10764
11552
|
}).sort().reverse();
|
|
10765
11553
|
if (versions.length > 0) {
|
|
10766
|
-
const vDir =
|
|
11554
|
+
const vDir = path12.join(scriptsDir, versions[0]);
|
|
10767
11555
|
lines.push(`Scripts version directory: \`${vDir}\``);
|
|
10768
11556
|
lines.push("");
|
|
10769
|
-
for (const file of
|
|
11557
|
+
for (const file of fs9.readdirSync(vDir)) {
|
|
10770
11558
|
if (file.endsWith(".js")) {
|
|
10771
11559
|
try {
|
|
10772
|
-
const content =
|
|
11560
|
+
const content = fs9.readFileSync(path12.join(vDir, file), "utf-8");
|
|
10773
11561
|
lines.push(`### \`${file}\``);
|
|
10774
11562
|
lines.push("```javascript");
|
|
10775
11563
|
lines.push(content);
|
|
@@ -10840,7 +11628,7 @@ var DevServer = class _DevServer {
|
|
|
10840
11628
|
lines.push("## Required Return Format");
|
|
10841
11629
|
lines.push("| Function | Return JSON |");
|
|
10842
11630
|
lines.push("|---|---|");
|
|
10843
|
-
lines.push("| readChat | `{ id, status, title, messages: [{role, content, index}], inputContent, activeModal }` |");
|
|
11631
|
+
lines.push("| readChat | `{ id, status, title, messages: [{role, content, index, kind?, meta?}], inputContent, activeModal }` \u2014 optional `kind`: standard, thought, tool, terminal; optional `meta`: e.g. `{ label, isRunning }` for dashboard |");
|
|
10844
11632
|
lines.push("| sendMessage | `{ sent: false, needsTypeAndSend: true, selector }` |");
|
|
10845
11633
|
lines.push("| resolveAction | `{ resolved: true/false, clicked? }` |");
|
|
10846
11634
|
lines.push("| listSessions | `{ sessions: [{ id, title, active, index }] }` |");
|
|
@@ -10964,14 +11752,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
10964
11752
|
res.end(JSON.stringify(data, null, 2));
|
|
10965
11753
|
}
|
|
10966
11754
|
async readBody(req) {
|
|
10967
|
-
return new Promise((
|
|
11755
|
+
return new Promise((resolve7) => {
|
|
10968
11756
|
let body = "";
|
|
10969
11757
|
req.on("data", (chunk) => body += chunk);
|
|
10970
11758
|
req.on("end", () => {
|
|
10971
11759
|
try {
|
|
10972
|
-
|
|
11760
|
+
resolve7(JSON.parse(body));
|
|
10973
11761
|
} catch {
|
|
10974
|
-
|
|
11762
|
+
resolve7({});
|
|
10975
11763
|
}
|
|
10976
11764
|
});
|
|
10977
11765
|
});
|
|
@@ -10979,7 +11767,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
10979
11767
|
};
|
|
10980
11768
|
|
|
10981
11769
|
// src/installer.ts
|
|
10982
|
-
var
|
|
11770
|
+
var import_child_process8 = require("child_process");
|
|
10983
11771
|
var EXTENSION_CATALOG = [
|
|
10984
11772
|
// AI Agent extensions
|
|
10985
11773
|
{
|
|
@@ -11056,7 +11844,7 @@ var EXTENSION_CATALOG = [
|
|
|
11056
11844
|
function isExtensionInstalled(ide, marketplaceId) {
|
|
11057
11845
|
if (!ide.cliCommand) return false;
|
|
11058
11846
|
try {
|
|
11059
|
-
const result = (0,
|
|
11847
|
+
const result = (0, import_child_process8.execSync)(`"${ide.cliCommand}" --list-extensions`, {
|
|
11060
11848
|
encoding: "utf-8",
|
|
11061
11849
|
timeout: 15e3,
|
|
11062
11850
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -11093,12 +11881,12 @@ async function installExtension(ide, extension) {
|
|
|
11093
11881
|
const res = await fetch(extension.vsixUrl);
|
|
11094
11882
|
if (res.ok) {
|
|
11095
11883
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
11096
|
-
const
|
|
11097
|
-
|
|
11098
|
-
return new Promise((
|
|
11884
|
+
const fs10 = await import("fs");
|
|
11885
|
+
fs10.writeFileSync(vsixPath, buffer);
|
|
11886
|
+
return new Promise((resolve7) => {
|
|
11099
11887
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
11100
|
-
(0,
|
|
11101
|
-
|
|
11888
|
+
(0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
11889
|
+
resolve7({
|
|
11102
11890
|
extensionId: extension.id,
|
|
11103
11891
|
marketplaceId: extension.marketplaceId,
|
|
11104
11892
|
success: !error,
|
|
@@ -11111,11 +11899,11 @@ async function installExtension(ide, extension) {
|
|
|
11111
11899
|
} catch (e) {
|
|
11112
11900
|
}
|
|
11113
11901
|
}
|
|
11114
|
-
return new Promise((
|
|
11902
|
+
return new Promise((resolve7) => {
|
|
11115
11903
|
const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
|
|
11116
|
-
(0,
|
|
11904
|
+
(0, import_child_process8.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
|
|
11117
11905
|
if (error) {
|
|
11118
|
-
|
|
11906
|
+
resolve7({
|
|
11119
11907
|
extensionId: extension.id,
|
|
11120
11908
|
marketplaceId: extension.marketplaceId,
|
|
11121
11909
|
success: false,
|
|
@@ -11123,7 +11911,7 @@ async function installExtension(ide, extension) {
|
|
|
11123
11911
|
error: stderr || error.message
|
|
11124
11912
|
});
|
|
11125
11913
|
} else {
|
|
11126
|
-
|
|
11914
|
+
resolve7({
|
|
11127
11915
|
extensionId: extension.id,
|
|
11128
11916
|
marketplaceId: extension.marketplaceId,
|
|
11129
11917
|
success: true,
|
|
@@ -11150,7 +11938,7 @@ function launchIDE(ide, workspacePath) {
|
|
|
11150
11938
|
if (!ide.cliCommand) return false;
|
|
11151
11939
|
try {
|
|
11152
11940
|
const args = workspacePath ? `"${workspacePath}"` : "";
|
|
11153
|
-
(0,
|
|
11941
|
+
(0, import_child_process8.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
|
|
11154
11942
|
return true;
|
|
11155
11943
|
} catch {
|
|
11156
11944
|
return false;
|
|
@@ -11315,9 +12103,12 @@ async function shutdownDaemonComponents(components) {
|
|
|
11315
12103
|
detectIDEs,
|
|
11316
12104
|
getAIExtensions,
|
|
11317
12105
|
getAvailableIdeIds,
|
|
12106
|
+
getHostMemorySnapshot,
|
|
11318
12107
|
getLogLevel,
|
|
11319
12108
|
getRecentCommands,
|
|
11320
12109
|
getRecentLogs,
|
|
12110
|
+
getWorkspaceActivity,
|
|
12111
|
+
getWorkspaceState,
|
|
11321
12112
|
initDaemonComponents,
|
|
11322
12113
|
installExtensions,
|
|
11323
12114
|
installGlobalInterceptor,
|