@threadbase-sh/streamer 1.39.0 → 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
+ }
138438
138706
  } catch {
138439
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
+ }
138733
+ } catch {
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;
@@ -146080,6 +146465,20 @@ var StreamerServer = class {
146080
146465
  // Set by onConversationChanged while a scan is in-flight; getScanner() does
146081
146466
  // a single rescan after the current one completes instead of restarting it.
146082
146467
  scannerStale = false;
146468
+ // WHICH files scannerStale is about. A directory event names exactly one
146469
+ // JSONL, and the only correct response is refreshFile() on that one file —
146470
+ // but scannerStale alone carries no identity, so honoring it used to mean a
146471
+ // full-tree rescan. On the non-persistent scanner this server actually runs
146472
+ // (buildStatCache => persistent:false, see listen()), scan() opens by
146473
+ // clearing metadataCache AND conversationLRU — so one live session appending
146474
+ // to its own transcript threw away every OTHER conversation's parsed
146475
+ // snapshot, and the next full fetch of an unrelated conversation re-parsed
146476
+ // it from disk (745-2877ms on a 5MB/1112-message history) while the
146477
+ // per-file paginated path stayed at ~20ms throughout. Populated alongside
146478
+ // scannerStale and drained with it by takeStaleFiles(); an armed flag with
146479
+ // an EMPTY set means "stale, source unknown" and still falls back to the
146480
+ // full rescan.
146481
+ staleFiles = /* @__PURE__ */ new Set();
146083
146482
  // Single-flight guard for the background disk reconcile: a burst of list
146084
146483
  // polls during active session writes shares one rescan instead of queueing
146085
146484
  // a full rescan per request.
@@ -146229,7 +146628,7 @@ var StreamerServer = class {
146229
146628
  this.skipStartupWarmup = config2.skipStartupWarmup ?? false;
146230
146629
  this.scannerPersistenceDisabled = config2.scannerPersistent === false;
146231
146630
  this.scanProfiles = config2.scanProfiles;
146232
- 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")];
146233
146632
  this.ptyGracePeriodMs = config2.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
146234
146633
  this.defaultSystemPrompt = config2.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
146235
146634
  this.featureFlags = resolveFeatureFlags({ cli: config2.featureFlags, yaml: loadFeatureFlags() });
@@ -146243,12 +146642,15 @@ var StreamerServer = class {
146243
146642
  this.claudeFlagsPersistable = config2.claudeFlags === void 0;
146244
146643
  this.claudeFlags = config2.claudeFlags ?? loadClaudeFlags();
146245
146644
  this.claudeExtraArgs = config2.claudeExtraArgs ?? loadClaudeExtraArgs();
146246
- 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");
146247
146646
  this.tailSize = config2.tailSize ?? loadTailSize() ?? 10;
146248
146647
  this.directoryDebounceMs = parseDirScanDebounceEnv(process.env.THREADBASE_DIR_SCAN_DEBOUNCE_MS) ?? config2.directoryScanDebounceMs ?? 1e3;
146249
146648
  this.markScannerStaleDebounced = debounce(() => {
146250
146649
  if (this.scannerReady) this.scannerStale = true;
146251
- else this.scanner = null;
146650
+ else {
146651
+ this.scanner = null;
146652
+ this.staleFiles.clear();
146653
+ }
146252
146654
  }, this.directoryDebounceMs);
146253
146655
  this.includeAgents = parseIncludeAgentsEnv(process.env.THREADBASE_INCLUDE_AGENTS);
146254
146656
  this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
@@ -146291,7 +146693,7 @@ var StreamerServer = class {
146291
146693
  const seqs = cache.extendMessageIndex(
146292
146694
  filePath,
146293
146695
  spans,
146294
- (0, import_fs29.statSync)(filePath),
146696
+ (0, import_fs30.statSync)(filePath),
146295
146697
  readFrom,
146296
146698
  endOffset
146297
146699
  );
@@ -146341,6 +146743,7 @@ var StreamerServer = class {
146341
146743
  if (!tailed) this.maybeAttachExternalTail(filePath);
146342
146744
  this.sweepIdleExternalTails();
146343
146745
  this.cache?.invalidateByFilePath(filePath, { skipIfTailed: true });
146746
+ this.staleFiles.add(filePath);
146344
146747
  this.markScannerStaleDebounced();
146345
146748
  this.log.debug?.(`Scanner invalidated by directory event: ${filePath}`, {
146346
146749
  filePath,
@@ -146753,14 +147156,14 @@ var StreamerServer = class {
146753
147156
  }
146754
147157
  this.apnsClient = new ApnsClient(creds);
146755
147158
  const sender = new LiveActivitySender(this.apnsClient, pushRepo);
146756
- const serverId = process.env.THREADBASE_INSTANCE_ID ?? (0, import_os12.hostname)();
146757
- 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)());
146758
147161
  this.liveActivityRenewal = new LiveActivityRenewalScheduler({
146759
147162
  repo: pushRepo,
146760
147163
  sender,
146761
147164
  sessionStore: this.sessionStore,
146762
147165
  serverId,
146763
- serverLabel: (0, import_os12.hostname)()
147166
+ serverLabel: (0, import_os13.hostname)()
146764
147167
  });
146765
147168
  this.liveActivityRenewal.start();
146766
147169
  this.log.info("Live Activity push enabled", {
@@ -147099,7 +147502,7 @@ var StreamerServer = class {
147099
147502
  this.fileWatcher.watchDirectory(dir);
147100
147503
  }
147101
147504
  for (const dir of this.codexRoots) {
147102
- if (!(0, import_fs29.existsSync)(dir)) continue;
147505
+ if (!(0, import_fs30.existsSync)(dir)) continue;
147103
147506
  this.fileWatcher.watchDirectory(dir);
147104
147507
  }
147105
147508
  } catch (err) {
@@ -147372,7 +147775,7 @@ var StreamerServer = class {
147372
147775
  }
147373
147776
  let body;
147374
147777
  try {
147375
- body = await readBody(req);
147778
+ body = await readBody2(req);
147376
147779
  } catch (err) {
147377
147780
  const message = err instanceof Error ? err.message : "Invalid body";
147378
147781
  json2(res, 400, { error: message });
@@ -147418,7 +147821,7 @@ var StreamerServer = class {
147418
147821
  nonce: sealed.nonce,
147419
147822
  ephemeralPublicKey: sealed.ephemeralPublicKey,
147420
147823
  publicUrl: this.publicUrl,
147421
- machineName: (0, import_os12.hostname)(),
147824
+ machineName: (0, import_os13.hostname)(),
147422
147825
  ...device && {
147423
147826
  deviceId: device.deviceId,
147424
147827
  deviceToken: device.deviceToken,
@@ -147546,7 +147949,7 @@ var StreamerServer = class {
147546
147949
  if (this.scanProfiles && this.scanProfiles.length > 0) {
147547
147950
  return this.scanProfiles.filter((p2) => p2.enabled).map((p2) => (0, import_path29.join)(p2.configDir, "projects"));
147548
147951
  }
147549
- return [(0, import_path29.join)((0, import_os12.homedir)(), ".claude", "projects")];
147952
+ return [(0, import_path29.join)((0, import_os13.homedir)(), ".claude", "projects")];
147550
147953
  }
147551
147954
  /**
147552
147955
  * Full-glob scan + cache upsert/delete reconcile. Used by ?refresh=1 and by
@@ -147587,21 +147990,46 @@ var StreamerServer = class {
147587
147990
  // so a burst of list polls during active session writes shares one rescan
147588
147991
  // rather than queueing a full rescan each; tracked so close() awaits the
147589
147992
  // in-flight cache write before shutting the DB.
147590
- startBackgroundConversationReconcile() {
147993
+ startBackgroundConversationReconcile(mode = "full") {
147591
147994
  if (this.conversationReconcileInFlight) return;
147592
- const task = this.reconcileConversationsCacheFromDisk().finally(() => {
147995
+ const paths = mode === "files" ? this.takeStaleFiles() : [];
147996
+ const task = (paths.length > 0 ? this.reconcileStaleFilesFromDisk(paths) : this.reconcileConversationsCacheFromDisk()).finally(() => {
147593
147997
  this.conversationReconcileInFlight = null;
147594
147998
  });
147595
147999
  this.conversationReconcileInFlight = task;
147596
148000
  this.trackCacheWrite(task);
147597
148001
  }
147598
- shouldAutoReconcileConversationList() {
147599
- if (!this.cache) return false;
147600
- if (this.scannerStale) return true;
147601
- if (!this.conversationsRepo || !this.cacheMetadataRepo) return false;
148002
+ // "files": a directory event named specific JSONLs, so refresh only those.
148003
+ // "full": disk drifted in ways a per-file refresh can't see (a project dir
148004
+ // appeared, rows vanished), so walk the tree. Order matters — the staleness
148005
+ // check short-circuits first so the HDD freshness probe stays off the hot
148006
+ // poll path, exactly as it did when this returned a boolean.
148007
+ conversationReconcileMode() {
148008
+ if (!this.cache) return null;
148009
+ if (this.scannerStale) return "files";
148010
+ if (!this.conversationsRepo || !this.cacheMetadataRepo) return null;
147602
148011
  return shouldRefreshProjectsFromHdd(this.conversationsRepo, this.cacheMetadataRepo, {
147603
148012
  projectsDirs: this.projectsDirsForFreshnessCheck()
147604
- });
148013
+ }) ? "full" : null;
148014
+ }
148015
+ // The per-file half of reconcileConversationsCacheFromDisk: re-index just the
148016
+ // changed JSONLs and upsert their rows. No reconcileDeletions here — that
148017
+ // needs the whole live-path set, and deletions already have their own path
148018
+ // (onFileDeleted -> invalidateByFilePath). New projects still arrive via the
148019
+ // HDD-freshness "full" mode.
148020
+ async reconcileStaleFilesFromDisk(paths) {
148021
+ if (!this.cache) return;
148022
+ const scanner = await this.getScanner(true);
148023
+ const metas = await this.refreshStaleFiles(scanner, paths);
148024
+ if (metas.length === 0) return;
148025
+ try {
148026
+ this.cache.upsertFromScannerMeta(metas);
148027
+ } catch (err) {
148028
+ this.log.warn(
148029
+ `stale-file reconcile failed: ${err instanceof Error ? err.message : String(err)}`,
148030
+ { event: "conversations.reconcile_failed" }
148031
+ );
148032
+ }
147605
148033
  }
147606
148034
  async handleListConversations(url2, res) {
147607
148035
  if (this.rejectIfWarmingUp(res)) return;
@@ -147611,10 +148039,11 @@ var StreamerServer = class {
147611
148039
  const project = url2.searchParams.get("project") ?? void 0;
147612
148040
  const providerFilter = url2.searchParams.get("provider") ?? void 0;
147613
148041
  const bustCache = url2.searchParams.get("refresh") === "1";
147614
- if (this.cache && (bustCache || this.shouldAutoReconcileConversationList())) {
148042
+ const reconcileMode = this.conversationReconcileMode();
148043
+ if (this.cache && (bustCache || reconcileMode)) {
147615
148044
  const canServeStale = !bustCache && this.cache.listConversations({ limit: 0, offset: 0 }).total > 0;
147616
148045
  if (canServeStale) {
147617
- this.startBackgroundConversationReconcile();
148046
+ this.startBackgroundConversationReconcile(reconcileMode ?? "full");
147618
148047
  } else {
147619
148048
  const shouldEmitProgress = createScanProgressThrottle();
147620
148049
  await this.withWarmup(
@@ -147814,21 +148243,54 @@ var StreamerServer = class {
147814
148243
  options ?? (this.scannerPersistenceDisabled ? { persistent: false } : void 0)
147815
148244
  );
147816
148245
  }
148246
+ // Drain the stale set and disarm the flag together. The caller owns the
148247
+ // returned paths: clearing before the refresh means events that land DURING
148248
+ // it re-arm the flag and get their own pass instead of being swallowed.
148249
+ takeStaleFiles() {
148250
+ const paths = [...this.staleFiles];
148251
+ this.staleFiles.clear();
148252
+ this.scannerStale = false;
148253
+ return paths;
148254
+ }
148255
+ // Reconcile exactly the JSONLs a directory event named. Failures are logged
148256
+ // and swallowed per file: one unreadable transcript must not abort the
148257
+ // others, and the file simply stays on its previous snapshot until the next
148258
+ // event — the same outcome the full rescan gave on a parse failure.
148259
+ async refreshStaleFiles(scanner, paths) {
148260
+ const metas = await Promise.all(
148261
+ paths.map(
148262
+ (filePath) => scanner.refreshFile(filePath).catch((err) => {
148263
+ this.log.warn("scanner.refreshFile: failed", {
148264
+ event: "scanner.refresh_failed",
148265
+ filePath,
148266
+ trigger: "directory-event",
148267
+ err
148268
+ });
148269
+ return null;
148270
+ })
148271
+ )
148272
+ );
148273
+ return metas.filter((m2) => m2 !== null);
148274
+ }
147817
148275
  async getScanner(skipStaleRescan = false) {
147818
148276
  if (this.scannerReady) {
147819
148277
  await this.scannerReady;
147820
148278
  if (this.scanner) {
147821
148279
  if (skipStaleRescan) return this.scanner;
147822
148280
  if (this.scannerStale) {
147823
- this.scannerStale = false;
147824
- this.scanner = null;
147825
- this.scannerReady = null;
147826
- return this.getScanner();
148281
+ const paths = this.takeStaleFiles();
148282
+ if (paths.length === 0) {
148283
+ this.scanner = null;
148284
+ this.scannerReady = null;
148285
+ return this.getScanner();
148286
+ }
148287
+ await this.refreshStaleFiles(this.scanner, paths);
148288
+ return this.scanner ?? this.getScanner();
147827
148289
  }
147828
148290
  return this.scanner;
147829
148291
  }
147830
148292
  }
147831
- this.scannerStale = false;
148293
+ this.takeStaleFiles();
147832
148294
  const statCache = this.buildStatCache(this.scanner);
147833
148295
  this.scanner = this.newScanner(statCache ? { persistent: false } : void 0);
147834
148296
  this.allScanners.add(this.scanner);
@@ -147862,7 +148324,7 @@ var StreamerServer = class {
147862
148324
  // getScanner() anti-infinite-loop guard is preserved.
147863
148325
  async rescanForRefresh(onProgress) {
147864
148326
  if (this.scannerReady) await this.scannerReady;
147865
- this.scannerStale = false;
148327
+ this.takeStaleFiles();
147866
148328
  if (!this.scanner) {
147867
148329
  this.scanner = new ConversationScanner();
147868
148330
  this.allScanners.add(this.scanner);
@@ -147889,20 +148351,20 @@ var StreamerServer = class {
147889
148351
  if (this.scanProfiles && this.scanProfiles.length > 0) {
147890
148352
  return this.scanProfiles.filter((p2) => p2.enabled).map((p2) => (0, import_path29.join)(p2.configDir, "projects"));
147891
148353
  }
147892
- return [(0, import_path29.join)((0, import_os12.homedir)(), ".claude", "projects")];
148354
+ return [(0, import_path29.join)((0, import_os13.homedir)(), ".claude", "projects")];
147893
148355
  }
147894
148356
  findJsonlPath(uuid3) {
147895
148357
  const filename = `${uuid3}.jsonl`;
147896
148358
  for (const projectsDir of this.projectsDirs()) {
147897
- if (!(0, import_fs29.existsSync)(projectsDir)) continue;
147898
- 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)) {
147899
148361
  const fp = (0, import_path29.join)(projectsDir, dir, filename);
147900
- if ((0, import_fs29.existsSync)(fp)) return fp;
148362
+ if ((0, import_fs30.existsSync)(fp)) return fp;
147901
148363
  const projectDir = (0, import_path29.join)(projectsDir, dir);
147902
148364
  try {
147903
- for (const sub of (0, import_fs29.readdirSync)(projectDir)) {
148365
+ for (const sub of (0, import_fs30.readdirSync)(projectDir)) {
147904
148366
  const subagentPath = (0, import_path29.join)(projectDir, sub, "subagents", filename);
147905
- if ((0, import_fs29.existsSync)(subagentPath)) return subagentPath;
148367
+ if ((0, import_fs30.existsSync)(subagentPath)) return subagentPath;
147906
148368
  }
147907
148369
  } catch {
147908
148370
  }
@@ -147912,7 +148374,7 @@ var StreamerServer = class {
147912
148374
  }
147913
148375
  async readCwdFromJsonl(filePath) {
147914
148376
  return new Promise((resolve4) => {
147915
- 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 });
147916
148378
  let found = false;
147917
148379
  rl.on("line", (line) => {
147918
148380
  if (found) return;
@@ -148002,7 +148464,7 @@ var StreamerServer = class {
148002
148464
  if (this.isManagedTailPath(key)) return;
148003
148465
  let mtimeMs;
148004
148466
  try {
148005
- mtimeMs = (0, import_fs29.statSync)(filePath).mtimeMs;
148467
+ mtimeMs = (0, import_fs30.statSync)(filePath).mtimeMs;
148006
148468
  } catch {
148007
148469
  return;
148008
148470
  }
@@ -148184,7 +148646,7 @@ var StreamerServer = class {
148184
148646
  if (!conv.filePath) return false;
148185
148647
  let mtimeMs = null;
148186
148648
  try {
148187
- mtimeMs = (0, import_fs29.statSync)(conv.filePath).mtimeMs;
148649
+ mtimeMs = (0, import_fs30.statSync)(conv.filePath).mtimeMs;
148188
148650
  } catch {
148189
148651
  return false;
148190
148652
  }
@@ -148439,7 +148901,7 @@ var StreamerServer = class {
148439
148901
  }
148440
148902
  let body;
148441
148903
  try {
148442
- body = await readBody(req);
148904
+ body = await readBody2(req);
148443
148905
  } catch {
148444
148906
  res.setHeader("Accept-Query", "application/json");
148445
148907
  json2(res, 422, { error: "Malformed JSON body", code: "invalid_query" });
@@ -148477,17 +148939,27 @@ var StreamerServer = class {
148477
148939
  });
148478
148940
  }
148479
148941
  async handleSearch(url2, res) {
148480
- const q2 = url2.searchParams.get("q") ?? "";
148481
- if (!q2) {
148482
- json2(res, 400, { error: "Missing query parameter: q" });
148483
- 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;
148484
148951
  }
148485
- const limit = intParam(url2, "limit", 50);
148952
+ const { q: q2, limit, offset, filters } = parsed;
148953
+ const startedAt = Date.now();
148486
148954
  const scanner = await this.getScanner();
148487
148955
  const results = await search(
148488
148956
  q2,
148489
148957
  {
148490
- 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),
148491
148963
  include: "conversations",
148492
148964
  ...this.scanProfiles ? { profiles: this.scanProfiles } : {},
148493
148965
  ...this.codexScanOpts()
@@ -148511,13 +148983,24 @@ var StreamerServer = class {
148511
148983
  lastActivity: r.meta.timestamp,
148512
148984
  firstMessage: r.meta.firstMessage ?? void 0,
148513
148985
  lastMessage: r.meta.lastMessage ?? void 0,
148514
- 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
+ })) : []
148515
148995
  }));
148996
+ const page = paginate(applyFilters(adapted, filters), offset, limit);
148516
148997
  json2(res, 200, {
148517
- conversations: adapted,
148518
- hasMore: false,
148519
- offset: 0,
148520
- 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
148521
149004
  });
148522
149005
  }
148523
149006
  async handleListSessions(url2, res) {
@@ -148563,7 +149046,7 @@ var StreamerServer = class {
148563
149046
  if (this.rejectIfWarmingUp(res)) return;
148564
149047
  const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
148565
149048
  if (session) {
148566
- if (!(0, import_fs29.existsSync)(session.projectPath)) {
149049
+ if (!(0, import_fs30.existsSync)(session.projectPath)) {
148567
149050
  session.failureReason = `Project directory not found: ${session.projectPath}`;
148568
149051
  }
148569
149052
  const reconciled = this.withReconciledLifecycle([session])[0];
@@ -148590,7 +149073,7 @@ var StreamerServer = class {
148590
149073
  json2(res, 404, { error: "Session not found" });
148591
149074
  }
148592
149075
  async handleResume(req, res) {
148593
- const body = await readBody(req);
149076
+ const body = await readBody2(req);
148594
149077
  const sessionId = body.sessionId ?? body.conversationId;
148595
149078
  if (!sessionId) {
148596
149079
  json2(res, 400, { error: "Missing sessionId" });
@@ -148722,7 +149205,7 @@ var StreamerServer = class {
148722
149205
  return;
148723
149206
  }
148724
149207
  if (this.agentConfig.enabled) {
148725
- const body2 = await readBody(req);
149208
+ const body2 = await readBody2(req);
148726
149209
  const cache = this.cache;
148727
149210
  if (!cache) {
148728
149211
  json2(res, 503, {
@@ -148741,7 +149224,7 @@ var StreamerServer = class {
148741
149224
  json2(res, result.status, result.body);
148742
149225
  return;
148743
149226
  }
148744
- const body = await readBody(req);
149227
+ const body = await readBody2(req);
148745
149228
  const { input, keys } = body;
148746
149229
  let idempotencyKey;
148747
149230
  try {
@@ -148905,7 +149388,7 @@ var StreamerServer = class {
148905
149388
  });
148906
149389
  }
148907
149390
  async handleSendAnswer(sessionId, req, res) {
148908
- const body = await readBody(req);
149391
+ const body = await readBody2(req);
148909
149392
  const pending = this.pendingQuestions.get(sessionId);
148910
149393
  const resolution = resolveAnswer(pending, body);
148911
149394
  if (!resolution.ok) {
@@ -148934,7 +149417,7 @@ var StreamerServer = class {
148934
149417
  json2(res, 400, { error: "Session has no project path" });
148935
149418
  return;
148936
149419
  }
148937
- const body = await readBody(req);
149420
+ const body = await readBody2(req);
148938
149421
  const { filename, mimeType, dataBase64 } = body ?? {};
148939
149422
  if (typeof filename !== "string" || typeof mimeType !== "string" || typeof dataBase64 !== "string") {
148940
149423
  json2(res, 400, { error: "Missing filename, mimeType, or dataBase64" });
@@ -149136,7 +149619,7 @@ var StreamerServer = class {
149136
149619
  return;
149137
149620
  }
149138
149621
  if (this.agentConfig.enabled) {
149139
- const body2 = await readBody(req);
149622
+ const body2 = await readBody2(req);
149140
149623
  const result = await handleStartAgentSession(body2, {
149141
149624
  sessionStore: this.sessionStore,
149142
149625
  // biome-ignore lint/style/noNonNullAssertion: agentClient is set when agentConfig.enabled is true
@@ -149150,7 +149633,7 @@ var StreamerServer = class {
149150
149633
  }
149151
149634
  return;
149152
149635
  }
149153
- const body = await readBody(req);
149636
+ const body = await readBody2(req);
149154
149637
  const { path: relativePath, provider: requestedProvider, systemPrompt: clientPrompt } = body;
149155
149638
  if (requestedProvider !== void 0 && !isProviderName(requestedProvider)) {
149156
149639
  json2(res, 400, { error: "Invalid provider" });
@@ -149287,7 +149770,7 @@ var StreamerServer = class {
149287
149770
  // file isn't slurped in full.
149288
149771
  readFirstLineSessionId(filePath) {
149289
149772
  try {
149290
- const content = (0, import_fs29.readFileSync)(filePath, "utf8");
149773
+ const content = (0, import_fs30.readFileSync)(filePath, "utf8");
149291
149774
  const nl = content.indexOf("\n");
149292
149775
  const firstLine = nl === -1 ? content : content.slice(0, nl);
149293
149776
  if (!firstLine.trim()) return null;
@@ -149302,7 +149785,7 @@ var StreamerServer = class {
149302
149785
  // was passed to Claude via --session-id so the filename matches from the start.
149303
149786
  watchForJsonl(sessionId, projectPath) {
149304
149787
  const encoded = projectPath.replace(/[/\\:.]/g, "-");
149305
- 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);
149306
149789
  const expectedFile = `${sessionId}.jsonl`;
149307
149790
  const filePath = (0, import_path29.join)(projectsDir, expectedFile);
149308
149791
  const deadline = Date.now() + 12e4;
@@ -149322,11 +149805,11 @@ var StreamerServer = class {
149322
149805
  cleanup();
149323
149806
  return;
149324
149807
  }
149325
- let resolvedFilePath = (0, import_fs29.existsSync)(filePath) ? filePath : null;
149326
- 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)) {
149327
149810
  try {
149328
149811
  const now = Date.now();
149329
- 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(
149330
149813
  ({ f: f2 }) => (0, import_path29.basename)(f2, ".jsonl") === sessionId || this.readFirstLineSessionId((0, import_path29.join)(projectsDir, f2)) === sessionId
149331
149814
  ).sort((a, b2) => b2.mtime - a.mtime)[0];
149332
149815
  if (match2) resolvedFilePath = (0, import_path29.join)(projectsDir, match2.f);
@@ -149337,7 +149820,7 @@ var StreamerServer = class {
149337
149820
  cleanup();
149338
149821
  this.sessionFileMap.set(sessionId, resolvedFilePath);
149339
149822
  try {
149340
- 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);
149341
149824
  if (existing.length > 0) {
149342
149825
  this.broadcastConversationLines(sessionId, existing);
149343
149826
  }
@@ -149361,7 +149844,7 @@ var StreamerServer = class {
149361
149844
  if (this.sessionFileMap.has(sessionId)) return;
149362
149845
  try {
149363
149846
  require("fs").mkdirSync(projectsDir, { recursive: true });
149364
- watcher = (0, import_fs29.watch)(projectsDir, tryWire);
149847
+ watcher = (0, import_fs30.watch)(projectsDir, tryWire);
149365
149848
  watcher.on("error", cleanup);
149366
149849
  } catch {
149367
149850
  }
@@ -149390,7 +149873,7 @@ var StreamerServer = class {
149390
149873
  };
149391
149874
  const matchesProjectPath = (candidatePath) => {
149392
149875
  try {
149393
- 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];
149394
149877
  if (!firstLine) return null;
149395
149878
  const parsed = JSON.parse(firstLine);
149396
149879
  if (parsed?.type !== "session_meta") return null;
@@ -149419,15 +149902,15 @@ var StreamerServer = class {
149419
149902
  );
149420
149903
  for (const root of this.codexRoots) {
149421
149904
  const sessionsDir = (0, import_path29.join)(root, dateDir);
149422
- if (!(0, import_fs29.existsSync)(sessionsDir)) continue;
149905
+ if (!(0, import_fs30.existsSync)(sessionsDir)) continue;
149423
149906
  let candidateFiles;
149424
149907
  try {
149425
- candidateFiles = (0, import_fs29.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
149908
+ candidateFiles = (0, import_fs30.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
149426
149909
  } catch {
149427
149910
  continue;
149428
149911
  }
149429
149912
  const nowMs = Date.now();
149430
- 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);
149431
149914
  for (const { f: f2 } of recentCandidates) {
149432
149915
  const candidatePath = (0, import_path29.join)(sessionsDir, f2);
149433
149916
  const match2 = matchesProjectPath(candidatePath);
@@ -149439,7 +149922,7 @@ var StreamerServer = class {
149439
149922
  this.sessionFileMap.set(sessionId, candidatePath);
149440
149923
  this.fileWatcher.watch(candidatePath);
149441
149924
  try {
149442
- 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);
149443
149926
  if (existing.length > 0) {
149444
149927
  this.broadcastConversationLines(sessionId, existing);
149445
149928
  }
@@ -149508,7 +149991,7 @@ var StreamerServer = class {
149508
149991
  });
149509
149992
  return;
149510
149993
  }
149511
- const body = await readBody(req);
149994
+ const body = await readBody2(req);
149512
149995
  const { path: relativePath, name } = body;
149513
149996
  if (!name || typeof name !== "string") {
149514
149997
  json2(res, 400, { error: "Missing name field" });
@@ -149538,7 +150021,7 @@ var StreamerServer = class {
149538
150021
  }
149539
150022
  let parsed;
149540
150023
  try {
149541
- parsed = await readBody(req);
150024
+ parsed = await readBody2(req);
149542
150025
  } catch {
149543
150026
  json2(res, 400, { error: "Invalid JSON" });
149544
150027
  return;
@@ -149595,7 +150078,7 @@ var StreamerServer = class {
149595
150078
  }
149596
150079
  let parsed;
149597
150080
  try {
149598
- parsed = await readBody(req);
150081
+ parsed = await readBody2(req);
149599
150082
  } catch {
149600
150083
  json2(res, 400, { error: "Invalid JSON" });
149601
150084
  return;
@@ -149654,7 +150137,7 @@ async function waitForProcessExit(pid, timeoutMs, pollMs = ADOPT_KILL_POLL_MS) {
149654
150137
  }
149655
150138
  function classifyResumability(cwd) {
149656
150139
  if (!cwd) return { resumable: true };
149657
- if ((0, import_fs29.existsSync)(cwd)) return { resumable: true };
150140
+ if ((0, import_fs30.existsSync)(cwd)) return { resumable: true };
149658
150141
  const ranInWorktree = /\/\.worktrees\//.test(cwd) || /\/\.claude\/worktrees\//.test(cwd);
149659
150142
  return {
149660
150143
  resumable: false,
@@ -149772,7 +150255,7 @@ function parseSessionListQuery(url2) {
149772
150255
  const cursor = url2.searchParams.get("cursor") ?? void 0;
149773
150256
  return { query: { limit, sortBy, order, status, cursor } };
149774
150257
  }
149775
- function readBody(req) {
150258
+ function readBody2(req) {
149776
150259
  return new Promise((resolve4, reject) => {
149777
150260
  const chunks = [];
149778
150261
  req.on("data", (chunk) => chunks.push(chunk));
@@ -150324,7 +150807,7 @@ var import_node_fs18 = require("fs");
150324
150807
 
150325
150808
  // node_modules/tar/dist/esm/index.min.js
150326
150809
  var import_events3 = __toESM(require("events"), 1);
150327
- var import_fs30 = __toESM(require("fs"), 1);
150810
+ var import_fs31 = __toESM(require("fs"), 1);
150328
150811
  var import_node_events3 = require("events");
150329
150812
  var import_node_stream2 = __toESM(require("stream"), 1);
150330
150813
  var import_node_string_decoder = require("string_decoder");
@@ -150338,8 +150821,8 @@ var Ps = __toESM(require("zlib"), 1);
150338
150821
  var import_zlib = __toESM(require("zlib"), 1);
150339
150822
  var import_node_path15 = require("path");
150340
150823
  var import_node_path16 = require("path");
150341
- var import_fs31 = __toESM(require("fs"), 1);
150342
150824
  var import_fs32 = __toESM(require("fs"), 1);
150825
+ var import_fs33 = __toESM(require("fs"), 1);
150343
150826
  var import_path31 = __toESM(require("path"), 1);
150344
150827
  var import_node_path17 = require("path");
150345
150828
  var import_path32 = __toESM(require("path"), 1);
@@ -150348,7 +150831,7 @@ var import_node_assert = __toESM(require("assert"), 1);
150348
150831
  var import_node_crypto6 = require("crypto");
150349
150832
  var import_node_fs14 = __toESM(require("fs"), 1);
150350
150833
  var import_node_path18 = __toESM(require("path"), 1);
150351
- var import_fs33 = __toESM(require("fs"), 1);
150834
+ var import_fs34 = __toESM(require("fs"), 1);
150352
150835
  var import_node_fs15 = __toESM(require("fs"), 1);
150353
150836
  var import_node_path19 = __toESM(require("path"), 1);
150354
150837
  var import_node_fs16 = __toESM(require("fs"), 1);
@@ -150700,7 +151183,7 @@ var A = class extends import_node_events3.EventEmitter {
150700
151183
  return Wr;
150701
151184
  }
150702
151185
  };
150703
- var Jr = import_fs30.default.writev;
151186
+ var Jr = import_fs31.default.writev;
150704
151187
  var ht = /* @__PURE__ */ Symbol("_autoClose");
150705
151188
  var H2 = /* @__PURE__ */ Symbol("_close");
150706
151189
  var te = /* @__PURE__ */ Symbol("_ended");
@@ -150755,7 +151238,7 @@ var _t = class extends A {
150755
151238
  throw new TypeError("this is a readable stream");
150756
151239
  }
150757
151240
  [at]() {
150758
- 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));
150759
151242
  }
150760
151243
  [Ht](t, e) {
150761
151244
  t ? this[Ut](t) : (this[u] = e, this.emit("open", e), this[zt]());
@@ -150768,7 +151251,7 @@ var _t = class extends A {
150768
151251
  this[j] = true;
150769
151252
  let t = this[vi]();
150770
151253
  if (t.length === 0) return process.nextTick(() => this[Ii](null, 0, t));
150771
- 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));
150772
151255
  }
150773
151256
  }
150774
151257
  [Ii](t, e, i) {
@@ -150777,7 +151260,7 @@ var _t = class extends A {
150777
151260
  [H2]() {
150778
151261
  if (this[ht] && typeof this[u] == "number") {
150779
151262
  let t = this[u];
150780
- 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"));
150781
151264
  }
150782
151265
  }
150783
151266
  [Ut](t) {
@@ -150805,7 +151288,7 @@ var Be = class extends _t {
150805
151288
  [at]() {
150806
151289
  let t = true;
150807
151290
  try {
150808
- 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;
150809
151292
  } finally {
150810
151293
  t && this[H2]();
150811
151294
  }
@@ -150816,7 +151299,7 @@ var Be = class extends _t {
150816
151299
  if (!this[j]) {
150817
151300
  this[j] = true;
150818
151301
  do {
150819
- 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);
150820
151303
  if (!this[ki](i, e)) break;
150821
151304
  } while (true);
150822
151305
  this[j] = false;
@@ -150829,7 +151312,7 @@ var Be = class extends _t {
150829
151312
  [H2]() {
150830
151313
  if (this[ht] && typeof this[u] == "number") {
150831
151314
  let t = this[u];
150832
- 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");
150833
151316
  }
150834
151317
  }
150835
151318
  };
@@ -150871,7 +151354,7 @@ var et = class extends import_events3.default {
150871
151354
  this[H2](), this[gt] = true, this.emit("error", t);
150872
151355
  }
150873
151356
  [at]() {
150874
- 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));
150875
151358
  }
150876
151359
  [Ht](t, e) {
150877
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]());
@@ -150883,7 +151366,7 @@ var et = class extends import_events3.default {
150883
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);
150884
151367
  }
150885
151368
  [ve](t) {
150886
- 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));
150887
151370
  }
150888
151371
  [Pt](t, e) {
150889
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"))));
@@ -150899,7 +151382,7 @@ var et = class extends import_events3.default {
150899
151382
  [H2]() {
150900
151383
  if (this[ht] && typeof this[u] == "number") {
150901
151384
  let t = this[u];
150902
- 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"));
150903
151386
  }
150904
151387
  }
150905
151388
  };
@@ -150907,24 +151390,24 @@ var Wt = class extends et {
150907
151390
  [at]() {
150908
151391
  let t;
150909
151392
  if (this[Me] && this[tt] === "r+") try {
150910
- t = import_fs30.default.openSync(this[U], this[tt], this[ie]);
151393
+ t = import_fs31.default.openSync(this[U], this[tt], this[ie]);
150911
151394
  } catch (e) {
150912
151395
  if (e?.code === "ENOENT") return this[tt] = "w", this[at]();
150913
151396
  throw e;
150914
151397
  }
150915
- 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]);
150916
151399
  this[Ht](null, t);
150917
151400
  }
150918
151401
  [H2]() {
150919
151402
  if (this[ht] && typeof this[u] == "number") {
150920
151403
  let t = this[u];
150921
- 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");
150922
151405
  }
150923
151406
  }
150924
151407
  [ve](t) {
150925
151408
  let e = true;
150926
151409
  try {
150927
- 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;
150928
151411
  } finally {
150929
151412
  if (e) try {
150930
151413
  this[H2]();
@@ -151842,7 +152325,7 @@ var de = class extends A {
151842
152325
  return t === "error" && (this.#t = true), super.emit(t, ...e);
151843
152326
  }
151844
152327
  [ss]() {
151845
- import_fs32.default.lstat(this.absolute, (t, e) => {
152328
+ import_fs33.default.lstat(this.absolute, (t, e) => {
151846
152329
  if (t) return this.emit("error", t);
151847
152330
  this[si](e);
151848
152331
  });
@@ -151880,7 +152363,7 @@ var de = class extends A {
151880
152363
  this.path.slice(-1) !== "/" && (this.path += "/"), this.stat.size = 0, this[fe](), this.end();
151881
152364
  }
151882
152365
  [is]() {
151883
- import_fs32.default.readlink(this.absolute, (t, e) => {
152366
+ import_fs33.default.readlink(this.absolute, (t, e) => {
151884
152367
  if (t) return this.emit("error", t);
151885
152368
  this[ns](e);
151886
152369
  });
@@ -151903,7 +152386,7 @@ var de = class extends A {
151903
152386
  this[os]();
151904
152387
  }
151905
152388
  [os]() {
151906
- import_fs32.default.open(this.absolute, "r", (t, e) => {
152389
+ import_fs33.default.open(this.absolute, "r", (t, e) => {
151907
152390
  if (t) return this.emit("error", t);
151908
152391
  this[hs](e);
151909
152392
  });
@@ -151918,14 +152401,14 @@ var de = class extends A {
151918
152401
  [ii]() {
151919
152402
  let { fd: t, buf: e, offset: i, length: r, pos: n } = this;
151920
152403
  if (t === void 0 || e === void 0) throw new Error("cannot read file without first opening");
151921
- import_fs32.default.read(t, e, i, r, n, (o, h) => {
152404
+ import_fs33.default.read(t, e, i, r, n, (o, h) => {
151922
152405
  if (o) return this[pt](() => this.emit("error", o));
151923
152406
  this[rs](h);
151924
152407
  });
151925
152408
  }
151926
152409
  [pt](t = () => {
151927
152410
  }) {
151928
- this.fd !== void 0 && import_fs32.default.close(this.fd, t);
152411
+ this.fd !== void 0 && import_fs33.default.close(this.fd, t);
151929
152412
  }
151930
152413
  [rs](t) {
151931
152414
  if (t <= 0 && this.remain > 0) {
@@ -151960,20 +152443,20 @@ var de = class extends A {
151960
152443
  var ni = class extends de {
151961
152444
  sync = true;
151962
152445
  [ss]() {
151963
- this[si](import_fs32.default.lstatSync(this.absolute));
152446
+ this[si](import_fs33.default.lstatSync(this.absolute));
151964
152447
  }
151965
152448
  [is]() {
151966
- this[ns](import_fs32.default.readlinkSync(this.absolute));
152449
+ this[ns](import_fs33.default.readlinkSync(this.absolute));
151967
152450
  }
151968
152451
  [os]() {
151969
- this[hs](import_fs32.default.openSync(this.absolute, "r"));
152452
+ this[hs](import_fs33.default.openSync(this.absolute, "r"));
151970
152453
  }
151971
152454
  [ii]() {
151972
152455
  let t = true;
151973
152456
  try {
151974
152457
  let { fd: e, buf: i, offset: r, length: n, pos: o } = this;
151975
152458
  if (e === void 0 || i === void 0) throw new Error("fd and buf must be set in READ method");
151976
- let h = import_fs32.default.readSync(e, i, r, n, o);
152459
+ let h = import_fs33.default.readSync(e, i, r, n, o);
151977
152460
  this[rs](h), t = false;
151978
152461
  } finally {
151979
152462
  if (t) try {
@@ -151988,7 +152471,7 @@ var ni = class extends de {
151988
152471
  }
151989
152472
  [pt](t = () => {
151990
152473
  }) {
151991
- this.fd !== void 0 && import_fs32.default.closeSync(this.fd), t();
152474
+ this.fd !== void 0 && import_fs33.default.closeSync(this.fd), t();
151992
152475
  }
151993
152476
  };
151994
152477
  var oi = class extends A {
@@ -152319,7 +152802,7 @@ var wt = class extends A {
152319
152802
  [ds](t) {
152320
152803
  t.pending = true, this[G] += 1;
152321
152804
  let e = this.follow ? "stat" : "lstat";
152322
- import_fs31.default[e](t.absolute, (i, r) => {
152805
+ import_fs32.default[e](t.absolute, (i, r) => {
152323
152806
  t.pending = false, this[G] -= 1, i ? this.emit("error", i) : this[li](t, r);
152324
152807
  });
152325
152808
  }
@@ -152333,7 +152816,7 @@ var wt = class extends A {
152333
152816
  this[Ft]();
152334
152817
  }
152335
152818
  [ms](t) {
152336
- 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) => {
152337
152820
  if (t.pending = false, this[G] -= 1, e) return this.emit("error", e);
152338
152821
  this[fi](t, i);
152339
152822
  });
@@ -152434,10 +152917,10 @@ var kt = class extends wt {
152434
152917
  }
152435
152918
  [ds](t) {
152436
152919
  let e = this.follow ? "statSync" : "lstatSync";
152437
- this[li](t, import_fs31.default[e](t.absolute));
152920
+ this[li](t, import_fs32.default[e](t.absolute));
152438
152921
  }
152439
152922
  [ms](t) {
152440
- this[fi](t, import_fs31.default.readdirSync(t.absolute));
152923
+ this[fi](t, import_fs32.default.readdirSync(t.absolute));
152441
152924
  }
152442
152925
  [di](t) {
152443
152926
  let e = t.entry, i = this.zip;
@@ -152488,8 +152971,8 @@ var Qn = K(Vn, $n, Xn, qn, (s3, t) => {
152488
152971
  });
152489
152972
  var Jn = process.env.__FAKE_PLATFORM__ || process.platform;
152490
152973
  var Er = Jn === "win32";
152491
- var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs33.default.constants;
152492
- 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;
152493
152976
  var jn = Er && !!Rr;
152494
152977
  var to = 512 * 1024;
152495
152978
  var eo = Rr | Sr | wr | yr;
@@ -153867,12 +154350,12 @@ program2.command("cache").description("Manage the local SQLite conversation cach
153867
154350
  "Cache directory (default: ~/.threadbase/cache)",
153868
154351
  `${process.env.HOME}/.threadbase/cache`
153869
154352
  ).action((opts) => {
153870
- const { rmSync: rmSync6, existsSync: existsSync15 } = require("fs");
154353
+ const { rmSync: rmSync6, existsSync: existsSync16 } = require("fs");
153871
154354
  const { join: join29 } = require("path");
153872
154355
  const dbPath = join29(opts.cacheDir, "cache.db");
153873
154356
  for (const suffix of ["", "-shm", "-wal"]) {
153874
154357
  const f2 = dbPath + suffix;
153875
- if (existsSync15(f2)) {
154358
+ if (existsSync16(f2)) {
153876
154359
  rmSync6(f2);
153877
154360
  log11.info(`Deleted ${f2}`, { path: f2 }, "console");
153878
154361
  }