anycodex 0.0.15 → 0.0.17

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 (2) hide show
  1. package/dist/bin.js +120 -115
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -22,7 +22,7 @@ import fs5 from "fs";
22
22
  import readline from "readline";
23
23
  import { fileURLToPath as fileURLToPath2 } from "url";
24
24
 
25
- // ../server/dist/chunk-AQFLUXUT.js
25
+ // ../server/dist/chunk-55FJSWGH.js
26
26
  import http from "http";
27
27
  import { fileURLToPath } from "url";
28
28
  import path3 from "path";
@@ -459,29 +459,29 @@ function simpleGlobMatch(filename, pattern) {
459
459
  }
460
460
  var ANYCODE_DIR = path3.join(os.homedir(), ".anycode");
461
461
  var DB_PATH = path3.join(ANYCODE_DIR, "data.db");
462
- var userSettings = {};
463
- var PROVIDER = "";
464
- var MODEL = "";
465
- var API_KEY = "";
466
- var BASE_URL = "";
467
- var PORT = 3210;
468
- var PREVIEW_PORT = 3211;
469
462
  function loadConfig() {
470
- PROVIDER = process.env.PROVIDER ?? "";
471
- MODEL = process.env.MODEL ?? userSettings.MODEL ?? "claude-sonnet-4-20250514";
472
- API_KEY = process.env.API_KEY ?? userSettings.API_KEY ?? "";
473
- BASE_URL = process.env.BASE_URL ?? userSettings.BASE_URL ?? "";
474
- PORT = parseInt(process.env.PORT ?? "3210", 10);
475
- PREVIEW_PORT = parseInt(process.env.PREVIEW_PORT ?? String(PORT + 1), 10);
476
- if (!PROVIDER || !MODEL || !BASE_URL) {
463
+ let userSettings = {};
464
+ try {
465
+ userSettings = JSON.parse(fs4.readFileSync(path3.join(ANYCODE_DIR, "settings.json"), "utf-8"));
466
+ } catch {
467
+ }
468
+ const provider = process.env.PROVIDER ?? userSettings.PROVIDER ?? "anthropic";
469
+ const model = process.env.MODEL ?? userSettings.MODEL ?? "claude-sonnet-4-20250514";
470
+ const apiKey = process.env.API_KEY ?? userSettings.API_KEY ?? "";
471
+ const baseUrl = process.env.BASE_URL ?? userSettings.BASE_URL ?? "";
472
+ const port = parseInt(process.env.PORT ?? "3210", 10);
473
+ const previewPort = parseInt(process.env.PREVIEW_PORT ?? String(port + 1), 10);
474
+ if (!provider || !model || !baseUrl) {
477
475
  console.error("\u274C Missing PROVIDER, MODEL, BASE_URL");
478
476
  process.exit(1);
479
477
  }
480
- if (!API_KEY) {
478
+ if (!apiKey) {
481
479
  console.error("\u274C Missing API_KEY");
482
480
  console.error("Run 'anycode start' to configure, or set API_KEY env var.");
483
481
  process.exit(1);
484
482
  }
483
+ const appDist = resolveAppDist();
484
+ return { provider, model, apiKey, baseUrl, port, previewPort, appDist, userSettings };
485
485
  }
486
486
  function makePaths() {
487
487
  const dataPath = path3.join(ANYCODE_DIR, "data");
@@ -546,10 +546,9 @@ var NodeGitProvider = class {
546
546
  }
547
547
  };
548
548
  var sessions = /* @__PURE__ */ new Map();
549
- var PROVIDER_ID = PROVIDER;
550
549
  var sharedStorage;
551
550
  var db;
552
- function createAgentConfig(directory, sessionId, terminal, preview) {
551
+ function createAgentConfig(cfg, directory, sessionId, terminal, preview) {
553
552
  return {
554
553
  directory,
555
554
  fs: new NodeFS(),
@@ -562,28 +561,26 @@ function createAgentConfig(directory, sessionId, terminal, preview) {
562
561
  ...terminal ? { terminal } : {},
563
562
  ...preview ? { preview } : {},
564
563
  provider: {
565
- id: PROVIDER_ID,
566
- apiKey: API_KEY,
567
- model: MODEL,
568
- ...BASE_URL ? { baseUrl: BASE_URL } : {}
564
+ id: cfg.provider,
565
+ apiKey: cfg.apiKey,
566
+ model: cfg.model,
567
+ ...cfg.baseUrl ? { baseUrl: cfg.baseUrl } : {}
569
568
  },
570
- settings: userSettings,
569
+ settings: cfg.userSettings,
571
570
  config: {
572
- model: `${PROVIDER_ID}/${MODEL}`,
573
- small_model: `${PROVIDER_ID}/${MODEL}`,
571
+ model: `${cfg.provider}/${cfg.model}`,
572
+ small_model: `${cfg.provider}/${cfg.model}`,
574
573
  provider: {
575
- [PROVIDER_ID]: {
576
- // Use @ai-sdk/anthropic for Claude models — it natively handles
577
- // thinking blocks and signatures. Other models use openai-compatible.
578
- npm: /claude/i.test(MODEL) ? "@ai-sdk/anthropic" : "@ai-sdk/openai-compatible",
579
- ...BASE_URL ? { api: BASE_URL } : {},
574
+ [cfg.provider]: {
575
+ npm: /claude/i.test(cfg.model) ? "@ai-sdk/anthropic" : "@ai-sdk/openai-compatible",
576
+ ...cfg.baseUrl ? { api: cfg.baseUrl } : {},
580
577
  options: {
581
- apiKey: API_KEY,
582
- ...BASE_URL ? { baseURL: BASE_URL } : {}
578
+ apiKey: cfg.apiKey,
579
+ ...cfg.baseUrl ? { baseURL: cfg.baseUrl } : {}
583
580
  },
584
581
  models: {
585
- [MODEL]: {
586
- name: MODEL,
582
+ [cfg.model]: {
583
+ name: cfg.model,
587
584
  attachment: true,
588
585
  tool_call: true,
589
586
  temperature: true,
@@ -597,7 +594,7 @@ function createAgentConfig(directory, sessionId, terminal, preview) {
597
594
  }
598
595
  };
599
596
  }
600
- function registerSession(id, agent, directory, createdAt) {
597
+ function registerSession(cfg, id, agent, directory, createdAt) {
601
598
  const entry = { id, agent, directory, createdAt };
602
599
  sessions.set(id, entry);
603
600
  agent.on("directory.set", (data) => {
@@ -609,36 +606,36 @@ function registerSession(id, agent, directory, createdAt) {
609
606
  }
610
607
  db.update("user_session", { op: "eq", field: "session_id", value: id }, { directory: dir });
611
608
  console.log(`\u{1F4C2} Session ${id} directory set to: ${dir}`);
612
- pushState(id);
613
- watchDirectory(id, dir);
609
+ pushState(cfg, id);
610
+ watchDirectory(cfg, id, dir);
614
611
  });
615
612
  return entry;
616
613
  }
617
- async function resumeSession(row) {
614
+ async function resumeSession(cfg, row) {
618
615
  const sessionId = row.session_id;
619
616
  const cached = sessions.get(sessionId);
620
617
  if (cached) return cached;
621
618
  const dir = row.directory || "";
622
619
  const tp = getOrCreateTerminalProvider(sessionId);
623
- const pp = getOrCreatePreviewProvider(sessionId);
624
- const agent = new CodeAgent(createAgentConfig(dir, sessionId, tp, pp));
620
+ const pp = getOrCreatePreviewProvider(cfg, sessionId);
621
+ const agent = new CodeAgent(createAgentConfig(cfg, dir, sessionId, tp, pp));
625
622
  await agent.init();
626
- const entry = registerSession(sessionId, agent, dir, row.time_created);
623
+ const entry = registerSession(cfg, sessionId, agent, dir, row.time_created);
627
624
  if (dir) {
628
625
  try {
629
626
  agent.setWorkingDirectory(dir);
630
627
  } catch {
631
628
  }
632
- watchDirectory(sessionId, dir);
629
+ watchDirectory(cfg, sessionId, dir);
633
630
  }
634
631
  console.log(`\u267B\uFE0F Session ${sessionId} resumed`);
635
632
  return entry;
636
633
  }
637
- async function createNewWindow(userId, isDefault = false) {
634
+ async function createNewWindow(cfg, userId, isDefault = false) {
638
635
  const tempId = `temp-${Date.now()}`;
639
636
  const tp = getOrCreateTerminalProvider(tempId);
640
- const pp = getOrCreatePreviewProvider(tempId);
641
- const agent = new CodeAgent(createAgentConfig("", void 0, tp, pp));
637
+ const pp = getOrCreatePreviewProvider(cfg, tempId);
638
+ const agent = new CodeAgent(createAgentConfig(cfg, "", void 0, tp, pp));
642
639
  await agent.init();
643
640
  const sessionId = agent.sessionId;
644
641
  const now = Date.now();
@@ -648,7 +645,7 @@ async function createNewWindow(userId, isDefault = false) {
648
645
  previewProviders.set(sessionId, pp);
649
646
  tp.sessionId = sessionId;
650
647
  pp.sessionId = sessionId;
651
- const entry = registerSession(sessionId, agent, "", now);
648
+ const entry = registerSession(cfg, sessionId, agent, "", now);
652
649
  db.insert("user_session", {
653
650
  user_id: userId,
654
651
  session_id: sessionId,
@@ -659,22 +656,22 @@ async function createNewWindow(userId, isDefault = false) {
659
656
  console.log(`\u2705 Window ${sessionId} created for user ${userId}${isDefault ? " (default)" : ""}`);
660
657
  return entry;
661
658
  }
662
- async function getOrCreateSession(userId) {
659
+ async function getOrCreateSession(cfg, userId) {
663
660
  const rows = db.findMany("user_session", { filter: { op: "eq", field: "user_id", value: userId } });
664
661
  const defaultRow = rows.find((r) => r.is_default === 1) || rows[0];
665
662
  if (defaultRow) {
666
663
  if (defaultRow.is_default !== 1) {
667
664
  db.update("user_session", { op: "eq", field: "session_id", value: defaultRow.session_id }, { is_default: 1 });
668
665
  }
669
- return resumeSession(defaultRow);
666
+ return resumeSession(cfg, defaultRow);
670
667
  }
671
- return createNewWindow(userId, true);
668
+ return createNewWindow(cfg, userId, true);
672
669
  }
673
- async function getAllWindows(userId) {
670
+ async function getAllWindows(cfg, userId) {
674
671
  const rows = db.findMany("user_session", { filter: { op: "eq", field: "user_id", value: userId } });
675
672
  const entries = [];
676
673
  for (const row of rows) {
677
- entries.push(await resumeSession(row));
674
+ entries.push(await resumeSession(cfg, row));
678
675
  }
679
676
  return entries;
680
677
  }
@@ -737,12 +734,12 @@ var sessionClients = /* @__PURE__ */ new Map();
737
734
  var sessionChatAbort = /* @__PURE__ */ new Map();
738
735
  var lastStateJson = /* @__PURE__ */ new Map();
739
736
  var statePushTimers = /* @__PURE__ */ new Map();
740
- function scheduleStatePush(sessionId, delayMs = 300) {
737
+ function scheduleStatePush(cfg, sessionId, delayMs = 300) {
741
738
  const existing = statePushTimers.get(sessionId);
742
739
  if (existing) clearTimeout(existing);
743
740
  const timer = setTimeout(() => {
744
741
  statePushTimers.delete(sessionId);
745
- void pushState(sessionId);
742
+ void pushState(cfg, sessionId);
746
743
  }, delayMs);
747
744
  statePushTimers.set(sessionId, timer);
748
745
  }
@@ -901,11 +898,11 @@ ${message}` : message;
901
898
  }
902
899
  }
903
900
  var watchers = /* @__PURE__ */ new Map();
904
- function watchDirectory(sessionId, dir) {
901
+ function watchDirectory(cfg, sessionId, dir) {
905
902
  const existing = watchers.get(sessionId);
906
903
  if (existing) existing.close();
907
904
  const debouncedPush = () => {
908
- scheduleStatePush(sessionId, 500);
905
+ scheduleStatePush(cfg, sessionId, 500);
909
906
  };
910
907
  try {
911
908
  const watcher = fs4.watch(dir, { recursive: true }, (eventType, filename) => {
@@ -918,7 +915,7 @@ function watchDirectory(sessionId, dir) {
918
915
  console.error(`\u274C fs.watch failed for ${dir}:`, err);
919
916
  }
920
917
  }
921
- async function buildState(sessionId) {
918
+ async function buildState(cfg, sessionId) {
922
919
  const session = getSession(sessionId);
923
920
  if (!session) return null;
924
921
  const dir = session.directory;
@@ -929,12 +926,12 @@ async function buildState(sessionId) {
929
926
  directory: dir,
930
927
  changes,
931
928
  topLevel,
932
- previewPort: previewSessionId === sessionId && previewTarget ? PREVIEW_PORT : null
929
+ previewPort: previewSessionId === sessionId && previewTarget ? cfg.previewPort : null
933
930
  };
934
931
  }
935
- async function pushState(sessionId) {
932
+ async function pushState(cfg, sessionId) {
936
933
  try {
937
- const payload = await buildState(sessionId);
934
+ const payload = await buildState(cfg, sessionId);
938
935
  if (!payload) return;
939
936
  const json = JSON.stringify(payload);
940
937
  const prev = lastStateJson.get(sessionId);
@@ -951,11 +948,11 @@ async function pushState(sessionId) {
951
948
  console.error(`\u274C pushState error:`, err);
952
949
  }
953
950
  }
954
- async function sendStateTo(sessionId, client) {
951
+ async function sendStateTo(cfg, sessionId, client) {
955
952
  try {
956
953
  let json = lastStateJson.get(sessionId);
957
954
  if (!json) {
958
- const payload = await buildState(sessionId);
955
+ const payload = await buildState(cfg, sessionId);
959
956
  if (!payload) return;
960
957
  json = JSON.stringify(payload);
961
958
  lastStateJson.set(sessionId, json);
@@ -1158,31 +1155,32 @@ var previewTarget = null;
1158
1155
  var previewSessionId = null;
1159
1156
  var NodePreviewProvider = class {
1160
1157
  sessionId;
1161
- constructor(sessionId) {
1158
+ cfg;
1159
+ constructor(cfg, sessionId) {
1160
+ this.cfg = cfg;
1162
1161
  this.sessionId = sessionId;
1163
1162
  }
1164
1163
  setPreviewTarget(forwardedLocalUrl) {
1165
1164
  previewTarget = forwardedLocalUrl.replace(/\/+$/, "");
1166
1165
  previewSessionId = this.sessionId;
1167
- console.log(`\u{1F517} Preview proxy: :${PREVIEW_PORT} \u2192 ${previewTarget} (session ${this.sessionId})`);
1166
+ console.log(`\u{1F517} Preview proxy: :${this.cfg.previewPort} \u2192 ${previewTarget} (session ${this.sessionId})`);
1168
1167
  broadcast(this.sessionId, {
1169
1168
  type: "preview",
1170
- port: PREVIEW_PORT
1169
+ port: this.cfg.previewPort
1171
1170
  });
1172
1171
  }
1173
1172
  };
1174
1173
  var previewProviders = /* @__PURE__ */ new Map();
1175
- function getOrCreatePreviewProvider(sessionId) {
1174
+ function getOrCreatePreviewProvider(cfg, sessionId) {
1176
1175
  let pp = previewProviders.get(sessionId);
1177
1176
  if (!pp) {
1178
- pp = new NodePreviewProvider(sessionId);
1177
+ pp = new NodePreviewProvider(cfg, sessionId);
1179
1178
  previewProviders.set(sessionId, pp);
1180
1179
  }
1181
1180
  return pp;
1182
1181
  }
1183
- var previewServer;
1184
- function createPreviewServer() {
1185
- previewServer = http.createServer((req, res) => {
1182
+ function createPreviewServer(cfg) {
1183
+ const previewServer = http.createServer((req, res) => {
1186
1184
  res.setHeader("Access-Control-Allow-Origin", "*");
1187
1185
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
1188
1186
  res.setHeader("Access-Control-Allow-Headers", "*");
@@ -1252,8 +1250,9 @@ function createPreviewServer() {
1252
1250
  socket.destroy();
1253
1251
  }
1254
1252
  });
1253
+ return previewServer;
1255
1254
  }
1256
- function adminHTML() {
1255
+ function adminHTML(cfg) {
1257
1256
  return (
1258
1257
  /* html */
1259
1258
  `<!DOCTYPE html>
@@ -1304,9 +1303,9 @@ function adminHTML() {
1304
1303
  <h1><span class="dot"></span> AnyCode Server</h1>
1305
1304
  <div class="card">
1306
1305
  <h2>\u2699 Configuration</h2>
1307
- <div class="row"><span class="label">Provider</span><span class="value">${PROVIDER}</span></div>
1308
- <div class="row"><span class="label">Model</span><span class="value">${MODEL}</span></div>
1309
- <div class="row"><span class="label">Port</span><span class="value">${PORT}</span></div>
1306
+ <div class="row"><span class="label">Provider</span><span class="value">${cfg.provider}</span></div>
1307
+ <div class="row"><span class="label">Model</span><span class="value">${cfg.model}</span></div>
1308
+ <div class="row"><span class="label">Port</span><span class="value">${cfg.port}</span></div>
1310
1309
  <div class="row"><span class="label">Sessions</span><span class="value" id="session-count">0</span></div>
1311
1310
  </div>
1312
1311
  <div class="card">
@@ -1373,10 +1372,9 @@ function resolveAppDist() {
1373
1372
  }
1374
1373
  return bundled;
1375
1374
  }
1376
- var APP_DIST = "";
1377
- function serveStatic(req, res) {
1375
+ function serveStatic(cfg, req, res) {
1378
1376
  const url = req.url || "/";
1379
- const filePath = path3.join(APP_DIST, url);
1377
+ const filePath = path3.join(cfg.appDist, url);
1380
1378
  if (fs4.existsSync(filePath) && fs4.statSync(filePath).isFile()) {
1381
1379
  const ext = path3.extname(filePath);
1382
1380
  res.writeHead(200, { "Content-Type": MIME_TYPES[ext] || "application/octet-stream" });
@@ -1385,10 +1383,10 @@ function serveStatic(req, res) {
1385
1383
  }
1386
1384
  return false;
1387
1385
  }
1388
- function serveAppIndex(res) {
1389
- const indexPath = path3.join(APP_DIST, "index.html");
1386
+ function serveAppIndex(cfg, res) {
1387
+ const indexPath = path3.join(cfg.appDist, "index.html");
1390
1388
  if (fs4.existsSync(indexPath)) {
1391
- const webSocket = userSettings.webSocket === true;
1389
+ const webSocket = cfg.userSettings.webSocket === true;
1392
1390
  const configScript = `<script>window.__ANYCODE_CONFIG__=${JSON.stringify({ webSocket })}</script>`;
1393
1391
  let html = fs4.readFileSync(indexPath, "utf-8");
1394
1392
  html = html.replace("</head>", `${configScript}</head>`);
@@ -1398,9 +1396,8 @@ function serveAppIndex(res) {
1398
1396
  }
1399
1397
  return false;
1400
1398
  }
1401
- var server;
1402
- function createMainServer() {
1403
- server = http.createServer(async (req, res) => {
1399
+ function createMainServer(cfg) {
1400
+ const server = http.createServer(async (req, res) => {
1404
1401
  res.setHeader("Access-Control-Allow-Origin", "*");
1405
1402
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
1406
1403
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");
@@ -1424,13 +1421,13 @@ function createMainServer() {
1424
1421
  pollingClients.set(channelId, client);
1425
1422
  getSessionClients(sessionId).add(client);
1426
1423
  console.log(`\u{1F50C} Poll client connected to session ${sessionId} (channel=${channelId})`);
1427
- sendStateTo(sessionId, client);
1424
+ sendStateTo(cfg, sessionId, client);
1428
1425
  res.writeHead(200, { "Content-Type": "application/json" });
1429
1426
  res.end(JSON.stringify({ channelId }));
1430
1427
  return;
1431
1428
  }
1432
1429
  if (req.method === "GET" && req.url?.startsWith("/api/poll?")) {
1433
- const url = new URL(req.url, `http://localhost:${PORT}`);
1430
+ const url = new URL(req.url, `http://localhost:${cfg.port}`);
1434
1431
  const channelId = url.searchParams.get("channelId");
1435
1432
  const client = channelId ? pollingClients.get(channelId) : void 0;
1436
1433
  if (!client || client.readyState !== 1) {
@@ -1483,7 +1480,7 @@ function createMainServer() {
1483
1480
  res.end(JSON.stringify({ error: "userId is required" }));
1484
1481
  return;
1485
1482
  }
1486
- getOrCreateSession(userId).then((entry) => {
1483
+ getOrCreateSession(cfg, userId).then((entry) => {
1487
1484
  res.writeHead(200, { "Content-Type": "application/json" });
1488
1485
  res.end(JSON.stringify({ id: entry.id, directory: entry.directory }));
1489
1486
  }).catch((err) => {
@@ -1504,14 +1501,14 @@ function createMainServer() {
1504
1501
  return;
1505
1502
  }
1506
1503
  if (req.method === "GET" && req.url?.startsWith("/api/windows")) {
1507
- const url = new URL(req.url, `http://localhost:${PORT}`);
1504
+ const url = new URL(req.url, `http://localhost:${cfg.port}`);
1508
1505
  const userId = url.searchParams.get("userId");
1509
1506
  if (!userId) {
1510
1507
  res.writeHead(400, { "Content-Type": "application/json" });
1511
1508
  res.end(JSON.stringify({ error: "userId is required" }));
1512
1509
  return;
1513
1510
  }
1514
- getAllWindows(userId).then((entries) => {
1511
+ getAllWindows(cfg, userId).then((entries) => {
1515
1512
  const rows = db.findMany("user_session", { filter: { op: "eq", field: "user_id", value: userId } });
1516
1513
  const defaultMap = new Map(rows.map((r) => [r.session_id, r.is_default === 1]));
1517
1514
  const list = entries.map((e) => ({
@@ -1538,7 +1535,7 @@ function createMainServer() {
1538
1535
  res.end(JSON.stringify({ error: "userId is required" }));
1539
1536
  return;
1540
1537
  }
1541
- createNewWindow(userId, false).then((entry) => {
1538
+ createNewWindow(cfg, userId, false).then((entry) => {
1542
1539
  res.writeHead(200, { "Content-Type": "application/json" });
1543
1540
  res.end(JSON.stringify({ id: entry.id, directory: entry.directory, isDefault: false }));
1544
1541
  }).catch((err) => {
@@ -1569,7 +1566,7 @@ function createMainServer() {
1569
1566
  return;
1570
1567
  }
1571
1568
  const sub = sessionMatch[2];
1572
- const url = new URL(req.url, `http://localhost:${PORT}`);
1569
+ const url = new URL(req.url, `http://localhost:${cfg.port}`);
1573
1570
  if (sub === "state") {
1574
1571
  const dir = session.directory;
1575
1572
  const [topLevel, changes] = await Promise.all([
@@ -1578,7 +1575,7 @@ function createMainServer() {
1578
1575
  ]);
1579
1576
  const hasPreview = previewSessionId === session.id && previewTarget;
1580
1577
  res.writeHead(200, { "Content-Type": "application/json" });
1581
- res.end(JSON.stringify({ directory: dir, topLevel, changes, previewPort: hasPreview ? PREVIEW_PORT : null }));
1578
+ res.end(JSON.stringify({ directory: dir, topLevel, changes, previewPort: hasPreview ? cfg.previewPort : null }));
1582
1579
  return;
1583
1580
  }
1584
1581
  if (sub === "ls") {
@@ -1695,7 +1692,7 @@ function createMainServer() {
1695
1692
  return;
1696
1693
  }
1697
1694
  if (req.method === "GET" && req.url?.startsWith("/api/messages")) {
1698
- const url = new URL(req.url, `http://localhost:${PORT}`);
1695
+ const url = new URL(req.url, `http://localhost:${cfg.port}`);
1699
1696
  const sessionId = url.searchParams.get("sessionId");
1700
1697
  const session = sessionId ? getSession(sessionId) : void 0;
1701
1698
  if (!session) {
@@ -1714,32 +1711,28 @@ function createMainServer() {
1714
1711
  }
1715
1712
  if (req.method === "GET" && req.url === "/admin") {
1716
1713
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1717
- res.end(adminHTML());
1714
+ res.end(adminHTML(cfg));
1718
1715
  return;
1719
1716
  }
1720
1717
  if (req.method === "GET") {
1721
- if (serveStatic(req, res)) return;
1722
- if (serveAppIndex(res)) return;
1718
+ if (serveStatic(cfg, req, res)) return;
1719
+ if (serveAppIndex(cfg, res)) return;
1723
1720
  }
1724
1721
  res.writeHead(404, { "Content-Type": "application/json" });
1725
1722
  res.end(JSON.stringify({ error: "Not found" }));
1726
1723
  });
1724
+ return server;
1727
1725
  }
1728
1726
  async function startServer() {
1729
- try {
1730
- userSettings = JSON.parse(fs4.readFileSync(path3.join(ANYCODE_DIR, "settings.json"), "utf-8"));
1731
- } catch {
1732
- }
1733
- loadConfig();
1727
+ const cfg = loadConfig();
1734
1728
  process.on("uncaughtException", (err) => {
1735
1729
  console.error("\u26A0 Uncaught exception:", err.message);
1736
1730
  });
1737
1731
  process.on("unhandledRejection", (reason) => {
1738
1732
  console.error("\u26A0 Unhandled rejection:", reason instanceof Error ? reason.message : reason);
1739
1733
  });
1740
- APP_DIST = resolveAppDist();
1741
- createPreviewServer();
1742
- createMainServer();
1734
+ const previewServer = createPreviewServer(cfg);
1735
+ const server = createMainServer(cfg);
1743
1736
  console.log("\u{1F680} Starting @any-code/server\u2026");
1744
1737
  sharedStorage = new SqlJsStorage(DB_PATH);
1745
1738
  const migrations = Database.getMigrations();
@@ -1780,7 +1773,7 @@ async function startServer() {
1780
1773
  )
1781
1774
  `);
1782
1775
  }
1783
- const appDistExists = fs4.existsSync(APP_DIST);
1776
+ const appDistExists = fs4.existsSync(cfg.appDist);
1784
1777
  setInterval(() => {
1785
1778
  const now = Date.now();
1786
1779
  for (const [id, client] of pollingClients) {
@@ -1794,7 +1787,7 @@ async function startServer() {
1794
1787
  }, 3e4);
1795
1788
  const wss = new WebSocketServer({ server });
1796
1789
  wss.on("connection", (ws, req) => {
1797
- const url = new URL(req.url || "/", `http://localhost:${PORT}`);
1790
+ const url = new URL(req.url || "/", `http://localhost:${cfg.port}`);
1798
1791
  const sessionId = url.searchParams.get("sessionId");
1799
1792
  if (!sessionId || !getSession(sessionId)) {
1800
1793
  ws.close(4001, "Invalid session");
@@ -1807,7 +1800,7 @@ async function startServer() {
1807
1800
  const clients = getSessionClients(sessionId);
1808
1801
  clients.add(ws);
1809
1802
  console.log(`\u{1F50C} WS client connected to session ${sessionId} (${clients.size} total)`);
1810
- sendStateTo(sessionId, ws);
1803
+ sendStateTo(cfg, sessionId, ws);
1811
1804
  ws.on("message", async (raw) => {
1812
1805
  try {
1813
1806
  const msg = JSON.parse(raw.toString());
@@ -1821,20 +1814,20 @@ async function startServer() {
1821
1814
  });
1822
1815
  });
1823
1816
  const HOST = process.env.HOST ?? "0.0.0.0";
1824
- previewServer.listen(PREVIEW_PORT, HOST, () => {
1825
- console.log(`\u{1F441} Preview proxy: http://${HOST}:${PREVIEW_PORT}`);
1817
+ previewServer.listen(cfg.previewPort, HOST, () => {
1818
+ console.log(`\u{1F441} Preview proxy: http://${HOST}:${cfg.previewPort}`);
1826
1819
  });
1827
- server.listen(PORT, HOST, () => {
1828
- console.log(`\u{1F310} http://${HOST}:${PORT}`);
1829
- console.log(`\u{1F916} Provider: ${PROVIDER} / ${MODEL}`);
1830
- console.log(`\u{1F5A5} Admin: http://${HOST}:${PORT}/admin`);
1820
+ server.listen(cfg.port, HOST, () => {
1821
+ console.log(`\u{1F310} http://${HOST}:${cfg.port}`);
1822
+ console.log(`\u{1F916} Provider: ${cfg.provider} / ${cfg.model}`);
1823
+ console.log(`\u{1F5A5} Admin: http://${HOST}:${cfg.port}/admin`);
1831
1824
  if (appDistExists) {
1832
- console.log(`\u{1F4F1} App: http://${HOST}:${PORT}`);
1825
+ console.log(`\u{1F4F1} App: http://${HOST}:${cfg.port}`);
1833
1826
  } else {
1834
- console.log(`\u26A0 App dist not found at ${APP_DIST} \u2014 run 'pnpm --filter @any-code/app build' first`);
1827
+ console.log(`\u26A0 App dist not found at ${cfg.appDist} \u2014 run 'pnpm --filter @any-code/app build' first`);
1835
1828
  }
1836
1829
  console.log(`\u{1F4CB} Sessions: POST /api/sessions to create`);
1837
- console.log(`\u{1F50C} WebSocket: ws://${HOST}:${PORT}?sessionId=xxx`);
1830
+ console.log(`\u{1F50C} WebSocket: ws://${HOST}:${cfg.port}?sessionId=xxx`);
1838
1831
  });
1839
1832
  }
1840
1833
 
@@ -1922,12 +1915,24 @@ function prompt(question) {
1922
1915
  async function ensureSettings() {
1923
1916
  const settings = loadSettings();
1924
1917
  let changed = false;
1925
- if (!settings.API_KEY) {
1918
+ if (!settings.PROVIDER) {
1926
1919
  blank();
1927
1920
  console.log(` ${c.bold}${c.white}Welcome! Let's configure your LLM provider.${c.reset}`);
1928
1921
  blank();
1929
1922
  divider();
1930
1923
  blank();
1924
+ const val = await prompt(` ${c.cyan}?${c.reset} ${c.bold}Provider${c.reset} ${c.gray}(anthropic, openai)${c.reset}: `);
1925
+ settings.PROVIDER = val || "anthropic";
1926
+ changed = true;
1927
+ }
1928
+ if (!settings.API_KEY) {
1929
+ if (!changed) {
1930
+ blank();
1931
+ console.log(` ${c.bold}${c.white}Welcome! Let's configure your LLM provider.${c.reset}`);
1932
+ blank();
1933
+ divider();
1934
+ blank();
1935
+ }
1931
1936
  settings.API_KEY = await prompt(` ${c.cyan}?${c.reset} ${c.bold}API Key${c.reset} ${c.gray}(required)${c.reset}: `);
1932
1937
  if (!settings.API_KEY) {
1933
1938
  fail("API Key is required to continue.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anycodex",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"