openfox 1.6.14 → 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.
Files changed (39) hide show
  1. package/dist/{auto-compaction-C4PMBB24.js → auto-compaction-2RKC6DC2.js} +5 -5
  2. package/dist/{chat-handler-US3QOOE4.js → chat-handler-IY2XVOO6.js} +26 -56
  3. package/dist/{chunk-7HLRI6JM.js → chunk-2KP34IDL.js} +161 -204
  4. package/dist/{chunk-N25QUEPO.js → chunk-4OI4VPZ6.js} +434 -812
  5. package/dist/{chunk-XFXOSPYH.js → chunk-55N6FAAZ.js} +1 -1
  6. package/dist/{chunk-5GE3QJSZ.js → chunk-6L3X7T4K.js} +82 -160
  7. package/dist/{chunk-QDEKU5RL.js → chunk-F54ZJN4X.js} +38 -2
  8. package/dist/{chunk-UL4JYQKK.js → chunk-IN5EP4ZB.js} +2 -2
  9. package/dist/{chunk-OOIRCXAY.js → chunk-KOUMYBYM.js} +53 -112
  10. package/dist/{chunk-3JU6H6A4.js → chunk-NN65D5SI.js} +426 -448
  11. package/dist/{chunk-3XZ23PXM.js → chunk-OVLFEBRR.js} +76 -92
  12. package/dist/chunk-SN7OBEVL.js +44 -0
  13. package/dist/{chunk-PCOG5FQD.js → chunk-T5PBG2PE.js} +6 -6
  14. package/dist/{chunk-H22VHHQ4.js → chunk-U54QVKL2.js} +4 -4
  15. package/dist/{chunk-J2DHVXRX.js → chunk-ZDNXCVW4.js} +2 -2
  16. package/dist/cli/dev.js +1 -1
  17. package/dist/cli/index.js +1 -1
  18. package/dist/{config-DEM6ASQM.js → config-67AX6CNS.js} +5 -5
  19. package/dist/{events-VDAC7E7K.js → events-2ETDOE5B.js} +3 -3
  20. package/dist/{folding-NDFQCISZ.js → folding-M7FMUBOL.js} +6 -4
  21. package/dist/{orchestrator-KZI7B5IS.js → orchestrator-U5VCLBYQ.js} +6 -6
  22. package/dist/package.json +13 -3
  23. package/dist/{processor-KBSF2HFD.js → processor-VUEJM73B.js} +24 -49
  24. package/dist/{provider-K3PHZO27.js → provider-DKGBQHUS.js} +7 -7
  25. package/dist/{serve-DERN4AB6.js → serve-GOLQMQFA.js} +12 -12
  26. package/dist/server/index.d.ts +2 -0
  27. package/dist/server/index.js +10 -10
  28. package/dist/{tools-PLVK22CF.js → tools-55YICCVH.js} +5 -5
  29. package/dist/{vision-fallback-NOC3YYIB.js → vision-fallback-ADYRFFD4.js} +2 -2
  30. package/dist/web/assets/index-CZBXRYpK.js +150 -0
  31. package/dist/web/assets/{index-MCWDS5UQ.css → index-D4V7Gtvt.css} +1 -1
  32. package/dist/web/index.html +2 -2
  33. package/dist/web/sw.js +1 -1
  34. package/package.json +13 -3
  35. package/dist/web/assets/index-Ccy2Csbl.js +0 -150
  36. /package/dist/{command-defaults → server/commands/defaults}/commit-push.command.md +0 -0
  37. /package/dist/{command-defaults → server/commands/defaults}/init.command.md +0 -0
  38. /package/dist/{command-defaults → server/commands/defaults}/test-ui.command.md +0 -0
  39. /package/dist/{skill-defaults → server/skills/defaults}/browser.skill.md +0 -0
@@ -1,50 +1,50 @@
1
1
  import {
2
2
  generateSessionName,
3
3
  needsNameGeneration
4
- } from "./chunk-QDEKU5RL.js";
4
+ } from "./chunk-F54ZJN4X.js";
5
5
  import {
6
6
  createVerifierNudgeConfig,
7
7
  runBuilderTurn,
8
8
  runChatTurn
9
- } from "./chunk-H22VHHQ4.js";
9
+ } from "./chunk-U54QVKL2.js";
10
10
  import {
11
11
  TurnMetrics,
12
12
  agentExists,
13
13
  assembleAgentRequest,
14
14
  cancelPathConfirmationsForSession,
15
+ checkAborted,
15
16
  createChatDoneEvent,
16
17
  createMessageStartEvent,
17
18
  createToolRegistry,
18
19
  deleteAgent,
19
20
  deleteSkill,
20
21
  devServerManager,
21
- ensureDefaultAgents,
22
- ensureDefaultSkills,
23
22
  executeSubAgent,
24
23
  findAgentById,
25
24
  findSkillById,
26
25
  getAllInstructions,
26
+ getDefaultAgentContent,
27
27
  getDefaultAgentIds,
28
+ getDefaultSkillContent,
28
29
  getDefaultSkillIds,
29
30
  getEnabledSkillMetadata,
30
- getModifiedDefaultAgentIds,
31
- getModifiedDefaultSkillIds,
32
31
  getToolRegistryForAgent,
33
32
  isSkillEnabled,
34
33
  loadAllAgents,
35
34
  loadAllAgentsDefault,
36
35
  loadAllSkills,
36
+ loadDefaultAgents,
37
+ loadDefaultSkills,
38
+ loadUserAgents,
39
+ loadUserSkills,
37
40
  maybeAutoCompactContext,
38
41
  performManualContextCompaction,
39
- restoreAllDefaultAgents,
40
- restoreAllDefaultSkills,
41
- restoreDefaultAgent,
42
- restoreDefaultSkill,
43
42
  saveAgent,
44
43
  saveSkill,
45
44
  setSkillEnabled,
46
- skillExists
47
- } from "./chunk-N25QUEPO.js";
45
+ skillExists,
46
+ spawnShellProcess
47
+ } from "./chunk-4OI4VPZ6.js";
48
48
  import {
49
49
  getPathSeparator,
50
50
  getPlatformShell,
@@ -54,7 +54,7 @@ import {
54
54
  import {
55
55
  createProviderManager,
56
56
  parseDefaultModelSelection
57
- } from "./chunk-OOIRCXAY.js";
57
+ } from "./chunk-KOUMYBYM.js";
58
58
  import {
59
59
  SessionNotFoundError,
60
60
  createLLMClient,
@@ -63,7 +63,7 @@ import {
63
63
  getBackendDisplayName,
64
64
  getLlmStatus,
65
65
  getModelProfile
66
- } from "./chunk-3XZ23PXM.js";
66
+ } from "./chunk-OVLFEBRR.js";
67
67
  import {
68
68
  createSession,
69
69
  deleteSession,
@@ -89,12 +89,12 @@ import {
89
89
  updateSessionProvider,
90
90
  updateSessionRunning,
91
91
  updateSessionSummary
92
- } from "./chunk-5GE3QJSZ.js";
92
+ } from "./chunk-6L3X7T4K.js";
93
93
  import {
94
94
  buildContextMessagesFromEventHistory,
95
95
  buildMessagesFromStoredEvents,
96
96
  foldPendingConfirmations
97
- } from "./chunk-7HLRI6JM.js";
97
+ } from "./chunk-2KP34IDL.js";
98
98
  import {
99
99
  createChatErrorMessage,
100
100
  createChatMessageMessage,
@@ -145,7 +145,7 @@ import express from "express";
145
145
  import cors from "cors";
146
146
  import { createServer as createHttpServer } from "http";
147
147
  import { fileURLToPath as fileURLToPath4 } from "url";
148
- import { dirname as dirname5, resolve, join as join5 } from "path";
148
+ import { dirname as dirname5, resolve, join as join6 } from "path";
149
149
  import { readFile as readFile4 } from "fs/promises";
150
150
  import { createServer as createViteServer } from "vite";
151
151
 
@@ -1414,7 +1414,7 @@ function unsubscribeAllFromTerminal(ws) {
1414
1414
  }
1415
1415
 
1416
1416
  // src/server/workflows/registry.ts
1417
- import { readdir, readFile, writeFile, copyFile, mkdir, access, unlink } from "fs/promises";
1417
+ import { readdir, readFile, writeFile, mkdir, access, unlink } from "fs/promises";
1418
1418
  import { join, dirname } from "path";
1419
1419
  import { constants } from "fs";
1420
1420
  import { fileURLToPath } from "url";
@@ -1433,49 +1433,20 @@ async function pathExists(path) {
1433
1433
  return false;
1434
1434
  }
1435
1435
  }
1436
- async function ensureDefaultWorkflows(configDir) {
1437
- const workflowsDir = getWorkflowsDir(configDir);
1438
- if (!await pathExists(workflowsDir)) {
1439
- await mkdir(workflowsDir, { recursive: true });
1440
- }
1441
- let defaultFiles;
1442
- let sourceDir;
1443
- try {
1444
- defaultFiles = (await readdir(DEFAULTS_DIR)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
1445
- sourceDir = DEFAULTS_DIR;
1446
- } catch {
1447
- try {
1448
- defaultFiles = (await readdir(DEFAULTS_DIR_ALT)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
1449
- sourceDir = DEFAULTS_DIR_ALT;
1450
- } catch {
1451
- logger.warn("No bundled workflow defaults found", { dir: DEFAULTS_DIR });
1452
- return;
1453
- }
1454
- }
1455
- for (const file of defaultFiles) {
1456
- const targetPath = join(workflowsDir, file);
1457
- try {
1458
- await copyFile(join(sourceDir, file), targetPath);
1459
- } catch (err) {
1460
- logger.error("Failed to copy default workflow", { file, error: err instanceof Error ? err.message : String(err) });
1461
- }
1462
- }
1463
- }
1464
- async function loadAllWorkflows(configDir) {
1465
- const workflowsDir = getWorkflowsDir(configDir);
1466
- if (!await pathExists(workflowsDir)) {
1436
+ async function loadWorkflowsFromDir(dir) {
1437
+ if (!await pathExists(dir)) {
1467
1438
  return [];
1468
1439
  }
1469
1440
  let files;
1470
1441
  try {
1471
- files = (await readdir(workflowsDir)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
1442
+ files = (await readdir(dir)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
1472
1443
  } catch {
1473
1444
  return [];
1474
1445
  }
1475
1446
  const workflows = [];
1476
1447
  for (const file of files) {
1477
1448
  try {
1478
- const raw = await readFile(join(workflowsDir, file), "utf-8");
1449
+ const raw = await readFile(join(dir, file), "utf-8");
1479
1450
  const parsed = JSON.parse(raw);
1480
1451
  if (parsed.metadata?.id && parsed.steps?.length > 0) {
1481
1452
  workflows.push(parsed);
@@ -1488,6 +1459,30 @@ async function loadAllWorkflows(configDir) {
1488
1459
  }
1489
1460
  return workflows;
1490
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
+ }
1491
1486
  async function getDefaultWorkflowIds() {
1492
1487
  for (const dir of [DEFAULTS_DIR, DEFAULTS_DIR_ALT]) {
1493
1488
  try {
@@ -1498,50 +1493,13 @@ async function getDefaultWorkflowIds() {
1498
1493
  }
1499
1494
  return [];
1500
1495
  }
1501
- async function restoreDefaultWorkflow(configDir, workflowId) {
1502
- const filename = `${workflowId}${WORKFLOW_EXTENSION}`;
1503
- for (const dir of [DEFAULTS_DIR, DEFAULTS_DIR_ALT]) {
1504
- const sourcePath = join(dir, filename);
1505
- if (await pathExists(sourcePath)) {
1506
- const targetPath = join(getWorkflowsDir(configDir), filename);
1507
- await copyFile(sourcePath, targetPath);
1508
- return true;
1509
- }
1510
- }
1511
- return false;
1496
+ async function getDefaultWorkflowContent(workflowId) {
1497
+ const defaults = await loadDefaultWorkflows();
1498
+ return defaults.find((w) => w.metadata.id === workflowId) ?? null;
1512
1499
  }
1513
- async function getModifiedDefaultWorkflowIds(configDir) {
1500
+ async function isDefaultWorkflow(workflowId) {
1514
1501
  const defaultIds = await getDefaultWorkflowIds();
1515
- const modified = [];
1516
- for (const id of defaultIds) {
1517
- const filename = `${id}${WORKFLOW_EXTENSION}`;
1518
- const userPath = join(getWorkflowsDir(configDir), filename);
1519
- let bundledContent = null;
1520
- for (const dir of [DEFAULTS_DIR, DEFAULTS_DIR_ALT]) {
1521
- try {
1522
- bundledContent = await readFile(join(dir, filename), "utf-8");
1523
- break;
1524
- } catch {
1525
- }
1526
- }
1527
- if (!bundledContent) continue;
1528
- try {
1529
- const userContent = await readFile(userPath, "utf-8");
1530
- if (userContent !== bundledContent) {
1531
- modified.push(id);
1532
- }
1533
- } catch {
1534
- }
1535
- }
1536
- return modified;
1537
- }
1538
- async function restoreAllDefaultWorkflows(configDir) {
1539
- const ids = await getDefaultWorkflowIds();
1540
- let count = 0;
1541
- for (const id of ids) {
1542
- if (await restoreDefaultWorkflow(configDir, id)) count++;
1543
- }
1544
- return count;
1502
+ return defaultIds.includes(workflowId);
1545
1503
  }
1546
1504
  function findWorkflowById(workflowId, workflows) {
1547
1505
  return workflows.find((p) => p.metadata.id === workflowId);
@@ -1559,12 +1517,16 @@ async function saveWorkflow(configDir, workflow) {
1559
1517
  await writeFile(filePath, JSON.stringify(workflow, null, 2) + "\n", "utf-8");
1560
1518
  }
1561
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
+ }
1562
1524
  const filePath = join(getWorkflowsDir(configDir), `${workflowId}${WORKFLOW_EXTENSION}`);
1563
1525
  try {
1564
1526
  await unlink(filePath);
1565
- return true;
1527
+ return { success: true };
1566
1528
  } catch {
1567
- return false;
1529
+ return { success: false };
1568
1530
  }
1569
1531
  }
1570
1532
 
@@ -1579,19 +1541,13 @@ var TERMINAL_DONE = "$done";
1579
1541
  var TERMINAL_BLOCKED = "$blocked";
1580
1542
 
1581
1543
  // src/server/workflows/shell.ts
1582
- import { spawn as spawn2 } from "child_process";
1583
1544
  function executeShellCommand(command, cwd, timeout, signal) {
1584
1545
  return new Promise((resolve2, reject) => {
1585
- if (signal?.aborted) {
1546
+ if (checkAborted(signal)) {
1586
1547
  reject(new Error("Aborted"));
1587
1548
  return;
1588
1549
  }
1589
- const shell = getPlatformShell();
1590
- const proc = spawn2(shell.command, [...shell.args, command], {
1591
- cwd,
1592
- env: { ...process.env, FORCE_COLOR: "0" },
1593
- stdio: ["ignore", "pipe", "pipe"]
1594
- });
1550
+ const proc = spawnShellProcess(command, cwd, signal);
1595
1551
  let stdout = "";
1596
1552
  let stderr = "";
1597
1553
  let killed = false;
@@ -1609,10 +1565,10 @@ function executeShellCommand(command, cwd, timeout, signal) {
1609
1565
  }
1610
1566
  };
1611
1567
  signal?.addEventListener("abort", onAbort);
1612
- proc.stdout.on("data", (data) => {
1568
+ proc.stdout?.on("data", (data) => {
1613
1569
  stdout += data.toString();
1614
1570
  });
1615
- proc.stderr.on("data", (data) => {
1571
+ proc.stderr?.on("data", (data) => {
1616
1572
  stderr += data.toString();
1617
1573
  });
1618
1574
  proc.on("close", (code) => {
@@ -1694,6 +1650,28 @@ function evaluateTransitions(transitions, criteria, stepOutcome) {
1694
1650
  }
1695
1651
  return TERMINAL_BLOCKED;
1696
1652
  }
1653
+ function emitWorkflowMessage(eventStore, sessionId, content, windowOptions, onMessage) {
1654
+ const msgId = crypto.randomUUID();
1655
+ eventStore.append(sessionId, createMessageStartEvent(msgId, "user", content, {
1656
+ ...windowOptions ?? {},
1657
+ isSystemGenerated: true,
1658
+ messageKind: "correction",
1659
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
1660
+ }));
1661
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: msgId } });
1662
+ if (onMessage) {
1663
+ onMessage(createChatMessageMessage({
1664
+ id: msgId,
1665
+ role: "user",
1666
+ content,
1667
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1668
+ isSystemGenerated: true,
1669
+ messageKind: "correction",
1670
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
1671
+ }));
1672
+ }
1673
+ return msgId;
1674
+ }
1697
1675
  function getCurrentWindowMessageOptions(sessionId) {
1698
1676
  const contextWindowId = getCurrentContextWindowId(sessionId);
1699
1677
  return contextWindowId ? { contextWindowId } : void 0;
@@ -1823,25 +1801,7 @@ async function executeWorkflow(workflow, options) {
1823
1801
  }
1824
1802
  parts.push(STEP_DONE_NUDGE);
1825
1803
  nudgeContent = parts.join("\n\n");
1826
- const nudgeMsgId = crypto.randomUUID();
1827
- eventStore.append(sessionId, createMessageStartEvent(nudgeMsgId, "user", nudgeContent, {
1828
- ...currentWindowMessageOptions ?? {},
1829
- isSystemGenerated: true,
1830
- messageKind: "correction",
1831
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
1832
- }));
1833
- eventStore.append(sessionId, { type: "message.done", data: { messageId: nudgeMsgId } });
1834
- if (onMessage) {
1835
- onMessage(createChatMessageMessage({
1836
- id: nudgeMsgId,
1837
- role: "user",
1838
- content: nudgeContent,
1839
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1840
- isSystemGenerated: true,
1841
- messageKind: "correction",
1842
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
1843
- }));
1844
- }
1804
+ emitWorkflowMessage(eventStore, sessionId, nudgeContent, currentWindowMessageOptions, onMessage);
1845
1805
  }
1846
1806
  const turnMetrics = new TurnMetrics();
1847
1807
  const agentResult = await runBuilderTurn({
@@ -2003,25 +1963,7 @@ ${output.slice(0, 1e4)}
2003
1963
  sessionManager.setPhase(sessionId, "blocked");
2004
1964
  const blockedCriteria = refreshedSession.criteria.filter((c) => c.status.type === "failed" && c.attempts.filter((a) => a.status === "failed").length >= RUNNER_CONFIG.maxVerifyRetries).map((c) => c.id);
2005
1965
  const reason = blockedCriteria.length > 0 ? `Retry limit reached for: ${blockedCriteria.join(", ")}` : "No matching transition";
2006
- const blockedMsgId = crypto.randomUUID();
2007
- eventStore.append(sessionId, createMessageStartEvent(blockedMsgId, "user", `Runner blocked: ${reason}`, {
2008
- ...currentWindowMessageOptions ?? {},
2009
- isSystemGenerated: true,
2010
- messageKind: "correction",
2011
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
2012
- }));
2013
- eventStore.append(sessionId, { type: "message.done", data: { messageId: blockedMsgId } });
2014
- if (onMessage) {
2015
- onMessage(createChatMessageMessage({
2016
- id: blockedMsgId,
2017
- role: "user",
2018
- content: `Runner blocked: ${reason}`,
2019
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2020
- isSystemGenerated: true,
2021
- messageKind: "correction",
2022
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
2023
- }));
2024
- }
1966
+ emitWorkflowMessage(eventStore, sessionId, `Runner blocked: ${reason}`, currentWindowMessageOptions, onMessage);
2025
1967
  logger.warn("Workflow executor blocked", { sessionId, iterations, reason });
2026
1968
  const blockedAction = { type: "BLOCKED", reason, blockedCriteria };
2027
1969
  return {
@@ -3174,7 +3116,7 @@ ${content}` : workflowInfo;
3174
3116
  }
3175
3117
 
3176
3118
  // src/server/lsp/server.ts
3177
- import { spawn as spawn3 } from "child_process";
3119
+ import { spawn as spawn2 } from "child_process";
3178
3120
  import { extname } from "path";
3179
3121
  import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node.js";
3180
3122
  var LSP = {
@@ -3236,7 +3178,7 @@ var LspServer = class {
3236
3178
  }
3237
3179
  this.state = "starting";
3238
3180
  try {
3239
- this.process = spawn3(this.commandPath, this.config.serverArgs, {
3181
+ this.process = spawn2(this.commandPath, this.config.serverArgs, {
3240
3182
  cwd: this.workdir,
3241
3183
  stdio: ["pipe", "pipe", "pipe"],
3242
3184
  env: {
@@ -4923,202 +4865,47 @@ ${summary}`,
4923
4865
  }
4924
4866
  };
4925
4867
 
4926
- // src/server/commands/registry.ts
4927
- import { readdir as readdir2, readFile as readFile3, writeFile as writeFile3, copyFile as copyFile2, mkdir as mkdir3, access as access3, unlink as unlink2 } from "fs/promises";
4928
- import { join as join4, dirname as dirname4 } from "path";
4929
- import { constants as constants3 } from "fs";
4930
- import { fileURLToPath as fileURLToPath3 } from "url";
4931
- import matter from "gray-matter";
4932
- var __bundleDir2 = dirname4(fileURLToPath3(import.meta.url));
4933
- var DEFAULTS_DIR2 = join4(__bundleDir2, "defaults");
4934
- var DEFAULTS_DIR_ALT2 = join4(__bundleDir2, "command-defaults");
4935
- var COMMAND_EXTENSION = ".command.md";
4936
- function getCommandsDir(configDir) {
4937
- return join4(configDir, "commands");
4938
- }
4939
- async function dirExists(path) {
4940
- try {
4941
- await access3(path, constants3.R_OK);
4942
- return true;
4943
- } catch {
4944
- return false;
4945
- }
4946
- }
4947
- async function ensureDefaultCommands(configDir) {
4948
- const commandsDir = getCommandsDir(configDir);
4949
- if (!await dirExists(commandsDir)) {
4950
- await mkdir3(commandsDir, { recursive: true });
4951
- }
4952
- let defaultFiles;
4953
- let sourceDir;
4954
- try {
4955
- defaultFiles = (await readdir2(DEFAULTS_DIR2)).filter((f) => f.endsWith(COMMAND_EXTENSION));
4956
- sourceDir = DEFAULTS_DIR2;
4957
- } catch {
4958
- try {
4959
- defaultFiles = (await readdir2(DEFAULTS_DIR_ALT2)).filter((f) => f.endsWith(COMMAND_EXTENSION));
4960
- sourceDir = DEFAULTS_DIR_ALT2;
4961
- } catch {
4962
- logger.warn("No bundled command defaults found", { dir: DEFAULTS_DIR2 });
4963
- return;
4964
- }
4965
- }
4966
- for (const file of defaultFiles) {
4967
- const targetPath = join4(commandsDir, file);
4968
- if (!await dirExists(targetPath)) {
4969
- try {
4970
- await copyFile2(join4(sourceDir, file), targetPath);
4971
- logger.info("Installed default command", { file });
4972
- } catch (err) {
4973
- logger.error("Failed to copy default command", { file, error: err instanceof Error ? err.message : String(err) });
4974
- }
4975
- }
4976
- }
4977
- }
4978
- async function loadAllCommands(configDir) {
4979
- const commandsDir = getCommandsDir(configDir);
4980
- if (!await dirExists(commandsDir)) {
4981
- return [];
4982
- }
4983
- let files;
4984
- try {
4985
- files = (await readdir2(commandsDir)).filter((f) => f.endsWith(COMMAND_EXTENSION));
4986
- } catch {
4987
- return [];
4988
- }
4989
- const commands = [];
4990
- for (const file of files) {
4991
- try {
4992
- const raw = await readFile3(join4(commandsDir, file), "utf-8");
4993
- const { data, content } = matter(raw);
4994
- const metadata = data;
4995
- if (metadata.id && content.trim()) {
4996
- commands.push({ metadata, prompt: content.trim() });
4997
- } else {
4998
- logger.warn("Skipping invalid command file", { file });
4999
- }
5000
- } catch (err) {
5001
- logger.warn("Failed to parse command file", { file, error: err instanceof Error ? err.message : String(err) });
5002
- }
5003
- }
5004
- return commands;
5005
- }
5006
- async function getDefaultCommandIds() {
5007
- for (const dir of [DEFAULTS_DIR2, DEFAULTS_DIR_ALT2]) {
5008
- try {
5009
- const files = (await readdir2(dir)).filter((f) => f.endsWith(COMMAND_EXTENSION));
5010
- return files.map((f) => f.replace(COMMAND_EXTENSION, ""));
5011
- } catch {
5012
- }
5013
- }
5014
- return [];
5015
- }
5016
- async function restoreDefaultCommand(configDir, commandId) {
5017
- const filename = `${commandId}${COMMAND_EXTENSION}`;
5018
- for (const dir of [DEFAULTS_DIR2, DEFAULTS_DIR_ALT2]) {
5019
- const sourcePath = join4(dir, filename);
5020
- if (await dirExists(sourcePath)) {
5021
- const targetPath = join4(getCommandsDir(configDir), filename);
5022
- await copyFile2(sourcePath, targetPath);
5023
- return true;
5024
- }
5025
- }
5026
- return false;
5027
- }
5028
- async function getModifiedDefaultCommandIds(configDir) {
5029
- const defaultIds = await getDefaultCommandIds();
5030
- const modified = [];
5031
- for (const id of defaultIds) {
5032
- const filename = `${id}${COMMAND_EXTENSION}`;
5033
- const userPath = join4(getCommandsDir(configDir), filename);
5034
- let bundledContent = null;
5035
- for (const dir of [DEFAULTS_DIR2, DEFAULTS_DIR_ALT2]) {
5036
- try {
5037
- bundledContent = await readFile3(join4(dir, filename), "utf-8");
5038
- break;
5039
- } catch {
5040
- }
5041
- }
5042
- if (!bundledContent) continue;
5043
- try {
5044
- const userContent = await readFile3(userPath, "utf-8");
5045
- if (userContent !== bundledContent) {
5046
- modified.push(id);
5047
- }
5048
- } catch {
5049
- }
5050
- }
5051
- return modified;
5052
- }
5053
- async function restoreAllDefaultCommands(configDir) {
5054
- const ids = await getDefaultCommandIds();
5055
- let count = 0;
5056
- for (const id of ids) {
5057
- if (await restoreDefaultCommand(configDir, id)) count++;
5058
- }
5059
- return count;
5060
- }
5061
- function findCommandById(commandId, commands) {
5062
- return commands.find((c) => c.metadata.id === commandId);
5063
- }
5064
- async function commandExists(configDir, commandId) {
5065
- const filePath = join4(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
5066
- return dirExists(filePath);
5067
- }
5068
- async function saveCommand(configDir, command) {
5069
- const commandsDir = getCommandsDir(configDir);
5070
- if (!await dirExists(commandsDir)) {
5071
- await mkdir3(commandsDir, { recursive: true });
5072
- }
5073
- const filePath = join4(commandsDir, `${command.metadata.id}${COMMAND_EXTENSION}`);
5074
- const content = matter.stringify(command.prompt, command.metadata);
5075
- await writeFile3(filePath, content, "utf-8");
5076
- }
5077
- async function deleteCommand(configDir, commandId) {
5078
- const filePath = join4(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
5079
- try {
5080
- await unlink2(filePath);
5081
- return true;
5082
- } catch {
5083
- return false;
5084
- }
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);
5085
4874
  }
5086
4875
 
5087
4876
  // src/server/routes/skills.ts
5088
- import { Router } from "express";
5089
4877
  function createSkillRoutes(configDir) {
5090
4878
  const router = Router();
5091
4879
  router.get("/", async (_req, res) => {
5092
- const [skills, defaultIds, modifiedIds] = await Promise.all([
5093
- loadAllSkills(configDir),
5094
- getDefaultSkillIds(),
5095
- getModifiedDefaultSkillIds(configDir)
4880
+ const [defaults, userItems] = await Promise.all([
4881
+ loadDefaultSkills(),
4882
+ loadUserSkills(configDir)
5096
4883
  ]);
4884
+ const overrideIds = computeOverrideIds(defaults, userItems);
5097
4885
  res.json({
5098
- skills: skills.map((s) => ({
4886
+ defaults: defaults.map((s) => ({
5099
4887
  ...s.metadata,
5100
4888
  enabled: isSkillEnabled(s.metadata.id)
5101
4889
  })),
5102
- defaultIds,
5103
- modifiedIds
4890
+ userItems: userItems.map((s) => ({
4891
+ ...s.metadata,
4892
+ enabled: isSkillEnabled(s.metadata.id)
4893
+ })),
4894
+ overrideIds
5104
4895
  });
5105
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
+ });
5106
4905
  router.get("/default-ids", async (_req, res) => {
5107
4906
  const ids = await getDefaultSkillIds();
5108
4907
  res.json({ ids });
5109
4908
  });
5110
- router.post("/restore-all-defaults", async (_req, res) => {
5111
- const count = await restoreAllDefaultSkills(configDir);
5112
- res.json({ success: true, count });
5113
- });
5114
- router.post("/:id/restore-default", async (req, res) => {
5115
- const { id } = req.params;
5116
- const restored = await restoreDefaultSkill(configDir, id);
5117
- if (!restored) {
5118
- return res.status(404).json({ error: "No bundled default found for this skill" });
5119
- }
5120
- res.json({ success: true });
5121
- });
5122
4909
  router.post("/:id/toggle", (req, res) => {
5123
4910
  const { id } = req.params;
5124
4911
  const currentlyEnabled = isSkillEnabled(id);
@@ -5142,7 +4929,8 @@ function createSkillRoutes(configDir) {
5142
4929
  if (!/^[a-z0-9-]+$/.test(body.metadata.id)) {
5143
4930
  return res.status(400).json({ error: "Skill ID must be lowercase alphanumeric with hyphens only" });
5144
4931
  }
5145
- if (await skillExists(configDir, body.metadata.id)) {
4932
+ const exists = await skillExists(configDir, body.metadata.id);
4933
+ if (exists) {
5146
4934
  return res.status(409).json({ error: "A skill with this ID already exists" });
5147
4935
  }
5148
4936
  await saveSkill(configDir, body);
@@ -5150,15 +4938,12 @@ function createSkillRoutes(configDir) {
5150
4938
  });
5151
4939
  router.put("/:id", async (req, res) => {
5152
4940
  const { id } = req.params;
5153
- if (!await skillExists(configDir, id)) {
5154
- return res.status(404).json({ error: "Skill not found" });
5155
- }
5156
- const body = req.body;
5157
4941
  const skills = await loadAllSkills(configDir);
5158
4942
  const existing = findSkillById(id, skills);
5159
4943
  if (!existing) {
5160
4944
  return res.status(404).json({ error: "Skill not found" });
5161
4945
  }
4946
+ const body = req.body;
5162
4947
  const updated = {
5163
4948
  metadata: { ...existing.metadata, ...body.metadata, id },
5164
4949
  prompt: body.prompt ?? existing.prompt
@@ -5168,47 +4953,205 @@ function createSkillRoutes(configDir) {
5168
4953
  });
5169
4954
  router.delete("/:id", async (req, res) => {
5170
4955
  const { id } = req.params;
5171
- const deleted = await deleteSkill(configDir, id);
5172
- if (!deleted) {
5173
- return res.status(404).json({ error: "Skill not found" });
4956
+ const result = await deleteSkill(configDir, id);
4957
+ if (!result.success) {
4958
+ return res.status(403).json({ error: result.reason ?? "Cannot delete this skill" });
5174
4959
  }
5175
4960
  res.json({ success: true });
5176
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
+ });
5177
4978
  return router;
5178
4979
  }
5179
4980
 
5180
4981
  // src/server/routes/commands.ts
5181
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
5182
5129
  function createCommandRoutes(configDir) {
5183
5130
  const router = Router2();
5184
5131
  router.get("/", async (_req, res) => {
5185
- const [commands, defaultIds, modifiedIds] = await Promise.all([
5186
- loadAllCommands(configDir),
5187
- getDefaultCommandIds(),
5188
- getModifiedDefaultCommandIds(configDir)
5132
+ const [defaults, userItems] = await Promise.all([
5133
+ loadDefaultCommands(),
5134
+ loadUserCommands(configDir)
5189
5135
  ]);
5136
+ const overrideIds = computeOverrideIds(defaults, userItems);
5190
5137
  res.json({
5191
- commands: commands.map((c) => c.metadata),
5192
- defaultIds,
5193
- modifiedIds
5138
+ defaults: defaults.map((c) => c.metadata),
5139
+ userItems: userItems.map((c) => c.metadata),
5140
+ overrideIds
5194
5141
  });
5195
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
+ });
5196
5151
  router.get("/default-ids", async (_req, res) => {
5197
5152
  const ids = await getDefaultCommandIds();
5198
5153
  res.json({ ids });
5199
5154
  });
5200
- router.post("/restore-all-defaults", async (_req, res) => {
5201
- const count = await restoreAllDefaultCommands(configDir);
5202
- res.json({ success: true, count });
5203
- });
5204
- router.post("/:id/restore-default", async (req, res) => {
5205
- const { id } = req.params;
5206
- const restored = await restoreDefaultCommand(configDir, id);
5207
- if (!restored) {
5208
- return res.status(404).json({ error: "No bundled default found for this command" });
5209
- }
5210
- res.json({ success: true });
5211
- });
5212
5155
  router.get("/:id", async (req, res) => {
5213
5156
  const { id } = req.params;
5214
5157
  const commands = await loadAllCommands(configDir);
@@ -5226,7 +5169,8 @@ function createCommandRoutes(configDir) {
5226
5169
  if (!/^[a-z0-9-]+$/.test(body.metadata.id)) {
5227
5170
  return res.status(400).json({ error: "Command ID must be lowercase alphanumeric with hyphens only" });
5228
5171
  }
5229
- if (await commandExists(configDir, body.metadata.id)) {
5172
+ const exists = await commandExists(configDir, body.metadata.id);
5173
+ if (exists) {
5230
5174
  return res.status(409).json({ error: "A command with this ID already exists" });
5231
5175
  }
5232
5176
  await saveCommand(configDir, body);
@@ -5234,15 +5178,12 @@ function createCommandRoutes(configDir) {
5234
5178
  });
5235
5179
  router.put("/:id", async (req, res) => {
5236
5180
  const { id } = req.params;
5237
- if (!await commandExists(configDir, id)) {
5238
- return res.status(404).json({ error: "Command not found" });
5239
- }
5240
- const body = req.body;
5241
5181
  const commands = await loadAllCommands(configDir);
5242
5182
  const existing = findCommandById(id, commands);
5243
5183
  if (!existing) {
5244
5184
  return res.status(404).json({ error: "Command not found" });
5245
5185
  }
5186
+ const body = req.body;
5246
5187
  const updated = {
5247
5188
  metadata: { ...existing.metadata, ...body.metadata, id },
5248
5189
  prompt: body.prompt ?? existing.prompt
@@ -5252,12 +5193,28 @@ function createCommandRoutes(configDir) {
5252
5193
  });
5253
5194
  router.delete("/:id", async (req, res) => {
5254
5195
  const { id } = req.params;
5255
- const deleted = await deleteCommand(configDir, id);
5256
- if (!deleted) {
5257
- return res.status(404).json({ error: "Command not found" });
5196
+ const result = await deleteCommand(configDir, id);
5197
+ if (!result.success) {
5198
+ return res.status(403).json({ error: result.reason ?? "Cannot delete this command" });
5258
5199
  }
5259
5200
  res.json({ success: true });
5260
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
+ });
5261
5218
  return router;
5262
5219
  }
5263
5220
 
@@ -5266,33 +5223,29 @@ import { Router as Router3 } from "express";
5266
5223
  function createAgentRoutes(configDir) {
5267
5224
  const router = Router3();
5268
5225
  router.get("/", async (_req, res) => {
5269
- const [agents, defaultIds, modifiedIds] = await Promise.all([
5270
- loadAllAgents(configDir),
5271
- getDefaultAgentIds(),
5272
- getModifiedDefaultAgentIds(configDir)
5226
+ const [defaults, userItems] = await Promise.all([
5227
+ loadDefaultAgents(),
5228
+ loadUserAgents(configDir)
5273
5229
  ]);
5230
+ const overrideIds = computeOverrideIds(defaults, userItems);
5274
5231
  res.json({
5275
- agents: agents.map((a) => a.metadata),
5276
- defaultIds,
5277
- modifiedIds
5232
+ defaults: defaults.map((a) => a.metadata),
5233
+ userItems: userItems.map((a) => a.metadata),
5234
+ overrideIds
5278
5235
  });
5279
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
+ });
5280
5245
  router.get("/default-ids", async (_req, res) => {
5281
5246
  const ids = await getDefaultAgentIds();
5282
5247
  res.json({ ids });
5283
5248
  });
5284
- router.post("/restore-all-defaults", async (_req, res) => {
5285
- const count = await restoreAllDefaultAgents(configDir);
5286
- res.json({ success: true, count });
5287
- });
5288
- router.post("/:id/restore-default", async (req, res) => {
5289
- const { id } = req.params;
5290
- const restored = await restoreDefaultAgent(configDir, id);
5291
- if (!restored) {
5292
- return res.status(404).json({ error: "No bundled default found for this agent" });
5293
- }
5294
- res.json({ success: true });
5295
- });
5296
5249
  router.get("/:id", async (req, res) => {
5297
5250
  const { id } = req.params;
5298
5251
  const agents = await loadAllAgents(configDir);
@@ -5307,7 +5260,8 @@ function createAgentRoutes(configDir) {
5307
5260
  if (!body?.metadata?.id || !body?.prompt) {
5308
5261
  return res.status(400).json({ error: "Missing required fields: metadata.id, prompt" });
5309
5262
  }
5310
- if (await agentExists(configDir, body.metadata.id)) {
5263
+ const exists = await agentExists(configDir, body.metadata.id);
5264
+ if (exists) {
5311
5265
  return res.status(409).json({ error: "An agent with this ID already exists" });
5312
5266
  }
5313
5267
  await saveAgent(configDir, body);
@@ -5333,12 +5287,28 @@ function createAgentRoutes(configDir) {
5333
5287
  });
5334
5288
  router.delete("/:id", async (req, res) => {
5335
5289
  const { id } = req.params;
5336
- const deleted = await deleteAgent(configDir, id);
5337
- if (!deleted) {
5338
- return res.status(404).json({ error: "Agent not found" });
5290
+ const result = await deleteAgent(configDir, id);
5291
+ if (!result.success) {
5292
+ return res.status(403).json({ error: result.reason ?? "Cannot delete this agent" });
5339
5293
  }
5340
5294
  res.json({ success: true });
5341
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
+ });
5342
5312
  return router;
5343
5313
  }
5344
5314
 
@@ -5347,37 +5317,33 @@ import { Router as Router4 } from "express";
5347
5317
  function createWorkflowRoutes(configDir, config) {
5348
5318
  const router = Router4();
5349
5319
  router.get("/", async (_req, res) => {
5350
- const [workflows, defaultIds, modifiedIds] = await Promise.all([
5351
- loadAllWorkflows(configDir),
5352
- getDefaultWorkflowIds(),
5353
- getModifiedDefaultWorkflowIds(configDir)
5320
+ const [defaults, userItems] = await Promise.all([
5321
+ loadDefaultWorkflows(),
5322
+ loadUserWorkflows(configDir)
5354
5323
  ]);
5324
+ const overrideIds = computeOverrideIds(defaults, userItems);
5355
5325
  res.json({
5356
- workflows: workflows.map((p) => ({ ...p.metadata, startCondition: p.startCondition })),
5326
+ defaults: defaults.map((p) => ({ ...p.metadata, startCondition: p.startCondition })),
5327
+ userItems: userItems.map((p) => ({ ...p.metadata, startCondition: p.startCondition })),
5357
5328
  activeWorkflowId: config.activeWorkflowId ?? "default",
5358
- defaultIds,
5359
- modifiedIds
5329
+ overrideIds
5360
5330
  });
5361
5331
  });
5362
5332
  router.get("/template-variables", (_req, res) => {
5363
5333
  res.json({ variables: TEMPLATE_VARIABLES });
5364
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
+ });
5365
5343
  router.get("/default-ids", async (_req, res) => {
5366
5344
  const ids = await getDefaultWorkflowIds();
5367
5345
  res.json({ ids });
5368
5346
  });
5369
- router.post("/restore-all-defaults", async (_req, res) => {
5370
- const count = await restoreAllDefaultWorkflows(configDir);
5371
- res.json({ success: true, count });
5372
- });
5373
- router.post("/:id/restore-default", async (req, res) => {
5374
- const { id } = req.params;
5375
- const restored = await restoreDefaultWorkflow(configDir, id);
5376
- if (!restored) {
5377
- return res.status(404).json({ error: "No bundled default found for this workflow" });
5378
- }
5379
- res.json({ success: true });
5380
- });
5381
5347
  router.get("/:id", async (req, res) => {
5382
5348
  const { id } = req.params;
5383
5349
  const workflows = await loadAllWorkflows(configDir);
@@ -5392,7 +5358,8 @@ function createWorkflowRoutes(configDir, config) {
5392
5358
  if (!body?.metadata?.id || !body?.steps?.length) {
5393
5359
  return res.status(400).json({ error: "Missing required fields: metadata.id, steps" });
5394
5360
  }
5395
- if (await workflowExists(configDir, body.metadata.id)) {
5361
+ const exists = await workflowExists(configDir, body.metadata.id);
5362
+ if (exists) {
5396
5363
  return res.status(409).json({ error: "A workflow with this ID already exists" });
5397
5364
  }
5398
5365
  await saveWorkflow(configDir, body);
@@ -5400,7 +5367,9 @@ function createWorkflowRoutes(configDir, config) {
5400
5367
  });
5401
5368
  router.put("/:id", async (req, res) => {
5402
5369
  const { id } = req.params;
5403
- if (!await workflowExists(configDir, id)) {
5370
+ const workflows = await loadAllWorkflows(configDir);
5371
+ const existing = findWorkflowById(id, workflows);
5372
+ if (!existing) {
5404
5373
  return res.status(404).json({ error: "Workflow not found" });
5405
5374
  }
5406
5375
  const body = req.body;
@@ -5413,14 +5382,27 @@ function createWorkflowRoutes(configDir, config) {
5413
5382
  });
5414
5383
  router.delete("/:id", async (req, res) => {
5415
5384
  const { id } = req.params;
5416
- if (id === "default") {
5417
- return res.status(400).json({ error: "Cannot delete the default workflow" });
5385
+ const result = await deleteWorkflow(configDir, id);
5386
+ if (!result.success) {
5387
+ return res.status(403).json({ error: result.reason ?? "Cannot delete this workflow" });
5418
5388
  }
5419
- const deleted = await deleteWorkflow(configDir, id);
5420
- if (!deleted) {
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) {
5421
5397
  return res.status(404).json({ error: "Workflow not found" });
5422
5398
  }
5423
- res.json({ success: true });
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);
5424
5406
  });
5425
5407
  return router;
5426
5408
  }
@@ -5544,7 +5526,7 @@ function createTerminalRoutes() {
5544
5526
  }
5545
5527
 
5546
5528
  // src/constants.ts
5547
- var VERSION = "1.6.14";
5529
+ var VERSION = "1.6.16";
5548
5530
 
5549
5531
  // src/server/index.ts
5550
5532
  var __dirname2 = dirname5(fileURLToPath4(import.meta.url));
@@ -5555,10 +5537,6 @@ async function createServerHandle(config) {
5555
5537
  const db = initDatabase(config);
5556
5538
  initEventStore(db);
5557
5539
  const configDir = getGlobalConfigDir(config.mode ?? "production");
5558
- await ensureDefaultSkills(configDir);
5559
- await ensureDefaultCommands(configDir);
5560
- await ensureDefaultAgents(configDir);
5561
- await ensureDefaultWorkflows(configDir);
5562
5540
  const providerManager = createProviderManager(config);
5563
5541
  const sessionManager = new SessionManager(providerManager);
5564
5542
  const useMock = process.env["OPENFOX_MOCK_LLM"] === "true";
@@ -5709,7 +5687,7 @@ async function createServerHandle(config) {
5709
5687
  res.json({ success: true });
5710
5688
  });
5711
5689
  app.get("/api/sessions", async (req, res) => {
5712
- const { getRecentUserPromptsForSession } = await import("./events-VDAC7E7K.js");
5690
+ const { getRecentUserPromptsForSession } = await import("./events-2ETDOE5B.js");
5713
5691
  const projectId = req.query["projectId"];
5714
5692
  const limit = Math.min(parseInt(req.query["limit"]) || 20, 100);
5715
5693
  const offset = parseInt(req.query["offset"]) || 0;
@@ -5742,8 +5720,8 @@ async function createServerHandle(config) {
5742
5720
  res.status(201).json({ session });
5743
5721
  });
5744
5722
  app.get("/api/sessions/:id", async (req, res) => {
5745
- const { getEventStore: getEventStore2 } = await import("./events-VDAC7E7K.js");
5746
- const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-NDFQCISZ.js");
5723
+ const { getEventStore: getEventStore2 } = await import("./events-2ETDOE5B.js");
5724
+ const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-M7FMUBOL.js");
5747
5725
  const session = sessionManager.getSession(req.params.id);
5748
5726
  if (!session) {
5749
5727
  return res.status(404).json({ error: "Session not found" });
@@ -5773,8 +5751,8 @@ async function createServerHandle(config) {
5773
5751
  res.json({ success: true });
5774
5752
  });
5775
5753
  app.post("/api/sessions/:id/provider", async (req, res) => {
5776
- const { getEventStore: getEventStore2 } = await import("./events-VDAC7E7K.js");
5777
- const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-NDFQCISZ.js");
5754
+ const { getEventStore: getEventStore2 } = await import("./events-2ETDOE5B.js");
5755
+ const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-M7FMUBOL.js");
5778
5756
  const sessionId = req.params.id;
5779
5757
  const session = sessionManager.getSession(sessionId);
5780
5758
  if (!session) {
@@ -5785,7 +5763,7 @@ async function createServerHandle(config) {
5785
5763
  return res.status(400).json({ error: "providerId is required" });
5786
5764
  }
5787
5765
  sessionManager.setSessionProvider(sessionId, providerId, model ?? "auto");
5788
- const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-DEM6ASQM.js");
5766
+ const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-67AX6CNS.js");
5789
5767
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
5790
5768
  const updatedConfig = setDefaultModelSelection(globalConfig, providerId, model ?? "auto");
5791
5769
  await saveGlobalConfig(config.mode ?? "production", updatedConfig);
@@ -5811,8 +5789,8 @@ async function createServerHandle(config) {
5811
5789
  res.json({ success: true });
5812
5790
  });
5813
5791
  app.put("/api/sessions/:id/mode", async (req, res) => {
5814
- const { getEventStore: getEventStore2 } = await import("./events-VDAC7E7K.js");
5815
- const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-NDFQCISZ.js");
5792
+ const { getEventStore: getEventStore2 } = await import("./events-2ETDOE5B.js");
5793
+ const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-M7FMUBOL.js");
5816
5794
  const sessionId = req.params.id;
5817
5795
  const session = sessionManager.getSession(sessionId);
5818
5796
  if (!session) {
@@ -5850,13 +5828,13 @@ async function createServerHandle(config) {
5850
5828
  if (!callId || approved === void 0) {
5851
5829
  return res.status(400).json({ error: "callId and approved are required" });
5852
5830
  }
5853
- const { providePathConfirmation: providePathConfirmation2 } = await import("./tools-PLVK22CF.js");
5831
+ const { providePathConfirmation: providePathConfirmation2 } = await import("./tools-55YICCVH.js");
5854
5832
  const result = providePathConfirmation2(callId, approved, alwaysAllow);
5855
5833
  if (!result.found) {
5856
5834
  return res.status(404).json({ error: "No pending path confirmation with that ID" });
5857
5835
  }
5858
- const { getEventStore: getEventStore2 } = await import("./events-VDAC7E7K.js");
5859
- const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2, foldPendingConfirmations: foldPendingConfirmations2 } = await import("./folding-NDFQCISZ.js");
5836
+ const { getEventStore: getEventStore2 } = await import("./events-2ETDOE5B.js");
5837
+ const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2, foldPendingConfirmations: foldPendingConfirmations2 } = await import("./folding-M7FMUBOL.js");
5860
5838
  const { createSessionStateMessage: createSessionStateMessage2 } = await import("./protocol-KUKFSV5U.js");
5861
5839
  const eventStore = getEventStore2();
5862
5840
  const events = eventStore.getEvents(sessionId);
@@ -5875,7 +5853,7 @@ async function createServerHandle(config) {
5875
5853
  if (!callId || !answer) {
5876
5854
  return res.status(400).json({ error: "callId and answer are required" });
5877
5855
  }
5878
- const { provideAnswer: provideAnswer2 } = await import("./tools-PLVK22CF.js");
5856
+ const { provideAnswer: provideAnswer2 } = await import("./tools-55YICCVH.js");
5879
5857
  const found = provideAnswer2(callId, answer);
5880
5858
  if (!found) {
5881
5859
  return res.status(404).json({ error: "No pending question with that ID" });
@@ -5911,14 +5889,14 @@ async function createServerHandle(config) {
5911
5889
  if (!session) {
5912
5890
  return res.status(404).json({ error: "Session not found" });
5913
5891
  }
5914
- const { stopSessionExecution } = await import("./chat-handler-US3QOOE4.js");
5915
- const { cancelQuestionsForSession: cancelQuestionsForSession2, cancelPathConfirmationsForSession: cancelPathConfirmationsForSession2 } = await import("./tools-PLVK22CF.js");
5892
+ const { stopSessionExecution } = await import("./chat-handler-IY2XVOO6.js");
5893
+ const { cancelQuestionsForSession: cancelQuestionsForSession2, cancelPathConfirmationsForSession: cancelPathConfirmationsForSession2 } = await import("./tools-55YICCVH.js");
5916
5894
  stopSessionExecution(sessionId, sessionManager);
5917
5895
  abortSession(sessionId);
5918
5896
  cancelQuestionsForSession2(sessionId, "Session stopped by user");
5919
5897
  cancelPathConfirmationsForSession2(sessionId, "Session stopped by user");
5920
5898
  sessionManager.clearMessageQueue(sessionId);
5921
- const eventStore = (await import("./events-VDAC7E7K.js")).getEventStore();
5899
+ const eventStore = (await import("./events-2ETDOE5B.js")).getEventStore();
5922
5900
  eventStore.append(sessionId, { type: "running.changed", data: { isRunning: false } });
5923
5901
  res.json({ success: true });
5924
5902
  });
@@ -5970,7 +5948,7 @@ async function createServerHandle(config) {
5970
5948
  let visionFallback;
5971
5949
  let globalWorkdir;
5972
5950
  try {
5973
- const { loadGlobalConfig, getVisionFallback } = await import("./config-DEM6ASQM.js");
5951
+ const { loadGlobalConfig, getVisionFallback } = await import("./config-67AX6CNS.js");
5974
5952
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
5975
5953
  const fallback = getVisionFallback(globalConfig);
5976
5954
  if (fallback) {
@@ -6049,7 +6027,7 @@ async function createServerHandle(config) {
6049
6027
  return res.status(400).json({ error: "name, url, and backend are required" });
6050
6028
  }
6051
6029
  try {
6052
- const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-DEM6ASQM.js");
6030
+ const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-67AX6CNS.js");
6053
6031
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
6054
6032
  const providerBackend = backend;
6055
6033
  const configWithProvider = addProvider(globalConfig, {
@@ -6082,7 +6060,7 @@ async function createServerHandle(config) {
6082
6060
  app.post("/api/init/config", async (req, res) => {
6083
6061
  const { workdir, visionFallback } = req.body;
6084
6062
  try {
6085
- const { loadGlobalConfig, saveGlobalConfig } = await import("./config-DEM6ASQM.js");
6063
+ const { loadGlobalConfig, saveGlobalConfig } = await import("./config-67AX6CNS.js");
6086
6064
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
6087
6065
  const updatedConfig = {
6088
6066
  ...globalConfig,
@@ -6110,7 +6088,7 @@ async function createServerHandle(config) {
6110
6088
  });
6111
6089
  app.delete("/api/providers/:id", async (req, res) => {
6112
6090
  const { id } = req.params;
6113
- const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-DEM6ASQM.js");
6091
+ const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-67AX6CNS.js");
6114
6092
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
6115
6093
  const updatedConfig = removeProvider(globalConfig, id);
6116
6094
  await saveGlobalConfig(config.mode ?? "production", updatedConfig);
@@ -6130,7 +6108,7 @@ async function createServerHandle(config) {
6130
6108
  return res.status(400).json({ error: result.error });
6131
6109
  }
6132
6110
  const llmClient = getLLMClient();
6133
- const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-DEM6ASQM.js");
6111
+ const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-67AX6CNS.js");
6134
6112
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
6135
6113
  const updatedConfig = setDefaultModelSelection(globalConfig, id, llmClient.getModel());
6136
6114
  await saveGlobalConfig(config.mode ?? "production", updatedConfig);
@@ -6151,7 +6129,7 @@ async function createServerHandle(config) {
6151
6129
  if (!result.success) {
6152
6130
  return res.status(400).json({ error: result.error });
6153
6131
  }
6154
- const { loadGlobalConfig, saveGlobalConfig } = await import("./config-DEM6ASQM.js");
6132
+ const { loadGlobalConfig, saveGlobalConfig } = await import("./config-67AX6CNS.js");
6155
6133
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
6156
6134
  const updatedProviders = providerManager.getProviders();
6157
6135
  const updatedConfig = {
@@ -6232,7 +6210,7 @@ async function createServerHandle(config) {
6232
6210
  const entries = await import("fs/promises").then((m) => m.readdir(resolvedPath, { withFileTypes: true }));
6233
6211
  const directories = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => ({
6234
6212
  name: entry.name,
6235
- path: join5(resolvedPath, entry.name)
6213
+ path: join6(resolvedPath, entry.name)
6236
6214
  })).sort((a, b) => a.name.localeCompare(b.name));
6237
6215
  const parent = dirname5(resolvedPath);
6238
6216
  const hasParent = parent !== resolvedPath;
@@ -6279,7 +6257,7 @@ async function createServerHandle(config) {
6279
6257
  }
6280
6258
  });
6281
6259
  app.get("/fox.svg", (_req, res) => {
6282
- readFile4(join5(webDir, "fox.svg")).then((content) => {
6260
+ readFile4(join6(webDir, "fox.svg")).then((content) => {
6283
6261
  res.set("Content-Type", "image/svg+xml");
6284
6262
  res.send(content);
6285
6263
  }).catch(() => {
@@ -6288,7 +6266,7 @@ async function createServerHandle(config) {
6288
6266
  });
6289
6267
  app.use(
6290
6268
  "/sounds",
6291
- express.static(join5(webDir, "public", "sounds"), {
6269
+ express.static(join6(webDir, "public", "sounds"), {
6292
6270
  setHeaders: (res) => {
6293
6271
  res.set("Content-Type", "audio/mpeg");
6294
6272
  }
@@ -6298,7 +6276,7 @@ async function createServerHandle(config) {
6298
6276
  if (req.path.startsWith("/api/")) {
6299
6277
  return;
6300
6278
  }
6301
- readFile4(join5(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
6279
+ readFile4(join6(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
6302
6280
  logger.error("Error serving index.html", { error: err });
6303
6281
  res.status(500).send("Server error");
6304
6282
  });
@@ -6309,7 +6287,7 @@ async function createServerHandle(config) {
6309
6287
  const distWebDir = resolve(__dirname2, "web");
6310
6288
  app.use(
6311
6289
  "/assets",
6312
- express.static(join5(distWebDir, "assets"), {
6290
+ express.static(join6(distWebDir, "assets"), {
6313
6291
  setHeaders: (res, filepath) => {
6314
6292
  if (filepath.endsWith(".css")) {
6315
6293
  res.set("Content-Type", "text/css");
@@ -6317,11 +6295,11 @@ async function createServerHandle(config) {
6317
6295
  }
6318
6296
  })
6319
6297
  );
6320
- app.use("/manifest.webmanifest", express.static(join5(distWebDir, "manifest.webmanifest")));
6321
- app.use("/registerSW.js", express.static(join5(distWebDir, "registerSW.js")));
6322
- app.use("/sw.js", express.static(join5(distWebDir, "sw.js")));
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")));
6323
6301
  app.get("/fox.svg", (_req, res) => {
6324
- readFile4(join5(distWebDir, "fox.svg")).then((content) => {
6302
+ readFile4(join6(distWebDir, "fox.svg")).then((content) => {
6325
6303
  res.set("Content-Type", "image/svg+xml");
6326
6304
  res.send(content);
6327
6305
  }).catch(() => {
@@ -6330,14 +6308,14 @@ async function createServerHandle(config) {
6330
6308
  });
6331
6309
  app.use(
6332
6310
  "/sounds",
6333
- express.static(join5(distWebDir, "sounds"), {
6311
+ express.static(join6(distWebDir, "sounds"), {
6334
6312
  setHeaders: (res) => {
6335
6313
  res.set("Content-Type", "audio/mpeg");
6336
6314
  }
6337
6315
  })
6338
6316
  );
6339
6317
  app.get("/", (_req, res) => {
6340
- readFile4(join5(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6318
+ readFile4(join6(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6341
6319
  res.status(404).send("Web UI not built. Run `npm run build:web`");
6342
6320
  });
6343
6321
  });
@@ -6345,7 +6323,7 @@ async function createServerHandle(config) {
6345
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") {
6346
6324
  return;
6347
6325
  }
6348
- readFile4(join5(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6326
+ readFile4(join6(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6349
6327
  res.status(404).send("Web UI not built");
6350
6328
  });
6351
6329
  });
@@ -6360,7 +6338,7 @@ async function createServerHandle(config) {
6360
6338
  providerManager
6361
6339
  );
6362
6340
  const wss = wssExports.wss;
6363
- const { QueueProcessor } = await import("./processor-KBSF2HFD.js");
6341
+ const { QueueProcessor } = await import("./processor-VUEJM73B.js");
6364
6342
  const queueProcessor = new QueueProcessor({
6365
6343
  sessionManager,
6366
6344
  providerManager,
@@ -6433,4 +6411,4 @@ export {
6433
6411
  createServerHandle,
6434
6412
  createServer
6435
6413
  };
6436
- //# sourceMappingURL=chunk-3JU6H6A4.js.map
6414
+ //# sourceMappingURL=chunk-NN65D5SI.js.map