@threadbase-sh/streamer 1.39.1 → 1.40.0

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/cli.cjs CHANGED
@@ -4121,7 +4121,7 @@ var require_transport = __commonJS({
4121
4121
  "node_modules/pino/lib/transport.js"(exports2, module2) {
4122
4122
  "use strict";
4123
4123
  var { createRequire } = require("module");
4124
- var { existsSync: existsSync15 } = require("fs");
4124
+ var { existsSync: existsSync16 } = require("fs");
4125
4125
  var getCallers = require_caller();
4126
4126
  var { join: join29, isAbsolute: isAbsolute2, sep: sep3 } = require("path");
4127
4127
  var { fileURLToPath: fileURLToPath3 } = require("url");
@@ -4195,7 +4195,7 @@ var require_transport = __commonJS({
4195
4195
  return false;
4196
4196
  }
4197
4197
  }
4198
- return isAbsolute2(path2) && !existsSync15(path2);
4198
+ return isAbsolute2(path2) && !existsSync16(path2);
4199
4199
  }
4200
4200
  function stripQuotes(value) {
4201
4201
  const first = value[0];
@@ -5937,7 +5937,7 @@ var require_pino = __commonJS({
5937
5937
  } = symbols;
5938
5938
  var { epochTime, nullTime } = time3;
5939
5939
  var { pid } = process;
5940
- var hostname5 = os2.hostname();
5940
+ var hostname6 = os2.hostname();
5941
5941
  var defaultErrorSerializer = stdSerializers.err;
5942
5942
  var defaultOptions2 = {
5943
5943
  level: "info",
@@ -5947,7 +5947,7 @@ var require_pino = __commonJS({
5947
5947
  errorKey: "err",
5948
5948
  nestedKey: null,
5949
5949
  enabled: true,
5950
- base: { pid, hostname: hostname5 },
5950
+ base: { pid, hostname: hostname6 },
5951
5951
  serializers: Object.assign(/* @__PURE__ */ Object.create(null), {
5952
5952
  err: defaultErrorSerializer
5953
5953
  }),
@@ -38620,8 +38620,8 @@ var require_service_config = __commonJS({
38620
38620
  }
38621
38621
  if (Array.isArray(validatedConfig.clientHostname)) {
38622
38622
  let hostnameMatched = false;
38623
- for (const hostname5 of validatedConfig.clientHostname) {
38624
- if (hostname5 === os2.hostname()) {
38623
+ for (const hostname6 of validatedConfig.clientHostname) {
38624
+ if (hostname6 === os2.hostname()) {
38625
38625
  hostnameMatched = true;
38626
38626
  }
38627
38627
  }
@@ -51190,8 +51190,8 @@ var require_single_subchannel_channel = __commonJS({
51190
51190
  if (splitPath2.length >= 2) {
51191
51191
  serviceName = splitPath2[1];
51192
51192
  }
51193
- const hostname5 = (_b = (_a3 = (0, uri_parser_1.splitHostPort)(this.options.host)) === null || _a3 === void 0 ? void 0 : _a3.host) !== null && _b !== void 0 ? _b : "localhost";
51194
- this.serviceUrl = `https://${hostname5}/${serviceName}`;
51193
+ const hostname6 = (_b = (_a3 = (0, uri_parser_1.splitHostPort)(this.options.host)) === null || _a3 === void 0 ? void 0 : _a3.host) !== null && _b !== void 0 ? _b : "localhost";
51194
+ this.serviceUrl = `https://${hostname6}/${serviceName}`;
51195
51195
  const timeout = (0, deadline_1.getRelativeTimeout)(options.deadline);
51196
51196
  if (timeout !== Infinity) {
51197
51197
  if (timeout <= 0) {
@@ -51838,8 +51838,8 @@ var require_resolver_dns = __commonJS({
51838
51838
  }
51839
51839
  trace("Looking up DNS hostname " + this.dnsHostname);
51840
51840
  this.latestLookupResult = null;
51841
- const hostname5 = this.dnsHostname;
51842
- this.pendingLookupPromise = this.lookup(hostname5);
51841
+ const hostname6 = this.dnsHostname;
51842
+ this.pendingLookupPromise = this.lookup(hostname6);
51843
51843
  this.pendingLookupPromise.then((addressList) => {
51844
51844
  if (this.pendingLookupPromise === null) {
51845
51845
  return;
@@ -51862,7 +51862,7 @@ var require_resolver_dns = __commonJS({
51862
51862
  this.listener((0, call_interface_1.statusOrFromError)(this.defaultResolutionError), {}, this.latestServiceConfigResult, "");
51863
51863
  });
51864
51864
  if (this.isServiceConfigEnabled && this.pendingTxtPromise === null) {
51865
- this.pendingTxtPromise = this.resolveTxt(hostname5);
51865
+ this.pendingTxtPromise = this.resolveTxt(hostname6);
51866
51866
  this.pendingTxtPromise.then((txtRecord) => {
51867
51867
  if (this.pendingTxtPromise === null) {
51868
51868
  return;
@@ -51904,12 +51904,12 @@ var require_resolver_dns = __commonJS({
51904
51904
  this.continueResolving = true;
51905
51905
  }
51906
51906
  }
51907
- async lookup(hostname5) {
51907
+ async lookup(hostname6) {
51908
51908
  if (environment_1.GRPC_NODE_USE_ALTERNATIVE_RESOLVER) {
51909
51909
  trace("Using alternative DNS resolver.");
51910
51910
  const records = await Promise.allSettled([
51911
- this.alternativeResolver.resolve4(hostname5),
51912
- this.alternativeResolver.resolve6(hostname5)
51911
+ this.alternativeResolver.resolve4(hostname6),
51912
+ this.alternativeResolver.resolve6(hostname6)
51913
51913
  ]);
51914
51914
  if (records.every((result) => result.status === "rejected")) {
51915
51915
  throw new Error(records[0].reason);
@@ -51921,15 +51921,15 @@ var require_resolver_dns = __commonJS({
51921
51921
  port: +this.port
51922
51922
  }));
51923
51923
  }
51924
- const addressList = await dns_1.promises.lookup(hostname5, { all: true });
51924
+ const addressList = await dns_1.promises.lookup(hostname6, { all: true });
51925
51925
  return addressList.map((addr) => ({ host: addr.address, port: +this.port }));
51926
51926
  }
51927
- async resolveTxt(hostname5) {
51927
+ async resolveTxt(hostname6) {
51928
51928
  if (environment_1.GRPC_NODE_USE_ALTERNATIVE_RESOLVER) {
51929
51929
  trace("Using alternative DNS resolver.");
51930
- return this.alternativeResolver.resolveTxt(hostname5);
51930
+ return this.alternativeResolver.resolveTxt(hostname6);
51931
51931
  }
51932
- return dns_1.promises.resolveTxt(hostname5);
51932
+ return dns_1.promises.resolveTxt(hostname6);
51933
51933
  }
51934
51934
  startNextResolutionTimer() {
51935
51935
  var _a3, _b;
@@ -52057,13 +52057,13 @@ var require_http_proxy = __commonJS({
52057
52057
  userCred = proxyUrl.username;
52058
52058
  }
52059
52059
  }
52060
- const hostname5 = proxyUrl.hostname;
52060
+ const hostname6 = proxyUrl.hostname;
52061
52061
  let port = proxyUrl.port;
52062
52062
  if (port === "") {
52063
52063
  port = "80";
52064
52064
  }
52065
52065
  const result = {
52066
- address: `${hostname5}:${port}`
52066
+ address: `${hostname6}:${port}`
52067
52067
  };
52068
52068
  if (userCred) {
52069
52069
  result.creds = userCred;
@@ -53376,8 +53376,8 @@ var require_load_balancing_call = __commonJS({
53376
53376
  if (splitPath2.length >= 2) {
53377
53377
  serviceName = splitPath2[1];
53378
53378
  }
53379
- const hostname5 = (_b = (_a3 = (0, uri_parser_1.splitHostPort)(this.host)) === null || _a3 === void 0 ? void 0 : _a3.host) !== null && _b !== void 0 ? _b : "localhost";
53380
- this.serviceUrl = `https://${hostname5}/${serviceName}`;
53379
+ const hostname6 = (_b = (_a3 = (0, uri_parser_1.splitHostPort)(this.host)) === null || _a3 === void 0 ? void 0 : _a3.host) !== null && _b !== void 0 ? _b : "localhost";
53380
+ this.serviceUrl = `https://${hostname6}/${serviceName}`;
53381
53381
  this.startTime = /* @__PURE__ */ new Date();
53382
53382
  }
53383
53383
  getDeadlineInfo() {
@@ -91186,9 +91186,9 @@ var require_parse_host_uri = __commonJS({
91186
91186
  var ipv4Hostname = "(?:\\d{1,3}(?:\\.\\d{1,3}){3})";
91187
91187
  var ipv6Hostname = "(?:\\[(?<ipv6>[0-9a-fA-F.:]+)\\])";
91188
91188
  var dnsHostname = "(?:[^:/]+)";
91189
- var hostname5 = `(?:${ipv4Hostname}|${ipv6Hostname}|${dnsHostname})`;
91189
+ var hostname6 = `(?:${ipv4Hostname}|${ipv6Hostname}|${dnsHostname})`;
91190
91190
  var port = "(?::(?<port>\\d+))";
91191
- var protoHostPortRegex = new RegExp(`^${scheme}??(?<hostname>${hostname5})${port}?$`);
91191
+ var protoHostPortRegex = new RegExp(`^${scheme}??(?<hostname>${hostname6})${port}?$`);
91192
91192
  function splitProtoHostPort(uri) {
91193
91193
  const match2 = protoHostPortRegex.exec(uri);
91194
91194
  if (!match2?.groups)
@@ -91200,9 +91200,9 @@ var require_parse_host_uri = __commonJS({
91200
91200
  };
91201
91201
  }
91202
91202
  function joinProtoHostPort(components) {
91203
- const { scheme: scheme2, hostname: hostname6, port: port2 } = components;
91203
+ const { scheme: scheme2, hostname: hostname7, port: port2 } = components;
91204
91204
  const schemeText = scheme2 ? `${scheme2}:` : "";
91205
- const hostnameText = hostname6.includes(":") ? `[${hostname6}]` : hostname6;
91205
+ const hostnameText = hostname7.includes(":") ? `[${hostname7}]` : hostname7;
91206
91206
  const portText = port2 !== void 0 ? `:${port2}` : "";
91207
91207
  return `${schemeText}${hostnameText}${portText}`;
91208
91208
  }
@@ -104140,11 +104140,11 @@ var require_pg_connection_string = __commonJS({
104140
104140
  config2.client_encoding = result.searchParams.get("encoding");
104141
104141
  return config2;
104142
104142
  }
104143
- const hostname5 = dummyHost ? "" : result.hostname;
104143
+ const hostname6 = dummyHost ? "" : result.hostname;
104144
104144
  if (!config2.host) {
104145
- config2.host = decodeURIComponent(hostname5);
104146
- } else if (hostname5 && /^%2f/i.test(hostname5)) {
104147
- result.pathname = hostname5 + result.pathname;
104145
+ config2.host = decodeURIComponent(hostname6);
104146
+ } else if (hostname6 && /^%2f/i.test(hostname6)) {
104147
+ result.pathname = hostname6 + result.pathname;
104148
104148
  }
104149
104149
  if (!config2.port) {
104150
104150
  config2.port = result.port;
@@ -135423,10 +135423,10 @@ async function search(query, options, scanner) {
135423
135423
  // src/server.ts
135424
135424
  var import_crypto13 = require("crypto");
135425
135425
  var import_events2 = require("events");
135426
- var import_fs29 = require("fs");
135426
+ var import_fs30 = require("fs");
135427
135427
  var import_promises16 = require("fs/promises");
135428
135428
  var import_http = require("http");
135429
- var import_os12 = require("os");
135429
+ var import_os13 = require("os");
135430
135430
  var import_path29 = require("path");
135431
135431
  var import_readline4 = require("readline");
135432
135432
 
@@ -138231,6 +138231,215 @@ var errorMiddleware = (err, c) => {
138231
138231
  return c.json({ error: message }, 500);
138232
138232
  };
138233
138233
 
138234
+ // src/api/routes/backup.routes.ts
138235
+ var import_os5 = require("os");
138236
+
138237
+ // src/services/backup/backup.ts
138238
+ var BACKUP_FORMAT_VERSION = 1;
138239
+ var BackupError = class extends Error {
138240
+ constructor(message, code) {
138241
+ super(message);
138242
+ this.code = code;
138243
+ }
138244
+ code;
138245
+ };
138246
+ function validateArchive(input) {
138247
+ if (!input || typeof input !== "object") {
138248
+ throw new BackupError("Backup is not an object", "INVALID_ARCHIVE");
138249
+ }
138250
+ const archive = input;
138251
+ const manifest = archive.manifest;
138252
+ if (!manifest || typeof manifest !== "object") {
138253
+ throw new BackupError("Backup is missing its manifest", "INVALID_ARCHIVE");
138254
+ }
138255
+ if (manifest.formatVersion !== BACKUP_FORMAT_VERSION) {
138256
+ throw new BackupError(
138257
+ `Unsupported backup format version ${String(manifest.formatVersion)}; this build reads version ${BACKUP_FORMAT_VERSION}`,
138258
+ "UNSUPPORTED_VERSION"
138259
+ );
138260
+ }
138261
+ if (!Array.isArray(archive.projects)) {
138262
+ throw new BackupError("Backup is missing its projects array", "INVALID_ARCHIVE");
138263
+ }
138264
+ for (const [i, p2] of archive.projects.entries()) {
138265
+ if (!p2 || typeof p2 !== "object") {
138266
+ throw new BackupError(`Project at index ${i} is not an object`, "INVALID_ARCHIVE");
138267
+ }
138268
+ if (typeof p2.id !== "string" || p2.id.length === 0) {
138269
+ throw new BackupError(`Project at index ${i} has no id`, "INVALID_ARCHIVE");
138270
+ }
138271
+ if (typeof p2.path !== "string" || p2.path.length === 0) {
138272
+ throw new BackupError(`Project at index ${i} has no path`, "INVALID_ARCHIVE");
138273
+ }
138274
+ }
138275
+ const ids = new Set(archive.projects.map((p2) => p2.id));
138276
+ if (ids.size !== archive.projects.length) {
138277
+ throw new BackupError("Backup contains duplicate project ids", "INVALID_ARCHIVE");
138278
+ }
138279
+ return archive;
138280
+ }
138281
+ function remapPaths(projects, rules) {
138282
+ const ordered = [...rules].sort((a, b2) => b2.from.length - a.from.length);
138283
+ return projects.map((p2) => {
138284
+ const rule = ordered.find((r) => p2.path === r.from || p2.path.startsWith(`${r.from}/`));
138285
+ if (!rule) return p2;
138286
+ return { ...p2, path: `${rule.to}${p2.path.slice(rule.from.length)}` };
138287
+ });
138288
+ }
138289
+ function planRestore(incoming, existing) {
138290
+ const byId = new Map(existing.map((e) => [e.id, e]));
138291
+ const byPath = new Map(existing.map((e) => [e.path, e]));
138292
+ const plan = { create: [], update: [], conflict: [] };
138293
+ for (const p2 of incoming) {
138294
+ const sameId = byId.get(p2.id);
138295
+ if (sameId) {
138296
+ if (sameId.path !== p2.path) plan.update.push(p2);
138297
+ continue;
138298
+ }
138299
+ const samePath = byPath.get(p2.path);
138300
+ if (samePath) {
138301
+ plan.conflict.push({ incoming: p2, existingId: samePath.id });
138302
+ continue;
138303
+ }
138304
+ plan.create.push(p2);
138305
+ }
138306
+ return plan;
138307
+ }
138308
+
138309
+ // src/version.ts
138310
+ var import_node_fs7 = require("fs");
138311
+ var import_node_path8 = require("path");
138312
+ var cached2;
138313
+ function getVersion() {
138314
+ if (cached2 !== void 0) return cached2;
138315
+ cached2 = resolveVersion();
138316
+ return cached2;
138317
+ }
138318
+ function resolveVersion() {
138319
+ const scriptPath = process.argv[1] ?? "";
138320
+ const here = scriptPath ? (0, import_node_path8.dirname)(scriptPath) : process.cwd();
138321
+ let realHere = here;
138322
+ try {
138323
+ realHere = (0, import_node_path8.dirname)((0, import_node_fs7.realpathSync)(scriptPath));
138324
+ } catch {
138325
+ }
138326
+ const searchDirs = realHere === here ? [here, (0, import_node_path8.join)(here, "..")] : [here, (0, import_node_path8.join)(here, ".."), realHere, (0, import_node_path8.join)(realHere, "..")];
138327
+ for (const dir of searchDirs) {
138328
+ try {
138329
+ const v2 = (0, import_node_fs7.readFileSync)((0, import_node_path8.join)(dir, "version.txt"), "utf8").trim();
138330
+ if (v2) return v2;
138331
+ } catch {
138332
+ }
138333
+ }
138334
+ try {
138335
+ const pkg = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path8.join)(here, "..", "package.json"), "utf8"));
138336
+ if (pkg.version) return `${pkg.version}+source`;
138337
+ } catch {
138338
+ }
138339
+ return "0.0.0+unknown";
138340
+ }
138341
+
138342
+ // src/api/routes/backup.routes.ts
138343
+ function readBody(c) {
138344
+ return new Promise((resolve4, reject) => {
138345
+ const chunks = [];
138346
+ c.env.incoming.on("data", (chunk) => chunks.push(chunk));
138347
+ c.env.incoming.on("end", () => {
138348
+ try {
138349
+ const raw2 = Buffer.concat(chunks).toString("utf-8");
138350
+ resolve4(raw2 ? JSON.parse(raw2) : {});
138351
+ } catch {
138352
+ reject(new Error("Invalid JSON body"));
138353
+ }
138354
+ });
138355
+ c.env.incoming.on("error", reject);
138356
+ });
138357
+ }
138358
+ var createBackupRoutes = (deps) => {
138359
+ const app = new Hono2();
138360
+ app.get("/export", (c) => {
138361
+ const repo = deps.projectsRepo();
138362
+ if (!repo) {
138363
+ return c.json({ error: "Project store is unavailable", code: "STORE_UNAVAILABLE" }, 503);
138364
+ }
138365
+ const projects = repo.listProjects().map((p2) => ({
138366
+ id: p2.id,
138367
+ path: p2.path,
138368
+ name: p2.name ?? null,
138369
+ createdAt: p2.createdAt,
138370
+ updatedAt: p2.updatedAt
138371
+ }));
138372
+ return c.json({
138373
+ manifest: {
138374
+ formatVersion: BACKUP_FORMAT_VERSION,
138375
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
138376
+ streamerVersion: getVersion(),
138377
+ sourceHost: (0, import_os5.hostname)(),
138378
+ // No endpoint here exports the API key. The flag is recorded so an
138379
+ // archive is self-describing about its own sensitivity rather than
138380
+ // requiring a reader to infer it.
138381
+ includesSecrets: false,
138382
+ counts: { projects: projects.length }
138383
+ },
138384
+ projects
138385
+ });
138386
+ });
138387
+ app.post("/restore", async (c) => {
138388
+ const repo = deps.projectsRepo();
138389
+ if (!repo) {
138390
+ return c.json({ error: "Project store is unavailable", code: "STORE_UNAVAILABLE" }, 503);
138391
+ }
138392
+ let body;
138393
+ try {
138394
+ body = await readBody(c);
138395
+ } catch {
138396
+ return c.json({ error: "Invalid JSON body", code: "INVALID_BODY" }, 400);
138397
+ }
138398
+ let archive;
138399
+ try {
138400
+ archive = validateArchive(body.archive);
138401
+ } catch (err) {
138402
+ if (err instanceof BackupError) {
138403
+ return c.json({ error: err.message, code: err.code }, 400);
138404
+ }
138405
+ throw err;
138406
+ }
138407
+ const rules = Array.isArray(body.pathMap) ? body.pathMap.filter((r) => typeof r?.from === "string" && typeof r?.to === "string").map((r) => ({ from: r.from, to: r.to })) : [];
138408
+ const incoming = rules.length > 0 ? remapPaths(archive.projects, rules) : archive.projects;
138409
+ const existing = repo.listProjects().map((p2) => ({ id: p2.id, path: p2.path }));
138410
+ const plan = planRestore(incoming, existing);
138411
+ const summary = {
138412
+ create: plan.create.length,
138413
+ update: plan.update.length,
138414
+ conflict: plan.conflict.length
138415
+ };
138416
+ if (body.apply !== true) {
138417
+ return c.json({ applied: false, summary, plan });
138418
+ }
138419
+ if (plan.conflict.length > 0) {
138420
+ return c.json(
138421
+ {
138422
+ error: "Restore has unresolved conflicts",
138423
+ code: "RESTORE_CONFLICT",
138424
+ summary,
138425
+ plan
138426
+ },
138427
+ 409
138428
+ );
138429
+ }
138430
+ let applied = 0;
138431
+ for (const p2 of [...plan.create, ...plan.update]) {
138432
+ try {
138433
+ repo.upsertProjectByPath(p2.path, { name: p2.name });
138434
+ applied++;
138435
+ } catch {
138436
+ }
138437
+ }
138438
+ return c.json({ applied: true, summary, appliedCount: applied });
138439
+ });
138440
+ return app;
138441
+ };
138442
+
138234
138443
  // src/api/routes/browse.routes.ts
138235
138444
  var ALREADY_HANDLED = 597;
138236
138445
  var alreadyHandled = () => new Response(null, { status: ALREADY_HANDLED });
@@ -138413,38 +138622,251 @@ var createDeviceRoutes = (deps) => {
138413
138622
  return app;
138414
138623
  };
138415
138624
 
138416
- // src/version.ts
138417
- var import_node_fs7 = require("fs");
138418
- var import_node_path8 = require("path");
138419
- var cached2;
138420
- function getVersion() {
138421
- if (cached2 !== void 0) return cached2;
138422
- cached2 = resolveVersion();
138423
- return cached2;
138424
- }
138425
- function resolveVersion() {
138426
- const scriptPath = process.argv[1] ?? "";
138427
- const here = scriptPath ? (0, import_node_path8.dirname)(scriptPath) : process.cwd();
138428
- let realHere = here;
138429
- try {
138430
- realHere = (0, import_node_path8.dirname)((0, import_node_fs7.realpathSync)(scriptPath));
138431
- } catch {
138625
+ // src/api/routes/diagnostics.routes.ts
138626
+ var import_fs14 = require("fs");
138627
+
138628
+ // src/platform.ts
138629
+ var import_child_process = require("child_process");
138630
+ var import_fs13 = require("fs");
138631
+ var import_os6 = require("os");
138632
+ var import_path13 = require("path");
138633
+ var isWindows2 = (0, import_os6.platform)() === "win32";
138634
+ var _claudeExe;
138635
+ function resolveClaudeExe() {
138636
+ if (_claudeExe !== void 0) return _claudeExe;
138637
+ if (isWindows2) {
138638
+ try {
138639
+ const found = (0, import_child_process.execFileSync)("where.exe", ["claude"], {
138640
+ encoding: "utf-8",
138641
+ windowsHide: true,
138642
+ timeout: 3e3
138643
+ }).trim().split("\n")[0].trim();
138644
+ if (found) {
138645
+ _claudeExe = found;
138646
+ return _claudeExe;
138647
+ }
138648
+ } catch {
138649
+ }
138650
+ const candidates = [
138651
+ (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "claude.exe"),
138652
+ (0, import_path13.join)(
138653
+ process.env.LOCALAPPDATA ?? (0, import_path13.join)((0, import_os6.homedir)(), "AppData", "Local"),
138654
+ "Microsoft",
138655
+ "WindowsApps",
138656
+ "claude.exe"
138657
+ )
138658
+ ];
138659
+ for (const p2 of candidates) {
138660
+ if ((0, import_fs13.existsSync)(p2)) {
138661
+ _claudeExe = p2;
138662
+ return _claudeExe;
138663
+ }
138664
+ }
138665
+ } else {
138666
+ try {
138667
+ const found = (0, import_child_process.execFileSync)("/usr/bin/which", ["claude"], {
138668
+ encoding: "utf-8",
138669
+ timeout: 3e3
138670
+ }).trim().split("\n")[0].trim();
138671
+ if (found && (0, import_fs13.existsSync)(found)) {
138672
+ _claudeExe = found;
138673
+ return _claudeExe;
138674
+ }
138675
+ } catch {
138676
+ }
138677
+ const candidates = [
138678
+ "/opt/homebrew/bin/claude",
138679
+ "/usr/local/bin/claude",
138680
+ (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "claude")
138681
+ ];
138682
+ for (const p2 of candidates) {
138683
+ if ((0, import_fs13.existsSync)(p2)) {
138684
+ _claudeExe = p2;
138685
+ return _claudeExe;
138686
+ }
138687
+ }
138432
138688
  }
138433
- const searchDirs = realHere === here ? [here, (0, import_node_path8.join)(here, "..")] : [here, (0, import_node_path8.join)(here, ".."), realHere, (0, import_node_path8.join)(realHere, "..")];
138434
- for (const dir of searchDirs) {
138689
+ _claudeExe = "claude";
138690
+ return _claudeExe;
138691
+ }
138692
+ var _codexExe;
138693
+ function resolveCodexExe() {
138694
+ if (_codexExe !== void 0) return _codexExe;
138695
+ if (isWindows2) {
138435
138696
  try {
138436
- const v2 = (0, import_node_fs7.readFileSync)((0, import_node_path8.join)(dir, "version.txt"), "utf8").trim();
138437
- if (v2) return v2;
138697
+ const found = (0, import_child_process.execFileSync)("where.exe", ["codex"], {
138698
+ encoding: "utf-8",
138699
+ windowsHide: true,
138700
+ timeout: 3e3
138701
+ }).trim().split("\n")[0].trim();
138702
+ if (found) {
138703
+ _codexExe = found;
138704
+ return _codexExe;
138705
+ }
138706
+ } catch {
138707
+ }
138708
+ const candidates = [
138709
+ (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "codex.exe"),
138710
+ (0, import_path13.join)(
138711
+ process.env.LOCALAPPDATA ?? (0, import_path13.join)((0, import_os6.homedir)(), "AppData", "Local"),
138712
+ "Microsoft",
138713
+ "WindowsApps",
138714
+ "codex.exe"
138715
+ )
138716
+ ];
138717
+ for (const p2 of candidates) {
138718
+ if ((0, import_fs13.existsSync)(p2)) {
138719
+ _codexExe = p2;
138720
+ return _codexExe;
138721
+ }
138722
+ }
138723
+ } else {
138724
+ try {
138725
+ const found = (0, import_child_process.execFileSync)("/usr/bin/which", ["codex"], {
138726
+ encoding: "utf-8",
138727
+ timeout: 3e3
138728
+ }).trim().split("\n")[0].trim();
138729
+ if (found && (0, import_fs13.existsSync)(found)) {
138730
+ _codexExe = found;
138731
+ return _codexExe;
138732
+ }
138438
138733
  } catch {
138439
138734
  }
138735
+ const candidates = [
138736
+ "/opt/homebrew/bin/codex",
138737
+ "/usr/local/bin/codex",
138738
+ (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "codex")
138739
+ ];
138740
+ for (const p2 of candidates) {
138741
+ if ((0, import_fs13.existsSync)(p2)) {
138742
+ _codexExe = p2;
138743
+ return _codexExe;
138744
+ }
138745
+ }
138440
138746
  }
138747
+ _codexExe = "codex";
138748
+ return _codexExe;
138749
+ }
138750
+
138751
+ // src/services/diagnostics/diagnostics.ts
138752
+ var DIAGNOSTICS_CONTRACT_VERSION = 1;
138753
+ function redactPath(path2) {
138754
+ if (!path2) return null;
138755
+ const parts = path2.split(/[/\\]/).filter(Boolean);
138756
+ if (parts.length <= 2) return parts.join("/");
138757
+ return `\u2026/${parts.slice(-2).join("/")}`;
138758
+ }
138759
+ function worstStatus(checks) {
138760
+ const rank = { ok: 0, unknown: 1, degraded: 2, failed: 3 };
138761
+ return checks.reduce(
138762
+ (worst, c) => rank[c.status] > rank[worst] ? c.status : worst,
138763
+ "ok"
138764
+ );
138765
+ }
138766
+ function buildReport(checks, now = /* @__PURE__ */ new Date()) {
138767
+ return {
138768
+ contractVersion: DIAGNOSTICS_CONTRACT_VERSION,
138769
+ generatedAt: now.toISOString(),
138770
+ overall: worstStatus(checks),
138771
+ checks
138772
+ };
138773
+ }
138774
+ var SECRET_KEY_RE = /(key|token|secret|password|passwd|credential|authorization|cookie)/i;
138775
+ function redactValue(value) {
138776
+ if (Array.isArray(value)) {
138777
+ return value.map((v2) => redactValue(v2));
138778
+ }
138779
+ if (value && typeof value === "object") {
138780
+ const out = {};
138781
+ for (const [k2, v2] of Object.entries(value)) {
138782
+ out[k2] = SECRET_KEY_RE.test(k2) ? "[redacted]" : redactValue(v2);
138783
+ }
138784
+ return out;
138785
+ }
138786
+ return value;
138787
+ }
138788
+
138789
+ // src/api/routes/diagnostics.routes.ts
138790
+ function providerCheck(name, resolve4) {
138441
138791
  try {
138442
- const pkg = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path8.join)(here, "..", "package.json"), "utf8"));
138443
- if (pkg.version) return `${pkg.version}+source`;
138792
+ const exe = resolve4();
138793
+ return {
138794
+ id: `provider:${name}`,
138795
+ status: "ok",
138796
+ summary: `${name} CLI is installed.`,
138797
+ remediation: "NONE",
138798
+ detail: { location: redactPath(exe) }
138799
+ };
138444
138800
  } catch {
138801
+ return {
138802
+ id: `provider:${name}`,
138803
+ status: "failed",
138804
+ summary: `${name} CLI could not be located. Sessions for this provider cannot start.`,
138805
+ remediation: "PROVIDER_NOT_INSTALLED"
138806
+ };
138445
138807
  }
138446
- return "0.0.0+unknown";
138447
138808
  }
138809
+ var createDiagnosticsRoutes = (deps) => {
138810
+ const app = new Hono2();
138811
+ app.get("/", (c) => {
138812
+ const checks = [];
138813
+ checks.push({
138814
+ id: "streamer",
138815
+ status: "ok",
138816
+ summary: "Streamer is running.",
138817
+ remediation: "NONE",
138818
+ detail: { version: getVersion(), uptimeSeconds: Math.floor(process.uptime()) }
138819
+ });
138820
+ checks.push(providerCheck("claude-code", resolveClaudeExe));
138821
+ checks.push(providerCheck("codex-cli", resolveCodexExe));
138822
+ const cacheAlert = deps.cacheMonitor()?.healthzField();
138823
+ checks.push(
138824
+ cacheAlert ? {
138825
+ id: "cache",
138826
+ status: "degraded",
138827
+ summary: "Conversation cache reported an integrity alert.",
138828
+ remediation: "CACHE_DEGRADED"
138829
+ } : {
138830
+ id: "cache",
138831
+ status: "ok",
138832
+ summary: "Conversation cache is healthy.",
138833
+ remediation: "NONE"
138834
+ }
138835
+ );
138836
+ let ptyOk = true;
138837
+ try {
138838
+ require.resolve("node-pty");
138839
+ } catch {
138840
+ ptyOk = false;
138841
+ }
138842
+ checks.push(
138843
+ ptyOk ? { id: "pty", status: "ok", summary: "PTY subsystem is available.", remediation: "NONE" } : {
138844
+ id: "pty",
138845
+ status: "failed",
138846
+ summary: "node-pty failed to load, so no managed session can start.",
138847
+ remediation: "PTY_UNAVAILABLE"
138848
+ }
138849
+ );
138850
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
138851
+ const claudeProjects = home ? `${home}/.claude/projects` : "";
138852
+ checks.push(
138853
+ claudeProjects && (0, import_fs14.existsSync)(claudeProjects) ? {
138854
+ id: "filesystem",
138855
+ status: "ok",
138856
+ summary: "Provider history directory is present.",
138857
+ remediation: "NONE",
138858
+ detail: { location: redactPath(claudeProjects) }
138859
+ } : {
138860
+ id: "filesystem",
138861
+ status: "degraded",
138862
+ summary: "Provider history directory was not found; history may be unavailable.",
138863
+ remediation: "FS_SCOPE_MISSING"
138864
+ }
138865
+ );
138866
+ return c.json(redactValue(buildReport(checks)));
138867
+ });
138868
+ return app;
138869
+ };
138448
138870
 
138449
138871
  // src/api/routes/health.routes.ts
138450
138872
  var createHealthRoutes = (deps) => {
@@ -138579,7 +139001,7 @@ function createLogsRoutes() {
138579
139001
  // src/api/routes/misc.routes.ts
138580
139002
  var import_node_child_process2 = require("child_process");
138581
139003
  var import_node_crypto = require("crypto");
138582
- var import_os5 = require("os");
139004
+ var import_os7 = require("os");
138583
139005
 
138584
139006
  // src/db/repositories/push.repository.ts
138585
139007
  var FAILURE_STREAK_LIMIT = 5;
@@ -138879,7 +139301,7 @@ var createMiscRoutes = (deps) => {
138879
139301
  const ptyIds = deps.ptyAttachedIds();
138880
139302
  return c.json({
138881
139303
  version: getVersion(),
138882
- machineName: (0, import_os5.hostname)(),
139304
+ machineName: (0, import_os7.hostname)(),
138883
139305
  platform: process.platform,
138884
139306
  activeSessions: deps.sessionStore.list(ptyIds).filter((s3) => s3.status === "running").length,
138885
139307
  publicUrl: deps.publicUrl,
@@ -139168,129 +139590,6 @@ var createProjectRoutes = (deps) => {
139168
139590
  return app;
139169
139591
  };
139170
139592
 
139171
- // src/platform.ts
139172
- var import_child_process = require("child_process");
139173
- var import_fs13 = require("fs");
139174
- var import_os6 = require("os");
139175
- var import_path13 = require("path");
139176
- var isWindows2 = (0, import_os6.platform)() === "win32";
139177
- var _claudeExe;
139178
- function resolveClaudeExe() {
139179
- if (_claudeExe !== void 0) return _claudeExe;
139180
- if (isWindows2) {
139181
- try {
139182
- const found = (0, import_child_process.execFileSync)("where.exe", ["claude"], {
139183
- encoding: "utf-8",
139184
- windowsHide: true,
139185
- timeout: 3e3
139186
- }).trim().split("\n")[0].trim();
139187
- if (found) {
139188
- _claudeExe = found;
139189
- return _claudeExe;
139190
- }
139191
- } catch {
139192
- }
139193
- const candidates = [
139194
- (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "claude.exe"),
139195
- (0, import_path13.join)(
139196
- process.env.LOCALAPPDATA ?? (0, import_path13.join)((0, import_os6.homedir)(), "AppData", "Local"),
139197
- "Microsoft",
139198
- "WindowsApps",
139199
- "claude.exe"
139200
- )
139201
- ];
139202
- for (const p2 of candidates) {
139203
- if ((0, import_fs13.existsSync)(p2)) {
139204
- _claudeExe = p2;
139205
- return _claudeExe;
139206
- }
139207
- }
139208
- } else {
139209
- try {
139210
- const found = (0, import_child_process.execFileSync)("/usr/bin/which", ["claude"], {
139211
- encoding: "utf-8",
139212
- timeout: 3e3
139213
- }).trim().split("\n")[0].trim();
139214
- if (found && (0, import_fs13.existsSync)(found)) {
139215
- _claudeExe = found;
139216
- return _claudeExe;
139217
- }
139218
- } catch {
139219
- }
139220
- const candidates = [
139221
- "/opt/homebrew/bin/claude",
139222
- "/usr/local/bin/claude",
139223
- (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "claude")
139224
- ];
139225
- for (const p2 of candidates) {
139226
- if ((0, import_fs13.existsSync)(p2)) {
139227
- _claudeExe = p2;
139228
- return _claudeExe;
139229
- }
139230
- }
139231
- }
139232
- _claudeExe = "claude";
139233
- return _claudeExe;
139234
- }
139235
- var _codexExe;
139236
- function resolveCodexExe() {
139237
- if (_codexExe !== void 0) return _codexExe;
139238
- if (isWindows2) {
139239
- try {
139240
- const found = (0, import_child_process.execFileSync)("where.exe", ["codex"], {
139241
- encoding: "utf-8",
139242
- windowsHide: true,
139243
- timeout: 3e3
139244
- }).trim().split("\n")[0].trim();
139245
- if (found) {
139246
- _codexExe = found;
139247
- return _codexExe;
139248
- }
139249
- } catch {
139250
- }
139251
- const candidates = [
139252
- (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "codex.exe"),
139253
- (0, import_path13.join)(
139254
- process.env.LOCALAPPDATA ?? (0, import_path13.join)((0, import_os6.homedir)(), "AppData", "Local"),
139255
- "Microsoft",
139256
- "WindowsApps",
139257
- "codex.exe"
139258
- )
139259
- ];
139260
- for (const p2 of candidates) {
139261
- if ((0, import_fs13.existsSync)(p2)) {
139262
- _codexExe = p2;
139263
- return _codexExe;
139264
- }
139265
- }
139266
- } else {
139267
- try {
139268
- const found = (0, import_child_process.execFileSync)("/usr/bin/which", ["codex"], {
139269
- encoding: "utf-8",
139270
- timeout: 3e3
139271
- }).trim().split("\n")[0].trim();
139272
- if (found && (0, import_fs13.existsSync)(found)) {
139273
- _codexExe = found;
139274
- return _codexExe;
139275
- }
139276
- } catch {
139277
- }
139278
- const candidates = [
139279
- "/opt/homebrew/bin/codex",
139280
- "/usr/local/bin/codex",
139281
- (0, import_path13.join)((0, import_os6.homedir)(), ".local", "bin", "codex")
139282
- ];
139283
- for (const p2 of candidates) {
139284
- if ((0, import_fs13.existsSync)(p2)) {
139285
- _codexExe = p2;
139286
- return _codexExe;
139287
- }
139288
- }
139289
- }
139290
- _codexExe = "codex";
139291
- return _codexExe;
139292
- }
139293
-
139294
139593
  // src/providers.ts
139295
139594
  var CLAUDE_CODE_PROVIDER2 = "claude-code";
139296
139595
  var CODEX_CLI_PROVIDER2 = "codex-cli";
@@ -139576,6 +139875,7 @@ var createHonoApp = (deps, upgradeWebSocket) => {
139576
139875
  app.use("*", authMiddleware(deps));
139577
139876
  app.onError(errorMiddleware);
139578
139877
  app.route("/healthz", createHealthRoutes(deps));
139878
+ app.route("/api/diagnostics", createDiagnosticsRoutes(deps));
139579
139879
  app.route("/", createMiscRoutes(deps));
139580
139880
  app.route("/api/sessions", createSessionRoutes(deps));
139581
139881
  app.route("/api/conversations", createConversationRoutes(deps));
@@ -139584,6 +139884,7 @@ var createHonoApp = (deps, upgradeWebSocket) => {
139584
139884
  app.route("/api/projects", createProjectRoutes(deps));
139585
139885
  app.route("/api/providers", createProviderRoutes());
139586
139886
  app.route("/api/devices", createDeviceRoutes(deps));
139887
+ app.route("/api/backup", createBackupRoutes(deps));
139587
139888
  app.route("/api/pair", createPairRoutes(deps));
139588
139889
  app.route("/api", createBrowseRoutes(deps));
139589
139890
  app.route("/", createScannerRoutes(deps));
@@ -139654,13 +139955,13 @@ init_claude_flags();
139654
139955
 
139655
139956
  // src/conversation-cache.ts
139656
139957
  var import_better_sqlite32 = __toESM(require("better-sqlite3"), 1);
139657
- var import_fs16 = require("fs");
139958
+ var import_fs17 = require("fs");
139658
139959
  var import_promises12 = require("fs/promises");
139659
139960
  var import_path17 = require("path");
139660
139961
  var import_promises13 = require("timers/promises");
139661
139962
 
139662
139963
  // src/db/sqlite-migrate.ts
139663
- var import_fs14 = require("fs");
139964
+ var import_fs15 = require("fs");
139664
139965
  var import_path15 = require("path");
139665
139966
  var import_url6 = require("url");
139666
139967
  var import_meta2 = {};
@@ -139679,7 +139980,7 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
139679
139980
  function runSqliteMigrations(db, migrationsDir) {
139680
139981
  db.exec(SCHEMA_MIGRATIONS_SQL);
139681
139982
  const dir = migrationsDir ?? (0, import_path15.join)(getMigrationsDir(), "migrations");
139682
- const files = (0, import_fs14.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
139983
+ const files = (0, import_fs15.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
139683
139984
  const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
139684
139985
  const appliedSet = new Set(appliedRows.map((r) => r.id));
139685
139986
  const recordApplied = db.prepare("INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)");
@@ -139690,7 +139991,7 @@ function runSqliteMigrations(db, migrationsDir) {
139690
139991
  skipped.push(file2);
139691
139992
  continue;
139692
139993
  }
139693
- const sql = (0, import_fs14.readFileSync)((0, import_path15.join)(dir, file2), "utf-8");
139994
+ const sql = (0, import_fs15.readFileSync)((0, import_path15.join)(dir, file2), "utf-8");
139694
139995
  const tx = db.transaction(() => {
139695
139996
  db.exec(sql);
139696
139997
  recordApplied.run(file2, (/* @__PURE__ */ new Date()).toISOString());
@@ -139702,7 +140003,7 @@ function runSqliteMigrations(db, migrationsDir) {
139702
140003
  }
139703
140004
 
139704
140005
  // src/services/conversations/isAgentConversation.ts
139705
- var import_fs15 = require("fs");
140006
+ var import_fs16 = require("fs");
139706
140007
  var DEFAULT_AGENT_ENTRYPOINTS = /* @__PURE__ */ new Set(["sdk-cli", "claude-vscode"]);
139707
140008
  var CHUNK_BYTES = 64 * 1024;
139708
140009
  var ENTRYPOINT_PROBE = `"entrypoint":`;
@@ -139724,12 +140025,12 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
139724
140025
  if (cached3 !== void 0) return cached3;
139725
140026
  let fd;
139726
140027
  try {
139727
- fd = (0, import_fs15.openSync)(filePath, "r");
140028
+ fd = (0, import_fs16.openSync)(filePath, "r");
139728
140029
  } catch {
139729
140030
  return false;
139730
140031
  }
139731
140032
  try {
139732
- const fileSize = (0, import_fs15.statSync)(filePath).size;
140033
+ const fileSize = (0, import_fs16.statSync)(filePath).size;
139733
140034
  if (fileSize === 0) {
139734
140035
  fileDecisionCache.set(key, false);
139735
140036
  return false;
@@ -139740,7 +140041,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
139740
140041
  let carry = "";
139741
140042
  while (offset < fileSize) {
139742
140043
  const toRead = Math.min(CHUNK_BYTES, fileSize - offset);
139743
- const got = (0, import_fs15.readSync)(fd, buf, 0, toRead, offset);
140044
+ const got = (0, import_fs16.readSync)(fd, buf, 0, toRead, offset);
139744
140045
  if (got <= 0) break;
139745
140046
  const chunk = carry + buf.toString("utf8", 0, got);
139746
140047
  for (const marker of markers) {
@@ -139761,7 +140062,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
139761
140062
  } catch {
139762
140063
  return false;
139763
140064
  } finally {
139764
- (0, import_fs15.closeSync)(fd);
140065
+ (0, import_fs16.closeSync)(fd);
139765
140066
  }
139766
140067
  }
139767
140068
  function parseAgentEntrypointsEnv(raw2) {
@@ -140336,7 +140637,7 @@ var ConversationCache = class _ConversationCache {
140336
140637
  if (!fileState) return null;
140337
140638
  let stat7;
140338
140639
  try {
140339
- stat7 = (0, import_fs16.statSync)(filePath);
140640
+ stat7 = (0, import_fs17.statSync)(filePath);
140340
140641
  } catch {
140341
140642
  return null;
140342
140643
  }
@@ -140357,17 +140658,17 @@ var ConversationCache = class _ConversationCache {
140357
140658
  );
140358
140659
  if (rows.length === 0) return { messages: [], total, fromIndex: from };
140359
140660
  const messages = [];
140360
- const fd = (0, import_fs16.openSync)(filePath, "r");
140661
+ const fd = (0, import_fs17.openSync)(filePath, "r");
140361
140662
  try {
140362
140663
  const state = initialConvState();
140363
140664
  for (const row of rows) {
140364
140665
  const buf = Buffer.alloc(row.byte_length);
140365
- (0, import_fs16.readSync)(fd, buf, 0, row.byte_length, row.byte_offset);
140666
+ (0, import_fs17.readSync)(fd, buf, 0, row.byte_length, row.byte_offset);
140366
140667
  const msg = parseJsonlLine(buf.toString("utf-8"), state);
140367
140668
  if (msg) messages.push(msg);
140368
140669
  }
140369
140670
  } finally {
140370
- (0, import_fs16.closeSync)(fd);
140671
+ (0, import_fs17.closeSync)(fd);
140371
140672
  }
140372
140673
  return { messages, total, fromIndex: from };
140373
140674
  }
@@ -140395,14 +140696,14 @@ var ConversationCache = class _ConversationCache {
140395
140696
  isAgentFileCached(filePath) {
140396
140697
  let s3;
140397
140698
  try {
140398
- s3 = (0, import_fs16.statSync)(filePath);
140699
+ s3 = (0, import_fs17.statSync)(filePath);
140399
140700
  } catch {
140400
140701
  return false;
140401
140702
  }
140402
140703
  return this.classifyAgentFile(filePath, s3.mtimeMs, s3.size);
140403
140704
  }
140404
140705
  static open(dbPath, tailSize = 10, migrationsDir, options) {
140405
- (0, import_fs16.mkdirSync)((0, import_path17.dirname)(dbPath), { recursive: true });
140706
+ (0, import_fs17.mkdirSync)((0, import_path17.dirname)(dbPath), { recursive: true });
140406
140707
  const db = new import_better_sqlite32.default(dbPath);
140407
140708
  db.pragma("journal_mode = WAL");
140408
140709
  db.pragma("foreign_keys = ON");
@@ -140589,7 +140890,7 @@ var ConversationCache = class _ConversationCache {
140589
140890
  let mtimeMs = null;
140590
140891
  let fileSize = null;
140591
140892
  try {
140592
- const s3 = (0, import_fs16.statSync)(m2.filePath);
140893
+ const s3 = (0, import_fs17.statSync)(m2.filePath);
140593
140894
  mtimeMs = s3.mtimeMs;
140594
140895
  fileSize = s3.size;
140595
140896
  } catch {
@@ -140649,8 +140950,8 @@ var ConversationCache = class _ConversationCache {
140649
140950
  let fileSize;
140650
140951
  let fd;
140651
140952
  try {
140652
- fileSize = (0, import_fs16.statSync)(filePath).size;
140653
- fd = (0, import_fs16.openSync)(filePath, "r");
140953
+ fileSize = (0, import_fs17.statSync)(filePath).size;
140954
+ fd = (0, import_fs17.openSync)(filePath, "r");
140654
140955
  } catch {
140655
140956
  return false;
140656
140957
  }
@@ -140663,7 +140964,7 @@ var ConversationCache = class _ConversationCache {
140663
140964
  while (pos > 0 && lines.length < this.tailSize * 4) {
140664
140965
  const toRead = Math.min(CHUNK, pos);
140665
140966
  pos -= toRead;
140666
- (0, import_fs16.readSync)(fd, buf, 0, toRead, pos);
140967
+ (0, import_fs17.readSync)(fd, buf, 0, toRead, pos);
140667
140968
  const chunk = buf.subarray(0, toRead).toString("utf8");
140668
140969
  const combined = chunk + partial2;
140669
140970
  const parts = combined.split("\n");
@@ -140674,7 +140975,7 @@ var ConversationCache = class _ConversationCache {
140674
140975
  }
140675
140976
  if (partial2) lines.push(partial2);
140676
140977
  } finally {
140677
- (0, import_fs16.closeSync)(fd);
140978
+ (0, import_fs17.closeSync)(fd);
140678
140979
  }
140679
140980
  const msgs = [];
140680
140981
  for (let i = 0; i < lines.length && msgs.length < this.tailSize; i++) {
@@ -140887,7 +141188,7 @@ var ConversationCache = class _ConversationCache {
140887
141188
  * `handleGetConversation` can still serve the cached tail even when the
140888
141189
  * JSONL has been deleted.
140889
141190
  */
140890
- pruneGhostFiles(exists = import_fs16.existsSync) {
141191
+ pruneGhostFiles(exists = import_fs17.existsSync) {
140891
141192
  const rows = this.stmts.allFilePaths.all();
140892
141193
  const ghosts = [];
140893
141194
  const prune = this.db.transaction((ids) => {
@@ -140942,7 +141243,7 @@ var ConversationCache = class _ConversationCache {
140942
141243
  * Returns the removed IDs.
140943
141244
  */
140944
141245
  reconcileDeletions(livePaths, opts) {
140945
- const exists = opts?.exists ?? import_fs16.existsSync;
141246
+ const exists = opts?.exists ?? import_fs17.existsSync;
140946
141247
  const rows = this.stmts.allFilePaths.all();
140947
141248
  const removed = [];
140948
141249
  const drop = this.db.transaction((ids) => {
@@ -140977,7 +141278,7 @@ var ConversationCache = class _ConversationCache {
140977
141278
  * reports drift for the CacheIntegrityMonitor to classify. `tailed` flags
140978
141279
  * rows that still have cached history (which pruneGhostFiles would keep).
140979
141280
  */
140980
- listMissingFiles(exists = import_fs16.existsSync) {
141281
+ listMissingFiles(exists = import_fs17.existsSync) {
140981
141282
  const rows = this.stmts.allFilePathsWithTitle.all();
140982
141283
  const missing = [];
140983
141284
  for (const row of rows) {
@@ -141062,7 +141363,7 @@ function getDbConfig() {
141062
141363
  }
141063
141364
 
141064
141365
  // src/db/migrations.ts
141065
- var import_fs17 = require("fs");
141366
+ var import_fs18 = require("fs");
141066
141367
  var import_path18 = require("path");
141067
141368
  var import_url7 = require("url");
141068
141369
  var import_meta3 = {};
@@ -141085,10 +141386,10 @@ async function runMigrations2(pool2, migrationsDir) {
141085
141386
  );
141086
141387
  const appliedSet = new Set(applied.map((r) => r.name));
141087
141388
  const dir = migrationsDir ?? (0, import_path18.join)(getMigrationsDir2(), "pg-migrations");
141088
- const files = (0, import_fs17.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
141389
+ const files = (0, import_fs18.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
141089
141390
  for (const file2 of files) {
141090
141391
  if (appliedSet.has(file2)) continue;
141091
- const sql = (0, import_fs17.readFileSync)((0, import_path18.join)(dir, file2), "utf-8");
141392
+ const sql = (0, import_fs18.readFileSync)((0, import_path18.join)(dir, file2), "utf-8");
141092
141393
  await pool2.query(sql);
141093
141394
  await pool2.query("INSERT INTO _migrations (name) VALUES ($1)", [file2]);
141094
141395
  }
@@ -141440,8 +141741,8 @@ async function recordUpload(pool2, instanceId, row) {
141440
141741
  init_feature_flags();
141441
141742
 
141442
141743
  // src/handlers/handleListProjects.ts
141443
- var import_fs18 = require("fs");
141444
- var import_os7 = require("os");
141744
+ var import_fs19 = require("fs");
141745
+ var import_os8 = require("os");
141445
141746
  var import_path19 = require("path");
141446
141747
  function decodeProjectPath(dirName) {
141447
141748
  return dirName.replace(/-/g, "/");
@@ -141449,14 +141750,14 @@ function decodeProjectPath(dirName) {
141449
141750
  function handleListProjects(url2, res) {
141450
141751
  const limit = Math.max(1, parseInt(url2.searchParams.get("limit") ?? "50", 10) || 50);
141451
141752
  const offset = Math.max(0, parseInt(url2.searchParams.get("offset") ?? "0", 10) || 0);
141452
- const projectsDir = (0, import_path19.join)((0, import_os7.homedir)(), ".claude", "projects");
141753
+ const projectsDir = (0, import_path19.join)((0, import_os8.homedir)(), ".claude", "projects");
141453
141754
  let entries;
141454
141755
  try {
141455
- entries = (0, import_fs18.readdirSync)(projectsDir).map((dirName) => {
141756
+ entries = (0, import_fs19.readdirSync)(projectsDir).map((dirName) => {
141456
141757
  const fullPath = (0, import_path19.join)(projectsDir, dirName);
141457
141758
  let mtime = 0;
141458
141759
  try {
141459
- mtime = (0, import_fs18.statSync)(fullPath).mtimeMs;
141760
+ mtime = (0, import_fs19.statSync)(fullPath).mtimeMs;
141460
141761
  } catch {
141461
141762
  }
141462
141763
  const path2 = decodeProjectPath(dirName);
@@ -141492,21 +141793,21 @@ var import_path23 = require("path");
141492
141793
  // src/codex-pty-runner.ts
141493
141794
  var import_headless = __toESM(require_xterm_headless(), 1);
141494
141795
  var import_crypto8 = require("crypto");
141495
- var import_fs20 = require("fs");
141796
+ var import_fs21 = require("fs");
141496
141797
  var import_path21 = require("path");
141497
141798
  init_logger();
141498
141799
 
141499
141800
  // src/services/questions/codexGateAnswers.ts
141500
- var import_fs19 = require("fs");
141501
- var import_os8 = require("os");
141801
+ var import_fs20 = require("fs");
141802
+ var import_os9 = require("os");
141502
141803
  var import_path20 = require("path");
141503
141804
  function gateAnswersPath() {
141504
- const dir = process.env.THREADBASE_CONFIG_DIR ?? (0, import_path20.join)((0, import_os8.homedir)(), ".threadbase");
141805
+ const dir = process.env.THREADBASE_CONFIG_DIR ?? (0, import_path20.join)((0, import_os9.homedir)(), ".threadbase");
141505
141806
  return (0, import_path20.join)(dir, "gate-answers.json");
141506
141807
  }
141507
141808
  function loadGateAnswers() {
141508
141809
  try {
141509
- const parsed = JSON.parse((0, import_fs19.readFileSync)(gateAnswersPath(), "utf-8"));
141810
+ const parsed = JSON.parse((0, import_fs20.readFileSync)(gateAnswersPath(), "utf-8"));
141510
141811
  return parsed && typeof parsed === "object" ? parsed : {};
141511
141812
  } catch {
141512
141813
  return {};
@@ -141514,8 +141815,8 @@ function loadGateAnswers() {
141514
141815
  }
141515
141816
  function saveGateAnswer(key, value) {
141516
141817
  const path2 = gateAnswersPath();
141517
- (0, import_fs19.mkdirSync)((0, import_path20.dirname)(path2), { recursive: true });
141518
- (0, import_fs19.writeFileSync)(path2, `${JSON.stringify({ ...loadGateAnswers(), [key]: value }, null, 2)}
141818
+ (0, import_fs20.mkdirSync)((0, import_path20.dirname)(path2), { recursive: true });
141819
+ (0, import_fs20.writeFileSync)(path2, `${JSON.stringify({ ...loadGateAnswers(), [key]: value }, null, 2)}
141519
141820
  `);
141520
141821
  }
141521
141822
  function rememberedGateDigit(gate) {
@@ -142191,7 +142492,7 @@ var CodexPtyRunner = class {
142191
142492
  session.statusUpdatedAt = /* @__PURE__ */ new Date();
142192
142493
  const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
142193
142494
  if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
142194
- if (!(0, import_fs20.existsSync)(session.projectPath)) {
142495
+ if (!(0, import_fs21.existsSync)(session.projectPath)) {
142195
142496
  session.failureReason = `Project directory not found: ${session.projectPath}`;
142196
142497
  } else {
142197
142498
  session.failureReason = `Codex process exited immediately (code ${exitCode}).`;
@@ -142230,7 +142531,7 @@ function stripAnsi(str) {
142230
142531
  // src/pty-manager.ts
142231
142532
  var import_headless2 = __toESM(require_xterm_headless(), 1);
142232
142533
  var import_crypto9 = require("crypto");
142233
- var import_fs21 = require("fs");
142534
+ var import_fs22 = require("fs");
142234
142535
  var import_path22 = require("path");
142235
142536
  init_claude_flags();
142236
142537
  init_logger();
@@ -143142,7 +143443,7 @@ var PTYManager = class {
143142
143443
  session.statusUpdatedAt = /* @__PURE__ */ new Date();
143143
143444
  const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
143144
143445
  if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
143145
- if (!(0, import_fs21.existsSync)(session.projectPath)) {
143446
+ if (!(0, import_fs22.existsSync)(session.projectPath)) {
143146
143447
  session.failureReason = `Project directory not found: ${session.projectPath}`;
143147
143448
  } else {
143148
143449
  session.failureReason = `Process exited immediately (code ${exitCode}). Check that the Claude binary is installed and accessible.`;
@@ -143351,10 +143652,10 @@ var PairTokenStore = class {
143351
143652
 
143352
143653
  // src/process-discovery.ts
143353
143654
  var import_child_process3 = require("child_process");
143354
- var import_os9 = require("os");
143655
+ var import_os10 = require("os");
143355
143656
  var import_path24 = require("path");
143356
143657
  async function discoverClaudeProcesses() {
143357
- if ((0, import_os9.platform)() === "win32") return discoverWindows();
143658
+ if ((0, import_os10.platform)() === "win32") return discoverWindows();
143358
143659
  return discoverUnix();
143359
143660
  }
143360
143661
  var CLAUDE_CLI_SCRIPT = /claude-code[\\/](?:cli|index)\.(?:js|mjs|cjs)$/i;
@@ -143494,7 +143795,7 @@ async function getProcessArgsUnix(pid) {
143494
143795
  async function getProcessArgs(pid) {
143495
143796
  if (!Number.isInteger(pid) || pid < 1) return "";
143496
143797
  try {
143497
- if ((0, import_os9.platform)() === "win32") {
143798
+ if ((0, import_os10.platform)() === "win32") {
143498
143799
  const info = await getProcessInfoWindows(pid);
143499
143800
  return info?.args ?? "";
143500
143801
  }
@@ -143645,19 +143946,19 @@ function setCacheMetadata(repo, key, value) {
143645
143946
 
143646
143947
  // src/services/cache-integrity/cacheIntegrityMonitor.ts
143647
143948
  var import_crypto11 = require("crypto");
143648
- var import_fs24 = require("fs");
143949
+ var import_fs25 = require("fs");
143649
143950
 
143650
143951
  // src/services/cache-integrity/alertStore.ts
143651
- var import_fs22 = require("fs");
143652
- var import_os10 = require("os");
143952
+ var import_fs23 = require("fs");
143953
+ var import_os11 = require("os");
143653
143954
  var import_path25 = require("path");
143654
143955
  function alertStatePath() {
143655
- const dir = process.env.THREADBASE_CONFIG_DIR ?? (0, import_path25.join)((0, import_os10.homedir)(), ".threadbase");
143956
+ const dir = process.env.THREADBASE_CONFIG_DIR ?? (0, import_path25.join)((0, import_os11.homedir)(), ".threadbase");
143656
143957
  return (0, import_path25.join)(dir, "cache-alert.json");
143657
143958
  }
143658
143959
  function loadAlertState() {
143659
143960
  try {
143660
- const parsed = JSON.parse((0, import_fs22.readFileSync)(alertStatePath(), "utf-8"));
143961
+ const parsed = JSON.parse((0, import_fs23.readFileSync)(alertStatePath(), "utf-8"));
143661
143962
  return parsed && typeof parsed === "object" ? parsed : {};
143662
143963
  } catch {
143663
143964
  return {};
@@ -143665,13 +143966,13 @@ function loadAlertState() {
143665
143966
  }
143666
143967
  function saveAlertState(state) {
143667
143968
  const path2 = alertStatePath();
143668
- (0, import_fs22.mkdirSync)((0, import_path25.dirname)(path2), { recursive: true });
143669
- (0, import_fs22.writeFileSync)(path2, `${JSON.stringify(state, null, 2)}
143969
+ (0, import_fs23.mkdirSync)((0, import_path25.dirname)(path2), { recursive: true });
143970
+ (0, import_fs23.writeFileSync)(path2, `${JSON.stringify(state, null, 2)}
143670
143971
  `);
143671
143972
  }
143672
143973
 
143673
143974
  // src/services/cache-integrity/backup.ts
143674
- var import_fs23 = require("fs");
143975
+ var import_fs24 = require("fs");
143675
143976
  var import_path26 = require("path");
143676
143977
  var DEFAULT_RETAIN = 3;
143677
143978
  function retainCount() {
@@ -143684,16 +143985,16 @@ function timestamp(d) {
143684
143985
  }
143685
143986
  async function backupCacheDb(db, cacheDir) {
143686
143987
  const backupsDir = (0, import_path26.join)(cacheDir, "backups");
143687
- (0, import_fs23.mkdirSync)(backupsDir, { recursive: true });
143988
+ (0, import_fs24.mkdirSync)(backupsDir, { recursive: true });
143688
143989
  const destPath = (0, import_path26.join)(backupsDir, `cache-${timestamp(/* @__PURE__ */ new Date())}.db`);
143689
143990
  await db.backup(destPath);
143690
143991
  const retain = retainCount();
143691
- const backups = (0, import_fs23.readdirSync)(backupsDir).filter((f2) => f2.startsWith("cache-") && f2.endsWith(".db")).map((f2) => {
143992
+ const backups = (0, import_fs24.readdirSync)(backupsDir).filter((f2) => f2.startsWith("cache-") && f2.endsWith(".db")).map((f2) => {
143692
143993
  const full = (0, import_path26.join)(backupsDir, f2);
143693
- return { full, mtime: (0, import_fs23.statSync)(full).mtimeMs };
143994
+ return { full, mtime: (0, import_fs24.statSync)(full).mtimeMs };
143694
143995
  }).sort((a, b2) => b2.mtime - a.mtime);
143695
143996
  for (const stale of backups.slice(retain)) {
143696
- if ((0, import_fs23.existsSync)(stale.full)) (0, import_fs23.unlinkSync)(stale.full);
143997
+ if ((0, import_fs24.existsSync)(stale.full)) (0, import_fs24.unlinkSync)(stale.full);
143697
143998
  }
143698
143999
  return destPath;
143699
144000
  }
@@ -143790,7 +144091,7 @@ var CacheIntegrityMonitor = class {
143790
144091
  * the pending record, back up on high severity, and broadcast the alert.
143791
144092
  */
143792
144093
  async runDetection(detectedAt = (/* @__PURE__ */ new Date()).toISOString()) {
143793
- const all = this.cache.listMissingFiles(import_fs24.existsSync);
144094
+ const all = this.cache.listMissingFiles(import_fs25.existsSync);
143794
144095
  const missing = all.filter((m2) => !this.ignoredIds.has(m2.id));
143795
144096
  if (missing.length === 0) {
143796
144097
  if (this._pending) {
@@ -143894,7 +144195,7 @@ var CacheIntegrityMonitor = class {
143894
144195
  case "prune_all": {
143895
144196
  await this.ensureBackup(pending);
143896
144197
  const backupPath = pending.backupPath;
143897
- const stillMissing = pending.missing.filter((m2) => !(0, import_fs24.existsSync)(m2.filePath)).map((m2) => m2.id);
144198
+ const stillMissing = pending.missing.filter((m2) => !(0, import_fs25.existsSync)(m2.filePath)).map((m2) => m2.id);
143898
144199
  const pruned = this.cache.dropRowsById(stillMissing);
143899
144200
  this.applyDeferredUnlinks();
143900
144201
  this.clearPending();
@@ -143955,7 +144256,7 @@ var CacheIntegrityMonitor = class {
143955
144256
  };
143956
144257
 
143957
144258
  // src/services/conversations/conversationWatcher.ts
143958
- var import_fs25 = require("fs");
144259
+ var import_fs26 = require("fs");
143959
144260
  var import_promises14 = require("fs/promises");
143960
144261
  var ConversationWatcher = class {
143961
144262
  files = /* @__PURE__ */ new Map();
@@ -143981,7 +144282,7 @@ var ConversationWatcher = class {
143981
144282
  if (this.files.has(key)) return;
143982
144283
  let offset;
143983
144284
  try {
143984
- offset = (0, import_fs25.statSync)(filePath).size;
144285
+ offset = (0, import_fs26.statSync)(filePath).size;
143985
144286
  } catch {
143986
144287
  offset = 0;
143987
144288
  }
@@ -144163,14 +144464,14 @@ function findSearchTarget(messages, query) {
144163
144464
  }
144164
144465
 
144165
144466
  // src/services/conversations/pruneAgentConversations.ts
144166
- var import_fs26 = require("fs");
144467
+ var import_fs27 = require("fs");
144167
144468
  function pruneAgentConversations(cache) {
144168
144469
  const db = cache.getDatabase();
144169
144470
  const rows = db.prepare("SELECT id, file_path FROM conversation_meta").all();
144170
144471
  let pruned = 0;
144171
144472
  let missing = 0;
144172
144473
  for (const row of rows) {
144173
- if (!(0, import_fs26.existsSync)(row.file_path)) {
144474
+ if (!(0, import_fs27.existsSync)(row.file_path)) {
144174
144475
  missing += 1;
144175
144476
  continue;
144176
144477
  }
@@ -144491,22 +144792,22 @@ function refreshConversationCache(deps) {
144491
144792
  }
144492
144793
 
144493
144794
  // src/services/conversations/shouldRefreshProjectsFromHdd.ts
144494
- var import_fs27 = require("fs");
144495
- var import_os11 = require("os");
144795
+ var import_fs28 = require("fs");
144796
+ var import_os12 = require("os");
144496
144797
  var import_path27 = require("path");
144497
- var DEFAULT_PROJECTS_DIR = (0, import_path27.join)((0, import_os11.homedir)(), ".claude", "projects");
144798
+ var DEFAULT_PROJECTS_DIR = (0, import_path27.join)((0, import_os12.homedir)(), ".claude", "projects");
144498
144799
  function maxProjectsTreeMtimeMs(projectsDir) {
144499
144800
  let maxMs;
144500
144801
  try {
144501
- maxMs = (0, import_fs27.statSync)(projectsDir).mtimeMs;
144802
+ maxMs = (0, import_fs28.statSync)(projectsDir).mtimeMs;
144502
144803
  } catch {
144503
144804
  return null;
144504
144805
  }
144505
144806
  try {
144506
- for (const ent of (0, import_fs27.readdirSync)(projectsDir, { withFileTypes: true })) {
144807
+ for (const ent of (0, import_fs28.readdirSync)(projectsDir, { withFileTypes: true })) {
144507
144808
  if (!ent.isDirectory()) continue;
144508
144809
  try {
144509
- const childMs = (0, import_fs27.statSync)((0, import_path27.join)(projectsDir, ent.name)).mtimeMs;
144810
+ const childMs = (0, import_fs28.statSync)((0, import_path27.join)(projectsDir, ent.name)).mtimeMs;
144510
144811
  if (childMs > maxMs) maxMs = childMs;
144511
144812
  } catch {
144512
144813
  }
@@ -145275,8 +145576,90 @@ function resolveAnswer(pending, body) {
145275
145576
  }
145276
145577
  }
145277
145578
 
145579
+ // src/services/search/searchQuery.ts
145580
+ var DEFAULT_SEARCH_LIMIT = 50;
145581
+ var MAX_SEARCH_LIMIT = 200;
145582
+ var MAX_QUERY_LENGTH = 256;
145583
+ var SearchQueryError = class extends Error {
145584
+ constructor(message, code) {
145585
+ super(message);
145586
+ this.code = code;
145587
+ }
145588
+ code;
145589
+ };
145590
+ function intOr(raw2, fallback) {
145591
+ if (raw2 === null) return fallback;
145592
+ const n = Number.parseInt(raw2, 10);
145593
+ return Number.isFinite(n) ? n : fallback;
145594
+ }
145595
+ function parseSearchQuery(params) {
145596
+ const q2 = (params.get("q") ?? "").trim();
145597
+ if (!q2) {
145598
+ throw new SearchQueryError("Missing query parameter: q", "invalid_query");
145599
+ }
145600
+ if (q2.length > MAX_QUERY_LENGTH) {
145601
+ throw new SearchQueryError(`Query exceeds ${MAX_QUERY_LENGTH} characters`, "query_too_long");
145602
+ }
145603
+ const limit = Math.min(
145604
+ Math.max(intOr(params.get("limit"), DEFAULT_SEARCH_LIMIT), 1),
145605
+ MAX_SEARCH_LIMIT
145606
+ );
145607
+ const offset = Math.max(intOr(params.get("offset"), 0), 0);
145608
+ const filters = {};
145609
+ const provider = params.get("provider");
145610
+ if (provider !== null) {
145611
+ if (!isProviderName(provider)) {
145612
+ throw new SearchQueryError(`Unknown provider: ${provider}`, "invalid_filter");
145613
+ }
145614
+ filters.provider = provider;
145615
+ }
145616
+ const projectPath = params.get("projectPath");
145617
+ if (projectPath) filters.projectPath = projectPath;
145618
+ const branch = params.get("branch");
145619
+ if (branch) filters.branch = branch;
145620
+ for (const [key, field] of [
145621
+ ["since", "since"],
145622
+ ["until", "until"]
145623
+ ]) {
145624
+ const raw2 = params.get(key);
145625
+ if (raw2 === null) continue;
145626
+ const ms2 = Date.parse(raw2);
145627
+ if (Number.isNaN(ms2)) {
145628
+ throw new SearchQueryError(`Invalid ${key}: expected an ISO 8601 date`, "invalid_filter");
145629
+ }
145630
+ filters[field] = ms2;
145631
+ }
145632
+ if (filters.since != null && filters.until != null && filters.since > filters.until) {
145633
+ throw new SearchQueryError("`since` must not be after `until`", "invalid_filter");
145634
+ }
145635
+ return { q: q2, limit, offset, filters };
145636
+ }
145637
+ function applyFilters(results, filters) {
145638
+ return results.filter((r) => {
145639
+ if (filters.provider && r.provider !== filters.provider) return false;
145640
+ if (filters.projectPath && r.projectPath !== filters.projectPath) return false;
145641
+ if (filters.branch && r.branch !== filters.branch) return false;
145642
+ if (filters.since != null || filters.until != null) {
145643
+ const ts2 = r.lastActivity == null ? Number.NaN : new Date(r.lastActivity).getTime();
145644
+ if (Number.isNaN(ts2)) return false;
145645
+ if (filters.since != null && ts2 < filters.since) return false;
145646
+ if (filters.until != null && ts2 > filters.until) return false;
145647
+ }
145648
+ return true;
145649
+ });
145650
+ }
145651
+ function paginate(results, offset, limit) {
145652
+ const items = results.slice(offset, offset + limit);
145653
+ return {
145654
+ items,
145655
+ total: results.length,
145656
+ offset,
145657
+ hasMore: offset + items.length < results.length
145658
+ };
145659
+ }
145660
+
145278
145661
  // src/services/sessions/conversationBusy.ts
145279
- var import_fs28 = require("fs");
145662
+ var import_fs29 = require("fs");
145280
145663
  var RESUME_BUSY_WINDOW_MS = 12e4;
145281
145664
  function resolveResumeBusyWindowMs(env = process.env) {
145282
145665
  const raw2 = env.THREADBASE_RESUME_BUSY_WINDOW_MS;
@@ -145293,7 +145676,7 @@ function conversationBusy(input) {
145293
145676
  let lastActivityMs = null;
145294
145677
  if (input.jsonlPath) {
145295
145678
  try {
145296
- const mtimeMs = (0, import_fs28.statSync)(input.jsonlPath).mtimeMs;
145679
+ const mtimeMs = (0, import_fs29.statSync)(input.jsonlPath).mtimeMs;
145297
145680
  const age = now - mtimeMs;
145298
145681
  lastActivityMs = Math.max(0, age);
145299
145682
  const isSelfEcho = input.selfPtyEndedAt != null && mtimeMs <= input.selfPtyEndedAt + SELF_ACTIVITY_SKEW_MS;
@@ -146003,6 +146386,8 @@ var DEFAULT_PTY_GRACE_PERIOD_MS = 27e4;
146003
146386
  var GRACE_MAX_DEFERS = 4;
146004
146387
  var IDLE_REAP_AFTER_MS = 6 * 60 * 60 * 1e3;
146005
146388
  var IDLE_REAP_SWEEP_MS = 5 * 60 * 1e3;
146389
+ var SEARCH_OVERFETCH = 4;
146390
+ var SEARCH_MAX_SCAN = 1e3;
146006
146391
  var RESUME_DISCOVERY_TIMEOUT_MS = 750;
146007
146392
  var DISCOVERY_TTL_MS = 15e3;
146008
146393
  var ADOPT_KILL_TIMEOUT_MS = 5e3;
@@ -146243,7 +146628,7 @@ var StreamerServer = class {
146243
146628
  this.skipStartupWarmup = config2.skipStartupWarmup ?? false;
146244
146629
  this.scannerPersistenceDisabled = config2.scannerPersistent === false;
146245
146630
  this.scanProfiles = config2.scanProfiles;
146246
- this.codexRoots = config2.codexRoots ?? [(0, import_path29.join)((0, import_os12.homedir)(), ".codex", "sessions")];
146631
+ this.codexRoots = config2.codexRoots ?? [(0, import_path29.join)((0, import_os13.homedir)(), ".codex", "sessions")];
146247
146632
  this.ptyGracePeriodMs = config2.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
146248
146633
  this.defaultSystemPrompt = config2.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
146249
146634
  this.featureFlags = resolveFeatureFlags({ cli: config2.featureFlags, yaml: loadFeatureFlags() });
@@ -146257,7 +146642,7 @@ var StreamerServer = class {
146257
146642
  this.claudeFlagsPersistable = config2.claudeFlags === void 0;
146258
146643
  this.claudeFlags = config2.claudeFlags ?? loadClaudeFlags();
146259
146644
  this.claudeExtraArgs = config2.claudeExtraArgs ?? loadClaudeExtraArgs();
146260
- this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0, import_path29.join)((0, import_os12.homedir)(), ".threadbase", "cache");
146645
+ this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0, import_path29.join)((0, import_os13.homedir)(), ".threadbase", "cache");
146261
146646
  this.tailSize = config2.tailSize ?? loadTailSize() ?? 10;
146262
146647
  this.directoryDebounceMs = parseDirScanDebounceEnv(process.env.THREADBASE_DIR_SCAN_DEBOUNCE_MS) ?? config2.directoryScanDebounceMs ?? 1e3;
146263
146648
  this.markScannerStaleDebounced = debounce(() => {
@@ -146308,7 +146693,7 @@ var StreamerServer = class {
146308
146693
  const seqs = cache.extendMessageIndex(
146309
146694
  filePath,
146310
146695
  spans,
146311
- (0, import_fs29.statSync)(filePath),
146696
+ (0, import_fs30.statSync)(filePath),
146312
146697
  readFrom,
146313
146698
  endOffset
146314
146699
  );
@@ -146771,14 +147156,14 @@ var StreamerServer = class {
146771
147156
  }
146772
147157
  this.apnsClient = new ApnsClient(creds);
146773
147158
  const sender = new LiveActivitySender(this.apnsClient, pushRepo);
146774
- const serverId = process.env.THREADBASE_INSTANCE_ID ?? (0, import_os12.hostname)();
146775
- this.liveActivityNotifier = new LiveActivityNotifier(sender, serverId, (0, import_os12.hostname)());
147159
+ const serverId = process.env.THREADBASE_INSTANCE_ID ?? (0, import_os13.hostname)();
147160
+ this.liveActivityNotifier = new LiveActivityNotifier(sender, serverId, (0, import_os13.hostname)());
146776
147161
  this.liveActivityRenewal = new LiveActivityRenewalScheduler({
146777
147162
  repo: pushRepo,
146778
147163
  sender,
146779
147164
  sessionStore: this.sessionStore,
146780
147165
  serverId,
146781
- serverLabel: (0, import_os12.hostname)()
147166
+ serverLabel: (0, import_os13.hostname)()
146782
147167
  });
146783
147168
  this.liveActivityRenewal.start();
146784
147169
  this.log.info("Live Activity push enabled", {
@@ -147117,7 +147502,7 @@ var StreamerServer = class {
147117
147502
  this.fileWatcher.watchDirectory(dir);
147118
147503
  }
147119
147504
  for (const dir of this.codexRoots) {
147120
- if (!(0, import_fs29.existsSync)(dir)) continue;
147505
+ if (!(0, import_fs30.existsSync)(dir)) continue;
147121
147506
  this.fileWatcher.watchDirectory(dir);
147122
147507
  }
147123
147508
  } catch (err) {
@@ -147390,7 +147775,7 @@ var StreamerServer = class {
147390
147775
  }
147391
147776
  let body;
147392
147777
  try {
147393
- body = await readBody(req);
147778
+ body = await readBody2(req);
147394
147779
  } catch (err) {
147395
147780
  const message = err instanceof Error ? err.message : "Invalid body";
147396
147781
  json2(res, 400, { error: message });
@@ -147436,7 +147821,7 @@ var StreamerServer = class {
147436
147821
  nonce: sealed.nonce,
147437
147822
  ephemeralPublicKey: sealed.ephemeralPublicKey,
147438
147823
  publicUrl: this.publicUrl,
147439
- machineName: (0, import_os12.hostname)(),
147824
+ machineName: (0, import_os13.hostname)(),
147440
147825
  ...device && {
147441
147826
  deviceId: device.deviceId,
147442
147827
  deviceToken: device.deviceToken,
@@ -147564,7 +147949,7 @@ var StreamerServer = class {
147564
147949
  if (this.scanProfiles && this.scanProfiles.length > 0) {
147565
147950
  return this.scanProfiles.filter((p2) => p2.enabled).map((p2) => (0, import_path29.join)(p2.configDir, "projects"));
147566
147951
  }
147567
- return [(0, import_path29.join)((0, import_os12.homedir)(), ".claude", "projects")];
147952
+ return [(0, import_path29.join)((0, import_os13.homedir)(), ".claude", "projects")];
147568
147953
  }
147569
147954
  /**
147570
147955
  * Full-glob scan + cache upsert/delete reconcile. Used by ?refresh=1 and by
@@ -147966,20 +148351,20 @@ var StreamerServer = class {
147966
148351
  if (this.scanProfiles && this.scanProfiles.length > 0) {
147967
148352
  return this.scanProfiles.filter((p2) => p2.enabled).map((p2) => (0, import_path29.join)(p2.configDir, "projects"));
147968
148353
  }
147969
- return [(0, import_path29.join)((0, import_os12.homedir)(), ".claude", "projects")];
148354
+ return [(0, import_path29.join)((0, import_os13.homedir)(), ".claude", "projects")];
147970
148355
  }
147971
148356
  findJsonlPath(uuid3) {
147972
148357
  const filename = `${uuid3}.jsonl`;
147973
148358
  for (const projectsDir of this.projectsDirs()) {
147974
- if (!(0, import_fs29.existsSync)(projectsDir)) continue;
147975
- for (const dir of (0, import_fs29.readdirSync)(projectsDir)) {
148359
+ if (!(0, import_fs30.existsSync)(projectsDir)) continue;
148360
+ for (const dir of (0, import_fs30.readdirSync)(projectsDir)) {
147976
148361
  const fp = (0, import_path29.join)(projectsDir, dir, filename);
147977
- if ((0, import_fs29.existsSync)(fp)) return fp;
148362
+ if ((0, import_fs30.existsSync)(fp)) return fp;
147978
148363
  const projectDir = (0, import_path29.join)(projectsDir, dir);
147979
148364
  try {
147980
- for (const sub of (0, import_fs29.readdirSync)(projectDir)) {
148365
+ for (const sub of (0, import_fs30.readdirSync)(projectDir)) {
147981
148366
  const subagentPath = (0, import_path29.join)(projectDir, sub, "subagents", filename);
147982
- if ((0, import_fs29.existsSync)(subagentPath)) return subagentPath;
148367
+ if ((0, import_fs30.existsSync)(subagentPath)) return subagentPath;
147983
148368
  }
147984
148369
  } catch {
147985
148370
  }
@@ -147989,7 +148374,7 @@ var StreamerServer = class {
147989
148374
  }
147990
148375
  async readCwdFromJsonl(filePath) {
147991
148376
  return new Promise((resolve4) => {
147992
- const rl = (0, import_readline4.createInterface)({ input: (0, import_fs29.createReadStream)(filePath), crlfDelay: Infinity });
148377
+ const rl = (0, import_readline4.createInterface)({ input: (0, import_fs30.createReadStream)(filePath), crlfDelay: Infinity });
147993
148378
  let found = false;
147994
148379
  rl.on("line", (line) => {
147995
148380
  if (found) return;
@@ -148079,7 +148464,7 @@ var StreamerServer = class {
148079
148464
  if (this.isManagedTailPath(key)) return;
148080
148465
  let mtimeMs;
148081
148466
  try {
148082
- mtimeMs = (0, import_fs29.statSync)(filePath).mtimeMs;
148467
+ mtimeMs = (0, import_fs30.statSync)(filePath).mtimeMs;
148083
148468
  } catch {
148084
148469
  return;
148085
148470
  }
@@ -148261,7 +148646,7 @@ var StreamerServer = class {
148261
148646
  if (!conv.filePath) return false;
148262
148647
  let mtimeMs = null;
148263
148648
  try {
148264
- mtimeMs = (0, import_fs29.statSync)(conv.filePath).mtimeMs;
148649
+ mtimeMs = (0, import_fs30.statSync)(conv.filePath).mtimeMs;
148265
148650
  } catch {
148266
148651
  return false;
148267
148652
  }
@@ -148516,7 +148901,7 @@ var StreamerServer = class {
148516
148901
  }
148517
148902
  let body;
148518
148903
  try {
148519
- body = await readBody(req);
148904
+ body = await readBody2(req);
148520
148905
  } catch {
148521
148906
  res.setHeader("Accept-Query", "application/json");
148522
148907
  json2(res, 422, { error: "Malformed JSON body", code: "invalid_query" });
@@ -148554,17 +148939,27 @@ var StreamerServer = class {
148554
148939
  });
148555
148940
  }
148556
148941
  async handleSearch(url2, res) {
148557
- const q2 = url2.searchParams.get("q") ?? "";
148558
- if (!q2) {
148559
- json2(res, 400, { error: "Missing query parameter: q" });
148560
- return;
148942
+ let parsed;
148943
+ try {
148944
+ parsed = parseSearchQuery(url2.searchParams);
148945
+ } catch (err) {
148946
+ if (err instanceof SearchQueryError) {
148947
+ json2(res, 400, { error: err.message, code: err.code });
148948
+ return;
148949
+ }
148950
+ throw err;
148561
148951
  }
148562
- const limit = intParam(url2, "limit", 50);
148952
+ const { q: q2, limit, offset, filters } = parsed;
148953
+ const startedAt = Date.now();
148563
148954
  const scanner = await this.getScanner();
148564
148955
  const results = await search(
148565
148956
  q2,
148566
148957
  {
148567
- limit,
148958
+ // Fetch beyond the requested page: filters below are applied AFTER the
148959
+ // scanner returns, so slicing at `limit` here would drop results that a
148960
+ // later page should contain. Bounded so a broad query cannot pull an
148961
+ // unbounded set into memory.
148962
+ limit: Math.min(offset + limit * SEARCH_OVERFETCH, SEARCH_MAX_SCAN),
148568
148963
  include: "conversations",
148569
148964
  ...this.scanProfiles ? { profiles: this.scanProfiles } : {},
148570
148965
  ...this.codexScanOpts()
@@ -148588,13 +148983,24 @@ var StreamerServer = class {
148588
148983
  lastActivity: r.meta.timestamp,
148589
148984
  firstMessage: r.meta.firstMessage ?? void 0,
148590
148985
  lastMessage: r.meta.lastMessage ?? void 0,
148591
- provider: r.meta.provider ?? CLAUDE_CODE_PROVIDER2
148986
+ provider: r.meta.provider ?? CLAUDE_CODE_PROVIDER2,
148987
+ // The scanner already computes relevance and match snippets; the previous
148988
+ // adapter discarded both, so results arrived in an unexplained order with
148989
+ // no indication of WHY anything matched.
148990
+ score: r.score,
148991
+ matches: Array.isArray(r.matches) ? r.matches.map((m2) => ({
148992
+ field: m2.field,
148993
+ snippet: m2.snippet
148994
+ })) : []
148592
148995
  }));
148996
+ const page = paginate(applyFilters(adapted, filters), offset, limit);
148593
148997
  json2(res, 200, {
148594
- conversations: adapted,
148595
- hasMore: false,
148596
- offset: 0,
148597
- total: adapted.length
148998
+ conversations: page.items,
148999
+ hasMore: page.hasMore,
149000
+ offset: page.offset,
149001
+ total: page.total,
149002
+ // Query timing, so a slow search is diagnosable rather than merely felt.
149003
+ tookMs: Date.now() - startedAt
148598
149004
  });
148599
149005
  }
148600
149006
  async handleListSessions(url2, res) {
@@ -148640,7 +149046,7 @@ var StreamerServer = class {
148640
149046
  if (this.rejectIfWarmingUp(res)) return;
148641
149047
  const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
148642
149048
  if (session) {
148643
- if (!(0, import_fs29.existsSync)(session.projectPath)) {
149049
+ if (!(0, import_fs30.existsSync)(session.projectPath)) {
148644
149050
  session.failureReason = `Project directory not found: ${session.projectPath}`;
148645
149051
  }
148646
149052
  const reconciled = this.withReconciledLifecycle([session])[0];
@@ -148667,7 +149073,7 @@ var StreamerServer = class {
148667
149073
  json2(res, 404, { error: "Session not found" });
148668
149074
  }
148669
149075
  async handleResume(req, res) {
148670
- const body = await readBody(req);
149076
+ const body = await readBody2(req);
148671
149077
  const sessionId = body.sessionId ?? body.conversationId;
148672
149078
  if (!sessionId) {
148673
149079
  json2(res, 400, { error: "Missing sessionId" });
@@ -148799,7 +149205,7 @@ var StreamerServer = class {
148799
149205
  return;
148800
149206
  }
148801
149207
  if (this.agentConfig.enabled) {
148802
- const body2 = await readBody(req);
149208
+ const body2 = await readBody2(req);
148803
149209
  const cache = this.cache;
148804
149210
  if (!cache) {
148805
149211
  json2(res, 503, {
@@ -148818,7 +149224,7 @@ var StreamerServer = class {
148818
149224
  json2(res, result.status, result.body);
148819
149225
  return;
148820
149226
  }
148821
- const body = await readBody(req);
149227
+ const body = await readBody2(req);
148822
149228
  const { input, keys } = body;
148823
149229
  let idempotencyKey;
148824
149230
  try {
@@ -148982,7 +149388,7 @@ var StreamerServer = class {
148982
149388
  });
148983
149389
  }
148984
149390
  async handleSendAnswer(sessionId, req, res) {
148985
- const body = await readBody(req);
149391
+ const body = await readBody2(req);
148986
149392
  const pending = this.pendingQuestions.get(sessionId);
148987
149393
  const resolution = resolveAnswer(pending, body);
148988
149394
  if (!resolution.ok) {
@@ -149011,7 +149417,7 @@ var StreamerServer = class {
149011
149417
  json2(res, 400, { error: "Session has no project path" });
149012
149418
  return;
149013
149419
  }
149014
- const body = await readBody(req);
149420
+ const body = await readBody2(req);
149015
149421
  const { filename, mimeType, dataBase64 } = body ?? {};
149016
149422
  if (typeof filename !== "string" || typeof mimeType !== "string" || typeof dataBase64 !== "string") {
149017
149423
  json2(res, 400, { error: "Missing filename, mimeType, or dataBase64" });
@@ -149213,7 +149619,7 @@ var StreamerServer = class {
149213
149619
  return;
149214
149620
  }
149215
149621
  if (this.agentConfig.enabled) {
149216
- const body2 = await readBody(req);
149622
+ const body2 = await readBody2(req);
149217
149623
  const result = await handleStartAgentSession(body2, {
149218
149624
  sessionStore: this.sessionStore,
149219
149625
  // biome-ignore lint/style/noNonNullAssertion: agentClient is set when agentConfig.enabled is true
@@ -149227,7 +149633,7 @@ var StreamerServer = class {
149227
149633
  }
149228
149634
  return;
149229
149635
  }
149230
- const body = await readBody(req);
149636
+ const body = await readBody2(req);
149231
149637
  const { path: relativePath, provider: requestedProvider, systemPrompt: clientPrompt } = body;
149232
149638
  if (requestedProvider !== void 0 && !isProviderName(requestedProvider)) {
149233
149639
  json2(res, 400, { error: "Invalid provider" });
@@ -149364,7 +149770,7 @@ var StreamerServer = class {
149364
149770
  // file isn't slurped in full.
149365
149771
  readFirstLineSessionId(filePath) {
149366
149772
  try {
149367
- const content = (0, import_fs29.readFileSync)(filePath, "utf8");
149773
+ const content = (0, import_fs30.readFileSync)(filePath, "utf8");
149368
149774
  const nl = content.indexOf("\n");
149369
149775
  const firstLine = nl === -1 ? content : content.slice(0, nl);
149370
149776
  if (!firstLine.trim()) return null;
@@ -149379,7 +149785,7 @@ var StreamerServer = class {
149379
149785
  // was passed to Claude via --session-id so the filename matches from the start.
149380
149786
  watchForJsonl(sessionId, projectPath) {
149381
149787
  const encoded = projectPath.replace(/[/\\:.]/g, "-");
149382
- const projectsDir = (0, import_path29.join)((0, import_os12.homedir)(), ".claude", "projects", encoded);
149788
+ const projectsDir = (0, import_path29.join)((0, import_os13.homedir)(), ".claude", "projects", encoded);
149383
149789
  const expectedFile = `${sessionId}.jsonl`;
149384
149790
  const filePath = (0, import_path29.join)(projectsDir, expectedFile);
149385
149791
  const deadline = Date.now() + 12e4;
@@ -149399,11 +149805,11 @@ var StreamerServer = class {
149399
149805
  cleanup();
149400
149806
  return;
149401
149807
  }
149402
- let resolvedFilePath = (0, import_fs29.existsSync)(filePath) ? filePath : null;
149403
- if (!resolvedFilePath && (0, import_fs29.existsSync)(projectsDir)) {
149808
+ let resolvedFilePath = (0, import_fs30.existsSync)(filePath) ? filePath : null;
149809
+ if (!resolvedFilePath && (0, import_fs30.existsSync)(projectsDir)) {
149404
149810
  try {
149405
149811
  const now = Date.now();
149406
- const match2 = (0, import_fs29.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs29.statSync)((0, import_path29.join)(projectsDir, f2)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).filter(
149812
+ const match2 = (0, import_fs30.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs30.statSync)((0, import_path29.join)(projectsDir, f2)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).filter(
149407
149813
  ({ f: f2 }) => (0, import_path29.basename)(f2, ".jsonl") === sessionId || this.readFirstLineSessionId((0, import_path29.join)(projectsDir, f2)) === sessionId
149408
149814
  ).sort((a, b2) => b2.mtime - a.mtime)[0];
149409
149815
  if (match2) resolvedFilePath = (0, import_path29.join)(projectsDir, match2.f);
@@ -149414,7 +149820,7 @@ var StreamerServer = class {
149414
149820
  cleanup();
149415
149821
  this.sessionFileMap.set(sessionId, resolvedFilePath);
149416
149822
  try {
149417
- const existing = (0, import_fs29.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
149823
+ const existing = (0, import_fs30.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
149418
149824
  if (existing.length > 0) {
149419
149825
  this.broadcastConversationLines(sessionId, existing);
149420
149826
  }
@@ -149438,7 +149844,7 @@ var StreamerServer = class {
149438
149844
  if (this.sessionFileMap.has(sessionId)) return;
149439
149845
  try {
149440
149846
  require("fs").mkdirSync(projectsDir, { recursive: true });
149441
- watcher = (0, import_fs29.watch)(projectsDir, tryWire);
149847
+ watcher = (0, import_fs30.watch)(projectsDir, tryWire);
149442
149848
  watcher.on("error", cleanup);
149443
149849
  } catch {
149444
149850
  }
@@ -149467,7 +149873,7 @@ var StreamerServer = class {
149467
149873
  };
149468
149874
  const matchesProjectPath = (candidatePath) => {
149469
149875
  try {
149470
- const firstLine = (0, import_fs29.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
149876
+ const firstLine = (0, import_fs30.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
149471
149877
  if (!firstLine) return null;
149472
149878
  const parsed = JSON.parse(firstLine);
149473
149879
  if (parsed?.type !== "session_meta") return null;
@@ -149496,15 +149902,15 @@ var StreamerServer = class {
149496
149902
  );
149497
149903
  for (const root of this.codexRoots) {
149498
149904
  const sessionsDir = (0, import_path29.join)(root, dateDir);
149499
- if (!(0, import_fs29.existsSync)(sessionsDir)) continue;
149905
+ if (!(0, import_fs30.existsSync)(sessionsDir)) continue;
149500
149906
  let candidateFiles;
149501
149907
  try {
149502
- candidateFiles = (0, import_fs29.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
149908
+ candidateFiles = (0, import_fs30.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
149503
149909
  } catch {
149504
149910
  continue;
149505
149911
  }
149506
149912
  const nowMs = Date.now();
149507
- const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs29.statSync)((0, import_path29.join)(sessionsDir, f2)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b2) => b2.mtime - a.mtime);
149913
+ const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs30.statSync)((0, import_path29.join)(sessionsDir, f2)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b2) => b2.mtime - a.mtime);
149508
149914
  for (const { f: f2 } of recentCandidates) {
149509
149915
  const candidatePath = (0, import_path29.join)(sessionsDir, f2);
149510
149916
  const match2 = matchesProjectPath(candidatePath);
@@ -149516,7 +149922,7 @@ var StreamerServer = class {
149516
149922
  this.sessionFileMap.set(sessionId, candidatePath);
149517
149923
  this.fileWatcher.watch(candidatePath);
149518
149924
  try {
149519
- const existing = (0, import_fs29.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
149925
+ const existing = (0, import_fs30.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
149520
149926
  if (existing.length > 0) {
149521
149927
  this.broadcastConversationLines(sessionId, existing);
149522
149928
  }
@@ -149585,7 +149991,7 @@ var StreamerServer = class {
149585
149991
  });
149586
149992
  return;
149587
149993
  }
149588
- const body = await readBody(req);
149994
+ const body = await readBody2(req);
149589
149995
  const { path: relativePath, name } = body;
149590
149996
  if (!name || typeof name !== "string") {
149591
149997
  json2(res, 400, { error: "Missing name field" });
@@ -149615,7 +150021,7 @@ var StreamerServer = class {
149615
150021
  }
149616
150022
  let parsed;
149617
150023
  try {
149618
- parsed = await readBody(req);
150024
+ parsed = await readBody2(req);
149619
150025
  } catch {
149620
150026
  json2(res, 400, { error: "Invalid JSON" });
149621
150027
  return;
@@ -149672,7 +150078,7 @@ var StreamerServer = class {
149672
150078
  }
149673
150079
  let parsed;
149674
150080
  try {
149675
- parsed = await readBody(req);
150081
+ parsed = await readBody2(req);
149676
150082
  } catch {
149677
150083
  json2(res, 400, { error: "Invalid JSON" });
149678
150084
  return;
@@ -149731,7 +150137,7 @@ async function waitForProcessExit(pid, timeoutMs, pollMs = ADOPT_KILL_POLL_MS) {
149731
150137
  }
149732
150138
  function classifyResumability(cwd) {
149733
150139
  if (!cwd) return { resumable: true };
149734
- if ((0, import_fs29.existsSync)(cwd)) return { resumable: true };
150140
+ if ((0, import_fs30.existsSync)(cwd)) return { resumable: true };
149735
150141
  const ranInWorktree = /\/\.worktrees\//.test(cwd) || /\/\.claude\/worktrees\//.test(cwd);
149736
150142
  return {
149737
150143
  resumable: false,
@@ -149849,7 +150255,7 @@ function parseSessionListQuery(url2) {
149849
150255
  const cursor = url2.searchParams.get("cursor") ?? void 0;
149850
150256
  return { query: { limit, sortBy, order, status, cursor } };
149851
150257
  }
149852
- function readBody(req) {
150258
+ function readBody2(req) {
149853
150259
  return new Promise((resolve4, reject) => {
149854
150260
  const chunks = [];
149855
150261
  req.on("data", (chunk) => chunks.push(chunk));
@@ -150401,7 +150807,7 @@ var import_node_fs18 = require("fs");
150401
150807
 
150402
150808
  // node_modules/tar/dist/esm/index.min.js
150403
150809
  var import_events3 = __toESM(require("events"), 1);
150404
- var import_fs30 = __toESM(require("fs"), 1);
150810
+ var import_fs31 = __toESM(require("fs"), 1);
150405
150811
  var import_node_events3 = require("events");
150406
150812
  var import_node_stream2 = __toESM(require("stream"), 1);
150407
150813
  var import_node_string_decoder = require("string_decoder");
@@ -150415,8 +150821,8 @@ var Ps = __toESM(require("zlib"), 1);
150415
150821
  var import_zlib = __toESM(require("zlib"), 1);
150416
150822
  var import_node_path15 = require("path");
150417
150823
  var import_node_path16 = require("path");
150418
- var import_fs31 = __toESM(require("fs"), 1);
150419
150824
  var import_fs32 = __toESM(require("fs"), 1);
150825
+ var import_fs33 = __toESM(require("fs"), 1);
150420
150826
  var import_path31 = __toESM(require("path"), 1);
150421
150827
  var import_node_path17 = require("path");
150422
150828
  var import_path32 = __toESM(require("path"), 1);
@@ -150425,7 +150831,7 @@ var import_node_assert = __toESM(require("assert"), 1);
150425
150831
  var import_node_crypto6 = require("crypto");
150426
150832
  var import_node_fs14 = __toESM(require("fs"), 1);
150427
150833
  var import_node_path18 = __toESM(require("path"), 1);
150428
- var import_fs33 = __toESM(require("fs"), 1);
150834
+ var import_fs34 = __toESM(require("fs"), 1);
150429
150835
  var import_node_fs15 = __toESM(require("fs"), 1);
150430
150836
  var import_node_path19 = __toESM(require("path"), 1);
150431
150837
  var import_node_fs16 = __toESM(require("fs"), 1);
@@ -150777,7 +151183,7 @@ var A = class extends import_node_events3.EventEmitter {
150777
151183
  return Wr;
150778
151184
  }
150779
151185
  };
150780
- var Jr = import_fs30.default.writev;
151186
+ var Jr = import_fs31.default.writev;
150781
151187
  var ht = /* @__PURE__ */ Symbol("_autoClose");
150782
151188
  var H2 = /* @__PURE__ */ Symbol("_close");
150783
151189
  var te = /* @__PURE__ */ Symbol("_ended");
@@ -150832,7 +151238,7 @@ var _t = class extends A {
150832
151238
  throw new TypeError("this is a readable stream");
150833
151239
  }
150834
151240
  [at]() {
150835
- import_fs30.default.open(this[U], "r", (t, e) => this[Ht](t, e));
151241
+ import_fs31.default.open(this[U], "r", (t, e) => this[Ht](t, e));
150836
151242
  }
150837
151243
  [Ht](t, e) {
150838
151244
  t ? this[Ut](t) : (this[u] = e, this.emit("open", e), this[zt]());
@@ -150845,7 +151251,7 @@ var _t = class extends A {
150845
151251
  this[j] = true;
150846
151252
  let t = this[vi]();
150847
151253
  if (t.length === 0) return process.nextTick(() => this[Ii](null, 0, t));
150848
- import_fs30.default.read(this[u], t, 0, t.length, null, (e, i, r) => this[Ii](e, i, r));
151254
+ import_fs31.default.read(this[u], t, 0, t.length, null, (e, i, r) => this[Ii](e, i, r));
150849
151255
  }
150850
151256
  }
150851
151257
  [Ii](t, e, i) {
@@ -150854,7 +151260,7 @@ var _t = class extends A {
150854
151260
  [H2]() {
150855
151261
  if (this[ht] && typeof this[u] == "number") {
150856
151262
  let t = this[u];
150857
- this[u] = void 0, import_fs30.default.close(t, (e) => e ? this.emit("error", e) : this.emit("close"));
151263
+ this[u] = void 0, import_fs31.default.close(t, (e) => e ? this.emit("error", e) : this.emit("close"));
150858
151264
  }
150859
151265
  }
150860
151266
  [Ut](t) {
@@ -150882,7 +151288,7 @@ var Be = class extends _t {
150882
151288
  [at]() {
150883
151289
  let t = true;
150884
151290
  try {
150885
- this[Ht](null, import_fs30.default.openSync(this[U], "r")), t = false;
151291
+ this[Ht](null, import_fs31.default.openSync(this[U], "r")), t = false;
150886
151292
  } finally {
150887
151293
  t && this[H2]();
150888
151294
  }
@@ -150893,7 +151299,7 @@ var Be = class extends _t {
150893
151299
  if (!this[j]) {
150894
151300
  this[j] = true;
150895
151301
  do {
150896
- let e = this[vi](), i = e.length === 0 ? 0 : import_fs30.default.readSync(this[u], e, 0, e.length, null);
151302
+ let e = this[vi](), i = e.length === 0 ? 0 : import_fs31.default.readSync(this[u], e, 0, e.length, null);
150897
151303
  if (!this[ki](i, e)) break;
150898
151304
  } while (true);
150899
151305
  this[j] = false;
@@ -150906,7 +151312,7 @@ var Be = class extends _t {
150906
151312
  [H2]() {
150907
151313
  if (this[ht] && typeof this[u] == "number") {
150908
151314
  let t = this[u];
150909
- this[u] = void 0, import_fs30.default.closeSync(t), this.emit("close");
151315
+ this[u] = void 0, import_fs31.default.closeSync(t), this.emit("close");
150910
151316
  }
150911
151317
  }
150912
151318
  };
@@ -150948,7 +151354,7 @@ var et = class extends import_events3.default {
150948
151354
  this[H2](), this[gt] = true, this.emit("error", t);
150949
151355
  }
150950
151356
  [at]() {
150951
- import_fs30.default.open(this[U], this[tt], this[ie], (t, e) => this[Ht](t, e));
151357
+ import_fs31.default.open(this[U], this[tt], this[ie], (t, e) => this[Ht](t, e));
150952
151358
  }
150953
151359
  [Ht](t, e) {
150954
151360
  this[Me] && this[tt] === "r+" && t && t.code === "ENOENT" ? (this[tt] = "w", this[at]()) : t ? this[Ut](t) : (this[u] = e, this.emit("open", e), this[gt] || this[Ai]());
@@ -150960,7 +151366,7 @@ var et = class extends import_events3.default {
150960
151366
  return typeof t == "string" && (t = Buffer.from(t, e)), this[te] ? (this.emit("error", new Error("write() after end()")), false) : this[u] === void 0 || this[gt] || this[Y2].length ? (this[Y2].push(t), this[ke] = true, false) : (this[gt] = true, this[ve](t), true);
150961
151367
  }
150962
151368
  [ve](t) {
150963
- import_fs30.default.write(this[u], t, 0, t.length, this[ot], (e, i) => this[Pt](e, i));
151369
+ import_fs31.default.write(this[u], t, 0, t.length, this[ot], (e, i) => this[Pt](e, i));
150964
151370
  }
150965
151371
  [Pt](t, e) {
150966
151372
  t ? this[Ut](t) : (this[ot] !== void 0 && typeof e == "number" && (this[ot] += e), this[Y2].length ? this[Ai]() : (this[gt] = false, this[te] && !this[Ni] ? (this[Ni] = true, this[H2](), this.emit("finish")) : this[ke] && (this[ke] = false, this.emit("drain"))));
@@ -150976,7 +151382,7 @@ var et = class extends import_events3.default {
150976
151382
  [H2]() {
150977
151383
  if (this[ht] && typeof this[u] == "number") {
150978
151384
  let t = this[u];
150979
- this[u] = void 0, import_fs30.default.close(t, (e) => e ? this.emit("error", e) : this.emit("close"));
151385
+ this[u] = void 0, import_fs31.default.close(t, (e) => e ? this.emit("error", e) : this.emit("close"));
150980
151386
  }
150981
151387
  }
150982
151388
  };
@@ -150984,24 +151390,24 @@ var Wt = class extends et {
150984
151390
  [at]() {
150985
151391
  let t;
150986
151392
  if (this[Me] && this[tt] === "r+") try {
150987
- t = import_fs30.default.openSync(this[U], this[tt], this[ie]);
151393
+ t = import_fs31.default.openSync(this[U], this[tt], this[ie]);
150988
151394
  } catch (e) {
150989
151395
  if (e?.code === "ENOENT") return this[tt] = "w", this[at]();
150990
151396
  throw e;
150991
151397
  }
150992
- else t = import_fs30.default.openSync(this[U], this[tt], this[ie]);
151398
+ else t = import_fs31.default.openSync(this[U], this[tt], this[ie]);
150993
151399
  this[Ht](null, t);
150994
151400
  }
150995
151401
  [H2]() {
150996
151402
  if (this[ht] && typeof this[u] == "number") {
150997
151403
  let t = this[u];
150998
- this[u] = void 0, import_fs30.default.closeSync(t), this.emit("close");
151404
+ this[u] = void 0, import_fs31.default.closeSync(t), this.emit("close");
150999
151405
  }
151000
151406
  }
151001
151407
  [ve](t) {
151002
151408
  let e = true;
151003
151409
  try {
151004
- this[Pt](null, import_fs30.default.writeSync(this[u], t, 0, t.length, this[ot])), e = false;
151410
+ this[Pt](null, import_fs31.default.writeSync(this[u], t, 0, t.length, this[ot])), e = false;
151005
151411
  } finally {
151006
151412
  if (e) try {
151007
151413
  this[H2]();
@@ -151919,7 +152325,7 @@ var de = class extends A {
151919
152325
  return t === "error" && (this.#t = true), super.emit(t, ...e);
151920
152326
  }
151921
152327
  [ss]() {
151922
- import_fs32.default.lstat(this.absolute, (t, e) => {
152328
+ import_fs33.default.lstat(this.absolute, (t, e) => {
151923
152329
  if (t) return this.emit("error", t);
151924
152330
  this[si](e);
151925
152331
  });
@@ -151957,7 +152363,7 @@ var de = class extends A {
151957
152363
  this.path.slice(-1) !== "/" && (this.path += "/"), this.stat.size = 0, this[fe](), this.end();
151958
152364
  }
151959
152365
  [is]() {
151960
- import_fs32.default.readlink(this.absolute, (t, e) => {
152366
+ import_fs33.default.readlink(this.absolute, (t, e) => {
151961
152367
  if (t) return this.emit("error", t);
151962
152368
  this[ns](e);
151963
152369
  });
@@ -151980,7 +152386,7 @@ var de = class extends A {
151980
152386
  this[os]();
151981
152387
  }
151982
152388
  [os]() {
151983
- import_fs32.default.open(this.absolute, "r", (t, e) => {
152389
+ import_fs33.default.open(this.absolute, "r", (t, e) => {
151984
152390
  if (t) return this.emit("error", t);
151985
152391
  this[hs](e);
151986
152392
  });
@@ -151995,14 +152401,14 @@ var de = class extends A {
151995
152401
  [ii]() {
151996
152402
  let { fd: t, buf: e, offset: i, length: r, pos: n } = this;
151997
152403
  if (t === void 0 || e === void 0) throw new Error("cannot read file without first opening");
151998
- import_fs32.default.read(t, e, i, r, n, (o, h) => {
152404
+ import_fs33.default.read(t, e, i, r, n, (o, h) => {
151999
152405
  if (o) return this[pt](() => this.emit("error", o));
152000
152406
  this[rs](h);
152001
152407
  });
152002
152408
  }
152003
152409
  [pt](t = () => {
152004
152410
  }) {
152005
- this.fd !== void 0 && import_fs32.default.close(this.fd, t);
152411
+ this.fd !== void 0 && import_fs33.default.close(this.fd, t);
152006
152412
  }
152007
152413
  [rs](t) {
152008
152414
  if (t <= 0 && this.remain > 0) {
@@ -152037,20 +152443,20 @@ var de = class extends A {
152037
152443
  var ni = class extends de {
152038
152444
  sync = true;
152039
152445
  [ss]() {
152040
- this[si](import_fs32.default.lstatSync(this.absolute));
152446
+ this[si](import_fs33.default.lstatSync(this.absolute));
152041
152447
  }
152042
152448
  [is]() {
152043
- this[ns](import_fs32.default.readlinkSync(this.absolute));
152449
+ this[ns](import_fs33.default.readlinkSync(this.absolute));
152044
152450
  }
152045
152451
  [os]() {
152046
- this[hs](import_fs32.default.openSync(this.absolute, "r"));
152452
+ this[hs](import_fs33.default.openSync(this.absolute, "r"));
152047
152453
  }
152048
152454
  [ii]() {
152049
152455
  let t = true;
152050
152456
  try {
152051
152457
  let { fd: e, buf: i, offset: r, length: n, pos: o } = this;
152052
152458
  if (e === void 0 || i === void 0) throw new Error("fd and buf must be set in READ method");
152053
- let h = import_fs32.default.readSync(e, i, r, n, o);
152459
+ let h = import_fs33.default.readSync(e, i, r, n, o);
152054
152460
  this[rs](h), t = false;
152055
152461
  } finally {
152056
152462
  if (t) try {
@@ -152065,7 +152471,7 @@ var ni = class extends de {
152065
152471
  }
152066
152472
  [pt](t = () => {
152067
152473
  }) {
152068
- this.fd !== void 0 && import_fs32.default.closeSync(this.fd), t();
152474
+ this.fd !== void 0 && import_fs33.default.closeSync(this.fd), t();
152069
152475
  }
152070
152476
  };
152071
152477
  var oi = class extends A {
@@ -152396,7 +152802,7 @@ var wt = class extends A {
152396
152802
  [ds](t) {
152397
152803
  t.pending = true, this[G] += 1;
152398
152804
  let e = this.follow ? "stat" : "lstat";
152399
- import_fs31.default[e](t.absolute, (i, r) => {
152805
+ import_fs32.default[e](t.absolute, (i, r) => {
152400
152806
  t.pending = false, this[G] -= 1, i ? this.emit("error", i) : this[li](t, r);
152401
152807
  });
152402
152808
  }
@@ -152410,7 +152816,7 @@ var wt = class extends A {
152410
152816
  this[Ft]();
152411
152817
  }
152412
152818
  [ms](t) {
152413
- t.pending = true, this[G] += 1, import_fs31.default.readdir(t.absolute, (e, i) => {
152819
+ t.pending = true, this[G] += 1, import_fs32.default.readdir(t.absolute, (e, i) => {
152414
152820
  if (t.pending = false, this[G] -= 1, e) return this.emit("error", e);
152415
152821
  this[fi](t, i);
152416
152822
  });
@@ -152511,10 +152917,10 @@ var kt = class extends wt {
152511
152917
  }
152512
152918
  [ds](t) {
152513
152919
  let e = this.follow ? "statSync" : "lstatSync";
152514
- this[li](t, import_fs31.default[e](t.absolute));
152920
+ this[li](t, import_fs32.default[e](t.absolute));
152515
152921
  }
152516
152922
  [ms](t) {
152517
- this[fi](t, import_fs31.default.readdirSync(t.absolute));
152923
+ this[fi](t, import_fs32.default.readdirSync(t.absolute));
152518
152924
  }
152519
152925
  [di](t) {
152520
152926
  let e = t.entry, i = this.zip;
@@ -152565,8 +152971,8 @@ var Qn = K(Vn, $n, Xn, qn, (s3, t) => {
152565
152971
  });
152566
152972
  var Jn = process.env.__FAKE_PLATFORM__ || process.platform;
152567
152973
  var Er = Jn === "win32";
152568
- var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs33.default.constants;
152569
- var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) || import_fs33.default.constants.UV_FS_O_FILEMAP || 0;
152974
+ var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs34.default.constants;
152975
+ var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) || import_fs34.default.constants.UV_FS_O_FILEMAP || 0;
152570
152976
  var jn = Er && !!Rr;
152571
152977
  var to = 512 * 1024;
152572
152978
  var eo = Rr | Sr | wr | yr;
@@ -153944,12 +154350,12 @@ program2.command("cache").description("Manage the local SQLite conversation cach
153944
154350
  "Cache directory (default: ~/.threadbase/cache)",
153945
154351
  `${process.env.HOME}/.threadbase/cache`
153946
154352
  ).action((opts) => {
153947
- const { rmSync: rmSync6, existsSync: existsSync15 } = require("fs");
154353
+ const { rmSync: rmSync6, existsSync: existsSync16 } = require("fs");
153948
154354
  const { join: join29 } = require("path");
153949
154355
  const dbPath = join29(opts.cacheDir, "cache.db");
153950
154356
  for (const suffix of ["", "-shm", "-wal"]) {
153951
154357
  const f2 = dbPath + suffix;
153952
- if (existsSync15(f2)) {
154358
+ if (existsSync16(f2)) {
153953
154359
  rmSync6(f2);
153954
154360
  log11.info(`Deleted ${f2}`, { path: f2 }, "console");
153955
154361
  }