openfox 1.2.0 → 1.2.2

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 (29) hide show
  1. package/dist/{auto-compaction-7RNWXTRQ.js → auto-compaction-Q36IMXD4.js} +3 -3
  2. package/dist/{chat-handler-ZBY3GCFF.js → chat-handler-BTU2FLJY.js} +5 -5
  3. package/dist/{chunk-CUXZUI2X.js → chunk-36AJGM6G.js} +3 -3
  4. package/dist/{chunk-2CK3CWOE.js → chunk-47TNOR2U.js} +239 -60
  5. package/dist/{chunk-CDITGSG3.js → chunk-BNK5N227.js} +3 -3
  6. package/dist/{chunk-GMWOLNCU.js → chunk-IBA3NQAD.js} +2 -2
  7. package/dist/{chunk-3AMXYXIA.js → chunk-NGSSEMII.js} +4 -4
  8. package/dist/{chunk-AOHPSZIW.js → chunk-NIQ4X7Y7.js} +2 -2
  9. package/dist/{chunk-KQRQXKH2.js → chunk-QYRLQ3NK.js} +12 -12
  10. package/dist/{chunk-5YQAXUKO.js → chunk-R4HADRYO.js} +9 -1
  11. package/dist/{chunk-A6NVV74R.js → chunk-YSPC6TQJ.js} +9 -3
  12. package/dist/cli/dev.js +1 -1
  13. package/dist/cli/index.js +1 -1
  14. package/dist/{config-VP3V5VGN.js → config-ONC2MTDE.js} +5 -5
  15. package/dist/{init-T35BNPF2.js → init-TLQQLRGQ.js} +89 -13
  16. package/dist/{orchestrator-NH3BO64D.js → orchestrator-TFJHY67A.js} +4 -4
  17. package/dist/package.json +1 -1
  18. package/dist/{paths-MM76AWYB.js → paths-ZRI56O63.js} +6 -2
  19. package/dist/{processor-W55O5T6T.js → processor-KJBVOF4W.js} +2 -2
  20. package/dist/{provider-CHKLHKG5.js → provider-FAO4R2GH.js} +7 -7
  21. package/dist/{serve-XGOABBXJ.js → serve-MRW7EKGE.js} +10 -10
  22. package/dist/server/index.js +7 -7
  23. package/dist/skill-defaults/{playwright-cli.skill.md → browser.skill.md} +5 -5
  24. package/dist/{tools-EGSJDCYX.js → tools-4D6R2BA3.js} +3 -3
  25. package/dist/{vision-fallback-MUKHLGFR.js → vision-fallback-MGSC5SWE.js} +2 -2
  26. package/dist/web/assets/{index-BY3Xdvmg.js → index-rZhr4yUO.js} +52 -52
  27. package/dist/web/index.html +1 -1
  28. package/dist/web/sw.js +1 -1
  29. package/package.json +1 -1
@@ -2,7 +2,7 @@ import {
2
2
  maybeAutoCompactContext,
3
3
  performManualContextCompaction,
4
4
  resolveCompactionStatsIdentity
5
- } from "./chunk-CUXZUI2X.js";
5
+ } from "./chunk-36AJGM6G.js";
6
6
  import "./chunk-NW7PIZH3.js";
7
7
  import "./chunk-WQ4W5H6A.js";
8
8
  import "./chunk-S4QKTRGJ.js";
@@ -13,11 +13,11 @@ import "./chunk-3EHGGBWE.js";
13
13
  import "./chunk-TPT6HP4H.js";
14
14
  import "./chunk-TVQOONDR.js";
15
15
  import "./chunk-XFXOSPYH.js";
16
- import "./chunk-5YQAXUKO.js";
16
+ import "./chunk-R4HADRYO.js";
17
17
  import "./chunk-PNBH3RAX.js";
18
18
  export {
19
19
  maybeAutoCompactContext,
20
20
  performManualContextCompaction,
21
21
  resolveCompactionStatsIdentity
22
22
  };
23
- //# sourceMappingURL=auto-compaction-7RNWXTRQ.js.map
23
+ //# sourceMappingURL=auto-compaction-Q36IMXD4.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  runChatTurn
3
- } from "./chunk-AOHPSZIW.js";
4
- import "./chunk-CUXZUI2X.js";
3
+ } from "./chunk-NIQ4X7Y7.js";
4
+ import "./chunk-36AJGM6G.js";
5
5
  import {
6
6
  generateSessionName,
7
7
  needsNameGeneration
@@ -28,7 +28,7 @@ import "./chunk-3EHGGBWE.js";
28
28
  import "./chunk-TPT6HP4H.js";
29
29
  import "./chunk-TVQOONDR.js";
30
30
  import "./chunk-XFXOSPYH.js";
31
- import "./chunk-5YQAXUKO.js";
31
+ import "./chunk-R4HADRYO.js";
32
32
  import {
33
33
  logger
34
34
  } from "./chunk-PNBH3RAX.js";
@@ -59,7 +59,7 @@ async function startChatSession(sessionId, content, deps, options) {
59
59
  sessionManager.setRunning(sessionId, true);
60
60
  broadcastForSession(sessionId, createSessionRunningMessage(true));
61
61
  try {
62
- const { maybeAutoCompactContext } = await import("./auto-compaction-7RNWXTRQ.js");
62
+ const { maybeAutoCompactContext } = await import("./auto-compaction-Q36IMXD4.js");
63
63
  await maybeAutoCompactContext({
64
64
  sessionManager,
65
65
  sessionId,
@@ -198,4 +198,4 @@ export {
198
198
  startChatSession,
199
199
  stopSessionExecution
200
200
  };
201
- //# sourceMappingURL=chat-handler-ZBY3GCFF.js.map
201
+ //# sourceMappingURL=chat-handler-BTU2FLJY.js.map
@@ -30,7 +30,7 @@ import {
30
30
  } from "./chunk-XFXOSPYH.js";
31
31
  import {
32
32
  getGlobalConfigDir
33
- } from "./chunk-5YQAXUKO.js";
33
+ } from "./chunk-R4HADRYO.js";
34
34
  import {
35
35
  logger
36
36
  } from "./chunk-PNBH3RAX.js";
@@ -3472,7 +3472,7 @@ var callSubAgentTool = {
3472
3472
  };
3473
3473
  }
3474
3474
  try {
3475
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-EGSJDCYX.js");
3475
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-4D6R2BA3.js");
3476
3476
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3477
3477
  const turnMetrics = new TurnMetrics();
3478
3478
  const result = await executeSubAgent({
@@ -4480,4 +4480,4 @@ export {
4480
4480
  getToolRegistryForAgent,
4481
4481
  createToolRegistry
4482
4482
  };
4483
- //# sourceMappingURL=chunk-CUXZUI2X.js.map
4483
+ //# sourceMappingURL=chunk-36AJGM6G.js.map
@@ -2,7 +2,7 @@ import {
2
2
  createVerifierNudgeConfig,
3
3
  runBuilderTurn,
4
4
  runChatTurn
5
- } from "./chunk-AOHPSZIW.js";
5
+ } from "./chunk-NIQ4X7Y7.js";
6
6
  import {
7
7
  TurnMetrics,
8
8
  agentExists,
@@ -40,7 +40,7 @@ import {
40
40
  saveSkill,
41
41
  setSkillEnabled,
42
42
  skillExists
43
- } from "./chunk-CUXZUI2X.js";
43
+ } from "./chunk-36AJGM6G.js";
44
44
  import {
45
45
  generateSessionName,
46
46
  needsNameGeneration
@@ -48,7 +48,7 @@ import {
48
48
  import {
49
49
  createProviderManager,
50
50
  parseDefaultModelSelection
51
- } from "./chunk-A6NVV74R.js";
51
+ } from "./chunk-YSPC6TQJ.js";
52
52
  import {
53
53
  createSession,
54
54
  deleteSession,
@@ -124,10 +124,10 @@ import {
124
124
  getBackendDisplayName,
125
125
  getLlmStatus,
126
126
  getModelProfile
127
- } from "./chunk-3AMXYXIA.js";
127
+ } from "./chunk-NGSSEMII.js";
128
128
  import {
129
129
  getGlobalConfigDir
130
- } from "./chunk-5YQAXUKO.js";
130
+ } from "./chunk-R4HADRYO.js";
131
131
  import {
132
132
  logger,
133
133
  setLogLevel
@@ -138,8 +138,8 @@ import express from "express";
138
138
  import cors from "cors";
139
139
  import { createServer as createHttpServer } from "http";
140
140
  import { fileURLToPath as fileURLToPath4 } from "url";
141
- import { dirname as dirname4, resolve, join as join4 } from "path";
142
- import { readFile as readFile3 } from "fs/promises";
141
+ import { dirname as dirname5, resolve, join as join5 } from "path";
142
+ import { readFile as readFile4 } from "fs/promises";
143
143
  import { createServer as createViteServer } from "vite";
144
144
 
145
145
  // src/server/llm/mock.ts
@@ -2122,6 +2122,130 @@ function needsSummaryGeneration(sessionSummary) {
2122
2122
  return sessionSummary === null || sessionSummary.trim() === "";
2123
2123
  }
2124
2124
 
2125
+ // src/server/auth.ts
2126
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
2127
+ import { join as join2, dirname as dirname2 } from "path";
2128
+ import { createHash, privateDecrypt, createPublicKey } from "crypto";
2129
+ function getAuthConfigPath() {
2130
+ const configDir = getRuntimeConfig();
2131
+ const mode = configDir.mode === "development" ? "development" : configDir.mode === "test" ? "test" : "production";
2132
+ if (mode === "test") {
2133
+ const cwd = process.cwd();
2134
+ const base = cwd.endsWith("/e2e") ? cwd : join2(cwd, "e2e");
2135
+ const testAuthPath = join2(base, ".openfox-test", "auth.json");
2136
+ return testAuthPath;
2137
+ }
2138
+ const home = process.env["HOME"] || process.env["USERPROFILE"] || "";
2139
+ const basePath = process.env["XDG_CONFIG_HOME"] || `${home}/.config`;
2140
+ const suffix = mode === "development" ? "-dev" : "";
2141
+ return `${basePath}/openfox${suffix}/auth.json`;
2142
+ }
2143
+ function getKeyPath() {
2144
+ const authPath = getAuthConfigPath();
2145
+ const dir = dirname2(authPath);
2146
+ return join2(dir, "auth.key");
2147
+ }
2148
+ var cachedAuth = null;
2149
+ var cachedPrivateKey = null;
2150
+ async function loadPrivateKey() {
2151
+ if (cachedPrivateKey) {
2152
+ return cachedPrivateKey;
2153
+ }
2154
+ const keyPath = getKeyPath();
2155
+ const keyDir = dirname2(keyPath);
2156
+ try {
2157
+ cachedPrivateKey = await readFile2(keyPath, "utf-8");
2158
+ return cachedPrivateKey;
2159
+ } catch {
2160
+ const { privateKey } = await import("crypto").then((c) => c.generateKeyPairSync("rsa", {
2161
+ modulusLength: 2048,
2162
+ privateKeyEncoding: { type: "pkcs8", format: "pem" },
2163
+ publicKeyEncoding: { type: "spki", format: "pem" }
2164
+ }));
2165
+ await mkdir2(keyDir, { recursive: true });
2166
+ await writeFile2(keyPath, privateKey, { mode: 384 });
2167
+ cachedPrivateKey = privateKey;
2168
+ return privateKey;
2169
+ }
2170
+ }
2171
+ async function loadServerAuthConfig() {
2172
+ const configDir = getRuntimeConfig();
2173
+ const isTestMode = configDir.mode === "test";
2174
+ if (!isTestMode) {
2175
+ if (cachedAuth) {
2176
+ return cachedAuth;
2177
+ }
2178
+ }
2179
+ try {
2180
+ const authPath = getAuthConfigPath();
2181
+ const data = await readFile2(authPath, "utf-8");
2182
+ const authConfig = JSON.parse(data);
2183
+ cachedAuth = authConfig;
2184
+ return authConfig;
2185
+ } catch {
2186
+ return null;
2187
+ }
2188
+ }
2189
+ function getAuthConfig() {
2190
+ return cachedAuth;
2191
+ }
2192
+ function hashPassword(password) {
2193
+ return createHash("sha256").update(password).digest("hex");
2194
+ }
2195
+ function requiresAuth() {
2196
+ return cachedAuth?.strategy === "network";
2197
+ }
2198
+ function hasPassword() {
2199
+ return cachedAuth?.encryptedPassword != null && cachedAuth.encryptedPassword.length > 0;
2200
+ }
2201
+ async function verifyPassword(password) {
2202
+ const encryptedPassword = cachedAuth?.encryptedPassword;
2203
+ if (!encryptedPassword) return false;
2204
+ const privateKey = await loadPrivateKey();
2205
+ try {
2206
+ const decrypted = privateDecrypt(
2207
+ { key: privateKey, padding: 1 },
2208
+ Buffer.from(encryptedPassword, "base64")
2209
+ );
2210
+ return decrypted.toString() === password;
2211
+ } catch {
2212
+ return false;
2213
+ }
2214
+ }
2215
+ async function tokenFromPassword(password) {
2216
+ const privateKey = await loadPrivateKey();
2217
+ const passwordHash = hashPassword(password);
2218
+ const sign = await import("crypto").then((c) => {
2219
+ const s = c.createSign("SHA256");
2220
+ s.update(passwordHash);
2221
+ s.end();
2222
+ return s.sign(privateKey, "base64");
2223
+ });
2224
+ return sign;
2225
+ }
2226
+ async function isValidToken(token) {
2227
+ if (!cachedAuth?.encryptedPassword) return false;
2228
+ const privateKey = await loadPrivateKey();
2229
+ try {
2230
+ const decrypted = privateDecrypt(
2231
+ { key: privateKey, padding: 1 },
2232
+ Buffer.from(cachedAuth.encryptedPassword, "base64")
2233
+ );
2234
+ const storedPassword = decrypted.toString();
2235
+ const storedHash = hashPassword(storedPassword);
2236
+ const verify = await import("crypto").then((c) => {
2237
+ const v = c.createVerify("SHA256");
2238
+ v.update(storedHash);
2239
+ v.end();
2240
+ return v;
2241
+ });
2242
+ const publicKey = createPublicKey(privateKey).export({ type: "spki", format: "pem" });
2243
+ return verify.verify(publicKey, token, "base64");
2244
+ } catch {
2245
+ return false;
2246
+ }
2247
+ }
2248
+
2125
2249
  // src/server/ws/server.ts
2126
2250
  function getCurrentWindowMessageOptions2(sessionId) {
2127
2251
  const contextWindowId = getCurrentContextWindowId(sessionId);
@@ -2154,7 +2278,7 @@ function resolveStatsIdentity(llmClient, getActiveProvider) {
2154
2278
  }
2155
2279
  var activeAgents = /* @__PURE__ */ new Map();
2156
2280
  function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvider, sessionManager, providerManager) {
2157
- const wss = new WebSocketServer({ server: httpServer, path: "/ws" });
2281
+ const wss = new WebSocketServer({ server: httpServer });
2158
2282
  const clients = /* @__PURE__ */ new Map();
2159
2283
  const sessionLLMClients = /* @__PURE__ */ new Map();
2160
2284
  function getSessionLLMClient(sessionId) {
@@ -2364,7 +2488,18 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2364
2488
  errorMessage
2365
2489
  }));
2366
2490
  });
2367
- wss.on("connection", (ws) => {
2491
+ wss.on("connection", async (ws, req) => {
2492
+ const url = new URL(req.url || "/", `http://${req.headers.host}`);
2493
+ const token = url.searchParams.get("token");
2494
+ const authConfig = getAuthConfig();
2495
+ if (authConfig?.strategy === "network" && authConfig.encryptedPassword) {
2496
+ if (!token || !await isValidToken(token)) {
2497
+ setTimeout(() => {
2498
+ ws.close(4e3, "Unauthorized");
2499
+ }, 100);
2500
+ return;
2501
+ }
2502
+ }
2368
2503
  logger.debug("WebSocket client connected");
2369
2504
  clients.set(ws, { ws, activeSessionId: null, subscribedSessions: /* @__PURE__ */ new Map(), eventStoreSubscriptions: /* @__PURE__ */ new Map() });
2370
2505
  ws.on("message", async (data) => {
@@ -3381,14 +3516,14 @@ var LspServer = class {
3381
3516
 
3382
3517
  // src/server/utils/which.ts
3383
3518
  import { access as access2, constants as constants2 } from "fs/promises";
3384
- import { join as join2, dirname as dirname2 } from "path";
3519
+ import { join as join3, dirname as dirname3 } from "path";
3385
3520
  import { fileURLToPath as fileURLToPath2 } from "url";
3386
- var __dirname = dirname2(fileURLToPath2(import.meta.url));
3521
+ var __dirname = dirname3(fileURLToPath2(import.meta.url));
3387
3522
  function getBundledBinPaths() {
3388
3523
  const paths = [];
3389
- paths.push(join2(process.cwd(), "node_modules", ".bin"));
3390
- paths.push(join2(__dirname, "..", "..", "..", "node_modules", ".bin"));
3391
- paths.push(join2(__dirname, "..", "..", "..", "..", "node_modules", ".bin"));
3524
+ paths.push(join3(process.cwd(), "node_modules", ".bin"));
3525
+ paths.push(join3(__dirname, "..", "..", "..", "node_modules", ".bin"));
3526
+ paths.push(join3(__dirname, "..", "..", "..", "..", "node_modules", ".bin"));
3392
3527
  return paths;
3393
3528
  }
3394
3529
  async function existsExecutable(path) {
@@ -3407,13 +3542,13 @@ async function which(command, workdir) {
3407
3542
  return null;
3408
3543
  }
3409
3544
  for (const binDir of getBundledBinPaths()) {
3410
- const fullPath = join2(binDir, command);
3545
+ const fullPath = join3(binDir, command);
3411
3546
  if (await existsExecutable(fullPath)) {
3412
3547
  return fullPath;
3413
3548
  }
3414
3549
  }
3415
3550
  if (workdir) {
3416
- const projectBin = join2(workdir, "node_modules", ".bin", command);
3551
+ const projectBin = join3(workdir, "node_modules", ".bin", command);
3417
3552
  if (await existsExecutable(projectBin)) {
3418
3553
  return projectBin;
3419
3554
  }
@@ -3422,7 +3557,7 @@ async function which(command, workdir) {
3422
3557
  const paths = pathEnv.split(":");
3423
3558
  for (const dir of paths) {
3424
3559
  if (!dir) continue;
3425
- const fullPath = join2(dir, command);
3560
+ const fullPath = join3(dir, command);
3426
3561
  if (await existsExecutable(fullPath)) {
3427
3562
  return fullPath;
3428
3563
  }
@@ -4795,17 +4930,17 @@ ${summary}`,
4795
4930
  };
4796
4931
 
4797
4932
  // src/server/commands/registry.ts
4798
- import { readdir as readdir2, readFile as readFile2, writeFile as writeFile2, copyFile as copyFile2, mkdir as mkdir2, access as access3, unlink as unlink2 } from "fs/promises";
4799
- import { join as join3, dirname as dirname3 } from "path";
4933
+ 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";
4934
+ import { join as join4, dirname as dirname4 } from "path";
4800
4935
  import { constants as constants3 } from "fs";
4801
4936
  import { fileURLToPath as fileURLToPath3 } from "url";
4802
4937
  import matter from "gray-matter";
4803
- var __bundleDir2 = dirname3(fileURLToPath3(import.meta.url));
4804
- var DEFAULTS_DIR2 = join3(__bundleDir2, "defaults");
4805
- var DEFAULTS_DIR_ALT2 = join3(__bundleDir2, "command-defaults");
4938
+ var __bundleDir2 = dirname4(fileURLToPath3(import.meta.url));
4939
+ var DEFAULTS_DIR2 = join4(__bundleDir2, "defaults");
4940
+ var DEFAULTS_DIR_ALT2 = join4(__bundleDir2, "command-defaults");
4806
4941
  var COMMAND_EXTENSION = ".command.md";
4807
4942
  function getCommandsDir(configDir) {
4808
- return join3(configDir, "commands");
4943
+ return join4(configDir, "commands");
4809
4944
  }
4810
4945
  async function dirExists(path) {
4811
4946
  try {
@@ -4818,7 +4953,7 @@ async function dirExists(path) {
4818
4953
  async function ensureDefaultCommands(configDir) {
4819
4954
  const commandsDir = getCommandsDir(configDir);
4820
4955
  if (!await dirExists(commandsDir)) {
4821
- await mkdir2(commandsDir, { recursive: true });
4956
+ await mkdir3(commandsDir, { recursive: true });
4822
4957
  }
4823
4958
  let defaultFiles;
4824
4959
  let sourceDir;
@@ -4835,10 +4970,10 @@ async function ensureDefaultCommands(configDir) {
4835
4970
  }
4836
4971
  }
4837
4972
  for (const file of defaultFiles) {
4838
- const targetPath = join3(commandsDir, file);
4973
+ const targetPath = join4(commandsDir, file);
4839
4974
  if (!await dirExists(targetPath)) {
4840
4975
  try {
4841
- await copyFile2(join3(sourceDir, file), targetPath);
4976
+ await copyFile2(join4(sourceDir, file), targetPath);
4842
4977
  logger.info("Installed default command", { file });
4843
4978
  } catch (err) {
4844
4979
  logger.error("Failed to copy default command", { file, error: err instanceof Error ? err.message : String(err) });
@@ -4860,7 +4995,7 @@ async function loadAllCommands(configDir) {
4860
4995
  const commands = [];
4861
4996
  for (const file of files) {
4862
4997
  try {
4863
- const raw = await readFile2(join3(commandsDir, file), "utf-8");
4998
+ const raw = await readFile3(join4(commandsDir, file), "utf-8");
4864
4999
  const { data, content } = matter(raw);
4865
5000
  const metadata = data;
4866
5001
  if (metadata.id && content.trim()) {
@@ -4887,9 +5022,9 @@ async function getDefaultCommandIds() {
4887
5022
  async function restoreDefaultCommand(configDir, commandId) {
4888
5023
  const filename = `${commandId}${COMMAND_EXTENSION}`;
4889
5024
  for (const dir of [DEFAULTS_DIR2, DEFAULTS_DIR_ALT2]) {
4890
- const sourcePath = join3(dir, filename);
5025
+ const sourcePath = join4(dir, filename);
4891
5026
  if (await dirExists(sourcePath)) {
4892
- const targetPath = join3(getCommandsDir(configDir), filename);
5027
+ const targetPath = join4(getCommandsDir(configDir), filename);
4893
5028
  await copyFile2(sourcePath, targetPath);
4894
5029
  return true;
4895
5030
  }
@@ -4901,18 +5036,18 @@ async function getModifiedDefaultCommandIds(configDir) {
4901
5036
  const modified = [];
4902
5037
  for (const id of defaultIds) {
4903
5038
  const filename = `${id}${COMMAND_EXTENSION}`;
4904
- const userPath = join3(getCommandsDir(configDir), filename);
5039
+ const userPath = join4(getCommandsDir(configDir), filename);
4905
5040
  let bundledContent = null;
4906
5041
  for (const dir of [DEFAULTS_DIR2, DEFAULTS_DIR_ALT2]) {
4907
5042
  try {
4908
- bundledContent = await readFile2(join3(dir, filename), "utf-8");
5043
+ bundledContent = await readFile3(join4(dir, filename), "utf-8");
4909
5044
  break;
4910
5045
  } catch {
4911
5046
  }
4912
5047
  }
4913
5048
  if (!bundledContent) continue;
4914
5049
  try {
4915
- const userContent = await readFile2(userPath, "utf-8");
5050
+ const userContent = await readFile3(userPath, "utf-8");
4916
5051
  if (userContent !== bundledContent) {
4917
5052
  modified.push(id);
4918
5053
  }
@@ -4933,20 +5068,20 @@ function findCommandById(commandId, commands) {
4933
5068
  return commands.find((c) => c.metadata.id === commandId);
4934
5069
  }
4935
5070
  async function commandExists(configDir, commandId) {
4936
- const filePath = join3(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
5071
+ const filePath = join4(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
4937
5072
  return dirExists(filePath);
4938
5073
  }
4939
5074
  async function saveCommand(configDir, command) {
4940
5075
  const commandsDir = getCommandsDir(configDir);
4941
5076
  if (!await dirExists(commandsDir)) {
4942
- await mkdir2(commandsDir, { recursive: true });
5077
+ await mkdir3(commandsDir, { recursive: true });
4943
5078
  }
4944
- const filePath = join3(commandsDir, `${command.metadata.id}${COMMAND_EXTENSION}`);
5079
+ const filePath = join4(commandsDir, `${command.metadata.id}${COMMAND_EXTENSION}`);
4945
5080
  const content = matter.stringify(command.prompt, command.metadata);
4946
- await writeFile2(filePath, content, "utf-8");
5081
+ await writeFile3(filePath, content, "utf-8");
4947
5082
  }
4948
5083
  async function deleteCommand(configDir, commandId) {
4949
- const filePath = join3(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
5084
+ const filePath = join4(getCommandsDir(configDir), `${commandId}${COMMAND_EXTENSION}`);
4950
5085
  try {
4951
5086
  await unlink2(filePath);
4952
5087
  return true;
@@ -5415,10 +5550,11 @@ function createTerminalRoutes() {
5415
5550
  }
5416
5551
 
5417
5552
  // src/server/index.ts
5418
- var __dirname2 = dirname4(fileURLToPath4(import.meta.url));
5553
+ var __dirname2 = dirname5(fileURLToPath4(import.meta.url));
5419
5554
  async function createServerHandle(config) {
5420
5555
  setRuntimeConfig(config);
5421
5556
  setLogLevel(config.logging?.level ?? void 0, config.mode);
5557
+ await loadServerAuthConfig();
5422
5558
  const db = initDatabase(config);
5423
5559
  initEventStore(db);
5424
5560
  const configDir = getGlobalConfigDir(config.mode ?? "production");
@@ -5479,9 +5615,52 @@ async function createServerHandle(config) {
5479
5615
  const app = express();
5480
5616
  app.use(cors());
5481
5617
  app.use(express.json());
5618
+ const authMiddleware = async (req, res, next) => {
5619
+ const path = req.path;
5620
+ const publicPaths = ["/health", "/auth", "/auth/login"];
5621
+ if (publicPaths.includes(path)) {
5622
+ return next();
5623
+ }
5624
+ const authConfig = getAuthConfig();
5625
+ if (authConfig?.strategy === "network" && authConfig.encryptedPassword) {
5626
+ const token = req.headers["x-session-token"];
5627
+ if (!token || !await isValidToken(token)) {
5628
+ res.status(401).json({ error: "Unauthorized" });
5629
+ return;
5630
+ }
5631
+ }
5632
+ next();
5633
+ };
5634
+ app.use("/api", authMiddleware);
5482
5635
  app.get("/api/health", (_req, res) => {
5483
5636
  res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
5484
5637
  });
5638
+ app.get("/api/auth", (_req, res) => {
5639
+ const authRequired = requiresAuth();
5640
+ const hasPwd = hasPassword();
5641
+ res.json({
5642
+ requiresAuth: authRequired && hasPwd,
5643
+ hasPassword: hasPwd
5644
+ });
5645
+ });
5646
+ app.post("/api/auth/login", async (req, res) => {
5647
+ const authConfig = getAuthConfig();
5648
+ if (authConfig?.strategy !== "network" || !authConfig.encryptedPassword) {
5649
+ res.status(400).json({ error: "Auth not configured" });
5650
+ return;
5651
+ }
5652
+ const password = req.body.password;
5653
+ if (!password || typeof password !== "string") {
5654
+ res.status(401).json({ error: "Password required" });
5655
+ return;
5656
+ }
5657
+ if (!await verifyPassword(password)) {
5658
+ res.status(401).json({ error: "Invalid password" });
5659
+ return;
5660
+ }
5661
+ const token = await tokenFromPassword(password);
5662
+ res.json({ token });
5663
+ });
5485
5664
  app.get("/api/tools", (_req, res) => {
5486
5665
  const tools = toolRegistry.tools.map((t) => ({
5487
5666
  name: t.name,
@@ -5609,7 +5788,7 @@ async function createServerHandle(config) {
5609
5788
  return res.status(400).json({ error: "providerId is required" });
5610
5789
  }
5611
5790
  sessionManager.setSessionProvider(sessionId, providerId, model ?? "auto");
5612
- const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-VP3V5VGN.js");
5791
+ const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-ONC2MTDE.js");
5613
5792
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
5614
5793
  const updatedConfig = setDefaultModelSelection(globalConfig, providerId, model ?? "auto");
5615
5794
  await saveGlobalConfig(config.mode ?? "production", updatedConfig);
@@ -5674,7 +5853,7 @@ async function createServerHandle(config) {
5674
5853
  if (!callId || approved === void 0) {
5675
5854
  return res.status(400).json({ error: "callId and approved are required" });
5676
5855
  }
5677
- const { providePathConfirmation: providePathConfirmation2 } = await import("./tools-EGSJDCYX.js");
5856
+ const { providePathConfirmation: providePathConfirmation2 } = await import("./tools-4D6R2BA3.js");
5678
5857
  const result = providePathConfirmation2(callId, approved, alwaysAllow);
5679
5858
  if (!result.found) {
5680
5859
  return res.status(404).json({ error: "No pending path confirmation with that ID" });
@@ -5699,7 +5878,7 @@ async function createServerHandle(config) {
5699
5878
  if (!callId || !answer) {
5700
5879
  return res.status(400).json({ error: "callId and answer are required" });
5701
5880
  }
5702
- const { provideAnswer: provideAnswer2 } = await import("./tools-EGSJDCYX.js");
5881
+ const { provideAnswer: provideAnswer2 } = await import("./tools-4D6R2BA3.js");
5703
5882
  const found = provideAnswer2(callId, answer);
5704
5883
  if (!found) {
5705
5884
  return res.status(404).json({ error: "No pending question with that ID" });
@@ -5735,8 +5914,8 @@ async function createServerHandle(config) {
5735
5914
  if (!session) {
5736
5915
  return res.status(404).json({ error: "Session not found" });
5737
5916
  }
5738
- const { stopSessionExecution } = await import("./chat-handler-ZBY3GCFF.js");
5739
- const { cancelQuestionsForSession: cancelQuestionsForSession2, cancelPathConfirmationsForSession: cancelPathConfirmationsForSession2 } = await import("./tools-EGSJDCYX.js");
5917
+ const { stopSessionExecution } = await import("./chat-handler-BTU2FLJY.js");
5918
+ const { cancelQuestionsForSession: cancelQuestionsForSession2, cancelPathConfirmationsForSession: cancelPathConfirmationsForSession2 } = await import("./tools-4D6R2BA3.js");
5740
5919
  stopSessionExecution(sessionId, sessionManager);
5741
5920
  abortSession(sessionId);
5742
5921
  cancelQuestionsForSession2(sessionId, "Session stopped by user");
@@ -5851,7 +6030,7 @@ async function createServerHandle(config) {
5851
6030
  return res.status(400).json({ error: result.error });
5852
6031
  }
5853
6032
  const llmClient = getLLMClient();
5854
- const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-VP3V5VGN.js");
6033
+ const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-ONC2MTDE.js");
5855
6034
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
5856
6035
  const updatedConfig = setDefaultModelSelection(globalConfig, id, llmClient.getModel());
5857
6036
  await saveGlobalConfig(config.mode ?? "production", updatedConfig);
@@ -5872,7 +6051,7 @@ async function createServerHandle(config) {
5872
6051
  if (!result.success) {
5873
6052
  return res.status(400).json({ error: result.error });
5874
6053
  }
5875
- const { loadGlobalConfig, saveGlobalConfig } = await import("./config-VP3V5VGN.js");
6054
+ const { loadGlobalConfig, saveGlobalConfig } = await import("./config-ONC2MTDE.js");
5876
6055
  const globalConfig = await loadGlobalConfig(config.mode ?? "production");
5877
6056
  const updatedProviders = providerManager.getProviders();
5878
6057
  const updatedConfig = {
@@ -5932,9 +6111,9 @@ async function createServerHandle(config) {
5932
6111
  const entries = await import("fs/promises").then((m) => m.readdir(resolvedPath, { withFileTypes: true }));
5933
6112
  const directories = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => ({
5934
6113
  name: entry.name,
5935
- path: join4(resolvedPath, entry.name)
6114
+ path: join5(resolvedPath, entry.name)
5936
6115
  })).sort((a, b) => a.name.localeCompare(b.name));
5937
- const parent = dirname4(resolvedPath);
6116
+ const parent = dirname5(resolvedPath);
5938
6117
  const hasParent = parent !== resolvedPath;
5939
6118
  res.json({
5940
6119
  current: resolvedPath,
@@ -5979,7 +6158,7 @@ async function createServerHandle(config) {
5979
6158
  }
5980
6159
  });
5981
6160
  app.get("/fox.svg", (_req, res) => {
5982
- readFile3(join4(webDir, "fox.svg")).then((content) => {
6161
+ readFile4(join5(webDir, "fox.svg")).then((content) => {
5983
6162
  res.set("Content-Type", "image/svg+xml");
5984
6163
  res.send(content);
5985
6164
  }).catch(() => {
@@ -5988,7 +6167,7 @@ async function createServerHandle(config) {
5988
6167
  });
5989
6168
  app.use(
5990
6169
  "/sounds",
5991
- express.static(join4(webDir, "public", "sounds"), {
6170
+ express.static(join5(webDir, "public", "sounds"), {
5992
6171
  setHeaders: (res) => {
5993
6172
  res.set("Content-Type", "audio/mpeg");
5994
6173
  }
@@ -5998,7 +6177,7 @@ async function createServerHandle(config) {
5998
6177
  if (req.path.startsWith("/api/")) {
5999
6178
  return;
6000
6179
  }
6001
- readFile3(join4(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
6180
+ readFile4(join5(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
6002
6181
  logger.error("Error serving index.html", { error: err });
6003
6182
  res.status(500).send("Server error");
6004
6183
  });
@@ -6009,7 +6188,7 @@ async function createServerHandle(config) {
6009
6188
  const distWebDir = resolve(__dirname2, "web");
6010
6189
  app.use(
6011
6190
  "/assets",
6012
- express.static(join4(distWebDir, "assets"), {
6191
+ express.static(join5(distWebDir, "assets"), {
6013
6192
  setHeaders: (res, filepath) => {
6014
6193
  if (filepath.endsWith(".css")) {
6015
6194
  res.set("Content-Type", "text/css");
@@ -6017,11 +6196,11 @@ async function createServerHandle(config) {
6017
6196
  }
6018
6197
  })
6019
6198
  );
6020
- app.use("/manifest.webmanifest", express.static(join4(distWebDir, "manifest.webmanifest")));
6021
- app.use("/registerSW.js", express.static(join4(distWebDir, "registerSW.js")));
6022
- app.use("/sw.js", express.static(join4(distWebDir, "sw.js")));
6199
+ app.use("/manifest.webmanifest", express.static(join5(distWebDir, "manifest.webmanifest")));
6200
+ app.use("/registerSW.js", express.static(join5(distWebDir, "registerSW.js")));
6201
+ app.use("/sw.js", express.static(join5(distWebDir, "sw.js")));
6023
6202
  app.get("/fox.svg", (_req, res) => {
6024
- readFile3(join4(distWebDir, "fox.svg")).then((content) => {
6203
+ readFile4(join5(distWebDir, "fox.svg")).then((content) => {
6025
6204
  res.set("Content-Type", "image/svg+xml");
6026
6205
  res.send(content);
6027
6206
  }).catch(() => {
@@ -6030,14 +6209,14 @@ async function createServerHandle(config) {
6030
6209
  });
6031
6210
  app.use(
6032
6211
  "/sounds",
6033
- express.static(join4(distWebDir, "sounds"), {
6212
+ express.static(join5(distWebDir, "sounds"), {
6034
6213
  setHeaders: (res) => {
6035
6214
  res.set("Content-Type", "audio/mpeg");
6036
6215
  }
6037
6216
  })
6038
6217
  );
6039
6218
  app.get("/", (_req, res) => {
6040
- readFile3(join4(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6219
+ readFile4(join5(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6041
6220
  res.status(404).send("Web UI not built. Run `npm run build:web`");
6042
6221
  });
6043
6222
  });
@@ -6045,7 +6224,7 @@ async function createServerHandle(config) {
6045
6224
  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") {
6046
6225
  return;
6047
6226
  }
6048
- readFile3(join4(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6227
+ readFile4(join5(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
6049
6228
  res.status(404).send("Web UI not built");
6050
6229
  });
6051
6230
  });
@@ -6060,7 +6239,7 @@ async function createServerHandle(config) {
6060
6239
  providerManager
6061
6240
  );
6062
6241
  const wss = wssExports.wss;
6063
- const { QueueProcessor } = await import("./processor-W55O5T6T.js");
6242
+ const { QueueProcessor } = await import("./processor-KJBVOF4W.js");
6064
6243
  const queueProcessor = new QueueProcessor({
6065
6244
  sessionManager,
6066
6245
  providerManager,
@@ -6130,4 +6309,4 @@ export {
6130
6309
  createServerHandle,
6131
6310
  createServer
6132
6311
  };
6133
- //# sourceMappingURL=chunk-2CK3CWOE.js.map
6312
+ //# sourceMappingURL=chunk-47TNOR2U.js.map