quoroom 0.1.35 → 0.1.37

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.
@@ -9914,7 +9914,7 @@ var require_package = __commonJS({
9914
9914
  "package.json"(exports2, module2) {
9915
9915
  module2.exports = {
9916
9916
  name: "quoroom",
9917
- version: "0.1.35",
9917
+ version: "0.1.37",
9918
9918
  description: "Open-source local AI agent framework \u2014 Queen, Workers, Quorum. Experimental research tool.",
9919
9919
  main: "./out/mcp/server.js",
9920
9920
  bin: {
@@ -9938,7 +9938,7 @@ var require_package = __commonJS({
9938
9938
  "build:parallel": "node scripts/build-parallel.js",
9939
9939
  "build:fast": "node scripts/build-parallel.js --skip-typecheck",
9940
9940
  "build:mcp": "node scripts/build-mcp.js",
9941
- "build:ui": "vite build --config src/ui/vite.config.ts && node scripts/copy-ui-to-app.js",
9941
+ "build:ui": "vite build --config src/ui/vite.config.ts",
9942
9942
  "kill:ports": "node scripts/kill-ports.js",
9943
9943
  "kill:dev-ports": "npm run kill:ports -- 3700 3702 4700 3715 5173 5174",
9944
9944
  "kill:quoroom-runtime": "node scripts/kill-quoroom-runtime.js",
@@ -10928,6 +10928,7 @@ var require_node_cron = __commonJS({
10928
10928
  var index_exports = {};
10929
10929
  __export(index_exports, {
10930
10930
  _isLoopbackAddress: () => isLoopbackAddress,
10931
+ _resolveStaticDirForStart: () => resolveStaticDirForStart,
10931
10932
  _shellQuote: () => shellQuote,
10932
10933
  _windowsQuote: () => windowsQuote,
10933
10934
  createApiServer: () => createApiServer,
@@ -32374,16 +32375,20 @@ var VERSION_FILE = import_node_path6.default.join(USER_APP_DIR, "version.json");
32374
32375
  var status = { state: "idle" };
32375
32376
  var downloadInProgress = false;
32376
32377
  function getAutoUpdateStatus() {
32377
- if (status.state === "idle" && import_node_fs4.default.existsSync(VERSION_FILE)) {
32378
- try {
32379
- const info = JSON.parse(import_node_fs4.default.readFileSync(VERSION_FILE, "utf-8"));
32380
- return { state: "ready", version: info.version };
32381
- } catch {
32382
- }
32378
+ if (status.state === "idle") {
32379
+ const readyVersion = getReadyUpdateVersion();
32380
+ if (readyVersion) return { state: "ready", version: readyVersion };
32383
32381
  }
32384
32382
  return status;
32385
32383
  }
32386
32384
  function initBootHealthCheck() {
32385
+ if (import_node_fs4.default.existsSync(USER_APP_DIR) && !import_node_fs4.default.existsSync(VERSION_FILE)) {
32386
+ try {
32387
+ console.error("[auto-update] Removing legacy unversioned user app cache");
32388
+ import_node_fs4.default.rmSync(USER_APP_DIR, { recursive: true, force: true });
32389
+ } catch {
32390
+ }
32391
+ }
32387
32392
  if (import_node_fs4.default.existsSync(VERSION_FILE)) {
32388
32393
  try {
32389
32394
  const info = JSON.parse(import_node_fs4.default.readFileSync(VERSION_FILE, "utf-8"));
@@ -32511,7 +32516,7 @@ function semverGt(a, b) {
32511
32516
  }
32512
32517
  function getCurrentVersion() {
32513
32518
  try {
32514
- return true ? "0.1.35" : null.version;
32519
+ return true ? "0.1.37" : null.version;
32515
32520
  } catch {
32516
32521
  return "0.0.0";
32517
32522
  }
@@ -32574,13 +32579,35 @@ var pollInterval = null;
32574
32579
  function isTestTag(tag) {
32575
32580
  return /-test/i.test(tag);
32576
32581
  }
32582
+ function parseSemver(tag) {
32583
+ const cleaned = tag.trim().replace(/^v/i, "");
32584
+ const match = cleaned.match(/^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/);
32585
+ if (!match) return null;
32586
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
32587
+ }
32588
+ function compareSemver(a, b) {
32589
+ for (let i = 0; i < 3; i++) {
32590
+ if (a[i] > b[i]) return 1;
32591
+ if (a[i] < b[i]) return -1;
32592
+ }
32593
+ return 0;
32594
+ }
32577
32595
  function pickLatestStable(releases) {
32596
+ let firstStable = null;
32597
+ let bestRelease = null;
32598
+ let bestVersion = null;
32578
32599
  for (const r of releases) {
32579
32600
  if (r.draft || r.prerelease) continue;
32580
32601
  if (isTestTag(r.tag_name)) continue;
32581
- return r;
32602
+ if (!firstStable) firstStable = r;
32603
+ const parsed = parseSemver(r.tag_name);
32604
+ if (!parsed) continue;
32605
+ if (!bestVersion || compareSemver(parsed, bestVersion) > 0) {
32606
+ bestVersion = parsed;
32607
+ bestRelease = r;
32608
+ }
32582
32609
  }
32583
- return null;
32610
+ return bestRelease ?? firstStable;
32584
32611
  }
32585
32612
  function fetchJson(url) {
32586
32613
  return new Promise((resolve2, reject) => {
@@ -32605,7 +32632,7 @@ function fetchJson(url) {
32605
32632
  async function forceCheck() {
32606
32633
  try {
32607
32634
  const releases = await fetchJson(
32608
- "https://api.github.com/repos/quoroom-ai/room/releases?per_page=20"
32635
+ "https://api.github.com/repos/quoroom-ai/room/releases?per_page=100"
32609
32636
  );
32610
32637
  if (!Array.isArray(releases)) return;
32611
32638
  const latest = pickLatestStable(releases);
@@ -32670,7 +32697,7 @@ var cachedVersion = null;
32670
32697
  function getVersion3() {
32671
32698
  if (cachedVersion) return cachedVersion;
32672
32699
  try {
32673
- cachedVersion = true ? "0.1.35" : null.version;
32700
+ cachedVersion = true ? "0.1.37" : null.version;
32674
32701
  } catch {
32675
32702
  cachedVersion = "unknown";
32676
32703
  }
@@ -34590,6 +34617,11 @@ var MIME_TYPES = {
34590
34617
  ".webp": "image/webp",
34591
34618
  ".webmanifest": "application/manifest+json"
34592
34619
  };
34620
+ var NO_CACHE_RESPONSE_HEADERS = {
34621
+ "Cache-Control": "no-cache, no-store, must-revalidate",
34622
+ "Pragma": "no-cache",
34623
+ "Expires": "0"
34624
+ };
34593
34625
  var PROFILE_HTTP = process.env.QUOROOM_PROFILE_HTTP === "1";
34594
34626
  var PROFILE_HTTP_SLOW_MS = Math.max(1, Number.parseInt(process.env.QUOROOM_PROFILE_HTTP_SLOW_MS ?? "300", 10) || 300);
34595
34627
  var PROFILE_HTTP_ENDPOINTS = /* @__PURE__ */ new Set([
@@ -34615,26 +34647,6 @@ function maybeLogHttpProfile(method, pathname, statusCode, durationMs) {
34615
34647
  const slowMark = durationMs >= PROFILE_HTTP_SLOW_MS ? " SLOW" : "";
34616
34648
  console.error(`[http-prof] ${method} ${normalized} -> ${statusCode} (${durationMs}ms)${slowMark}`);
34617
34649
  }
34618
- function getCacheControl(filePath, ext) {
34619
- const normalized = filePath.replace(/\\/g, "/");
34620
- const base2 = import_node_path9.default.basename(filePath);
34621
- if (base2 === "sw.js") return "no-cache, no-store, must-revalidate";
34622
- if (ext === ".html") return "no-cache, no-store, must-revalidate";
34623
- if (ext === ".webmanifest") return "public, max-age=3600";
34624
- if (base2 === "social.png" || base2.startsWith("social-")) {
34625
- return "no-cache, max-age=0, must-revalidate";
34626
- }
34627
- if (normalized.includes("/assets/") && /-[A-Za-z0-9_-]{8,}\./.test(base2)) {
34628
- return "public, max-age=31536000, immutable";
34629
- }
34630
- if (base2.startsWith("icon-") || base2 === "apple-touch-icon.png" || [".png", ".jpg", ".jpeg", ".svg", ".ico", ".webp", ".woff", ".woff2"].includes(ext)) {
34631
- return "public, max-age=604800";
34632
- }
34633
- if (ext === ".js" || ext === ".css") {
34634
- return "public, max-age=3600";
34635
- }
34636
- return "no-cache, max-age=0";
34637
- }
34638
34650
  function serveStatic(staticDir, pathname, res) {
34639
34651
  const safePath = import_node_path9.default.normalize(pathname).replace(/^(\.\.[/\\])+/, "");
34640
34652
  let filePath = import_node_path9.default.join(staticDir, safePath);
@@ -34647,7 +34659,7 @@ function serveStatic(staticDir, pathname, res) {
34647
34659
  if (import_node_path9.default.extname(safePath)) {
34648
34660
  res.writeHead(404, {
34649
34661
  "Content-Type": "text/plain; charset=utf-8",
34650
- "Cache-Control": "no-cache, no-store, must-revalidate"
34662
+ ...NO_CACHE_RESPONSE_HEADERS
34651
34663
  });
34652
34664
  res.end("Not Found");
34653
34665
  return;
@@ -34658,8 +34670,9 @@ function serveStatic(staticDir, pathname, res) {
34658
34670
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
34659
34671
  const headers = {
34660
34672
  "Content-Type": contentType,
34661
- "Cache-Control": getCacheControl(filePath, ext)
34673
+ ...NO_CACHE_RESPONSE_HEADERS
34662
34674
  };
34675
+ if (ext === ".html") headers["Clear-Site-Data"] = '"cache"';
34663
34676
  const stream = import_node_fs6.default.createReadStream(filePath);
34664
34677
  stream.on("open", () => {
34665
34678
  res.writeHead(200, headers);
@@ -34667,11 +34680,26 @@ function serveStatic(staticDir, pathname, res) {
34667
34680
  });
34668
34681
  stream.on("error", () => {
34669
34682
  if (!res.headersSent) {
34670
- res.writeHead(404, { "Content-Type": "text/plain" });
34683
+ res.writeHead(404, {
34684
+ "Content-Type": "text/plain; charset=utf-8",
34685
+ ...NO_CACHE_RESPONSE_HEADERS
34686
+ });
34671
34687
  }
34672
34688
  res.end("Not Found");
34673
34689
  });
34674
34690
  }
34691
+ function resolveStaticDirForStart() {
34692
+ const userUiDir = import_node_path9.default.join(USER_APP_DIR, "ui");
34693
+ const bundledUiDir = import_node_path9.default.join(__dirname, "../ui");
34694
+ const readyVersion = getReadyUpdateVersion();
34695
+ if (readyVersion && import_node_fs6.default.existsSync(import_node_path9.default.join(userUiDir, "index.html"))) {
34696
+ return userUiDir;
34697
+ }
34698
+ if (import_node_fs6.default.existsSync(bundledUiDir)) {
34699
+ return bundledUiDir;
34700
+ }
34701
+ return void 0;
34702
+ }
34675
34703
  var RATE_LIMIT_WINDOW_MS2 = 6e4;
34676
34704
  var RATE_LIMIT_READ = 300;
34677
34705
  var RATE_LIMIT_WRITE = 120;
@@ -34729,14 +34757,15 @@ function createApiServer(options = {}) {
34729
34757
  });
34730
34758
  }
34731
34759
  if (req.method === "OPTIONS") {
34732
- const headers = {};
34760
+ const headers = { ...NO_CACHE_RESPONSE_HEADERS };
34733
34761
  setCorsHeaders(origin, headers);
34734
34762
  res.writeHead(204, headers);
34735
34763
  res.end();
34736
34764
  return;
34737
34765
  }
34738
34766
  const responseHeaders = {
34739
- "Content-Type": "application/json"
34767
+ "Content-Type": "application/json",
34768
+ ...NO_CACHE_RESPONSE_HEADERS
34740
34769
  };
34741
34770
  if (isCloudDeployment()) {
34742
34771
  Object.assign(responseHeaders, CLOUD_SECURITY_HEADERS);
@@ -34766,10 +34795,7 @@ function createApiServer(options = {}) {
34766
34795
  }
34767
34796
  if (pathname === "/api/auth/handshake" && req.method === "GET") {
34768
34797
  const handshakeHeaders = {
34769
- ...responseHeaders,
34770
- "Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate",
34771
- "Pragma": "no-cache",
34772
- "Expires": "0"
34798
+ ...responseHeaders
34773
34799
  };
34774
34800
  if (isCloudDeployment()) {
34775
34801
  res.writeHead(403, handshakeHeaders);
@@ -34935,7 +34961,10 @@ function createApiServer(options = {}) {
34935
34961
  if (options.staticDir) {
34936
34962
  serveStatic(options.staticDir, pathname, res);
34937
34963
  } else {
34938
- res.writeHead(404, { "Content-Type": "text/plain" });
34964
+ res.writeHead(404, {
34965
+ "Content-Type": "text/plain; charset=utf-8",
34966
+ ...NO_CACHE_RESPONSE_HEADERS
34967
+ });
34939
34968
  res.end("Not Found");
34940
34969
  }
34941
34970
  });
@@ -35047,14 +35076,9 @@ function startServer(options = {}) {
35047
35076
  const port = options.port ?? DEFAULT_PORT;
35048
35077
  const deploymentMode = getDeploymentMode();
35049
35078
  const bindHost = process.env.QUOROOM_BIND_HOST || (deploymentMode === "cloud" ? DEFAULT_BIND_HOST_CLOUD : DEFAULT_BIND_HOST_LOCAL);
35079
+ initBootHealthCheck();
35050
35080
  if (!options.staticDir) {
35051
- const userUiDir = import_node_path9.default.join(USER_APP_DIR, "ui");
35052
- const bundledUiDir = import_node_path9.default.join(__dirname, "../ui");
35053
- if (import_node_fs6.default.existsSync(import_node_path9.default.join(userUiDir, "index.html"))) {
35054
- options.staticDir = userUiDir;
35055
- } else if (import_node_fs6.default.existsSync(bundledUiDir)) {
35056
- options.staticDir = bundledUiDir;
35057
- }
35081
+ options.staticDir = resolveStaticDirForStart();
35058
35082
  }
35059
35083
  const dbPath = process.env.QUOROOM_DB_PATH || import_node_path9.default.join(options.dataDir ?? getDataDir(), "data.db");
35060
35084
  const { server, token, db: serverDb } = createApiServer(options);
@@ -35068,7 +35092,6 @@ function startServer(options = {}) {
35068
35092
  }
35069
35093
  initCloudSync(serverDb);
35070
35094
  initUpdateChecker();
35071
- initBootHealthCheck();
35072
35095
  startServerRuntime(serverDb);
35073
35096
  function listen() {
35074
35097
  server.listen(port, bindHost, () => {
@@ -35152,6 +35175,7 @@ function startServer(options = {}) {
35152
35175
  // Annotate the CommonJS export names for ESM import in node:
35153
35176
  0 && (module.exports = {
35154
35177
  _isLoopbackAddress,
35178
+ _resolveStaticDirForStart,
35155
35179
  _shellQuote,
35156
35180
  _windowsQuote,
35157
35181
  createApiServer,
package/out/mcp/cli.js CHANGED
@@ -52537,7 +52537,7 @@ var server_exports = {};
52537
52537
  async function main() {
52538
52538
  const server = new McpServer({
52539
52539
  name: "quoroom",
52540
- version: true ? "0.1.35" : "0.0.0"
52540
+ version: true ? "0.1.37" : "0.0.0"
52541
52541
  });
52542
52542
  registerMemoryTools(server);
52543
52543
  registerSchedulerTools(server);
@@ -54189,7 +54189,7 @@ var require_package = __commonJS({
54189
54189
  "package.json"(exports2, module2) {
54190
54190
  module2.exports = {
54191
54191
  name: "quoroom",
54192
- version: "0.1.35",
54192
+ version: "0.1.37",
54193
54193
  description: "Open-source local AI agent framework \u2014 Queen, Workers, Quorum. Experimental research tool.",
54194
54194
  main: "./out/mcp/server.js",
54195
54195
  bin: {
@@ -54213,7 +54213,7 @@ var require_package = __commonJS({
54213
54213
  "build:parallel": "node scripts/build-parallel.js",
54214
54214
  "build:fast": "node scripts/build-parallel.js --skip-typecheck",
54215
54215
  "build:mcp": "node scripts/build-mcp.js",
54216
- "build:ui": "vite build --config src/ui/vite.config.ts && node scripts/copy-ui-to-app.js",
54216
+ "build:ui": "vite build --config src/ui/vite.config.ts",
54217
54217
  "kill:ports": "node scripts/kill-ports.js",
54218
54218
  "kill:dev-ports": "npm run kill:ports -- 3700 3702 4700 3715 5173 5174",
54219
54219
  "kill:quoroom-runtime": "node scripts/kill-quoroom-runtime.js",
@@ -59614,16 +59614,20 @@ var init_db2 = __esm({
59614
59614
 
59615
59615
  // src/server/autoUpdate.ts
59616
59616
  function getAutoUpdateStatus() {
59617
- if (status.state === "idle" && import_node_fs4.default.existsSync(VERSION_FILE)) {
59618
- try {
59619
- const info = JSON.parse(import_node_fs4.default.readFileSync(VERSION_FILE, "utf-8"));
59620
- return { state: "ready", version: info.version };
59621
- } catch {
59622
- }
59617
+ if (status.state === "idle") {
59618
+ const readyVersion = getReadyUpdateVersion();
59619
+ if (readyVersion) return { state: "ready", version: readyVersion };
59623
59620
  }
59624
59621
  return status;
59625
59622
  }
59626
59623
  function initBootHealthCheck() {
59624
+ if (import_node_fs4.default.existsSync(USER_APP_DIR) && !import_node_fs4.default.existsSync(VERSION_FILE)) {
59625
+ try {
59626
+ console.error("[auto-update] Removing legacy unversioned user app cache");
59627
+ import_node_fs4.default.rmSync(USER_APP_DIR, { recursive: true, force: true });
59628
+ } catch {
59629
+ }
59630
+ }
59627
59631
  if (import_node_fs4.default.existsSync(VERSION_FILE)) {
59628
59632
  try {
59629
59633
  const info = JSON.parse(import_node_fs4.default.readFileSync(VERSION_FILE, "utf-8"));
@@ -59751,7 +59755,7 @@ function semverGt(a, b) {
59751
59755
  }
59752
59756
  function getCurrentVersion() {
59753
59757
  try {
59754
- return true ? "0.1.35" : null.version;
59758
+ return true ? "0.1.37" : null.version;
59755
59759
  } catch {
59756
59760
  return "0.0.0";
59757
59761
  }
@@ -59829,13 +59833,35 @@ var init_autoUpdate = __esm({
59829
59833
  function isTestTag(tag) {
59830
59834
  return /-test/i.test(tag);
59831
59835
  }
59836
+ function parseSemver(tag) {
59837
+ const cleaned = tag.trim().replace(/^v/i, "");
59838
+ const match = cleaned.match(/^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/);
59839
+ if (!match) return null;
59840
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
59841
+ }
59842
+ function compareSemver(a, b) {
59843
+ for (let i = 0; i < 3; i++) {
59844
+ if (a[i] > b[i]) return 1;
59845
+ if (a[i] < b[i]) return -1;
59846
+ }
59847
+ return 0;
59848
+ }
59832
59849
  function pickLatestStable(releases) {
59850
+ let firstStable = null;
59851
+ let bestRelease = null;
59852
+ let bestVersion = null;
59833
59853
  for (const r of releases) {
59834
59854
  if (r.draft || r.prerelease) continue;
59835
59855
  if (isTestTag(r.tag_name)) continue;
59836
- return r;
59856
+ if (!firstStable) firstStable = r;
59857
+ const parsed = parseSemver(r.tag_name);
59858
+ if (!parsed) continue;
59859
+ if (!bestVersion || compareSemver(parsed, bestVersion) > 0) {
59860
+ bestVersion = parsed;
59861
+ bestRelease = r;
59862
+ }
59837
59863
  }
59838
- return null;
59864
+ return bestRelease ?? firstStable;
59839
59865
  }
59840
59866
  function fetchJson(url) {
59841
59867
  return new Promise((resolve2, reject) => {
@@ -59860,7 +59886,7 @@ function fetchJson(url) {
59860
59886
  async function forceCheck() {
59861
59887
  try {
59862
59888
  const releases = await fetchJson(
59863
- "https://api.github.com/repos/quoroom-ai/room/releases?per_page=20"
59889
+ "https://api.github.com/repos/quoroom-ai/room/releases?per_page=100"
59864
59890
  );
59865
59891
  if (!Array.isArray(releases)) return;
59866
59892
  const latest = pickLatestStable(releases);
@@ -59936,7 +59962,7 @@ var init_updateChecker = __esm({
59936
59962
  function getVersion3() {
59937
59963
  if (cachedVersion) return cachedVersion;
59938
59964
  try {
59939
- cachedVersion = true ? "0.1.35" : null.version;
59965
+ cachedVersion = true ? "0.1.37" : null.version;
59940
59966
  } catch {
59941
59967
  cachedVersion = "unknown";
59942
59968
  }
@@ -65422,6 +65448,7 @@ var init_shell_path = __esm({
65422
65448
  var server_exports2 = {};
65423
65449
  __export(server_exports2, {
65424
65450
  _isLoopbackAddress: () => isLoopbackAddress,
65451
+ _resolveStaticDirForStart: () => resolveStaticDirForStart,
65425
65452
  _shellQuote: () => shellQuote,
65426
65453
  _windowsQuote: () => windowsQuote,
65427
65454
  createApiServer: () => createApiServer,
@@ -65596,26 +65623,6 @@ function maybeLogHttpProfile(method, pathname, statusCode, durationMs) {
65596
65623
  const slowMark = durationMs >= PROFILE_HTTP_SLOW_MS ? " SLOW" : "";
65597
65624
  console.error(`[http-prof] ${method} ${normalized} -> ${statusCode} (${durationMs}ms)${slowMark}`);
65598
65625
  }
65599
- function getCacheControl(filePath, ext) {
65600
- const normalized = filePath.replace(/\\/g, "/");
65601
- const base2 = import_node_path9.default.basename(filePath);
65602
- if (base2 === "sw.js") return "no-cache, no-store, must-revalidate";
65603
- if (ext === ".html") return "no-cache, no-store, must-revalidate";
65604
- if (ext === ".webmanifest") return "public, max-age=3600";
65605
- if (base2 === "social.png" || base2.startsWith("social-")) {
65606
- return "no-cache, max-age=0, must-revalidate";
65607
- }
65608
- if (normalized.includes("/assets/") && /-[A-Za-z0-9_-]{8,}\./.test(base2)) {
65609
- return "public, max-age=31536000, immutable";
65610
- }
65611
- if (base2.startsWith("icon-") || base2 === "apple-touch-icon.png" || [".png", ".jpg", ".jpeg", ".svg", ".ico", ".webp", ".woff", ".woff2"].includes(ext)) {
65612
- return "public, max-age=604800";
65613
- }
65614
- if (ext === ".js" || ext === ".css") {
65615
- return "public, max-age=3600";
65616
- }
65617
- return "no-cache, max-age=0";
65618
- }
65619
65626
  function serveStatic(staticDir, pathname, res) {
65620
65627
  const safePath = import_node_path9.default.normalize(pathname).replace(/^(\.\.[/\\])+/, "");
65621
65628
  let filePath = import_node_path9.default.join(staticDir, safePath);
@@ -65628,7 +65635,7 @@ function serveStatic(staticDir, pathname, res) {
65628
65635
  if (import_node_path9.default.extname(safePath)) {
65629
65636
  res.writeHead(404, {
65630
65637
  "Content-Type": "text/plain; charset=utf-8",
65631
- "Cache-Control": "no-cache, no-store, must-revalidate"
65638
+ ...NO_CACHE_RESPONSE_HEADERS
65632
65639
  });
65633
65640
  res.end("Not Found");
65634
65641
  return;
@@ -65639,8 +65646,9 @@ function serveStatic(staticDir, pathname, res) {
65639
65646
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
65640
65647
  const headers = {
65641
65648
  "Content-Type": contentType,
65642
- "Cache-Control": getCacheControl(filePath, ext)
65649
+ ...NO_CACHE_RESPONSE_HEADERS
65643
65650
  };
65651
+ if (ext === ".html") headers["Clear-Site-Data"] = '"cache"';
65644
65652
  const stream = import_node_fs6.default.createReadStream(filePath);
65645
65653
  stream.on("open", () => {
65646
65654
  res.writeHead(200, headers);
@@ -65648,11 +65656,26 @@ function serveStatic(staticDir, pathname, res) {
65648
65656
  });
65649
65657
  stream.on("error", () => {
65650
65658
  if (!res.headersSent) {
65651
- res.writeHead(404, { "Content-Type": "text/plain" });
65659
+ res.writeHead(404, {
65660
+ "Content-Type": "text/plain; charset=utf-8",
65661
+ ...NO_CACHE_RESPONSE_HEADERS
65662
+ });
65652
65663
  }
65653
65664
  res.end("Not Found");
65654
65665
  });
65655
65666
  }
65667
+ function resolveStaticDirForStart() {
65668
+ const userUiDir = import_node_path9.default.join(USER_APP_DIR, "ui");
65669
+ const bundledUiDir = import_node_path9.default.join(__dirname, "../ui");
65670
+ const readyVersion = getReadyUpdateVersion();
65671
+ if (readyVersion && import_node_fs6.default.existsSync(import_node_path9.default.join(userUiDir, "index.html"))) {
65672
+ return userUiDir;
65673
+ }
65674
+ if (import_node_fs6.default.existsSync(bundledUiDir)) {
65675
+ return bundledUiDir;
65676
+ }
65677
+ return void 0;
65678
+ }
65656
65679
  function checkRateLimit2(ip, method) {
65657
65680
  const isWrite = method !== "GET" && method !== "HEAD" && method !== "OPTIONS";
65658
65681
  const limit = isWrite ? RATE_LIMIT_WRITE : RATE_LIMIT_READ;
@@ -65694,14 +65717,15 @@ function createApiServer(options = {}) {
65694
65717
  });
65695
65718
  }
65696
65719
  if (req.method === "OPTIONS") {
65697
- const headers = {};
65720
+ const headers = { ...NO_CACHE_RESPONSE_HEADERS };
65698
65721
  setCorsHeaders(origin, headers);
65699
65722
  res.writeHead(204, headers);
65700
65723
  res.end();
65701
65724
  return;
65702
65725
  }
65703
65726
  const responseHeaders = {
65704
- "Content-Type": "application/json"
65727
+ "Content-Type": "application/json",
65728
+ ...NO_CACHE_RESPONSE_HEADERS
65705
65729
  };
65706
65730
  if (isCloudDeployment()) {
65707
65731
  Object.assign(responseHeaders, CLOUD_SECURITY_HEADERS);
@@ -65731,10 +65755,7 @@ function createApiServer(options = {}) {
65731
65755
  }
65732
65756
  if (pathname === "/api/auth/handshake" && req.method === "GET") {
65733
65757
  const handshakeHeaders = {
65734
- ...responseHeaders,
65735
- "Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate",
65736
- "Pragma": "no-cache",
65737
- "Expires": "0"
65758
+ ...responseHeaders
65738
65759
  };
65739
65760
  if (isCloudDeployment()) {
65740
65761
  res.writeHead(403, handshakeHeaders);
@@ -65900,7 +65921,10 @@ function createApiServer(options = {}) {
65900
65921
  if (options.staticDir) {
65901
65922
  serveStatic(options.staticDir, pathname, res);
65902
65923
  } else {
65903
- res.writeHead(404, { "Content-Type": "text/plain" });
65924
+ res.writeHead(404, {
65925
+ "Content-Type": "text/plain; charset=utf-8",
65926
+ ...NO_CACHE_RESPONSE_HEADERS
65927
+ });
65904
65928
  res.end("Not Found");
65905
65929
  }
65906
65930
  });
@@ -66012,14 +66036,9 @@ function startServer(options = {}) {
66012
66036
  const port = options.port ?? DEFAULT_PORT;
66013
66037
  const deploymentMode = getDeploymentMode();
66014
66038
  const bindHost = process.env.QUOROOM_BIND_HOST || (deploymentMode === "cloud" ? DEFAULT_BIND_HOST_CLOUD : DEFAULT_BIND_HOST_LOCAL);
66039
+ initBootHealthCheck();
66015
66040
  if (!options.staticDir) {
66016
- const userUiDir = import_node_path9.default.join(USER_APP_DIR, "ui");
66017
- const bundledUiDir = import_node_path9.default.join(__dirname, "../ui");
66018
- if (import_node_fs6.default.existsSync(import_node_path9.default.join(userUiDir, "index.html"))) {
66019
- options.staticDir = userUiDir;
66020
- } else if (import_node_fs6.default.existsSync(bundledUiDir)) {
66021
- options.staticDir = bundledUiDir;
66022
- }
66041
+ options.staticDir = resolveStaticDirForStart();
66023
66042
  }
66024
66043
  const dbPath = process.env.QUOROOM_DB_PATH || import_node_path9.default.join(options.dataDir ?? getDataDir(), "data.db");
66025
66044
  const { server, token, db: serverDb } = createApiServer(options);
@@ -66033,7 +66052,6 @@ function startServer(options = {}) {
66033
66052
  }
66034
66053
  initCloudSync(serverDb);
66035
66054
  initUpdateChecker();
66036
- initBootHealthCheck();
66037
66055
  startServerRuntime(serverDb);
66038
66056
  function listen() {
66039
66057
  server.listen(port, bindHost, () => {
@@ -66114,7 +66132,7 @@ function startServer(options = {}) {
66114
66132
  process.on("SIGINT", () => shutdown(0));
66115
66133
  process.on("SIGTERM", () => shutdown(0));
66116
66134
  }
66117
- var import_node_http2, import_node_https3, import_node_url, import_node_fs6, import_node_path9, import_node_os8, import_node_child_process8, DEFAULT_PORT, DEFAULT_BIND_HOST_LOCAL, DEFAULT_BIND_HOST_CLOUD, requestProcessShutdown, MIME_TYPES, PROFILE_HTTP, PROFILE_HTTP_SLOW_MS, PROFILE_HTTP_ENDPOINTS, RATE_LIMIT_WINDOW_MS2, RATE_LIMIT_READ, RATE_LIMIT_WRITE, rateBuckets2, CLOUD_SECURITY_HEADERS;
66135
+ var import_node_http2, import_node_https3, import_node_url, import_node_fs6, import_node_path9, import_node_os8, import_node_child_process8, DEFAULT_PORT, DEFAULT_BIND_HOST_LOCAL, DEFAULT_BIND_HOST_CLOUD, requestProcessShutdown, MIME_TYPES, NO_CACHE_RESPONSE_HEADERS, PROFILE_HTTP, PROFILE_HTTP_SLOW_MS, PROFILE_HTTP_ENDPOINTS, RATE_LIMIT_WINDOW_MS2, RATE_LIMIT_READ, RATE_LIMIT_WRITE, rateBuckets2, CLOUD_SECURITY_HEADERS;
66118
66136
  var init_server4 = __esm({
66119
66137
  "src/server/index.ts"() {
66120
66138
  "use strict";
@@ -66165,6 +66183,11 @@ var init_server4 = __esm({
66165
66183
  ".webp": "image/webp",
66166
66184
  ".webmanifest": "application/manifest+json"
66167
66185
  };
66186
+ NO_CACHE_RESPONSE_HEADERS = {
66187
+ "Cache-Control": "no-cache, no-store, must-revalidate",
66188
+ "Pragma": "no-cache",
66189
+ "Expires": "0"
66190
+ };
66168
66191
  PROFILE_HTTP = process.env.QUOROOM_PROFILE_HTTP === "1";
66169
66192
  PROFILE_HTTP_SLOW_MS = Math.max(1, Number.parseInt(process.env.QUOROOM_PROFILE_HTTP_SLOW_MS ?? "300", 10) || 300);
66170
66193
  PROFILE_HTTP_ENDPOINTS = /* @__PURE__ */ new Set([
@@ -66205,7 +66228,7 @@ __export(update_exports, {
66205
66228
  });
66206
66229
  function getCurrentVersion2() {
66207
66230
  try {
66208
- return true ? "0.1.35" : null.version;
66231
+ return true ? "0.1.37" : null.version;
66209
66232
  } catch {
66210
66233
  return "0.0.0";
66211
66234
  }
package/out/mcp/server.js CHANGED
@@ -49085,7 +49085,7 @@ init_db();
49085
49085
  async function main() {
49086
49086
  const server = new McpServer({
49087
49087
  name: "quoroom",
49088
- version: true ? "0.1.35" : "0.0.0"
49088
+ version: true ? "0.1.37" : "0.0.0"
49089
49089
  });
49090
49090
  registerMemoryTools(server);
49091
49091
  registerSchedulerTools(server);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quoroom",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "description": "Open-source local AI agent framework — Queen, Workers, Quorum. Experimental research tool.",
5
5
  "main": "./out/mcp/server.js",
6
6
  "bin": {
@@ -24,7 +24,7 @@
24
24
  "build:parallel": "node scripts/build-parallel.js",
25
25
  "build:fast": "node scripts/build-parallel.js --skip-typecheck",
26
26
  "build:mcp": "node scripts/build-mcp.js",
27
- "build:ui": "vite build --config src/ui/vite.config.ts && node scripts/copy-ui-to-app.js",
27
+ "build:ui": "vite build --config src/ui/vite.config.ts",
28
28
  "kill:ports": "node scripts/kill-ports.js",
29
29
  "kill:dev-ports": "npm run kill:ports -- 3700 3702 4700 3715 5173 5174",
30
30
  "kill:quoroom-runtime": "node scripts/kill-quoroom-runtime.js",