@vibedeckx/linux-x64 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -13356,12 +13356,12 @@ var require_semver = __commonJS({
13356
13356
  }
13357
13357
  function replaceHyphen(comp, options) {
13358
13358
  const r = HYPHENRANGE_REGEXP;
13359
- return comp.replace(r, (_3, from, fM, fm, fp35, fpr, fb, to, tM, tm, tp, tpr) => {
13359
+ return comp.replace(r, (_3, from, fM, fm, fp36, fpr, fb, to, tM, tm, tp, tpr) => {
13360
13360
  if (isX(fM)) {
13361
13361
  from = "";
13362
13362
  } else if (isX(fm)) {
13363
13363
  from = `>=${fM}.0.0${options?.includePrerelease ? "-0" : ""}`;
13364
- } else if (isX(fp35)) {
13364
+ } else if (isX(fp36)) {
13365
13365
  from = `>=${fM}.${fm}.0${options?.includePrerelease ? "-0" : ""}`;
13366
13366
  } else if (fpr) {
13367
13367
  from = `>=${from}`;
@@ -87525,12 +87525,12 @@ var require_range = __commonJS({
87525
87525
  debug("replaceGTE0", comp, options);
87526
87526
  return comp.trim().replace(re2[options.includePrerelease ? t.GTE0PRE : t.GTE0], "");
87527
87527
  };
87528
- var hyphenReplace = (incPr) => ($0, from, fM, fm, fp35, fpr, fb, to, tM, tm, tp, tpr) => {
87528
+ var hyphenReplace = (incPr) => ($0, from, fM, fm, fp36, fpr, fb, to, tM, tm, tp, tpr) => {
87529
87529
  if (isX(fM)) {
87530
87530
  from = "";
87531
87531
  } else if (isX(fm)) {
87532
87532
  from = `>=${fM}.0.0${incPr ? "-0" : ""}`;
87533
- } else if (isX(fp35)) {
87533
+ } else if (isX(fp36)) {
87534
87534
  from = `>=${fM}.${fm}.0${incPr ? "-0" : ""}`;
87535
87535
  } else if (fpr) {
87536
87536
  from = `>=${from}`;
@@ -90111,8 +90111,8 @@ var require_pretty_print = __commonJS({
90111
90111
  serializedRoute += serializeMetaData(route.metaData);
90112
90112
  return serializedRoute;
90113
90113
  }
90114
- function mergeSimilarRoutes(routes34) {
90115
- return routes34.reduce((mergedRoutes, route) => {
90114
+ function mergeSimilarRoutes(routes35) {
90115
+ return routes35.reduce((mergedRoutes, route) => {
90116
90116
  for (const nodeRoute of mergedRoutes) {
90117
90117
  if (deepEqual(route.opts.constraints, nodeRoute.opts.constraints) && deepEqual(route.metaData, nodeRoute.metaData)) {
90118
90118
  nodeRoute.method += ", " + route.method;
@@ -90124,18 +90124,18 @@ var require_pretty_print = __commonJS({
90124
90124
  }, []);
90125
90125
  }
90126
90126
  function serializeNode(node, prefix, options) {
90127
- let routes34 = node.routes;
90127
+ let routes35 = node.routes;
90128
90128
  if (options.method === void 0) {
90129
- routes34 = routes34.map(normalizeRoute);
90129
+ routes35 = routes35.map(normalizeRoute);
90130
90130
  }
90131
- routes34 = routes34.map((route) => {
90131
+ routes35 = routes35.map((route) => {
90132
90132
  route.metaData = getRouteMetaData(route, options);
90133
90133
  return route;
90134
90134
  });
90135
90135
  if (options.method === void 0) {
90136
- routes34 = mergeSimilarRoutes(routes34);
90136
+ routes35 = mergeSimilarRoutes(routes35);
90137
90137
  }
90138
- return routes34.map(serializeRoute).join(`
90138
+ return routes35.map(serializeRoute).join(`
90139
90139
  ${prefix}`);
90140
90140
  }
90141
90141
  function buildObjectTree(node, tree, prefix, options) {
@@ -91402,9 +91402,9 @@ var require_find_my_way = __commonJS({
91402
91402
  pathIndex = paramEndIndex;
91403
91403
  }
91404
91404
  };
91405
- Router.prototype._rebuild = function(routes34) {
91405
+ Router.prototype._rebuild = function(routes35) {
91406
91406
  this.reset();
91407
- for (const route of routes34) {
91407
+ for (const route of routes35) {
91408
91408
  const { method, path: path22, opts, handler, store } = route;
91409
91409
  this._on(method, path22, opts, handler, store);
91410
91410
  }
@@ -100612,8 +100612,8 @@ var require_commonjs6 = __commonJS({
100612
100612
  return this.#fullpath = this.name;
100613
100613
  }
100614
100614
  const pv = p2.fullpath();
100615
- const fp35 = pv + (!p2.parent ? "" : this.sep) + name25;
100616
- return this.#fullpath = fp35;
100615
+ const fp36 = pv + (!p2.parent ? "" : this.sep) + name25;
100616
+ return this.#fullpath = fp36;
100617
100617
  }
100618
100618
  /**
100619
100619
  * On platforms other than windows, this is identical to fullpath.
@@ -105329,7 +105329,7 @@ var require_static = __commonJS({
105329
105329
  var { fileURLToPath: fileURLToPath4 } = __require("node:url");
105330
105330
  var { statSync: statSync2 } = __require("node:fs");
105331
105331
  var { glob } = require_commonjs7();
105332
- var fp35 = require_plugin2();
105332
+ var fp36 = require_plugin2();
105333
105333
  var send = require_send2();
105334
105334
  var encodingNegotiator = require_accept_negotiator();
105335
105335
  var contentDisposition = require_content_disposition();
@@ -105433,7 +105433,7 @@ var require_static = __commonJS({
105433
105433
  } else {
105434
105434
  const indexes = new Set(opts.index === void 0 ? ["index.html"] : [].concat(opts.index));
105435
105435
  const indexDirs = /* @__PURE__ */ new Map();
105436
- const routes34 = /* @__PURE__ */ new Set();
105436
+ const routes35 = /* @__PURE__ */ new Set();
105437
105437
  const roots = Array.isArray(sendOptions.root) ? sendOptions.root : [sendOptions.root];
105438
105438
  for (let rootPath of roots) {
105439
105439
  rootPath = rootPath.split(path22.win32.sep).join(path22.posix.sep);
@@ -105449,10 +105449,10 @@ var require_static = __commonJS({
105449
105449
  for (let file2 of files) {
105450
105450
  file2 = file2.split(path22.win32.sep).join(path22.posix.sep);
105451
105451
  const route = prefix + file2;
105452
- if (routes34.has(route)) {
105452
+ if (routes35.has(route)) {
105453
105453
  continue;
105454
105454
  }
105455
- routes34.add(route);
105455
+ routes35.add(route);
105456
105456
  setUpHeadAndGet(routeOpts, route, `/${file2}`, rootPath);
105457
105457
  const key = path22.posix.basename(route);
105458
105458
  if (indexes.has(key) && !indexDirs.has(key)) {
@@ -105747,7 +105747,7 @@ var require_static = __commonJS({
105747
105747
  throw err;
105748
105748
  }
105749
105749
  }
105750
- module.exports = fp35(fastifyStatic2, {
105750
+ module.exports = fp36(fastifyStatic2, {
105751
105751
  fastify: "5.x",
105752
105752
  name: "@fastify/static"
105753
105753
  });
@@ -112390,7 +112390,7 @@ var require_websocket2 = __commonJS({
112390
112390
  var { ServerResponse } = __require("node:http");
112391
112391
  var { PassThrough } = __require("node:stream");
112392
112392
  var { randomBytes: randomBytes3 } = __require("node:crypto");
112393
- var fp35 = require_plugin2();
112393
+ var fp36 = require_plugin2();
112394
112394
  var WebSocket2 = require_ws();
112395
112395
  var Duplexify = require_duplexify();
112396
112396
  var kWs = /* @__PURE__ */ Symbol("ws-socket");
@@ -112576,7 +112576,7 @@ var require_websocket2 = __commonJS({
112576
112576
  }
112577
112577
  next();
112578
112578
  }
112579
- module.exports = fp35(fastifyWebsocket2, {
112579
+ module.exports = fp36(fastifyWebsocket2, {
112580
112580
  fastify: "5.x",
112581
112581
  name: "@fastify/websocket"
112582
112582
  });
@@ -115020,7 +115020,7 @@ var require_multipart2 = __commonJS({
115020
115020
  "use strict";
115021
115021
  var Busboy = require_main();
115022
115022
  var os2 = __require("node:os");
115023
- var fp35 = require_plugin2();
115023
+ var fp36 = require_plugin2();
115024
115024
  var { createWriteStream: createWriteStream2 } = __require("node:fs");
115025
115025
  var { unlink: unlink2 } = __require("node:fs/promises");
115026
115026
  var path22 = __require("node:path");
@@ -115469,7 +115469,7 @@ var require_multipart2 = __commonJS({
115469
115469
  }
115470
115470
  });
115471
115471
  }
115472
- module.exports = fp35(fastifyMultipart2, {
115472
+ module.exports = fp36(fastifyMultipart2, {
115473
115473
  fastify: "5.x",
115474
115474
  name: "@fastify/multipart"
115475
115475
  });
@@ -154378,6 +154378,7 @@ var VIBEDECKX_HOME = path.join(homedir(), ".vibedeckx");
154378
154378
  var DB_PATH = path.join(VIBEDECKX_HOME, "data.sqlite");
154379
154379
  var DEFAULT_PORT = 5173;
154380
154380
  var MIN_WORKER_VERSION = "0.0.0";
154381
+ var WORKER_VERSION_REPORTING_SINCE = "2026-08-03";
154381
154382
 
154382
154383
  // src/load-env.ts
154383
154384
  function getArg(argv, name25) {
@@ -169020,11 +169021,11 @@ function buildCommand(builderArgs) {
169020
169021
  }
169021
169022
  };
169022
169023
  }
169023
- function* generateRouteMapHelpLines(routes34, docs, args) {
169024
+ function* generateRouteMapHelpLines(routes35, docs, args) {
169024
169025
  const { brief, fullDescription, hideRoute } = docs;
169025
169026
  const { headers } = args.text;
169026
169027
  yield args.ansiColor ? `\x1B[1m${headers.usage}\x1B[22m` : headers.usage;
169027
- for (const [name25, route] of Object.entries(routes34)) {
169028
+ for (const [name25, route] of Object.entries(routes35)) {
169028
169029
  if (!hideRoute || !hideRoute[name25] || args.includeHidden) {
169029
169030
  const externalRouteName = args.config.caseStyle === "convert-camel-to-kebab" ? convertCamelCaseToKebabCase(name25) : name25;
169030
169031
  yield ` ${route.formatUsageLine({
@@ -169054,7 +169055,7 @@ function* generateRouteMapHelpLines(routes34, docs, args) {
169054
169055
  }
169055
169056
  yield "";
169056
169057
  yield args.ansiColor ? `\x1B[1m${headers.commands}\x1B[22m` : headers.commands;
169057
- const visibleRoutes = Object.entries(routes34).filter(
169058
+ const visibleRoutes = Object.entries(routes35).filter(
169058
169059
  ([name25]) => !hideRoute || !hideRoute[name25] || args.includeHidden
169059
169060
  );
169060
169061
  const rows = visibleRoutes.map(([internalRouteName, route]) => {
@@ -169082,24 +169083,24 @@ function* generateRouteMapHelpLines(routes34, docs, args) {
169082
169083
  }
169083
169084
  }
169084
169085
  function buildRouteMap({
169085
- routes: routes34,
169086
+ routes: routes35,
169086
169087
  defaultCommand: defaultCommandRoute,
169087
169088
  docs,
169088
169089
  aliases
169089
169090
  }) {
169090
- if (Object.entries(routes34).length === 0) {
169091
+ if (Object.entries(routes35).length === 0) {
169091
169092
  throw new InternalError("Route map must contain at least one route");
169092
169093
  }
169093
169094
  const activeAliases = aliases ?? {};
169094
169095
  const aliasesByRoute = /* @__PURE__ */ new Map();
169095
169096
  for (const [alias, routeName] of Object.entries(activeAliases)) {
169096
- if (alias in routes34) {
169097
+ if (alias in routes35) {
169097
169098
  throw new InternalError(`Cannot use "${alias}" as an alias when a route with that name already exists`);
169098
169099
  }
169099
169100
  const routeAliases = aliasesByRoute.get(routeName) ?? [];
169100
169101
  aliasesByRoute.set(routeName, [...routeAliases, alias]);
169101
169102
  }
169102
- const defaultCommand = defaultCommandRoute ? routes34[defaultCommandRoute] : void 0;
169103
+ const defaultCommand = defaultCommandRoute ? routes35[defaultCommandRoute] : void 0;
169103
169104
  if (defaultCommand && defaultCommand.kind === RouteMapSymbol) {
169104
169105
  throw new InternalError(
169105
169106
  `Cannot use "${defaultCommandRoute}" as the default command because it is not a Command`
@@ -169108,7 +169109,7 @@ function buildRouteMap({
169108
169109
  const resolveRouteName = (input) => {
169109
169110
  if (input in activeAliases) {
169110
169111
  return activeAliases[input];
169111
- } else if (input in routes34) {
169112
+ } else if (input in routes35) {
169112
169113
  return input;
169113
169114
  }
169114
169115
  };
@@ -169126,7 +169127,7 @@ function buildRouteMap({
169126
169127
  return `${args.prefix.join(" ")} ${routeNames.join("|")} ...`;
169127
169128
  },
169128
169129
  formatHelp: (config2) => {
169129
- const lines = [...generateRouteMapHelpLines(routes34, docs, config2)];
169130
+ const lines = [...generateRouteMapHelpLines(routes35, docs, config2)];
169130
169131
  const text2 = lines.join("\n");
169131
169132
  return text2 + "\n";
169132
169133
  },
@@ -169169,11 +169170,11 @@ function buildRouteMap({
169169
169170
  },
169170
169171
  getRoutingTargetForInput: (input) => {
169171
169172
  const routeName = input in activeAliases ? activeAliases[input] : input;
169172
- return routes34[routeName];
169173
+ return routes35[routeName];
169173
169174
  },
169174
169175
  getAllEntries() {
169175
169176
  const hiddenRoutes = docs.hideRoute;
169176
- return Object.entries(routes34).map(([originalRouteName, target]) => {
169177
+ return Object.entries(routes35).map(([originalRouteName, target]) => {
169177
169178
  return {
169178
169179
  name: {
169179
169180
  original: originalRouteName,
@@ -185911,8 +185912,6 @@ var mapProject = (row) => ({
185911
185912
  path: row.path,
185912
185913
  is_remote: fromDbBool(row.is_remote),
185913
185914
  remote_path: row.remote_path ?? void 0,
185914
- remote_url: row.remote_url ?? void 0,
185915
- remote_api_key: row.remote_api_key ?? void 0,
185916
185915
  agent_mode: row.agent_mode ?? "local",
185917
185916
  executor_mode: row.executor_mode ?? "local",
185918
185917
  sync_up_config: row.sync_up_config ? JSON.parse(row.sync_up_config) : void 0,
@@ -185928,10 +185927,10 @@ var createCoreRepos = (kdb, h) => ({
185928
185927
  path: opts.path ?? null,
185929
185928
  remote_path: opts.remote_path ?? null,
185930
185929
  is_remote: h.toDbBool(false),
185931
- remote_url: null,
185932
- remote_api_key: null,
185933
- // Dead column: never populated by any current caller (kept only so
185934
- // legacy DDL/back-compat readers relying on its presence don't break).
185930
+ // Dead columns: never populated by any current caller (kept only so
185931
+ // legacy DDL/back-compat readers relying on their presence don't break).
185932
+ // remote_url/remote_api_key are leftovers from the removed direct-URL
185933
+ // (outbound) transport all remote traffic rides reverse-connect now.
185935
185934
  remote_project_id: null,
185936
185935
  agent_mode: opts.agent_mode ?? "local",
185937
185936
  executor_mode: opts.executor_mode ?? "local",
@@ -186114,9 +186113,6 @@ var createRemoteServerRepos = (kdb, _h) => ({
186114
186113
  await kdb.insertInto("remote_servers").values({
186115
186114
  id,
186116
186115
  name: server.name,
186117
- url: null,
186118
- api_key: null,
186119
- connection_mode: "inbound",
186120
186116
  connect_token: null,
186121
186117
  connect_token_created_at: null,
186122
186118
  last_connected_at: null,
@@ -186339,8 +186335,17 @@ var mapExecutorProcess = (row) => ({
186339
186335
  status: row.status
186340
186336
  });
186341
186337
  var mapRemoteExecutorProcess = (row) => ({
186342
- ...row,
186343
- status: row.status
186338
+ local_process_id: row.local_process_id,
186339
+ remote_server_id: row.remote_server_id,
186340
+ remote_process_id: row.remote_process_id,
186341
+ executor_id: row.executor_id,
186342
+ project_id: row.project_id,
186343
+ branch: row.branch,
186344
+ started_at: row.started_at,
186345
+ status: row.status,
186346
+ exit_code: row.exit_code,
186347
+ finished_at: row.finished_at,
186348
+ machine_id: row.machine_id
186344
186349
  });
186345
186350
  var createExecutorRepos = (kdb, h) => ({
186346
186351
  executorGroups: {
@@ -187170,6 +187175,10 @@ var createSearchCacheRepos = (kdb, _h) => ({
187170
187175
  ]).executeTakeFirstOrThrow();
187171
187176
  return { running: Number(row.running) };
187172
187177
  },
187178
+ countRunningRemoteSessions: async () => {
187179
+ const row = await kdb.selectFrom("session_search_cache as c").innerJoin("remote_session_mappings as mapping", (join2) => join2.onRef("mapping.local_session_id", "=", "c.local_session_id").onRef("mapping.project_id", "=", "c.project_id").onRef("mapping.remote_server_id", "=", "c.target_id")).innerJoin("project_remotes as association", (join2) => join2.onRef("association.project_id", "=", "c.project_id").onRef("association.remote_server_id", "=", "c.target_id")).where("c.target_id", "!=", "local").where("c.deleted_at", "is", null).where("c.status", "=", "running").select([sql`count(*)`.as("n")]).executeTakeFirstOrThrow();
187180
+ return Number(row.n);
187181
+ },
187173
187182
  updateRemoteSessionActivity: async (entry) => {
187174
187183
  return kdb.transaction().execute(async (trx) => {
187175
187184
  const authorized = await trx.selectFrom("remote_session_mappings as mapping").innerJoin("project_remotes as association", (join2) => join2.onRef("association.project_id", "=", "mapping.project_id").onRef("association.remote_server_id", "=", "mapping.remote_server_id")).select("mapping.branch").where("mapping.local_session_id", "=", entry.localSessionId).where("mapping.project_id", "=", entry.projectId).where("mapping.remote_server_id", "=", entry.targetId).where("mapping.remote_session_id", "=", entry.remoteSessionId).executeTakeFirst();
@@ -238530,16 +238539,12 @@ function resolveUserId(authResult) {
238530
238539
  }
238531
238540
 
238532
238541
  // src/routes/project-routes.ts
238533
- function sanitizeProject(project) {
238534
- const { remote_api_key, ...safe } = project;
238535
- return { ...safe, has_remote_api_key: !!remote_api_key };
238536
- }
238537
238542
  var routes2 = async (fastify2) => {
238538
238543
  fastify2.get("/api/projects", async (req, reply) => {
238539
238544
  const authResult = requireAuth(req, reply);
238540
238545
  if (authResult === null) return;
238541
238546
  const userId = resolveUserId(authResult);
238542
- const projects = (await fastify2.storage.projects.getAll(userId)).map(sanitizeProject);
238547
+ const projects = await fastify2.storage.projects.getAll(userId);
238543
238548
  return reply.code(200).send({ projects });
238544
238549
  });
238545
238550
  fastify2.get("/api/projects/:id", async (req, reply) => {
@@ -238550,7 +238555,7 @@ var routes2 = async (fastify2) => {
238550
238555
  if (!project) {
238551
238556
  return reply.code(404).send({ error: "Project not found" });
238552
238557
  }
238553
- return reply.code(200).send({ project: sanitizeProject(project) });
238558
+ return reply.code(200).send({ project });
238554
238559
  });
238555
238560
  fastify2.post("/api/dialog/select-folder", async (req, reply) => {
238556
238561
  const folderPath = await selectFolder();
@@ -238621,7 +238626,7 @@ var routes2 = async (fastify2) => {
238621
238626
  agent_mode: agentMode,
238622
238627
  executor_mode: executorMode
238623
238628
  }, userId);
238624
- return reply.code(201).send({ project: sanitizeProject(project) });
238629
+ return reply.code(201).send({ project });
238625
238630
  });
238626
238631
  fastify2.put("/api/projects/:id", async (req, reply) => {
238627
238632
  const authResult = requireAuth(req, reply);
@@ -238661,7 +238666,7 @@ var routes2 = async (fastify2) => {
238661
238666
  if (!updated) {
238662
238667
  return reply.code(404).send({ error: "Project not found" });
238663
238668
  }
238664
- return reply.code(200).send({ project: sanitizeProject(updated) });
238669
+ return reply.code(200).send({ project: updated });
238665
238670
  });
238666
238671
  fastify2.delete("/api/projects/:id", async (req, reply) => {
238667
238672
  const authResult = requireAuth(req, reply);
@@ -238800,11 +238805,101 @@ function requireUserFacingOrTrustedProxyUserId(request, reply) {
238800
238805
  return authResult === void 0 && request.server.authEnabled ? void 0 : resolveUserId(authResult);
238801
238806
  }
238802
238807
 
238808
+ // src/update-check.ts
238809
+ var SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?$/;
238810
+ async function fetchLatestPublishedVersion(pkg = "vibedeckx", fetchImpl = fetch) {
238811
+ try {
238812
+ const response = await fetchImpl(
238813
+ `https://registry.npmjs.org/${pkg}/latest`,
238814
+ { signal: AbortSignal.timeout(4e3) }
238815
+ );
238816
+ if (!response.ok) return void 0;
238817
+ const body = await response.json();
238818
+ return typeof body.version === "string" && parseSemver(body.version) ? body.version : void 0;
238819
+ } catch {
238820
+ return void 0;
238821
+ }
238822
+ }
238823
+ function parseSemver(version2) {
238824
+ const match2 = SEMVER_RE.exec(version2);
238825
+ if (!match2) return void 0;
238826
+ return {
238827
+ core: [match2[1], match2[2], match2[3]],
238828
+ prerelease: match2[4]?.split(".")
238829
+ };
238830
+ }
238831
+ function compareNumericStrings(a, b2) {
238832
+ if (a.length !== b2.length) return a.length - b2.length;
238833
+ return a < b2 ? -1 : a > b2 ? 1 : 0;
238834
+ }
238835
+ function comparePrereleaseIdentifiers(a, b2) {
238836
+ const aNumeric = /^\d+$/.test(a);
238837
+ const bNumeric = /^\d+$/.test(b2);
238838
+ if (aNumeric && bNumeric) return compareNumericStrings(a, b2);
238839
+ if (aNumeric !== bNumeric) return aNumeric ? -1 : 1;
238840
+ return a < b2 ? -1 : a > b2 ? 1 : 0;
238841
+ }
238842
+ function compareSemver(a, b2) {
238843
+ for (let i = 0; i < 3; i += 1) {
238844
+ const compared = compareNumericStrings(a.core[i], b2.core[i]);
238845
+ if (compared !== 0) return compared;
238846
+ }
238847
+ if (!a.prerelease && !b2.prerelease) return 0;
238848
+ if (!a.prerelease) return 1;
238849
+ if (!b2.prerelease) return -1;
238850
+ const length = Math.max(a.prerelease.length, b2.prerelease.length);
238851
+ for (let i = 0; i < length; i += 1) {
238852
+ const aId = a.prerelease[i];
238853
+ const bId = b2.prerelease[i];
238854
+ if (aId === void 0) return -1;
238855
+ if (bId === void 0) return 1;
238856
+ const compared = comparePrereleaseIdentifiers(aId, bId);
238857
+ if (compared !== 0) return compared;
238858
+ }
238859
+ return 0;
238860
+ }
238861
+ function compareVersionStrings(a, b2) {
238862
+ const parsedA = parseSemver(a);
238863
+ const parsedB = parseSemver(b2);
238864
+ if (!parsedA || !parsedB) return void 0;
238865
+ return compareSemver(parsedA, parsedB);
238866
+ }
238867
+ function compareUpdateStatus(current, latest) {
238868
+ if (latest === void 0) return "unknown";
238869
+ const currentParsed = parseSemver(current);
238870
+ const latestParsed = parseSemver(latest);
238871
+ if (!currentParsed || !latestParsed) return "unknown";
238872
+ return compareSemver(latestParsed, currentParsed) > 0 ? "update-available" : "up-to-date";
238873
+ }
238874
+
238803
238875
  // src/routes/remote-server-routes.ts
238804
238876
  function sanitizeServer(server) {
238805
238877
  const { connect_token: _t, ...safe } = server;
238806
238878
  return safe;
238807
238879
  }
238880
+ var npmLatestCache;
238881
+ var npmLatestRefreshInFlight = false;
238882
+ function getLatestWorkerVersion() {
238883
+ const ttlMs = npmLatestCache?.value !== void 0 ? 60 * 60 * 1e3 : 5 * 60 * 1e3;
238884
+ const fresh = npmLatestCache !== void 0 && Date.now() - npmLatestCache.fetchedAt < ttlMs;
238885
+ if (!fresh && !npmLatestRefreshInFlight) {
238886
+ npmLatestRefreshInFlight = true;
238887
+ void fetchLatestPublishedVersion().then((value) => {
238888
+ npmLatestCache = { value, fetchedAt: Date.now() };
238889
+ }).finally(() => {
238890
+ npmLatestRefreshInFlight = false;
238891
+ });
238892
+ }
238893
+ return npmLatestCache?.value;
238894
+ }
238895
+ function workerUpdateStatus(workerVersion, latest) {
238896
+ if (!workerVersion) return "unreported";
238897
+ const vsMin = compareVersionStrings(workerVersion, MIN_WORKER_VERSION);
238898
+ if (vsMin !== void 0 && vsMin < 0) return "behind-min";
238899
+ const vsLatest = latest === void 0 ? void 0 : compareVersionStrings(workerVersion, latest);
238900
+ if (vsLatest !== void 0 && vsLatest < 0) return "behind-latest";
238901
+ return "current";
238902
+ }
238808
238903
  var CROSS_REMOTE_ACCESS_VALUES = ["off", "read", "exec"];
238809
238904
  var isCrossRemoteAccess = (value) => typeof value === "string" && CROSS_REMOTE_ACCESS_VALUES.includes(value);
238810
238905
  var routes3 = async (fastify2) => {
@@ -238812,7 +238907,12 @@ var routes3 = async (fastify2) => {
238812
238907
  const userId = requireUserFacingUserId(request, reply);
238813
238908
  if (userId === null) return;
238814
238909
  const servers = await fastify2.storage.remoteServers.getAll(userId);
238815
- return reply.send(servers.map(sanitizeServer));
238910
+ const latest = getLatestWorkerVersion();
238911
+ return reply.send(servers.map((server) => ({
238912
+ ...sanitizeServer(server),
238913
+ latest_worker_version: latest,
238914
+ worker_update_status: workerUpdateStatus(server.worker_version, latest)
238915
+ })));
238816
238916
  });
238817
238917
  fastify2.post("/api/remote-servers", async (request, reply) => {
238818
238918
  const userId = requireUserFacingUserId(request, reply);
@@ -238971,12 +239071,94 @@ var routes3 = async (fastify2) => {
238971
239071
  };
238972
239072
  var remote_server_routes_default = (0, import_fastify_plugin4.default)(routes3, { name: "remote-server-routes" });
238973
239073
 
238974
- // src/routes/project-remote-routes.ts
239074
+ // src/routes/worker-stats-routes.ts
238975
239075
  var import_fastify_plugin5 = __toESM(require_plugin2(), 1);
239076
+ var API_KEY = process.env.VIBEDECKX_API_KEY || void 0;
239077
+ var STALE_WORKER_THRESHOLD_MS = 7 * 24 * 60 * 60 * 1e3;
239078
+ var PHASE4_UNKNOWN_SHARE_MAX = 0.05;
239079
+ var PHASE4_DEPRECATION_DAYS = 60;
239080
+ function parseDbTimestamp3(ts) {
239081
+ if (!ts) return void 0;
239082
+ const ms = Date.parse(ts.replace(" ", "T") + "Z");
239083
+ return Number.isNaN(ms) ? void 0 : ms;
239084
+ }
239085
+ function countByVersion(versions) {
239086
+ const counts = {};
239087
+ for (const version2 of versions) {
239088
+ const key = version2 ?? "unknown";
239089
+ counts[key] = (counts[key] ?? 0) + 1;
239090
+ }
239091
+ return counts;
239092
+ }
239093
+ function oldestVersion(versions) {
239094
+ let oldest;
239095
+ for (const version2 of versions) {
239096
+ if (oldest === void 0) {
239097
+ oldest = version2;
239098
+ continue;
239099
+ }
239100
+ const cmp = compareVersionStrings(version2, oldest);
239101
+ if (cmp !== void 0 && cmp < 0) oldest = version2;
239102
+ }
239103
+ return oldest;
239104
+ }
239105
+ var routes4 = async (fastify2) => {
239106
+ fastify2.get("/api/admin/worker-version-stats", async (request, reply) => {
239107
+ const apiKeyHeader = request.headers["x-vibedeckx-api-key"];
239108
+ const isOperator = API_KEY !== void 0 && apiKeyHeader !== void 0 || !fastify2.authEnabled && API_KEY === void 0;
239109
+ if (!isOperator) return reply.code(404).send({ error: "Not found" });
239110
+ const now3 = Date.now();
239111
+ const servers = await fastify2.storage.remoteServers.getAll();
239112
+ const connected = servers.filter((server) => fastify2.reverseConnectManager.isConnected(server.id));
239113
+ const everActive = servers.filter((server) => server.last_connected_at !== void 0);
239114
+ const connectedVersions = connected.map((server) => server.worker_version);
239115
+ const unknownConnected = connectedVersions.filter((v2) => v2 === void 0).length;
239116
+ const unknownShareConnected = connected.length > 0 ? unknownConnected / connected.length : null;
239117
+ const daysSinceReporting = Math.floor(
239118
+ (now3 - Date.parse(WORKER_VERSION_REPORTING_SINCE)) / (24 * 60 * 60 * 1e3)
239119
+ );
239120
+ return reply.send({
239121
+ min_worker_version: MIN_WORKER_VERSION,
239122
+ reporting_since: WORKER_VERSION_REPORTING_SINCE,
239123
+ workers_total: servers.length,
239124
+ connected_workers: connected.length,
239125
+ // Two lenses on the distribution: _all accumulates dead rows forever
239126
+ // (abandoned trials), _connected is the one Phase 4 decisions use.
239127
+ versions_all: countByVersion(servers.map((server) => server.worker_version)),
239128
+ versions_connected: countByVersion(connectedVersions),
239129
+ oldest_connected_version: oldestVersion(
239130
+ connectedVersions.filter((v2) => v2 !== void 0)
239131
+ ) ?? null,
239132
+ // Deploy blast radius: how many live tunnels a restart would sever, and
239133
+ // how many of those are mid-turn (the actual user harm — idle sessions
239134
+ // recover on reconnect).
239135
+ active_remote_sessions: fastify2.remoteSessionMap.size,
239136
+ active_turns: await fastify2.storage.searchCache.countRunningRemoteSessions(),
239137
+ // Upgrade-failure tripwire: workers that were active once but have been
239138
+ // offline > 7 days — the classic "daemon didn't come back" signature.
239139
+ stale_workers_7d: everActive.filter((server) => {
239140
+ if (fastify2.reverseConnectManager.isConnected(server.id)) return false;
239141
+ const lastSeen = parseDbTimestamp3(server.last_connected_at);
239142
+ return lastSeen !== void 0 && now3 - lastSeen > STALE_WORKER_THRESHOLD_MS;
239143
+ }).length,
239144
+ phase4_ready: {
239145
+ unknown_share_connected: unknownShareConnected,
239146
+ unknown_share_max: PHASE4_UNKNOWN_SHARE_MAX,
239147
+ days_since_reporting_release: daysSinceReporting,
239148
+ deprecation_days: PHASE4_DEPRECATION_DAYS,
239149
+ verdict: unknownShareConnected !== null && unknownShareConnected < PHASE4_UNKNOWN_SHARE_MAX && daysSinceReporting >= PHASE4_DEPRECATION_DAYS
239150
+ }
239151
+ });
239152
+ });
239153
+ };
239154
+ var worker_stats_routes_default = (0, import_fastify_plugin5.default)(routes4, { name: "worker-stats-routes" });
239155
+
239156
+ // src/routes/project-remote-routes.ts
239157
+ var import_fastify_plugin6 = __toESM(require_plugin2(), 1);
238976
239158
  function sanitizeProjectRemote(pr) {
238977
239159
  return pr;
238978
239160
  }
238979
- var routes4 = async (fastify2) => {
239161
+ var routes5 = async (fastify2) => {
238980
239162
  fastify2.get(
238981
239163
  "/api/projects/:id/remotes",
238982
239164
  async (request, reply) => {
@@ -239076,12 +239258,12 @@ var routes4 = async (fastify2) => {
239076
239258
  }
239077
239259
  );
239078
239260
  };
239079
- var project_remote_routes_default = (0, import_fastify_plugin5.default)(routes4, { name: "project-remote-routes" });
239261
+ var project_remote_routes_default = (0, import_fastify_plugin6.default)(routes5, { name: "project-remote-routes" });
239080
239262
 
239081
239263
  // src/routes/executor-group-routes.ts
239082
- var import_fastify_plugin6 = __toESM(require_plugin2(), 1);
239264
+ var import_fastify_plugin7 = __toESM(require_plugin2(), 1);
239083
239265
  import { randomUUID as randomUUID11 } from "crypto";
239084
- var routes5 = async (fastify2) => {
239266
+ var routes6 = async (fastify2) => {
239085
239267
  fastify2.get(
239086
239268
  "/api/projects/:projectId/executor-groups",
239087
239269
  async (req, reply) => {
@@ -239152,17 +239334,17 @@ var routes5 = async (fastify2) => {
239152
239334
  }
239153
239335
  );
239154
239336
  };
239155
- var executor_group_routes_default = (0, import_fastify_plugin6.default)(routes5, { name: "executor-group-routes" });
239337
+ var executor_group_routes_default = (0, import_fastify_plugin7.default)(routes6, { name: "executor-group-routes" });
239156
239338
 
239157
239339
  // src/routes/executor-routes.ts
239158
- var import_fastify_plugin7 = __toESM(require_plugin2(), 1);
239340
+ var import_fastify_plugin8 = __toESM(require_plugin2(), 1);
239159
239341
  import { randomUUID as randomUUID12 } from "crypto";
239160
239342
  function normalizeSqlTimestamp(value) {
239161
239343
  if (!value) return null;
239162
239344
  if (value.includes("T") && /(Z|[+-]\d{2}:?\d{2})$/.test(value)) return value;
239163
239345
  return value.replace(" ", "T") + "Z";
239164
239346
  }
239165
- var routes6 = async (fastify2) => {
239347
+ var routes7 = async (fastify2) => {
239166
239348
  fastify2.get(
239167
239349
  "/api/projects/:projectId/executors",
239168
239350
  async (req, reply) => {
@@ -239301,13 +239483,13 @@ var routes6 = async (fastify2) => {
239301
239483
  return reply.code(200).send({ success: true });
239302
239484
  });
239303
239485
  };
239304
- var executor_routes_default = (0, import_fastify_plugin7.default)(routes6, { name: "executor-routes" });
239486
+ var executor_routes_default = (0, import_fastify_plugin8.default)(routes7, { name: "executor-routes" });
239305
239487
 
239306
239488
  // src/routes/process-routes.ts
239307
- var import_fastify_plugin8 = __toESM(require_plugin2(), 1);
239489
+ var import_fastify_plugin9 = __toESM(require_plugin2(), 1);
239308
239490
  import path9 from "path";
239309
239491
  import { randomUUID as randomUUID13 } from "crypto";
239310
- var routes7 = async (fastify2) => {
239492
+ var routes8 = async (fastify2) => {
239311
239493
  fastify2.post("/api/path/execute", async (req, reply) => {
239312
239494
  const userId = requireAuth(req, reply);
239313
239495
  if (userId === null) return;
@@ -239519,10 +239701,10 @@ var routes7 = async (fastify2) => {
239519
239701
  return reply.code(200).send({ processes });
239520
239702
  });
239521
239703
  };
239522
- var process_routes_default = (0, import_fastify_plugin8.default)(routes7, { name: "process-routes" });
239704
+ var process_routes_default = (0, import_fastify_plugin9.default)(routes8, { name: "process-routes" });
239523
239705
 
239524
239706
  // src/routes/worktree-routes.ts
239525
- var import_fastify_plugin9 = __toESM(require_plugin2(), 1);
239707
+ var import_fastify_plugin10 = __toESM(require_plugin2(), 1);
239526
239708
  import { mkdir as mkdir3 } from "fs/promises";
239527
239709
  async function getAllRemoteConfigs(fastify2, project) {
239528
239710
  const remotes = await fastify2.storage.projectRemotes.getByProject(project.id);
@@ -239535,7 +239717,7 @@ async function getRemoteConfig(fastify2, project) {
239535
239717
  const all = await getAllRemoteConfigs(fastify2, project);
239536
239718
  return all.length > 0 ? all[0] : null;
239537
239719
  }
239538
- var routes8 = async (fastify2) => {
239720
+ var routes9 = async (fastify2) => {
239539
239721
  fastify2.get("/api/path/branches", async (req, reply) => {
239540
239722
  const projectPath = req.query.path;
239541
239723
  if (!projectPath) {
@@ -240063,10 +240245,10 @@ var routes8 = async (fastify2) => {
240063
240245
  });
240064
240246
  });
240065
240247
  };
240066
- var worktree_routes_default = (0, import_fastify_plugin9.default)(routes8, { name: "worktree-routes" });
240248
+ var worktree_routes_default = (0, import_fastify_plugin10.default)(routes9, { name: "worktree-routes" });
240067
240249
 
240068
240250
  // src/routes/diff-routes.ts
240069
- var import_fastify_plugin10 = __toESM(require_plugin2(), 1);
240251
+ var import_fastify_plugin11 = __toESM(require_plugin2(), 1);
240070
240252
  import path10 from "path";
240071
240253
  import { readFileSync as readFileSync4 } from "fs";
240072
240254
  import { execFileSync as execFileSync5 } from "child_process";
@@ -240374,7 +240556,7 @@ async function getUntrackedFiles(cwd) {
240374
240556
  }
240375
240557
  return files;
240376
240558
  }
240377
- var routes9 = async (fastify2) => {
240559
+ var routes10 = async (fastify2) => {
240378
240560
  fastify2.get("/api/path/diff", async (req, reply) => {
240379
240561
  const projectPath = req.query.path;
240380
240562
  if (!projectPath) {
@@ -240565,10 +240747,10 @@ var routes9 = async (fastify2) => {
240565
240747
  }
240566
240748
  });
240567
240749
  };
240568
- var diff_routes_default = (0, import_fastify_plugin10.default)(routes9, { name: "diff-routes" });
240750
+ var diff_routes_default = (0, import_fastify_plugin11.default)(routes10, { name: "diff-routes" });
240569
240751
 
240570
240752
  // src/routes/file-routes.ts
240571
- var import_fastify_plugin11 = __toESM(require_plugin2(), 1);
240753
+ var import_fastify_plugin12 = __toESM(require_plugin2(), 1);
240572
240754
  import path11 from "path";
240573
240755
  import fs2 from "fs/promises";
240574
240756
  import { createReadStream, constants as fsConstants } from "fs";
@@ -240791,7 +240973,7 @@ async function searchSymbol(basePath33, symbol26) {
240791
240973
  }
240792
240974
  return { hits, truncated };
240793
240975
  }
240794
- var routes10 = async (fastify2) => {
240976
+ var routes11 = async (fastify2) => {
240795
240977
  fastify2.get("/api/path/browse", async (req, reply) => {
240796
240978
  const projectPath = req.query.path;
240797
240979
  if (!projectPath) {
@@ -241352,10 +241534,10 @@ var routes10 = async (fastify2) => {
241352
241534
  }
241353
241535
  });
241354
241536
  };
241355
- var file_routes_default = (0, import_fastify_plugin11.default)(routes10, { name: "file-routes" });
241537
+ var file_routes_default = (0, import_fastify_plugin12.default)(routes11, { name: "file-routes" });
241356
241538
 
241357
241539
  // src/routes/agent-session-routes.ts
241358
- var import_fastify_plugin12 = __toESM(require_plugin2(), 1);
241540
+ var import_fastify_plugin13 = __toESM(require_plugin2(), 1);
241359
241541
 
241360
241542
  // src/utils/paste-file.ts
241361
241543
  import { chmod, mkdir as mkdir4, open } from "node:fs/promises";
@@ -241406,7 +241588,7 @@ function messageTextLength(content) {
241406
241588
  }
241407
241589
  return n;
241408
241590
  }
241409
- var routes11 = async (fastify2) => {
241591
+ var routes12 = async (fastify2) => {
241410
241592
  const instructionReceiverToken = randomUUID15();
241411
241593
  const instructionDeliveryLocks = /* @__PURE__ */ new Map();
241412
241594
  async function serializeInstructionDelivery(key, effect) {
@@ -242760,10 +242942,10 @@ var routes11 = async (fastify2) => {
242760
242942
  return reply.code(200).send({ success: true, favorited });
242761
242943
  });
242762
242944
  };
242763
- var agent_session_routes_default = (0, import_fastify_plugin12.default)(routes11, { name: "agent-session-routes" });
242945
+ var agent_session_routes_default = (0, import_fastify_plugin13.default)(routes12, { name: "agent-session-routes" });
242764
242946
 
242765
242947
  // src/routes/branch-activity-routes.ts
242766
- var import_fastify_plugin13 = __toESM(require_plugin2(), 1);
242948
+ var import_fastify_plugin14 = __toESM(require_plugin2(), 1);
242767
242949
  function toResponse(map2) {
242768
242950
  return {
242769
242951
  branches: Array.from(map2.entries()).map(([branch, state]) => ({
@@ -242778,7 +242960,7 @@ function fromResponse(resp) {
242778
242960
  resp.branches.map((b2) => [b2.branch ?? "", { activity: b2.activity, since: b2.since }])
242779
242961
  );
242780
242962
  }
242781
- var routes12 = async (fastify2) => {
242963
+ var routes13 = async (fastify2) => {
242782
242964
  function proxyAuto(remoteServerId, method, apiPath, body) {
242783
242965
  return proxyToRemoteAuto(remoteServerId, method, apiPath, body, {
242784
242966
  reverseConnectManager: fastify2.reverseConnectManager
@@ -242843,10 +243025,10 @@ var routes12 = async (fastify2) => {
242843
243025
  }
242844
243026
  );
242845
243027
  };
242846
- var branch_activity_routes_default = (0, import_fastify_plugin13.default)(routes12, { name: "branch-activity-routes" });
243028
+ var branch_activity_routes_default = (0, import_fastify_plugin14.default)(routes13, { name: "branch-activity-routes" });
242847
243029
 
242848
243030
  // src/routes/merge-status-routes.ts
242849
- var import_fastify_plugin14 = __toESM(require_plugin2(), 1);
243031
+ var import_fastify_plugin15 = __toESM(require_plugin2(), 1);
242850
243032
  function resolveTargets(comparisons, storedTargets) {
242851
243033
  const sources = [];
242852
243034
  const effective = comparisons.map((comparison) => {
@@ -242960,7 +243142,7 @@ function sendComputed(reply, repoPath, comparisons, repository) {
242960
243142
  return reply.code(statusCode).send({ error: message });
242961
243143
  }
242962
243144
  }
242963
- var routes13 = async (fastify2) => {
243145
+ var routes14 = async (fastify2) => {
242964
243146
  fastify2.post(
242965
243147
  "/api/path/branches/merge-status",
242966
243148
  async (req, reply) => {
@@ -243082,11 +243264,11 @@ var routes13 = async (fastify2) => {
243082
243264
  }
243083
243265
  );
243084
243266
  };
243085
- var merge_status_routes_default = (0, import_fastify_plugin14.default)(routes13, { name: "merge-status-routes" });
243267
+ var merge_status_routes_default = (0, import_fastify_plugin15.default)(routes14, { name: "merge-status-routes" });
243086
243268
 
243087
243269
  // src/routes/chat-session-routes.ts
243088
- var import_fastify_plugin15 = __toESM(require_plugin2(), 1);
243089
- var routes14 = async (fastify2) => {
243270
+ var import_fastify_plugin16 = __toESM(require_plugin2(), 1);
243271
+ var routes15 = async (fastify2) => {
243090
243272
  const getAuthorizedSession = (req, reply, sessionId) => {
243091
243273
  const authResult = requireUserFacingUserId(req, reply);
243092
243274
  if (authResult === null) return null;
@@ -243191,10 +243373,10 @@ var routes14 = async (fastify2) => {
243191
243373
  return reply.send({ ok: true });
243192
243374
  });
243193
243375
  };
243194
- var chat_session_routes_default = (0, import_fastify_plugin15.default)(routes14, { name: "chat-session-routes" });
243376
+ var chat_session_routes_default = (0, import_fastify_plugin16.default)(routes15, { name: "chat-session-routes" });
243195
243377
 
243196
243378
  // src/routes/project-chat-routes.ts
243197
- var import_fastify_plugin16 = __toESM(require_plugin2(), 1);
243379
+ var import_fastify_plugin17 = __toESM(require_plugin2(), 1);
243198
243380
  import { createHash as createHash6, randomUUID as randomUUID16 } from "crypto";
243199
243381
  var MAX_TITLE_LENGTH = 200;
243200
243382
  var MAX_MESSAGE_LENGTH = 1e5;
@@ -243307,7 +243489,7 @@ function parseWorkspaceSelectionBody(body) {
243307
243489
  if (!requestId || requestId.length > MAX_TOOL_SELECTOR_ID || !workspaceId || workspaceId.length > MAX_TOOL_SELECTOR_ID) return null;
243308
243490
  return { requestId, workspaceId };
243309
243491
  }
243310
- var routes15 = async (fastify2) => {
243492
+ var routes16 = async (fastify2) => {
243311
243493
  const getOwnedThread = async (req, reply, threadId) => {
243312
243494
  const authResult = requireAuth(req, reply);
243313
243495
  if (authResult === null) return null;
@@ -243526,10 +243708,10 @@ var routes15 = async (fastify2) => {
243526
243708
  }
243527
243709
  });
243528
243710
  };
243529
- var project_chat_routes_default = (0, import_fastify_plugin16.default)(routes15, { name: "project-chat-routes" });
243711
+ var project_chat_routes_default = (0, import_fastify_plugin17.default)(routes16, { name: "project-chat-routes" });
243530
243712
 
243531
243713
  // src/routes/project-activity-routes.ts
243532
- var import_fastify_plugin17 = __toESM(require_plugin2(), 1);
243714
+ var import_fastify_plugin18 = __toESM(require_plugin2(), 1);
243533
243715
 
243534
243716
  // src/project-activity.ts
243535
243717
  var RECENT_THREAD_LIMIT = 5;
@@ -243537,7 +243719,7 @@ var RECENT_SESSION_LIMIT = 8;
243537
243719
  var RECENT_RUN_LIMIT = 5;
243538
243720
  var PRIORITY_TASK_LIMIT = 5;
243539
243721
  var ATTENTION_LIMIT = 10;
243540
- var parseDbTimestamp3 = (value) => {
243722
+ var parseDbTimestamp4 = (value) => {
243541
243723
  if (!value) return null;
243542
243724
  const explicitZone = /(?:Z|[+-]\d\d:\d\d)$/i.test(value);
243543
243725
  const parsed = Date.parse(explicitZone ? value : `${value.replace(" ", "T")}Z`);
@@ -243562,8 +243744,8 @@ var localActivity = (session) => {
243562
243744
  lastActiveAt: maxTimestamp(
243563
243745
  session.last_user_message_at,
243564
243746
  session.last_completed_at,
243565
- parseDbTimestamp3(session.updated_at),
243566
- parseDbTimestamp3(session.created_at)
243747
+ parseDbTimestamp4(session.updated_at),
243748
+ parseDbTimestamp4(session.created_at)
243567
243749
  ),
243568
243750
  lastUserMessageAt: session.last_user_message_at ?? null,
243569
243751
  lastCompletedAt: session.last_completed_at ?? null
@@ -243627,7 +243809,7 @@ async function getProjectActivity(storage, projectId, userId) {
243627
243809
  entityId: run2.id,
243628
243810
  status: run2.status,
243629
243811
  title: run2.scheduleName,
243630
- occurredAtMs: parseDbTimestamp3(run2.finished_at ?? run2.started_at) ?? 0
243812
+ occurredAtMs: parseDbTimestamp4(run2.finished_at ?? run2.started_at) ?? 0
243631
243813
  }))
243632
243814
  ].sort((left, right) => right.occurredAtMs - left.occurredAtMs || right.entityId.localeCompare(left.entityId)).slice(0, ATTENTION_LIMIT).map(({ occurredAtMs, ...item }) => ({
243633
243815
  ...item,
@@ -243647,7 +243829,7 @@ async function getProjectActivity(storage, projectId, userId) {
243647
243829
  }
243648
243830
 
243649
243831
  // src/routes/project-activity-routes.ts
243650
- var routes16 = async (fastify2) => {
243832
+ var routes17 = async (fastify2) => {
243651
243833
  fastify2.get(
243652
243834
  "/api/projects/:projectId/activity",
243653
243835
  async (req, reply) => {
@@ -243663,12 +243845,12 @@ var routes16 = async (fastify2) => {
243663
243845
  }
243664
243846
  );
243665
243847
  };
243666
- var project_activity_routes_default = (0, import_fastify_plugin17.default)(routes16);
243848
+ var project_activity_routes_default = (0, import_fastify_plugin18.default)(routes17);
243667
243849
 
243668
243850
  // src/routes/task-routes.ts
243669
- var import_fastify_plugin18 = __toESM(require_plugin2(), 1);
243851
+ var import_fastify_plugin19 = __toESM(require_plugin2(), 1);
243670
243852
  import { randomUUID as randomUUID17 } from "crypto";
243671
- var routes17 = async (fastify2) => {
243853
+ var routes18 = async (fastify2) => {
243672
243854
  fastify2.get(
243673
243855
  "/api/projects/:projectId/tasks",
243674
243856
  async (req, reply) => {
@@ -243828,12 +244010,12 @@ Description: ${description}`,
243828
244010
  return reply.code(200).send({ success: true });
243829
244011
  });
243830
244012
  };
243831
- var task_routes_default = (0, import_fastify_plugin18.default)(routes17, { name: "task-routes" });
244013
+ var task_routes_default = (0, import_fastify_plugin19.default)(routes18, { name: "task-routes" });
243832
244014
 
243833
244015
  // src/routes/rule-routes.ts
243834
- var import_fastify_plugin19 = __toESM(require_plugin2(), 1);
244016
+ var import_fastify_plugin20 = __toESM(require_plugin2(), 1);
243835
244017
  import { randomUUID as randomUUID18 } from "crypto";
243836
- var routes18 = async (fastify2) => {
244018
+ var routes19 = async (fastify2) => {
243837
244019
  fastify2.get(
243838
244020
  "/api/projects/:projectId/rules",
243839
244021
  async (req, reply) => {
@@ -243919,12 +244101,12 @@ var routes18 = async (fastify2) => {
243919
244101
  return reply.code(200).send({ success: true });
243920
244102
  });
243921
244103
  };
243922
- var rule_routes_default = (0, import_fastify_plugin19.default)(routes18, { name: "rule-routes" });
244104
+ var rule_routes_default = (0, import_fastify_plugin20.default)(routes19, { name: "rule-routes" });
243923
244105
 
243924
244106
  // src/routes/command-routes.ts
243925
- var import_fastify_plugin20 = __toESM(require_plugin2(), 1);
244107
+ var import_fastify_plugin21 = __toESM(require_plugin2(), 1);
243926
244108
  import { randomUUID as randomUUID19 } from "crypto";
243927
- var routes19 = async (fastify2) => {
244109
+ var routes20 = async (fastify2) => {
243928
244110
  fastify2.get(
243929
244111
  "/api/projects/:projectId/commands",
243930
244112
  async (req, reply) => {
@@ -243993,10 +244175,10 @@ var routes19 = async (fastify2) => {
243993
244175
  return reply.code(200).send({ success: true });
243994
244176
  });
243995
244177
  };
243996
- var command_routes_default = (0, import_fastify_plugin20.default)(routes19, { name: "command-routes" });
244178
+ var command_routes_default = (0, import_fastify_plugin21.default)(routes20, { name: "command-routes" });
243997
244179
 
243998
244180
  // src/routes/workflow-run-routes.ts
243999
- var import_fastify_plugin21 = __toESM(require_plugin2(), 1);
244181
+ var import_fastify_plugin22 = __toESM(require_plugin2(), 1);
244000
244182
 
244001
244183
  // src/utils/review-brief.ts
244002
244184
  var BASE_TIMEOUT_MS = 15e3;
@@ -244328,7 +244510,7 @@ function errStatus(err) {
244328
244510
  return 500;
244329
244511
  }
244330
244512
  }
244331
- async function routes20(fastify2) {
244513
+ async function routes21(fastify2) {
244332
244514
  const remoteRunMap = /* @__PURE__ */ new Map();
244333
244515
  const TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set(["completed", "cancelled", "failed"]);
244334
244516
  const trackRemoteRun = (localRun, info) => {
@@ -244793,10 +244975,10 @@ async function routes20(fastify2) {
244793
244975
  return reply.send({ runs });
244794
244976
  });
244795
244977
  }
244796
- var workflow_run_routes_default = (0, import_fastify_plugin21.default)(routes20, { name: "workflow-run-routes" });
244978
+ var workflow_run_routes_default = (0, import_fastify_plugin22.default)(routes21, { name: "workflow-run-routes" });
244797
244979
 
244798
244980
  // src/routes/settings-routes.ts
244799
- var import_fastify_plugin22 = __toESM(require_plugin2(), 1);
244981
+ var import_fastify_plugin23 = __toESM(require_plugin2(), 1);
244800
244982
  var SettingsValidationError = class extends Error {
244801
244983
  };
244802
244984
  var DEFAULT_PROXY_CONFIG = { type: "none", host: "", port: 0 };
@@ -244860,7 +245042,7 @@ function requireSettingsUser(req, reply) {
244860
245042
  if (auth === null) return null;
244861
245043
  return resolveUserId(auth);
244862
245044
  }
244863
- var routes21 = async (fastify2) => {
245045
+ var routes22 = async (fastify2) => {
244864
245046
  fastify2.get("/api/settings/agent-processes", async (req, reply) => {
244865
245047
  if (requireAuth(req, reply) === null) return;
244866
245048
  const saved = await fastify2.storage.settings.get("agentProcesses");
@@ -245134,11 +245316,11 @@ var routes21 = async (fastify2) => {
245134
245316
  return reply.code(200).send(updated);
245135
245317
  });
245136
245318
  };
245137
- var settings_routes_default = (0, import_fastify_plugin22.default)(routes21, { name: "settings-routes" });
245319
+ var settings_routes_default = (0, import_fastify_plugin23.default)(routes22, { name: "settings-routes" });
245138
245320
 
245139
245321
  // src/routes/translate-routes.ts
245140
- var import_fastify_plugin23 = __toESM(require_plugin2(), 1);
245141
- var routes22 = async (fastify2) => {
245322
+ var import_fastify_plugin24 = __toESM(require_plugin2(), 1);
245323
+ var routes23 = async (fastify2) => {
245142
245324
  fastify2.post(
245143
245325
  "/api/translate",
245144
245326
  async (req, reply) => {
@@ -245179,10 +245361,10 @@ ${text2}`,
245179
245361
  }
245180
245362
  );
245181
245363
  };
245182
- var translate_routes_default = (0, import_fastify_plugin23.default)(routes22, { name: "translate-routes" });
245364
+ var translate_routes_default = (0, import_fastify_plugin24.default)(routes23, { name: "translate-routes" });
245183
245365
 
245184
245366
  // src/routes/websocket-routes.ts
245185
- var import_fastify_plugin24 = __toESM(require_plugin2(), 1);
245367
+ var import_fastify_plugin25 = __toESM(require_plugin2(), 1);
245186
245368
 
245187
245369
  // src/routes/executor-stream-handlers.ts
245188
245370
  import { randomUUID as randomUUID20 } from "crypto";
@@ -245393,7 +245575,6 @@ async function verifyWsToken(token) {
245393
245575
  }
245394
245576
  async function authenticateWs(authEnabled, query, socket) {
245395
245577
  if (!authEnabled) return { userId: null, kind: "solo" };
245396
- if (process.env.VIBEDECKX_API_KEY && query.apiKey) return { userId: null, kind: "api_key" };
245397
245578
  const reject = (error48) => {
245398
245579
  try {
245399
245580
  socket.send(JSON.stringify({ error: error48 }));
@@ -245450,7 +245631,7 @@ async function userOwnsSession(fastify2, sessionId, userId) {
245450
245631
  }
245451
245632
 
245452
245633
  // src/routes/websocket-routes.ts
245453
- var routes23 = async (fastify2) => {
245634
+ var routes24 = async (fastify2) => {
245454
245635
  fastify2.reverseConnectManager.setStatusChangeHandler((remoteServerId, status) => {
245455
245636
  if (status !== "online") return;
245456
245637
  const cache2 = fastify2.remotePatchCache;
@@ -245666,25 +245847,21 @@ var routes23 = async (fastify2) => {
245666
245847
  console.log(`[AgentWS] Connection attempt for session ${sessionId} (auth=${fastify2.authEnabled})`);
245667
245848
  let principalUserId = fastify2.authEnabled ? null : "local";
245668
245849
  if (fastify2.authEnabled) {
245669
- const apiKey = req.query.apiKey;
245670
245850
  const token = req.query.token;
245671
- const apiKeyTrusted = !!process.env.VIBEDECKX_API_KEY && !!apiKey;
245672
- if (!apiKeyTrusted) {
245673
- if (!token) {
245674
- console.log(`[AgentWS] Auth rejected: no token (session=${sessionId})`);
245675
- socket.send(JSON.stringify({ error: "Authentication required" }));
245676
- socket.close();
245677
- return;
245678
- }
245679
- const userId = await verifyWsToken(token);
245680
- if (!userId) {
245681
- console.log(`[AgentWS] Auth rejected: invalid token (session=${sessionId})`);
245682
- socket.send(JSON.stringify({ error: "Invalid authentication token" }));
245683
- socket.close();
245684
- return;
245685
- }
245686
- principalUserId = userId;
245851
+ if (!token) {
245852
+ console.log(`[AgentWS] Auth rejected: no token (session=${sessionId})`);
245853
+ socket.send(JSON.stringify({ error: "Authentication required" }));
245854
+ socket.close();
245855
+ return;
245687
245856
  }
245857
+ const userId = await verifyWsToken(token);
245858
+ if (!userId) {
245859
+ console.log(`[AgentWS] Auth rejected: invalid token (session=${sessionId})`);
245860
+ socket.send(JSON.stringify({ error: "Invalid authentication token" }));
245861
+ socket.close();
245862
+ return;
245863
+ }
245864
+ principalUserId = userId;
245688
245865
  }
245689
245866
  if (principalUserId !== null && !await userOwnsSession(fastify2, sessionId, principalUserId)) {
245690
245867
  console.log(`[AgentWS] Ownership denied for session ${sessionId} (user=${principalUserId})`);
@@ -245814,37 +245991,33 @@ var routes23 = async (fastify2) => {
245814
245991
  const { sessionId } = req.params;
245815
245992
  let principalUserId = fastify2.authEnabled ? null : "local";
245816
245993
  if (fastify2.authEnabled) {
245817
- const apiKey = req.query.apiKey;
245818
245994
  const token = req.query.token;
245819
- const apiKeyTrusted = !!process.env.VIBEDECKX_API_KEY && !!apiKey;
245820
- if (!apiKeyTrusted) {
245821
- if (!token) {
245822
- console.log(`[ChatWS] Auth rejected: no token (session=${sessionId})`);
245823
- try {
245824
- socket.send(JSON.stringify({ error: "Authentication required" }));
245825
- } catch {
245826
- }
245827
- try {
245828
- socket.close();
245829
- } catch {
245830
- }
245831
- return;
245995
+ if (!token) {
245996
+ console.log(`[ChatWS] Auth rejected: no token (session=${sessionId})`);
245997
+ try {
245998
+ socket.send(JSON.stringify({ error: "Authentication required" }));
245999
+ } catch {
245832
246000
  }
245833
- const userId = await verifyWsToken(token);
245834
- if (!userId) {
245835
- console.log(`[ChatWS] Auth rejected: invalid token (session=${sessionId})`);
245836
- try {
245837
- socket.send(JSON.stringify({ error: "Invalid authentication token" }));
245838
- } catch {
245839
- }
245840
- try {
245841
- socket.close();
245842
- } catch {
245843
- }
245844
- return;
246001
+ try {
246002
+ socket.close();
246003
+ } catch {
245845
246004
  }
245846
- principalUserId = userId;
246005
+ return;
245847
246006
  }
246007
+ const userId = await verifyWsToken(token);
246008
+ if (!userId) {
246009
+ console.log(`[ChatWS] Auth rejected: invalid token (session=${sessionId})`);
246010
+ try {
246011
+ socket.send(JSON.stringify({ error: "Invalid authentication token" }));
246012
+ } catch {
246013
+ }
246014
+ try {
246015
+ socket.close();
246016
+ } catch {
246017
+ }
246018
+ return;
246019
+ }
246020
+ principalUserId = userId;
245848
246021
  }
245849
246022
  if (principalUserId !== null) {
245850
246023
  const owned = fastify2.chatSessionManager.getSession(sessionId);
@@ -245897,10 +246070,10 @@ var routes23 = async (fastify2) => {
245897
246070
  );
245898
246071
  });
245899
246072
  };
245900
- var websocket_routes_default = (0, import_fastify_plugin24.default)(routes23, { name: "websocket-routes" });
246073
+ var websocket_routes_default = (0, import_fastify_plugin25.default)(routes24, { name: "websocket-routes" });
245901
246074
 
245902
246075
  // src/routes/reverse-connect-routes.ts
245903
- var import_fastify_plugin25 = __toESM(require_plugin2(), 1);
246076
+ var import_fastify_plugin26 = __toESM(require_plugin2(), 1);
245904
246077
  import { randomBytes as randomBytes2, createHash as createHash7, verify as cryptoVerify } from "crypto";
245905
246078
 
245906
246079
  // src/utils/rate-limited-warn.ts
@@ -245936,73 +246109,6 @@ function createRateLimitedWarn(windowMs, maxKeys) {
245936
246109
  };
245937
246110
  }
245938
246111
 
245939
- // src/update-check.ts
245940
- var SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?$/;
245941
- async function fetchLatestPublishedVersion(pkg = "vibedeckx", fetchImpl = fetch) {
245942
- try {
245943
- const response = await fetchImpl(
245944
- `https://registry.npmjs.org/${pkg}/latest`,
245945
- { signal: AbortSignal.timeout(4e3) }
245946
- );
245947
- if (!response.ok) return void 0;
245948
- const body = await response.json();
245949
- return typeof body.version === "string" && parseSemver(body.version) ? body.version : void 0;
245950
- } catch {
245951
- return void 0;
245952
- }
245953
- }
245954
- function parseSemver(version2) {
245955
- const match2 = SEMVER_RE.exec(version2);
245956
- if (!match2) return void 0;
245957
- return {
245958
- core: [match2[1], match2[2], match2[3]],
245959
- prerelease: match2[4]?.split(".")
245960
- };
245961
- }
245962
- function compareNumericStrings(a, b2) {
245963
- if (a.length !== b2.length) return a.length - b2.length;
245964
- return a < b2 ? -1 : a > b2 ? 1 : 0;
245965
- }
245966
- function comparePrereleaseIdentifiers(a, b2) {
245967
- const aNumeric = /^\d+$/.test(a);
245968
- const bNumeric = /^\d+$/.test(b2);
245969
- if (aNumeric && bNumeric) return compareNumericStrings(a, b2);
245970
- if (aNumeric !== bNumeric) return aNumeric ? -1 : 1;
245971
- return a < b2 ? -1 : a > b2 ? 1 : 0;
245972
- }
245973
- function compareSemver(a, b2) {
245974
- for (let i = 0; i < 3; i += 1) {
245975
- const compared = compareNumericStrings(a.core[i], b2.core[i]);
245976
- if (compared !== 0) return compared;
245977
- }
245978
- if (!a.prerelease && !b2.prerelease) return 0;
245979
- if (!a.prerelease) return 1;
245980
- if (!b2.prerelease) return -1;
245981
- const length = Math.max(a.prerelease.length, b2.prerelease.length);
245982
- for (let i = 0; i < length; i += 1) {
245983
- const aId = a.prerelease[i];
245984
- const bId = b2.prerelease[i];
245985
- if (aId === void 0) return -1;
245986
- if (bId === void 0) return 1;
245987
- const compared = comparePrereleaseIdentifiers(aId, bId);
245988
- if (compared !== 0) return compared;
245989
- }
245990
- return 0;
245991
- }
245992
- function compareVersionStrings(a, b2) {
245993
- const parsedA = parseSemver(a);
245994
- const parsedB = parseSemver(b2);
245995
- if (!parsedA || !parsedB) return void 0;
245996
- return compareSemver(parsedA, parsedB);
245997
- }
245998
- function compareUpdateStatus(current, latest) {
245999
- if (latest === void 0) return "unknown";
246000
- const currentParsed = parseSemver(current);
246001
- const latestParsed = parseSemver(latest);
246002
- if (!currentParsed || !latestParsed) return "unknown";
246003
- return compareSemver(latestParsed, currentParsed) > 0 ? "update-available" : "up-to-date";
246004
- }
246005
-
246006
246112
  // src/routes/reverse-connect-routes.ts
246007
246113
  function extractReportedVersion(frame) {
246008
246114
  if (typeof frame.version !== "string" || frame.version.length === 0) return void 0;
@@ -246012,7 +246118,7 @@ function extractReportedVersion(frame) {
246012
246118
  var MACHINE_HANDSHAKE_TIMEOUT_MS = 5e3;
246013
246119
  var REJECT_LOG_WINDOW_MS = 3e4;
246014
246120
  var REJECT_LOG_MAX_KEYS = 500;
246015
- var routes24 = async (fastify2) => {
246121
+ var routes25 = async (fastify2) => {
246016
246122
  const logRejectedUpgrade = createRateLimitedWarn(REJECT_LOG_WINDOW_MS, REJECT_LOG_MAX_KEYS);
246017
246123
  fastify2.get("/api/reverse-connect/identity", async (req, reply) => {
246018
246124
  const token = req.headers["x-vibedeckx-connect-token"];
@@ -246059,7 +246165,11 @@ var routes24 = async (fastify2) => {
246059
246165
  console.log(`[ReverseConnect] Worker ${serverId} reported no version (pre-reporting release)`);
246060
246166
  return;
246061
246167
  }
246168
+ const previous = (await fastify2.storage.remoteServers.getById(serverId))?.worker_version;
246062
246169
  await fastify2.storage.remoteServers.updateWorkerVersion(serverId, reported.version, reported.capabilities);
246170
+ if (previous !== reported.version) {
246171
+ console.log(`[ReverseConnect] Worker ${serverId} version ${previous ?? "unreported"} \u2192 ${reported.version}`);
246172
+ }
246063
246173
  const cmp = compareVersionStrings(reported.version, MIN_WORKER_VERSION);
246064
246174
  if (cmp !== void 0 && cmp < 0) {
246065
246175
  console.warn(
@@ -246142,10 +246252,10 @@ var routes24 = async (fastify2) => {
246142
246252
  );
246143
246253
  });
246144
246254
  };
246145
- var reverse_connect_routes_default = (0, import_fastify_plugin25.default)(routes24, { name: "reverse-connect-routes" });
246255
+ var reverse_connect_routes_default = (0, import_fastify_plugin26.default)(routes25, { name: "reverse-connect-routes" });
246146
246256
 
246147
246257
  // src/routes/event-routes.ts
246148
- var import_fastify_plugin26 = __toESM(require_plugin2(), 1);
246258
+ var import_fastify_plugin27 = __toESM(require_plugin2(), 1);
246149
246259
  function toWireEvent(event) {
246150
246260
  if (event.type === "executor:stopped" && (event.tailOutput !== void 0 || event.finalResult !== void 0)) {
246151
246261
  const { tailOutput: _tailOutput, finalResult: _finalResult, ...rest } = event;
@@ -246153,31 +246263,28 @@ function toWireEvent(event) {
246153
246263
  }
246154
246264
  return event;
246155
246265
  }
246156
- var routes25 = async (fastify2) => {
246266
+ var routes26 = async (fastify2) => {
246157
246267
  fastify2.get("/api/events", async (req, reply) => {
246158
246268
  let userId = null;
246159
246269
  if (fastify2.authEnabled) {
246160
- const apiKey = req.headers["x-vibedeckx-api-key"];
246161
- if (!(process.env.VIBEDECKX_API_KEY && apiKey)) {
246162
- const token = req.query.token;
246163
- if (!token) {
246164
- return reply.code(401).send({ error: "Unauthorized" });
246165
- }
246166
- try {
246167
- const { verifyToken: verifyToken3 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
246168
- const payload = await verifyToken3(token, {
246169
- secretKey: process.env.CLERK_SECRET_KEY,
246170
- clockSkewInMs: CLERK_CLOCK_SKEW_MS
246171
- });
246172
- if (!payload.sub) {
246173
- return reply.code(401).send({ error: "Unauthorized" });
246174
- }
246175
- userId = payload.sub;
246176
- } catch (err) {
246177
- const reason = err?.reason;
246178
- if (reason) console.log(`[EventsSSE] token verification failed: ${reason}`);
246270
+ const token = req.query.token;
246271
+ if (!token) {
246272
+ return reply.code(401).send({ error: "Unauthorized" });
246273
+ }
246274
+ try {
246275
+ const { verifyToken: verifyToken3 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
246276
+ const payload = await verifyToken3(token, {
246277
+ secretKey: process.env.CLERK_SECRET_KEY,
246278
+ clockSkewInMs: CLERK_CLOCK_SKEW_MS
246279
+ });
246280
+ if (!payload.sub) {
246179
246281
  return reply.code(401).send({ error: "Unauthorized" });
246180
246282
  }
246283
+ userId = payload.sub;
246284
+ } catch (err) {
246285
+ const reason = err?.reason;
246286
+ if (reason) console.log(`[EventsSSE] token verification failed: ${reason}`);
246287
+ return reply.code(401).send({ error: "Unauthorized" });
246181
246288
  }
246182
246289
  }
246183
246290
  reply.raw.writeHead(200, {
@@ -246211,10 +246318,10 @@ var routes25 = async (fastify2) => {
246211
246318
  await reply;
246212
246319
  });
246213
246320
  };
246214
- var event_routes_default = (0, import_fastify_plugin26.default)(routes25, { name: "event-routes" });
246321
+ var event_routes_default = (0, import_fastify_plugin27.default)(routes26, { name: "event-routes" });
246215
246322
 
246216
246323
  // src/routes/terminal-routes.ts
246217
- var import_fastify_plugin27 = __toESM(require_plugin2(), 1);
246324
+ var import_fastify_plugin28 = __toESM(require_plugin2(), 1);
246218
246325
  import path13 from "path";
246219
246326
 
246220
246327
  // src/utils/path-project.ts
@@ -246242,7 +246349,7 @@ async function getRemoteConfig5(fastify2, project, remoteServerId) {
246242
246349
  remotePath: target.remote_path
246243
246350
  };
246244
246351
  }
246245
- var routes26 = async (fastify2) => {
246352
+ var routes27 = async (fastify2) => {
246246
246353
  fastify2.post("/api/path/terminals", async (req, reply) => {
246247
246354
  const { path: projectPath, branch } = req.body;
246248
246355
  if (!projectPath) {
@@ -246418,11 +246525,11 @@ var routes26 = async (fastify2) => {
246418
246525
  }
246419
246526
  );
246420
246527
  };
246421
- var terminal_routes_default = (0, import_fastify_plugin27.default)(routes26, { name: "terminal-routes" });
246528
+ var terminal_routes_default = (0, import_fastify_plugin28.default)(routes27, { name: "terminal-routes" });
246422
246529
 
246423
246530
  // src/routes/browser-routes.ts
246424
- var import_fastify_plugin28 = __toESM(require_plugin2(), 1);
246425
- var routes27 = async (fastify2) => {
246531
+ var import_fastify_plugin29 = __toESM(require_plugin2(), 1);
246532
+ var routes28 = async (fastify2) => {
246426
246533
  const ensureProjectAccess = async (req, reply) => {
246427
246534
  const userId = requireUserFacingUserId(req, reply);
246428
246535
  if (userId === null) return null;
@@ -246493,10 +246600,10 @@ var routes27 = async (fastify2) => {
246493
246600
  return reply.code(200).send({ ok: true });
246494
246601
  });
246495
246602
  };
246496
- var browser_routes_default = (0, import_fastify_plugin28.default)(routes27, { name: "browser-routes" });
246603
+ var browser_routes_default = (0, import_fastify_plugin29.default)(routes28, { name: "browser-routes" });
246497
246604
 
246498
246605
  // src/routes/browser-proxy-routes.ts
246499
- var import_fastify_plugin29 = __toESM(require_plugin2(), 1);
246606
+ var import_fastify_plugin30 = __toESM(require_plugin2(), 1);
246500
246607
  import { randomUUID as randomUUID21 } from "crypto";
246501
246608
 
246502
246609
  // src/utils/ssrf-guard.ts
@@ -246992,7 +247099,7 @@ function generateInjectedScript(projectId, targetOrigin, proxyWsPrefix) {
246992
247099
  })();
246993
247100
  </script>`;
246994
247101
  }
246995
- var routes28 = async (fastify2) => {
247102
+ var routes29 = async (fastify2) => {
246996
247103
  fastify2.get("/api/projects/:id/browser/proxy/*", async (req, reply) => {
246997
247104
  const userId = requireUserFacingOrTrustedProxyUserId(req, reply);
246998
247105
  if (userId === null) return;
@@ -247061,7 +247168,7 @@ var routes28 = async (fastify2) => {
247061
247168
  const { id: projectId } = req.params;
247062
247169
  const principal = await authenticateWs(fastify2.authEnabled, req.query, socket);
247063
247170
  if (!principal) return;
247064
- const projectOwner = principal.kind === "api_key" ? void 0 : principal.userId ?? "local";
247171
+ const projectOwner = principal.userId ?? "local";
247065
247172
  if (!await fastify2.storage.projects.getById(projectId, projectOwner)) {
247066
247173
  try {
247067
247174
  socket.send(JSON.stringify({ error: "Forbidden" }));
@@ -247164,10 +247271,10 @@ var routes28 = async (fastify2) => {
247164
247271
  });
247165
247272
  });
247166
247273
  };
247167
- var browser_proxy_routes_default = (0, import_fastify_plugin29.default)(routes28, { name: "browser-proxy-routes" });
247274
+ var browser_proxy_routes_default = (0, import_fastify_plugin30.default)(routes29, { name: "browser-proxy-routes" });
247168
247275
 
247169
247276
  // src/routes/cross-remote-target-routes.ts
247170
- var import_fastify_plugin30 = __toESM(require_plugin2(), 1);
247277
+ var import_fastify_plugin31 = __toESM(require_plugin2(), 1);
247171
247278
  import path14 from "path";
247172
247279
  import { promises as fs3 } from "fs";
247173
247280
 
@@ -247247,7 +247354,7 @@ var clampTimeoutMs = (timeoutSec) => {
247247
247354
  const requested = typeof timeoutSec === "number" && Number.isFinite(timeoutSec) && timeoutSec > 0 ? timeoutSec : DEFAULT_TIMEOUT_SEC;
247248
247355
  return Math.min(requested, MAX_TIMEOUT_SEC) * 1e3;
247249
247356
  };
247250
- var routes29 = async (fastify2) => {
247357
+ var routes30 = async (fastify2) => {
247251
247358
  fastify2.post(
247252
247359
  "/api/path/cross-remote/exec",
247253
247360
  async (request, reply) => {
@@ -247355,10 +247462,10 @@ var routes29 = async (fastify2) => {
247355
247462
  return reply.send(result);
247356
247463
  });
247357
247464
  };
247358
- var cross_remote_target_routes_default = (0, import_fastify_plugin30.default)(routes29, { name: "cross-remote-target-routes" });
247465
+ var cross_remote_target_routes_default = (0, import_fastify_plugin31.default)(routes30, { name: "cross-remote-target-routes" });
247359
247466
 
247360
247467
  // src/routes/cross-remote-mcp-routes.ts
247361
- var import_fastify_plugin31 = __toESM(require_plugin2(), 1);
247468
+ var import_fastify_plugin32 = __toESM(require_plugin2(), 1);
247362
247469
  var PROTOCOL_VERSION = "2024-11-05";
247363
247470
  var AUDIT_ARGS_MAX = 1024;
247364
247471
  var NOT_ACCESSIBLE = "remote not found or not accessible";
@@ -247461,7 +247568,7 @@ var textResult = (text2, isError = false) => ({
247461
247568
  content: [{ type: "text", text: text2 }],
247462
247569
  ...isError ? { isError: true } : {}
247463
247570
  });
247464
- var routes30 = async (fastify2) => {
247571
+ var routes31 = async (fastify2) => {
247465
247572
  const guard = new SessionConcurrencyGuard();
247466
247573
  let cachedSecret;
247467
247574
  const getSecret = () => {
@@ -247582,10 +247689,10 @@ var routes30 = async (fastify2) => {
247582
247689
  }
247583
247690
  });
247584
247691
  };
247585
- var cross_remote_mcp_routes_default = (0, import_fastify_plugin31.default)(routes30, { name: "cross-remote-mcp-routes" });
247692
+ var cross_remote_mcp_routes_default = (0, import_fastify_plugin32.default)(routes31, { name: "cross-remote-mcp-routes" });
247586
247693
 
247587
247694
  // src/routes/schedule-routes.ts
247588
- var import_fastify_plugin32 = __toESM(require_plugin2(), 1);
247695
+ var import_fastify_plugin33 = __toESM(require_plugin2(), 1);
247589
247696
  import { randomUUID as randomUUID22 } from "crypto";
247590
247697
  import path15 from "path";
247591
247698
  var RUN_TYPES = ["command", "prompt"];
@@ -247604,7 +247711,7 @@ function validateResolved(b2) {
247604
247711
  if (cronError) return `Invalid cron expression: ${cronError}`;
247605
247712
  return null;
247606
247713
  }
247607
- var routes31 = async (fastify2) => {
247714
+ var routes32 = async (fastify2) => {
247608
247715
  const sendTerminalManualOutcome = (reply, request, replay) => {
247609
247716
  if (!request.terminalStatus || request.terminalResponseStatus === null) return null;
247610
247717
  const common = { runId: request.runId, status: request.terminalStatus, durable: true, replay };
@@ -247835,10 +247942,10 @@ var routes31 = async (fastify2) => {
247835
247942
  }
247836
247943
  );
247837
247944
  };
247838
- var schedule_routes_default = (0, import_fastify_plugin32.default)(routes31, { name: "schedule-routes" });
247945
+ var schedule_routes_default = (0, import_fastify_plugin33.default)(routes32, { name: "schedule-routes" });
247839
247946
 
247840
247947
  // src/search/catalog.ts
247841
- var parseDbTimestamp4 = (ts) => {
247948
+ var parseDbTimestamp5 = (ts) => {
247842
247949
  if (!ts) return null;
247843
247950
  const ms = Date.parse(ts.replace(" ", "T") + "Z");
247844
247951
  return Number.isNaN(ms) ? null : ms;
@@ -247860,7 +247967,7 @@ async function buildSearchCatalog(deps, projectId, projectPath) {
247860
247967
  id: s3.id,
247861
247968
  branch: s3.branch === "" ? null : s3.branch,
247862
247969
  title: s3.title ?? null,
247863
- lastActiveAt: s3.last_user_message_at ?? parseDbTimestamp4(s3.updated_at),
247970
+ lastActiveAt: s3.last_user_message_at ?? parseDbTimestamp5(s3.updated_at),
247864
247971
  favoritedAt: s3.favorited_at ?? null,
247865
247972
  entryCount,
247866
247973
  status: s3.status,
@@ -248127,10 +248234,10 @@ var searchRoutes = async (fastify2) => {
248127
248234
  var search_routes_default = searchRoutes;
248128
248235
 
248129
248236
  // src/routes/notification-routes.ts
248130
- var import_fastify_plugin33 = __toESM(require_plugin2(), 1);
248237
+ var import_fastify_plugin34 = __toESM(require_plugin2(), 1);
248131
248238
  var MAX_LIMIT = 500;
248132
248239
  var DEFAULT_LIMIT = 100;
248133
- var routes32 = async (fastify2) => {
248240
+ var routes33 = async (fastify2) => {
248134
248241
  fastify2.get(
248135
248242
  "/api/notifications",
248136
248243
  async (req, reply) => {
@@ -248162,7 +248269,7 @@ var routes32 = async (fastify2) => {
248162
248269
  return reply.code(200).send({ ok: true });
248163
248270
  });
248164
248271
  };
248165
- var notification_routes_default = (0, import_fastify_plugin33.default)(routes32, { name: "notification-routes" });
248272
+ var notification_routes_default = (0, import_fastify_plugin34.default)(routes33, { name: "notification-routes" });
248166
248273
 
248167
248274
  // ../../node_modules/.pnpm/@clerk+fastify@3.1.2_fastify@5.7.2_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@clerk/fastify/dist/chunk-RY4T2JMQ.mjs
248168
248275
  import { Readable as Readable2 } from "stream";
@@ -248214,7 +248321,7 @@ var requestToProxyRequest = (req) => {
248214
248321
 
248215
248322
  // ../../node_modules/.pnpm/@clerk+fastify@3.1.2_fastify@5.7.2_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@clerk/fastify/dist/index.mjs
248216
248323
  init_dist();
248217
- var import_fastify_plugin34 = __toESM(require_plugin2(), 1);
248324
+ var import_fastify_plugin35 = __toESM(require_plugin2(), 1);
248218
248325
 
248219
248326
  // ../../node_modules/.pnpm/@clerk+backend@3.2.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@clerk/backend/dist/internal.mjs
248220
248327
  init_chunk_JW73PKED();
@@ -248502,7 +248609,7 @@ var plugin = (instance, opts, done) => {
248502
248609
  instance.addHook(hookName, withClerkMiddleware(opts));
248503
248610
  done();
248504
248611
  };
248505
- var clerkPlugin = (0, import_fastify_plugin34.default)(plugin, {
248612
+ var clerkPlugin = (0, import_fastify_plugin35.default)(plugin, {
248506
248613
  name: "@clerk/fastify",
248507
248614
  fastify: "5.x"
248508
248615
  });
@@ -249250,12 +249357,10 @@ async function shutdownLogging() {
249250
249357
  }
249251
249358
 
249252
249359
  // src/server.ts
249253
- var API_KEY = process.env.VIBEDECKX_API_KEY;
249360
+ var API_KEY2 = process.env.VIBEDECKX_API_KEY || void 0;
249254
249361
  function requireAuth(req, reply) {
249255
249362
  const server = req.server;
249256
249363
  if (!server.authEnabled) return void 0;
249257
- const apiKeyHeader = req.headers["x-vibedeckx-api-key"];
249258
- if (API_KEY && apiKeyHeader) return void 0;
249259
249364
  try {
249260
249365
  const { userId } = getAuth(req);
249261
249366
  if (!userId) {
@@ -249342,19 +249447,12 @@ var createServer = async (opts) => {
249342
249447
  done();
249343
249448
  });
249344
249449
  server.addHook("onRequest", (req, reply, done) => {
249345
- if (!API_KEY) return done();
249346
- if (!req.url.startsWith("/api/")) return done();
249450
+ if (!API_KEY2) return done();
249451
+ if (!req.url.startsWith("/api/admin/")) return done();
249347
249452
  if (req.method === "OPTIONS") return done();
249348
- const pathname = req.url.split("?")[0];
249349
- if (pathname === "/api/config" || pathname === "/api/reverse-connect" || pathname === "/api/reverse-connect/identity") {
249350
- return done();
249351
- }
249352
249453
  const providedKey = req.headers["x-vibedeckx-api-key"] || req.query?.apiKey;
249353
- if (!providedKey && authEnabled) {
249354
- return done();
249355
- }
249356
- if (providedKey !== API_KEY) {
249357
- return reply.code(401).send({ error: "Unauthorized" });
249454
+ if (providedKey !== API_KEY2) {
249455
+ return reply.code(404).send({ error: "Not found" });
249358
249456
  }
249359
249457
  done();
249360
249458
  });
@@ -249430,6 +249528,7 @@ var createServer = async (opts) => {
249430
249528
  server.register(reverse_connect_routes_default);
249431
249529
  server.register(project_routes_default);
249432
249530
  server.register(remote_server_routes_default);
249531
+ server.register(worker_stats_routes_default);
249433
249532
  server.register(project_remote_routes_default);
249434
249533
  server.register(search_routes_default);
249435
249534
  server.register(executor_group_routes_default);
@@ -249919,14 +250018,10 @@ var ReverseConnectClient = class {
249919
250018
  });
249920
250019
  body = await response.text();
249921
250020
  } else {
249922
- const injectHeaders = { ...frame.headers ?? {} };
249923
- if (process.env.VIBEDECKX_API_KEY) {
249924
- injectHeaders["x-vibedeckx-api-key"] = process.env.VIBEDECKX_API_KEY;
249925
- }
249926
250021
  const response = await this.localServer.inject({
249927
250022
  method: frame.method,
249928
250023
  url: frame.path,
249929
- headers: injectHeaders,
250024
+ headers: frame.headers ?? {},
249930
250025
  payload: frame.body
249931
250026
  });
249932
250027
  status = response.statusCode;
@@ -249966,11 +250061,7 @@ var ReverseConnectClient = class {
249966
250061
  }
249967
250062
  }
249968
250063
  handleWsOpen(frame) {
249969
- const queryParts = [
249970
- ...frame.query ? [frame.query] : [],
249971
- ...process.env.VIBEDECKX_API_KEY ? [`apiKey=${encodeURIComponent(process.env.VIBEDECKX_API_KEY)}`] : []
249972
- ];
249973
- const wsUrl = `ws://127.0.0.1:${this.localPort}${frame.path}${queryParts.length ? `?${queryParts.join("&")}` : ""}`;
250064
+ const wsUrl = `ws://127.0.0.1:${this.localPort}${frame.path}${frame.query ? `?${frame.query}` : ""}`;
249974
250065
  console.log(`[ReverseClient] Opening local WS channel ${frame.channelId} \u2192 ${frame.path}`);
249975
250066
  const localWs = new wrapper_default(wsUrl);
249976
250067
  localWs.on("open", () => {
@@ -251477,7 +251568,7 @@ var startCommand = buildCommand({
251477
251568
  host: {
251478
251569
  kind: "parsed",
251479
251570
  parse: String,
251480
- brief: "Network interface to bind (default: 127.0.0.1, loopback only). Use 0.0.0.0 to expose on all interfaces \u2014 only do so behind --auth, VIBEDECKX_API_KEY, or a trusted tunnel/proxy.",
251571
+ brief: "Network interface to bind (default: 127.0.0.1, loopback only). Use 0.0.0.0 to expose on all interfaces \u2014 only do so behind --auth or an authenticating proxy.",
251481
251572
  optional: true
251482
251573
  },
251483
251574
  auth: {
@@ -251548,11 +251639,16 @@ var startCommand = buildCommand({
251548
251639
  const noLocalProjects = flags["no-local-projects"] ?? false;
251549
251640
  const tls = loadTLSOptions(flags);
251550
251641
  const isLoopbackHost = host === "127.0.0.1" || host === "::1" || host === "localhost";
251551
- if (!isLoopbackHost && !authEnabled && !process.env.VIBEDECKX_API_KEY) {
251642
+ if (!isLoopbackHost && !authEnabled) {
251552
251643
  console.warn(
251553
251644
  `Warning: binding to ${host} exposes vibedeckx on the network with no authentication.
251554
- Anyone who can reach this host can run commands via the executor API. Enable --auth or
251555
- set VIBEDECKX_API_KEY, or keep the default loopback bind (127.0.0.1) behind a trusted tunnel/proxy.`
251645
+ Anyone who can reach this host can run commands via the executor API. Enable --auth, or put
251646
+ an authenticating proxy in front, or keep the default loopback bind (127.0.0.1).`
251647
+ );
251648
+ }
251649
+ if (process.env.VIBEDECKX_API_KEY) {
251650
+ console.log(
251651
+ "VIBEDECKX_API_KEY is set: it authenticates operator-only endpoints (/api/admin/*).\nIt does not lock the rest of the API and is not user authentication \u2014 use --auth or a\nproxy in front for that."
251556
251652
  );
251557
251653
  }
251558
251654
  console.log(`Starting vibedeckx${tls ? " (HTTPS)" : ""}...`);
@@ -251828,7 +251924,7 @@ var connectRoutes = buildRouteMap({
251828
251924
  defaultCommand: "run",
251829
251925
  docs: { brief: "Connect to a Vibedeckx server as an inbound node" }
251830
251926
  });
251831
- var routes33 = buildRouteMap({
251927
+ var routes34 = buildRouteMap({
251832
251928
  routes: {
251833
251929
  start: startCommand,
251834
251930
  connect: connectRoutes
@@ -251838,7 +251934,7 @@ var routes33 = buildRouteMap({
251838
251934
  brief: "Vibedeckx - AI-powered app generator"
251839
251935
  }
251840
251936
  });
251841
- var program = buildApplication(routes33, {
251937
+ var program = buildApplication(routes34, {
251842
251938
  name: "vibedeckx",
251843
251939
  versionInfo: {
251844
251940
  currentVersion: readPackageVersion()