openfox 2.0.59 → 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/{chat-handler-AS44EMQE.js → chat-handler-MBR6ZQTX.js} +4 -4
- package/dist/{chunk-FRU2X3IZ.js → chunk-3JRYK5UG.js} +265 -62
- package/dist/{chunk-LQFCQ6PY.js → chunk-DEWNWF2P.js} +469 -253
- package/dist/{chunk-5MDIKIMG.js → chunk-DOJKA4XO.js} +3 -3
- package/dist/{chunk-P7C6KF2H.js → chunk-MTBQQ5DN.js} +2 -2
- package/dist/{chunk-EKI5SZC7.js → chunk-NY6IGGKZ.js} +3 -3
- package/dist/{chunk-CDRQJDSJ.js → chunk-WNSAJCWT.js} +3 -2
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{orchestrator-MH7J2YVP.js → orchestrator-PIZJ42J2.js} +4 -4
- package/dist/package.json +4 -2
- package/dist/{processor-34MVJZTD.js → processor-PKKTNKWY.js} +4 -4
- package/dist/{serve-NHF6B5RQ.js → serve-GKS55Y2C.js} +6 -6
- package/dist/server/index.js +5 -5
- package/dist/{server-KDGQZNYQ.js → server-LMH7ZH5X.js} +5 -5
- package/dist/{settings-X43DCM55.js → settings-2TQA7VTP.js} +2 -2
- package/dist/skill-defaults/{browser.skill.md → browser/SKILL.md} +5 -3
- package/dist/{tools-FQ54IAYG.js → tools-WGAZKL56.js} +3 -3
- 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,
|
|
@@ -61,8 +63,10 @@ import {
|
|
|
61
63
|
setMcpManagerForTools,
|
|
62
64
|
setMcpTools,
|
|
63
65
|
setNotifyMcpServersChanged,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
setSkillEnabled,
|
|
67
|
+
skillExists,
|
|
68
|
+
updateOwnedSkill
|
|
69
|
+
} from "./chunk-3JRYK5UG.js";
|
|
66
70
|
import {
|
|
67
71
|
getPathSeparator,
|
|
68
72
|
isAbsolutePath
|
|
@@ -76,6 +80,11 @@ import {
|
|
|
76
80
|
import {
|
|
77
81
|
EventEmitter
|
|
78
82
|
} from "./chunk-EU3WWTFH.js";
|
|
83
|
+
import {
|
|
84
|
+
deleteSetting,
|
|
85
|
+
getSetting,
|
|
86
|
+
setSetting
|
|
87
|
+
} from "./chunk-WNSAJCWT.js";
|
|
79
88
|
import {
|
|
80
89
|
getProject
|
|
81
90
|
} from "./chunk-YQ3SOPBI.js";
|
|
@@ -150,8 +159,8 @@ import express from "express";
|
|
|
150
159
|
import cors from "cors";
|
|
151
160
|
import { createServer as createHttpServer } from "http";
|
|
152
161
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
153
|
-
import { dirname as
|
|
154
|
-
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";
|
|
155
164
|
import { createServer as createViteServer } from "vite";
|
|
156
165
|
|
|
157
166
|
// src/server/llm/mock.ts
|
|
@@ -1426,12 +1435,12 @@ var McpManager = class {
|
|
|
1426
1435
|
this.onServersChanged = options?.onServersChanged;
|
|
1427
1436
|
this.onToolsDiscovered = options?.onToolsDiscovered;
|
|
1428
1437
|
}
|
|
1429
|
-
async addServer(name,
|
|
1438
|
+
async addServer(name, config3) {
|
|
1430
1439
|
if (this.servers.has(name)) {
|
|
1431
1440
|
throw new Error(`MCP server '${name}' already exists`);
|
|
1432
1441
|
}
|
|
1433
|
-
const state = { name, config:
|
|
1434
|
-
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 });
|
|
1435
1444
|
await this.connectServer(name);
|
|
1436
1445
|
}
|
|
1437
1446
|
removeServer(name) {
|
|
@@ -1678,10 +1687,10 @@ var LspServer = class {
|
|
|
1678
1687
|
// Pending diagnostic waiters
|
|
1679
1688
|
pendingDiagnostics = /* @__PURE__ */ new Map();
|
|
1680
1689
|
commandPath;
|
|
1681
|
-
constructor(
|
|
1682
|
-
this.config =
|
|
1690
|
+
constructor(config3, workdir, commandPath) {
|
|
1691
|
+
this.config = config3;
|
|
1683
1692
|
this.workdir = workdir;
|
|
1684
|
-
this.commandPath = commandPath ??
|
|
1693
|
+
this.commandPath = commandPath ?? config3.serverCommand;
|
|
1685
1694
|
}
|
|
1686
1695
|
// ============================================================================
|
|
1687
1696
|
// Lifecycle
|
|
@@ -1914,19 +1923,19 @@ var LspServer = class {
|
|
|
1914
1923
|
*/
|
|
1915
1924
|
async getDiagnosticsWithWait(path, timeoutMs = DIAGNOSTIC_WAIT_MS) {
|
|
1916
1925
|
if (this.openDocuments.has(path)) {
|
|
1917
|
-
return new Promise((
|
|
1926
|
+
return new Promise((resolve5) => {
|
|
1918
1927
|
const existing = this.diagnostics.get(path);
|
|
1919
1928
|
if (existing !== void 0) {
|
|
1920
1929
|
setTimeout(() => {
|
|
1921
|
-
|
|
1930
|
+
resolve5(this.diagnostics.get(path) ?? []);
|
|
1922
1931
|
}, 100);
|
|
1923
1932
|
return;
|
|
1924
1933
|
}
|
|
1925
1934
|
const timeout = setTimeout(() => {
|
|
1926
1935
|
this.pendingDiagnostics.delete(path);
|
|
1927
|
-
|
|
1936
|
+
resolve5(this.diagnostics.get(path) ?? []);
|
|
1928
1937
|
}, timeoutMs);
|
|
1929
|
-
this.pendingDiagnostics.set(path, { resolve:
|
|
1938
|
+
this.pendingDiagnostics.set(path, { resolve: resolve5, timeout });
|
|
1930
1939
|
});
|
|
1931
1940
|
}
|
|
1932
1941
|
return this.diagnostics.get(path) ?? [];
|
|
@@ -2238,8 +2247,8 @@ var LspManager = class {
|
|
|
2238
2247
|
// ============================================================================
|
|
2239
2248
|
// Server Management
|
|
2240
2249
|
// ============================================================================
|
|
2241
|
-
async getOrCreateServer(
|
|
2242
|
-
const langId =
|
|
2250
|
+
async getOrCreateServer(config3) {
|
|
2251
|
+
const langId = config3.id;
|
|
2243
2252
|
const existing = this.servers.get(langId);
|
|
2244
2253
|
if (existing?.isRunning()) {
|
|
2245
2254
|
return existing;
|
|
@@ -2251,7 +2260,7 @@ var LspManager = class {
|
|
|
2251
2260
|
if (pending) {
|
|
2252
2261
|
return pending;
|
|
2253
2262
|
}
|
|
2254
|
-
const promise = this.startServer(
|
|
2263
|
+
const promise = this.startServer(config3);
|
|
2255
2264
|
this.serverPromises.set(langId, promise);
|
|
2256
2265
|
try {
|
|
2257
2266
|
const server = await promise;
|
|
@@ -2260,19 +2269,19 @@ var LspManager = class {
|
|
|
2260
2269
|
this.serverPromises.delete(langId);
|
|
2261
2270
|
}
|
|
2262
2271
|
}
|
|
2263
|
-
async startServer(
|
|
2264
|
-
const langId =
|
|
2265
|
-
const commandPath = await which(
|
|
2272
|
+
async startServer(config3) {
|
|
2273
|
+
const langId = config3.id;
|
|
2274
|
+
const commandPath = await which(config3.serverCommand, this.workdir);
|
|
2266
2275
|
if (!commandPath) {
|
|
2267
2276
|
logger.warn("LSP server not installed, skipping", {
|
|
2268
2277
|
language: langId,
|
|
2269
|
-
command:
|
|
2278
|
+
command: config3.serverCommand,
|
|
2270
2279
|
sessionId: this.sessionId
|
|
2271
2280
|
});
|
|
2272
2281
|
this.unavailableServers.add(langId);
|
|
2273
2282
|
return null;
|
|
2274
2283
|
}
|
|
2275
|
-
const server = new LspServer(
|
|
2284
|
+
const server = new LspServer(config3, this.workdir, commandPath);
|
|
2276
2285
|
try {
|
|
2277
2286
|
await server.start();
|
|
2278
2287
|
this.servers.set(langId, server);
|
|
@@ -2292,11 +2301,11 @@ var LspManager = class {
|
|
|
2292
2301
|
}
|
|
2293
2302
|
}
|
|
2294
2303
|
async getServerForFile(path) {
|
|
2295
|
-
const
|
|
2296
|
-
if (!
|
|
2304
|
+
const config3 = detectLanguage(path);
|
|
2305
|
+
if (!config3) {
|
|
2297
2306
|
return null;
|
|
2298
2307
|
}
|
|
2299
|
-
return this.getOrCreateServer(
|
|
2308
|
+
return this.getOrCreateServer(config3);
|
|
2300
2309
|
}
|
|
2301
2310
|
// ============================================================================
|
|
2302
2311
|
// Public Interface
|
|
@@ -2327,11 +2336,11 @@ var LspManager = class {
|
|
|
2327
2336
|
* Get current diagnostics for a file without triggering a change.
|
|
2328
2337
|
*/
|
|
2329
2338
|
getDiagnostics(path) {
|
|
2330
|
-
const
|
|
2331
|
-
if (!
|
|
2339
|
+
const config3 = detectLanguage(path);
|
|
2340
|
+
if (!config3) {
|
|
2332
2341
|
return [];
|
|
2333
2342
|
}
|
|
2334
|
-
const server = this.servers.get(
|
|
2343
|
+
const server = this.servers.get(config3.id);
|
|
2335
2344
|
if (!server?.isRunning()) {
|
|
2336
2345
|
return [];
|
|
2337
2346
|
}
|
|
@@ -2342,11 +2351,11 @@ var LspManager = class {
|
|
|
2342
2351
|
* Returns true if we have or can start a server for this file type.
|
|
2343
2352
|
*/
|
|
2344
2353
|
isAvailableFor(path) {
|
|
2345
|
-
const
|
|
2346
|
-
if (!
|
|
2354
|
+
const config3 = detectLanguage(path);
|
|
2355
|
+
if (!config3) {
|
|
2347
2356
|
return false;
|
|
2348
2357
|
}
|
|
2349
|
-
if (this.unavailableServers.has(
|
|
2358
|
+
if (this.unavailableServers.has(config3.id)) {
|
|
2350
2359
|
return false;
|
|
2351
2360
|
}
|
|
2352
2361
|
return true;
|
|
@@ -2357,13 +2366,13 @@ var LspManager = class {
|
|
|
2357
2366
|
* to avoid spamming the user on every edit.
|
|
2358
2367
|
*/
|
|
2359
2368
|
getInstallHint(path) {
|
|
2360
|
-
const
|
|
2361
|
-
if (!
|
|
2369
|
+
const config3 = detectLanguage(path);
|
|
2370
|
+
if (!config3?.installHint) {
|
|
2362
2371
|
return null;
|
|
2363
2372
|
}
|
|
2364
|
-
if (this.unavailableServers.has(
|
|
2365
|
-
this.dismissedHints.add(
|
|
2366
|
-
return
|
|
2373
|
+
if (this.unavailableServers.has(config3.id) && !this.dismissedHints.has(config3.id)) {
|
|
2374
|
+
this.dismissedHints.add(config3.id);
|
|
2375
|
+
return config3.installHint;
|
|
2367
2376
|
}
|
|
2368
2377
|
return null;
|
|
2369
2378
|
}
|
|
@@ -3243,9 +3252,77 @@ var SessionManager = class {
|
|
|
3243
3252
|
}
|
|
3244
3253
|
};
|
|
3245
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
|
+
|
|
3246
3323
|
// src/server/routes/crud-helpers.ts
|
|
3247
3324
|
import { Router } from "express";
|
|
3248
|
-
import { join as
|
|
3325
|
+
import { join as join3 } from "path";
|
|
3249
3326
|
function computeOverrideIds(defaults, userItems) {
|
|
3250
3327
|
return userItems.filter((u) => defaults.some((d) => d.metadata.id === u.metadata.id)).map((u) => u.metadata.id);
|
|
3251
3328
|
}
|
|
@@ -3257,34 +3334,34 @@ function validateNameIdPrompt(body) {
|
|
|
3257
3334
|
return null;
|
|
3258
3335
|
}
|
|
3259
3336
|
function getProjectItemPath(projectDir, dirName, id, ext) {
|
|
3260
|
-
return
|
|
3337
|
+
return join3(projectDir, ".openfox", dirName, `${id}${ext}`);
|
|
3261
3338
|
}
|
|
3262
3339
|
async function isProjectItem(projectDir, dirName, id, ext) {
|
|
3263
3340
|
if (!projectDir) return false;
|
|
3264
3341
|
return pathExists(getProjectItemPath(projectDir, dirName, id, ext));
|
|
3265
3342
|
}
|
|
3266
|
-
function createCrudRoutes(
|
|
3343
|
+
function createCrudRoutes(config3, configDir, projectDir) {
|
|
3267
3344
|
const router = Router();
|
|
3268
3345
|
router.get("/", async (_req, res) => {
|
|
3269
3346
|
const [defaults, userItems, projectItems] = await Promise.all([
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
projectDir ?
|
|
3347
|
+
config3.loadDefaults(),
|
|
3348
|
+
config3.loadUser(configDir),
|
|
3349
|
+
projectDir ? config3.loadProject(projectDir) : []
|
|
3273
3350
|
]);
|
|
3274
3351
|
const userOverrideIds = computeOverrideIds(defaults, userItems);
|
|
3275
3352
|
const projectOverrideIds = computeOverrideIds(defaults, projectItems);
|
|
3276
|
-
const extra =
|
|
3353
|
+
const extra = config3.extraGetData ? await config3.extraGetData() : {};
|
|
3277
3354
|
res.json({
|
|
3278
|
-
defaults: defaults.map(
|
|
3279
|
-
userItems: userItems.map(
|
|
3280
|
-
projectItems: projectItems.map(
|
|
3355
|
+
defaults: defaults.map(config3.mapToResponse),
|
|
3356
|
+
userItems: userItems.map(config3.mapToResponse),
|
|
3357
|
+
projectItems: projectItems.map(config3.mapToResponse),
|
|
3281
3358
|
overrideIds: [...userOverrideIds, ...projectOverrideIds],
|
|
3282
3359
|
...extra
|
|
3283
3360
|
});
|
|
3284
3361
|
});
|
|
3285
3362
|
router.get("/defaults/:id", async (req, res) => {
|
|
3286
3363
|
const { id } = req.params;
|
|
3287
|
-
const allDefaults = await
|
|
3364
|
+
const allDefaults = await config3.loadDefaults();
|
|
3288
3365
|
const item = allDefaults.find((d) => d.metadata.id === id);
|
|
3289
3366
|
if (!item) {
|
|
3290
3367
|
return res.status(404).json({ error: "Default not found" });
|
|
@@ -3292,13 +3369,13 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3292
3369
|
res.json(item);
|
|
3293
3370
|
});
|
|
3294
3371
|
router.get("/default-ids", async (_req, res) => {
|
|
3295
|
-
const ids =
|
|
3372
|
+
const ids = config3.getDefaultIds ? await config3.getDefaultIds() : [];
|
|
3296
3373
|
res.json({ ids });
|
|
3297
3374
|
});
|
|
3298
3375
|
router.get("/:id", async (req, res) => {
|
|
3299
3376
|
const { id } = req.params;
|
|
3300
|
-
const items = await
|
|
3301
|
-
const item =
|
|
3377
|
+
const items = await config3.loadAll(configDir, projectDir);
|
|
3378
|
+
const item = config3.findById(id, items);
|
|
3302
3379
|
if (!item) {
|
|
3303
3380
|
return res.status(404).json({ error: "Not found" });
|
|
3304
3381
|
}
|
|
@@ -3307,7 +3384,7 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3307
3384
|
router.post("/", async (req, res) => {
|
|
3308
3385
|
const body = req.body;
|
|
3309
3386
|
const meta = body["metadata"];
|
|
3310
|
-
const customError =
|
|
3387
|
+
const customError = config3.validateCreate?.(body);
|
|
3311
3388
|
if (!meta?.["id"] || customError) {
|
|
3312
3389
|
return res.status(400).json({ error: customError ?? "Missing required fields" });
|
|
3313
3390
|
}
|
|
@@ -3316,21 +3393,21 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3316
3393
|
if (destination === "project" && !projectDir) {
|
|
3317
3394
|
return res.status(400).json({ error: "No project directory configured" });
|
|
3318
3395
|
}
|
|
3319
|
-
const exists = await
|
|
3396
|
+
const exists = await config3.exists(configDir, id, projectDir);
|
|
3320
3397
|
if (exists) {
|
|
3321
3398
|
return res.status(409).json({ error: "An item with this ID already exists" });
|
|
3322
3399
|
}
|
|
3323
3400
|
if (destination === "project") {
|
|
3324
|
-
await
|
|
3401
|
+
await config3.saveToProject(projectDir, body);
|
|
3325
3402
|
} else {
|
|
3326
|
-
await
|
|
3403
|
+
await config3.save(configDir, body);
|
|
3327
3404
|
}
|
|
3328
3405
|
res.status(201).json(body);
|
|
3329
3406
|
});
|
|
3330
3407
|
router.put("/:id", async (req, res) => {
|
|
3331
3408
|
const { id } = req.params;
|
|
3332
|
-
const items = await
|
|
3333
|
-
const existing =
|
|
3409
|
+
const items = await config3.loadAll(configDir, projectDir);
|
|
3410
|
+
const existing = config3.findById(id, items);
|
|
3334
3411
|
if (!existing) {
|
|
3335
3412
|
return res.status(404).json({ error: "Not found" });
|
|
3336
3413
|
}
|
|
@@ -3341,29 +3418,29 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3341
3418
|
...body,
|
|
3342
3419
|
metadata: { ...existing.metadata, ...meta, id }
|
|
3343
3420
|
};
|
|
3344
|
-
const isProject = await isProjectItem(projectDir,
|
|
3421
|
+
const isProject = await isProjectItem(projectDir, config3.dirName, id, config3.ext);
|
|
3345
3422
|
if (isProject) {
|
|
3346
|
-
await
|
|
3423
|
+
await config3.saveToProject(projectDir, updated);
|
|
3347
3424
|
} else {
|
|
3348
|
-
await
|
|
3425
|
+
await config3.save(configDir, updated);
|
|
3349
3426
|
}
|
|
3350
3427
|
res.json(updated);
|
|
3351
3428
|
});
|
|
3352
3429
|
router.delete("/:id", async (req, res) => {
|
|
3353
3430
|
const { id } = req.params;
|
|
3354
|
-
const isProject = await isProjectItem(projectDir,
|
|
3431
|
+
const isProject = await isProjectItem(projectDir, config3.dirName, id, config3.ext);
|
|
3355
3432
|
if (isProject) {
|
|
3356
|
-
const result2 = await
|
|
3433
|
+
const result2 = await config3.deleteProject(projectDir, id);
|
|
3357
3434
|
if (!result2.success) {
|
|
3358
3435
|
return res.status(500).json({ error: "Failed to delete project item" });
|
|
3359
3436
|
}
|
|
3360
3437
|
return res.json({ success: true });
|
|
3361
3438
|
}
|
|
3362
|
-
const isDefault = await
|
|
3439
|
+
const isDefault = await config3.isDefault(id);
|
|
3363
3440
|
if (isDefault) {
|
|
3364
3441
|
return res.status(403).json({ error: "Cannot delete built-in defaults" });
|
|
3365
3442
|
}
|
|
3366
|
-
const result = await
|
|
3443
|
+
const result = await config3.delete(configDir, id);
|
|
3367
3444
|
if (!result.success) {
|
|
3368
3445
|
return res.status(403).json({ error: result.reason ?? "Cannot delete this item" });
|
|
3369
3446
|
}
|
|
@@ -3371,8 +3448,8 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3371
3448
|
});
|
|
3372
3449
|
router.post("/:id/duplicate", async (req, res) => {
|
|
3373
3450
|
const { id } = req.params;
|
|
3374
|
-
const items = await
|
|
3375
|
-
const source =
|
|
3451
|
+
const items = await config3.loadAll(configDir, projectDir);
|
|
3452
|
+
const source = config3.findById(id, items);
|
|
3376
3453
|
if (!source) {
|
|
3377
3454
|
return res.status(404).json({ error: "Not found" });
|
|
3378
3455
|
}
|
|
@@ -3384,56 +3461,195 @@ function createCrudRoutes(config4, configDir, projectDir) {
|
|
|
3384
3461
|
const destination = req.body.destination ?? "user";
|
|
3385
3462
|
if (destination === "project") {
|
|
3386
3463
|
if (!projectDir) return res.status(400).json({ error: "No project directory configured" });
|
|
3387
|
-
await
|
|
3464
|
+
await config3.saveToProject(projectDir, duplicated);
|
|
3388
3465
|
} else {
|
|
3389
|
-
await
|
|
3466
|
+
await config3.save(configDir, duplicated);
|
|
3390
3467
|
}
|
|
3391
3468
|
res.status(201).json(duplicated);
|
|
3392
3469
|
});
|
|
3393
|
-
|
|
3470
|
+
config3.extraRoutes?.(router);
|
|
3394
3471
|
return router;
|
|
3395
3472
|
}
|
|
3396
3473
|
|
|
3397
3474
|
// src/server/routes/skills.ts
|
|
3398
|
-
var
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
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
|
+
}
|
|
3419
3567
|
function createSkillRoutes(configDir, projectDir) {
|
|
3420
|
-
|
|
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;
|
|
3421
3637
|
}
|
|
3422
3638
|
|
|
3423
3639
|
// src/server/commands/registry.ts
|
|
3424
|
-
import { writeFile, mkdir, unlink } from "fs/promises";
|
|
3425
|
-
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";
|
|
3426
3642
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3427
|
-
import
|
|
3428
|
-
var __bundleDir =
|
|
3429
|
-
var DEFAULTS_DIR =
|
|
3430
|
-
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");
|
|
3431
3647
|
var COMMAND_EXTENSION = ".command.md";
|
|
3432
3648
|
function getCommandsDir(configDir) {
|
|
3433
|
-
return
|
|
3649
|
+
return join5(configDir, "commands");
|
|
3434
3650
|
}
|
|
3435
3651
|
function getProjectCommandsDir(projectDir) {
|
|
3436
|
-
return
|
|
3652
|
+
return join5(projectDir, ".openfox", "commands");
|
|
3437
3653
|
}
|
|
3438
3654
|
async function loadDefaultCommands() {
|
|
3439
3655
|
let defaults = await loadItemsFromDir(DEFAULTS_DIR, {
|
|
@@ -3490,26 +3706,26 @@ function findCommandById(commandId, commands) {
|
|
|
3490
3706
|
return commands.find((c) => c.metadata.id === commandId);
|
|
3491
3707
|
}
|
|
3492
3708
|
async function commandExists(configDir, commandId, projectDir) {
|
|
3493
|
-
if (await pathExists(
|
|
3494
|
-
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}`)))
|
|
3495
3711
|
return true;
|
|
3496
3712
|
return false;
|
|
3497
3713
|
}
|
|
3498
3714
|
async function saveCommand(configDir, command) {
|
|
3499
3715
|
const commandsDir = getCommandsDir(configDir);
|
|
3500
3716
|
if (!await pathExists(commandsDir)) {
|
|
3501
|
-
await
|
|
3717
|
+
await mkdir3(commandsDir, { recursive: true });
|
|
3502
3718
|
}
|
|
3503
|
-
const filePath =
|
|
3504
|
-
const content =
|
|
3505
|
-
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");
|
|
3506
3722
|
}
|
|
3507
3723
|
async function saveCommandToProject(projectDir, command) {
|
|
3508
3724
|
await saveItemToDir(
|
|
3509
3725
|
getProjectCommandsDir(projectDir),
|
|
3510
3726
|
command,
|
|
3511
3727
|
COMMAND_EXTENSION,
|
|
3512
|
-
(c) =>
|
|
3728
|
+
(c) => matter2.stringify(c.prompt, c.metadata)
|
|
3513
3729
|
);
|
|
3514
3730
|
}
|
|
3515
3731
|
async function deleteProjectCommand(projectDir, commandId) {
|
|
@@ -3520,7 +3736,7 @@ async function deleteCommand(configDir, commandId) {
|
|
|
3520
3736
|
if (isDefault) {
|
|
3521
3737
|
return { success: false, reason: "Cannot delete built-in defaults" };
|
|
3522
3738
|
}
|
|
3523
|
-
const filePath =
|
|
3739
|
+
const filePath = join5(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
|
|
3524
3740
|
try {
|
|
3525
3741
|
await unlink(filePath);
|
|
3526
3742
|
return { success: true };
|
|
@@ -3530,7 +3746,7 @@ async function deleteCommand(configDir, commandId) {
|
|
|
3530
3746
|
}
|
|
3531
3747
|
|
|
3532
3748
|
// src/server/routes/commands.ts
|
|
3533
|
-
var
|
|
3749
|
+
var config = {
|
|
3534
3750
|
dirName: "commands",
|
|
3535
3751
|
ext: ".command.md",
|
|
3536
3752
|
loadDefaults: loadDefaultCommands,
|
|
@@ -3549,11 +3765,11 @@ var config2 = {
|
|
|
3549
3765
|
mapToResponse: (c) => c.metadata
|
|
3550
3766
|
};
|
|
3551
3767
|
function createCommandRoutes(configDir, projectDir) {
|
|
3552
|
-
return createCrudRoutes(
|
|
3768
|
+
return createCrudRoutes(config, configDir, projectDir);
|
|
3553
3769
|
}
|
|
3554
3770
|
|
|
3555
3771
|
// src/server/routes/agents.ts
|
|
3556
|
-
var
|
|
3772
|
+
var config2 = {
|
|
3557
3773
|
dirName: "agents",
|
|
3558
3774
|
ext: ".agent.md",
|
|
3559
3775
|
loadDefaults: loadDefaultAgents,
|
|
@@ -3576,12 +3792,12 @@ var config3 = {
|
|
|
3576
3792
|
mapToResponse: (a) => a.metadata
|
|
3577
3793
|
};
|
|
3578
3794
|
function createAgentRoutes(configDir, projectDir) {
|
|
3579
|
-
return createCrudRoutes(
|
|
3795
|
+
return createCrudRoutes(config2, configDir, projectDir);
|
|
3580
3796
|
}
|
|
3581
3797
|
|
|
3582
3798
|
// src/server/routes/workflows.ts
|
|
3583
3799
|
import "express";
|
|
3584
|
-
function createWorkflowRoutes(configDir,
|
|
3800
|
+
function createWorkflowRoutes(configDir, config3, projectDir) {
|
|
3585
3801
|
const crudConfig = {
|
|
3586
3802
|
dirName: "workflows",
|
|
3587
3803
|
ext: ".workflow.json",
|
|
@@ -3610,7 +3826,7 @@ function createWorkflowRoutes(configDir, config4, projectDir) {
|
|
|
3610
3826
|
subGroups: subGroups.length > 0 ? subGroups : void 0
|
|
3611
3827
|
};
|
|
3612
3828
|
},
|
|
3613
|
-
extraGetData: () => Promise.resolve({ activeWorkflowId:
|
|
3829
|
+
extraGetData: () => Promise.resolve({ activeWorkflowId: config3.activeWorkflowId ?? "default" }),
|
|
3614
3830
|
extraRoutes: (router) => {
|
|
3615
3831
|
router.get("/template-variables", (_req, res) => {
|
|
3616
3832
|
res.json({ variables: TEMPLATE_VARIABLES });
|
|
@@ -3621,19 +3837,19 @@ function createWorkflowRoutes(configDir, config4, projectDir) {
|
|
|
3621
3837
|
}
|
|
3622
3838
|
|
|
3623
3839
|
// src/server/routes/dev-server.ts
|
|
3624
|
-
import { Router as
|
|
3840
|
+
import { Router as Router4 } from "express";
|
|
3625
3841
|
function createDevServerRoutes() {
|
|
3626
|
-
const router =
|
|
3842
|
+
const router = Router4();
|
|
3627
3843
|
router.get("/", async (req, res) => {
|
|
3628
3844
|
const workdir = req.query["workdir"];
|
|
3629
3845
|
if (!workdir) return res.status(400).json({ error: "workdir required" });
|
|
3630
3846
|
const status = devServerManager.getStatus(workdir);
|
|
3631
3847
|
if (!status.config) {
|
|
3632
|
-
const
|
|
3633
|
-
if (
|
|
3634
|
-
status.config =
|
|
3635
|
-
status.url =
|
|
3636
|
-
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;
|
|
3637
3853
|
}
|
|
3638
3854
|
}
|
|
3639
3855
|
res.json(status);
|
|
@@ -3679,8 +3895,8 @@ function createDevServerRoutes() {
|
|
|
3679
3895
|
router.get("/config", async (req, res) => {
|
|
3680
3896
|
const workdir = req.query["workdir"];
|
|
3681
3897
|
if (!workdir) return res.status(400).json({ error: "workdir required" });
|
|
3682
|
-
const
|
|
3683
|
-
res.json({ config:
|
|
3898
|
+
const config3 = await devServerManager.loadConfig(workdir);
|
|
3899
|
+
res.json({ config: config3 });
|
|
3684
3900
|
});
|
|
3685
3901
|
router.post("/config", async (req, res) => {
|
|
3686
3902
|
const workdir = req.query["workdir"];
|
|
@@ -3690,9 +3906,9 @@ function createDevServerRoutes() {
|
|
|
3690
3906
|
return res.status(400).json({ error: "command and url are required" });
|
|
3691
3907
|
}
|
|
3692
3908
|
try {
|
|
3693
|
-
const
|
|
3694
|
-
await devServerManager.saveConfig(workdir,
|
|
3695
|
-
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 });
|
|
3696
3912
|
} catch (err) {
|
|
3697
3913
|
res.status(500).json({ error: err instanceof Error ? err.message : "Failed to save config" });
|
|
3698
3914
|
}
|
|
@@ -3701,9 +3917,9 @@ function createDevServerRoutes() {
|
|
|
3701
3917
|
}
|
|
3702
3918
|
|
|
3703
3919
|
// src/server/routes/terminals.ts
|
|
3704
|
-
import { Router as
|
|
3920
|
+
import { Router as Router5 } from "express";
|
|
3705
3921
|
function createTerminalRoutes() {
|
|
3706
|
-
const router =
|
|
3922
|
+
const router = Router5();
|
|
3707
3923
|
router.get("/", (req, res) => {
|
|
3708
3924
|
const projectId = req.query["projectId"];
|
|
3709
3925
|
const sessions = projectId ? terminalManager.getByProject(projectId) : [];
|
|
@@ -3742,22 +3958,22 @@ function createTerminalRoutes() {
|
|
|
3742
3958
|
}
|
|
3743
3959
|
|
|
3744
3960
|
// src/server/routes/directories.ts
|
|
3745
|
-
import { Router as
|
|
3961
|
+
import { Router as Router6 } from "express";
|
|
3746
3962
|
import { readdir } from "fs/promises";
|
|
3747
|
-
import { resolve as
|
|
3963
|
+
import { resolve as resolve3, join as join6, dirname as dirname5, basename as basename2 } from "path";
|
|
3748
3964
|
function createDirectoryRoutes() {
|
|
3749
|
-
const router =
|
|
3965
|
+
const router = Router6();
|
|
3750
3966
|
const DEFAULT_BASE_PATH = process.cwd();
|
|
3751
3967
|
router.get("/", async (req, res) => {
|
|
3752
3968
|
const path = req.query["path"] || DEFAULT_BASE_PATH;
|
|
3753
3969
|
try {
|
|
3754
|
-
const resolvedPath =
|
|
3970
|
+
const resolvedPath = resolve3(path);
|
|
3755
3971
|
const entries = await readdir(resolvedPath, { withFileTypes: true });
|
|
3756
3972
|
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
3757
3973
|
name: entry.name,
|
|
3758
|
-
path:
|
|
3974
|
+
path: join6(resolvedPath, entry.name)
|
|
3759
3975
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
3760
|
-
const parent =
|
|
3976
|
+
const parent = dirname5(resolvedPath);
|
|
3761
3977
|
const hasParent = parent !== resolvedPath;
|
|
3762
3978
|
res.json({
|
|
3763
3979
|
current: resolvedPath,
|
|
@@ -3779,10 +3995,10 @@ function createDirectoryRoutes() {
|
|
|
3779
3995
|
}
|
|
3780
3996
|
|
|
3781
3997
|
// src/server/routes/file-search.ts
|
|
3782
|
-
import { Router as
|
|
3998
|
+
import { Router as Router7 } from "express";
|
|
3783
3999
|
import fg from "fast-glob";
|
|
3784
4000
|
function createFileSearchRoutes() {
|
|
3785
|
-
const router =
|
|
4001
|
+
const router = Router7();
|
|
3786
4002
|
router.get("/", async (req, res) => {
|
|
3787
4003
|
const query = req.query["q"] || "";
|
|
3788
4004
|
const workdir = req.query["workdir"] || process.cwd();
|
|
@@ -3858,11 +4074,11 @@ function fuzzyScore(filePath, query) {
|
|
|
3858
4074
|
}
|
|
3859
4075
|
|
|
3860
4076
|
// src/server/routes/auto-update.ts
|
|
3861
|
-
import { Router as
|
|
4077
|
+
import { Router as Router8 } from "express";
|
|
3862
4078
|
import { spawn as spawn2 } from "child_process";
|
|
3863
4079
|
|
|
3864
4080
|
// src/constants.ts
|
|
3865
|
-
var VERSION = "2.0.
|
|
4081
|
+
var VERSION = "2.0.60";
|
|
3866
4082
|
|
|
3867
4083
|
// src/server/routes/auto-update.ts
|
|
3868
4084
|
var updateInProgress = false;
|
|
@@ -3880,12 +4096,12 @@ async function checkAuth(req, opts) {
|
|
|
3880
4096
|
return true;
|
|
3881
4097
|
}
|
|
3882
4098
|
function createAutoUpdateRoutes(options = {}) {
|
|
3883
|
-
const router =
|
|
4099
|
+
const router = Router8();
|
|
3884
4100
|
router.get("/check", async (_req, res) => {
|
|
3885
4101
|
const isService = isRunningAsService();
|
|
3886
4102
|
const current = VERSION;
|
|
3887
4103
|
try {
|
|
3888
|
-
const latest = await new Promise((
|
|
4104
|
+
const latest = await new Promise((resolve5, reject) => {
|
|
3889
4105
|
const child = spawn2("npm", ["view", "openfox", "version"], {
|
|
3890
4106
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3891
4107
|
windowsHide: true
|
|
@@ -3896,7 +4112,7 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3896
4112
|
});
|
|
3897
4113
|
child.on("close", (code) => {
|
|
3898
4114
|
if (code === 0) {
|
|
3899
|
-
|
|
4115
|
+
resolve5(stdout.trim());
|
|
3900
4116
|
} else {
|
|
3901
4117
|
reject(new Error(`npm view exited with code ${code}`));
|
|
3902
4118
|
}
|
|
@@ -3940,9 +4156,9 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3940
4156
|
const timeout = setTimeout(() => {
|
|
3941
4157
|
child.kill();
|
|
3942
4158
|
}, UPDATE_TIMEOUT);
|
|
3943
|
-
const exitCode = await new Promise((
|
|
3944
|
-
child.on("close",
|
|
3945
|
-
child.on("error", () =>
|
|
4159
|
+
const exitCode = await new Promise((resolve5) => {
|
|
4160
|
+
child.on("close", resolve5);
|
|
4161
|
+
child.on("error", () => resolve5(1));
|
|
3946
4162
|
});
|
|
3947
4163
|
clearTimeout(timeout);
|
|
3948
4164
|
if (exitCode === 0) {
|
|
@@ -3980,15 +4196,15 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
3980
4196
|
}
|
|
3981
4197
|
|
|
3982
4198
|
// src/server/index.ts
|
|
3983
|
-
var __dirname3 =
|
|
3984
|
-
async function createServerHandle(
|
|
3985
|
-
setRuntimeConfig(
|
|
3986
|
-
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);
|
|
3987
4203
|
await loadServerAuthConfig();
|
|
3988
|
-
const db = initDatabase(
|
|
4204
|
+
const db = initDatabase(config3);
|
|
3989
4205
|
initEventStore(db);
|
|
3990
|
-
const configDir = getGlobalConfigDir(
|
|
3991
|
-
const providerManager = createProviderManager(
|
|
4206
|
+
const configDir = getGlobalConfigDir(config3.mode ?? "production");
|
|
4207
|
+
const providerManager = createProviderManager(config3);
|
|
3992
4208
|
const sessionManager = new SessionManager(providerManager);
|
|
3993
4209
|
devServerManager.setSessionManager(sessionManager);
|
|
3994
4210
|
const useMock = process.env["OPENFOX_MOCK_LLM"] === "true";
|
|
@@ -3999,24 +4215,24 @@ async function createServerHandle(config4) {
|
|
|
3999
4215
|
}
|
|
4000
4216
|
async function initLLM() {
|
|
4001
4217
|
const llmClient = getLLMClient();
|
|
4002
|
-
const backend =
|
|
4218
|
+
const backend = config3.llm.backend;
|
|
4003
4219
|
llmClient.setBackend(backend);
|
|
4004
4220
|
if (!useMock) {
|
|
4005
4221
|
logger.info("Using configured LLM backend", { backend: getBackendDisplayName(backend) });
|
|
4006
4222
|
}
|
|
4007
|
-
const detected = await detectModel(
|
|
4008
|
-
if (detected && !
|
|
4223
|
+
const detected = await detectModel(config3.llm.baseUrl);
|
|
4224
|
+
if (detected && !config3.defaultModelSelection) {
|
|
4009
4225
|
llmClient.setModel(detected);
|
|
4010
4226
|
if (!useMock) {
|
|
4011
4227
|
logger.info("Auto-detected LLM model", { model: detected, backend: getBackendDisplayName(backend) });
|
|
4012
4228
|
}
|
|
4013
|
-
} else if (detected &&
|
|
4229
|
+
} else if (detected && config3.defaultModelSelection) {
|
|
4014
4230
|
if (!useMock) {
|
|
4015
|
-
logger.debug("Skipping auto-detect, using configured model", { model:
|
|
4231
|
+
logger.debug("Skipping auto-detect, using configured model", { model: config3.llm.model });
|
|
4016
4232
|
}
|
|
4017
4233
|
} else {
|
|
4018
4234
|
if (!useMock) {
|
|
4019
|
-
logger.warn("Could not auto-detect model, using config", { model:
|
|
4235
|
+
logger.warn("Could not auto-detect model, using config", { model: config3.llm.model });
|
|
4020
4236
|
}
|
|
4021
4237
|
}
|
|
4022
4238
|
const activeProvider = providerManager.getActiveProvider();
|
|
@@ -4037,14 +4253,14 @@ async function createServerHandle(config4) {
|
|
|
4037
4253
|
onToolsDiscovered: async (name, tools) => {
|
|
4038
4254
|
try {
|
|
4039
4255
|
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
4040
|
-
const mode =
|
|
4041
|
-
const globalConfig = await loadGlobalConfig(mode,
|
|
4256
|
+
const mode = config3.mode ?? "production";
|
|
4257
|
+
const globalConfig = await loadGlobalConfig(mode, config3.globalConfigPath);
|
|
4042
4258
|
const mcpServers2 = {
|
|
4043
4259
|
...globalConfig.mcpServers ?? {}
|
|
4044
4260
|
};
|
|
4045
4261
|
if (mcpServers2[name]) {
|
|
4046
4262
|
mcpServers2[name] = { ...mcpServers2[name], cachedTools: tools };
|
|
4047
|
-
await saveGlobalConfig(mode, { ...globalConfig, mcpServers: mcpServers2 },
|
|
4263
|
+
await saveGlobalConfig(mode, { ...globalConfig, mcpServers: mcpServers2 }, config3.globalConfigPath);
|
|
4048
4264
|
}
|
|
4049
4265
|
} catch (err) {
|
|
4050
4266
|
logger.warn("Failed to persist MCP tool cache", { name, error: String(err) });
|
|
@@ -4052,9 +4268,9 @@ async function createServerHandle(config4) {
|
|
|
4052
4268
|
}
|
|
4053
4269
|
});
|
|
4054
4270
|
setMcpManagerForTools(mcpManager);
|
|
4055
|
-
setMcpConfigMode(
|
|
4056
|
-
setMcpConfigPath(
|
|
4057
|
-
const mcpServers =
|
|
4271
|
+
setMcpConfigMode(config3.mode ?? "production");
|
|
4272
|
+
setMcpConfigPath(config3.globalConfigPath);
|
|
4273
|
+
const mcpServers = config3.mcpServers ?? {};
|
|
4058
4274
|
Promise.all(
|
|
4059
4275
|
Object.entries(mcpServers).map(
|
|
4060
4276
|
([name, serverConfig]) => mcpManager.addServer(name, serverConfig).catch((err) => {
|
|
@@ -4067,7 +4283,7 @@ async function createServerHandle(config4) {
|
|
|
4067
4283
|
setMcpTools(mcpTools);
|
|
4068
4284
|
logger.info("MCP tools registered", { count: mcpTools.length });
|
|
4069
4285
|
}
|
|
4070
|
-
const { signalMcpReady } = await import("./server-
|
|
4286
|
+
const { signalMcpReady } = await import("./server-LMH7ZH5X.js");
|
|
4071
4287
|
signalMcpReady();
|
|
4072
4288
|
});
|
|
4073
4289
|
const app = express();
|
|
@@ -4253,14 +4469,14 @@ async function createServerHandle(config4) {
|
|
|
4253
4469
|
if (!project) {
|
|
4254
4470
|
return res.status(404).json({ error: "Project not found" });
|
|
4255
4471
|
}
|
|
4256
|
-
const { providerId, model } = parseDefaultModelSelection(
|
|
4472
|
+
const { providerId, model } = parseDefaultModelSelection(config3.defaultModelSelection);
|
|
4257
4473
|
const session = sessionManager.createSession(projectId, title, providerId ?? null, model ?? null);
|
|
4258
4474
|
res.status(201).json({ session });
|
|
4259
4475
|
});
|
|
4260
4476
|
app.get("/api/sessions/:id", async (req, res) => {
|
|
4261
4477
|
const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
|
|
4262
4478
|
const { buildMessagesFromStoredEvents } = await import("./folding-2BGFLV5J.js");
|
|
4263
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
4479
|
+
const { getPendingQuestionsForSession } = await import("./tools-WGAZKL56.js");
|
|
4264
4480
|
const session = sessionManager.getSession(req.params.id);
|
|
4265
4481
|
if (!session) {
|
|
4266
4482
|
return res.status(404).json({ error: "Session not found" });
|
|
@@ -4279,8 +4495,8 @@ async function createServerHandle(config4) {
|
|
|
4279
4495
|
if (!session) {
|
|
4280
4496
|
return res.status(404).json({ error: "Session not found" });
|
|
4281
4497
|
}
|
|
4282
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
4283
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
4498
|
+
const { stopSessionExecution } = await import("./chat-handler-MBR6ZQTX.js");
|
|
4499
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-WGAZKL56.js");
|
|
4284
4500
|
sessionManager.clearMessageQueue(sessionId);
|
|
4285
4501
|
stopSessionExecution(sessionId, sessionManager);
|
|
4286
4502
|
abortSession(sessionId);
|
|
@@ -4334,11 +4550,11 @@ async function createServerHandle(config4) {
|
|
|
4334
4550
|
return res.status(500).json({ error: result.error ?? "Failed to set default model" });
|
|
4335
4551
|
}
|
|
4336
4552
|
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-GMQUPNBY.js");
|
|
4337
|
-
const globalConfig = await loadGlobalConfig(
|
|
4553
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4338
4554
|
const updatedConfig = setDefaultModelSelection(globalConfig, providerId, model);
|
|
4339
|
-
await saveGlobalConfig(
|
|
4340
|
-
|
|
4341
|
-
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 });
|
|
4342
4558
|
});
|
|
4343
4559
|
app.put("/api/sessions/:id/criteria", async (req, res) => {
|
|
4344
4560
|
const sessionId = req.params.id;
|
|
@@ -4434,7 +4650,7 @@ async function createServerHandle(config4) {
|
|
|
4434
4650
|
if (!callId || approved === void 0) {
|
|
4435
4651
|
return res.status(400).json({ error: "callId and approved are required" });
|
|
4436
4652
|
}
|
|
4437
|
-
const { providePathConfirmation } = await import("./tools-
|
|
4653
|
+
const { providePathConfirmation } = await import("./tools-WGAZKL56.js");
|
|
4438
4654
|
const result = providePathConfirmation(callId, approved, alwaysAllow);
|
|
4439
4655
|
if (!result.found) {
|
|
4440
4656
|
return res.status(404).json({ error: "No pending path confirmation with that ID" });
|
|
@@ -4442,7 +4658,7 @@ async function createServerHandle(config4) {
|
|
|
4442
4658
|
const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
|
|
4443
4659
|
const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-2BGFLV5J.js");
|
|
4444
4660
|
const { createSessionStateMessage } = await import("./protocol-CTNE3ANP.js");
|
|
4445
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
4661
|
+
const { getPendingQuestionsForSession } = await import("./tools-WGAZKL56.js");
|
|
4446
4662
|
const eventStore = getEventStore2();
|
|
4447
4663
|
const events = eventStore.getEvents(sessionId);
|
|
4448
4664
|
const messages = buildMessagesFromStoredEvents(events);
|
|
@@ -4463,7 +4679,7 @@ async function createServerHandle(config4) {
|
|
|
4463
4679
|
if (!skip && typeof answer !== "string") {
|
|
4464
4680
|
return res.status(400).json({ error: "answer is required when not skipping" });
|
|
4465
4681
|
}
|
|
4466
|
-
const { provideAnswer } = await import("./tools-
|
|
4682
|
+
const { provideAnswer } = await import("./tools-WGAZKL56.js");
|
|
4467
4683
|
const found = provideAnswer(callId, answer ?? "", skip ?? false);
|
|
4468
4684
|
if (!found) {
|
|
4469
4685
|
return res.status(404).json({ error: "No pending question with that ID" });
|
|
@@ -4491,8 +4707,8 @@ async function createServerHandle(config4) {
|
|
|
4491
4707
|
if (!session) {
|
|
4492
4708
|
return res.status(404).json({ error: "Session not found" });
|
|
4493
4709
|
}
|
|
4494
|
-
const { getSetting, SETTINGS_KEYS } = await import("./settings-
|
|
4495
|
-
if (
|
|
4710
|
+
const { getSetting: getSetting2, SETTINGS_KEYS } = await import("./settings-2TQA7VTP.js");
|
|
4711
|
+
if (getSetting2(SETTINGS_KEYS.CACHE_WARMING) !== "true") {
|
|
4496
4712
|
return res.json({ success: false, reason: "disabled" });
|
|
4497
4713
|
}
|
|
4498
4714
|
if (session.messages.length > 0) {
|
|
@@ -4523,7 +4739,7 @@ async function createServerHandle(config4) {
|
|
|
4523
4739
|
backend: activeProvider?.backend ?? llmClient.getBackend(),
|
|
4524
4740
|
model: llmClient.getModel()
|
|
4525
4741
|
};
|
|
4526
|
-
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-
|
|
4742
|
+
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-PIZJ42J2.js");
|
|
4527
4743
|
runAgentTurn(
|
|
4528
4744
|
{
|
|
4529
4745
|
sessionManager,
|
|
@@ -4561,8 +4777,8 @@ async function createServerHandle(config4) {
|
|
|
4561
4777
|
if (!session) {
|
|
4562
4778
|
return res.status(404).json({ error: "Session not found" });
|
|
4563
4779
|
}
|
|
4564
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
4565
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
4780
|
+
const { stopSessionExecution } = await import("./chat-handler-MBR6ZQTX.js");
|
|
4781
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-WGAZKL56.js");
|
|
4566
4782
|
const queuedMessages = sessionManager.getQueueState(sessionId);
|
|
4567
4783
|
sessionManager.clearMessageQueue(sessionId);
|
|
4568
4784
|
stopSessionExecution(sessionId, sessionManager);
|
|
@@ -4642,7 +4858,7 @@ async function createServerHandle(config4) {
|
|
|
4642
4858
|
res.json({ accepted: true });
|
|
4643
4859
|
});
|
|
4644
4860
|
app.get("/api/settings", async (req, res) => {
|
|
4645
|
-
const { getSetting, SETTINGS_DEFAULTS } = await import("./settings-
|
|
4861
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-2TQA7VTP.js");
|
|
4646
4862
|
const keysParam = req.query["keys"];
|
|
4647
4863
|
if (!keysParam) {
|
|
4648
4864
|
return res.status(400).json({ error: "keys query parameter is required" });
|
|
@@ -4650,30 +4866,30 @@ async function createServerHandle(config4) {
|
|
|
4650
4866
|
const keys = keysParam.split(",").map((k) => k.trim());
|
|
4651
4867
|
const result = {};
|
|
4652
4868
|
for (const key of keys) {
|
|
4653
|
-
result[key] =
|
|
4869
|
+
result[key] = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? "";
|
|
4654
4870
|
}
|
|
4655
4871
|
res.json(result);
|
|
4656
4872
|
});
|
|
4657
4873
|
app.get("/api/settings/:key", async (req, res) => {
|
|
4658
|
-
const { getSetting, SETTINGS_DEFAULTS } = await import("./settings-
|
|
4874
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-2TQA7VTP.js");
|
|
4659
4875
|
const key = req.params.key;
|
|
4660
|
-
const value =
|
|
4876
|
+
const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
|
|
4661
4877
|
res.json({ key, value });
|
|
4662
4878
|
});
|
|
4663
4879
|
app.get("/api/settings/:key", async (req, res) => {
|
|
4664
|
-
const { getSetting, SETTINGS_DEFAULTS } = await import("./settings-
|
|
4880
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-2TQA7VTP.js");
|
|
4665
4881
|
const key = req.params.key;
|
|
4666
|
-
const value =
|
|
4882
|
+
const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
|
|
4667
4883
|
res.json({ key, value });
|
|
4668
4884
|
});
|
|
4669
4885
|
app.put("/api/settings/:key", async (req, res) => {
|
|
4670
|
-
const { setSetting } = await import("./settings-
|
|
4886
|
+
const { setSetting: setSetting2 } = await import("./settings-2TQA7VTP.js");
|
|
4671
4887
|
const key = req.params.key;
|
|
4672
4888
|
const { value } = req.body;
|
|
4673
4889
|
if (value === void 0) {
|
|
4674
4890
|
return res.status(400).json({ error: "value is required" });
|
|
4675
4891
|
}
|
|
4676
|
-
|
|
4892
|
+
setSetting2(key, value);
|
|
4677
4893
|
res.json({ key, value });
|
|
4678
4894
|
});
|
|
4679
4895
|
app.get("/api/config", async (_req, res) => {
|
|
@@ -4683,7 +4899,7 @@ async function createServerHandle(config4) {
|
|
|
4683
4899
|
let globalWorkdir;
|
|
4684
4900
|
try {
|
|
4685
4901
|
const { loadGlobalConfig, getVisionFallback } = await import("./config-GMQUPNBY.js");
|
|
4686
|
-
const globalConfig = await loadGlobalConfig(
|
|
4902
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4687
4903
|
const fallback = getVisionFallback(globalConfig);
|
|
4688
4904
|
if (fallback) {
|
|
4689
4905
|
visionFallback = {
|
|
@@ -4701,13 +4917,13 @@ async function createServerHandle(config4) {
|
|
|
4701
4917
|
version: VERSION,
|
|
4702
4918
|
model: llmClient.getModel(),
|
|
4703
4919
|
maxContext: providerManager.getCurrentModelContext(),
|
|
4704
|
-
llmUrl: activeProvider?.url ??
|
|
4920
|
+
llmUrl: activeProvider?.url ?? config3.llm.baseUrl,
|
|
4705
4921
|
llmStatus: getLlmStatus(),
|
|
4706
4922
|
backend: llmClient.getBackend(),
|
|
4707
|
-
workdir: globalWorkdir ??
|
|
4923
|
+
workdir: globalWorkdir ?? config3.workdir,
|
|
4708
4924
|
providers: providerManager.getProviders(),
|
|
4709
4925
|
activeProviderId: providerManager.getActiveProviderId(),
|
|
4710
|
-
defaultModelSelection:
|
|
4926
|
+
defaultModelSelection: config3.defaultModelSelection,
|
|
4711
4927
|
visionFallback
|
|
4712
4928
|
});
|
|
4713
4929
|
});
|
|
@@ -4716,7 +4932,7 @@ async function createServerHandle(config4) {
|
|
|
4716
4932
|
const currentModel = providerManager.getCurrentModel();
|
|
4717
4933
|
if (currentModel === "auto") {
|
|
4718
4934
|
const activeProvider = providerManager.getActiveProvider();
|
|
4719
|
-
const baseUrl = activeProvider?.url ??
|
|
4935
|
+
const baseUrl = activeProvider?.url ?? config3.llm.baseUrl;
|
|
4720
4936
|
const detected = await detectModel(baseUrl);
|
|
4721
4937
|
if (detected) {
|
|
4722
4938
|
llmClient.setModel(detected);
|
|
@@ -4906,7 +5122,7 @@ async function createServerHandle(config4) {
|
|
|
4906
5122
|
}
|
|
4907
5123
|
try {
|
|
4908
5124
|
const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-GMQUPNBY.js");
|
|
4909
|
-
const globalConfig = await loadGlobalConfig(
|
|
5125
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4910
5126
|
const providerBackend = backend;
|
|
4911
5127
|
const providerModels = modelConfigs?.length ? buildModelConfigs(modelConfigs) : model ? [{ id: model, contextWindow: 2e5, source: "user" }] : [];
|
|
4912
5128
|
const configWithProvider = addProvider(globalConfig, {
|
|
@@ -4925,9 +5141,9 @@ async function createServerHandle(config4) {
|
|
|
4925
5141
|
configWithProvider.providers[configWithProvider.providers.length - 1].id,
|
|
4926
5142
|
firstModelId
|
|
4927
5143
|
);
|
|
4928
|
-
await saveGlobalConfig(
|
|
5144
|
+
await saveGlobalConfig(config3.mode ?? "production", finalConfig, config3.globalConfigPath);
|
|
4929
5145
|
providerManager.setProviders(finalConfig.providers, finalConfig.defaultModelSelection ?? void 0);
|
|
4930
|
-
|
|
5146
|
+
config3.defaultModelSelection = finalConfig.defaultModelSelection;
|
|
4931
5147
|
const newProvider = finalConfig.providers[finalConfig.providers.length - 1];
|
|
4932
5148
|
res.status(201).json({
|
|
4933
5149
|
success: true,
|
|
@@ -4944,13 +5160,13 @@ async function createServerHandle(config4) {
|
|
|
4944
5160
|
const { workdir, visionFallback } = req.body;
|
|
4945
5161
|
try {
|
|
4946
5162
|
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
4947
|
-
const globalConfig = await loadGlobalConfig(
|
|
5163
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4948
5164
|
const updatedConfig = {
|
|
4949
5165
|
...globalConfig,
|
|
4950
5166
|
workspace: workdir ? { workdir } : globalConfig.workspace,
|
|
4951
5167
|
visionFallback: visionFallback ?? globalConfig.visionFallback
|
|
4952
5168
|
};
|
|
4953
|
-
await saveGlobalConfig(
|
|
5169
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
4954
5170
|
res.json({ success: true });
|
|
4955
5171
|
} catch (error) {
|
|
4956
5172
|
res.status(500).json({
|
|
@@ -4972,11 +5188,11 @@ async function createServerHandle(config4) {
|
|
|
4972
5188
|
app.delete("/api/providers/:id", async (req, res) => {
|
|
4973
5189
|
const { id } = req.params;
|
|
4974
5190
|
const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-GMQUPNBY.js");
|
|
4975
|
-
const globalConfig = await loadGlobalConfig(
|
|
5191
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4976
5192
|
const updatedConfig = removeProvider(globalConfig, id);
|
|
4977
|
-
await saveGlobalConfig(
|
|
5193
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
4978
5194
|
providerManager.setProviders(updatedConfig.providers, updatedConfig.defaultModelSelection ?? void 0);
|
|
4979
|
-
|
|
5195
|
+
config3.defaultModelSelection = updatedConfig.defaultModelSelection;
|
|
4980
5196
|
res.json({ success: true });
|
|
4981
5197
|
});
|
|
4982
5198
|
app.patch("/api/providers/:id", async (req, res) => {
|
|
@@ -4984,7 +5200,7 @@ async function createServerHandle(config4) {
|
|
|
4984
5200
|
const { isLocal } = req.body;
|
|
4985
5201
|
try {
|
|
4986
5202
|
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-GMQUPNBY.js");
|
|
4987
|
-
const globalConfig = await loadGlobalConfig(
|
|
5203
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4988
5204
|
const provider = globalConfig.providers.find((p) => p.id === id);
|
|
4989
5205
|
if (!provider) {
|
|
4990
5206
|
return res.status(404).json({ error: "Provider not found" });
|
|
@@ -4992,9 +5208,9 @@ async function createServerHandle(config4) {
|
|
|
4992
5208
|
const updates = {};
|
|
4993
5209
|
if (isLocal !== void 0) updates["isLocal"] = isLocal;
|
|
4994
5210
|
const updatedConfig = updateProvider(globalConfig, id, updates);
|
|
4995
|
-
await saveGlobalConfig(
|
|
5211
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
4996
5212
|
providerManager.setProviders(updatedConfig.providers, updatedConfig.defaultModelSelection ?? void 0);
|
|
4997
|
-
|
|
5213
|
+
config3.defaultModelSelection = updatedConfig.defaultModelSelection;
|
|
4998
5214
|
res.json({ success: true, provider: updatedConfig.providers.find((p) => p.id === id) });
|
|
4999
5215
|
} catch (error) {
|
|
5000
5216
|
res.status(500).json({ error: error instanceof Error ? error.message : "Failed to update provider" });
|
|
@@ -5013,7 +5229,7 @@ async function createServerHandle(config4) {
|
|
|
5013
5229
|
} = req.body;
|
|
5014
5230
|
try {
|
|
5015
5231
|
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-GMQUPNBY.js");
|
|
5016
|
-
const globalConfig = await loadGlobalConfig(
|
|
5232
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5017
5233
|
const provider = globalConfig.providers.find((p) => p.id === id);
|
|
5018
5234
|
if (!provider) {
|
|
5019
5235
|
return res.status(404).json({ error: "Provider not found" });
|
|
@@ -5029,9 +5245,9 @@ async function createServerHandle(config4) {
|
|
|
5029
5245
|
updates["models"] = buildModelConfigs(modelConfigs);
|
|
5030
5246
|
}
|
|
5031
5247
|
const updatedConfig = updateProvider(globalConfig, id, updates);
|
|
5032
|
-
await saveGlobalConfig(
|
|
5248
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
5033
5249
|
providerManager.setProviders(updatedConfig.providers, updatedConfig.defaultModelSelection ?? void 0);
|
|
5034
|
-
|
|
5250
|
+
config3.defaultModelSelection = updatedConfig.defaultModelSelection;
|
|
5035
5251
|
res.json({ success: true, provider: updatedConfig.providers.find((p) => p.id === id) });
|
|
5036
5252
|
} catch (error) {
|
|
5037
5253
|
res.status(500).json({ error: error instanceof Error ? error.message : "Failed to update provider" });
|
|
@@ -5051,9 +5267,9 @@ async function createServerHandle(config4) {
|
|
|
5051
5267
|
}
|
|
5052
5268
|
const llmClient = getLLMClient();
|
|
5053
5269
|
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-GMQUPNBY.js");
|
|
5054
|
-
const globalConfig = await loadGlobalConfig(
|
|
5270
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5055
5271
|
const updatedConfig = setDefaultModelSelection(globalConfig, id, llmClient.getModel());
|
|
5056
|
-
await saveGlobalConfig(
|
|
5272
|
+
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
5057
5273
|
res.json({
|
|
5058
5274
|
success: true,
|
|
5059
5275
|
activeProviderId: id,
|
|
@@ -5077,7 +5293,7 @@ async function createServerHandle(config4) {
|
|
|
5077
5293
|
});
|
|
5078
5294
|
async function rebuildMcpTools() {
|
|
5079
5295
|
const { createMcpTools: createMcpTools2 } = await import("./tool-adapter-MOGEI6TP.js");
|
|
5080
|
-
const { setMcpTools: setMcpTools2 } = await import("./tools-
|
|
5296
|
+
const { setMcpTools: setMcpTools2 } = await import("./tools-WGAZKL56.js");
|
|
5081
5297
|
const mcpTools = createMcpTools2(mcpManager);
|
|
5082
5298
|
setMcpTools2(mcpTools);
|
|
5083
5299
|
}
|
|
@@ -5140,15 +5356,15 @@ async function createServerHandle(config4) {
|
|
|
5140
5356
|
await mcpManager.addServer(name, serverCfg);
|
|
5141
5357
|
const server = mcpManager.getServer(name);
|
|
5142
5358
|
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
5143
|
-
const globalConfig = await loadGlobalConfig(
|
|
5359
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5144
5360
|
const updatedMcpServers = { ...globalConfig.mcpServers ?? {}, [name]: serverCfg };
|
|
5145
5361
|
await saveGlobalConfig(
|
|
5146
|
-
|
|
5362
|
+
config3.mode ?? "production",
|
|
5147
5363
|
{
|
|
5148
5364
|
...globalConfig,
|
|
5149
5365
|
mcpServers: updatedMcpServers
|
|
5150
5366
|
},
|
|
5151
|
-
|
|
5367
|
+
config3.globalConfigPath
|
|
5152
5368
|
);
|
|
5153
5369
|
await rebuildMcpTools();
|
|
5154
5370
|
if (server) {
|
|
@@ -5170,16 +5386,16 @@ async function createServerHandle(config4) {
|
|
|
5170
5386
|
}
|
|
5171
5387
|
mcpManager.removeServer(name);
|
|
5172
5388
|
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
5173
|
-
const globalConfig = await loadGlobalConfig(
|
|
5389
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5174
5390
|
const updatedMcpServers = { ...globalConfig.mcpServers ?? {} };
|
|
5175
5391
|
delete updatedMcpServers[name];
|
|
5176
5392
|
await saveGlobalConfig(
|
|
5177
|
-
|
|
5393
|
+
config3.mode ?? "production",
|
|
5178
5394
|
{
|
|
5179
5395
|
...globalConfig,
|
|
5180
5396
|
mcpServers: updatedMcpServers
|
|
5181
5397
|
},
|
|
5182
|
-
|
|
5398
|
+
config3.globalConfigPath
|
|
5183
5399
|
);
|
|
5184
5400
|
await rebuildMcpTools();
|
|
5185
5401
|
const sessions = sessionManager.listSessions();
|
|
@@ -5199,7 +5415,7 @@ async function createServerHandle(config4) {
|
|
|
5199
5415
|
const server = mcpManager.getServer(name);
|
|
5200
5416
|
if (server) {
|
|
5201
5417
|
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-GMQUPNBY.js");
|
|
5202
|
-
const globalConfig = await loadGlobalConfig(
|
|
5418
|
+
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5203
5419
|
const mcpServers2 = { ...globalConfig.mcpServers ?? {} };
|
|
5204
5420
|
const serverCfg = mcpServers2[name];
|
|
5205
5421
|
if (serverCfg) {
|
|
@@ -5207,12 +5423,12 @@ async function createServerHandle(config4) {
|
|
|
5207
5423
|
const cfg = { ...serverCfg, ...disabledTools.length > 0 ? { disabledTools } : { disabledTools: void 0 } };
|
|
5208
5424
|
mcpServers2[name] = cfg;
|
|
5209
5425
|
await saveGlobalConfig(
|
|
5210
|
-
|
|
5426
|
+
config3.mode ?? "production",
|
|
5211
5427
|
{
|
|
5212
5428
|
...globalConfig,
|
|
5213
5429
|
mcpServers: mcpServers2
|
|
5214
5430
|
},
|
|
5215
|
-
|
|
5431
|
+
config3.globalConfigPath
|
|
5216
5432
|
);
|
|
5217
5433
|
}
|
|
5218
5434
|
}
|
|
@@ -5226,11 +5442,11 @@ async function createServerHandle(config4) {
|
|
|
5226
5442
|
res.status(400).json({ error: error instanceof Error ? error.message : String(error) });
|
|
5227
5443
|
}
|
|
5228
5444
|
});
|
|
5229
|
-
const projectDir =
|
|
5445
|
+
const projectDir = config3.workdir;
|
|
5230
5446
|
app.use("/api/skills", createSkillRoutes(configDir, projectDir));
|
|
5231
5447
|
app.use("/api/commands", createCommandRoutes(configDir, projectDir));
|
|
5232
5448
|
app.use("/api/agents", createAgentRoutes(configDir, projectDir));
|
|
5233
|
-
app.use("/api/workflows", createWorkflowRoutes(configDir,
|
|
5449
|
+
app.use("/api/workflows", createWorkflowRoutes(configDir, config3, projectDir));
|
|
5234
5450
|
app.use("/api/dev-server", createDevServerRoutes());
|
|
5235
5451
|
app.use("/api/terminals", createTerminalRoutes());
|
|
5236
5452
|
app.use(
|
|
@@ -5274,14 +5490,14 @@ async function createServerHandle(config4) {
|
|
|
5274
5490
|
});
|
|
5275
5491
|
app.use("/api/directories", createDirectoryRoutes());
|
|
5276
5492
|
app.use("/api/files", createFileSearchRoutes());
|
|
5277
|
-
const webDir =
|
|
5278
|
-
const isDev =
|
|
5493
|
+
const webDir = resolve4(__dirname3, "../../web");
|
|
5494
|
+
const isDev = config3.mode === "development";
|
|
5279
5495
|
let viteServer;
|
|
5280
5496
|
if (isDev) {
|
|
5281
5497
|
logger.info("Dev mode: using Vite middleware");
|
|
5282
5498
|
viteServer = await createViteServer({
|
|
5283
5499
|
root: webDir,
|
|
5284
|
-
configFile:
|
|
5500
|
+
configFile: resolve4(__dirname3, "../../web/vite.config.ts"),
|
|
5285
5501
|
server: { middlewareMode: true },
|
|
5286
5502
|
appType: "spa",
|
|
5287
5503
|
logLevel: "warn"
|
|
@@ -5301,7 +5517,7 @@ async function createServerHandle(config4) {
|
|
|
5301
5517
|
}
|
|
5302
5518
|
});
|
|
5303
5519
|
app.get("/fox.svg", (_req, res) => {
|
|
5304
|
-
|
|
5520
|
+
readFile2(join7(webDir, "fox.svg")).then((content) => {
|
|
5305
5521
|
res.set("Content-Type", "image/svg+xml");
|
|
5306
5522
|
res.send(content);
|
|
5307
5523
|
}).catch(() => {
|
|
@@ -5310,7 +5526,7 @@ async function createServerHandle(config4) {
|
|
|
5310
5526
|
});
|
|
5311
5527
|
app.use(
|
|
5312
5528
|
"/sounds",
|
|
5313
|
-
express.static(
|
|
5529
|
+
express.static(join7(webDir, "public", "sounds"), {
|
|
5314
5530
|
setHeaders: (res) => {
|
|
5315
5531
|
res.set("Content-Type", "audio/mpeg");
|
|
5316
5532
|
}
|
|
@@ -5319,24 +5535,24 @@ async function createServerHandle(config4) {
|
|
|
5319
5535
|
app.use("/__inspect__.js", (_req, res) => {
|
|
5320
5536
|
res.set("Access-Control-Allow-Origin", "*");
|
|
5321
5537
|
res.set("Content-Type", "application/javascript");
|
|
5322
|
-
|
|
5538
|
+
readFile2(join7(webDir, "public", "__inspect__.js")).then((content) => res.send(content)).catch(() => res.status(404).send("Not found"));
|
|
5323
5539
|
});
|
|
5324
5540
|
app.get("/*path", (req, res) => {
|
|
5325
5541
|
if (req.path.startsWith("/api/")) {
|
|
5326
5542
|
return;
|
|
5327
5543
|
}
|
|
5328
|
-
|
|
5544
|
+
readFile2(join7(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
|
|
5329
5545
|
logger.error("Error serving index.html", { error: err });
|
|
5330
5546
|
res.status(500).send("Server error");
|
|
5331
5547
|
});
|
|
5332
5548
|
});
|
|
5333
|
-
logger.info("Vite middleware ready", { port:
|
|
5549
|
+
logger.info("Vite middleware ready", { port: config3.server.port });
|
|
5334
5550
|
}
|
|
5335
5551
|
if (!isDev) {
|
|
5336
|
-
const distWebDir =
|
|
5552
|
+
const distWebDir = resolve4(__dirname3, "web");
|
|
5337
5553
|
app.use(
|
|
5338
5554
|
"/assets",
|
|
5339
|
-
express.static(
|
|
5555
|
+
express.static(join7(distWebDir, "assets"), {
|
|
5340
5556
|
setHeaders: (res, filepath) => {
|
|
5341
5557
|
if (filepath.endsWith(".css")) {
|
|
5342
5558
|
res.set("Content-Type", "text/css");
|
|
@@ -5344,11 +5560,11 @@ async function createServerHandle(config4) {
|
|
|
5344
5560
|
}
|
|
5345
5561
|
})
|
|
5346
5562
|
);
|
|
5347
|
-
app.use("/manifest.webmanifest", express.static(
|
|
5348
|
-
app.use("/registerSW.js", express.static(
|
|
5349
|
-
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")));
|
|
5350
5566
|
app.get("/fox.svg", (_req, res) => {
|
|
5351
|
-
|
|
5567
|
+
readFile2(join7(distWebDir, "fox.svg")).then((content) => {
|
|
5352
5568
|
res.set("Content-Type", "image/svg+xml");
|
|
5353
5569
|
res.send(content);
|
|
5354
5570
|
}).catch(() => {
|
|
@@ -5357,7 +5573,7 @@ async function createServerHandle(config4) {
|
|
|
5357
5573
|
});
|
|
5358
5574
|
app.use(
|
|
5359
5575
|
"/sounds",
|
|
5360
|
-
express.static(
|
|
5576
|
+
express.static(join7(distWebDir, "sounds"), {
|
|
5361
5577
|
setHeaders: (res) => {
|
|
5362
5578
|
res.set("Content-Type", "audio/mpeg");
|
|
5363
5579
|
}
|
|
@@ -5366,10 +5582,10 @@ async function createServerHandle(config4) {
|
|
|
5366
5582
|
app.use("/__inspect__.js", (_req, res) => {
|
|
5367
5583
|
res.set("Access-Control-Allow-Origin", "*");
|
|
5368
5584
|
res.set("Content-Type", "application/javascript");
|
|
5369
|
-
|
|
5585
|
+
readFile2(join7(distWebDir, "__inspect__.js")).then((content) => res.send(content)).catch(() => res.status(404).send("Not found"));
|
|
5370
5586
|
});
|
|
5371
5587
|
app.get("/", (_req, res) => {
|
|
5372
|
-
|
|
5588
|
+
readFile2(join7(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
5373
5589
|
res.status(404).send("Web UI not built. Run `npm run build:web`");
|
|
5374
5590
|
});
|
|
5375
5591
|
});
|
|
@@ -5377,7 +5593,7 @@ async function createServerHandle(config4) {
|
|
|
5377
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") {
|
|
5378
5594
|
return;
|
|
5379
5595
|
}
|
|
5380
|
-
|
|
5596
|
+
readFile2(join7(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
5381
5597
|
res.status(404).send("Web UI not built");
|
|
5382
5598
|
});
|
|
5383
5599
|
});
|
|
@@ -5385,7 +5601,7 @@ async function createServerHandle(config4) {
|
|
|
5385
5601
|
const httpServer = createHttpServer(app);
|
|
5386
5602
|
const wssExports = createWebSocketServer(
|
|
5387
5603
|
httpServer,
|
|
5388
|
-
|
|
5604
|
+
config3,
|
|
5389
5605
|
getLLMClient,
|
|
5390
5606
|
() => providerManager.getActiveProvider(),
|
|
5391
5607
|
sessionManager,
|
|
@@ -5397,7 +5613,7 @@ async function createServerHandle(config4) {
|
|
|
5397
5613
|
const state = sessionManager.getContextState(sessionId);
|
|
5398
5614
|
wssExports.broadcastForSession(sessionId, createContextStateMessage(state));
|
|
5399
5615
|
});
|
|
5400
|
-
const { QueueProcessor } = await import("./processor-
|
|
5616
|
+
const { QueueProcessor } = await import("./processor-PKKTNKWY.js");
|
|
5401
5617
|
const queueProcessor = new QueueProcessor({
|
|
5402
5618
|
sessionManager,
|
|
5403
5619
|
providerManager,
|
|
@@ -5418,22 +5634,22 @@ async function createServerHandle(config4) {
|
|
|
5418
5634
|
};
|
|
5419
5635
|
return {
|
|
5420
5636
|
httpServer,
|
|
5421
|
-
ctx: { config:
|
|
5422
|
-
start: (port) => new Promise((
|
|
5423
|
-
const listenPort = port ??
|
|
5424
|
-
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;
|
|
5425
5641
|
httpServer.listen(listenPort, host, () => {
|
|
5426
5642
|
const addr = httpServer.address();
|
|
5427
5643
|
const actualPort = typeof addr === "object" && addr ? addr.port : listenPort;
|
|
5428
5644
|
const client = getLLMClient();
|
|
5429
5645
|
logger.info(`OpenFox server running at http://${host}:${actualPort}`);
|
|
5430
5646
|
logger.info(`WebSocket available at ws://${host}:${actualPort}/ws`);
|
|
5431
|
-
logger.info(`LLM backend: ${client.getBackend()}, model: ${client.getModel()}, url: ${
|
|
5432
|
-
|
|
5647
|
+
logger.info(`LLM backend: ${client.getBackend()}, model: ${client.getModel()}, url: ${config3.llm.baseUrl}`);
|
|
5648
|
+
resolve5({ port: actualPort });
|
|
5433
5649
|
});
|
|
5434
5650
|
httpServer.on("error", reject);
|
|
5435
5651
|
}),
|
|
5436
|
-
close: () => new Promise((
|
|
5652
|
+
close: () => new Promise((resolve5) => {
|
|
5437
5653
|
logger.info("Shutting down...");
|
|
5438
5654
|
void (async () => {
|
|
5439
5655
|
await devServerManager.stopAll();
|
|
@@ -5443,22 +5659,22 @@ async function createServerHandle(config4) {
|
|
|
5443
5659
|
const { cleanupAllProcesses } = await import("./store-FXTCHBI4.js");
|
|
5444
5660
|
cleanupAllProcesses();
|
|
5445
5661
|
viteServer?.close();
|
|
5446
|
-
if (
|
|
5662
|
+
if (config3.globalConfigPath) {
|
|
5447
5663
|
const { unlink: unlink2 } = await import("fs/promises");
|
|
5448
|
-
unlink2(
|
|
5664
|
+
unlink2(config3.globalConfigPath).catch(() => {
|
|
5449
5665
|
});
|
|
5450
5666
|
}
|
|
5451
5667
|
for (const client of wss.clients) {
|
|
5452
5668
|
client.terminate();
|
|
5453
5669
|
}
|
|
5454
5670
|
wss.close();
|
|
5455
|
-
httpServer.close(() =>
|
|
5671
|
+
httpServer.close(() => resolve5());
|
|
5456
5672
|
})();
|
|
5457
5673
|
})
|
|
5458
5674
|
};
|
|
5459
5675
|
}
|
|
5460
|
-
async function createServer(
|
|
5461
|
-
const handle = await createServerHandle(
|
|
5676
|
+
async function createServer(config3) {
|
|
5677
|
+
const handle = await createServerHandle(config3);
|
|
5462
5678
|
await handle.start();
|
|
5463
5679
|
const shutdown = () => {
|
|
5464
5680
|
const forceExitTimer = setTimeout(() => {
|
|
@@ -5477,4 +5693,4 @@ export {
|
|
|
5477
5693
|
createServerHandle,
|
|
5478
5694
|
createServer
|
|
5479
5695
|
};
|
|
5480
|
-
//# sourceMappingURL=chunk-
|
|
5696
|
+
//# sourceMappingURL=chunk-DEWNWF2P.js.map
|