openfox 2.0.58 → 2.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-defaults/explorer.agent.md +4 -0
- package/dist/{branch.api-5DMEAIBI.js → branch.api-LAN42BA5.js} +3 -2
- package/dist/{chat-handler-W5D5LKKU.js → chat-handler-MBR6ZQTX.js} +7 -7
- package/dist/{chunk-LAWUUAN7.js → chunk-3JRYK5UG.js} +323 -80
- package/dist/{chunk-YMEZFRY2.js → chunk-43UFGATL.js} +5 -5
- package/dist/{chunk-BIWVYBIE.js → chunk-BGTEIA2S.js} +4 -3
- package/dist/{chunk-UDZNMYWN.js → chunk-DEWNWF2P.js} +519 -280
- package/dist/{chunk-CFLGVCYT.js → chunk-DOJKA4XO.js} +20 -9
- package/dist/{chunk-55VITQP3.js → chunk-MTBQQ5DN.js} +9 -9
- package/dist/{chunk-XR2XC7WM.js → chunk-NY6IGGKZ.js} +3 -3
- package/dist/{chunk-ADOXTORQ.js → chunk-PK2RMVMB.js} +2 -2
- package/dist/{chunk-CDRQJDSJ.js → chunk-WNSAJCWT.js} +3 -2
- package/dist/cli/dev.js +2 -2
- package/dist/cli/index.js +2 -2
- package/dist/{config-C2YDEF3N.js → config-GMQUPNBY.js} +2 -2
- package/dist/{manager-CZOVNTSN.js → manager-344C5JLZ.js} +3 -3
- package/dist/{orchestrator-Q47D6JXG.js → orchestrator-PIZJ42J2.js} +7 -7
- package/dist/package.json +4 -2
- package/dist/{permissions-QLHZUEGW.js → permissions-CGEK3DGZ.js} +21 -17
- package/dist/{processor-2YJ33KUH.js → processor-PKKTNKWY.js} +7 -7
- package/dist/{project-creator-7RBHP6K6.js → project-creator-IDW7RACH.js} +4 -4
- package/dist/{protocol-PSKVUhdN.d.ts → protocol-J7khRG62.d.ts} +2 -0
- package/dist/{provider-SNXYPSPH.js → provider-LBYBC5AG.js} +3 -3
- package/dist/{pwa-M6QZ52ZO.js → pwa-T6JRAYJB.js} +11 -10
- package/dist/{serve-LOPGRMFP.js → serve-GKS55Y2C.js} +9 -9
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +8 -8
- package/dist/{server-XUDZRBD3.js → server-LMH7ZH5X.js} +8 -8
- package/dist/{service-YYJ5Y7CN.js → service-6DL3MJZD.js} +7 -5
- package/dist/{settings-X43DCM55.js → settings-2TQA7VTP.js} +2 -2
- package/dist/shared/index.d.ts +2 -2
- package/dist/skill-defaults/{browser.skill.md → browser/SKILL.md} +5 -3
- package/dist/{store-NS2RMRA7.js → store-FXTCHBI4.js} +2 -2
- package/dist/{tools-YJLXW3QS.js → tools-WGAZKL56.js} +6 -6
- package/dist/web/assets/index-C0YKw2cD.js +302 -0
- package/dist/web/assets/{index-DjfRXOO7.css → index-D4bVx84a.css} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +4 -2
- package/dist/web/assets/index-Dqqp_j-f.js +0 -302
|
@@ -21,12 +21,13 @@ import {
|
|
|
21
21
|
tokenFromPassword,
|
|
22
22
|
verifyPassword,
|
|
23
23
|
workflowExists
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-DOJKA4XO.js";
|
|
25
25
|
import {
|
|
26
26
|
agentExists,
|
|
27
27
|
createToolRegistry,
|
|
28
28
|
deleteAgent,
|
|
29
29
|
deleteItemFromDir,
|
|
30
|
+
deleteOwnedSkill,
|
|
30
31
|
deleteProjectAgent,
|
|
31
32
|
deleteProjectSkill,
|
|
32
33
|
deleteSkill,
|
|
@@ -43,6 +44,7 @@ import {
|
|
|
43
44
|
loadAllAgents,
|
|
44
45
|
loadAllAgentsDefault,
|
|
45
46
|
loadAllSkills,
|
|
47
|
+
loadAllSkillsWithDiagnostics,
|
|
46
48
|
loadDefaultAgents,
|
|
47
49
|
loadDefaultSkills,
|
|
48
50
|
loadItemsFromDir,
|
|
@@ -57,15 +59,18 @@ import {
|
|
|
57
59
|
saveSkill,
|
|
58
60
|
saveSkillToProject,
|
|
59
61
|
setMcpConfigMode,
|
|
62
|
+
setMcpConfigPath,
|
|
60
63
|
setMcpManagerForTools,
|
|
61
64
|
setMcpTools,
|
|
62
65
|
setNotifyMcpServersChanged,
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
setSkillEnabled,
|
|
67
|
+
skillExists,
|
|
68
|
+
updateOwnedSkill
|
|
69
|
+
} from "./chunk-3JRYK5UG.js";
|
|
65
70
|
import {
|
|
66
71
|
getPathSeparator,
|
|
67
72
|
isAbsolutePath
|
|
68
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-BGTEIA2S.js";
|
|
69
74
|
import {
|
|
70
75
|
createMcpTools
|
|
71
76
|
} from "./chunk-NWO6GRYE.js";
|
|
@@ -75,6 +80,11 @@ import {
|
|
|
75
80
|
import {
|
|
76
81
|
EventEmitter
|
|
77
82
|
} from "./chunk-EU3WWTFH.js";
|
|
83
|
+
import {
|
|
84
|
+
deleteSetting,
|
|
85
|
+
getSetting,
|
|
86
|
+
setSetting
|
|
87
|
+
} from "./chunk-WNSAJCWT.js";
|
|
78
88
|
import {
|
|
79
89
|
getProject
|
|
80
90
|
} from "./chunk-YQ3SOPBI.js";
|
|
@@ -149,8 +159,8 @@ import express from "express";
|
|
|
149
159
|
import cors from "cors";
|
|
150
160
|
import { createServer as createHttpServer } from "http";
|
|
151
161
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
152
|
-
import { dirname as
|
|
153
|
-
import { readFile } from "fs/promises";
|
|
162
|
+
import { dirname as dirname6, resolve as resolve4, join as join7 } from "path";
|
|
163
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
154
164
|
import { createServer as createViteServer } from "vite";
|
|
155
165
|
|
|
156
166
|
// src/server/llm/mock.ts
|
|
@@ -1425,12 +1435,12 @@ var McpManager = class {
|
|
|
1425
1435
|
this.onServersChanged = options?.onServersChanged;
|
|
1426
1436
|
this.onToolsDiscovered = options?.onToolsDiscovered;
|
|
1427
1437
|
}
|
|
1428
|
-
async addServer(name,
|
|
1438
|
+
async addServer(name, config3) {
|
|
1429
1439
|
if (this.servers.has(name)) {
|
|
1430
1440
|
throw new Error(`MCP server '${name}' already exists`);
|
|
1431
1441
|
}
|
|
1432
|
-
const state = { name, config:
|
|
1433
|
-
this.servers.set(name, { config:
|
|
1442
|
+
const state = { name, config: config3, status: "disconnected", tools: [], estimatedTokens: 0 };
|
|
1443
|
+
this.servers.set(name, { config: config3, client: void 0, transport: null, state });
|
|
1434
1444
|
await this.connectServer(name);
|
|
1435
1445
|
}
|
|
1436
1446
|
removeServer(name) {
|
|
@@ -1677,10 +1687,10 @@ var LspServer = class {
|
|
|
1677
1687
|
// Pending diagnostic waiters
|
|
1678
1688
|
pendingDiagnostics = /* @__PURE__ */ new Map();
|
|
1679
1689
|
commandPath;
|
|
1680
|
-
constructor(
|
|
1681
|
-
this.config =
|
|
1690
|
+
constructor(config3, workdir, commandPath) {
|
|
1691
|
+
this.config = config3;
|
|
1682
1692
|
this.workdir = workdir;
|
|
1683
|
-
this.commandPath = commandPath ??
|
|
1693
|
+
this.commandPath = commandPath ?? config3.serverCommand;
|
|
1684
1694
|
}
|
|
1685
1695
|
// ============================================================================
|
|
1686
1696
|
// Lifecycle
|
|
@@ -1698,7 +1708,8 @@ var LspServer = class {
|
|
|
1698
1708
|
...process.env,
|
|
1699
1709
|
HOME: process.env["HOME"],
|
|
1700
1710
|
PATH: process.env["PATH"]
|
|
1701
|
-
}
|
|
1711
|
+
},
|
|
1712
|
+
windowsHide: true
|
|
1702
1713
|
});
|
|
1703
1714
|
if (!this.process.stdin || !this.process.stdout) {
|
|
1704
1715
|
throw new Error("Failed to get stdio streams from language server process");
|
|
@@ -1912,19 +1923,19 @@ var LspServer = class {
|
|
|
1912
1923
|
*/
|
|
1913
1924
|
async getDiagnosticsWithWait(path, timeoutMs = DIAGNOSTIC_WAIT_MS) {
|
|
1914
1925
|
if (this.openDocuments.has(path)) {
|
|
1915
|
-
return new Promise((
|
|
1926
|
+
return new Promise((resolve5) => {
|
|
1916
1927
|
const existing = this.diagnostics.get(path);
|
|
1917
1928
|
if (existing !== void 0) {
|
|
1918
1929
|
setTimeout(() => {
|
|
1919
|
-
|
|
1930
|
+
resolve5(this.diagnostics.get(path) ?? []);
|
|
1920
1931
|
}, 100);
|
|
1921
1932
|
return;
|
|
1922
1933
|
}
|
|
1923
1934
|
const timeout = setTimeout(() => {
|
|
1924
1935
|
this.pendingDiagnostics.delete(path);
|
|
1925
|
-
|
|
1936
|
+
resolve5(this.diagnostics.get(path) ?? []);
|
|
1926
1937
|
}, timeoutMs);
|
|
1927
|
-
this.pendingDiagnostics.set(path, { resolve:
|
|
1938
|
+
this.pendingDiagnostics.set(path, { resolve: resolve5, timeout });
|
|
1928
1939
|
});
|
|
1929
1940
|
}
|
|
1930
1941
|
return this.diagnostics.get(path) ?? [];
|
|
@@ -2236,8 +2247,8 @@ var LspManager = class {
|
|
|
2236
2247
|
// ============================================================================
|
|
2237
2248
|
// Server Management
|
|
2238
2249
|
// ============================================================================
|
|
2239
|
-
async getOrCreateServer(
|
|
2240
|
-
const langId =
|
|
2250
|
+
async getOrCreateServer(config3) {
|
|
2251
|
+
const langId = config3.id;
|
|
2241
2252
|
const existing = this.servers.get(langId);
|
|
2242
2253
|
if (existing?.isRunning()) {
|
|
2243
2254
|
return existing;
|
|
@@ -2249,7 +2260,7 @@ var LspManager = class {
|
|
|
2249
2260
|
if (pending) {
|
|
2250
2261
|
return pending;
|
|
2251
2262
|
}
|
|
2252
|
-
const promise = this.startServer(
|
|
2263
|
+
const promise = this.startServer(config3);
|
|
2253
2264
|
this.serverPromises.set(langId, promise);
|
|
2254
2265
|
try {
|
|
2255
2266
|
const server = await promise;
|
|
@@ -2258,19 +2269,19 @@ var LspManager = class {
|
|
|
2258
2269
|
this.serverPromises.delete(langId);
|
|
2259
2270
|
}
|
|
2260
2271
|
}
|
|
2261
|
-
async startServer(
|
|
2262
|
-
const langId =
|
|
2263
|
-
const commandPath = await which(
|
|
2272
|
+
async startServer(config3) {
|
|
2273
|
+
const langId = config3.id;
|
|
2274
|
+
const commandPath = await which(config3.serverCommand, this.workdir);
|
|
2264
2275
|
if (!commandPath) {
|
|
2265
2276
|
logger.warn("LSP server not installed, skipping", {
|
|
2266
2277
|
language: langId,
|
|
2267
|
-
command:
|
|
2278
|
+
command: config3.serverCommand,
|
|
2268
2279
|
sessionId: this.sessionId
|
|
2269
2280
|
});
|
|
2270
2281
|
this.unavailableServers.add(langId);
|
|
2271
2282
|
return null;
|
|
2272
2283
|
}
|
|
2273
|
-
const server = new LspServer(
|
|
2284
|
+
const server = new LspServer(config3, this.workdir, commandPath);
|
|
2274
2285
|
try {
|
|
2275
2286
|
await server.start();
|
|
2276
2287
|
this.servers.set(langId, server);
|
|
@@ -2290,11 +2301,11 @@ var LspManager = class {
|
|
|
2290
2301
|
}
|
|
2291
2302
|
}
|
|
2292
2303
|
async getServerForFile(path) {
|
|
2293
|
-
const
|
|
2294
|
-
if (!
|
|
2304
|
+
const config3 = detectLanguage(path);
|
|
2305
|
+
if (!config3) {
|
|
2295
2306
|
return null;
|
|
2296
2307
|
}
|
|
2297
|
-
return this.getOrCreateServer(
|
|
2308
|
+
return this.getOrCreateServer(config3);
|
|
2298
2309
|
}
|
|
2299
2310
|
// ============================================================================
|
|
2300
2311
|
// Public Interface
|
|
@@ -2325,11 +2336,11 @@ var LspManager = class {
|
|
|
2325
2336
|
* Get current diagnostics for a file without triggering a change.
|
|
2326
2337
|
*/
|
|
2327
2338
|
getDiagnostics(path) {
|
|
2328
|
-
const
|
|
2329
|
-
if (!
|
|
2339
|
+
const config3 = detectLanguage(path);
|
|
2340
|
+
if (!config3) {
|
|
2330
2341
|
return [];
|
|
2331
2342
|
}
|
|
2332
|
-
const server = this.servers.get(
|
|
2343
|
+
const server = this.servers.get(config3.id);
|
|
2333
2344
|
if (!server?.isRunning()) {
|
|
2334
2345
|
return [];
|
|
2335
2346
|
}
|
|
@@ -2340,11 +2351,11 @@ var LspManager = class {
|
|
|
2340
2351
|
* Returns true if we have or can start a server for this file type.
|
|
2341
2352
|
*/
|
|
2342
2353
|
isAvailableFor(path) {
|
|
2343
|
-
const
|
|
2344
|
-
if (!
|
|
2354
|
+
const config3 = detectLanguage(path);
|
|
2355
|
+
if (!config3) {
|
|
2345
2356
|
return false;
|
|
2346
2357
|
}
|
|
2347
|
-
if (this.unavailableServers.has(
|
|
2358
|
+
if (this.unavailableServers.has(config3.id)) {
|
|
2348
2359
|
return false;
|
|
2349
2360
|
}
|
|
2350
2361
|
return true;
|
|
@@ -2355,13 +2366,13 @@ var LspManager = class {
|
|
|
2355
2366
|
* to avoid spamming the user on every edit.
|
|
2356
2367
|
*/
|
|
2357
2368
|
getInstallHint(path) {
|
|
2358
|
-
const
|
|
2359
|
-
if (!
|
|
2369
|
+
const config3 = detectLanguage(path);
|
|
2370
|
+
if (!config3?.installHint) {
|
|
2360
2371
|
return null;
|
|
2361
2372
|
}
|
|
2362
|
-
if (this.unavailableServers.has(
|
|
2363
|
-
this.dismissedHints.add(
|
|
2364
|
-
return
|
|
2373
|
+
if (this.unavailableServers.has(config3.id) && !this.dismissedHints.has(config3.id)) {
|
|
2374
|
+
this.dismissedHints.add(config3.id);
|
|
2375
|
+
return config3.installHint;
|
|
2365
2376
|
}
|
|
2366
2377
|
return null;
|
|
2367
2378
|
}
|
|
@@ -3241,9 +3252,77 @@ var SessionManager = class {
|
|
|
3241
3252
|
}
|
|
3242
3253
|
};
|
|
3243
3254
|
|
|
3255
|
+
// src/server/routes/skills.ts
|
|
3256
|
+
import { Router as Router2 } from "express";
|
|
3257
|
+
import multer from "multer";
|
|
3258
|
+
import { access as access2, mkdir as mkdir2, realpath, stat } from "fs/promises";
|
|
3259
|
+
import { constants as constants2 } from "fs";
|
|
3260
|
+
import { homedir } from "os";
|
|
3261
|
+
import { isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "path";
|
|
3262
|
+
|
|
3263
|
+
// src/server/skills/installer.ts
|
|
3264
|
+
import { randomUUID } from "crypto";
|
|
3265
|
+
import { mkdir, readFile, rename, rm, writeFile } from "fs/promises";
|
|
3266
|
+
import { dirname as dirname3, isAbsolute, join as join2 } from "path";
|
|
3267
|
+
import matter from "gray-matter";
|
|
3268
|
+
var SkillInstallError = class extends Error {
|
|
3269
|
+
constructor(message, status) {
|
|
3270
|
+
super(message);
|
|
3271
|
+
this.status = status;
|
|
3272
|
+
}
|
|
3273
|
+
};
|
|
3274
|
+
function validateRelativePath(path) {
|
|
3275
|
+
if (!path || isAbsolute(path) || path.includes("\\") || path.includes("\0") || path.split("/").some((part) => !part || part === "." || part === "..")) {
|
|
3276
|
+
throw new SkillInstallError(`Invalid package path: ${path}`, 400);
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
function validatePackageName(name) {
|
|
3280
|
+
if (!name || name.includes("/") || name.includes("\\") || name === "." || name === ".." || name.includes("\0")) {
|
|
3281
|
+
throw new SkillInstallError("Invalid package name", 400);
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
async function installSkillPackage(libraryDir, packageName, files) {
|
|
3285
|
+
validatePackageName(packageName);
|
|
3286
|
+
if (!files.length || files.length > 1e3) throw new SkillInstallError("Package must contain 1-1000 files", 400);
|
|
3287
|
+
if (!files.some((file) => file.path === "SKILL.md")) throw new SkillInstallError("Package must contain SKILL.md", 400);
|
|
3288
|
+
let totalBytes = 0;
|
|
3289
|
+
const paths = /* @__PURE__ */ new Set();
|
|
3290
|
+
for (const file of files) {
|
|
3291
|
+
validateRelativePath(file.path);
|
|
3292
|
+
if (paths.has(file.path)) throw new SkillInstallError(`Duplicate package path: ${file.path}`, 400);
|
|
3293
|
+
paths.add(file.path);
|
|
3294
|
+
if (file.content.byteLength > 25 * 1024 * 1024) throw new SkillInstallError("Package file exceeds 25 MiB", 413);
|
|
3295
|
+
totalBytes += file.content.byteLength;
|
|
3296
|
+
}
|
|
3297
|
+
if (totalBytes > 50 * 1024 * 1024) throw new SkillInstallError("Package exceeds 50 MiB", 413);
|
|
3298
|
+
const destination = join2(libraryDir, packageName);
|
|
3299
|
+
if (await pathExists(destination)) throw new SkillInstallError("A package with this name already exists", 409);
|
|
3300
|
+
const staging = join2(libraryDir, `.${packageName}.openfox-upload-${randomUUID()}`);
|
|
3301
|
+
try {
|
|
3302
|
+
await mkdir(staging, { recursive: false });
|
|
3303
|
+
for (const file of files) {
|
|
3304
|
+
const target = join2(staging, file.path);
|
|
3305
|
+
await mkdir(dirname3(target), { recursive: true });
|
|
3306
|
+
await writeFile(target, file.content);
|
|
3307
|
+
}
|
|
3308
|
+
const parsed = matter(await readFile(join2(staging, "SKILL.md"), "utf-8"));
|
|
3309
|
+
const name = typeof parsed.data["name"] === "string" ? parsed.data["name"].trim() : "";
|
|
3310
|
+
const description = typeof parsed.data["description"] === "string" ? parsed.data["description"].trim() : "";
|
|
3311
|
+
if (!name || !description || !parsed.content.trim()) {
|
|
3312
|
+
throw new SkillInstallError("SKILL.md requires name, description, and instructions", 400);
|
|
3313
|
+
}
|
|
3314
|
+
if (await pathExists(destination)) throw new SkillInstallError("A package with this name already exists", 409);
|
|
3315
|
+
await rename(staging, destination);
|
|
3316
|
+
return { id: name, path: destination };
|
|
3317
|
+
} catch (error) {
|
|
3318
|
+
await rm(staging, { recursive: true, force: true });
|
|
3319
|
+
throw error;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3244
3323
|
// src/server/routes/crud-helpers.ts
|
|
3245
3324
|
import { Router } from "express";
|
|
3246
|
-
import { join as
|
|
3325
|
+
import { join as join3 } from "path";
|
|
3247
3326
|
function computeOverrideIds(defaults, userItems) {
|
|
3248
3327
|
return userItems.filter((u) => defaults.some((d) => d.metadata.id === u.metadata.id)).map((u) => u.metadata.id);
|
|
3249
3328
|
}
|
|
@@ -3255,34 +3334,34 @@ function validateNameIdPrompt(body) {
|
|
|
3255
3334
|
return null;
|
|
3256
3335
|
}
|
|
3257
3336
|
function getProjectItemPath(projectDir, dirName, id, ext) {
|
|
3258
|
-
return
|
|
3337
|
+
return join3(projectDir, ".openfox", dirName, `${id}${ext}`);
|
|
3259
3338
|
}
|
|
3260
3339
|
async function isProjectItem(projectDir, dirName, id, ext) {
|
|
3261
3340
|
if (!projectDir) return false;
|
|
3262
3341
|
return pathExists(getProjectItemPath(projectDir, dirName, id, ext));
|
|
3263
3342
|
}
|
|
3264
|
-
function createCrudRoutes(
|
|
3343
|
+
function createCrudRoutes(config3, configDir, projectDir) {
|
|
3265
3344
|
const router = Router();
|
|
3266
3345
|
router.get("/", async (_req, res) => {
|
|
3267
3346
|
const [defaults, userItems, projectItems] = await Promise.all([
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
projectDir ?
|
|
3347
|
+
config3.loadDefaults(),
|
|
3348
|
+
config3.loadUser(configDir),
|
|
3349
|
+
projectDir ? config3.loadProject(projectDir) : []
|
|
3271
3350
|
]);
|
|
3272
3351
|
const userOverrideIds = computeOverrideIds(defaults, userItems);
|
|
3273
3352
|
const projectOverrideIds = computeOverrideIds(defaults, projectItems);
|
|
3274
|
-
const extra =
|
|
3353
|
+
const extra = config3.extraGetData ? await config3.extraGetData() : {};
|
|
3275
3354
|
res.json({
|
|
3276
|
-
defaults: defaults.map(
|
|
3277
|
-
userItems: userItems.map(
|
|
3278
|
-
projectItems: projectItems.map(
|
|
3355
|
+
defaults: defaults.map(config3.mapToResponse),
|
|
3356
|
+
userItems: userItems.map(config3.mapToResponse),
|
|
3357
|
+
projectItems: projectItems.map(config3.mapToResponse),
|
|
3279
3358
|
overrideIds: [...userOverrideIds, ...projectOverrideIds],
|
|
3280
3359
|
...extra
|
|
3281
3360
|
});
|
|
3282
3361
|
});
|
|
3283
3362
|
router.get("/defaults/:id", async (req, res) => {
|
|
3284
3363
|
const { id } = req.params;
|
|
3285
|
-
const allDefaults = await
|
|
3364
|
+
const allDefaults = await config3.loadDefaults();
|
|
3286
3365
|
const item = allDefaults.find((d) => d.metadata.id === id);
|
|
3287
3366
|
if (!item) {
|
|
3288
3367
|
return res.status(404).json({ error: "Default not found" });
|
|
@@ -3290,13 +3369,13 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3290
3369
|
res.json(item);
|
|
3291
3370
|
});
|
|
3292
3371
|
router.get("/default-ids", async (_req, res) => {
|
|
3293
|
-
const ids =
|
|
3372
|
+
const ids = config3.getDefaultIds ? await config3.getDefaultIds() : [];
|
|
3294
3373
|
res.json({ ids });
|
|
3295
3374
|
});
|
|
3296
3375
|
router.get("/:id", async (req, res) => {
|
|
3297
3376
|
const { id } = req.params;
|
|
3298
|
-
const items = await
|
|
3299
|
-
const item =
|
|
3377
|
+
const items = await config3.loadAll(configDir, projectDir);
|
|
3378
|
+
const item = config3.findById(id, items);
|
|
3300
3379
|
if (!item) {
|
|
3301
3380
|
return res.status(404).json({ error: "Not found" });
|
|
3302
3381
|
}
|
|
@@ -3305,7 +3384,7 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3305
3384
|
router.post("/", async (req, res) => {
|
|
3306
3385
|
const body = req.body;
|
|
3307
3386
|
const meta = body["metadata"];
|
|
3308
|
-
const customError =
|
|
3387
|
+
const customError = config3.validateCreate?.(body);
|
|
3309
3388
|
if (!meta?.["id"] || customError) {
|
|
3310
3389
|
return res.status(400).json({ error: customError ?? "Missing required fields" });
|
|
3311
3390
|
}
|
|
@@ -3314,21 +3393,21 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3314
3393
|
if (destination === "project" && !projectDir) {
|
|
3315
3394
|
return res.status(400).json({ error: "No project directory configured" });
|
|
3316
3395
|
}
|
|
3317
|
-
const exists = await
|
|
3396
|
+
const exists = await config3.exists(configDir, id, projectDir);
|
|
3318
3397
|
if (exists) {
|
|
3319
3398
|
return res.status(409).json({ error: "An item with this ID already exists" });
|
|
3320
3399
|
}
|
|
3321
3400
|
if (destination === "project") {
|
|
3322
|
-
await
|
|
3401
|
+
await config3.saveToProject(projectDir, body);
|
|
3323
3402
|
} else {
|
|
3324
|
-
await
|
|
3403
|
+
await config3.save(configDir, body);
|
|
3325
3404
|
}
|
|
3326
3405
|
res.status(201).json(body);
|
|
3327
3406
|
});
|
|
3328
3407
|
router.put("/:id", async (req, res) => {
|
|
3329
3408
|
const { id } = req.params;
|
|
3330
|
-
const items = await
|
|
3331
|
-
const existing =
|
|
3409
|
+
const items = await config3.loadAll(configDir, projectDir);
|
|
3410
|
+
const existing = config3.findById(id, items);
|
|
3332
3411
|
if (!existing) {
|
|
3333
3412
|
return res.status(404).json({ error: "Not found" });
|
|
3334
3413
|
}
|
|
@@ -3339,29 +3418,29 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3339
3418
|
...body,
|
|
3340
3419
|
metadata: { ...existing.metadata, ...meta, id }
|
|
3341
3420
|
};
|
|
3342
|
-
const isProject = await isProjectItem(projectDir,
|
|
3421
|
+
const isProject = await isProjectItem(projectDir, config3.dirName, id, config3.ext);
|
|
3343
3422
|
if (isProject) {
|
|
3344
|
-
await
|
|
3423
|
+
await config3.saveToProject(projectDir, updated);
|
|
3345
3424
|
} else {
|
|
3346
|
-
await
|
|
3425
|
+
await config3.save(configDir, updated);
|
|
3347
3426
|
}
|
|
3348
3427
|
res.json(updated);
|
|
3349
3428
|
});
|
|
3350
3429
|
router.delete("/:id", async (req, res) => {
|
|
3351
3430
|
const { id } = req.params;
|
|
3352
|
-
const isProject = await isProjectItem(projectDir,
|
|
3431
|
+
const isProject = await isProjectItem(projectDir, config3.dirName, id, config3.ext);
|
|
3353
3432
|
if (isProject) {
|
|
3354
|
-
const result2 = await
|
|
3433
|
+
const result2 = await config3.deleteProject(projectDir, id);
|
|
3355
3434
|
if (!result2.success) {
|
|
3356
3435
|
return res.status(500).json({ error: "Failed to delete project item" });
|
|
3357
3436
|
}
|
|
3358
3437
|
return res.json({ success: true });
|
|
3359
3438
|
}
|
|
3360
|
-
const isDefault = await
|
|
3439
|
+
const isDefault = await config3.isDefault(id);
|
|
3361
3440
|
if (isDefault) {
|
|
3362
3441
|
return res.status(403).json({ error: "Cannot delete built-in defaults" });
|
|
3363
3442
|
}
|
|
3364
|
-
const result = await
|
|
3443
|
+
const result = await config3.delete(configDir, id);
|
|
3365
3444
|
if (!result.success) {
|
|
3366
3445
|
return res.status(403).json({ error: result.reason ?? "Cannot delete this item" });
|
|
3367
3446
|
}
|
|
@@ -3369,8 +3448,8 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3369
3448
|
});
|
|
3370
3449
|
router.post("/:id/duplicate", async (req, res) => {
|
|
3371
3450
|
const { id } = req.params;
|
|
3372
|
-
const items = await
|
|
3373
|
-
const source =
|
|
3451
|
+
const items = await config3.loadAll(configDir, projectDir);
|
|
3452
|
+
const source = config3.findById(id, items);
|
|
3374
3453
|
if (!source) {
|
|
3375
3454
|
return res.status(404).json({ error: "Not found" });
|
|
3376
3455
|
}
|
|
@@ -3382,56 +3461,195 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3382
3461
|
const destination = req.body.destination ?? "user";
|
|
3383
3462
|
if (destination === "project") {
|
|
3384
3463
|
if (!projectDir) return res.status(400).json({ error: "No project directory configured" });
|
|
3385
|
-
await
|
|
3464
|
+
await config3.saveToProject(projectDir, duplicated);
|
|
3386
3465
|
} else {
|
|
3387
|
-
await
|
|
3466
|
+
await config3.save(configDir, duplicated);
|
|
3388
3467
|
}
|
|
3389
3468
|
res.status(201).json(duplicated);
|
|
3390
3469
|
});
|
|
3391
|
-
|
|
3470
|
+
config3.extraRoutes?.(router);
|
|
3392
3471
|
return router;
|
|
3393
3472
|
}
|
|
3394
3473
|
|
|
3395
3474
|
// src/server/routes/skills.ts
|
|
3396
|
-
var
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3475
|
+
var SKILL_DIRECTORIES_SETTING = "skills.directories";
|
|
3476
|
+
var upload = multer({
|
|
3477
|
+
storage: multer.memoryStorage(),
|
|
3478
|
+
limits: { files: 1e3, fileSize: 25 * 1024 * 1024, fields: 4 }
|
|
3479
|
+
});
|
|
3480
|
+
function expandHome(path) {
|
|
3481
|
+
if (path === "~") return homedir();
|
|
3482
|
+
return path.startsWith("~/") ? join4(homedir(), path.slice(2)) : path;
|
|
3483
|
+
}
|
|
3484
|
+
function configuredDirectory() {
|
|
3485
|
+
const raw = getSetting(SKILL_DIRECTORIES_SETTING);
|
|
3486
|
+
if (!raw) return null;
|
|
3487
|
+
try {
|
|
3488
|
+
const parsed = JSON.parse(raw);
|
|
3489
|
+
return Array.isArray(parsed) && typeof parsed[0] === "string" ? parsed[0] : null;
|
|
3490
|
+
} catch {
|
|
3491
|
+
return null;
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
function defaultLibrary(configDir) {
|
|
3495
|
+
const path = resolve2(configDir, "skills");
|
|
3496
|
+
return { configuredPath: path, resolvedPath: path, available: true, custom: false };
|
|
3497
|
+
}
|
|
3498
|
+
async function resolveLibrary(path) {
|
|
3499
|
+
const expanded = expandHome(path);
|
|
3500
|
+
if (!isAbsolute2(expanded)) throw new Error("Selected path must be absolute");
|
|
3501
|
+
const absolute = resolve2(expanded);
|
|
3502
|
+
const info = await stat(absolute);
|
|
3503
|
+
if (!info.isDirectory()) throw new Error("Selected path is not a directory");
|
|
3504
|
+
await access2(absolute, constants2.R_OK);
|
|
3505
|
+
return { configuredPath: path, resolvedPath: await realpath(absolute) };
|
|
3506
|
+
}
|
|
3507
|
+
function mapToResponse(skill) {
|
|
3508
|
+
const source = skill.source ?? "global-openfox";
|
|
3509
|
+
return {
|
|
3510
|
+
...skill.metadata,
|
|
3511
|
+
enabled: isSkillEnabled(skill.metadata.id),
|
|
3512
|
+
source,
|
|
3513
|
+
path: skill.entrypoint ?? null,
|
|
3514
|
+
legacy: skill.legacy ?? true,
|
|
3515
|
+
readOnly: source === "bundled" || (source === "global-shared" || source === "selected" || source === "project-shared") && (skill.legacy ?? true),
|
|
3516
|
+
warnings: skill.warnings ?? []
|
|
3517
|
+
};
|
|
3518
|
+
}
|
|
3519
|
+
function validateSkillCreate(body) {
|
|
3520
|
+
const baseError = validateNameIdPrompt(body);
|
|
3521
|
+
if (baseError) return baseError;
|
|
3522
|
+
const metadata = body["metadata"];
|
|
3523
|
+
if (typeof metadata["description"] !== "string" || !metadata["description"].trim()) {
|
|
3524
|
+
return "Missing required field: metadata.description";
|
|
3525
|
+
}
|
|
3526
|
+
return null;
|
|
3527
|
+
}
|
|
3528
|
+
function createConfig(configDir, projectDir) {
|
|
3529
|
+
return {
|
|
3530
|
+
dirName: "skills",
|
|
3531
|
+
ext: ".skill.md",
|
|
3532
|
+
loadDefaults: loadDefaultSkills,
|
|
3533
|
+
loadUser: loadUserSkills,
|
|
3534
|
+
loadProject: loadProjectSkills,
|
|
3535
|
+
loadAll: loadAllSkills,
|
|
3536
|
+
findById: findSkillById,
|
|
3537
|
+
save: saveSkill,
|
|
3538
|
+
saveToProject: saveSkillToProject,
|
|
3539
|
+
delete: deleteSkill,
|
|
3540
|
+
deleteProject: deleteProjectSkill,
|
|
3541
|
+
exists: skillExists,
|
|
3542
|
+
isDefault: isDefaultSkill,
|
|
3543
|
+
getDefaultIds: getDefaultSkillIds,
|
|
3544
|
+
validateCreate: validateSkillCreate,
|
|
3545
|
+
mapToResponse,
|
|
3546
|
+
extraGetData: async () => {
|
|
3547
|
+
const discovery = await loadAllSkillsWithDiagnostics(configDir, projectDir);
|
|
3548
|
+
const items = discovery.skills;
|
|
3549
|
+
const configured = configuredDirectory();
|
|
3550
|
+
let selectedDirectory = configured ? { configuredPath: configured, resolvedPath: null, available: false, custom: true } : defaultLibrary(configDir);
|
|
3551
|
+
const diagnostics = [];
|
|
3552
|
+
if (configured) {
|
|
3553
|
+
try {
|
|
3554
|
+
selectedDirectory = { ...await resolveLibrary(configured), available: true, custom: true };
|
|
3555
|
+
} catch {
|
|
3556
|
+
diagnostics.push(`Selected skills directory is unavailable: ${configured}`);
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
return {
|
|
3560
|
+
items: items.map(mapToResponse),
|
|
3561
|
+
selectedDirectory,
|
|
3562
|
+
diagnostics: [...diagnostics, ...discovery.diagnostics, ...items.flatMap((skill) => skill.warnings ?? [])]
|
|
3563
|
+
};
|
|
3564
|
+
}
|
|
3565
|
+
};
|
|
3566
|
+
}
|
|
3417
3567
|
function createSkillRoutes(configDir, projectDir) {
|
|
3418
|
-
|
|
3568
|
+
const router = Router2();
|
|
3569
|
+
router.put("/library", async (req, res) => {
|
|
3570
|
+
const path = req.body.path;
|
|
3571
|
+
if (typeof path !== "string" || !path.trim()) return res.status(400).json({ error: "path is required" });
|
|
3572
|
+
try {
|
|
3573
|
+
const selected = await resolveLibrary(path);
|
|
3574
|
+
setSetting(SKILL_DIRECTORIES_SETTING, JSON.stringify([path]));
|
|
3575
|
+
res.json(selected);
|
|
3576
|
+
} catch (error) {
|
|
3577
|
+
res.status(400).json({ error: error instanceof Error ? error.message : "Cannot use directory" });
|
|
3578
|
+
}
|
|
3579
|
+
});
|
|
3580
|
+
router.delete("/library", (_req, res) => {
|
|
3581
|
+
deleteSetting(SKILL_DIRECTORIES_SETTING);
|
|
3582
|
+
res.json({ success: true });
|
|
3583
|
+
});
|
|
3584
|
+
router.post("/install", (req, res) => {
|
|
3585
|
+
upload.array("files", 1e3)(req, res, async (uploadError) => {
|
|
3586
|
+
if (uploadError) return res.status(413).json({ error: uploadError.message });
|
|
3587
|
+
try {
|
|
3588
|
+
const configured = configuredDirectory();
|
|
3589
|
+
const library = configured ? await resolveLibrary(configured) : defaultLibrary(configDir);
|
|
3590
|
+
await mkdir2(library.resolvedPath, { recursive: true });
|
|
3591
|
+
const packageName = String(req.body["packageName"] ?? "");
|
|
3592
|
+
const paths = JSON.parse(String(req.body["paths"] ?? "[]"));
|
|
3593
|
+
const files = req.files;
|
|
3594
|
+
if (!Array.isArray(paths) || paths.length !== files.length || paths.some((path) => typeof path !== "string")) {
|
|
3595
|
+
return res.status(400).json({ error: "File path manifest does not match upload" });
|
|
3596
|
+
}
|
|
3597
|
+
const totalBytes = files.reduce((total, file) => total + file.size, 0);
|
|
3598
|
+
if (totalBytes > 50 * 1024 * 1024) return res.status(413).json({ error: "Package exceeds 50 MiB" });
|
|
3599
|
+
const installed = await installSkillPackage(
|
|
3600
|
+
library.resolvedPath,
|
|
3601
|
+
packageName,
|
|
3602
|
+
files.map((file, index) => ({ path: paths[index], content: file.buffer }))
|
|
3603
|
+
);
|
|
3604
|
+
res.status(201).json(installed);
|
|
3605
|
+
} catch (error) {
|
|
3606
|
+
const status = error instanceof SkillInstallError ? error.status : 400;
|
|
3607
|
+
res.status(status).json({ error: error instanceof Error ? error.message : "Install failed" });
|
|
3608
|
+
}
|
|
3609
|
+
});
|
|
3610
|
+
});
|
|
3611
|
+
router.post("/:id/toggle", async (req, res) => {
|
|
3612
|
+
const skills = await loadAllSkills(configDir, projectDir);
|
|
3613
|
+
const existing = findSkillById(req.params["id"], skills);
|
|
3614
|
+
if (!existing) return res.status(404).json({ error: "Not found" });
|
|
3615
|
+
const enabled = !isSkillEnabled(existing.metadata.id);
|
|
3616
|
+
setSkillEnabled(existing.metadata.id, enabled);
|
|
3617
|
+
res.json({ enabled });
|
|
3618
|
+
});
|
|
3619
|
+
router.put("/:id", async (req, res) => {
|
|
3620
|
+
const skills = await loadAllSkills(configDir, projectDir);
|
|
3621
|
+
const existing = findSkillById(req.params["id"], skills);
|
|
3622
|
+
if (!existing) return res.status(404).json({ error: "Not found" });
|
|
3623
|
+
const updated = await updateOwnedSkill(existing, req.body);
|
|
3624
|
+
if (!updated) return res.status(403).json({ error: "This skill is read-only" });
|
|
3625
|
+
res.json(updated);
|
|
3626
|
+
});
|
|
3627
|
+
router.delete("/:id", async (req, res) => {
|
|
3628
|
+
const skills = await loadAllSkills(configDir, projectDir);
|
|
3629
|
+
const existing = findSkillById(req.params["id"], skills);
|
|
3630
|
+
if (!existing) return res.status(404).json({ error: "Not found" });
|
|
3631
|
+
const result = await deleteOwnedSkill(existing);
|
|
3632
|
+
if (!result.success) return res.status(403).json({ error: result.reason ?? "Cannot delete this skill" });
|
|
3633
|
+
res.json({ success: true });
|
|
3634
|
+
});
|
|
3635
|
+
router.use(createCrudRoutes(createConfig(configDir, projectDir), configDir, projectDir));
|
|
3636
|
+
return router;
|
|
3419
3637
|
}
|
|
3420
3638
|
|
|
3421
3639
|
// src/server/commands/registry.ts
|
|
3422
|
-
import { writeFile, mkdir, unlink } from "fs/promises";
|
|
3423
|
-
import { join as
|
|
3640
|
+
import { writeFile as writeFile2, mkdir as mkdir3, unlink } from "fs/promises";
|
|
3641
|
+
import { join as join5, dirname as dirname4 } from "path";
|
|
3424
3642
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3425
|
-
import
|
|
3426
|
-
var __bundleDir =
|
|
3427
|
-
var DEFAULTS_DIR =
|
|
3428
|
-
var DEFAULTS_DIR_ALT =
|
|
3643
|
+
import matter2 from "gray-matter";
|
|
3644
|
+
var __bundleDir = dirname4(fileURLToPath4(import.meta.url));
|
|
3645
|
+
var DEFAULTS_DIR = join5(__bundleDir, "defaults");
|
|
3646
|
+
var DEFAULTS_DIR_ALT = join5(__bundleDir, "command-defaults");
|
|
3429
3647
|
var COMMAND_EXTENSION = ".command.md";
|
|
3430
3648
|
function getCommandsDir(configDir) {
|
|
3431
|
-
return
|
|
3649
|
+
return join5(configDir, "commands");
|
|
3432
3650
|
}
|
|
3433
3651
|
function getProjectCommandsDir(projectDir) {
|
|
3434
|
-
return
|
|
3652
|
+
return join5(projectDir, ".openfox", "commands");
|
|
3435
3653
|
}
|
|
3436
3654
|
async function loadDefaultCommands() {
|
|
3437
3655
|
let defaults = await loadItemsFromDir(DEFAULTS_DIR, {
|
|
@@ -3488,26 +3706,26 @@ function findCommandById(commandId, commands) {
|
|
|
3488
3706
|
return commands.find((c) => c.metadata.id === commandId);
|
|
3489
3707
|
}
|
|
3490
3708
|
async function commandExists(configDir, commandId, projectDir) {
|
|
3491
|
-
if (await pathExists(
|
|
3492
|
-
if (projectDir && await pathExists(
|
|
3709
|
+
if (await pathExists(join5(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`))) return true;
|
|
3710
|
+
if (projectDir && await pathExists(join5(getProjectCommandsDir(projectDir), `${commandId}${COMMAND_EXTENSION}`)))
|
|
3493
3711
|
return true;
|
|
3494
3712
|
return false;
|
|
3495
3713
|
}
|
|
3496
3714
|
async function saveCommand(configDir, command) {
|
|
3497
3715
|
const commandsDir = getCommandsDir(configDir);
|
|
3498
3716
|
if (!await pathExists(commandsDir)) {
|
|
3499
|
-
await
|
|
3717
|
+
await mkdir3(commandsDir, { recursive: true });
|
|
3500
3718
|
}
|
|
3501
|
-
const filePath =
|
|
3502
|
-
const content =
|
|
3503
|
-
await
|
|
3719
|
+
const filePath = join5(commandsDir, `${command.metadata.id}${COMMAND_EXTENSION}`);
|
|
3720
|
+
const content = matter2.stringify(command.prompt, command.metadata);
|
|
3721
|
+
await writeFile2(filePath, content, "utf-8");
|
|
3504
3722
|
}
|
|
3505
3723
|
async function saveCommandToProject(projectDir, command) {
|
|
3506
3724
|
await saveItemToDir(
|
|
3507
3725
|
getProjectCommandsDir(projectDir),
|
|
3508
3726
|
command,
|
|
3509
3727
|
COMMAND_EXTENSION,
|
|
3510
|
-
(c) =>
|
|
3728
|
+
(c) => matter2.stringify(c.prompt, c.metadata)
|
|
3511
3729
|
);
|
|
3512
3730
|
}
|
|
3513
3731
|
async function deleteProjectCommand(projectDir, commandId) {
|
|
@@ -3518,7 +3736,7 @@ async function deleteCommand(configDir, commandId) {
|
|
|
3518
3736
|
if (isDefault) {
|
|
3519
3737
|
return { success: false, reason: "Cannot delete built-in defaults" };
|
|
3520
3738
|
}
|
|
3521
|
-
const filePath =
|
|
3739
|
+
const filePath = join5(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
|
|
3522
3740
|
try {
|
|
3523
3741
|
await unlink(filePath);
|
|
3524
3742
|
return { success: true };
|
|
@@ -3528,7 +3746,7 @@ async function deleteCommand(configDir, commandId) {
|
|
|
3528
3746
|
}
|
|
3529
3747
|
|
|
3530
3748
|
// src/server/routes/commands.ts
|
|
3531
|
-
var
|
|
3749
|
+
var config = {
|
|
3532
3750
|
dirName: "commands",
|
|
3533
3751
|
ext: ".command.md",
|
|
3534
3752
|
loadDefaults: loadDefaultCommands,
|
|
@@ -3547,11 +3765,11 @@ var config2 = {
|
|
|
3547
3765
|
mapToResponse: (c) => c.metadata
|
|
3548
3766
|
};
|
|
3549
3767
|
function createCommandRoutes(configDir, projectDir) {
|
|
3550
|
-
return createCrudRoutes(
|
|
3768
|
+
return createCrudRoutes(config, configDir, projectDir);
|
|
3551
3769
|
}
|
|
3552
3770
|
|
|
3553
3771
|
// src/server/routes/agents.ts
|
|
3554
|
-
var
|
|
3772
|
+
var config2 = {
|
|
3555
3773
|
dirName: "agents",
|
|
3556
3774
|
ext: ".agent.md",
|
|
3557
3775
|
loadDefaults: loadDefaultAgents,
|
|
@@ -3574,12 +3792,12 @@ var config3 = {
|
|
|
3574
3792
|
mapToResponse: (a) => a.metadata
|
|
3575
3793
|
};
|
|
3576
3794
|
function createAgentRoutes(configDir, projectDir) {
|
|
3577
|
-
return createCrudRoutes(
|
|
3795
|
+
return createCrudRoutes(config2, configDir, projectDir);
|
|
3578
3796
|
}
|
|
3579
3797
|
|
|
3580
3798
|
// src/server/routes/workflows.ts
|
|
3581
3799
|
import "express";
|
|
3582
|
-
function createWorkflowRoutes(configDir,
|
|
3800
|
+
function createWorkflowRoutes(configDir, config3, projectDir) {
|
|
3583
3801
|
const crudConfig = {
|
|
3584
3802
|
dirName: "workflows",
|
|
3585
3803
|
ext: ".workflow.json",
|
|
@@ -3608,7 +3826,7 @@ function createWorkflowRoutes(configDir, config4, projectDir) {
|
|
|
3608
3826
|
subGroups: subGroups.length > 0 ? subGroups : void 0
|
|
3609
3827
|
};
|
|
3610
3828
|
},
|
|
3611
|
-
extraGetData: () => Promise.resolve({ activeWorkflowId:
|
|
3829
|
+
extraGetData: () => Promise.resolve({ activeWorkflowId: config3.activeWorkflowId ?? "default" }),
|
|
3612
3830
|
extraRoutes: (router) => {
|
|
3613
3831
|
router.get("/template-variables", (_req, res) => {
|
|
3614
3832
|
res.json({ variables: TEMPLATE_VARIABLES });
|
|
@@ -3619,19 +3837,19 @@ function createWorkflowRoutes(configDir, config4, projectDir) {
|
|
|
3619
3837
|
}
|
|
3620
3838
|
|
|
3621
3839
|
// src/server/routes/dev-server.ts
|
|
3622
|
-
import { Router as
|
|
3840
|
+
import { Router as Router4 } from "express";
|
|
3623
3841
|
function createDevServerRoutes() {
|
|
3624
|
-
const router =
|
|
3842
|
+
const router = Router4();
|
|
3625
3843
|
router.get("/", async (req, res) => {
|
|
3626
3844
|
const workdir = req.query["workdir"];
|
|
3627
3845
|
if (!workdir) return res.status(400).json({ error: "workdir required" });
|
|
3628
3846
|
const status = devServerManager.getStatus(workdir);
|
|
3629
3847
|
if (!status.config) {
|
|
3630
|
-
const
|
|
3631
|
-
if (
|
|
3632
|
-
status.config =
|
|
3633
|
-
status.url =
|
|
3634
|
-
status.hotReload =
|
|
3848
|
+
const config3 = await devServerManager.loadConfig(workdir);
|
|
3849
|
+
if (config3) {
|
|
3850
|
+
status.config = config3;
|
|
3851
|
+
status.url = config3.url;
|
|
3852
|
+
status.hotReload = config3.hotReload;
|
|
3635
3853
|
}
|
|
3636
3854
|
}
|
|
3637
3855
|
res.json(status);
|
|
@@ -3677,8 +3895,8 @@ function createDevServerRoutes() {
|
|
|
3677
3895
|
router.get("/config", async (req, res) => {
|
|
3678
3896
|
const workdir = req.query["workdir"];
|
|
3679
3897
|
if (!workdir) return res.status(400).json({ error: "workdir required" });
|
|
3680
|
-
const
|
|
3681
|
-
res.json({ config:
|
|
3898
|
+
const config3 = await devServerManager.loadConfig(workdir);
|
|
3899
|
+
res.json({ config: config3 });
|
|
3682
3900
|
});
|
|
3683
3901
|
router.post("/config", async (req, res) => {
|
|
3684
3902
|
const workdir = req.query["workdir"];
|
|
@@ -3688,9 +3906,9 @@ function createDevServerRoutes() {
|
|
|
3688
3906
|
return res.status(400).json({ error: "command and url are required" });
|
|
3689
3907
|
}
|
|
3690
3908
|
try {
|
|
3691
|
-
const
|
|
3692
|
-
await devServerManager.saveConfig(workdir,
|
|
3693
|
-
res.json({ config:
|
|
3909
|
+
const config3 = { command, url, hotReload: hotReload ?? false, disableInspect: disableInspect ?? false };
|
|
3910
|
+
await devServerManager.saveConfig(workdir, config3);
|
|
3911
|
+
res.json({ config: config3 });
|
|
3694
3912
|
} catch (err) {
|
|
3695
3913
|
res.status(500).json({ error: err instanceof Error ? err.message : "Failed to save config" });
|
|
3696
3914
|
}
|
|
@@ -3699,9 +3917,9 @@ function createDevServerRoutes() {
|
|
|
3699
3917
|
}
|
|
3700
3918
|
|
|
3701
3919
|
// src/server/routes/terminals.ts
|
|
3702
|
-
import { Router as
|
|
3920
|
+
import { Router as Router5 } from "express";
|
|
3703
3921
|
function createTerminalRoutes() {
|
|
3704
|
-
const router =
|
|
3922
|
+
const router = Router5();
|
|
3705
3923
|
router.get("/", (req, res) => {
|
|
3706
3924
|
const projectId = req.query["projectId"];
|
|
3707
3925
|
const sessions = projectId ? terminalManager.getByProject(projectId) : [];
|
|
@@ -3740,22 +3958,22 @@ function createTerminalRoutes() {
|
|
|
3740
3958
|
}
|
|
3741
3959
|
|
|
3742
3960
|
// src/server/routes/directories.ts
|
|
3743
|
-
import { Router as
|
|
3961
|
+
import { Router as Router6 } from "express";
|
|
3744
3962
|
import { readdir } from "fs/promises";
|
|
3745
|
-
import { resolve as
|
|
3963
|
+
import { resolve as resolve3, join as join6, dirname as dirname5, basename as basename2 } from "path";
|
|
3746
3964
|
function createDirectoryRoutes() {
|
|
3747
|
-
const router =
|
|
3965
|
+
const router = Router6();
|
|
3748
3966
|
const DEFAULT_BASE_PATH = process.cwd();
|
|
3749
3967
|
router.get("/", async (req, res) => {
|
|
3750
3968
|
const path = req.query["path"] || DEFAULT_BASE_PATH;
|
|
3751
3969
|
try {
|
|
3752
|
-
const resolvedPath =
|
|
3970
|
+
const resolvedPath = resolve3(path);
|
|
3753
3971
|
const entries = await readdir(resolvedPath, { withFileTypes: true });
|
|
3754
3972
|
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
3755
3973
|
name: entry.name,
|
|
3756
|
-
path:
|
|
3974
|
+
path: join6(resolvedPath, entry.name)
|
|
3757
3975
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
3758
|
-
const parent =
|
|
3976
|
+
const parent = dirname5(resolvedPath);
|
|
3759
3977
|
const hasParent = parent !== resolvedPath;
|
|
3760
3978
|
res.json({
|
|
3761
3979
|
current: resolvedPath,
|
|
@@ -3777,10 +3995,10 @@ function createDirectoryRoutes() {
|
|
|
3777
3995
|
}
|
|
3778
3996
|
|
|
3779
3997
|
// src/server/routes/file-search.ts
|
|
3780
|
-
import { Router as
|
|
3998
|
+
import { Router as Router7 } from "express";
|
|
3781
3999
|
import fg from "fast-glob";
|
|
3782
4000
|
function createFileSearchRoutes() {
|
|
3783
|
-
const router =
|
|
4001
|
+
const router = Router7();
|
|
3784
4002
|
router.get("/", async (req, res) => {
|
|
3785
4003
|
const query = req.query["q"] || "";
|
|
3786
4004
|
const workdir = req.query["workdir"] || process.cwd();
|
|
@@ -3856,11 +4074,11 @@ function fuzzyScore(filePath, query) {
|
|
|
3856
4074
|
}
|
|
3857
4075
|
|
|
3858
4076
|
// src/server/routes/auto-update.ts
|
|
3859
|
-
import { Router as
|
|
4077
|
+
import { Router as Router8 } from "express";
|
|
3860
4078
|
import { spawn as spawn2 } from "child_process";
|
|
3861
4079
|
|
|
3862
4080
|
// src/constants.ts
|
|
3863
|
-
var VERSION = "2.0.
|
|
4081
|
+
var VERSION = "2.0.60";
|
|
3864
4082
|
|
|
3865
4083
|
// src/server/routes/auto-update.ts
|
|
3866
4084
|
var updateInProgress = false;
|
|
@@ -3878,14 +4096,15 @@ async function checkAuth(req, opts) {
|
|
|
3878
4096
|
return true;
|
|
3879
4097
|
}
|
|
3880
4098
|
function createAutoUpdateRoutes(options = {}) {
|
|
3881
|
-
const router =
|
|
4099
|
+
const router = Router8();
|
|
3882
4100
|
router.get("/check", async (_req, res) => {
|
|
3883
4101
|
const isService = isRunningAsService();
|
|
3884
4102
|
const current = VERSION;
|
|
3885
4103
|
try {
|
|
3886
|
-
const latest = await new Promise((
|
|
4104
|
+
const latest = await new Promise((resolve5, reject) => {
|
|
3887
4105
|
const child = spawn2("npm", ["view", "openfox", "version"], {
|
|
3888
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4106
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4107
|
+
windowsHide: true
|
|
3889
4108
|
});
|
|
3890
4109
|
let stdout = "";
|
|
3891
4110
|
child.stdout?.on("data", (data) => {
|
|
@@ -3893,7 +4112,7 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3893
4112
|
});
|
|
3894
4113
|
child.on("close", (code) => {
|
|
3895
4114
|
if (code === 0) {
|
|
3896
|
-
|
|
4115
|
+
resolve5(stdout.trim());
|
|
3897
4116
|
} else {
|
|
3898
4117
|
reject(new Error(`npm view exited with code ${code}`));
|
|
3899
4118
|
}
|
|
@@ -3923,7 +4142,8 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3923
4142
|
try {
|
|
3924
4143
|
const isService = isRunningAsService();
|
|
3925
4144
|
const child = spawn2("bash", ["-c", "openfox update"], {
|
|
3926
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4145
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4146
|
+
windowsHide: true
|
|
3927
4147
|
});
|
|
3928
4148
|
let stdout = "";
|
|
3929
4149
|
let stderr = "";
|
|
@@ -3936,9 +4156,9 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3936
4156
|
const timeout = setTimeout(() => {
|
|
3937
4157
|
child.kill();
|
|
3938
4158
|
}, UPDATE_TIMEOUT);
|
|
3939
|
-
const exitCode = await new Promise((
|
|
3940
|
-
child.on("close",
|
|
3941
|
-
child.on("error", () =>
|
|
4159
|
+
const exitCode = await new Promise((resolve5) => {
|
|
4160
|
+
child.on("close", resolve5);
|
|
4161
|
+
child.on("error", () => resolve5(1));
|
|
3942
4162
|
});
|
|
3943
4163
|
clearTimeout(timeout);
|
|
3944
4164
|
if (exitCode === 0) {
|
|
@@ -3963,7 +4183,8 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3963
4183
|
try {
|
|
3964
4184
|
const child = spawn2("bash", ["-c", "openfox service restart"], {
|
|
3965
4185
|
detached: true,
|
|
3966
|
-
stdio: "ignore"
|
|
4186
|
+
stdio: "ignore",
|
|
4187
|
+
windowsHide: true
|
|
3967
4188
|
});
|
|
3968
4189
|
child.unref();
|
|
3969
4190
|
res.json({ success: true });
|
|
@@ -3975,15 +4196,15 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3975
4196
|
}
|
|
3976
4197
|
|
|
3977
4198
|
// src/server/index.ts
|
|
3978
|
-
var __dirname3 =
|
|
3979
|
-
async function createServerHandle(
|
|
3980
|
-
setRuntimeConfig(
|
|
3981
|
-
setLogLevel(
|
|
4199
|
+
var __dirname3 = dirname6(fileURLToPath5(import.meta.url));
|
|
4200
|
+
async function createServerHandle(config3) {
|
|
4201
|
+
setRuntimeConfig(config3);
|
|
4202
|
+
setLogLevel(config3.logging?.level ?? void 0, config3.mode);
|
|
3982
4203
|
await loadServerAuthConfig();
|
|
3983
|
-
const db = initDatabase(
|
|
4204
|
+
const db = initDatabase(config3);
|
|
3984
4205
|
initEventStore(db);
|
|
3985
|
-
const configDir = getGlobalConfigDir(
|
|
3986
|
-
const providerManager = createProviderManager(
|
|
4206
|
+
const configDir = getGlobalConfigDir(config3.mode ?? "production");
|
|
4207
|
+
const providerManager = createProviderManager(config3);
|
|
3987
4208
|
const sessionManager = new SessionManager(providerManager);
|
|
3988
4209
|
devServerManager.setSessionManager(sessionManager);
|
|
3989
4210
|
const useMock = process.env["OPENFOX_MOCK_LLM"] === "true";
|
|
@@ -3994,24 +4215,24 @@ async function createServerHandle(config4) {
|
|
|
3994
4215
|
}
|
|
3995
4216
|
async function initLLM() {
|
|
3996
4217
|
const llmClient = getLLMClient();
|
|
3997
|
-
const backend =
|
|
4218
|
+
const backend = config3.llm.backend;
|
|
3998
4219
|
llmClient.setBackend(backend);
|
|
3999
4220
|
if (!useMock) {
|
|
4000
4221
|
logger.info("Using configured LLM backend", { backend: getBackendDisplayName(backend) });
|
|
4001
4222
|
}
|
|
4002
|
-
const detected = await detectModel(
|
|
4003
|
-
if (detected && !
|
|
4223
|
+
const detected = await detectModel(config3.llm.baseUrl);
|
|
4224
|
+
if (detected && !config3.defaultModelSelection) {
|
|
4004
4225
|
llmClient.setModel(detected);
|
|
4005
4226
|
if (!useMock) {
|
|
4006
4227
|
logger.info("Auto-detected LLM model", { model: detected, backend: getBackendDisplayName(backend) });
|
|
4007
4228
|
}
|
|
4008
|
-
} else if (detected &&
|
|
4229
|
+
} else if (detected && config3.defaultModelSelection) {
|
|
4009
4230
|
if (!useMock) {
|
|
4010
|
-
logger.debug("Skipping auto-detect, using configured model", { model:
|
|
4231
|
+
logger.debug("Skipping auto-detect, using configured model", { model: config3.llm.model });
|
|
4011
4232
|
}
|
|
4012
4233
|
} else {
|
|
4013
4234
|
if (!useMock) {
|
|
4014
|
-
logger.warn("Could not auto-detect model, using config", { model:
|
|
4235
|
+
logger.warn("Could not auto-detect model, using config", { model: config3.llm.model });
|
|
4015
4236
|
}
|
|
4016
4237
|
}
|
|
4017
4238
|
const activeProvider = providerManager.getActiveProvider();
|
|
@@ -4031,15 +4252,15 @@ async function createServerHandle(config4) {
|
|
|
4031
4252
|
const mcpManager = new McpManager({
|
|
4032
4253
|
onToolsDiscovered: async (name, tools) => {
|
|
4033
4254
|
try {
|
|
4034
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
4035
|
-
const mode =
|
|
4036
|
-
const globalConfig = await loadGlobalConfig(mode);
|
|
4255
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
4256
|
+
const mode = config3.mode ?? "production";
|
|
4257
|
+
const globalConfig = await loadGlobalConfig(mode, config3.globalConfigPath);
|
|
4037
4258
|
const mcpServers2 = {
|
|
4038
4259
|
...globalConfig.mcpServers ?? {}
|
|
4039
4260
|
};
|
|
4040
4261
|
if (mcpServers2[name]) {
|
|
4041
4262
|
mcpServers2[name] = { ...mcpServers2[name], cachedTools: tools };
|
|
4042
|
-
await saveGlobalConfig(mode, { ...globalConfig, mcpServers: mcpServers2 });
|
|
4263
|
+
await saveGlobalConfig(mode, { ...globalConfig, mcpServers: mcpServers2 }, config3.globalConfigPath);
|
|
4043
4264
|
}
|
|
4044
4265
|
} catch (err) {
|
|
4045
4266
|
logger.warn("Failed to persist MCP tool cache", { name, error: String(err) });
|
|
@@ -4047,8 +4268,9 @@ async function createServerHandle(config4) {
|
|
|
4047
4268
|
}
|
|
4048
4269
|
});
|
|
4049
4270
|
setMcpManagerForTools(mcpManager);
|
|
4050
|
-
setMcpConfigMode(
|
|
4051
|
-
|
|
4271
|
+
setMcpConfigMode(config3.mode ?? "production");
|
|
4272
|
+
setMcpConfigPath(config3.globalConfigPath);
|
|
4273
|
+
const mcpServers = config3.mcpServers ?? {};
|
|
4052
4274
|
Promise.all(
|
|
4053
4275
|
Object.entries(mcpServers).map(
|
|
4054
4276
|
([name, serverConfig]) => mcpManager.addServer(name, serverConfig).catch((err) => {
|
|
@@ -4061,7 +4283,7 @@ async function createServerHandle(config4) {
|
|
|
4061
4283
|
setMcpTools(mcpTools);
|
|
4062
4284
|
logger.info("MCP tools registered", { count: mcpTools.length });
|
|
4063
4285
|
}
|
|
4064
|
-
const { signalMcpReady } = await import("./server-
|
|
4286
|
+
const { signalMcpReady } = await import("./server-LMH7ZH5X.js");
|
|
4065
4287
|
signalMcpReady();
|
|
4066
4288
|
});
|
|
4067
4289
|
const app = express();
|
|
@@ -4132,7 +4354,7 @@ async function createServerHandle(config4) {
|
|
|
4132
4354
|
if (!name || !workdir) {
|
|
4133
4355
|
return res.status(400).json({ error: "name and workdir are required" });
|
|
4134
4356
|
}
|
|
4135
|
-
const { createDirectoryWithGit } = await import("./project-creator-
|
|
4357
|
+
const { createDirectoryWithGit } = await import("./project-creator-IDW7RACH.js");
|
|
4136
4358
|
try {
|
|
4137
4359
|
const project = await createDirectoryWithGit(name, workdir);
|
|
4138
4360
|
res.status(201).json({ project });
|
|
@@ -4150,7 +4372,7 @@ async function createServerHandle(config4) {
|
|
|
4150
4372
|
if (!targetPath) {
|
|
4151
4373
|
return res.status(400).json({ error: "path is required" });
|
|
4152
4374
|
}
|
|
4153
|
-
const { checkPermissions } = await import("./permissions-
|
|
4375
|
+
const { checkPermissions } = await import("./permissions-CGEK3DGZ.js");
|
|
4154
4376
|
const result = await checkPermissions(targetPath);
|
|
4155
4377
|
if (result.success) {
|
|
4156
4378
|
res.json(result);
|
|
@@ -4167,7 +4389,7 @@ async function createServerHandle(config4) {
|
|
|
4167
4389
|
if (!["group", "ownership", "join_group", "join_group_and_group"].includes(action)) {
|
|
4168
4390
|
return res.status(400).json({ error: 'action must be "group", "ownership", "join_group", or "join_group_and_group"' });
|
|
4169
4391
|
}
|
|
4170
|
-
const { fixPermissions } = await import("./permissions-
|
|
4392
|
+
const { fixPermissions } = await import("./permissions-CGEK3DGZ.js");
|
|
4171
4393
|
const result = await fixPermissions(targetPath, action);
|
|
4172
4394
|
if (result.success) {
|
|
4173
4395
|
res.json(result);
|
|
@@ -4247,14 +4469,14 @@ async function createServerHandle(config4) {
|
|
|
4247
4469
|
if (!project) {
|
|
4248
4470
|
return res.status(404).json({ error: "Project not found" });
|
|
4249
4471
|
}
|
|
4250
|
-
const { providerId, model } = parseDefaultModelSelection(
|
|
4472
|
+
const { providerId, model } = parseDefaultModelSelection(config3.defaultModelSelection);
|
|
4251
4473
|
const session = sessionManager.createSession(projectId, title, providerId ?? null, model ?? null);
|
|
4252
4474
|
res.status(201).json({ session });
|
|
4253
4475
|
});
|
|
4254
4476
|
app.get("/api/sessions/:id", async (req, res) => {
|
|
4255
4477
|
const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
|
|
4256
4478
|
const { buildMessagesFromStoredEvents } = await import("./folding-2BGFLV5J.js");
|
|
4257
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
4479
|
+
const { getPendingQuestionsForSession } = await import("./tools-WGAZKL56.js");
|
|
4258
4480
|
const session = sessionManager.getSession(req.params.id);
|
|
4259
4481
|
if (!session) {
|
|
4260
4482
|
return res.status(404).json({ error: "Session not found" });
|
|
@@ -4273,8 +4495,8 @@ async function createServerHandle(config4) {
|
|
|
4273
4495
|
if (!session) {
|
|
4274
4496
|
return res.status(404).json({ error: "Session not found" });
|
|
4275
4497
|
}
|
|
4276
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
4277
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
4498
|
+
const { stopSessionExecution } = await import("./chat-handler-MBR6ZQTX.js");
|
|
4499
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-WGAZKL56.js");
|
|
4278
4500
|
sessionManager.clearMessageQueue(sessionId);
|
|
4279
4501
|
stopSessionExecution(sessionId, sessionManager);
|
|
4280
4502
|
abortSession(sessionId);
|
|
@@ -4327,12 +4549,12 @@ async function createServerHandle(config4) {
|
|
|
4327
4549
|
if (!result.success) {
|
|
4328
4550
|
return res.status(500).json({ error: result.error ?? "Failed to set default model" });
|
|
4329
4551
|
}
|
|
4330
|
-
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-
|
|
4331
|
-
const globalConfig = await loadGlobalConfig(
|
|
4552
|
+
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-GMQUPNBY.js");
|
|
4553
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4332
4554
|
const updatedConfig = setDefaultModelSelection(globalConfig, providerId, model);
|
|
4333
|
-
await saveGlobalConfig(
|
|
4334
|
-
|
|
4335
|
-
res.json({ success: true, defaultModelSelection:
|
|
4555
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
4556
|
+
config3.defaultModelSelection = updatedConfig.defaultModelSelection;
|
|
4557
|
+
res.json({ success: true, defaultModelSelection: config3.defaultModelSelection });
|
|
4336
4558
|
});
|
|
4337
4559
|
app.put("/api/sessions/:id/criteria", async (req, res) => {
|
|
4338
4560
|
const sessionId = req.params.id;
|
|
@@ -4428,7 +4650,7 @@ async function createServerHandle(config4) {
|
|
|
4428
4650
|
if (!callId || approved === void 0) {
|
|
4429
4651
|
return res.status(400).json({ error: "callId and approved are required" });
|
|
4430
4652
|
}
|
|
4431
|
-
const { providePathConfirmation } = await import("./tools-
|
|
4653
|
+
const { providePathConfirmation } = await import("./tools-WGAZKL56.js");
|
|
4432
4654
|
const result = providePathConfirmation(callId, approved, alwaysAllow);
|
|
4433
4655
|
if (!result.found) {
|
|
4434
4656
|
return res.status(404).json({ error: "No pending path confirmation with that ID" });
|
|
@@ -4436,7 +4658,7 @@ async function createServerHandle(config4) {
|
|
|
4436
4658
|
const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
|
|
4437
4659
|
const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-2BGFLV5J.js");
|
|
4438
4660
|
const { createSessionStateMessage } = await import("./protocol-CTNE3ANP.js");
|
|
4439
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
4661
|
+
const { getPendingQuestionsForSession } = await import("./tools-WGAZKL56.js");
|
|
4440
4662
|
const eventStore = getEventStore2();
|
|
4441
4663
|
const events = eventStore.getEvents(sessionId);
|
|
4442
4664
|
const messages = buildMessagesFromStoredEvents(events);
|
|
@@ -4457,7 +4679,7 @@ async function createServerHandle(config4) {
|
|
|
4457
4679
|
if (!skip && typeof answer !== "string") {
|
|
4458
4680
|
return res.status(400).json({ error: "answer is required when not skipping" });
|
|
4459
4681
|
}
|
|
4460
|
-
const { provideAnswer } = await import("./tools-
|
|
4682
|
+
const { provideAnswer } = await import("./tools-WGAZKL56.js");
|
|
4461
4683
|
const found = provideAnswer(callId, answer ?? "", skip ?? false);
|
|
4462
4684
|
if (!found) {
|
|
4463
4685
|
return res.status(404).json({ error: "No pending question with that ID" });
|
|
@@ -4485,8 +4707,8 @@ async function createServerHandle(config4) {
|
|
|
4485
4707
|
if (!session) {
|
|
4486
4708
|
return res.status(404).json({ error: "Session not found" });
|
|
4487
4709
|
}
|
|
4488
|
-
const { getSetting, SETTINGS_KEYS } = await import("./settings-
|
|
4489
|
-
if (
|
|
4710
|
+
const { getSetting: getSetting2, SETTINGS_KEYS } = await import("./settings-2TQA7VTP.js");
|
|
4711
|
+
if (getSetting2(SETTINGS_KEYS.CACHE_WARMING) !== "true") {
|
|
4490
4712
|
return res.json({ success: false, reason: "disabled" });
|
|
4491
4713
|
}
|
|
4492
4714
|
if (session.messages.length > 0) {
|
|
@@ -4517,7 +4739,7 @@ async function createServerHandle(config4) {
|
|
|
4517
4739
|
backend: activeProvider?.backend ?? llmClient.getBackend(),
|
|
4518
4740
|
model: llmClient.getModel()
|
|
4519
4741
|
};
|
|
4520
|
-
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-
|
|
4742
|
+
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-PIZJ42J2.js");
|
|
4521
4743
|
runAgentTurn(
|
|
4522
4744
|
{
|
|
4523
4745
|
sessionManager,
|
|
@@ -4555,8 +4777,8 @@ async function createServerHandle(config4) {
|
|
|
4555
4777
|
if (!session) {
|
|
4556
4778
|
return res.status(404).json({ error: "Session not found" });
|
|
4557
4779
|
}
|
|
4558
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
4559
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
4780
|
+
const { stopSessionExecution } = await import("./chat-handler-MBR6ZQTX.js");
|
|
4781
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-WGAZKL56.js");
|
|
4560
4782
|
const queuedMessages = sessionManager.getQueueState(sessionId);
|
|
4561
4783
|
sessionManager.clearMessageQueue(sessionId);
|
|
4562
4784
|
stopSessionExecution(sessionId, sessionManager);
|
|
@@ -4636,7 +4858,7 @@ async function createServerHandle(config4) {
|
|
|
4636
4858
|
res.json({ accepted: true });
|
|
4637
4859
|
});
|
|
4638
4860
|
app.get("/api/settings", async (req, res) => {
|
|
4639
|
-
const { getSetting, SETTINGS_DEFAULTS } = await import("./settings-
|
|
4861
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-2TQA7VTP.js");
|
|
4640
4862
|
const keysParam = req.query["keys"];
|
|
4641
4863
|
if (!keysParam) {
|
|
4642
4864
|
return res.status(400).json({ error: "keys query parameter is required" });
|
|
@@ -4644,30 +4866,30 @@ async function createServerHandle(config4) {
|
|
|
4644
4866
|
const keys = keysParam.split(",").map((k) => k.trim());
|
|
4645
4867
|
const result = {};
|
|
4646
4868
|
for (const key of keys) {
|
|
4647
|
-
result[key] =
|
|
4869
|
+
result[key] = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? "";
|
|
4648
4870
|
}
|
|
4649
4871
|
res.json(result);
|
|
4650
4872
|
});
|
|
4651
4873
|
app.get("/api/settings/:key", async (req, res) => {
|
|
4652
|
-
const { getSetting, SETTINGS_DEFAULTS } = await import("./settings-
|
|
4874
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-2TQA7VTP.js");
|
|
4653
4875
|
const key = req.params.key;
|
|
4654
|
-
const value =
|
|
4876
|
+
const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
|
|
4655
4877
|
res.json({ key, value });
|
|
4656
4878
|
});
|
|
4657
4879
|
app.get("/api/settings/:key", async (req, res) => {
|
|
4658
|
-
const { getSetting, SETTINGS_DEFAULTS } = await import("./settings-
|
|
4880
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-2TQA7VTP.js");
|
|
4659
4881
|
const key = req.params.key;
|
|
4660
|
-
const value =
|
|
4882
|
+
const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
|
|
4661
4883
|
res.json({ key, value });
|
|
4662
4884
|
});
|
|
4663
4885
|
app.put("/api/settings/:key", async (req, res) => {
|
|
4664
|
-
const { setSetting } = await import("./settings-
|
|
4886
|
+
const { setSetting: setSetting2 } = await import("./settings-2TQA7VTP.js");
|
|
4665
4887
|
const key = req.params.key;
|
|
4666
4888
|
const { value } = req.body;
|
|
4667
4889
|
if (value === void 0) {
|
|
4668
4890
|
return res.status(400).json({ error: "value is required" });
|
|
4669
4891
|
}
|
|
4670
|
-
|
|
4892
|
+
setSetting2(key, value);
|
|
4671
4893
|
res.json({ key, value });
|
|
4672
4894
|
});
|
|
4673
4895
|
app.get("/api/config", async (_req, res) => {
|
|
@@ -4676,8 +4898,8 @@ async function createServerHandle(config4) {
|
|
|
4676
4898
|
let visionFallback;
|
|
4677
4899
|
let globalWorkdir;
|
|
4678
4900
|
try {
|
|
4679
|
-
const { loadGlobalConfig, getVisionFallback } = await import("./config-
|
|
4680
|
-
const globalConfig = await loadGlobalConfig(
|
|
4901
|
+
const { loadGlobalConfig, getVisionFallback } = await import("./config-GMQUPNBY.js");
|
|
4902
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4681
4903
|
const fallback = getVisionFallback(globalConfig);
|
|
4682
4904
|
if (fallback) {
|
|
4683
4905
|
visionFallback = {
|
|
@@ -4695,13 +4917,13 @@ async function createServerHandle(config4) {
|
|
|
4695
4917
|
version: VERSION,
|
|
4696
4918
|
model: llmClient.getModel(),
|
|
4697
4919
|
maxContext: providerManager.getCurrentModelContext(),
|
|
4698
|
-
llmUrl: activeProvider?.url ??
|
|
4920
|
+
llmUrl: activeProvider?.url ?? config3.llm.baseUrl,
|
|
4699
4921
|
llmStatus: getLlmStatus(),
|
|
4700
4922
|
backend: llmClient.getBackend(),
|
|
4701
|
-
workdir: globalWorkdir ??
|
|
4923
|
+
workdir: globalWorkdir ?? config3.workdir,
|
|
4702
4924
|
providers: providerManager.getProviders(),
|
|
4703
4925
|
activeProviderId: providerManager.getActiveProviderId(),
|
|
4704
|
-
defaultModelSelection:
|
|
4926
|
+
defaultModelSelection: config3.defaultModelSelection,
|
|
4705
4927
|
visionFallback
|
|
4706
4928
|
});
|
|
4707
4929
|
});
|
|
@@ -4710,7 +4932,7 @@ async function createServerHandle(config4) {
|
|
|
4710
4932
|
const currentModel = providerManager.getCurrentModel();
|
|
4711
4933
|
if (currentModel === "auto") {
|
|
4712
4934
|
const activeProvider = providerManager.getActiveProvider();
|
|
4713
|
-
const baseUrl = activeProvider?.url ??
|
|
4935
|
+
const baseUrl = activeProvider?.url ?? config3.llm.baseUrl;
|
|
4714
4936
|
const detected = await detectModel(baseUrl);
|
|
4715
4937
|
if (detected) {
|
|
4716
4938
|
llmClient.setModel(detected);
|
|
@@ -4899,8 +5121,8 @@ async function createServerHandle(config4) {
|
|
|
4899
5121
|
return res.status(400).json({ error: "name, url, and backend are required" });
|
|
4900
5122
|
}
|
|
4901
5123
|
try {
|
|
4902
|
-
const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-
|
|
4903
|
-
const globalConfig = await loadGlobalConfig(
|
|
5124
|
+
const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-GMQUPNBY.js");
|
|
5125
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4904
5126
|
const providerBackend = backend;
|
|
4905
5127
|
const providerModels = modelConfigs?.length ? buildModelConfigs(modelConfigs) : model ? [{ id: model, contextWindow: 2e5, source: "user" }] : [];
|
|
4906
5128
|
const configWithProvider = addProvider(globalConfig, {
|
|
@@ -4919,9 +5141,9 @@ async function createServerHandle(config4) {
|
|
|
4919
5141
|
configWithProvider.providers[configWithProvider.providers.length - 1].id,
|
|
4920
5142
|
firstModelId
|
|
4921
5143
|
);
|
|
4922
|
-
await saveGlobalConfig(
|
|
5144
|
+
await saveGlobalConfig(config3.mode ?? "production", finalConfig, config3.globalConfigPath);
|
|
4923
5145
|
providerManager.setProviders(finalConfig.providers, finalConfig.defaultModelSelection ?? void 0);
|
|
4924
|
-
|
|
5146
|
+
config3.defaultModelSelection = finalConfig.defaultModelSelection;
|
|
4925
5147
|
const newProvider = finalConfig.providers[finalConfig.providers.length - 1];
|
|
4926
5148
|
res.status(201).json({
|
|
4927
5149
|
success: true,
|
|
@@ -4937,14 +5159,14 @@ async function createServerHandle(config4) {
|
|
|
4937
5159
|
app.post("/api/init/config", async (req, res) => {
|
|
4938
5160
|
const { workdir, visionFallback } = req.body;
|
|
4939
5161
|
try {
|
|
4940
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
4941
|
-
const globalConfig = await loadGlobalConfig(
|
|
5162
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
5163
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4942
5164
|
const updatedConfig = {
|
|
4943
5165
|
...globalConfig,
|
|
4944
5166
|
workspace: workdir ? { workdir } : globalConfig.workspace,
|
|
4945
5167
|
visionFallback: visionFallback ?? globalConfig.visionFallback
|
|
4946
5168
|
};
|
|
4947
|
-
await saveGlobalConfig(
|
|
5169
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
4948
5170
|
res.json({ success: true });
|
|
4949
5171
|
} catch (error) {
|
|
4950
5172
|
res.status(500).json({
|
|
@@ -4965,20 +5187,20 @@ async function createServerHandle(config4) {
|
|
|
4965
5187
|
});
|
|
4966
5188
|
app.delete("/api/providers/:id", async (req, res) => {
|
|
4967
5189
|
const { id } = req.params;
|
|
4968
|
-
const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-
|
|
4969
|
-
const globalConfig = await loadGlobalConfig(
|
|
5190
|
+
const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-GMQUPNBY.js");
|
|
5191
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4970
5192
|
const updatedConfig = removeProvider(globalConfig, id);
|
|
4971
|
-
await saveGlobalConfig(
|
|
5193
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
4972
5194
|
providerManager.setProviders(updatedConfig.providers, updatedConfig.defaultModelSelection ?? void 0);
|
|
4973
|
-
|
|
5195
|
+
config3.defaultModelSelection = updatedConfig.defaultModelSelection;
|
|
4974
5196
|
res.json({ success: true });
|
|
4975
5197
|
});
|
|
4976
5198
|
app.patch("/api/providers/:id", async (req, res) => {
|
|
4977
5199
|
const { id } = req.params;
|
|
4978
5200
|
const { isLocal } = req.body;
|
|
4979
5201
|
try {
|
|
4980
|
-
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-
|
|
4981
|
-
const globalConfig = await loadGlobalConfig(
|
|
5202
|
+
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-GMQUPNBY.js");
|
|
5203
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4982
5204
|
const provider = globalConfig.providers.find((p) => p.id === id);
|
|
4983
5205
|
if (!provider) {
|
|
4984
5206
|
return res.status(404).json({ error: "Provider not found" });
|
|
@@ -4986,9 +5208,9 @@ async function createServerHandle(config4) {
|
|
|
4986
5208
|
const updates = {};
|
|
4987
5209
|
if (isLocal !== void 0) updates["isLocal"] = isLocal;
|
|
4988
5210
|
const updatedConfig = updateProvider(globalConfig, id, updates);
|
|
4989
|
-
await saveGlobalConfig(
|
|
5211
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
4990
5212
|
providerManager.setProviders(updatedConfig.providers, updatedConfig.defaultModelSelection ?? void 0);
|
|
4991
|
-
|
|
5213
|
+
config3.defaultModelSelection = updatedConfig.defaultModelSelection;
|
|
4992
5214
|
res.json({ success: true, provider: updatedConfig.providers.find((p) => p.id === id) });
|
|
4993
5215
|
} catch (error) {
|
|
4994
5216
|
res.status(500).json({ error: error instanceof Error ? error.message : "Failed to update provider" });
|
|
@@ -5006,8 +5228,8 @@ async function createServerHandle(config4) {
|
|
|
5006
5228
|
models: modelConfigs
|
|
5007
5229
|
} = req.body;
|
|
5008
5230
|
try {
|
|
5009
|
-
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-
|
|
5010
|
-
const globalConfig = await loadGlobalConfig(
|
|
5231
|
+
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-GMQUPNBY.js");
|
|
5232
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5011
5233
|
const provider = globalConfig.providers.find((p) => p.id === id);
|
|
5012
5234
|
if (!provider) {
|
|
5013
5235
|
return res.status(404).json({ error: "Provider not found" });
|
|
@@ -5023,9 +5245,9 @@ async function createServerHandle(config4) {
|
|
|
5023
5245
|
updates["models"] = buildModelConfigs(modelConfigs);
|
|
5024
5246
|
}
|
|
5025
5247
|
const updatedConfig = updateProvider(globalConfig, id, updates);
|
|
5026
|
-
await saveGlobalConfig(
|
|
5248
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
5027
5249
|
providerManager.setProviders(updatedConfig.providers, updatedConfig.defaultModelSelection ?? void 0);
|
|
5028
|
-
|
|
5250
|
+
config3.defaultModelSelection = updatedConfig.defaultModelSelection;
|
|
5029
5251
|
res.json({ success: true, provider: updatedConfig.providers.find((p) => p.id === id) });
|
|
5030
5252
|
} catch (error) {
|
|
5031
5253
|
res.status(500).json({ error: error instanceof Error ? error.message : "Failed to update provider" });
|
|
@@ -5044,10 +5266,10 @@ async function createServerHandle(config4) {
|
|
|
5044
5266
|
return res.status(400).json({ error: result.error });
|
|
5045
5267
|
}
|
|
5046
5268
|
const llmClient = getLLMClient();
|
|
5047
|
-
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-
|
|
5048
|
-
const globalConfig = await loadGlobalConfig(
|
|
5269
|
+
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-GMQUPNBY.js");
|
|
5270
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5049
5271
|
const updatedConfig = setDefaultModelSelection(globalConfig, id, llmClient.getModel());
|
|
5050
|
-
await saveGlobalConfig(
|
|
5272
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
5051
5273
|
res.json({
|
|
5052
5274
|
success: true,
|
|
5053
5275
|
activeProviderId: id,
|
|
@@ -5071,7 +5293,7 @@ async function createServerHandle(config4) {
|
|
|
5071
5293
|
});
|
|
5072
5294
|
async function rebuildMcpTools() {
|
|
5073
5295
|
const { createMcpTools: createMcpTools2 } = await import("./tool-adapter-MOGEI6TP.js");
|
|
5074
|
-
const { setMcpTools: setMcpTools2 } = await import("./tools-
|
|
5296
|
+
const { setMcpTools: setMcpTools2 } = await import("./tools-WGAZKL56.js");
|
|
5075
5297
|
const mcpTools = createMcpTools2(mcpManager);
|
|
5076
5298
|
setMcpTools2(mcpTools);
|
|
5077
5299
|
}
|
|
@@ -5133,13 +5355,17 @@ async function createServerHandle(config4) {
|
|
|
5133
5355
|
};
|
|
5134
5356
|
await mcpManager.addServer(name, serverCfg);
|
|
5135
5357
|
const server = mcpManager.getServer(name);
|
|
5136
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
5137
|
-
const globalConfig = await loadGlobalConfig(
|
|
5358
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
5359
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5138
5360
|
const updatedMcpServers = { ...globalConfig.mcpServers ?? {}, [name]: serverCfg };
|
|
5139
|
-
await saveGlobalConfig(
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5361
|
+
await saveGlobalConfig(
|
|
5362
|
+
config3.mode ?? "production",
|
|
5363
|
+
{
|
|
5364
|
+
...globalConfig,
|
|
5365
|
+
mcpServers: updatedMcpServers
|
|
5366
|
+
},
|
|
5367
|
+
config3.globalConfigPath
|
|
5368
|
+
);
|
|
5143
5369
|
await rebuildMcpTools();
|
|
5144
5370
|
if (server) {
|
|
5145
5371
|
const sessions = sessionManager.listSessions();
|
|
@@ -5159,14 +5385,18 @@ async function createServerHandle(config4) {
|
|
|
5159
5385
|
return res.status(404).json({ error: `MCP server '${name}' not found` });
|
|
5160
5386
|
}
|
|
5161
5387
|
mcpManager.removeServer(name);
|
|
5162
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
5163
|
-
const globalConfig = await loadGlobalConfig(
|
|
5388
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
5389
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5164
5390
|
const updatedMcpServers = { ...globalConfig.mcpServers ?? {} };
|
|
5165
5391
|
delete updatedMcpServers[name];
|
|
5166
|
-
await saveGlobalConfig(
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5392
|
+
await saveGlobalConfig(
|
|
5393
|
+
config3.mode ?? "production",
|
|
5394
|
+
{
|
|
5395
|
+
...globalConfig,
|
|
5396
|
+
mcpServers: updatedMcpServers
|
|
5397
|
+
},
|
|
5398
|
+
config3.globalConfigPath
|
|
5399
|
+
);
|
|
5170
5400
|
await rebuildMcpTools();
|
|
5171
5401
|
const sessions = sessionManager.listSessions();
|
|
5172
5402
|
for (const s of sessions) {
|
|
@@ -5184,18 +5414,22 @@ async function createServerHandle(config4) {
|
|
|
5184
5414
|
await mcpManager.setToolEnabled(name, toolName, enabled);
|
|
5185
5415
|
const server = mcpManager.getServer(name);
|
|
5186
5416
|
if (server) {
|
|
5187
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
5188
|
-
const globalConfig = await loadGlobalConfig(
|
|
5417
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
5418
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5189
5419
|
const mcpServers2 = { ...globalConfig.mcpServers ?? {} };
|
|
5190
5420
|
const serverCfg = mcpServers2[name];
|
|
5191
5421
|
if (serverCfg) {
|
|
5192
5422
|
const disabledTools = server.tools.filter((t) => !t.enabled).map((t) => t.name);
|
|
5193
5423
|
const cfg = { ...serverCfg, ...disabledTools.length > 0 ? { disabledTools } : { disabledTools: void 0 } };
|
|
5194
5424
|
mcpServers2[name] = cfg;
|
|
5195
|
-
await saveGlobalConfig(
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5425
|
+
await saveGlobalConfig(
|
|
5426
|
+
config3.mode ?? "production",
|
|
5427
|
+
{
|
|
5428
|
+
...globalConfig,
|
|
5429
|
+
mcpServers: mcpServers2
|
|
5430
|
+
},
|
|
5431
|
+
config3.globalConfigPath
|
|
5432
|
+
);
|
|
5199
5433
|
}
|
|
5200
5434
|
}
|
|
5201
5435
|
await rebuildMcpTools();
|
|
@@ -5208,11 +5442,11 @@ async function createServerHandle(config4) {
|
|
|
5208
5442
|
res.status(400).json({ error: error instanceof Error ? error.message : String(error) });
|
|
5209
5443
|
}
|
|
5210
5444
|
});
|
|
5211
|
-
const projectDir =
|
|
5445
|
+
const projectDir = config3.workdir;
|
|
5212
5446
|
app.use("/api/skills", createSkillRoutes(configDir, projectDir));
|
|
5213
5447
|
app.use("/api/commands", createCommandRoutes(configDir, projectDir));
|
|
5214
5448
|
app.use("/api/agents", createAgentRoutes(configDir, projectDir));
|
|
5215
|
-
app.use("/api/workflows", createWorkflowRoutes(configDir,
|
|
5449
|
+
app.use("/api/workflows", createWorkflowRoutes(configDir, config3, projectDir));
|
|
5216
5450
|
app.use("/api/dev-server", createDevServerRoutes());
|
|
5217
5451
|
app.use("/api/terminals", createTerminalRoutes());
|
|
5218
5452
|
app.use(
|
|
@@ -5230,13 +5464,13 @@ async function createServerHandle(config4) {
|
|
|
5230
5464
|
})
|
|
5231
5465
|
);
|
|
5232
5466
|
app.get("/api/sessions/:id/background-processes", async (req, res) => {
|
|
5233
|
-
const { getSessionProcesses } = await import("./manager-
|
|
5467
|
+
const { getSessionProcesses } = await import("./manager-344C5JLZ.js");
|
|
5234
5468
|
const sessionId = req.params.id;
|
|
5235
5469
|
const processes = getSessionProcesses(sessionId);
|
|
5236
5470
|
res.json({ processes });
|
|
5237
5471
|
});
|
|
5238
5472
|
app.post("/api/sessions/:id/background-process/:processId/stop", async (req, res) => {
|
|
5239
|
-
const { stopProcess } = await import("./manager-
|
|
5473
|
+
const { stopProcess } = await import("./manager-344C5JLZ.js");
|
|
5240
5474
|
const sessionId = req.params.id;
|
|
5241
5475
|
const processId = req.params.processId;
|
|
5242
5476
|
const session = sessionManager.getSession(sessionId);
|
|
@@ -5250,20 +5484,20 @@ async function createServerHandle(config4) {
|
|
|
5250
5484
|
res.status(500).json({ error: err instanceof Error ? err.message : "Failed to stop process" });
|
|
5251
5485
|
}
|
|
5252
5486
|
});
|
|
5253
|
-
const { getCurrentBranch } = await import("./branch.api-
|
|
5487
|
+
const { getCurrentBranch } = await import("./branch.api-LAN42BA5.js");
|
|
5254
5488
|
app.get("/api/branch", async (req, res) => {
|
|
5255
5489
|
await getCurrentBranch(req, res);
|
|
5256
5490
|
});
|
|
5257
5491
|
app.use("/api/directories", createDirectoryRoutes());
|
|
5258
5492
|
app.use("/api/files", createFileSearchRoutes());
|
|
5259
|
-
const webDir =
|
|
5260
|
-
const isDev =
|
|
5493
|
+
const webDir = resolve4(__dirname3, "../../web");
|
|
5494
|
+
const isDev = config3.mode === "development";
|
|
5261
5495
|
let viteServer;
|
|
5262
5496
|
if (isDev) {
|
|
5263
5497
|
logger.info("Dev mode: using Vite middleware");
|
|
5264
5498
|
viteServer = await createViteServer({
|
|
5265
5499
|
root: webDir,
|
|
5266
|
-
configFile:
|
|
5500
|
+
configFile: resolve4(__dirname3, "../../web/vite.config.ts"),
|
|
5267
5501
|
server: { middlewareMode: true },
|
|
5268
5502
|
appType: "spa",
|
|
5269
5503
|
logLevel: "warn"
|
|
@@ -5283,7 +5517,7 @@ async function createServerHandle(config4) {
|
|
|
5283
5517
|
}
|
|
5284
5518
|
});
|
|
5285
5519
|
app.get("/fox.svg", (_req, res) => {
|
|
5286
|
-
|
|
5520
|
+
readFile2(join7(webDir, "fox.svg")).then((content) => {
|
|
5287
5521
|
res.set("Content-Type", "image/svg+xml");
|
|
5288
5522
|
res.send(content);
|
|
5289
5523
|
}).catch(() => {
|
|
@@ -5292,7 +5526,7 @@ async function createServerHandle(config4) {
|
|
|
5292
5526
|
});
|
|
5293
5527
|
app.use(
|
|
5294
5528
|
"/sounds",
|
|
5295
|
-
express.static(
|
|
5529
|
+
express.static(join7(webDir, "public", "sounds"), {
|
|
5296
5530
|
setHeaders: (res) => {
|
|
5297
5531
|
res.set("Content-Type", "audio/mpeg");
|
|
5298
5532
|
}
|
|
@@ -5301,24 +5535,24 @@ async function createServerHandle(config4) {
|
|
|
5301
5535
|
app.use("/__inspect__.js", (_req, res) => {
|
|
5302
5536
|
res.set("Access-Control-Allow-Origin", "*");
|
|
5303
5537
|
res.set("Content-Type", "application/javascript");
|
|
5304
|
-
|
|
5538
|
+
readFile2(join7(webDir, "public", "__inspect__.js")).then((content) => res.send(content)).catch(() => res.status(404).send("Not found"));
|
|
5305
5539
|
});
|
|
5306
5540
|
app.get("/*path", (req, res) => {
|
|
5307
5541
|
if (req.path.startsWith("/api/")) {
|
|
5308
5542
|
return;
|
|
5309
5543
|
}
|
|
5310
|
-
|
|
5544
|
+
readFile2(join7(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
|
|
5311
5545
|
logger.error("Error serving index.html", { error: err });
|
|
5312
5546
|
res.status(500).send("Server error");
|
|
5313
5547
|
});
|
|
5314
5548
|
});
|
|
5315
|
-
logger.info("Vite middleware ready", { port:
|
|
5549
|
+
logger.info("Vite middleware ready", { port: config3.server.port });
|
|
5316
5550
|
}
|
|
5317
5551
|
if (!isDev) {
|
|
5318
|
-
const distWebDir =
|
|
5552
|
+
const distWebDir = resolve4(__dirname3, "web");
|
|
5319
5553
|
app.use(
|
|
5320
5554
|
"/assets",
|
|
5321
|
-
express.static(
|
|
5555
|
+
express.static(join7(distWebDir, "assets"), {
|
|
5322
5556
|
setHeaders: (res, filepath) => {
|
|
5323
5557
|
if (filepath.endsWith(".css")) {
|
|
5324
5558
|
res.set("Content-Type", "text/css");
|
|
@@ -5326,11 +5560,11 @@ async function createServerHandle(config4) {
|
|
|
5326
5560
|
}
|
|
5327
5561
|
})
|
|
5328
5562
|
);
|
|
5329
|
-
app.use("/manifest.webmanifest", express.static(
|
|
5330
|
-
app.use("/registerSW.js", express.static(
|
|
5331
|
-
app.use("/sw.js", express.static(
|
|
5563
|
+
app.use("/manifest.webmanifest", express.static(join7(distWebDir, "manifest.webmanifest")));
|
|
5564
|
+
app.use("/registerSW.js", express.static(join7(distWebDir, "registerSW.js")));
|
|
5565
|
+
app.use("/sw.js", express.static(join7(distWebDir, "sw.js")));
|
|
5332
5566
|
app.get("/fox.svg", (_req, res) => {
|
|
5333
|
-
|
|
5567
|
+
readFile2(join7(distWebDir, "fox.svg")).then((content) => {
|
|
5334
5568
|
res.set("Content-Type", "image/svg+xml");
|
|
5335
5569
|
res.send(content);
|
|
5336
5570
|
}).catch(() => {
|
|
@@ -5339,7 +5573,7 @@ async function createServerHandle(config4) {
|
|
|
5339
5573
|
});
|
|
5340
5574
|
app.use(
|
|
5341
5575
|
"/sounds",
|
|
5342
|
-
express.static(
|
|
5576
|
+
express.static(join7(distWebDir, "sounds"), {
|
|
5343
5577
|
setHeaders: (res) => {
|
|
5344
5578
|
res.set("Content-Type", "audio/mpeg");
|
|
5345
5579
|
}
|
|
@@ -5348,10 +5582,10 @@ async function createServerHandle(config4) {
|
|
|
5348
5582
|
app.use("/__inspect__.js", (_req, res) => {
|
|
5349
5583
|
res.set("Access-Control-Allow-Origin", "*");
|
|
5350
5584
|
res.set("Content-Type", "application/javascript");
|
|
5351
|
-
|
|
5585
|
+
readFile2(join7(distWebDir, "__inspect__.js")).then((content) => res.send(content)).catch(() => res.status(404).send("Not found"));
|
|
5352
5586
|
});
|
|
5353
5587
|
app.get("/", (_req, res) => {
|
|
5354
|
-
|
|
5588
|
+
readFile2(join7(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
5355
5589
|
res.status(404).send("Web UI not built. Run `npm run build:web`");
|
|
5356
5590
|
});
|
|
5357
5591
|
});
|
|
@@ -5359,7 +5593,7 @@ async function createServerHandle(config4) {
|
|
|
5359
5593
|
if (req.path.startsWith("/api/") || req.path.startsWith("/assets/") || req.path.startsWith("/sounds/") || req.path.startsWith("/manifest.webmanifest") || req.path.startsWith("/registerSW.js") || req.path.startsWith("/sw.js") || req.path === "/fox.svg") {
|
|
5360
5594
|
return;
|
|
5361
5595
|
}
|
|
5362
|
-
|
|
5596
|
+
readFile2(join7(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
5363
5597
|
res.status(404).send("Web UI not built");
|
|
5364
5598
|
});
|
|
5365
5599
|
});
|
|
@@ -5367,7 +5601,7 @@ async function createServerHandle(config4) {
|
|
|
5367
5601
|
const httpServer = createHttpServer(app);
|
|
5368
5602
|
const wssExports = createWebSocketServer(
|
|
5369
5603
|
httpServer,
|
|
5370
|
-
|
|
5604
|
+
config3,
|
|
5371
5605
|
getLLMClient,
|
|
5372
5606
|
() => providerManager.getActiveProvider(),
|
|
5373
5607
|
sessionManager,
|
|
@@ -5379,7 +5613,7 @@ async function createServerHandle(config4) {
|
|
|
5379
5613
|
const state = sessionManager.getContextState(sessionId);
|
|
5380
5614
|
wssExports.broadcastForSession(sessionId, createContextStateMessage(state));
|
|
5381
5615
|
});
|
|
5382
|
-
const { QueueProcessor } = await import("./processor-
|
|
5616
|
+
const { QueueProcessor } = await import("./processor-PKKTNKWY.js");
|
|
5383
5617
|
const queueProcessor = new QueueProcessor({
|
|
5384
5618
|
sessionManager,
|
|
5385
5619
|
providerManager,
|
|
@@ -5400,42 +5634,47 @@ async function createServerHandle(config4) {
|
|
|
5400
5634
|
};
|
|
5401
5635
|
return {
|
|
5402
5636
|
httpServer,
|
|
5403
|
-
ctx: { config:
|
|
5404
|
-
start: (port) => new Promise((
|
|
5405
|
-
const listenPort = port ??
|
|
5406
|
-
const host =
|
|
5637
|
+
ctx: { config: config3, sessionManager, llmClient: getLLMClient(), toolRegistry, providerManager },
|
|
5638
|
+
start: (port) => new Promise((resolve5, reject) => {
|
|
5639
|
+
const listenPort = port ?? config3.server.port;
|
|
5640
|
+
const host = config3.server.host;
|
|
5407
5641
|
httpServer.listen(listenPort, host, () => {
|
|
5408
5642
|
const addr = httpServer.address();
|
|
5409
5643
|
const actualPort = typeof addr === "object" && addr ? addr.port : listenPort;
|
|
5410
5644
|
const client = getLLMClient();
|
|
5411
5645
|
logger.info(`OpenFox server running at http://${host}:${actualPort}`);
|
|
5412
5646
|
logger.info(`WebSocket available at ws://${host}:${actualPort}/ws`);
|
|
5413
|
-
logger.info(`LLM backend: ${client.getBackend()}, model: ${client.getModel()}, url: ${
|
|
5414
|
-
|
|
5647
|
+
logger.info(`LLM backend: ${client.getBackend()}, model: ${client.getModel()}, url: ${config3.llm.baseUrl}`);
|
|
5648
|
+
resolve5({ port: actualPort });
|
|
5415
5649
|
});
|
|
5416
5650
|
httpServer.on("error", reject);
|
|
5417
5651
|
}),
|
|
5418
|
-
close: () => new Promise((
|
|
5652
|
+
close: () => new Promise((resolve5) => {
|
|
5419
5653
|
logger.info("Shutting down...");
|
|
5420
5654
|
void (async () => {
|
|
5421
5655
|
await devServerManager.stopAll();
|
|
5422
5656
|
await mcpManager.disconnectAll();
|
|
5423
5657
|
const { stopAllInspectProxies } = await import("./inspect-proxy-BV25JERQ.js");
|
|
5424
5658
|
stopAllInspectProxies();
|
|
5425
|
-
const { cleanupAllProcesses } = await import("./store-
|
|
5659
|
+
const { cleanupAllProcesses } = await import("./store-FXTCHBI4.js");
|
|
5426
5660
|
cleanupAllProcesses();
|
|
5427
5661
|
viteServer?.close();
|
|
5662
|
+
if (config3.globalConfigPath) {
|
|
5663
|
+
const { unlink: unlink2 } = await import("fs/promises");
|
|
5664
|
+
unlink2(config3.globalConfigPath).catch(() => {
|
|
5665
|
+
});
|
|
5666
|
+
}
|
|
5428
5667
|
for (const client of wss.clients) {
|
|
5429
5668
|
client.terminate();
|
|
5430
5669
|
}
|
|
5431
5670
|
wss.close();
|
|
5432
|
-
httpServer.close(() =>
|
|
5671
|
+
httpServer.close(() => resolve5());
|
|
5433
5672
|
})();
|
|
5434
5673
|
})
|
|
5435
5674
|
};
|
|
5436
5675
|
}
|
|
5437
|
-
async function createServer(
|
|
5438
|
-
const handle = await createServerHandle(
|
|
5676
|
+
async function createServer(config3) {
|
|
5677
|
+
const handle = await createServerHandle(config3);
|
|
5439
5678
|
await handle.start();
|
|
5440
5679
|
const shutdown = () => {
|
|
5441
5680
|
const forceExitTimer = setTimeout(() => {
|
|
@@ -5454,4 +5693,4 @@ export {
|
|
|
5454
5693
|
createServerHandle,
|
|
5455
5694
|
createServer
|
|
5456
5695
|
};
|
|
5457
|
-
//# sourceMappingURL=chunk-
|
|
5696
|
+
//# sourceMappingURL=chunk-DEWNWF2P.js.map
|