openfox 1.6.15 → 1.6.16
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/{auto-compaction-JZIM73ZY.js → auto-compaction-2RKC6DC2.js} +2 -2
- package/dist/{chat-handler-F2A2IMQB.js → chat-handler-IY2XVOO6.js} +4 -4
- package/dist/{chunk-3WHZ47PY.js → chunk-4OI4VPZ6.js} +140 -238
- package/dist/{chunk-G4E72ST3.js → chunk-NN65D5SI.js} +376 -273
- package/dist/{chunk-JFKYCGZ5.js → chunk-T5PBG2PE.js} +2 -2
- package/dist/{chunk-YM6VHAPM.js → chunk-U54QVKL2.js} +2 -2
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{orchestrator-SRSG2SIZ.js → orchestrator-U5VCLBYQ.js} +3 -3
- package/dist/package.json +1 -1
- package/dist/{processor-H5BQ5HQM.js → processor-VUEJM73B.js} +2 -2
- package/dist/{serve-5AY7GMN7.js → serve-GOLQMQFA.js} +4 -4
- package/dist/server/index.js +3 -3
- package/dist/{tools-VOWNOP6V.js → tools-55YICCVH.js} +2 -2
- package/dist/web/assets/index-CZBXRYpK.js +150 -0
- package/dist/web/assets/{index-CNeIjdxm.css → index-D4V7Gtvt.css} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/dist/web/assets/index-mBLhctLW.js +0 -150
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
createVerifierNudgeConfig,
|
|
7
7
|
runBuilderTurn,
|
|
8
8
|
runChatTurn
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-U54QVKL2.js";
|
|
10
10
|
import {
|
|
11
11
|
TurnMetrics,
|
|
12
12
|
agentExists,
|
|
@@ -17,46 +17,34 @@ import {
|
|
|
17
17
|
createMessageStartEvent,
|
|
18
18
|
createToolRegistry,
|
|
19
19
|
deleteAgent,
|
|
20
|
-
deleteItem,
|
|
21
20
|
deleteSkill,
|
|
22
21
|
devServerManager,
|
|
23
|
-
dirExists,
|
|
24
|
-
ensureDefaultAgents,
|
|
25
|
-
ensureDefaultSkills,
|
|
26
|
-
ensureDir,
|
|
27
22
|
executeSubAgent,
|
|
28
23
|
findAgentById,
|
|
29
|
-
findById,
|
|
30
|
-
findModifiedDefaultFiles,
|
|
31
24
|
findSkillById,
|
|
32
25
|
getAllInstructions,
|
|
33
|
-
|
|
26
|
+
getDefaultAgentContent,
|
|
34
27
|
getDefaultAgentIds,
|
|
35
|
-
|
|
28
|
+
getDefaultSkillContent,
|
|
36
29
|
getDefaultSkillIds,
|
|
37
30
|
getEnabledSkillMetadata,
|
|
38
|
-
getModifiedDefaultAgentIds,
|
|
39
|
-
getModifiedDefaultSkillIds,
|
|
40
31
|
getToolRegistryForAgent,
|
|
41
32
|
isSkillEnabled,
|
|
42
33
|
loadAllAgents,
|
|
43
34
|
loadAllAgentsDefault,
|
|
44
35
|
loadAllSkills,
|
|
45
|
-
|
|
36
|
+
loadDefaultAgents,
|
|
37
|
+
loadDefaultSkills,
|
|
38
|
+
loadUserAgents,
|
|
39
|
+
loadUserSkills,
|
|
46
40
|
maybeAutoCompactContext,
|
|
47
41
|
performManualContextCompaction,
|
|
48
|
-
restoreAllDefaultAgents,
|
|
49
|
-
restoreAllDefaultSkills,
|
|
50
|
-
restoreDefault,
|
|
51
|
-
restoreDefaultAgent,
|
|
52
|
-
restoreDefaultSkill,
|
|
53
42
|
saveAgent,
|
|
54
|
-
saveItem,
|
|
55
43
|
saveSkill,
|
|
56
44
|
setSkillEnabled,
|
|
57
45
|
skillExists,
|
|
58
46
|
spawnShellProcess
|
|
59
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-4OI4VPZ6.js";
|
|
60
48
|
import {
|
|
61
49
|
getPathSeparator,
|
|
62
50
|
getPlatformShell,
|
|
@@ -156,9 +144,9 @@ import {
|
|
|
156
144
|
import express from "express";
|
|
157
145
|
import cors from "cors";
|
|
158
146
|
import { createServer as createHttpServer } from "http";
|
|
159
|
-
import { fileURLToPath as
|
|
160
|
-
import { dirname as
|
|
161
|
-
import { readFile as
|
|
147
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
148
|
+
import { dirname as dirname5, resolve, join as join6 } from "path";
|
|
149
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
162
150
|
import { createServer as createViteServer } from "vite";
|
|
163
151
|
|
|
164
152
|
// src/server/llm/mock.ts
|
|
@@ -1426,7 +1414,7 @@ function unsubscribeAllFromTerminal(ws) {
|
|
|
1426
1414
|
}
|
|
1427
1415
|
|
|
1428
1416
|
// src/server/workflows/registry.ts
|
|
1429
|
-
import { readdir, readFile, writeFile,
|
|
1417
|
+
import { readdir, readFile, writeFile, mkdir, access, unlink } from "fs/promises";
|
|
1430
1418
|
import { join, dirname } from "path";
|
|
1431
1419
|
import { constants } from "fs";
|
|
1432
1420
|
import { fileURLToPath } from "url";
|
|
@@ -1445,49 +1433,20 @@ async function pathExists(path) {
|
|
|
1445
1433
|
return false;
|
|
1446
1434
|
}
|
|
1447
1435
|
}
|
|
1448
|
-
async function
|
|
1449
|
-
|
|
1450
|
-
if (!await pathExists(workflowsDir)) {
|
|
1451
|
-
await mkdir(workflowsDir, { recursive: true });
|
|
1452
|
-
}
|
|
1453
|
-
let defaultFiles;
|
|
1454
|
-
let sourceDir;
|
|
1455
|
-
try {
|
|
1456
|
-
defaultFiles = (await readdir(DEFAULTS_DIR)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
|
|
1457
|
-
sourceDir = DEFAULTS_DIR;
|
|
1458
|
-
} catch {
|
|
1459
|
-
try {
|
|
1460
|
-
defaultFiles = (await readdir(DEFAULTS_DIR_ALT)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
|
|
1461
|
-
sourceDir = DEFAULTS_DIR_ALT;
|
|
1462
|
-
} catch {
|
|
1463
|
-
logger.warn("No bundled workflow defaults found", { dir: DEFAULTS_DIR });
|
|
1464
|
-
return;
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
for (const file of defaultFiles) {
|
|
1468
|
-
const targetPath = join(workflowsDir, file);
|
|
1469
|
-
try {
|
|
1470
|
-
await copyFile(join(sourceDir, file), targetPath);
|
|
1471
|
-
} catch (err) {
|
|
1472
|
-
logger.error("Failed to copy default workflow", { file, error: err instanceof Error ? err.message : String(err) });
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
async function loadAllWorkflows(configDir) {
|
|
1477
|
-
const workflowsDir = getWorkflowsDir(configDir);
|
|
1478
|
-
if (!await pathExists(workflowsDir)) {
|
|
1436
|
+
async function loadWorkflowsFromDir(dir) {
|
|
1437
|
+
if (!await pathExists(dir)) {
|
|
1479
1438
|
return [];
|
|
1480
1439
|
}
|
|
1481
1440
|
let files;
|
|
1482
1441
|
try {
|
|
1483
|
-
files = (await readdir(
|
|
1442
|
+
files = (await readdir(dir)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
|
|
1484
1443
|
} catch {
|
|
1485
1444
|
return [];
|
|
1486
1445
|
}
|
|
1487
1446
|
const workflows = [];
|
|
1488
1447
|
for (const file of files) {
|
|
1489
1448
|
try {
|
|
1490
|
-
const raw = await readFile(join(
|
|
1449
|
+
const raw = await readFile(join(dir, file), "utf-8");
|
|
1491
1450
|
const parsed = JSON.parse(raw);
|
|
1492
1451
|
if (parsed.metadata?.id && parsed.steps?.length > 0) {
|
|
1493
1452
|
workflows.push(parsed);
|
|
@@ -1500,6 +1459,30 @@ async function loadAllWorkflows(configDir) {
|
|
|
1500
1459
|
}
|
|
1501
1460
|
return workflows;
|
|
1502
1461
|
}
|
|
1462
|
+
async function loadDefaultWorkflows() {
|
|
1463
|
+
let defaults = await loadWorkflowsFromDir(DEFAULTS_DIR);
|
|
1464
|
+
if (!defaults.length) {
|
|
1465
|
+
defaults = await loadWorkflowsFromDir(DEFAULTS_DIR_ALT);
|
|
1466
|
+
}
|
|
1467
|
+
return defaults;
|
|
1468
|
+
}
|
|
1469
|
+
async function loadUserWorkflows(configDir) {
|
|
1470
|
+
return loadWorkflowsFromDir(getWorkflowsDir(configDir));
|
|
1471
|
+
}
|
|
1472
|
+
async function loadAllWorkflows(configDir) {
|
|
1473
|
+
const [defaultWorkflows, userWorkflows] = await Promise.all([
|
|
1474
|
+
loadDefaultWorkflows(),
|
|
1475
|
+
loadUserWorkflows(configDir)
|
|
1476
|
+
]);
|
|
1477
|
+
const workflowMap = /* @__PURE__ */ new Map();
|
|
1478
|
+
for (const workflow of defaultWorkflows) {
|
|
1479
|
+
workflowMap.set(workflow.metadata.id, workflow);
|
|
1480
|
+
}
|
|
1481
|
+
for (const workflow of userWorkflows) {
|
|
1482
|
+
workflowMap.set(workflow.metadata.id, workflow);
|
|
1483
|
+
}
|
|
1484
|
+
return Array.from(workflowMap.values());
|
|
1485
|
+
}
|
|
1503
1486
|
async function getDefaultWorkflowIds() {
|
|
1504
1487
|
for (const dir of [DEFAULTS_DIR, DEFAULTS_DIR_ALT]) {
|
|
1505
1488
|
try {
|
|
@@ -1510,33 +1493,13 @@ async function getDefaultWorkflowIds() {
|
|
|
1510
1493
|
}
|
|
1511
1494
|
return [];
|
|
1512
1495
|
}
|
|
1513
|
-
async function
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
const sourcePath = join(dir, filename);
|
|
1517
|
-
if (await pathExists(sourcePath)) {
|
|
1518
|
-
const targetPath = join(getWorkflowsDir(configDir), filename);
|
|
1519
|
-
await copyFile(sourcePath, targetPath);
|
|
1520
|
-
return true;
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
return false;
|
|
1524
|
-
}
|
|
1525
|
-
async function getModifiedDefaultWorkflowIds(configDir) {
|
|
1526
|
-
return findModifiedDefaultFiles(
|
|
1527
|
-
await getDefaultWorkflowIds(),
|
|
1528
|
-
WORKFLOW_EXTENSION,
|
|
1529
|
-
[DEFAULTS_DIR, DEFAULTS_DIR_ALT],
|
|
1530
|
-
getWorkflowsDir(configDir)
|
|
1531
|
-
);
|
|
1496
|
+
async function getDefaultWorkflowContent(workflowId) {
|
|
1497
|
+
const defaults = await loadDefaultWorkflows();
|
|
1498
|
+
return defaults.find((w) => w.metadata.id === workflowId) ?? null;
|
|
1532
1499
|
}
|
|
1533
|
-
async function
|
|
1534
|
-
const
|
|
1535
|
-
|
|
1536
|
-
for (const id of ids) {
|
|
1537
|
-
if (await restoreDefaultWorkflow(configDir, id)) count++;
|
|
1538
|
-
}
|
|
1539
|
-
return count;
|
|
1500
|
+
async function isDefaultWorkflow(workflowId) {
|
|
1501
|
+
const defaultIds = await getDefaultWorkflowIds();
|
|
1502
|
+
return defaultIds.includes(workflowId);
|
|
1540
1503
|
}
|
|
1541
1504
|
function findWorkflowById(workflowId, workflows) {
|
|
1542
1505
|
return workflows.find((p) => p.metadata.id === workflowId);
|
|
@@ -1554,12 +1517,16 @@ async function saveWorkflow(configDir, workflow) {
|
|
|
1554
1517
|
await writeFile(filePath, JSON.stringify(workflow, null, 2) + "\n", "utf-8");
|
|
1555
1518
|
}
|
|
1556
1519
|
async function deleteWorkflow(configDir, workflowId) {
|
|
1520
|
+
const isDefault = await isDefaultWorkflow(workflowId);
|
|
1521
|
+
if (isDefault) {
|
|
1522
|
+
return { success: false, reason: "Cannot delete built-in defaults" };
|
|
1523
|
+
}
|
|
1557
1524
|
const filePath = join(getWorkflowsDir(configDir), `${workflowId}${WORKFLOW_EXTENSION}`);
|
|
1558
1525
|
try {
|
|
1559
1526
|
await unlink(filePath);
|
|
1560
|
-
return true;
|
|
1527
|
+
return { success: true };
|
|
1561
1528
|
} catch {
|
|
1562
|
-
return false;
|
|
1529
|
+
return { success: false };
|
|
1563
1530
|
}
|
|
1564
1531
|
}
|
|
1565
1532
|
|
|
@@ -4898,102 +4865,47 @@ ${summary}`,
|
|
|
4898
4865
|
}
|
|
4899
4866
|
};
|
|
4900
4867
|
|
|
4901
|
-
// src/server/
|
|
4902
|
-
import {
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
function getCommandsDir(configDir) {
|
|
4908
|
-
return join4(configDir, "commands");
|
|
4909
|
-
}
|
|
4910
|
-
async function ensureDefaultCommands(configDir) {
|
|
4911
|
-
const bundleDir = getBundleDir();
|
|
4912
|
-
const commandsDir = getCommandsDir(configDir);
|
|
4913
|
-
await ensureDir(commandsDir);
|
|
4914
|
-
const ids = await getDefaultIds(bundleDir, DEFAULTS_DIR2, COMMAND_EXTENSION);
|
|
4915
|
-
for (const id of ids) {
|
|
4916
|
-
if (!await restoreDefault(commandsDir, bundleDir, DEFAULTS_DIR2, id, COMMAND_EXTENSION)) {
|
|
4917
|
-
await restoreDefault(commandsDir, bundleDir, DEFAULTS_DIR_ALT2, id, COMMAND_EXTENSION);
|
|
4918
|
-
}
|
|
4919
|
-
}
|
|
4920
|
-
}
|
|
4921
|
-
async function loadAllCommands(configDir) {
|
|
4922
|
-
return loadItems(getCommandsDir(configDir), COMMAND_EXTENSION);
|
|
4923
|
-
}
|
|
4924
|
-
async function getDefaultCommandIds() {
|
|
4925
|
-
const bundleDir = getBundleDir();
|
|
4926
|
-
const ids = await getDefaultIds(bundleDir, DEFAULTS_DIR2, COMMAND_EXTENSION);
|
|
4927
|
-
if (ids.length) return ids;
|
|
4928
|
-
return getDefaultIds(bundleDir, DEFAULTS_DIR_ALT2, COMMAND_EXTENSION);
|
|
4929
|
-
}
|
|
4930
|
-
async function restoreDefaultCommand(configDir, commandId) {
|
|
4931
|
-
const bundleDir = getBundleDir();
|
|
4932
|
-
const commandsDir = getCommandsDir(configDir);
|
|
4933
|
-
return restoreDefault(commandsDir, bundleDir, DEFAULTS_DIR2, commandId, COMMAND_EXTENSION) || restoreDefault(commandsDir, bundleDir, DEFAULTS_DIR_ALT2, commandId, COMMAND_EXTENSION);
|
|
4934
|
-
}
|
|
4935
|
-
async function getModifiedDefaultCommandIds(configDir) {
|
|
4936
|
-
const bundleDir = getBundleDir();
|
|
4937
|
-
const ids = await getDefaultCommandIds();
|
|
4938
|
-
const files = (await readdir2(join4(bundleDir, DEFAULTS_DIR2))).filter((f) => f.endsWith(COMMAND_EXTENSION));
|
|
4939
|
-
return files.map((f) => f.replace(COMMAND_EXTENSION, "")).filter((id) => ids.includes(id));
|
|
4940
|
-
}
|
|
4941
|
-
async function restoreAllDefaultCommands(configDir) {
|
|
4942
|
-
const ids = await getDefaultCommandIds();
|
|
4943
|
-
let count = 0;
|
|
4944
|
-
for (const id of ids) {
|
|
4945
|
-
if (await restoreDefaultCommand(configDir, id)) count++;
|
|
4946
|
-
}
|
|
4947
|
-
return count;
|
|
4948
|
-
}
|
|
4949
|
-
function findCommandById(commandId, commands) {
|
|
4950
|
-
return findById(commandId, commands);
|
|
4951
|
-
}
|
|
4952
|
-
async function commandExists(configDir, commandId) {
|
|
4953
|
-
return dirExists(join4(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`));
|
|
4954
|
-
}
|
|
4955
|
-
async function saveCommand(configDir, command) {
|
|
4956
|
-
return saveItem(getCommandsDir(configDir), command.metadata.id, COMMAND_EXTENSION, command);
|
|
4957
|
-
}
|
|
4958
|
-
async function deleteCommand(configDir, commandId) {
|
|
4959
|
-
return deleteItem(getCommandsDir(configDir), commandId, COMMAND_EXTENSION);
|
|
4868
|
+
// src/server/routes/skills.ts
|
|
4869
|
+
import { Router } from "express";
|
|
4870
|
+
|
|
4871
|
+
// src/server/routes/crud-helpers.ts
|
|
4872
|
+
function computeOverrideIds(defaults, userItems) {
|
|
4873
|
+
return userItems.filter((u) => defaults.some((d) => d.metadata.id === u.metadata.id)).map((u) => u.metadata.id);
|
|
4960
4874
|
}
|
|
4961
4875
|
|
|
4962
4876
|
// src/server/routes/skills.ts
|
|
4963
|
-
import { Router } from "express";
|
|
4964
4877
|
function createSkillRoutes(configDir) {
|
|
4965
4878
|
const router = Router();
|
|
4966
4879
|
router.get("/", async (_req, res) => {
|
|
4967
|
-
const [
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
getModifiedDefaultSkillIds(configDir)
|
|
4880
|
+
const [defaults, userItems] = await Promise.all([
|
|
4881
|
+
loadDefaultSkills(),
|
|
4882
|
+
loadUserSkills(configDir)
|
|
4971
4883
|
]);
|
|
4884
|
+
const overrideIds = computeOverrideIds(defaults, userItems);
|
|
4972
4885
|
res.json({
|
|
4973
|
-
|
|
4886
|
+
defaults: defaults.map((s) => ({
|
|
4887
|
+
...s.metadata,
|
|
4888
|
+
enabled: isSkillEnabled(s.metadata.id)
|
|
4889
|
+
})),
|
|
4890
|
+
userItems: userItems.map((s) => ({
|
|
4974
4891
|
...s.metadata,
|
|
4975
4892
|
enabled: isSkillEnabled(s.metadata.id)
|
|
4976
4893
|
})),
|
|
4977
|
-
|
|
4978
|
-
modifiedIds
|
|
4894
|
+
overrideIds
|
|
4979
4895
|
});
|
|
4980
4896
|
});
|
|
4897
|
+
router.get("/defaults/:id", async (req, res) => {
|
|
4898
|
+
const { id } = req.params;
|
|
4899
|
+
const content = await getDefaultSkillContent(id);
|
|
4900
|
+
if (!content) {
|
|
4901
|
+
return res.status(404).json({ error: "Default skill not found" });
|
|
4902
|
+
}
|
|
4903
|
+
res.json(content);
|
|
4904
|
+
});
|
|
4981
4905
|
router.get("/default-ids", async (_req, res) => {
|
|
4982
4906
|
const ids = await getDefaultSkillIds();
|
|
4983
4907
|
res.json({ ids });
|
|
4984
4908
|
});
|
|
4985
|
-
router.post("/restore-all-defaults", async (_req, res) => {
|
|
4986
|
-
const count = await restoreAllDefaultSkills(configDir);
|
|
4987
|
-
res.json({ success: true, count });
|
|
4988
|
-
});
|
|
4989
|
-
router.post("/:id/restore-default", async (req, res) => {
|
|
4990
|
-
const { id } = req.params;
|
|
4991
|
-
const restored = await restoreDefaultSkill(configDir, id);
|
|
4992
|
-
if (!restored) {
|
|
4993
|
-
return res.status(404).json({ error: "No bundled default found for this skill" });
|
|
4994
|
-
}
|
|
4995
|
-
res.json({ success: true });
|
|
4996
|
-
});
|
|
4997
4909
|
router.post("/:id/toggle", (req, res) => {
|
|
4998
4910
|
const { id } = req.params;
|
|
4999
4911
|
const currentlyEnabled = isSkillEnabled(id);
|
|
@@ -5017,7 +4929,8 @@ function createSkillRoutes(configDir) {
|
|
|
5017
4929
|
if (!/^[a-z0-9-]+$/.test(body.metadata.id)) {
|
|
5018
4930
|
return res.status(400).json({ error: "Skill ID must be lowercase alphanumeric with hyphens only" });
|
|
5019
4931
|
}
|
|
5020
|
-
|
|
4932
|
+
const exists = await skillExists(configDir, body.metadata.id);
|
|
4933
|
+
if (exists) {
|
|
5021
4934
|
return res.status(409).json({ error: "A skill with this ID already exists" });
|
|
5022
4935
|
}
|
|
5023
4936
|
await saveSkill(configDir, body);
|
|
@@ -5025,15 +4938,12 @@ function createSkillRoutes(configDir) {
|
|
|
5025
4938
|
});
|
|
5026
4939
|
router.put("/:id", async (req, res) => {
|
|
5027
4940
|
const { id } = req.params;
|
|
5028
|
-
if (!await skillExists(configDir, id)) {
|
|
5029
|
-
return res.status(404).json({ error: "Skill not found" });
|
|
5030
|
-
}
|
|
5031
|
-
const body = req.body;
|
|
5032
4941
|
const skills = await loadAllSkills(configDir);
|
|
5033
4942
|
const existing = findSkillById(id, skills);
|
|
5034
4943
|
if (!existing) {
|
|
5035
4944
|
return res.status(404).json({ error: "Skill not found" });
|
|
5036
4945
|
}
|
|
4946
|
+
const body = req.body;
|
|
5037
4947
|
const updated = {
|
|
5038
4948
|
metadata: { ...existing.metadata, ...body.metadata, id },
|
|
5039
4949
|
prompt: body.prompt ?? existing.prompt
|
|
@@ -5043,47 +4953,205 @@ function createSkillRoutes(configDir) {
|
|
|
5043
4953
|
});
|
|
5044
4954
|
router.delete("/:id", async (req, res) => {
|
|
5045
4955
|
const { id } = req.params;
|
|
5046
|
-
const
|
|
5047
|
-
if (!
|
|
5048
|
-
return res.status(
|
|
4956
|
+
const result = await deleteSkill(configDir, id);
|
|
4957
|
+
if (!result.success) {
|
|
4958
|
+
return res.status(403).json({ error: result.reason ?? "Cannot delete this skill" });
|
|
5049
4959
|
}
|
|
5050
4960
|
res.json({ success: true });
|
|
5051
4961
|
});
|
|
4962
|
+
router.post("/:id/duplicate", async (req, res) => {
|
|
4963
|
+
const { id } = req.params;
|
|
4964
|
+
const defaults = await loadDefaultSkills();
|
|
4965
|
+
const userItems = await loadUserSkills(configDir);
|
|
4966
|
+
const source = defaults.find((s) => s.metadata.id === id) ?? userItems.find((s) => s.metadata.id === id);
|
|
4967
|
+
if (!source) {
|
|
4968
|
+
return res.status(404).json({ error: "Skill not found" });
|
|
4969
|
+
}
|
|
4970
|
+
const newId = `${id}-copy-${Date.now()}`;
|
|
4971
|
+
const duplicated = {
|
|
4972
|
+
metadata: { ...source.metadata, id: newId, name: `${source.metadata.name} (copy)` },
|
|
4973
|
+
prompt: source.prompt
|
|
4974
|
+
};
|
|
4975
|
+
await saveSkill(configDir, duplicated);
|
|
4976
|
+
res.status(201).json(duplicated);
|
|
4977
|
+
});
|
|
5052
4978
|
return router;
|
|
5053
4979
|
}
|
|
5054
4980
|
|
|
5055
4981
|
// src/server/routes/commands.ts
|
|
5056
4982
|
import { Router as Router2 } from "express";
|
|
4983
|
+
|
|
4984
|
+
// src/server/commands/registry.ts
|
|
4985
|
+
import { join as join5 } from "path";
|
|
4986
|
+
|
|
4987
|
+
// src/server/commands/registry-utils.ts
|
|
4988
|
+
import { readdir as readdir2, readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, access as access3, unlink as unlink2 } from "fs/promises";
|
|
4989
|
+
import { join as join4, dirname as dirname4 } from "path";
|
|
4990
|
+
import { constants as constants3 } from "fs";
|
|
4991
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4992
|
+
import matter from "gray-matter";
|
|
4993
|
+
function getBundleDir() {
|
|
4994
|
+
return dirname4(fileURLToPath3(import.meta.url));
|
|
4995
|
+
}
|
|
4996
|
+
async function dirExists(path) {
|
|
4997
|
+
try {
|
|
4998
|
+
await access3(path, constants3.R_OK);
|
|
4999
|
+
return true;
|
|
5000
|
+
} catch {
|
|
5001
|
+
return false;
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
async function ensureDir(path) {
|
|
5005
|
+
if (!await dirExists(path)) {
|
|
5006
|
+
await mkdir3(path, { recursive: true });
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
async function loadItems(dir, extension) {
|
|
5010
|
+
if (!await dirExists(dir)) return [];
|
|
5011
|
+
let files;
|
|
5012
|
+
try {
|
|
5013
|
+
files = (await readdir2(dir)).filter((f) => f.endsWith(extension));
|
|
5014
|
+
} catch {
|
|
5015
|
+
return [];
|
|
5016
|
+
}
|
|
5017
|
+
const items = [];
|
|
5018
|
+
for (const file of files) {
|
|
5019
|
+
try {
|
|
5020
|
+
const raw = await readFile3(join4(dir, file), "utf-8");
|
|
5021
|
+
const { data, content } = matter(raw);
|
|
5022
|
+
if (data.id && content.trim()) {
|
|
5023
|
+
items.push({ metadata: data, prompt: content.trim() });
|
|
5024
|
+
} else {
|
|
5025
|
+
logger.warn(`Skipping invalid ${extension} file`, { file });
|
|
5026
|
+
}
|
|
5027
|
+
} catch (err) {
|
|
5028
|
+
logger.warn(`Failed to parse ${extension} file`, { file, error: err instanceof Error ? err.message : String(err) });
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
return items;
|
|
5032
|
+
}
|
|
5033
|
+
async function saveItem(dir, id, extension, item) {
|
|
5034
|
+
await ensureDir(dir);
|
|
5035
|
+
const filePath = join4(dir, `${id}${extension}`);
|
|
5036
|
+
const content = matter.stringify(item.prompt, item.metadata);
|
|
5037
|
+
await writeFile3(filePath, content, "utf-8");
|
|
5038
|
+
}
|
|
5039
|
+
async function deleteItem(dir, id, extension) {
|
|
5040
|
+
const filePath = join4(dir, `${id}${extension}`);
|
|
5041
|
+
try {
|
|
5042
|
+
await unlink2(filePath);
|
|
5043
|
+
return true;
|
|
5044
|
+
} catch {
|
|
5045
|
+
return false;
|
|
5046
|
+
}
|
|
5047
|
+
}
|
|
5048
|
+
function findById(id, items) {
|
|
5049
|
+
return items.find((i) => i.metadata.id === id);
|
|
5050
|
+
}
|
|
5051
|
+
async function getDefaultIds(bundleDir, defaultsDir, extension) {
|
|
5052
|
+
try {
|
|
5053
|
+
const files = (await readdir2(join4(bundleDir, defaultsDir))).filter((f) => f.endsWith(extension));
|
|
5054
|
+
return files.map((f) => f.replace(extension, ""));
|
|
5055
|
+
} catch {
|
|
5056
|
+
return [];
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
async function loadDefaults(bundleDir, defaultsDir, extension) {
|
|
5060
|
+
const dir = join4(bundleDir, defaultsDir);
|
|
5061
|
+
return loadItems(dir, extension);
|
|
5062
|
+
}
|
|
5063
|
+
|
|
5064
|
+
// src/server/commands/registry.ts
|
|
5065
|
+
var DEFAULTS_DIR2 = "defaults";
|
|
5066
|
+
var DEFAULTS_DIR_ALT2 = "command-defaults";
|
|
5067
|
+
var COMMAND_EXTENSION = ".command.md";
|
|
5068
|
+
function getCommandsDir(configDir) {
|
|
5069
|
+
return join5(configDir, "commands");
|
|
5070
|
+
}
|
|
5071
|
+
async function loadDefaultCommands() {
|
|
5072
|
+
const bundleDir = getBundleDir();
|
|
5073
|
+
let defaults = await loadDefaults(bundleDir, DEFAULTS_DIR2, COMMAND_EXTENSION);
|
|
5074
|
+
if (!defaults.length) {
|
|
5075
|
+
defaults = await loadDefaults(bundleDir, DEFAULTS_DIR_ALT2, COMMAND_EXTENSION);
|
|
5076
|
+
}
|
|
5077
|
+
return defaults;
|
|
5078
|
+
}
|
|
5079
|
+
async function loadUserCommands(configDir) {
|
|
5080
|
+
return loadItems(getCommandsDir(configDir), COMMAND_EXTENSION);
|
|
5081
|
+
}
|
|
5082
|
+
async function loadAllCommands(configDir) {
|
|
5083
|
+
const [defaultCommands, userCommands] = await Promise.all([
|
|
5084
|
+
loadDefaultCommands(),
|
|
5085
|
+
loadUserCommands(configDir)
|
|
5086
|
+
]);
|
|
5087
|
+
const commandMap = /* @__PURE__ */ new Map();
|
|
5088
|
+
for (const cmd of defaultCommands) {
|
|
5089
|
+
commandMap.set(cmd.metadata.id, cmd);
|
|
5090
|
+
}
|
|
5091
|
+
for (const cmd of userCommands) {
|
|
5092
|
+
commandMap.set(cmd.metadata.id, cmd);
|
|
5093
|
+
}
|
|
5094
|
+
return Array.from(commandMap.values());
|
|
5095
|
+
}
|
|
5096
|
+
async function getDefaultCommandIds() {
|
|
5097
|
+
const bundleDir = getBundleDir();
|
|
5098
|
+
const ids = await getDefaultIds(bundleDir, DEFAULTS_DIR2, COMMAND_EXTENSION);
|
|
5099
|
+
if (ids.length) return ids;
|
|
5100
|
+
return getDefaultIds(bundleDir, DEFAULTS_DIR_ALT2, COMMAND_EXTENSION);
|
|
5101
|
+
}
|
|
5102
|
+
async function getDefaultCommandContent(commandId) {
|
|
5103
|
+
const defaults = await loadDefaultCommands();
|
|
5104
|
+
return defaults.find((c) => c.metadata.id === commandId) ?? null;
|
|
5105
|
+
}
|
|
5106
|
+
async function isDefaultCommand(commandId) {
|
|
5107
|
+
const defaultIds = await getDefaultCommandIds();
|
|
5108
|
+
return defaultIds.includes(commandId);
|
|
5109
|
+
}
|
|
5110
|
+
function findCommandById(commandId, commands) {
|
|
5111
|
+
return findById(commandId, commands);
|
|
5112
|
+
}
|
|
5113
|
+
async function commandExists(configDir, commandId) {
|
|
5114
|
+
return dirExists(join5(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`));
|
|
5115
|
+
}
|
|
5116
|
+
async function saveCommand(configDir, command) {
|
|
5117
|
+
return saveItem(getCommandsDir(configDir), command.metadata.id, COMMAND_EXTENSION, command);
|
|
5118
|
+
}
|
|
5119
|
+
async function deleteCommand(configDir, commandId) {
|
|
5120
|
+
const isDefault = await isDefaultCommand(commandId);
|
|
5121
|
+
if (isDefault) {
|
|
5122
|
+
return { success: false, reason: "Cannot delete built-in defaults" };
|
|
5123
|
+
}
|
|
5124
|
+
const deleted = await deleteItem(getCommandsDir(configDir), commandId, COMMAND_EXTENSION);
|
|
5125
|
+
return { success: deleted };
|
|
5126
|
+
}
|
|
5127
|
+
|
|
5128
|
+
// src/server/routes/commands.ts
|
|
5057
5129
|
function createCommandRoutes(configDir) {
|
|
5058
5130
|
const router = Router2();
|
|
5059
5131
|
router.get("/", async (_req, res) => {
|
|
5060
|
-
const [
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
getModifiedDefaultCommandIds(configDir)
|
|
5132
|
+
const [defaults, userItems] = await Promise.all([
|
|
5133
|
+
loadDefaultCommands(),
|
|
5134
|
+
loadUserCommands(configDir)
|
|
5064
5135
|
]);
|
|
5136
|
+
const overrideIds = computeOverrideIds(defaults, userItems);
|
|
5065
5137
|
res.json({
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5138
|
+
defaults: defaults.map((c) => c.metadata),
|
|
5139
|
+
userItems: userItems.map((c) => c.metadata),
|
|
5140
|
+
overrideIds
|
|
5069
5141
|
});
|
|
5070
5142
|
});
|
|
5143
|
+
router.get("/defaults/:id", async (req, res) => {
|
|
5144
|
+
const { id } = req.params;
|
|
5145
|
+
const content = await getDefaultCommandContent(id);
|
|
5146
|
+
if (!content) {
|
|
5147
|
+
return res.status(404).json({ error: "Default command not found" });
|
|
5148
|
+
}
|
|
5149
|
+
res.json(content);
|
|
5150
|
+
});
|
|
5071
5151
|
router.get("/default-ids", async (_req, res) => {
|
|
5072
5152
|
const ids = await getDefaultCommandIds();
|
|
5073
5153
|
res.json({ ids });
|
|
5074
5154
|
});
|
|
5075
|
-
router.post("/restore-all-defaults", async (_req, res) => {
|
|
5076
|
-
const count = await restoreAllDefaultCommands(configDir);
|
|
5077
|
-
res.json({ success: true, count });
|
|
5078
|
-
});
|
|
5079
|
-
router.post("/:id/restore-default", async (req, res) => {
|
|
5080
|
-
const { id } = req.params;
|
|
5081
|
-
const restored = await restoreDefaultCommand(configDir, id);
|
|
5082
|
-
if (!restored) {
|
|
5083
|
-
return res.status(404).json({ error: "No bundled default found for this command" });
|
|
5084
|
-
}
|
|
5085
|
-
res.json({ success: true });
|
|
5086
|
-
});
|
|
5087
5155
|
router.get("/:id", async (req, res) => {
|
|
5088
5156
|
const { id } = req.params;
|
|
5089
5157
|
const commands = await loadAllCommands(configDir);
|
|
@@ -5101,7 +5169,8 @@ function createCommandRoutes(configDir) {
|
|
|
5101
5169
|
if (!/^[a-z0-9-]+$/.test(body.metadata.id)) {
|
|
5102
5170
|
return res.status(400).json({ error: "Command ID must be lowercase alphanumeric with hyphens only" });
|
|
5103
5171
|
}
|
|
5104
|
-
|
|
5172
|
+
const exists = await commandExists(configDir, body.metadata.id);
|
|
5173
|
+
if (exists) {
|
|
5105
5174
|
return res.status(409).json({ error: "A command with this ID already exists" });
|
|
5106
5175
|
}
|
|
5107
5176
|
await saveCommand(configDir, body);
|
|
@@ -5109,15 +5178,12 @@ function createCommandRoutes(configDir) {
|
|
|
5109
5178
|
});
|
|
5110
5179
|
router.put("/:id", async (req, res) => {
|
|
5111
5180
|
const { id } = req.params;
|
|
5112
|
-
if (!await commandExists(configDir, id)) {
|
|
5113
|
-
return res.status(404).json({ error: "Command not found" });
|
|
5114
|
-
}
|
|
5115
|
-
const body = req.body;
|
|
5116
5181
|
const commands = await loadAllCommands(configDir);
|
|
5117
5182
|
const existing = findCommandById(id, commands);
|
|
5118
5183
|
if (!existing) {
|
|
5119
5184
|
return res.status(404).json({ error: "Command not found" });
|
|
5120
5185
|
}
|
|
5186
|
+
const body = req.body;
|
|
5121
5187
|
const updated = {
|
|
5122
5188
|
metadata: { ...existing.metadata, ...body.metadata, id },
|
|
5123
5189
|
prompt: body.prompt ?? existing.prompt
|
|
@@ -5127,12 +5193,28 @@ function createCommandRoutes(configDir) {
|
|
|
5127
5193
|
});
|
|
5128
5194
|
router.delete("/:id", async (req, res) => {
|
|
5129
5195
|
const { id } = req.params;
|
|
5130
|
-
const
|
|
5131
|
-
if (!
|
|
5132
|
-
return res.status(
|
|
5196
|
+
const result = await deleteCommand(configDir, id);
|
|
5197
|
+
if (!result.success) {
|
|
5198
|
+
return res.status(403).json({ error: result.reason ?? "Cannot delete this command" });
|
|
5133
5199
|
}
|
|
5134
5200
|
res.json({ success: true });
|
|
5135
5201
|
});
|
|
5202
|
+
router.post("/:id/duplicate", async (req, res) => {
|
|
5203
|
+
const { id } = req.params;
|
|
5204
|
+
const defaults = await loadDefaultCommands();
|
|
5205
|
+
const userItems = await loadUserCommands(configDir);
|
|
5206
|
+
const source = defaults.find((c) => c.metadata.id === id) ?? userItems.find((c) => c.metadata.id === id);
|
|
5207
|
+
if (!source) {
|
|
5208
|
+
return res.status(404).json({ error: "Command not found" });
|
|
5209
|
+
}
|
|
5210
|
+
const newId = `${id}-copy-${Date.now()}`;
|
|
5211
|
+
const duplicated = {
|
|
5212
|
+
metadata: { ...source.metadata, id: newId, name: `${source.metadata.name} (copy)` },
|
|
5213
|
+
prompt: source.prompt
|
|
5214
|
+
};
|
|
5215
|
+
await saveCommand(configDir, duplicated);
|
|
5216
|
+
res.status(201).json(duplicated);
|
|
5217
|
+
});
|
|
5136
5218
|
return router;
|
|
5137
5219
|
}
|
|
5138
5220
|
|
|
@@ -5141,33 +5223,29 @@ import { Router as Router3 } from "express";
|
|
|
5141
5223
|
function createAgentRoutes(configDir) {
|
|
5142
5224
|
const router = Router3();
|
|
5143
5225
|
router.get("/", async (_req, res) => {
|
|
5144
|
-
const [
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
getModifiedDefaultAgentIds(configDir)
|
|
5226
|
+
const [defaults, userItems] = await Promise.all([
|
|
5227
|
+
loadDefaultAgents(),
|
|
5228
|
+
loadUserAgents(configDir)
|
|
5148
5229
|
]);
|
|
5230
|
+
const overrideIds = computeOverrideIds(defaults, userItems);
|
|
5149
5231
|
res.json({
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5232
|
+
defaults: defaults.map((a) => a.metadata),
|
|
5233
|
+
userItems: userItems.map((a) => a.metadata),
|
|
5234
|
+
overrideIds
|
|
5153
5235
|
});
|
|
5154
5236
|
});
|
|
5237
|
+
router.get("/defaults/:id", async (req, res) => {
|
|
5238
|
+
const { id } = req.params;
|
|
5239
|
+
const content = await getDefaultAgentContent(id);
|
|
5240
|
+
if (!content) {
|
|
5241
|
+
return res.status(404).json({ error: "Default agent not found" });
|
|
5242
|
+
}
|
|
5243
|
+
res.json(content);
|
|
5244
|
+
});
|
|
5155
5245
|
router.get("/default-ids", async (_req, res) => {
|
|
5156
5246
|
const ids = await getDefaultAgentIds();
|
|
5157
5247
|
res.json({ ids });
|
|
5158
5248
|
});
|
|
5159
|
-
router.post("/restore-all-defaults", async (_req, res) => {
|
|
5160
|
-
const count = await restoreAllDefaultAgents(configDir);
|
|
5161
|
-
res.json({ success: true, count });
|
|
5162
|
-
});
|
|
5163
|
-
router.post("/:id/restore-default", async (req, res) => {
|
|
5164
|
-
const { id } = req.params;
|
|
5165
|
-
const restored = await restoreDefaultAgent(configDir, id);
|
|
5166
|
-
if (!restored) {
|
|
5167
|
-
return res.status(404).json({ error: "No bundled default found for this agent" });
|
|
5168
|
-
}
|
|
5169
|
-
res.json({ success: true });
|
|
5170
|
-
});
|
|
5171
5249
|
router.get("/:id", async (req, res) => {
|
|
5172
5250
|
const { id } = req.params;
|
|
5173
5251
|
const agents = await loadAllAgents(configDir);
|
|
@@ -5182,7 +5260,8 @@ function createAgentRoutes(configDir) {
|
|
|
5182
5260
|
if (!body?.metadata?.id || !body?.prompt) {
|
|
5183
5261
|
return res.status(400).json({ error: "Missing required fields: metadata.id, prompt" });
|
|
5184
5262
|
}
|
|
5185
|
-
|
|
5263
|
+
const exists = await agentExists(configDir, body.metadata.id);
|
|
5264
|
+
if (exists) {
|
|
5186
5265
|
return res.status(409).json({ error: "An agent with this ID already exists" });
|
|
5187
5266
|
}
|
|
5188
5267
|
await saveAgent(configDir, body);
|
|
@@ -5208,12 +5287,28 @@ function createAgentRoutes(configDir) {
|
|
|
5208
5287
|
});
|
|
5209
5288
|
router.delete("/:id", async (req, res) => {
|
|
5210
5289
|
const { id } = req.params;
|
|
5211
|
-
const
|
|
5212
|
-
if (!
|
|
5213
|
-
return res.status(
|
|
5290
|
+
const result = await deleteAgent(configDir, id);
|
|
5291
|
+
if (!result.success) {
|
|
5292
|
+
return res.status(403).json({ error: result.reason ?? "Cannot delete this agent" });
|
|
5214
5293
|
}
|
|
5215
5294
|
res.json({ success: true });
|
|
5216
5295
|
});
|
|
5296
|
+
router.post("/:id/duplicate", async (req, res) => {
|
|
5297
|
+
const { id } = req.params;
|
|
5298
|
+
const defaults = await loadDefaultAgents();
|
|
5299
|
+
const userItems = await loadUserAgents(configDir);
|
|
5300
|
+
const source = defaults.find((a) => a.metadata.id === id) ?? userItems.find((a) => a.metadata.id === id);
|
|
5301
|
+
if (!source) {
|
|
5302
|
+
return res.status(404).json({ error: "Agent not found" });
|
|
5303
|
+
}
|
|
5304
|
+
const newId = `${id}-copy-${Date.now()}`;
|
|
5305
|
+
const duplicated = {
|
|
5306
|
+
metadata: { ...source.metadata, id: newId, name: `${source.metadata.name} (copy)` },
|
|
5307
|
+
prompt: source.prompt
|
|
5308
|
+
};
|
|
5309
|
+
await saveAgent(configDir, duplicated);
|
|
5310
|
+
res.status(201).json(duplicated);
|
|
5311
|
+
});
|
|
5217
5312
|
return router;
|
|
5218
5313
|
}
|
|
5219
5314
|
|
|
@@ -5222,37 +5317,33 @@ import { Router as Router4 } from "express";
|
|
|
5222
5317
|
function createWorkflowRoutes(configDir, config) {
|
|
5223
5318
|
const router = Router4();
|
|
5224
5319
|
router.get("/", async (_req, res) => {
|
|
5225
|
-
const [
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
getModifiedDefaultWorkflowIds(configDir)
|
|
5320
|
+
const [defaults, userItems] = await Promise.all([
|
|
5321
|
+
loadDefaultWorkflows(),
|
|
5322
|
+
loadUserWorkflows(configDir)
|
|
5229
5323
|
]);
|
|
5324
|
+
const overrideIds = computeOverrideIds(defaults, userItems);
|
|
5230
5325
|
res.json({
|
|
5231
|
-
|
|
5326
|
+
defaults: defaults.map((p) => ({ ...p.metadata, startCondition: p.startCondition })),
|
|
5327
|
+
userItems: userItems.map((p) => ({ ...p.metadata, startCondition: p.startCondition })),
|
|
5232
5328
|
activeWorkflowId: config.activeWorkflowId ?? "default",
|
|
5233
|
-
|
|
5234
|
-
modifiedIds
|
|
5329
|
+
overrideIds
|
|
5235
5330
|
});
|
|
5236
5331
|
});
|
|
5237
5332
|
router.get("/template-variables", (_req, res) => {
|
|
5238
5333
|
res.json({ variables: TEMPLATE_VARIABLES });
|
|
5239
5334
|
});
|
|
5335
|
+
router.get("/defaults/:id", async (req, res) => {
|
|
5336
|
+
const { id } = req.params;
|
|
5337
|
+
const content = await getDefaultWorkflowContent(id);
|
|
5338
|
+
if (!content) {
|
|
5339
|
+
return res.status(404).json({ error: "Default workflow not found" });
|
|
5340
|
+
}
|
|
5341
|
+
res.json(content);
|
|
5342
|
+
});
|
|
5240
5343
|
router.get("/default-ids", async (_req, res) => {
|
|
5241
5344
|
const ids = await getDefaultWorkflowIds();
|
|
5242
5345
|
res.json({ ids });
|
|
5243
5346
|
});
|
|
5244
|
-
router.post("/restore-all-defaults", async (_req, res) => {
|
|
5245
|
-
const count = await restoreAllDefaultWorkflows(configDir);
|
|
5246
|
-
res.json({ success: true, count });
|
|
5247
|
-
});
|
|
5248
|
-
router.post("/:id/restore-default", async (req, res) => {
|
|
5249
|
-
const { id } = req.params;
|
|
5250
|
-
const restored = await restoreDefaultWorkflow(configDir, id);
|
|
5251
|
-
if (!restored) {
|
|
5252
|
-
return res.status(404).json({ error: "No bundled default found for this workflow" });
|
|
5253
|
-
}
|
|
5254
|
-
res.json({ success: true });
|
|
5255
|
-
});
|
|
5256
5347
|
router.get("/:id", async (req, res) => {
|
|
5257
5348
|
const { id } = req.params;
|
|
5258
5349
|
const workflows = await loadAllWorkflows(configDir);
|
|
@@ -5267,7 +5358,8 @@ function createWorkflowRoutes(configDir, config) {
|
|
|
5267
5358
|
if (!body?.metadata?.id || !body?.steps?.length) {
|
|
5268
5359
|
return res.status(400).json({ error: "Missing required fields: metadata.id, steps" });
|
|
5269
5360
|
}
|
|
5270
|
-
|
|
5361
|
+
const exists = await workflowExists(configDir, body.metadata.id);
|
|
5362
|
+
if (exists) {
|
|
5271
5363
|
return res.status(409).json({ error: "A workflow with this ID already exists" });
|
|
5272
5364
|
}
|
|
5273
5365
|
await saveWorkflow(configDir, body);
|
|
@@ -5275,7 +5367,9 @@ function createWorkflowRoutes(configDir, config) {
|
|
|
5275
5367
|
});
|
|
5276
5368
|
router.put("/:id", async (req, res) => {
|
|
5277
5369
|
const { id } = req.params;
|
|
5278
|
-
|
|
5370
|
+
const workflows = await loadAllWorkflows(configDir);
|
|
5371
|
+
const existing = findWorkflowById(id, workflows);
|
|
5372
|
+
if (!existing) {
|
|
5279
5373
|
return res.status(404).json({ error: "Workflow not found" });
|
|
5280
5374
|
}
|
|
5281
5375
|
const body = req.body;
|
|
@@ -5288,14 +5382,27 @@ function createWorkflowRoutes(configDir, config) {
|
|
|
5288
5382
|
});
|
|
5289
5383
|
router.delete("/:id", async (req, res) => {
|
|
5290
5384
|
const { id } = req.params;
|
|
5291
|
-
|
|
5292
|
-
|
|
5385
|
+
const result = await deleteWorkflow(configDir, id);
|
|
5386
|
+
if (!result.success) {
|
|
5387
|
+
return res.status(403).json({ error: result.reason ?? "Cannot delete this workflow" });
|
|
5293
5388
|
}
|
|
5294
|
-
|
|
5295
|
-
|
|
5389
|
+
res.json({ success: true });
|
|
5390
|
+
});
|
|
5391
|
+
router.post("/:id/duplicate", async (req, res) => {
|
|
5392
|
+
const { id } = req.params;
|
|
5393
|
+
const defaults = await loadDefaultWorkflows();
|
|
5394
|
+
const userItems = await loadUserWorkflows(configDir);
|
|
5395
|
+
const source = defaults.find((w) => w.metadata.id === id) ?? userItems.find((w) => w.metadata.id === id);
|
|
5396
|
+
if (!source) {
|
|
5296
5397
|
return res.status(404).json({ error: "Workflow not found" });
|
|
5297
5398
|
}
|
|
5298
|
-
|
|
5399
|
+
const newId = `${id}-copy-${Date.now()}`;
|
|
5400
|
+
const duplicated = {
|
|
5401
|
+
...source,
|
|
5402
|
+
metadata: { ...source.metadata, id: newId, name: `${source.metadata.name} (copy)` }
|
|
5403
|
+
};
|
|
5404
|
+
await saveWorkflow(configDir, duplicated);
|
|
5405
|
+
res.status(201).json(duplicated);
|
|
5299
5406
|
});
|
|
5300
5407
|
return router;
|
|
5301
5408
|
}
|
|
@@ -5419,10 +5526,10 @@ function createTerminalRoutes() {
|
|
|
5419
5526
|
}
|
|
5420
5527
|
|
|
5421
5528
|
// src/constants.ts
|
|
5422
|
-
var VERSION = "1.6.
|
|
5529
|
+
var VERSION = "1.6.16";
|
|
5423
5530
|
|
|
5424
5531
|
// src/server/index.ts
|
|
5425
|
-
var __dirname2 =
|
|
5532
|
+
var __dirname2 = dirname5(fileURLToPath4(import.meta.url));
|
|
5426
5533
|
async function createServerHandle(config) {
|
|
5427
5534
|
setRuntimeConfig(config);
|
|
5428
5535
|
setLogLevel(config.logging?.level ?? void 0, config.mode);
|
|
@@ -5430,10 +5537,6 @@ async function createServerHandle(config) {
|
|
|
5430
5537
|
const db = initDatabase(config);
|
|
5431
5538
|
initEventStore(db);
|
|
5432
5539
|
const configDir = getGlobalConfigDir(config.mode ?? "production");
|
|
5433
|
-
await ensureDefaultSkills(configDir);
|
|
5434
|
-
await ensureDefaultCommands(configDir);
|
|
5435
|
-
await ensureDefaultAgents(configDir);
|
|
5436
|
-
await ensureDefaultWorkflows(configDir);
|
|
5437
5540
|
const providerManager = createProviderManager(config);
|
|
5438
5541
|
const sessionManager = new SessionManager(providerManager);
|
|
5439
5542
|
const useMock = process.env["OPENFOX_MOCK_LLM"] === "true";
|
|
@@ -5725,7 +5828,7 @@ async function createServerHandle(config) {
|
|
|
5725
5828
|
if (!callId || approved === void 0) {
|
|
5726
5829
|
return res.status(400).json({ error: "callId and approved are required" });
|
|
5727
5830
|
}
|
|
5728
|
-
const { providePathConfirmation: providePathConfirmation2 } = await import("./tools-
|
|
5831
|
+
const { providePathConfirmation: providePathConfirmation2 } = await import("./tools-55YICCVH.js");
|
|
5729
5832
|
const result = providePathConfirmation2(callId, approved, alwaysAllow);
|
|
5730
5833
|
if (!result.found) {
|
|
5731
5834
|
return res.status(404).json({ error: "No pending path confirmation with that ID" });
|
|
@@ -5750,7 +5853,7 @@ async function createServerHandle(config) {
|
|
|
5750
5853
|
if (!callId || !answer) {
|
|
5751
5854
|
return res.status(400).json({ error: "callId and answer are required" });
|
|
5752
5855
|
}
|
|
5753
|
-
const { provideAnswer: provideAnswer2 } = await import("./tools-
|
|
5856
|
+
const { provideAnswer: provideAnswer2 } = await import("./tools-55YICCVH.js");
|
|
5754
5857
|
const found = provideAnswer2(callId, answer);
|
|
5755
5858
|
if (!found) {
|
|
5756
5859
|
return res.status(404).json({ error: "No pending question with that ID" });
|
|
@@ -5786,8 +5889,8 @@ async function createServerHandle(config) {
|
|
|
5786
5889
|
if (!session) {
|
|
5787
5890
|
return res.status(404).json({ error: "Session not found" });
|
|
5788
5891
|
}
|
|
5789
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
5790
|
-
const { cancelQuestionsForSession: cancelQuestionsForSession2, cancelPathConfirmationsForSession: cancelPathConfirmationsForSession2 } = await import("./tools-
|
|
5892
|
+
const { stopSessionExecution } = await import("./chat-handler-IY2XVOO6.js");
|
|
5893
|
+
const { cancelQuestionsForSession: cancelQuestionsForSession2, cancelPathConfirmationsForSession: cancelPathConfirmationsForSession2 } = await import("./tools-55YICCVH.js");
|
|
5791
5894
|
stopSessionExecution(sessionId, sessionManager);
|
|
5792
5895
|
abortSession(sessionId);
|
|
5793
5896
|
cancelQuestionsForSession2(sessionId, "Session stopped by user");
|
|
@@ -6107,9 +6210,9 @@ async function createServerHandle(config) {
|
|
|
6107
6210
|
const entries = await import("fs/promises").then((m) => m.readdir(resolvedPath, { withFileTypes: true }));
|
|
6108
6211
|
const directories = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => ({
|
|
6109
6212
|
name: entry.name,
|
|
6110
|
-
path:
|
|
6213
|
+
path: join6(resolvedPath, entry.name)
|
|
6111
6214
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
6112
|
-
const parent =
|
|
6215
|
+
const parent = dirname5(resolvedPath);
|
|
6113
6216
|
const hasParent = parent !== resolvedPath;
|
|
6114
6217
|
res.json({
|
|
6115
6218
|
current: resolvedPath,
|
|
@@ -6154,7 +6257,7 @@ async function createServerHandle(config) {
|
|
|
6154
6257
|
}
|
|
6155
6258
|
});
|
|
6156
6259
|
app.get("/fox.svg", (_req, res) => {
|
|
6157
|
-
|
|
6260
|
+
readFile4(join6(webDir, "fox.svg")).then((content) => {
|
|
6158
6261
|
res.set("Content-Type", "image/svg+xml");
|
|
6159
6262
|
res.send(content);
|
|
6160
6263
|
}).catch(() => {
|
|
@@ -6163,7 +6266,7 @@ async function createServerHandle(config) {
|
|
|
6163
6266
|
});
|
|
6164
6267
|
app.use(
|
|
6165
6268
|
"/sounds",
|
|
6166
|
-
express.static(
|
|
6269
|
+
express.static(join6(webDir, "public", "sounds"), {
|
|
6167
6270
|
setHeaders: (res) => {
|
|
6168
6271
|
res.set("Content-Type", "audio/mpeg");
|
|
6169
6272
|
}
|
|
@@ -6173,7 +6276,7 @@ async function createServerHandle(config) {
|
|
|
6173
6276
|
if (req.path.startsWith("/api/")) {
|
|
6174
6277
|
return;
|
|
6175
6278
|
}
|
|
6176
|
-
|
|
6279
|
+
readFile4(join6(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
|
|
6177
6280
|
logger.error("Error serving index.html", { error: err });
|
|
6178
6281
|
res.status(500).send("Server error");
|
|
6179
6282
|
});
|
|
@@ -6184,7 +6287,7 @@ async function createServerHandle(config) {
|
|
|
6184
6287
|
const distWebDir = resolve(__dirname2, "web");
|
|
6185
6288
|
app.use(
|
|
6186
6289
|
"/assets",
|
|
6187
|
-
express.static(
|
|
6290
|
+
express.static(join6(distWebDir, "assets"), {
|
|
6188
6291
|
setHeaders: (res, filepath) => {
|
|
6189
6292
|
if (filepath.endsWith(".css")) {
|
|
6190
6293
|
res.set("Content-Type", "text/css");
|
|
@@ -6192,11 +6295,11 @@ async function createServerHandle(config) {
|
|
|
6192
6295
|
}
|
|
6193
6296
|
})
|
|
6194
6297
|
);
|
|
6195
|
-
app.use("/manifest.webmanifest", express.static(
|
|
6196
|
-
app.use("/registerSW.js", express.static(
|
|
6197
|
-
app.use("/sw.js", express.static(
|
|
6298
|
+
app.use("/manifest.webmanifest", express.static(join6(distWebDir, "manifest.webmanifest")));
|
|
6299
|
+
app.use("/registerSW.js", express.static(join6(distWebDir, "registerSW.js")));
|
|
6300
|
+
app.use("/sw.js", express.static(join6(distWebDir, "sw.js")));
|
|
6198
6301
|
app.get("/fox.svg", (_req, res) => {
|
|
6199
|
-
|
|
6302
|
+
readFile4(join6(distWebDir, "fox.svg")).then((content) => {
|
|
6200
6303
|
res.set("Content-Type", "image/svg+xml");
|
|
6201
6304
|
res.send(content);
|
|
6202
6305
|
}).catch(() => {
|
|
@@ -6205,14 +6308,14 @@ async function createServerHandle(config) {
|
|
|
6205
6308
|
});
|
|
6206
6309
|
app.use(
|
|
6207
6310
|
"/sounds",
|
|
6208
|
-
express.static(
|
|
6311
|
+
express.static(join6(distWebDir, "sounds"), {
|
|
6209
6312
|
setHeaders: (res) => {
|
|
6210
6313
|
res.set("Content-Type", "audio/mpeg");
|
|
6211
6314
|
}
|
|
6212
6315
|
})
|
|
6213
6316
|
);
|
|
6214
6317
|
app.get("/", (_req, res) => {
|
|
6215
|
-
|
|
6318
|
+
readFile4(join6(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
6216
6319
|
res.status(404).send("Web UI not built. Run `npm run build:web`");
|
|
6217
6320
|
});
|
|
6218
6321
|
});
|
|
@@ -6220,7 +6323,7 @@ async function createServerHandle(config) {
|
|
|
6220
6323
|
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") {
|
|
6221
6324
|
return;
|
|
6222
6325
|
}
|
|
6223
|
-
|
|
6326
|
+
readFile4(join6(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
6224
6327
|
res.status(404).send("Web UI not built");
|
|
6225
6328
|
});
|
|
6226
6329
|
});
|
|
@@ -6235,7 +6338,7 @@ async function createServerHandle(config) {
|
|
|
6235
6338
|
providerManager
|
|
6236
6339
|
);
|
|
6237
6340
|
const wss = wssExports.wss;
|
|
6238
|
-
const { QueueProcessor } = await import("./processor-
|
|
6341
|
+
const { QueueProcessor } = await import("./processor-VUEJM73B.js");
|
|
6239
6342
|
const queueProcessor = new QueueProcessor({
|
|
6240
6343
|
sessionManager,
|
|
6241
6344
|
providerManager,
|
|
@@ -6308,4 +6411,4 @@ export {
|
|
|
6308
6411
|
createServerHandle,
|
|
6309
6412
|
createServer
|
|
6310
6413
|
};
|
|
6311
|
-
//# sourceMappingURL=chunk-
|
|
6414
|
+
//# sourceMappingURL=chunk-NN65D5SI.js.map
|