@threadbase-sh/streamer 1.20.0 → 1.22.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
@@ -24089,6 +24089,27 @@ var init_zod = __esm({
24089
24089
  }
24090
24090
  });
24091
24091
 
24092
+ // src/lifecycle/constants.ts
24093
+ function installDir() {
24094
+ return process.env.THREADBASE_INSTALL_DIR ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".threadbase");
24095
+ }
24096
+ function markerPath() {
24097
+ return (0, import_node_path3.join)(installDir(), "prod-suspended.json");
24098
+ }
24099
+ function prefsPath() {
24100
+ return (0, import_node_path3.join)(installDir(), "dev-prefs.json");
24101
+ }
24102
+ var import_node_os2, import_node_path3, LAUNCHD_LABEL, TASK_NAME;
24103
+ var init_constants = __esm({
24104
+ "src/lifecycle/constants.ts"() {
24105
+ "use strict";
24106
+ import_node_os2 = require("os");
24107
+ import_node_path3 = require("path");
24108
+ LAUNCHD_LABEL = "com.ronen.threadbase";
24109
+ TASK_NAME = process.env.THREADBASE_TASK_NAME ?? "Threadbase";
24110
+ }
24111
+ });
24112
+
24092
24113
  // node_modules/pino-std-serializers/lib/err-helpers.js
24093
24114
  var require_err_helpers = __commonJS({
24094
24115
  "node_modules/pino-std-serializers/lib/err-helpers.js"(exports2, module2) {
@@ -26078,7 +26099,7 @@ var require_thread_stream = __commonJS({
26078
26099
  var { version: version2 } = require_package();
26079
26100
  var { EventEmitter: EventEmitter6 } = require("events");
26080
26101
  var { Worker: Worker2 } = require("worker_threads");
26081
- var { join: join24 } = require("path");
26102
+ var { join: join26 } = require("path");
26082
26103
  var { pathToFileURL } = require("url");
26083
26104
  var { wait } = require_wait();
26084
26105
  var {
@@ -26129,7 +26150,7 @@ var require_thread_stream = __commonJS({
26129
26150
  function createWorker(stream, opts) {
26130
26151
  const { filename, workerData } = opts;
26131
26152
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
26132
- const toExecute = bundlerOverrides["thread-stream-worker"] || join24(__dirname, "lib", "worker.js");
26153
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join26(__dirname, "lib", "worker.js");
26133
26154
  const worker = new Worker2(toExecute, {
26134
26155
  ...opts.workerOpts,
26135
26156
  name: opts.workerOpts?.name || "thread-stream",
@@ -26597,7 +26618,7 @@ var require_transport = __commonJS({
26597
26618
  var { createRequire } = require("module");
26598
26619
  var { existsSync: existsSync11 } = require("fs");
26599
26620
  var getCallers = require_caller();
26600
- var { join: join24, isAbsolute: isAbsolute3, sep: sep2 } = require("path");
26621
+ var { join: join26, isAbsolute: isAbsolute3, sep: sep2 } = require("path");
26601
26622
  var { fileURLToPath: fileURLToPath3 } = require("url");
26602
26623
  var sleep = require_atomic_sleep();
26603
26624
  var onExit = require_on_exit_leak_free();
@@ -26750,7 +26771,7 @@ var require_transport = __commonJS({
26750
26771
  throw new Error("only one of target or targets can be specified");
26751
26772
  }
26752
26773
  if (targets) {
26753
- target = bundlerOverrides["pino-worker"] || join24(__dirname, "worker.js");
26774
+ target = bundlerOverrides["pino-worker"] || join26(__dirname, "worker.js");
26754
26775
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
26755
26776
  return {
26756
26777
  ...dest,
@@ -26768,7 +26789,7 @@ var require_transport = __commonJS({
26768
26789
  });
26769
26790
  });
26770
26791
  } else if (pipeline2) {
26771
- target = bundlerOverrides["pino-worker"] || join24(__dirname, "worker.js");
26792
+ target = bundlerOverrides["pino-worker"] || join26(__dirname, "worker.js");
26772
26793
  options.pipelines = [pipeline2.map((dest) => {
26773
26794
  return {
26774
26795
  ...dest,
@@ -26791,7 +26812,7 @@ var require_transport = __commonJS({
26791
26812
  return origin;
26792
26813
  }
26793
26814
  if (origin === "pino/file") {
26794
- return join24(__dirname, "..", "file.js");
26815
+ return join26(__dirname, "..", "file.js");
26795
26816
  }
26796
26817
  let fixTarget2;
26797
26818
  for (const filePath of callers) {
@@ -27772,7 +27793,7 @@ var require_safe_stable_stringify = __commonJS({
27772
27793
  return circularValue;
27773
27794
  }
27774
27795
  let res = "";
27775
- let join24 = ",";
27796
+ let join26 = ",";
27776
27797
  const originalIndentation = indentation;
27777
27798
  if (Array.isArray(value)) {
27778
27799
  if (value.length === 0) {
@@ -27786,7 +27807,7 @@ var require_safe_stable_stringify = __commonJS({
27786
27807
  indentation += spacer;
27787
27808
  res += `
27788
27809
  ${indentation}`;
27789
- join24 = `,
27810
+ join26 = `,
27790
27811
  ${indentation}`;
27791
27812
  }
27792
27813
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -27794,13 +27815,13 @@ ${indentation}`;
27794
27815
  for (; i < maximumValuesToStringify - 1; i++) {
27795
27816
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
27796
27817
  res += tmp2 !== void 0 ? tmp2 : "null";
27797
- res += join24;
27818
+ res += join26;
27798
27819
  }
27799
27820
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
27800
27821
  res += tmp !== void 0 ? tmp : "null";
27801
27822
  if (value.length - 1 > maximumBreadth) {
27802
27823
  const removedKeys = value.length - maximumBreadth - 1;
27803
- res += `${join24}"... ${getItemCount(removedKeys)} not stringified"`;
27824
+ res += `${join26}"... ${getItemCount(removedKeys)} not stringified"`;
27804
27825
  }
27805
27826
  if (spacer !== "") {
27806
27827
  res += `
@@ -27821,7 +27842,7 @@ ${originalIndentation}`;
27821
27842
  let separator = "";
27822
27843
  if (spacer !== "") {
27823
27844
  indentation += spacer;
27824
- join24 = `,
27845
+ join26 = `,
27825
27846
  ${indentation}`;
27826
27847
  whitespace = " ";
27827
27848
  }
@@ -27835,13 +27856,13 @@ ${indentation}`;
27835
27856
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
27836
27857
  if (tmp !== void 0) {
27837
27858
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
27838
- separator = join24;
27859
+ separator = join26;
27839
27860
  }
27840
27861
  }
27841
27862
  if (keyLength > maximumBreadth) {
27842
27863
  const removedKeys = keyLength - maximumBreadth;
27843
27864
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
27844
- separator = join24;
27865
+ separator = join26;
27845
27866
  }
27846
27867
  if (spacer !== "" && separator.length > 1) {
27847
27868
  res = `
@@ -27882,7 +27903,7 @@ ${originalIndentation}`;
27882
27903
  }
27883
27904
  const originalIndentation = indentation;
27884
27905
  let res = "";
27885
- let join24 = ",";
27906
+ let join26 = ",";
27886
27907
  if (Array.isArray(value)) {
27887
27908
  if (value.length === 0) {
27888
27909
  return "[]";
@@ -27895,7 +27916,7 @@ ${originalIndentation}`;
27895
27916
  indentation += spacer;
27896
27917
  res += `
27897
27918
  ${indentation}`;
27898
- join24 = `,
27919
+ join26 = `,
27899
27920
  ${indentation}`;
27900
27921
  }
27901
27922
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -27903,13 +27924,13 @@ ${indentation}`;
27903
27924
  for (; i < maximumValuesToStringify - 1; i++) {
27904
27925
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
27905
27926
  res += tmp2 !== void 0 ? tmp2 : "null";
27906
- res += join24;
27927
+ res += join26;
27907
27928
  }
27908
27929
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
27909
27930
  res += tmp !== void 0 ? tmp : "null";
27910
27931
  if (value.length - 1 > maximumBreadth) {
27911
27932
  const removedKeys = value.length - maximumBreadth - 1;
27912
- res += `${join24}"... ${getItemCount(removedKeys)} not stringified"`;
27933
+ res += `${join26}"... ${getItemCount(removedKeys)} not stringified"`;
27913
27934
  }
27914
27935
  if (spacer !== "") {
27915
27936
  res += `
@@ -27922,7 +27943,7 @@ ${originalIndentation}`;
27922
27943
  let whitespace = "";
27923
27944
  if (spacer !== "") {
27924
27945
  indentation += spacer;
27925
- join24 = `,
27946
+ join26 = `,
27926
27947
  ${indentation}`;
27927
27948
  whitespace = " ";
27928
27949
  }
@@ -27931,7 +27952,7 @@ ${indentation}`;
27931
27952
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
27932
27953
  if (tmp !== void 0) {
27933
27954
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
27934
- separator = join24;
27955
+ separator = join26;
27935
27956
  }
27936
27957
  }
27937
27958
  if (spacer !== "" && separator.length > 1) {
@@ -27989,20 +28010,20 @@ ${originalIndentation}`;
27989
28010
  indentation += spacer;
27990
28011
  let res2 = `
27991
28012
  ${indentation}`;
27992
- const join25 = `,
28013
+ const join27 = `,
27993
28014
  ${indentation}`;
27994
28015
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
27995
28016
  let i = 0;
27996
28017
  for (; i < maximumValuesToStringify - 1; i++) {
27997
28018
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
27998
28019
  res2 += tmp2 !== void 0 ? tmp2 : "null";
27999
- res2 += join25;
28020
+ res2 += join27;
28000
28021
  }
28001
28022
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
28002
28023
  res2 += tmp !== void 0 ? tmp : "null";
28003
28024
  if (value.length - 1 > maximumBreadth) {
28004
28025
  const removedKeys = value.length - maximumBreadth - 1;
28005
- res2 += `${join25}"... ${getItemCount(removedKeys)} not stringified"`;
28026
+ res2 += `${join27}"... ${getItemCount(removedKeys)} not stringified"`;
28006
28027
  }
28007
28028
  res2 += `
28008
28029
  ${originalIndentation}`;
@@ -28018,16 +28039,16 @@ ${originalIndentation}`;
28018
28039
  return '"[Object]"';
28019
28040
  }
28020
28041
  indentation += spacer;
28021
- const join24 = `,
28042
+ const join26 = `,
28022
28043
  ${indentation}`;
28023
28044
  let res = "";
28024
28045
  let separator = "";
28025
28046
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
28026
28047
  if (isTypedArrayWithEntries(value)) {
28027
- res += stringifyTypedArray(value, join24, maximumBreadth);
28048
+ res += stringifyTypedArray(value, join26, maximumBreadth);
28028
28049
  keys = keys.slice(value.length);
28029
28050
  maximumPropertiesToStringify -= value.length;
28030
- separator = join24;
28051
+ separator = join26;
28031
28052
  }
28032
28053
  if (deterministic) {
28033
28054
  keys = sort(keys, comparator);
@@ -28038,13 +28059,13 @@ ${indentation}`;
28038
28059
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
28039
28060
  if (tmp !== void 0) {
28040
28061
  res += `${separator}${strEscape(key2)}: ${tmp}`;
28041
- separator = join24;
28062
+ separator = join26;
28042
28063
  }
28043
28064
  }
28044
28065
  if (keyLength > maximumBreadth) {
28045
28066
  const removedKeys = keyLength - maximumBreadth;
28046
28067
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
28047
- separator = join24;
28068
+ separator = join26;
28048
28069
  }
28049
28070
  if (separator !== "") {
28050
28071
  res = `
@@ -124397,27 +124418,6 @@ var require_semver2 = __commonJS({
124397
124418
  }
124398
124419
  });
124399
124420
 
124400
- // src/lifecycle/constants.ts
124401
- function installDir() {
124402
- return process.env.THREADBASE_INSTALL_DIR ?? (0, import_node_path21.join)((0, import_node_os4.homedir)(), ".threadbase");
124403
- }
124404
- function markerPath() {
124405
- return (0, import_node_path21.join)(installDir(), "prod-suspended.json");
124406
- }
124407
- function prefsPath() {
124408
- return (0, import_node_path21.join)(installDir(), "dev-prefs.json");
124409
- }
124410
- var import_node_os4, import_node_path21, LAUNCHD_LABEL, TASK_NAME;
124411
- var init_constants = __esm({
124412
- "src/lifecycle/constants.ts"() {
124413
- "use strict";
124414
- import_node_os4 = require("os");
124415
- import_node_path21 = require("path");
124416
- LAUNCHD_LABEL = "com.ronen.threadbase";
124417
- TASK_NAME = process.env.THREADBASE_TASK_NAME ?? "Threadbase";
124418
- }
124419
- });
124420
-
124421
124421
  // src/lifecycle/launchd.ts
124422
124422
  var launchd_exports = {};
124423
124423
  __export(launchd_exports, {
@@ -124487,8 +124487,8 @@ function darwinPlistPath() {
124487
124487
  return `${process.env.HOME}/Library/LaunchAgents/${resolveLoadedLabel()}.plist`;
124488
124488
  }
124489
124489
  function getLogPaths() {
124490
- const dir = (0, import_node_path22.join)(installDir(), "logs");
124491
- return { stdout: (0, import_node_path22.join)(dir, "stdout.log"), stderr: (0, import_node_path22.join)(dir, "stderr.log") };
124490
+ const dir = (0, import_node_path24.join)(installDir(), "logs");
124491
+ return { stdout: (0, import_node_path24.join)(dir, "stdout.log"), stderr: (0, import_node_path24.join)(dir, "stderr.log") };
124492
124492
  }
124493
124493
  function getAgentPid() {
124494
124494
  try {
@@ -124508,12 +124508,12 @@ function getAgentPid() {
124508
124508
  return null;
124509
124509
  }
124510
124510
  }
124511
- var import_node_child_process4, import_node_path22, BREW_LAUNCHD_LABEL2;
124511
+ var import_node_child_process4, import_node_path24, BREW_LAUNCHD_LABEL2;
124512
124512
  var init_launchd = __esm({
124513
124513
  "src/lifecycle/launchd.ts"() {
124514
124514
  "use strict";
124515
124515
  import_node_child_process4 = require("child_process");
124516
- import_node_path22 = require("path");
124516
+ import_node_path24 = require("path");
124517
124517
  init_constants();
124518
124518
  BREW_LAUNCHD_LABEL2 = "homebrew.mxcl.tb-streamer";
124519
124519
  }
@@ -124538,9 +124538,9 @@ var init_marker_schema = __esm({
124538
124538
 
124539
124539
  // src/lifecycle/marker.ts
124540
124540
  function readMarker() {
124541
- if (!(0, import_node_fs18.existsSync)(markerPath())) return null;
124541
+ if (!(0, import_node_fs20.existsSync)(markerPath())) return null;
124542
124542
  try {
124543
- const raw2 = (0, import_node_fs18.readFileSync)(markerPath(), "utf8");
124543
+ const raw2 = (0, import_node_fs20.readFileSync)(markerPath(), "utf8");
124544
124544
  const parsed = JSON.parse(raw2);
124545
124545
  return MarkerSchema.parse(parsed);
124546
124546
  } catch (err) {
@@ -124552,21 +124552,21 @@ function readMarker() {
124552
124552
  }
124553
124553
  function writeMarker(marker) {
124554
124554
  MarkerSchema.parse(marker);
124555
- (0, import_node_fs18.mkdirSync)((0, import_node_path23.dirname)(markerPath()), { recursive: true });
124555
+ (0, import_node_fs20.mkdirSync)((0, import_node_path25.dirname)(markerPath()), { recursive: true });
124556
124556
  const tmp = `${markerPath()}.tmp`;
124557
- (0, import_node_fs18.writeFileSync)(tmp, `${JSON.stringify(marker, null, 2)}
124557
+ (0, import_node_fs20.writeFileSync)(tmp, `${JSON.stringify(marker, null, 2)}
124558
124558
  `, { mode: 384 });
124559
- (0, import_node_fs18.renameSync)(tmp, markerPath());
124559
+ (0, import_node_fs20.renameSync)(tmp, markerPath());
124560
124560
  }
124561
124561
  function clearMarker() {
124562
- if ((0, import_node_fs18.existsSync)(markerPath())) (0, import_node_fs18.rmSync)(markerPath());
124562
+ if ((0, import_node_fs20.existsSync)(markerPath())) (0, import_node_fs20.rmSync)(markerPath());
124563
124563
  }
124564
- var import_node_fs18, import_node_path23, log3;
124564
+ var import_node_fs20, import_node_path25, log3;
124565
124565
  var init_marker = __esm({
124566
124566
  "src/lifecycle/marker.ts"() {
124567
124567
  "use strict";
124568
- import_node_fs18 = require("fs");
124569
- import_node_path23 = require("path");
124568
+ import_node_fs20 = require("fs");
124569
+ import_node_path25 = require("path");
124570
124570
  init_logger();
124571
124571
  init_constants();
124572
124572
  init_marker_schema();
@@ -124661,9 +124661,9 @@ var init_platform = __esm({
124661
124661
  // src/lifecycle/prefs.ts
124662
124662
  function readPrefs() {
124663
124663
  const path2 = prefsPath();
124664
- if (!(0, import_node_fs20.existsSync)(path2)) return { repos: {} };
124664
+ if (!(0, import_node_fs22.existsSync)(path2)) return { repos: {} };
124665
124665
  try {
124666
- return PrefsSchema.parse(JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8")));
124666
+ return PrefsSchema.parse(JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8")));
124667
124667
  } catch (err) {
124668
124668
  log5.warn(`prefs at ${path2} are malformed; treating as empty`, {
124669
124669
  error: err instanceof Error ? err.message : String(err)
@@ -124673,11 +124673,11 @@ function readPrefs() {
124673
124673
  }
124674
124674
  function savePrefs(p2) {
124675
124675
  const path2 = prefsPath();
124676
- (0, import_node_fs20.mkdirSync)((0, import_node_path24.dirname)(path2), { recursive: true });
124676
+ (0, import_node_fs22.mkdirSync)((0, import_node_path26.dirname)(path2), { recursive: true });
124677
124677
  const tmp = `${path2}.tmp`;
124678
- (0, import_node_fs20.writeFileSync)(tmp, `${JSON.stringify(p2, null, 2)}
124678
+ (0, import_node_fs22.writeFileSync)(tmp, `${JSON.stringify(p2, null, 2)}
124679
124679
  `, { mode: 384 });
124680
- (0, import_node_fs20.renameSync)(tmp, path2);
124680
+ (0, import_node_fs22.renameSync)(tmp, path2);
124681
124681
  }
124682
124682
  function writePrefForRepo(repoToplevel, choice) {
124683
124683
  const p2 = readPrefs();
@@ -124698,14 +124698,14 @@ function forgetRepo(repoToplevel) {
124698
124698
  }
124699
124699
  function forgetAll() {
124700
124700
  const path2 = prefsPath();
124701
- if ((0, import_node_fs20.existsSync)(path2)) (0, import_node_fs20.rmSync)(path2);
124701
+ if ((0, import_node_fs22.existsSync)(path2)) (0, import_node_fs22.rmSync)(path2);
124702
124702
  }
124703
- var import_node_fs20, import_node_path24, log5, PrefsSchema;
124703
+ var import_node_fs22, import_node_path26, log5, PrefsSchema;
124704
124704
  var init_prefs = __esm({
124705
124705
  "src/lifecycle/prefs.ts"() {
124706
124706
  "use strict";
124707
- import_node_fs20 = require("fs");
124708
- import_node_path24 = require("path");
124707
+ import_node_fs22 = require("fs");
124708
+ import_node_path26 = require("path");
124709
124709
  init_zod();
124710
124710
  init_logger();
124711
124711
  init_constants();
@@ -124927,7 +124927,7 @@ __export(setKey_exports, {
124927
124927
  async function defaultReadStdin() {
124928
124928
  return new Promise((resolve6, reject) => {
124929
124929
  const chunks = [];
124930
- process.stdin.on("data", (chunk) => chunks.push(chunk));
124930
+ process.stdin.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
124931
124931
  process.stdin.on("end", () => resolve6(Buffer.concat(chunks).toString("utf-8")));
124932
124932
  process.stdin.on("error", reject);
124933
124933
  });
@@ -128384,6 +128384,23 @@ function loadUpdateConfig(opts = {}) {
128384
128384
  return UpdateConfigSchema.parse(parsed);
128385
128385
  }
128386
128386
 
128387
+ // src/devLog.ts
128388
+ var import_node_fs3 = require("fs");
128389
+ var import_node_path4 = require("path");
128390
+ init_constants();
128391
+ function devLogPath() {
128392
+ return (0, import_node_path4.join)(installDir(), "logs", "dev.log");
128393
+ }
128394
+ function appendDevSessionMarker() {
128395
+ try {
128396
+ const path2 = devLogPath();
128397
+ (0, import_node_fs3.mkdirSync)((0, import_node_path4.join)(installDir(), "logs"), { recursive: true });
128398
+ (0, import_node_fs3.appendFileSync)(path2, `=== dev session started ${(/* @__PURE__ */ new Date()).toISOString()} ===
128399
+ `, "utf8");
128400
+ } catch {
128401
+ }
128402
+ }
128403
+
128387
128404
  // src/lan-url.ts
128388
128405
  var import_os2 = require("os");
128389
128406
  function resolveServerUrl({ publicUrl, port }) {
@@ -129428,7 +129445,7 @@ var sysPath2 = __toESM(require("path"), 1);
129428
129445
  // node_modules/@threadbase-sh/scanner/node_modules/readdirp/esm/index.js
129429
129446
  var import_promises = require("fs/promises");
129430
129447
  var import_node_stream = require("stream");
129431
- var import_node_path3 = require("path");
129448
+ var import_node_path5 = require("path");
129432
129449
  var EntryTypes = {
129433
129450
  FILE_TYPE: "files",
129434
129451
  DIR_TYPE: "directories",
@@ -129503,7 +129520,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
129503
129520
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
129504
129521
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
129505
129522
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
129506
- this._root = (0, import_node_path3.resolve)(root);
129523
+ this._root = (0, import_node_path5.resolve)(root);
129507
129524
  this._isDirent = !opts.alwaysStat;
129508
129525
  this._statsProp = this._isDirent ? "dirent" : "stats";
129509
129526
  this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
@@ -129574,8 +129591,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
129574
129591
  let entry;
129575
129592
  const basename9 = this._isDirent ? dirent.name : dirent;
129576
129593
  try {
129577
- const fullPath = (0, import_node_path3.resolve)((0, import_node_path3.join)(path2, basename9));
129578
- entry = { path: (0, import_node_path3.relative)(this._root, fullPath), fullPath, basename: basename9 };
129594
+ const fullPath = (0, import_node_path5.resolve)((0, import_node_path5.join)(path2, basename9));
129595
+ entry = { path: (0, import_node_path5.relative)(this._root, fullPath), fullPath, basename: basename9 };
129579
129596
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
129580
129597
  } catch (err) {
129581
129598
  this._onError(err);
@@ -129609,7 +129626,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
129609
129626
  }
129610
129627
  if (entryRealPathStats.isDirectory()) {
129611
129628
  const len = entryRealPath.length;
129612
- if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path3.sep) {
129629
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path5.sep) {
129613
129630
  const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
129614
129631
  recursiveError.code = RECURSIVE_ERROR_CODE;
129615
129632
  return this._onError(recursiveError);
@@ -134045,7 +134062,7 @@ function readAgentConfig(env = process.env) {
134045
134062
 
134046
134063
  // src/agent/conversation-writer.ts
134047
134064
  var import_promises7 = require("fs/promises");
134048
- var import_node_path4 = require("path");
134065
+ var import_node_path6 = require("path");
134049
134066
  function createConversationWriter(opts) {
134050
134067
  const { baseDir } = opts;
134051
134068
  return {
@@ -134053,8 +134070,8 @@ function createConversationWriter(opts) {
134053
134070
  if (!args.content || args.content.length === 0) {
134054
134071
  throw new Error("ConversationWriter: refusing to write empty assistant turn");
134055
134072
  }
134056
- const file2 = (0, import_node_path4.join)(baseDir, `${args.sessionId}.jsonl`);
134057
- await (0, import_promises7.mkdir)((0, import_node_path4.dirname)(file2), { recursive: true });
134073
+ const file2 = (0, import_node_path6.join)(baseDir, `${args.sessionId}.jsonl`);
134074
+ await (0, import_promises7.mkdir)((0, import_node_path6.dirname)(file2), { recursive: true });
134058
134075
  const record2 = {
134059
134076
  role: "assistant",
134060
134077
  turnId: args.turnId,
@@ -134253,8 +134270,8 @@ async function handleSendAgentInput(sessionId, body, deps) {
134253
134270
  }
134254
134271
 
134255
134272
  // src/agent/handle-start-agent-session.ts
134256
- var import_node_fs3 = require("fs");
134257
- var import_node_path5 = require("path");
134273
+ var import_node_fs4 = require("fs");
134274
+ var import_node_path7 = require("path");
134258
134275
  function validateBody(body) {
134259
134276
  if (body === null || body === void 0 || typeof body !== "object") {
134260
134277
  return { ok: false };
@@ -134284,8 +134301,8 @@ async function handleStartAgentSession(body, deps) {
134284
134301
  }
134285
134302
  let conversationId = parsed.conversationId;
134286
134303
  if (conversationId) {
134287
- const jsonlPath = (0, import_node_path5.join)(deps.conversationsDir, `${conversationId}.jsonl`);
134288
- if (!(0, import_node_fs3.existsSync)(jsonlPath)) {
134304
+ const jsonlPath = (0, import_node_path7.join)(deps.conversationsDir, `${conversationId}.jsonl`);
134305
+ if (!(0, import_node_fs4.existsSync)(jsonlPath)) {
134289
134306
  return {
134290
134307
  status: 404,
134291
134308
  body: agentErrorResponse(
@@ -136445,13 +136462,23 @@ var authMiddleware = (deps) => async (c, next) => {
136445
136462
  };
136446
136463
 
136447
136464
  // src/api/middleware/cors.middleware.ts
136465
+ var ALLOWED_ORIGINS = /* @__PURE__ */ new Set([
136466
+ "http://localhost:8081",
136467
+ "http://localhost:19006",
136468
+ "http://localhost:3000"
136469
+ ]);
136448
136470
  var corsMiddleware = () => async (c, next) => {
136449
- c.res.headers.set("Access-Control-Allow-Origin", "*");
136450
- c.res.headers.set("Access-Control-Allow-Methods", "GET, POST, PATCH, OPTIONS");
136451
- c.res.headers.set("Access-Control-Allow-Headers", "Authorization, Content-Type, If-None-Match");
136452
- c.res.headers.set("Access-Control-Expose-Headers", "ETag");
136471
+ const origin = c.req.header("origin");
136472
+ const allowedOrigin = origin && ALLOWED_ORIGINS.has(origin) ? origin : null;
136473
+ if (allowedOrigin) {
136474
+ c.res.headers.set("Access-Control-Allow-Origin", allowedOrigin);
136475
+ c.res.headers.set("Vary", "Origin");
136476
+ c.res.headers.set("Access-Control-Allow-Methods", "GET, POST, PATCH, OPTIONS");
136477
+ c.res.headers.set("Access-Control-Allow-Headers", "Authorization, Content-Type, If-None-Match");
136478
+ c.res.headers.set("Access-Control-Expose-Headers", "ETag");
136479
+ }
136453
136480
  if (c.req.method === "OPTIONS") {
136454
- return c.newResponse(null, 204);
136481
+ return c.newResponse(null, allowedOrigin ? 204 : 403);
136455
136482
  }
136456
136483
  await next();
136457
136484
  };
@@ -136505,8 +136532,8 @@ var createConversationRoutes = (deps) => {
136505
136532
  };
136506
136533
 
136507
136534
  // src/version.ts
136508
- var import_node_fs4 = require("fs");
136509
- var import_node_path6 = require("path");
136535
+ var import_node_fs5 = require("fs");
136536
+ var import_node_path8 = require("path");
136510
136537
  var cached2;
136511
136538
  function getVersion() {
136512
136539
  if (cached2 !== void 0) return cached2;
@@ -136515,22 +136542,22 @@ function getVersion() {
136515
136542
  }
136516
136543
  function resolveVersion() {
136517
136544
  const scriptPath = process.argv[1] ?? "";
136518
- const here = scriptPath ? (0, import_node_path6.dirname)(scriptPath) : process.cwd();
136545
+ const here = scriptPath ? (0, import_node_path8.dirname)(scriptPath) : process.cwd();
136519
136546
  let realHere = here;
136520
136547
  try {
136521
- realHere = (0, import_node_path6.dirname)((0, import_node_fs4.realpathSync)(scriptPath));
136548
+ realHere = (0, import_node_path8.dirname)((0, import_node_fs5.realpathSync)(scriptPath));
136522
136549
  } catch {
136523
136550
  }
136524
- const searchDirs = realHere === here ? [here, (0, import_node_path6.join)(here, "..")] : [here, (0, import_node_path6.join)(here, ".."), realHere, (0, import_node_path6.join)(realHere, "..")];
136551
+ 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, "..")];
136525
136552
  for (const dir of searchDirs) {
136526
136553
  try {
136527
- const v3 = (0, import_node_fs4.readFileSync)((0, import_node_path6.join)(dir, "version.txt"), "utf8").trim();
136554
+ const v3 = (0, import_node_fs5.readFileSync)((0, import_node_path8.join)(dir, "version.txt"), "utf8").trim();
136528
136555
  if (v3) return v3;
136529
136556
  } catch {
136530
136557
  }
136531
136558
  }
136532
136559
  try {
136533
- const pkg = JSON.parse((0, import_node_fs4.readFileSync)((0, import_node_path6.join)(here, "..", "package.json"), "utf8"));
136560
+ const pkg = JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path8.join)(here, "..", "package.json"), "utf8"));
136534
136561
  if (pkg.version) return `${pkg.version}+source`;
136535
136562
  } catch {
136536
136563
  }
@@ -136595,6 +136622,19 @@ var createMiscRoutes = (deps) => {
136595
136622
  });
136596
136623
  });
136597
136624
  app.get("/api/profiles", (c) => c.json([]));
136625
+ app.post("/api/auth/rotate", (c) => {
136626
+ if (deps.localNoAuth) {
136627
+ return c.json({ error: "key rotation is disabled while localNoAuth is active" }, 403);
136628
+ }
136629
+ const { newKey, persisted } = deps.rotateApiKey();
136630
+ return c.json({
136631
+ apiKey: newKey,
136632
+ persisted,
136633
+ ...persisted ? {} : {
136634
+ warning: "Key rotated in memory only. The server was started with --api-key, so the old key will be restored on restart. Remove --api-key and let the server manage the key via ~/.threadbase/server.yaml for rotation to survive restarts."
136635
+ }
136636
+ });
136637
+ });
136598
136638
  app.post("/api/push/register", (c) => c.json({ ok: true }));
136599
136639
  app.post("/api/__update", async (c) => {
136600
136640
  const cfg = loadUpdateConfig();
@@ -136796,6 +136836,11 @@ var ALREADY_HANDLED4 = 597;
136796
136836
  var alreadyHandled4 = () => new Response(null, { status: ALREADY_HANDLED4 });
136797
136837
  var createProjectRoutes = (deps) => {
136798
136838
  const app = new Hono2();
136839
+ app.get("/", (c) => {
136840
+ const url2 = new URL(c.req.url);
136841
+ deps.handleListProjects(url2, c.env.outgoing);
136842
+ return alreadyHandled4();
136843
+ });
136799
136844
  app.get("/popular", (c) => {
136800
136845
  const url2 = new URL(c.req.url);
136801
136846
  deps.handleGetPopularProjects(url2, c.env.outgoing);
@@ -136814,11 +136859,6 @@ var createScannerRoutes = (deps) => {
136814
136859
  await deps.handleSearch(url2, c.env.outgoing);
136815
136860
  return alreadyHandled5();
136816
136861
  });
136817
- app.get("/project-chats", async (c) => {
136818
- const url2 = new URL(c.req.url);
136819
- await deps.handleListProjectChats(url2, c.env.outgoing);
136820
- return alreadyHandled5();
136821
- });
136822
136862
  return app;
136823
136863
  };
136824
136864
 
@@ -138082,517 +138122,39 @@ async function recordUpload(pool2, instanceId, row) {
138082
138122
  );
138083
138123
  }
138084
138124
 
138085
- // src/schemas/queryParams.schema.ts
138086
- init_zod();
138087
- var ListProjectChatsQuerySchema = external_exports.object({
138088
- refresh: external_exports.enum(["1"]).optional(),
138089
- refreshConversations: external_exports.enum(["1"]).optional()
138090
- });
138091
-
138092
- // src/services/cache/cacheMetadata.ts
138093
- function getCacheMetadata(repo, key) {
138094
- return repo.getCacheMetadata(key);
138095
- }
138096
- function setCacheMetadata(repo, key, value) {
138097
- repo.setCacheMetadata(key, value);
138098
- }
138099
-
138100
- // node_modules/date-fns/constants.js
138101
- var daysInYear = 365.2425;
138102
- var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1e3;
138103
- var minTime = -maxTime;
138104
- var millisecondsInMinute = 6e4;
138105
- var millisecondsInHour = 36e5;
138106
- var secondsInHour = 3600;
138107
- var secondsInDay = secondsInHour * 24;
138108
- var secondsInWeek = secondsInDay * 7;
138109
- var secondsInYear = secondsInDay * daysInYear;
138110
- var secondsInMonth = secondsInYear / 12;
138111
- var secondsInQuarter = secondsInMonth * 3;
138112
- var constructFromSymbol = /* @__PURE__ */ Symbol.for("constructDateFrom");
138113
-
138114
- // node_modules/date-fns/constructFrom.js
138115
- function constructFrom(date5, value) {
138116
- if (typeof date5 === "function") return date5(value);
138117
- if (date5 && typeof date5 === "object" && constructFromSymbol in date5)
138118
- return date5[constructFromSymbol](value);
138119
- if (date5 instanceof Date) return new date5.constructor(value);
138120
- return new Date(value);
138121
- }
138122
-
138123
- // node_modules/date-fns/toDate.js
138124
- function toDate(argument, context) {
138125
- return constructFrom(context || argument, argument);
138126
- }
138127
-
138128
- // node_modules/date-fns/compareDesc.js
138129
- function compareDesc(dateLeft, dateRight) {
138130
- const diff = +toDate(dateLeft) - +toDate(dateRight);
138131
- if (diff > 0) return -1;
138132
- else if (diff < 0) return 1;
138133
- return diff;
138134
- }
138135
-
138136
- // node_modules/date-fns/isDate.js
138137
- function isDate(value) {
138138
- return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
138139
- }
138140
-
138141
- // node_modules/date-fns/isValid.js
138142
- function isValid(date5) {
138143
- return !(!isDate(date5) && typeof date5 !== "number" || isNaN(+toDate(date5)));
138144
- }
138145
-
138146
- // node_modules/date-fns/parseISO.js
138147
- function parseISO(argument, options) {
138148
- const invalidDate = () => constructFrom(options?.in, NaN);
138149
- const additionalDigits = options?.additionalDigits ?? 2;
138150
- const dateStrings = splitDateString(argument);
138151
- let date5;
138152
- if (dateStrings.date) {
138153
- const parseYearResult = parseYear(dateStrings.date, additionalDigits);
138154
- date5 = parseDate(parseYearResult.restDateString, parseYearResult.year);
138155
- }
138156
- if (!date5 || isNaN(+date5)) return invalidDate();
138157
- const timestamp = +date5;
138158
- let time3 = 0;
138159
- let offset;
138160
- if (dateStrings.time) {
138161
- time3 = parseTime(dateStrings.time);
138162
- if (isNaN(time3)) return invalidDate();
138163
- }
138164
- if (dateStrings.timezone) {
138165
- offset = parseTimezone(dateStrings.timezone);
138166
- if (isNaN(offset)) return invalidDate();
138167
- } else {
138168
- const tmpDate = new Date(timestamp + time3);
138169
- const result = toDate(0, options?.in);
138170
- result.setFullYear(
138171
- tmpDate.getUTCFullYear(),
138172
- tmpDate.getUTCMonth(),
138173
- tmpDate.getUTCDate()
138174
- );
138175
- result.setHours(
138176
- tmpDate.getUTCHours(),
138177
- tmpDate.getUTCMinutes(),
138178
- tmpDate.getUTCSeconds(),
138179
- tmpDate.getUTCMilliseconds()
138180
- );
138181
- return result;
138182
- }
138183
- return toDate(timestamp + time3 + offset, options?.in);
138184
- }
138185
- var patterns = {
138186
- dateTimeDelimiter: /[T ]/,
138187
- timeZoneDelimiter: /[Z ]/i,
138188
- timezone: /([Z+-].*)$/
138189
- };
138190
- var dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
138191
- var timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
138192
- var timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
138193
- function splitDateString(dateString) {
138194
- const dateStrings = {};
138195
- const array2 = dateString.split(patterns.dateTimeDelimiter);
138196
- let timeString;
138197
- if (array2.length > 2) {
138198
- return dateStrings;
138199
- }
138200
- if (/:/.test(array2[0])) {
138201
- timeString = array2[0];
138202
- } else {
138203
- dateStrings.date = array2[0];
138204
- timeString = array2[1];
138205
- if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
138206
- dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
138207
- timeString = dateString.substr(
138208
- dateStrings.date.length,
138209
- dateString.length
138210
- );
138211
- }
138212
- }
138213
- if (timeString) {
138214
- const token = patterns.timezone.exec(timeString);
138215
- if (token) {
138216
- dateStrings.time = timeString.replace(token[1], "");
138217
- dateStrings.timezone = token[1];
138218
- } else {
138219
- dateStrings.time = timeString;
138220
- }
138221
- }
138222
- return dateStrings;
138223
- }
138224
- function parseYear(dateString, additionalDigits) {
138225
- const regex = new RegExp(
138226
- "^(?:(\\d{4}|[+-]\\d{" + (4 + additionalDigits) + "})|(\\d{2}|[+-]\\d{" + (2 + additionalDigits) + "})$)"
138227
- );
138228
- const captures = dateString.match(regex);
138229
- if (!captures) return { year: NaN, restDateString: "" };
138230
- const year = captures[1] ? parseInt(captures[1]) : null;
138231
- const century = captures[2] ? parseInt(captures[2]) : null;
138232
- return {
138233
- year: century === null ? year : century * 100,
138234
- restDateString: dateString.slice((captures[1] || captures[2]).length)
138235
- };
138236
- }
138237
- function parseDate(dateString, year) {
138238
- if (year === null) return /* @__PURE__ */ new Date(NaN);
138239
- const captures = dateString.match(dateRegex);
138240
- if (!captures) return /* @__PURE__ */ new Date(NaN);
138241
- const isWeekDate = !!captures[4];
138242
- const dayOfYear = parseDateUnit(captures[1]);
138243
- const month = parseDateUnit(captures[2]) - 1;
138244
- const day = parseDateUnit(captures[3]);
138245
- const week = parseDateUnit(captures[4]);
138246
- const dayOfWeek = parseDateUnit(captures[5]) - 1;
138247
- if (isWeekDate) {
138248
- if (!validateWeekDate(year, week, dayOfWeek)) {
138249
- return /* @__PURE__ */ new Date(NaN);
138250
- }
138251
- return dayOfISOWeekYear(year, week, dayOfWeek);
138252
- } else {
138253
- const date5 = /* @__PURE__ */ new Date(0);
138254
- if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
138255
- return /* @__PURE__ */ new Date(NaN);
138256
- }
138257
- date5.setUTCFullYear(year, month, Math.max(dayOfYear, day));
138258
- return date5;
138259
- }
138260
- }
138261
- function parseDateUnit(value) {
138262
- return value ? parseInt(value) : 1;
138263
- }
138264
- function parseTime(timeString) {
138265
- const captures = timeString.match(timeRegex);
138266
- if (!captures) return NaN;
138267
- const hours = parseTimeUnit(captures[1]);
138268
- const minutes = parseTimeUnit(captures[2]);
138269
- const seconds = parseTimeUnit(captures[3]);
138270
- if (!validateTime(hours, minutes, seconds)) {
138271
- return NaN;
138272
- }
138273
- return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1e3;
138274
- }
138275
- function parseTimeUnit(value) {
138276
- return value && parseFloat(value.replace(",", ".")) || 0;
138277
- }
138278
- function parseTimezone(timezoneString) {
138279
- if (timezoneString === "Z") return 0;
138280
- const captures = timezoneString.match(timezoneRegex);
138281
- if (!captures) return 0;
138282
- const sign = captures[1] === "+" ? -1 : 1;
138283
- const hours = parseInt(captures[2]);
138284
- const minutes = captures[3] && parseInt(captures[3]) || 0;
138285
- if (!validateTimezone(hours, minutes)) {
138286
- return NaN;
138287
- }
138288
- return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
138289
- }
138290
- function dayOfISOWeekYear(isoWeekYear, week, day) {
138291
- const date5 = /* @__PURE__ */ new Date(0);
138292
- date5.setUTCFullYear(isoWeekYear, 0, 4);
138293
- const fourthOfJanuaryDay = date5.getUTCDay() || 7;
138294
- const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
138295
- date5.setUTCDate(date5.getUTCDate() + diff);
138296
- return date5;
138297
- }
138298
- var daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
138299
- function isLeapYearIndex(year) {
138300
- return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
138301
- }
138302
- function validateDate(year, month, date5) {
138303
- return month >= 0 && month <= 11 && date5 >= 1 && date5 <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
138304
- }
138305
- function validateDayOfYearDate(year, dayOfYear) {
138306
- return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
138307
- }
138308
- function validateWeekDate(_year, week, day) {
138309
- return week >= 1 && week <= 53 && day >= 0 && day <= 6;
138310
- }
138311
- function validateTime(hours, minutes, seconds) {
138312
- if (hours === 24) {
138313
- return minutes === 0 && seconds === 0;
138314
- }
138315
- return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
138316
- }
138317
- function validateTimezone(_hours, minutes) {
138318
- return minutes >= 0 && minutes <= 59;
138319
- }
138320
-
138321
- // src/utils/dates.ts
138322
- function parseIsoDateOrNull(value) {
138323
- if (!value) return null;
138324
- const parsed = parseISO(value);
138325
- return isValid(parsed) ? parsed : null;
138326
- }
138327
- function compareIsoDesc(a, b2) {
138328
- const dateA = parseIsoDateOrNull(a);
138329
- const dateB = parseIsoDateOrNull(b2);
138330
- if (!dateA && !dateB) return 0;
138331
- if (!dateA) return 1;
138332
- if (!dateB) return -1;
138333
- return compareDesc(dateA, dateB);
138334
- }
138335
-
138336
- // src/services/projects/ensureProjectsForConversations.ts
138337
- function ensureProjectsForConversations(repo, conversations) {
138338
- const conversationsByPath = /* @__PURE__ */ new Map();
138339
- for (const conversation of conversations) {
138340
- if (!conversation.projectPath) continue;
138341
- const canonical = canonicalizeProjectPath(conversation.projectPath);
138342
- if (!canonical) continue;
138343
- const existing = conversationsByPath.get(canonical) ?? [];
138344
- existing.push(conversation);
138345
- conversationsByPath.set(canonical, existing);
138346
- }
138347
- const pathToProjectId = /* @__PURE__ */ new Map();
138348
- for (const [path2, projectConversations] of conversationsByPath) {
138349
- const latest = pickLatestConversation(projectConversations);
138350
- const project = repo.upsertProjectByPath(path2, {
138351
- lastConversationId: latest?.id ?? null,
138352
- lastConversationCreatedAt: latest?.createdAt ?? null,
138353
- latestMessageAt: latest?.latestMessageAt ?? null
138354
- });
138355
- pathToProjectId.set(path2, project.id);
138356
- }
138357
- return pathToProjectId;
138358
- }
138359
- function pickLatestConversation(conversations) {
138360
- if (conversations.length === 0) return void 0;
138361
- return [...conversations].sort((a, b2) => {
138362
- const cmp = compareIsoDesc(a.latestMessageAt ?? null, b2.latestMessageAt ?? null);
138363
- if (cmp !== 0) return cmp;
138364
- return compareIsoDesc(a.createdAt ?? null, b2.createdAt ?? null);
138365
- })[0];
138366
- }
138367
-
138368
- // src/services/conversations/refreshConversationCache.ts
138369
- function refreshConversationCache(deps) {
138370
- const { projectsRepo, conversationsRepo, cacheMetadataRepo } = deps;
138371
- const conversations = conversationsRepo.listConversationsForProjectBackfill();
138372
- const pathToProjectId = ensureProjectsForConversations(
138373
- projectsRepo,
138374
- conversations.map((c) => ({
138375
- id: c.id,
138376
- projectPath: c.projectPath,
138377
- latestMessageAt: c.lastActivity ?? null,
138378
- createdAt: c.lastActivity ?? null
138379
- }))
138380
- );
138381
- let conversationsBackfilled = 0;
138382
- for (const conversation of conversations) {
138383
- if (!conversation.projectPath) continue;
138384
- if (conversation.projectId) continue;
138385
- const projectId = pathToProjectId.get(canonicalizeProjectPath(conversation.projectPath));
138386
- if (!projectId) continue;
138387
- conversationsRepo.updateConversationProjectId({
138388
- conversationId: conversation.id,
138389
- projectId
138390
- });
138391
- conversationsBackfilled += 1;
138392
- }
138393
- const latest = conversationsRepo.getLatestConversation();
138394
- if (latest) {
138395
- setCacheMetadata(cacheMetadataRepo, "last_conversation_id", latest.id);
138396
- if (latest.lastActivity) {
138397
- setCacheMetadata(cacheMetadataRepo, "last_conversation_created_at", latest.lastActivity);
138398
- }
138399
- }
138400
- setCacheMetadata(cacheMetadataRepo, "conversations_last_indexed_at", (/* @__PURE__ */ new Date()).toISOString());
138401
- return {
138402
- projectsTouched: pathToProjectId.size,
138403
- conversationsBackfilled,
138404
- latestConversationId: latest?.id ?? null
138405
- };
138406
- }
138407
-
138408
- // src/services/conversations/shouldRefreshProjectsFromHdd.ts
138125
+ // src/handlers/handleListProjects.ts
138409
138126
  var import_fs18 = require("fs");
138410
138127
  var import_os7 = require("os");
138411
138128
  var import_path14 = require("path");
138412
- var DEFAULT_PROJECTS_DIR = (0, import_path14.join)((0, import_os7.homedir)(), ".claude", "projects");
138413
- function shouldRefreshProjectsFromHdd(conversationsRepo, cacheMetadataRepo, opts = {}) {
138414
- if (conversationsRepo.hasOrphanRows()) return true;
138415
- const projectsDir = opts.projectsDir ?? DEFAULT_PROJECTS_DIR;
138416
- let dirMtimeMs;
138129
+ function decodeProjectPath(dirName) {
138130
+ return dirName.replace(/-/g, "/");
138131
+ }
138132
+ function handleListProjects(url2, res) {
138133
+ const limit = Math.max(1, parseInt(url2.searchParams.get("limit") ?? "50", 10) || 50);
138134
+ const offset = Math.max(0, parseInt(url2.searchParams.get("offset") ?? "0", 10) || 0);
138135
+ const projectsDir = (0, import_path14.join)((0, import_os7.homedir)(), ".claude", "projects");
138136
+ let entries;
138417
138137
  try {
138418
- dirMtimeMs = (0, import_fs18.statSync)(projectsDir).mtimeMs;
138138
+ entries = (0, import_fs18.readdirSync)(projectsDir).map((dirName) => {
138139
+ const fullPath = (0, import_path14.join)(projectsDir, dirName);
138140
+ let mtime = 0;
138141
+ try {
138142
+ mtime = (0, import_fs18.statSync)(fullPath).mtimeMs;
138143
+ } catch {
138144
+ }
138145
+ const path2 = decodeProjectPath(dirName);
138146
+ const name = path2.split("/").filter(Boolean).pop() ?? dirName;
138147
+ return { name, path: path2, dirName, mtime };
138148
+ }).sort((a, b2) => b2.mtime - a.mtime);
138419
138149
  } catch {
138420
- return false;
138421
- }
138422
- const lastIndexedIso = getCacheMetadata(cacheMetadataRepo, "conversations_last_indexed_at");
138423
- if (!lastIndexedIso) return true;
138424
- const lastIndexedMs = Date.parse(lastIndexedIso);
138425
- if (Number.isNaN(lastIndexedMs)) return true;
138426
- return dirMtimeMs > lastIndexedMs;
138427
- }
138428
-
138429
- // src/services/sessions/ensureSessionProjectIdsFromExistingProjects.ts
138430
- function ensureSessionProjectIdsFromExistingProjects(projectsRepo, sessionsRepo) {
138431
- let linked = 0;
138432
- let missing = 0;
138433
- for (const session of sessionsRepo.listManagedSessions()) {
138434
- if (session.projectId) continue;
138435
- const canonical = canonicalizeProjectPath(session.projectPath);
138436
- if (!canonical) continue;
138437
- const project = projectsRepo.getProjectByPath(canonical);
138438
- if (!project) {
138439
- missing += 1;
138440
- continue;
138441
- }
138442
- sessionsRepo.updateSessionProjectId({ sessionId: session.id, projectId: project.id });
138443
- linked += 1;
138444
- }
138445
- return { linked, missing };
138446
- }
138447
-
138448
- // src/services/projectChats/sortProjectChats.ts
138449
- function sortProjectChats(a, b2) {
138450
- const byLatest = compareIsoDesc(a.latestMessageAt, b2.latestMessageAt);
138451
- if (byLatest !== 0) return byLatest;
138452
- const byUpdated = compareIsoDesc(a.updatedAt ?? null, b2.updatedAt ?? null);
138453
- if (byUpdated !== 0) return byUpdated;
138454
- const byCreated = compareIsoDesc(a.createdAt ?? null, b2.createdAt ?? null);
138455
- if (byCreated !== 0) return byCreated;
138456
- return a.title.localeCompare(b2.title);
138457
- }
138458
-
138459
- // src/services/projectChats/mergeProjectChats.ts
138460
- function mergeProjectChats(args) {
138461
- const { sessions, conversations } = args;
138462
- const resumedConversationIds = new Set(
138463
- sessions.filter((c) => c.type === "session").map((c) => c.resumedFromConversationId).filter((id) => Boolean(id))
138464
- );
138465
- const visibleConversations = conversations.filter((c) => {
138466
- if (c.type !== "conversation") return true;
138467
- return !resumedConversationIds.has(c.id);
138468
- });
138469
- return [...sessions, ...visibleConversations].sort(sortProjectChats);
138470
- }
138471
-
138472
- // src/services/projectChats/deriveProjectChatTitle.ts
138473
- function deriveProjectChatTitle(input) {
138474
- const trimmed = input.title?.trim();
138475
- if (trimmed) return trimmed;
138476
- const name = input.projectName?.trim();
138477
- if (name) return name;
138478
- const pathSuffix = input.projectPath ? input.projectPath.split(/[/\\]/).filter(Boolean).slice(-2).join("/") : "";
138479
- if (pathSuffix) return pathSuffix;
138480
- return `Untitled \xB7 ${input.id.slice(0, 8)}`;
138481
- }
138482
-
138483
- // src/services/projectChats/normalizeConversationToProjectChat.ts
138484
- function normalizeConversationToProjectChat(conversation) {
138485
- if (!conversation.projectId) {
138486
- throw new Error(
138487
- `normalizeConversationToProjectChat: conversation ${conversation.id} has no projectId \u2014 resolve it before normalizing`
138488
- );
138489
- }
138490
- return {
138491
- type: "conversation",
138492
- id: conversation.id,
138493
- projectId: conversation.projectId,
138494
- projectPath: conversation.projectPath ?? null,
138495
- title: deriveProjectChatTitle({
138496
- title: conversation.title,
138497
- projectName: conversation.projectName,
138498
- projectPath: conversation.projectPath,
138499
- id: conversation.id
138500
- }),
138501
- latestMessageAt: conversation.lastActivity ?? null,
138502
- updatedAt: conversation.lastActivity ?? null,
138503
- createdAt: null,
138504
- status: "resumable",
138505
- source: "hdd-cache",
138506
- provider: conversation.provider ?? CLAUDE_CODE_PROVIDER2,
138507
- indexedAt: null,
138508
- fileMtime: null,
138509
- filePath: conversation.filePath ?? null,
138510
- sourceHash: null
138511
- };
138512
- }
138513
-
138514
- // src/services/projectChats/normalizeSessionToProjectChat.ts
138515
- function normalizeSessionToProjectChat(session) {
138516
- if (!session.projectId) {
138517
- throw new Error(
138518
- `normalizeSessionToProjectChat: session ${session.id} has no projectId \u2014 resolve it before normalizing`
138519
- );
138520
- }
138521
- return {
138522
- type: "session",
138523
- id: session.id,
138524
- projectId: session.projectId,
138525
- projectPath: session.projectPath ?? null,
138526
- title: deriveProjectChatTitle({
138527
- title: session.sessionName,
138528
- projectName: session.projectName,
138529
- projectPath: session.projectPath,
138530
- id: session.id
138531
- }),
138532
- latestMessageAt: session.lastMessageAt ?? session.lastActivityAt ?? null,
138533
- updatedAt: session.lastActivityAt ?? null,
138534
- createdAt: session.startedAt ?? null,
138535
- status: "active",
138536
- source: "session-store",
138537
- resumedFromConversationId: session.resumedFromConversationId ?? null
138538
- };
138539
- }
138540
-
138541
- // src/services/projectChats/listProjectChats.ts
138542
- async function listProjectChats(deps, args) {
138543
- const {
138544
- cache,
138545
- projectsRepo,
138546
- conversationsRepo,
138547
- sessionsRepo,
138548
- cacheMetadataRepo,
138549
- getSessionResponses,
138550
- getFreshScanner,
138551
- projectsDir
138552
- } = deps;
138553
- const needsRefresh = args.refreshConversations || shouldRefreshProjectsFromHdd(conversationsRepo, cacheMetadataRepo, { projectsDir });
138554
- if (needsRefresh) {
138555
- const scanner = await getFreshScanner();
138556
- const metas = [...scanner.getMetadataCache().values()];
138557
- if (metas.length > 0) {
138558
- cache.upsertFromScannerMeta(metas);
138559
- }
138560
- refreshConversationCache({ cache, projectsRepo, conversationsRepo, cacheMetadataRepo });
138561
- }
138562
- ensureSessionProjectIdsFromExistingProjects(projectsRepo, sessionsRepo);
138563
- const sessionResponses = getSessionResponses();
138564
- const sessionChats = [];
138565
- for (const s3 of sessionResponses) {
138566
- if (!s3.projectId) continue;
138567
- sessionChats.push(normalizeSessionToProjectChat(s3));
138568
- }
138569
- const conversationChats = [];
138570
- const { conversations } = cache.listConversations({ limit: 1e3, offset: 0 });
138571
- for (const c of conversations) {
138572
- if (!c.projectId) continue;
138573
- conversationChats.push(normalizeConversationToProjectChat(c));
138574
- }
138575
- return mergeProjectChats({ sessions: sessionChats, conversations: conversationChats });
138576
- }
138577
-
138578
- // src/handlers/handleListProjectChats.ts
138579
- async function handleListProjectChats(url2, res, deps) {
138580
- const queryObj = Object.fromEntries(url2.searchParams.entries());
138581
- const parsed = ListProjectChatsQuerySchema.safeParse(queryObj);
138582
- if (!parsed.success) {
138583
- res.writeHead(400, { "Content-Type": "application/json" });
138584
- res.end(
138585
- JSON.stringify({
138586
- error: "Invalid query parameters",
138587
- details: parsed.error.flatten()
138588
- })
138589
- );
138150
+ res.writeHead(200, { "Content-Type": "application/json" });
138151
+ res.end(JSON.stringify({ projects: [], total: 0 }));
138590
138152
  return;
138591
138153
  }
138592
- const refreshConversations = parsed.data.refreshConversations === "1" || parsed.data.refresh === "1";
138593
- const chats = await listProjectChats(deps, { refreshConversations });
138154
+ const total = entries.length;
138155
+ const page = entries.slice(offset, offset + limit).map(({ name, path: path2, dirName }) => ({ name, path: path2, dirName }));
138594
138156
  res.writeHead(200, { "Content-Type": "application/json" });
138595
- res.end(JSON.stringify({ projectChats: chats }));
138157
+ res.end(JSON.stringify({ projects: page, total }));
138596
138158
  }
138597
138159
 
138598
138160
  // src/server.ts
@@ -139632,13 +139194,13 @@ function seal(plaintext, recipientPublicKeyBase64) {
139632
139194
 
139633
139195
  // node_modules/chokidar/index.js
139634
139196
  var import_node_events2 = require("events");
139635
- var import_node_fs6 = require("fs");
139197
+ var import_node_fs7 = require("fs");
139636
139198
  var import_promises11 = require("fs/promises");
139637
139199
  var sp2 = __toESM(require("path"), 1);
139638
139200
 
139639
139201
  // node_modules/readdirp/index.js
139640
139202
  var import_promises9 = require("fs/promises");
139641
- var import_node_path7 = require("path");
139203
+ var import_node_path9 = require("path");
139642
139204
  var import_node_stream2 = require("stream");
139643
139205
  var EntryTypes2 = {
139644
139206
  FILE_TYPE: "files",
@@ -139728,7 +139290,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139728
139290
  this._wantsDir = type ? DIR_TYPES2.has(type) : false;
139729
139291
  this._wantsFile = type ? FILE_TYPES2.has(type) : false;
139730
139292
  this._wantsEverything = type === EntryTypes2.EVERYTHING_TYPE;
139731
- this._root = (0, import_node_path7.resolve)(root);
139293
+ this._root = (0, import_node_path9.resolve)(root);
139732
139294
  this._isDirent = !opts.alwaysStat;
139733
139295
  this._statsProp = this._isDirent ? "dirent" : "stats";
139734
139296
  this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
@@ -139799,8 +139361,8 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139799
139361
  let entry;
139800
139362
  const basename9 = this._isDirent ? dirent.name : dirent;
139801
139363
  try {
139802
- const fullPath = (0, import_node_path7.resolve)((0, import_node_path7.join)(path2, basename9));
139803
- entry = { path: (0, import_node_path7.relative)(this._root, fullPath), fullPath, basename: basename9 };
139364
+ const fullPath = (0, import_node_path9.resolve)((0, import_node_path9.join)(path2, basename9));
139365
+ entry = { path: (0, import_node_path9.relative)(this._root, fullPath), fullPath, basename: basename9 };
139804
139366
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
139805
139367
  } catch (err) {
139806
139368
  this._onError(err);
@@ -139834,7 +139396,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139834
139396
  }
139835
139397
  if (entryRealPathStats.isDirectory()) {
139836
139398
  const len = entryRealPath.length;
139837
- if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path7.sep) {
139399
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path9.sep) {
139838
139400
  const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
139839
139401
  recursiveError.code = RECURSIVE_ERROR_CODE2;
139840
139402
  return this._onError(recursiveError);
@@ -139870,9 +139432,9 @@ function readdirp2(root, options = {}) {
139870
139432
  }
139871
139433
 
139872
139434
  // node_modules/chokidar/handler.js
139873
- var import_node_fs5 = require("fs");
139435
+ var import_node_fs6 = require("fs");
139874
139436
  var import_promises10 = require("fs/promises");
139875
- var import_node_os2 = require("os");
139437
+ var import_node_os3 = require("os");
139876
139438
  var sp = __toESM(require("path"), 1);
139877
139439
  var STR_DATA2 = "data";
139878
139440
  var STR_END2 = "end";
@@ -139884,7 +139446,7 @@ var isWindows3 = pl2 === "win32";
139884
139446
  var isMacos2 = pl2 === "darwin";
139885
139447
  var isLinux2 = pl2 === "linux";
139886
139448
  var isFreeBSD2 = pl2 === "freebsd";
139887
- var isIBMi2 = (0, import_node_os2.type)() === "OS400";
139449
+ var isIBMi2 = (0, import_node_os3.type)() === "OS400";
139888
139450
  var EVENTS2 = {
139889
139451
  ALL: "all",
139890
139452
  READY: "ready",
@@ -140208,7 +139770,7 @@ function createFsWatchInstance2(path2, options, listener, errHandler, emitRaw) {
140208
139770
  }
140209
139771
  };
140210
139772
  try {
140211
- return (0, import_node_fs5.watch)(path2, {
139773
+ return (0, import_node_fs6.watch)(path2, {
140212
139774
  persistent: options.persistent
140213
139775
  }, handleEvent);
140214
139776
  } catch (error51) {
@@ -140291,7 +139853,7 @@ var setFsWatchFileListener2 = (path2, fullPath, options, handlers) => {
140291
139853
  let cont = FsWatchFileInstances2.get(fullPath);
140292
139854
  const copts = cont && cont.options;
140293
139855
  if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
140294
- (0, import_node_fs5.unwatchFile)(fullPath);
139856
+ (0, import_node_fs6.unwatchFile)(fullPath);
140295
139857
  cont = void 0;
140296
139858
  }
140297
139859
  if (cont) {
@@ -140302,7 +139864,7 @@ var setFsWatchFileListener2 = (path2, fullPath, options, handlers) => {
140302
139864
  listeners: listener,
140303
139865
  rawEmitters: rawEmitter,
140304
139866
  options,
140305
- watcher: (0, import_node_fs5.watchFile)(fullPath, options, (curr, prev) => {
139867
+ watcher: (0, import_node_fs6.watchFile)(fullPath, options, (curr, prev) => {
140306
139868
  foreach2(cont.rawEmitters, (rawEmitter2) => {
140307
139869
  rawEmitter2(EV2.CHANGE, fullPath, { curr, prev });
140308
139870
  });
@@ -140319,7 +139881,7 @@ var setFsWatchFileListener2 = (path2, fullPath, options, handlers) => {
140319
139881
  delFromSet2(cont, KEY_RAW2, rawEmitter);
140320
139882
  if (isEmptySet2(cont.listeners)) {
140321
139883
  FsWatchFileInstances2.delete(fullPath);
140322
- (0, import_node_fs5.unwatchFile)(fullPath);
139884
+ (0, import_node_fs6.unwatchFile)(fullPath);
140323
139885
  cont.options = cont.watcher = void 0;
140324
139886
  Object.freeze(cont);
140325
139887
  }
@@ -141189,7 +140751,7 @@ var FSWatcher2 = class extends import_node_events2.EventEmitter {
141189
140751
  const now = /* @__PURE__ */ new Date();
141190
140752
  const writes = this._pendingWrites;
141191
140753
  function awaitWriteFinishFn(prevStat) {
141192
- (0, import_node_fs6.stat)(fullPath, (err, curStat) => {
140754
+ (0, import_node_fs7.stat)(fullPath, (err, curStat) => {
141193
140755
  if (err || !writes.has(path2)) {
141194
140756
  if (err && err.code !== "ENOENT")
141195
140757
  awfEmit(err);
@@ -141512,6 +141074,17 @@ function pruneAgentConversations(cache) {
141512
141074
  return { scanned: rows.length, pruned, missing };
141513
141075
  }
141514
141076
 
141077
+ // src/services/projectChats/deriveProjectChatTitle.ts
141078
+ function deriveProjectChatTitle(input) {
141079
+ const trimmed = input.title?.trim();
141080
+ if (trimmed) return trimmed;
141081
+ const name = input.projectName?.trim();
141082
+ if (name) return name;
141083
+ const pathSuffix = input.projectPath ? input.projectPath.split(/[/\\]/).filter(Boolean).slice(-2).join("/") : "";
141084
+ if (pathSuffix) return pathSuffix;
141085
+ return `Untitled \xB7 ${input.id.slice(0, 8)}`;
141086
+ }
141087
+
141515
141088
  // src/services/questions/detectAskUserQuestion.ts
141516
141089
  function normalizeContent2(raw2) {
141517
141090
  if (Array.isArray(raw2)) return raw2;
@@ -141941,6 +141514,226 @@ function debounce(fn, waitMs) {
141941
141514
  return debounced;
141942
141515
  }
141943
141516
 
141517
+ // node_modules/date-fns/constants.js
141518
+ var daysInYear = 365.2425;
141519
+ var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1e3;
141520
+ var minTime = -maxTime;
141521
+ var millisecondsInMinute = 6e4;
141522
+ var millisecondsInHour = 36e5;
141523
+ var secondsInHour = 3600;
141524
+ var secondsInDay = secondsInHour * 24;
141525
+ var secondsInWeek = secondsInDay * 7;
141526
+ var secondsInYear = secondsInDay * daysInYear;
141527
+ var secondsInMonth = secondsInYear / 12;
141528
+ var secondsInQuarter = secondsInMonth * 3;
141529
+ var constructFromSymbol = /* @__PURE__ */ Symbol.for("constructDateFrom");
141530
+
141531
+ // node_modules/date-fns/constructFrom.js
141532
+ function constructFrom(date5, value) {
141533
+ if (typeof date5 === "function") return date5(value);
141534
+ if (date5 && typeof date5 === "object" && constructFromSymbol in date5)
141535
+ return date5[constructFromSymbol](value);
141536
+ if (date5 instanceof Date) return new date5.constructor(value);
141537
+ return new Date(value);
141538
+ }
141539
+
141540
+ // node_modules/date-fns/toDate.js
141541
+ function toDate(argument, context) {
141542
+ return constructFrom(context || argument, argument);
141543
+ }
141544
+
141545
+ // node_modules/date-fns/isDate.js
141546
+ function isDate(value) {
141547
+ return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
141548
+ }
141549
+
141550
+ // node_modules/date-fns/isValid.js
141551
+ function isValid(date5) {
141552
+ return !(!isDate(date5) && typeof date5 !== "number" || isNaN(+toDate(date5)));
141553
+ }
141554
+
141555
+ // node_modules/date-fns/parseISO.js
141556
+ function parseISO(argument, options) {
141557
+ const invalidDate = () => constructFrom(options?.in, NaN);
141558
+ const additionalDigits = options?.additionalDigits ?? 2;
141559
+ const dateStrings = splitDateString(argument);
141560
+ let date5;
141561
+ if (dateStrings.date) {
141562
+ const parseYearResult = parseYear(dateStrings.date, additionalDigits);
141563
+ date5 = parseDate(parseYearResult.restDateString, parseYearResult.year);
141564
+ }
141565
+ if (!date5 || isNaN(+date5)) return invalidDate();
141566
+ const timestamp = +date5;
141567
+ let time3 = 0;
141568
+ let offset;
141569
+ if (dateStrings.time) {
141570
+ time3 = parseTime(dateStrings.time);
141571
+ if (isNaN(time3)) return invalidDate();
141572
+ }
141573
+ if (dateStrings.timezone) {
141574
+ offset = parseTimezone(dateStrings.timezone);
141575
+ if (isNaN(offset)) return invalidDate();
141576
+ } else {
141577
+ const tmpDate = new Date(timestamp + time3);
141578
+ const result = toDate(0, options?.in);
141579
+ result.setFullYear(
141580
+ tmpDate.getUTCFullYear(),
141581
+ tmpDate.getUTCMonth(),
141582
+ tmpDate.getUTCDate()
141583
+ );
141584
+ result.setHours(
141585
+ tmpDate.getUTCHours(),
141586
+ tmpDate.getUTCMinutes(),
141587
+ tmpDate.getUTCSeconds(),
141588
+ tmpDate.getUTCMilliseconds()
141589
+ );
141590
+ return result;
141591
+ }
141592
+ return toDate(timestamp + time3 + offset, options?.in);
141593
+ }
141594
+ var patterns = {
141595
+ dateTimeDelimiter: /[T ]/,
141596
+ timeZoneDelimiter: /[Z ]/i,
141597
+ timezone: /([Z+-].*)$/
141598
+ };
141599
+ var dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
141600
+ var timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
141601
+ var timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
141602
+ function splitDateString(dateString) {
141603
+ const dateStrings = {};
141604
+ const array2 = dateString.split(patterns.dateTimeDelimiter);
141605
+ let timeString;
141606
+ if (array2.length > 2) {
141607
+ return dateStrings;
141608
+ }
141609
+ if (/:/.test(array2[0])) {
141610
+ timeString = array2[0];
141611
+ } else {
141612
+ dateStrings.date = array2[0];
141613
+ timeString = array2[1];
141614
+ if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
141615
+ dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
141616
+ timeString = dateString.substr(
141617
+ dateStrings.date.length,
141618
+ dateString.length
141619
+ );
141620
+ }
141621
+ }
141622
+ if (timeString) {
141623
+ const token = patterns.timezone.exec(timeString);
141624
+ if (token) {
141625
+ dateStrings.time = timeString.replace(token[1], "");
141626
+ dateStrings.timezone = token[1];
141627
+ } else {
141628
+ dateStrings.time = timeString;
141629
+ }
141630
+ }
141631
+ return dateStrings;
141632
+ }
141633
+ function parseYear(dateString, additionalDigits) {
141634
+ const regex = new RegExp(
141635
+ "^(?:(\\d{4}|[+-]\\d{" + (4 + additionalDigits) + "})|(\\d{2}|[+-]\\d{" + (2 + additionalDigits) + "})$)"
141636
+ );
141637
+ const captures = dateString.match(regex);
141638
+ if (!captures) return { year: NaN, restDateString: "" };
141639
+ const year = captures[1] ? parseInt(captures[1]) : null;
141640
+ const century = captures[2] ? parseInt(captures[2]) : null;
141641
+ return {
141642
+ year: century === null ? year : century * 100,
141643
+ restDateString: dateString.slice((captures[1] || captures[2]).length)
141644
+ };
141645
+ }
141646
+ function parseDate(dateString, year) {
141647
+ if (year === null) return /* @__PURE__ */ new Date(NaN);
141648
+ const captures = dateString.match(dateRegex);
141649
+ if (!captures) return /* @__PURE__ */ new Date(NaN);
141650
+ const isWeekDate = !!captures[4];
141651
+ const dayOfYear = parseDateUnit(captures[1]);
141652
+ const month = parseDateUnit(captures[2]) - 1;
141653
+ const day = parseDateUnit(captures[3]);
141654
+ const week = parseDateUnit(captures[4]);
141655
+ const dayOfWeek = parseDateUnit(captures[5]) - 1;
141656
+ if (isWeekDate) {
141657
+ if (!validateWeekDate(year, week, dayOfWeek)) {
141658
+ return /* @__PURE__ */ new Date(NaN);
141659
+ }
141660
+ return dayOfISOWeekYear(year, week, dayOfWeek);
141661
+ } else {
141662
+ const date5 = /* @__PURE__ */ new Date(0);
141663
+ if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
141664
+ return /* @__PURE__ */ new Date(NaN);
141665
+ }
141666
+ date5.setUTCFullYear(year, month, Math.max(dayOfYear, day));
141667
+ return date5;
141668
+ }
141669
+ }
141670
+ function parseDateUnit(value) {
141671
+ return value ? parseInt(value) : 1;
141672
+ }
141673
+ function parseTime(timeString) {
141674
+ const captures = timeString.match(timeRegex);
141675
+ if (!captures) return NaN;
141676
+ const hours = parseTimeUnit(captures[1]);
141677
+ const minutes = parseTimeUnit(captures[2]);
141678
+ const seconds = parseTimeUnit(captures[3]);
141679
+ if (!validateTime(hours, minutes, seconds)) {
141680
+ return NaN;
141681
+ }
141682
+ return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1e3;
141683
+ }
141684
+ function parseTimeUnit(value) {
141685
+ return value && parseFloat(value.replace(",", ".")) || 0;
141686
+ }
141687
+ function parseTimezone(timezoneString) {
141688
+ if (timezoneString === "Z") return 0;
141689
+ const captures = timezoneString.match(timezoneRegex);
141690
+ if (!captures) return 0;
141691
+ const sign = captures[1] === "+" ? -1 : 1;
141692
+ const hours = parseInt(captures[2]);
141693
+ const minutes = captures[3] && parseInt(captures[3]) || 0;
141694
+ if (!validateTimezone(hours, minutes)) {
141695
+ return NaN;
141696
+ }
141697
+ return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
141698
+ }
141699
+ function dayOfISOWeekYear(isoWeekYear, week, day) {
141700
+ const date5 = /* @__PURE__ */ new Date(0);
141701
+ date5.setUTCFullYear(isoWeekYear, 0, 4);
141702
+ const fourthOfJanuaryDay = date5.getUTCDay() || 7;
141703
+ const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
141704
+ date5.setUTCDate(date5.getUTCDate() + diff);
141705
+ return date5;
141706
+ }
141707
+ var daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
141708
+ function isLeapYearIndex(year) {
141709
+ return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
141710
+ }
141711
+ function validateDate(year, month, date5) {
141712
+ return month >= 0 && month <= 11 && date5 >= 1 && date5 <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
141713
+ }
141714
+ function validateDayOfYearDate(year, dayOfYear) {
141715
+ return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
141716
+ }
141717
+ function validateWeekDate(_year, week, day) {
141718
+ return week >= 1 && week <= 53 && day >= 0 && day <= 6;
141719
+ }
141720
+ function validateTime(hours, minutes, seconds) {
141721
+ if (hours === 24) {
141722
+ return minutes === 0 && seconds === 0;
141723
+ }
141724
+ return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
141725
+ }
141726
+ function validateTimezone(_hours, minutes) {
141727
+ return minutes >= 0 && minutes <= 59;
141728
+ }
141729
+
141730
+ // src/utils/dates.ts
141731
+ function parseIsoDateOrNull(value) {
141732
+ if (!value) return null;
141733
+ const parsed = parseISO(value);
141734
+ return isValid(parsed) ? parsed : null;
141735
+ }
141736
+
141944
141737
  // src/utils/isScannedSnapshotStale.ts
141945
141738
  var STALENESS_TOLERANCE_MS = 1e3;
141946
141739
  function isScannedSnapshotStale(snapshotTimestamp, fileMtimeMs) {
@@ -142116,6 +141909,7 @@ var StreamerServer = class {
142116
141909
  binding = false;
142117
141910
  cacheReady = false;
142118
141911
  apiKey;
141912
+ apiKeySource;
142119
141913
  localNoAuth;
142120
141914
  logMenubarRequests;
142121
141915
  verbose;
@@ -142127,6 +141921,8 @@ var StreamerServer = class {
142127
141921
  publicUrl = null;
142128
141922
  pairTokens = new PairTokenStore();
142129
141923
  exchangeAttempts = /* @__PURE__ */ new Map();
141924
+ sessionStartAttempts = /* @__PURE__ */ new Map();
141925
+ sessionInputAttempts = /* @__PURE__ */ new Map();
142130
141926
  ptyGracePeriodMs;
142131
141927
  defaultSystemPrompt;
142132
141928
  // Map of sessionId → grace timer; fires to kill PTY after WS disconnect
@@ -142162,8 +141958,14 @@ var StreamerServer = class {
142162
141958
  constructor(config2) {
142163
141959
  this.sessionStatusBus.setMaxListeners(0);
142164
141960
  this.apiKey = config2.apiKey;
141961
+ this.apiKeySource = config2.apiKeySource ?? "config";
142165
141962
  this.localNoAuth = config2.localNoAuth ?? false;
142166
141963
  this.logMenubarRequests = config2.logMenubarRequests ?? false;
141964
+ if (this.localNoAuth) {
141965
+ console.warn(
141966
+ "[WARN] localNoAuth is ENABLED \u2014 all requests from localhost bypass authentication. Do not run with --local-no-auth in shared or production environments."
141967
+ );
141968
+ }
142167
141969
  this.verbose = config2.verbose ?? false;
142168
141970
  this.disableDb = config2.disableDb ?? false;
142169
141971
  this.scanProfiles = config2.scanProfiles;
@@ -142341,10 +142143,15 @@ var StreamerServer = class {
142341
142143
  });
142342
142144
  }
142343
142145
  const agentClient = this.agentClient;
142146
+ const self2 = this;
142344
142147
  const apiDeps = {
142345
- apiKey: this.apiKey,
142148
+ // ponytail: getter so rotateApiKey() takes effect without restarting the server
142149
+ get apiKey() {
142150
+ return self2.apiKey;
142151
+ },
142346
142152
  localNoAuth: this.localNoAuth,
142347
142153
  logMenubarRequests: this.logMenubarRequests,
142154
+ rotateApiKey: () => this.rotateApiKey(),
142348
142155
  publicUrl: this.publicUrl,
142349
142156
  browseRoot: this.browseRoot,
142350
142157
  ptyManager: this.ptyManager,
@@ -142375,8 +142182,8 @@ var StreamerServer = class {
142375
142182
  handleConversationsCount: (url2, res) => this.handleConversationsCount(url2, res),
142376
142183
  handleGetConversation: (id, url2, res, ifNoneMatch) => this.handleGetConversation(id, url2, res, ifNoneMatch),
142377
142184
  handleSearch: (url2, res) => this.handleSearch(url2, res),
142185
+ handleListProjects: (url2, res) => handleListProjects(url2, res),
142378
142186
  handleGetPopularProjects: (url2, res) => this.handleGetPopularProjects(url2, res),
142379
- handleListProjectChats: (url2, res) => this.handleListProjectChats(url2, res),
142380
142187
  handlePairStart: (res) => this.handlePairStart(res),
142381
142188
  handlePairExchange: (req, res) => this.handlePairExchange(req, res),
142382
142189
  handleBrowse: (url2, res) => this.handleBrowse(url2, res),
@@ -142811,19 +142618,45 @@ var StreamerServer = class {
142811
142618
  machineName: hostname4()
142812
142619
  });
142813
142620
  }
142814
- checkExchangeRateLimit(ip) {
142621
+ rotateApiKey() {
142622
+ const oldKey = this.apiKey;
142623
+ const newKey = generateApiKey();
142624
+ const persisted = this.apiKeySource === "config";
142625
+ if (persisted) setApiKey(newKey);
142626
+ this.apiKey = newKey;
142627
+ this.log.info("API key rotated", {
142628
+ event: "auth.api_key_rotated",
142629
+ oldKeyMasked: `${oldKey.slice(0, 6)}\u2026`,
142630
+ newKeyMasked: `${newKey.slice(0, 6)}\u2026`,
142631
+ persisted
142632
+ });
142633
+ return { newKey, persisted };
142634
+ }
142635
+ checkRateLimit(map2, key, limit, windowMs) {
142815
142636
  const now = Date.now();
142816
- const windowMs = 6e4;
142817
- const limit = 5;
142818
- const arr = (this.exchangeAttempts.get(ip) ?? []).filter((t2) => now - t2 < windowMs);
142637
+ const arr = (map2.get(key) ?? []).filter((t2) => now - t2 < windowMs);
142819
142638
  if (arr.length >= limit) {
142820
- this.exchangeAttempts.set(ip, arr);
142639
+ map2.set(key, arr);
142821
142640
  return false;
142822
142641
  }
142823
142642
  arr.push(now);
142824
- this.exchangeAttempts.set(ip, arr);
142643
+ map2.set(key, arr);
142644
+ setTimeout(() => {
142645
+ const remaining = (map2.get(key) ?? []).filter((t2) => Date.now() - t2 < windowMs);
142646
+ if (remaining.length === 0) map2.delete(key);
142647
+ else map2.set(key, remaining);
142648
+ }, windowMs);
142825
142649
  return true;
142826
142650
  }
142651
+ checkExchangeRateLimit(ip) {
142652
+ return this.checkRateLimit(this.exchangeAttempts, ip, 5, 6e4);
142653
+ }
142654
+ checkSessionStartRateLimit(ip) {
142655
+ return this.checkRateLimit(this.sessionStartAttempts, ip, 10, 6e4);
142656
+ }
142657
+ checkSessionInputRateLimit(sessionId) {
142658
+ return this.checkRateLimit(this.sessionInputAttempts, sessionId, 500, 6e4);
142659
+ }
142827
142660
  async handleListConversations(url2, res) {
142828
142661
  const limit = intParam(url2, "limit", 50);
142829
142662
  const offset = intParam(url2, "offset", 0);
@@ -142985,21 +142818,6 @@ var StreamerServer = class {
142985
142818
  const projects = this.cache.getPopularProjects(limit);
142986
142819
  json2(res, 200, { projects, total: projects.length });
142987
142820
  }
142988
- async handleListProjectChats(url2, res) {
142989
- if (!this.cache || !this.projectsRepo || !this.conversationsRepo || !this.sessionsRepo || !this.cacheMetadataRepo) {
142990
- json2(res, 503, { error: "Cache not available" });
142991
- return;
142992
- }
142993
- await handleListProjectChats(url2, res, {
142994
- cache: this.cache,
142995
- projectsRepo: this.projectsRepo,
142996
- conversationsRepo: this.conversationsRepo,
142997
- sessionsRepo: this.sessionsRepo,
142998
- cacheMetadataRepo: this.cacheMetadataRepo,
142999
- getSessionResponses: () => this.sessionStore.list(this.ptyAttachedIds()),
143000
- getFreshScanner: () => this.getFreshScanner()
143001
- });
143002
- }
143003
142821
  buildStatCache(previousScanner) {
143004
142822
  if (!this.cache) return void 0;
143005
142823
  const dbStats = this.cache.getFileStats();
@@ -143476,6 +143294,10 @@ var StreamerServer = class {
143476
143294
  }
143477
143295
  }
143478
143296
  async handleSendInput(sessionId, req, res) {
143297
+ if (!this.checkSessionInputRateLimit(sessionId)) {
143298
+ json2(res, 429, { error: "Too many input requests for this session. Please slow down." });
143299
+ return;
143300
+ }
143479
143301
  if (this.agentConfig.enabled) {
143480
143302
  const body2 = await readBody(req);
143481
143303
  const cache = this.cache;
@@ -143757,6 +143579,13 @@ var StreamerServer = class {
143757
143579
  json2(res, 201, { sessionId: session.id });
143758
143580
  }
143759
143581
  async handleStartSession(req, res) {
143582
+ const ip = req.socket?.remoteAddress ?? "unknown";
143583
+ if (!this.checkSessionStartRateLimit(ip)) {
143584
+ json2(res, 429, {
143585
+ error: "Too many session start requests. Please wait before trying again."
143586
+ });
143587
+ return;
143588
+ }
143760
143589
  if (this.agentConfig.enabled) {
143761
143590
  const body2 = await readBody(req);
143762
143591
  const result = await handleStartAgentSession(body2, {
@@ -144280,7 +144109,7 @@ async function checkForUpdate(opts) {
144280
144109
  }
144281
144110
 
144282
144111
  // src/updater/install.ts
144283
- var import_node_fs17 = require("fs");
144112
+ var import_node_fs19 = require("fs");
144284
144113
 
144285
144114
  // src/updater/active-sessions.ts
144286
144115
  async function countActiveSessions(opts) {
@@ -144333,8 +144162,8 @@ function isBrewInstall(scriptPath = process.argv[1] ?? "") {
144333
144162
 
144334
144163
  // src/updater/download.ts
144335
144164
  var import_node_crypto4 = require("crypto");
144336
- var import_node_fs7 = require("fs");
144337
- var import_node_path8 = require("path");
144165
+ var import_node_fs8 = require("fs");
144166
+ var import_node_path10 = require("path");
144338
144167
  var import_promises15 = require("stream/promises");
144339
144168
 
144340
144169
  // src/updater/manifest.ts
@@ -144394,13 +144223,13 @@ async function downloadAndVerify(opts) {
144394
144223
  `Manifest references ${artifact.filename} but it is not attached to the release`
144395
144224
  );
144396
144225
  }
144397
- (0, import_node_fs7.mkdirSync)((0, import_node_path8.dirname)(targetPath), { recursive: true });
144226
+ (0, import_node_fs8.mkdirSync)((0, import_node_path10.dirname)(targetPath), { recursive: true });
144398
144227
  const res = await fetch(asset.browserDownloadUrl);
144399
144228
  if (!res.ok || !res.body) {
144400
144229
  throw new Error(`Failed to download ${artifact.filename}: ${res.status} ${res.statusText}`);
144401
144230
  }
144402
144231
  const hash2 = (0, import_node_crypto4.createHash)("sha256");
144403
- const out = (0, import_node_fs7.createWriteStream)(targetPath);
144232
+ const out = (0, import_node_fs8.createWriteStream)(targetPath);
144404
144233
  let bytes = 0;
144405
144234
  const measured = new TransformStream({
144406
144235
  transform(chunk, controller) {
@@ -144412,19 +144241,19 @@ async function downloadAndVerify(opts) {
144412
144241
  try {
144413
144242
  await (0, import_promises15.pipeline)(res.body.pipeThrough(measured), out);
144414
144243
  } catch (err) {
144415
- (0, import_node_fs7.rmSync)(targetPath, { force: true });
144244
+ (0, import_node_fs8.rmSync)(targetPath, { force: true });
144416
144245
  throw err;
144417
144246
  }
144418
144247
  const actual = hash2.digest("hex");
144419
144248
  if (actual !== artifact.sha256) {
144420
- (0, import_node_fs7.rmSync)(targetPath, { force: true });
144249
+ (0, import_node_fs8.rmSync)(targetPath, { force: true });
144421
144250
  throw new Error(
144422
144251
  `sha256 mismatch for ${artifact.filename}: expected ${artifact.sha256}, got ${actual}`
144423
144252
  );
144424
144253
  }
144425
- const stat10 = (0, import_node_fs7.statSync)(targetPath);
144254
+ const stat10 = (0, import_node_fs8.statSync)(targetPath);
144426
144255
  if (stat10.size !== artifact.size) {
144427
- (0, import_node_fs7.rmSync)(targetPath, { force: true });
144256
+ (0, import_node_fs8.rmSync)(targetPath, { force: true });
144428
144257
  throw new Error(
144429
144258
  `size mismatch for ${artifact.filename}: expected ${artifact.size}, got ${stat10.size}`
144430
144259
  );
@@ -144433,17 +144262,17 @@ async function downloadAndVerify(opts) {
144433
144262
  }
144434
144263
 
144435
144264
  // src/updater/paths.ts
144436
- var import_node_os3 = require("os");
144437
- var import_node_path9 = require("path");
144438
- var THREADBASE_ROOT = (0, import_node_path9.join)((0, import_node_os3.homedir)(), ".threadbase");
144439
- var RELEASES_DIR = (0, import_node_path9.join)(THREADBASE_ROOT, "releases");
144440
- var CURRENT_SYMLINK = (0, import_node_path9.join)(THREADBASE_ROOT, "current");
144441
- var DOWNLOAD_DIR = (0, import_node_path9.join)(THREADBASE_ROOT, "releases", ".tmp");
144265
+ var import_node_os4 = require("os");
144266
+ var import_node_path11 = require("path");
144267
+ var THREADBASE_ROOT = (0, import_node_path11.join)((0, import_node_os4.homedir)(), ".threadbase");
144268
+ var RELEASES_DIR = (0, import_node_path11.join)(THREADBASE_ROOT, "releases");
144269
+ var CURRENT_SYMLINK = (0, import_node_path11.join)(THREADBASE_ROOT, "current");
144270
+ var DOWNLOAD_DIR = (0, import_node_path11.join)(THREADBASE_ROOT, "releases", ".tmp");
144442
144271
  function releaseDir(version2) {
144443
- return (0, import_node_path9.join)(RELEASES_DIR, version2);
144272
+ return (0, import_node_path11.join)(RELEASES_DIR, version2);
144444
144273
  }
144445
144274
  function downloadPath(version2, filename) {
144446
- return (0, import_node_path9.join)(DOWNLOAD_DIR, `${version2}-${filename}`);
144275
+ return (0, import_node_path11.join)(DOWNLOAD_DIR, `${version2}-${filename}`);
144447
144276
  }
144448
144277
 
144449
144278
  // src/updater/restart.ts
@@ -144524,75 +144353,75 @@ async function stopService(opts = {}) {
144524
144353
  }
144525
144354
 
144526
144355
  // src/updater/stamp-version.ts
144527
- var import_node_fs8 = require("fs");
144528
- var import_node_path10 = require("path");
144356
+ var import_node_fs9 = require("fs");
144357
+ var import_node_path12 = require("path");
144529
144358
  function stampVersionTxt(destDir, version2) {
144530
- const distDir = (0, import_node_path10.join)(destDir, "dist");
144531
- (0, import_node_fs8.mkdirSync)(distDir, { recursive: true });
144532
- (0, import_node_fs8.writeFileSync)((0, import_node_path10.join)(distDir, "version.txt"), `${version2}+update
144359
+ const distDir = (0, import_node_path12.join)(destDir, "dist");
144360
+ (0, import_node_fs9.mkdirSync)(distDir, { recursive: true });
144361
+ (0, import_node_fs9.writeFileSync)((0, import_node_path12.join)(distDir, "version.txt"), `${version2}+update
144533
144362
  `);
144534
144363
  }
144535
144364
 
144536
144365
  // src/updater/swap.ts
144537
- var import_node_fs9 = require("fs");
144538
- var import_node_path11 = require("path");
144366
+ var import_node_fs10 = require("fs");
144367
+ var import_node_path13 = require("path");
144539
144368
  var import_semver2 = __toESM(require_semver2(), 1);
144540
144369
  var KEEP_LAST_N = 2;
144541
144370
  function swapCurrent(version2) {
144542
144371
  const target = releaseDir(version2);
144543
- if (!(0, import_node_fs9.existsSync)(target)) {
144372
+ if (!(0, import_node_fs10.existsSync)(target)) {
144544
144373
  throw new Error(`Cannot swap to ${version2}: ${target} does not exist`);
144545
144374
  }
144546
144375
  if (process.platform === "win32") {
144547
144376
  const tmp = `${CURRENT_SYMLINK}.new`;
144548
- (0, import_node_fs9.rmSync)(tmp, { recursive: true, force: true });
144549
- (0, import_node_fs9.cpSync)(target, tmp, { recursive: true });
144550
- if ((0, import_node_fs9.existsSync)(CURRENT_SYMLINK)) {
144551
- (0, import_node_fs9.rmSync)(CURRENT_SYMLINK, { recursive: true, force: true });
144377
+ (0, import_node_fs10.rmSync)(tmp, { recursive: true, force: true });
144378
+ (0, import_node_fs10.cpSync)(target, tmp, { recursive: true });
144379
+ if ((0, import_node_fs10.existsSync)(CURRENT_SYMLINK)) {
144380
+ (0, import_node_fs10.rmSync)(CURRENT_SYMLINK, { recursive: true, force: true });
144552
144381
  }
144553
- (0, import_node_fs9.renameSync)(tmp, CURRENT_SYMLINK);
144554
- (0, import_node_fs9.copyFileSync)((0, import_node_path11.join)(CURRENT_SYMLINK, "dist", "cli.cjs"), (0, import_node_path11.join)(THREADBASE_ROOT, "cli.js"));
144382
+ (0, import_node_fs10.renameSync)(tmp, CURRENT_SYMLINK);
144383
+ (0, import_node_fs10.copyFileSync)((0, import_node_path13.join)(CURRENT_SYMLINK, "dist", "cli.cjs"), (0, import_node_path13.join)(THREADBASE_ROOT, "cli.js"));
144555
144384
  return;
144556
144385
  }
144557
144386
  const tmpLink = `${CURRENT_SYMLINK}.new`;
144558
- if ((0, import_node_fs9.existsSync)(tmpLink) || lstatSafeIsSymlink(tmpLink)) {
144559
- (0, import_node_fs9.unlinkSync)(tmpLink);
144387
+ if ((0, import_node_fs10.existsSync)(tmpLink) || lstatSafeIsSymlink(tmpLink)) {
144388
+ (0, import_node_fs10.unlinkSync)(tmpLink);
144560
144389
  }
144561
- (0, import_node_fs9.symlinkSync)(target, tmpLink);
144562
- (0, import_node_fs9.renameSync)(tmpLink, CURRENT_SYMLINK);
144563
- const cliJs = (0, import_node_path11.join)(THREADBASE_ROOT, "cli.js");
144390
+ (0, import_node_fs10.symlinkSync)(target, tmpLink);
144391
+ (0, import_node_fs10.renameSync)(tmpLink, CURRENT_SYMLINK);
144392
+ const cliJs = (0, import_node_path13.join)(THREADBASE_ROOT, "cli.js");
144564
144393
  const tmpCliJs = `${cliJs}.new`;
144565
- if ((0, import_node_fs9.existsSync)(tmpCliJs) || lstatSafeIsSymlink(tmpCliJs)) (0, import_node_fs9.unlinkSync)(tmpCliJs);
144566
- (0, import_node_fs9.symlinkSync)((0, import_node_path11.join)(target, "dist", "cli.cjs"), tmpCliJs);
144567
- (0, import_node_fs9.renameSync)(tmpCliJs, cliJs);
144394
+ if ((0, import_node_fs10.existsSync)(tmpCliJs) || lstatSafeIsSymlink(tmpCliJs)) (0, import_node_fs10.unlinkSync)(tmpCliJs);
144395
+ (0, import_node_fs10.symlinkSync)((0, import_node_path13.join)(target, "dist", "cli.cjs"), tmpCliJs);
144396
+ (0, import_node_fs10.renameSync)(tmpCliJs, cliJs);
144568
144397
  }
144569
144398
  function lstatSafeIsSymlink(path2) {
144570
144399
  try {
144571
- return (0, import_node_fs9.lstatSync)(path2).isSymbolicLink();
144400
+ return (0, import_node_fs10.lstatSync)(path2).isSymbolicLink();
144572
144401
  } catch {
144573
144402
  return false;
144574
144403
  }
144575
144404
  }
144576
144405
  function pruneOldReleases(activeVersion, keep = KEEP_LAST_N) {
144577
- if (!(0, import_node_fs9.existsSync)(RELEASES_DIR)) return [];
144578
- const entries = (0, import_node_fs9.readdirSync)(RELEASES_DIR, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).filter((name) => import_semver2.default.valid(name) !== null);
144406
+ if (!(0, import_node_fs10.existsSync)(RELEASES_DIR)) return [];
144407
+ const entries = (0, import_node_fs10.readdirSync)(RELEASES_DIR, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).filter((name) => import_semver2.default.valid(name) !== null);
144579
144408
  const sorted = entries.sort((a, b2) => import_semver2.default.rcompare(a, b2));
144580
144409
  const toKeep = new Set(sorted.slice(0, keep));
144581
144410
  toKeep.add(activeVersion);
144582
144411
  const removed = [];
144583
144412
  for (const name of sorted) {
144584
144413
  if (toKeep.has(name)) continue;
144585
- (0, import_node_fs9.rmSync)(releaseDir(name), { recursive: true, force: true });
144414
+ (0, import_node_fs10.rmSync)(releaseDir(name), { recursive: true, force: true });
144586
144415
  removed.push(name);
144587
144416
  }
144588
144417
  return removed;
144589
144418
  }
144590
144419
  function ensureReleasesDir() {
144591
- (0, import_node_fs9.mkdirSync)(RELEASES_DIR, { recursive: true });
144420
+ (0, import_node_fs10.mkdirSync)(RELEASES_DIR, { recursive: true });
144592
144421
  }
144593
144422
 
144594
144423
  // src/updater/unpack.ts
144595
- var import_node_fs16 = require("fs");
144424
+ var import_node_fs17 = require("fs");
144596
144425
 
144597
144426
  // node_modules/tar/dist/esm/index.min.js
144598
144427
  var import_events4 = __toESM(require("events"), 1);
@@ -144600,35 +144429,35 @@ var import_fs24 = __toESM(require("fs"), 1);
144600
144429
  var import_node_events3 = require("events");
144601
144430
  var import_node_stream3 = __toESM(require("stream"), 1);
144602
144431
  var import_node_string_decoder = require("string_decoder");
144603
- var import_node_path12 = __toESM(require("path"), 1);
144604
- var import_node_fs10 = __toESM(require("fs"), 1);
144432
+ var import_node_path14 = __toESM(require("path"), 1);
144433
+ var import_node_fs11 = __toESM(require("fs"), 1);
144605
144434
  var import_path20 = require("path");
144606
144435
  var import_events5 = require("events");
144607
144436
  var import_assert = __toESM(require("assert"), 1);
144608
144437
  var import_buffer = require("buffer");
144609
144438
  var Ps = __toESM(require("zlib"), 1);
144610
144439
  var import_zlib = __toESM(require("zlib"), 1);
144611
- var import_node_path13 = require("path");
144612
- var import_node_path14 = require("path");
144440
+ var import_node_path15 = require("path");
144441
+ var import_node_path16 = require("path");
144613
144442
  var import_fs25 = __toESM(require("fs"), 1);
144614
144443
  var import_fs26 = __toESM(require("fs"), 1);
144615
144444
  var import_path21 = __toESM(require("path"), 1);
144616
- var import_node_path15 = require("path");
144445
+ var import_node_path17 = require("path");
144617
144446
  var import_path22 = __toESM(require("path"), 1);
144618
- var import_node_fs11 = __toESM(require("fs"), 1);
144447
+ var import_node_fs12 = __toESM(require("fs"), 1);
144619
144448
  var import_node_assert = __toESM(require("assert"), 1);
144620
144449
  var import_node_crypto5 = require("crypto");
144621
- var import_node_fs12 = __toESM(require("fs"), 1);
144622
- var import_node_path16 = __toESM(require("path"), 1);
144623
- var import_fs27 = __toESM(require("fs"), 1);
144624
144450
  var import_node_fs13 = __toESM(require("fs"), 1);
144625
- var import_node_path17 = __toESM(require("path"), 1);
144626
- var import_node_fs14 = __toESM(require("fs"), 1);
144627
- var import_promises16 = __toESM(require("fs/promises"), 1);
144628
144451
  var import_node_path18 = __toESM(require("path"), 1);
144629
- var import_node_path19 = require("path");
144452
+ var import_fs27 = __toESM(require("fs"), 1);
144453
+ var import_node_fs14 = __toESM(require("fs"), 1);
144454
+ var import_node_path19 = __toESM(require("path"), 1);
144630
144455
  var import_node_fs15 = __toESM(require("fs"), 1);
144456
+ var import_promises16 = __toESM(require("fs/promises"), 1);
144631
144457
  var import_node_path20 = __toESM(require("path"), 1);
144458
+ var import_node_path21 = require("path");
144459
+ var import_node_fs16 = __toESM(require("fs"), 1);
144460
+ var import_node_path22 = __toESM(require("path"), 1);
144632
144461
  var zr = Object.defineProperty;
144633
144462
  var Ur = (s3, t2) => {
144634
144463
  for (var e in t2) zr(s3, e, { get: t2[e], enumerable: true });
@@ -145522,12 +145351,12 @@ var F2 = class {
145522
145351
  }
145523
145352
  };
145524
145353
  var un = (s3, t2) => {
145525
- let i = s3, r = "", n, o = import_node_path13.posix.parse(s3).root || ".";
145354
+ let i = s3, r = "", n, o = import_node_path15.posix.parse(s3).root || ".";
145526
145355
  if (Buffer.byteLength(i) < 100) n = [i, r, false];
145527
145356
  else {
145528
- r = import_node_path13.posix.dirname(i), i = import_node_path13.posix.basename(i);
145357
+ r = import_node_path15.posix.dirname(i), i = import_node_path15.posix.basename(i);
145529
145358
  do
145530
- Buffer.byteLength(i) <= 100 && Buffer.byteLength(r) <= t2 ? n = [i, r, false] : Buffer.byteLength(i) > 100 && Buffer.byteLength(r) <= t2 ? n = [i.slice(0, 99), r, true] : (i = import_node_path13.posix.join(import_node_path13.posix.basename(r), i), r = import_node_path13.posix.dirname(r));
145359
+ Buffer.byteLength(i) <= 100 && Buffer.byteLength(r) <= t2 ? n = [i, r, false] : Buffer.byteLength(i) > 100 && Buffer.byteLength(r) <= t2 ? n = [i.slice(0, 99), r, true] : (i = import_node_path15.posix.join(import_node_path15.posix.basename(r), i), r = import_node_path15.posix.dirname(r));
145531
145360
  while (r !== o && n === void 0);
145532
145361
  n || (n = [s3.slice(0, 99), "", true]);
145533
145362
  }
@@ -145573,7 +145402,7 @@ var ft = class s {
145573
145402
  if (t2 === "") return Buffer.allocUnsafe(0);
145574
145403
  let e = Buffer.byteLength(t2), i = 512 * Math.ceil(1 + e / 512), r = Buffer.allocUnsafe(i);
145575
145404
  for (let n = 0; n < 512; n++) r[n] = 0;
145576
- new F2({ path: ("PaxHeader/" + (0, import_node_path14.basename)(this.path ?? "")).slice(0, 99), mode: this.mode || 420, uid: this.uid, gid: this.gid, size: e, mtime: this.mtime, type: this.global ? "GlobalExtendedHeader" : "ExtendedHeader", linkpath: "", uname: this.uname || "", gname: this.gname || "", devmaj: 0, devmin: 0, atime: this.atime, ctime: this.ctime }).encode(r), r.write(t2, 512, e, "utf8");
145405
+ new F2({ path: ("PaxHeader/" + (0, import_node_path16.basename)(this.path ?? "")).slice(0, 99), mode: this.mode || 420, uid: this.uid, gid: this.gid, size: e, mtime: this.mtime, type: this.global ? "GlobalExtendedHeader" : "ExtendedHeader", linkpath: "", uname: this.uname || "", gname: this.gname || "", devmaj: 0, devmin: 0, atime: this.atime, ctime: this.ctime }).encode(r), r.write(t2, 512, e, "utf8");
145577
145406
  for (let n = e + 512; n < r.length; n++) r[n] = 0;
145578
145407
  return r;
145579
145408
  }
@@ -145992,15 +145821,15 @@ var Qi = (s3, t2) => {
145992
145821
  var Mn = (s3) => {
145993
145822
  let t2 = new rt(s3), e = s3.file, i;
145994
145823
  try {
145995
- i = import_node_fs10.default.openSync(e, "r");
145996
- let r = import_node_fs10.default.fstatSync(i), n = s3.maxReadSize || 16 * 1024 * 1024;
145824
+ i = import_node_fs11.default.openSync(e, "r");
145825
+ let r = import_node_fs11.default.fstatSync(i), n = s3.maxReadSize || 16 * 1024 * 1024;
145997
145826
  if (r.size < n) {
145998
- let o = Buffer.allocUnsafe(r.size), h = import_node_fs10.default.readSync(i, o, 0, r.size, 0);
145827
+ let o = Buffer.allocUnsafe(r.size), h = import_node_fs11.default.readSync(i, o, 0, r.size, 0);
145999
145828
  t2.end(h === o.byteLength ? o : o.subarray(0, h));
146000
145829
  } else {
146001
145830
  let o = 0, h = Buffer.allocUnsafe(n);
146002
145831
  for (; o < r.size; ) {
146003
- let a = import_node_fs10.default.readSync(i, h, 0, n, o);
145832
+ let a = import_node_fs11.default.readSync(i, h, 0, n, o);
146004
145833
  if (a === 0) break;
146005
145834
  o += a, t2.write(h.subarray(0, a));
146006
145835
  }
@@ -146008,7 +145837,7 @@ var Mn = (s3) => {
146008
145837
  }
146009
145838
  } finally {
146010
145839
  if (typeof i == "number") try {
146011
- import_node_fs10.default.closeSync(i);
145840
+ import_node_fs11.default.closeSync(i);
146012
145841
  } catch {
146013
145842
  }
146014
145843
  }
@@ -146016,7 +145845,7 @@ var Mn = (s3) => {
146016
145845
  var Bn = (s3, t2) => {
146017
145846
  let e = new rt(s3), i = s3.maxReadSize || 16 * 1024 * 1024, r = s3.file;
146018
145847
  return new Promise((o, h) => {
146019
- e.on("error", h), e.on("end", o), import_node_fs10.default.stat(r, (a, l) => {
145848
+ e.on("error", h), e.on("end", o), import_node_fs11.default.stat(r, (a, l) => {
146020
145849
  if (a) h(a);
146021
145850
  else {
146022
145851
  let c = new _t(r, { readSize: i, size: l.size });
@@ -146029,7 +145858,7 @@ var Ct = K2(Mn, Bn, (s3) => new rt(s3), (s3) => new rt(s3), (s3, t2) => {
146029
145858
  t2?.length && Qi(s3, t2), s3.noResume || vn(s3);
146030
145859
  });
146031
145860
  var Ji = (s3, t2, e) => (s3 &= 4095, e && (s3 = (s3 | 384) & -19), t2 && (s3 & 256 && (s3 |= 64), s3 & 32 && (s3 |= 8), s3 & 4 && (s3 |= 1)), s3);
146032
- var { isAbsolute: zn, parse: qs } = import_node_path15.win32;
145861
+ var { isAbsolute: zn, parse: qs } = import_node_path17.win32;
146033
145862
  var ce = (s3) => {
146034
145863
  let t2 = "", e = qs(s3);
146035
145864
  for (; zn(s3) || e.root; ) {
@@ -146738,11 +146567,11 @@ var $n = (s3, t2) => {
146738
146567
  };
146739
146568
  var fr = (s3, t2) => {
146740
146569
  t2.forEach((e) => {
146741
- e.charAt(0) === "@" ? Ct({ file: import_node_path12.default.resolve(s3.cwd, e.slice(1)), sync: true, noResume: true, onReadEntry: (i) => s3.add(i) }) : s3.add(e);
146570
+ e.charAt(0) === "@" ? Ct({ file: import_node_path14.default.resolve(s3.cwd, e.slice(1)), sync: true, noResume: true, onReadEntry: (i) => s3.add(i) }) : s3.add(e);
146742
146571
  }), s3.end();
146743
146572
  };
146744
146573
  var dr = async (s3, t2) => {
146745
- for (let e of t2) e.charAt(0) === "@" ? await Ct({ file: import_node_path12.default.resolve(String(s3.cwd), e.slice(1)), noResume: true, onReadEntry: (i) => {
146574
+ for (let e of t2) e.charAt(0) === "@" ? await Ct({ file: import_node_path14.default.resolve(String(s3.cwd), e.slice(1)), noResume: true, onReadEntry: (i) => {
146746
146575
  s3.add(i);
146747
146576
  } }) : s3.add(e);
146748
146577
  s3.end();
@@ -146769,29 +146598,29 @@ var ur = !Er && typeof mr == "number" ? mr | Sr | wr | yr : null;
146769
146598
  var us = ur !== null ? () => ur : jn ? (s3) => s3 < to ? eo : "w" : () => "w";
146770
146599
  var ps = (s3, t2, e) => {
146771
146600
  try {
146772
- return import_node_fs13.default.lchownSync(s3, t2, e);
146601
+ return import_node_fs14.default.lchownSync(s3, t2, e);
146773
146602
  } catch (i) {
146774
146603
  if (i?.code !== "ENOENT") throw i;
146775
146604
  }
146776
146605
  };
146777
146606
  var Ei = (s3, t2, e, i) => {
146778
- import_node_fs13.default.lchown(s3, t2, e, (r) => {
146607
+ import_node_fs14.default.lchown(s3, t2, e, (r) => {
146779
146608
  i(r && r?.code !== "ENOENT" ? r : null);
146780
146609
  });
146781
146610
  };
146782
146611
  var io = (s3, t2, e, i, r) => {
146783
- if (t2.isDirectory()) Es(import_node_path17.default.resolve(s3, t2.name), e, i, (n) => {
146612
+ if (t2.isDirectory()) Es(import_node_path19.default.resolve(s3, t2.name), e, i, (n) => {
146784
146613
  if (n) return r(n);
146785
- let o = import_node_path17.default.resolve(s3, t2.name);
146614
+ let o = import_node_path19.default.resolve(s3, t2.name);
146786
146615
  Ei(o, e, i, r);
146787
146616
  });
146788
146617
  else {
146789
- let n = import_node_path17.default.resolve(s3, t2.name);
146618
+ let n = import_node_path19.default.resolve(s3, t2.name);
146790
146619
  Ei(n, e, i, r);
146791
146620
  }
146792
146621
  };
146793
146622
  var Es = (s3, t2, e, i) => {
146794
- import_node_fs13.default.readdir(s3, { withFileTypes: true }, (r, n) => {
146623
+ import_node_fs14.default.readdir(s3, { withFileTypes: true }, (r, n) => {
146795
146624
  if (r) {
146796
146625
  if (r.code === "ENOENT") return i();
146797
146626
  if (r.code !== "ENOTDIR" && r.code !== "ENOTSUP") return i(r);
@@ -146807,12 +146636,12 @@ var Es = (s3, t2, e, i) => {
146807
146636
  });
146808
146637
  };
146809
146638
  var so = (s3, t2, e, i) => {
146810
- t2.isDirectory() && ws(import_node_path17.default.resolve(s3, t2.name), e, i), ps(import_node_path17.default.resolve(s3, t2.name), e, i);
146639
+ t2.isDirectory() && ws(import_node_path19.default.resolve(s3, t2.name), e, i), ps(import_node_path19.default.resolve(s3, t2.name), e, i);
146811
146640
  };
146812
146641
  var ws = (s3, t2, e) => {
146813
146642
  let i;
146814
146643
  try {
146815
- i = import_node_fs13.default.readdirSync(s3, { withFileTypes: true });
146644
+ i = import_node_fs14.default.readdirSync(s3, { withFileTypes: true });
146816
146645
  } catch (r) {
146817
146646
  let n = r;
146818
146647
  if (n?.code === "ENOENT") return;
@@ -146846,32 +146675,32 @@ var St = class extends Error {
146846
146675
  }
146847
146676
  };
146848
146677
  var no = (s3, t2) => {
146849
- import_node_fs14.default.stat(s3, (e, i) => {
146678
+ import_node_fs15.default.stat(s3, (e, i) => {
146850
146679
  (e || !i.isDirectory()) && (e = new Se(s3, e?.code || "ENOTDIR")), t2(e);
146851
146680
  });
146852
146681
  };
146853
146682
  var gr = (s3, t2, e) => {
146854
146683
  s3 = f(s3);
146855
146684
  let i = t2.umask ?? 18, r = t2.mode | 448, n = (r & i) !== 0, o = t2.uid, h = t2.gid, a = typeof o == "number" && typeof h == "number" && (o !== t2.processUid || h !== t2.processGid), l = t2.preserve, c = t2.unlink, d = f(t2.cwd), S2 = (E2, x2) => {
146856
- E2 ? e(E2) : x2 && a ? Es(x2, o, h, (Le) => S2(Le)) : n ? import_node_fs14.default.chmod(s3, r, e) : e();
146685
+ E2 ? e(E2) : x2 && a ? Es(x2, o, h, (Le) => S2(Le)) : n ? import_node_fs15.default.chmod(s3, r, e) : e();
146857
146686
  };
146858
146687
  if (s3 === d) return no(s3, S2);
146859
146688
  if (l) return import_promises16.default.mkdir(s3, { mode: r, recursive: true }).then((E2) => S2(null, E2 ?? void 0), S2);
146860
- let D2 = f(import_node_path18.default.relative(d, s3)).split("/");
146689
+ let D2 = f(import_node_path20.default.relative(d, s3)).split("/");
146861
146690
  Ss(d, D2, r, c, d, void 0, S2);
146862
146691
  };
146863
146692
  var Ss = (s3, t2, e, i, r, n, o) => {
146864
146693
  if (t2.length === 0) return o(null, n);
146865
- let h = t2.shift(), a = f(import_node_path18.default.resolve(s3 + "/" + h));
146866
- import_node_fs14.default.mkdir(a, e, br(a, t2, e, i, r, n, o));
146694
+ let h = t2.shift(), a = f(import_node_path20.default.resolve(s3 + "/" + h));
146695
+ import_node_fs15.default.mkdir(a, e, br(a, t2, e, i, r, n, o));
146867
146696
  };
146868
146697
  var br = (s3, t2, e, i, r, n, o) => (h) => {
146869
- h ? import_node_fs14.default.lstat(s3, (a, l) => {
146698
+ h ? import_node_fs15.default.lstat(s3, (a, l) => {
146870
146699
  if (a) a.path = a.path && f(a.path), o(a);
146871
146700
  else if (l.isDirectory()) Ss(s3, t2, e, i, r, n, o);
146872
- else if (i) import_node_fs14.default.unlink(s3, (c) => {
146701
+ else if (i) import_node_fs15.default.unlink(s3, (c) => {
146873
146702
  if (c) return o(c);
146874
- import_node_fs14.default.mkdir(s3, e, br(s3, t2, e, i, r, n, o));
146703
+ import_node_fs15.default.mkdir(s3, e, br(s3, t2, e, i, r, n, o));
146875
146704
  });
146876
146705
  else {
146877
146706
  if (l.isSymbolicLink()) return o(new St(s3, s3 + "/" + t2.join("/")));
@@ -146882,7 +146711,7 @@ var br = (s3, t2, e, i, r, n, o) => (h) => {
146882
146711
  var oo = (s3) => {
146883
146712
  let t2 = false, e;
146884
146713
  try {
146885
- t2 = import_node_fs14.default.statSync(s3).isDirectory();
146714
+ t2 = import_node_fs15.default.statSync(s3).isDirectory();
146886
146715
  } catch (i) {
146887
146716
  e = i?.code;
146888
146717
  } finally {
@@ -146892,20 +146721,20 @@ var oo = (s3) => {
146892
146721
  var _r = (s3, t2) => {
146893
146722
  s3 = f(s3);
146894
146723
  let e = t2.umask ?? 18, i = t2.mode | 448, r = (i & e) !== 0, n = t2.uid, o = t2.gid, h = typeof n == "number" && typeof o == "number" && (n !== t2.processUid || o !== t2.processGid), a = t2.preserve, l = t2.unlink, c = f(t2.cwd), d = (E2) => {
146895
- E2 && h && ws(E2, n, o), r && import_node_fs14.default.chmodSync(s3, i);
146724
+ E2 && h && ws(E2, n, o), r && import_node_fs15.default.chmodSync(s3, i);
146896
146725
  };
146897
146726
  if (s3 === c) return oo(c), d();
146898
- if (a) return d(import_node_fs14.default.mkdirSync(s3, { mode: i, recursive: true }) ?? void 0);
146899
- let T2 = f(import_node_path18.default.relative(c, s3)).split("/"), D2;
146727
+ if (a) return d(import_node_fs15.default.mkdirSync(s3, { mode: i, recursive: true }) ?? void 0);
146728
+ let T2 = f(import_node_path20.default.relative(c, s3)).split("/"), D2;
146900
146729
  for (let E2 = T2.shift(), x2 = c; E2 && (x2 += "/" + E2); E2 = T2.shift()) {
146901
- x2 = f(import_node_path18.default.resolve(x2));
146730
+ x2 = f(import_node_path20.default.resolve(x2));
146902
146731
  try {
146903
- import_node_fs14.default.mkdirSync(x2, i), D2 = D2 || x2;
146732
+ import_node_fs15.default.mkdirSync(x2, i), D2 = D2 || x2;
146904
146733
  } catch {
146905
- let Le = import_node_fs14.default.lstatSync(x2);
146734
+ let Le = import_node_fs15.default.lstatSync(x2);
146906
146735
  if (Le.isDirectory()) continue;
146907
146736
  if (l) {
146908
- import_node_fs14.default.unlinkSync(x2), import_node_fs14.default.mkdirSync(x2, i), D2 = D2 || x2;
146737
+ import_node_fs15.default.unlinkSync(x2), import_node_fs15.default.mkdirSync(x2, i), D2 = D2 || x2;
146909
146738
  continue;
146910
146739
  } else if (Le.isSymbolicLink()) return new St(x2, x2 + "/" + T2.join("/"));
146911
146740
  }
@@ -146927,14 +146756,14 @@ var ho = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform;
146927
146756
  var ao = ho === "win32";
146928
146757
  var lo = (s3) => s3.split("/").slice(0, -1).reduce((e, i) => {
146929
146758
  let r = e.at(-1);
146930
- return r !== void 0 && (i = (0, import_node_path19.join)(r, i)), e.push(i || "/"), e;
146759
+ return r !== void 0 && (i = (0, import_node_path21.join)(r, i)), e.push(i || "/"), e;
146931
146760
  }, []);
146932
146761
  var yi = class {
146933
146762
  #t = /* @__PURE__ */ new Map();
146934
146763
  #i = /* @__PURE__ */ new Map();
146935
146764
  #s = /* @__PURE__ */ new Set();
146936
146765
  reserve(t2, e) {
146937
- t2 = ao ? ["win32 parallelization disabled"] : t2.map((r) => ut((0, import_node_path19.join)(Tr(r))));
146766
+ t2 = ao ? ["win32 parallelization disabled"] : t2.map((r) => ut((0, import_node_path21.join)(Tr(r))));
146938
146767
  let i = new Set(t2.map((r) => lo(r)).reduce((r, n) => r.concat(n)));
146939
146768
  this.#i.set(e, { dirs: i, paths: t2 });
146940
146769
  for (let r of t2) {
@@ -147024,17 +146853,17 @@ var fo = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform;
147024
146853
  var Te = fo === "win32";
147025
146854
  var mo = 1024;
147026
146855
  var uo = (s3, t2) => {
147027
- if (!Te) return import_node_fs12.default.unlink(s3, t2);
146856
+ if (!Te) return import_node_fs13.default.unlink(s3, t2);
147028
146857
  let e = s3 + ".DELETE." + (0, import_node_crypto5.randomBytes)(16).toString("hex");
147029
- import_node_fs12.default.rename(s3, e, (i) => {
146858
+ import_node_fs13.default.rename(s3, e, (i) => {
147030
146859
  if (i) return t2(i);
147031
- import_node_fs12.default.unlink(e, t2);
146860
+ import_node_fs13.default.unlink(e, t2);
147032
146861
  });
147033
146862
  };
147034
146863
  var po = (s3) => {
147035
- if (!Te) return import_node_fs12.default.unlinkSync(s3);
146864
+ if (!Te) return import_node_fs13.default.unlinkSync(s3);
147036
146865
  let t2 = s3 + ".DELETE." + (0, import_node_crypto5.randomBytes)(16).toString("hex");
147037
- import_node_fs12.default.renameSync(s3, t2), import_node_fs12.default.unlinkSync(t2);
146866
+ import_node_fs13.default.renameSync(s3, t2), import_node_fs13.default.unlinkSync(t2);
147038
146867
  };
147039
146868
  var vr = (s3, t2, e) => s3 !== void 0 && s3 === s3 >>> 0 ? s3 : t2 !== void 0 && t2 === t2 >>> 0 ? t2 : e;
147040
146869
  var Xt = class extends rt {
@@ -147074,7 +146903,7 @@ var Xt = class extends rt {
147074
146903
  if (t2.preserveOwner) throw new TypeError("cannot preserve owner in archive and also set owner explicitly");
147075
146904
  this.uid = t2.uid, this.gid = t2.gid, this.setOwner = true;
147076
146905
  } else this.uid = void 0, this.gid = void 0, this.setOwner = false;
147077
- this.preserveOwner = t2.preserveOwner === void 0 && typeof t2.uid != "number" ? process.getuid?.() === 0 : !!t2.preserveOwner, this.processUid = (this.preserveOwner || this.setOwner) && process.getuid ? process.getuid() : void 0, this.processGid = (this.preserveOwner || this.setOwner) && process.getgid ? process.getgid() : void 0, this.maxDepth = typeof t2.maxDepth == "number" ? t2.maxDepth : mo, this.forceChown = t2.forceChown === true, this.win32 = !!t2.win32 || Te, this.newer = !!t2.newer, this.keep = !!t2.keep, this.noMtime = !!t2.noMtime, this.preservePaths = !!t2.preservePaths, this.unlink = !!t2.unlink, this.cwd = f(import_node_path16.default.resolve(t2.cwd || process.cwd())), this.strip = Number(t2.strip) || 0, this.processUmask = this.chmod ? typeof t2.processUmask == "number" ? t2.processUmask : Lr() : 0, this.umask = typeof t2.umask == "number" ? t2.umask : this.processUmask, this.dmode = t2.dmode || 511 & ~this.umask, this.fmode = t2.fmode || 438 & ~this.umask, this.on("entry", (e) => this[Dr](e));
146906
+ this.preserveOwner = t2.preserveOwner === void 0 && typeof t2.uid != "number" ? process.getuid?.() === 0 : !!t2.preserveOwner, this.processUid = (this.preserveOwner || this.setOwner) && process.getuid ? process.getuid() : void 0, this.processGid = (this.preserveOwner || this.setOwner) && process.getgid ? process.getgid() : void 0, this.maxDepth = typeof t2.maxDepth == "number" ? t2.maxDepth : mo, this.forceChown = t2.forceChown === true, this.win32 = !!t2.win32 || Te, this.newer = !!t2.newer, this.keep = !!t2.keep, this.noMtime = !!t2.noMtime, this.preservePaths = !!t2.preservePaths, this.unlink = !!t2.unlink, this.cwd = f(import_node_path18.default.resolve(t2.cwd || process.cwd())), this.strip = Number(t2.strip) || 0, this.processUmask = this.chmod ? typeof t2.processUmask == "number" ? t2.processUmask : Lr() : 0, this.umask = typeof t2.umask == "number" ? t2.umask : this.processUmask, this.dmode = t2.dmode || 511 & ~this.umask, this.fmode = t2.fmode || 438 & ~this.umask, this.on("entry", (e) => this[Dr](e));
147078
146907
  }
147079
146908
  warn(t2, e, i = {}) {
147080
146909
  return (t2 === "TAR_BAD_ARCHIVE" || t2 === "TAR_ABORT") && (i.recoverable = false), super.warn(t2, e, i);
@@ -147088,7 +146917,7 @@ var Xt = class extends rt {
147088
146917
  let [n, o] = ce(i), h = o.replaceAll(/\\/g, "/").split("/");
147089
146918
  if (h.includes("..") || Te && /^[a-z]:\.\.$/i.test(h[0] ?? "")) {
147090
146919
  if (e === "path" || r === "Link") return this.warn("TAR_ENTRY_ERROR", `${e} contains '..'`, { entry: t2, [e]: i }), false;
147091
- let a = import_node_path16.default.posix.dirname(t2.path), l = import_node_path16.default.posix.normalize(import_node_path16.default.posix.join(a, h.join("/")));
146920
+ let a = import_node_path18.default.posix.dirname(t2.path), l = import_node_path18.default.posix.normalize(import_node_path18.default.posix.join(a, h.join("/")));
147092
146921
  if (l.startsWith("../") || l === "..") return this.warn("TAR_ENTRY_ERROR", `${e} escapes extraction directory`, { entry: t2, [e]: i }), false;
147093
146922
  }
147094
146923
  return n && (t2[e] = String(o), this.warn("TAR_ENTRY_INFO", `stripping ${n} from absolute ${e}`, { entry: t2, [e]: i })), true;
@@ -147106,12 +146935,12 @@ var Xt = class extends rt {
147106
146935
  }
147107
146936
  if (isFinite(this.maxDepth) && i.length > this.maxDepth) return this.warn("TAR_ENTRY_ERROR", "path excessively deep", { entry: t2, path: e, depth: i.length, maxDepth: this.maxDepth }), false;
147108
146937
  if (!this[Rs](t2, "path") || !this[Rs](t2, "linkpath")) return false;
147109
- if (t2.absolute = import_node_path16.default.isAbsolute(t2.path) ? f(import_node_path16.default.resolve(t2.path)) : f(import_node_path16.default.resolve(this.cwd, t2.path)), !this.preservePaths && typeof t2.absolute == "string" && t2.absolute.indexOf(this.cwd + "/") !== 0 && t2.absolute !== this.cwd) return this.warn("TAR_ENTRY_ERROR", "path escaped extraction target", { entry: t2, path: f(t2.path), resolvedPath: t2.absolute, cwd: this.cwd }), false;
146938
+ if (t2.absolute = import_node_path18.default.isAbsolute(t2.path) ? f(import_node_path18.default.resolve(t2.path)) : f(import_node_path18.default.resolve(this.cwd, t2.path)), !this.preservePaths && typeof t2.absolute == "string" && t2.absolute.indexOf(this.cwd + "/") !== 0 && t2.absolute !== this.cwd) return this.warn("TAR_ENTRY_ERROR", "path escaped extraction target", { entry: t2, path: f(t2.path), resolvedPath: t2.absolute, cwd: this.cwd }), false;
147110
146939
  if (t2.absolute === this.cwd && t2.type !== "Directory" && t2.type !== "GNUDumpDir") return false;
147111
146940
  if (this.win32) {
147112
- let { root: r } = import_node_path16.default.win32.parse(String(t2.absolute));
146941
+ let { root: r } = import_node_path18.default.win32.parse(String(t2.absolute));
147113
146942
  t2.absolute = r + ts(String(t2.absolute).slice(r.length));
147114
- let { root: n } = import_node_path16.default.win32.parse(t2.path);
146943
+ let { root: n } = import_node_path18.default.win32.parse(t2.path);
147115
146944
  t2.path = n + ts(t2.path.slice(n.length));
147116
146945
  }
147117
146946
  return true;
@@ -147150,16 +146979,16 @@ var Xt = class extends rt {
147150
146979
  [Ts](t2, e) {
147151
146980
  let i = typeof t2.mode == "number" ? t2.mode & 4095 : this.fmode, r = new et(String(t2.absolute), { flags: us(t2.size), mode: i, autoClose: false });
147152
146981
  r.on("error", (a) => {
147153
- r.fd && import_node_fs12.default.close(r.fd, () => {
146982
+ r.fd && import_node_fs13.default.close(r.fd, () => {
147154
146983
  }), r.write = () => true, this[O2](a, t2), e();
147155
146984
  });
147156
146985
  let n = 1, o = (a) => {
147157
146986
  if (a) {
147158
- r.fd && import_node_fs12.default.close(r.fd, () => {
146987
+ r.fd && import_node_fs13.default.close(r.fd, () => {
147159
146988
  }), this[O2](a, t2), e();
147160
146989
  return;
147161
146990
  }
147162
- --n === 0 && r.fd !== void 0 && import_node_fs12.default.close(r.fd, (l) => {
146991
+ --n === 0 && r.fd !== void 0 && import_node_fs13.default.close(r.fd, (l) => {
147163
146992
  l ? this[O2](l, t2) : this[$t](), e();
147164
146993
  });
147165
146994
  };
@@ -147168,12 +146997,12 @@ var Xt = class extends rt {
147168
146997
  if (typeof l == "number" && t2.mtime && !this.noMtime) {
147169
146998
  n++;
147170
146999
  let c = t2.atime || /* @__PURE__ */ new Date(), d = t2.mtime;
147171
- import_node_fs12.default.futimes(l, c, d, (S2) => S2 ? import_node_fs12.default.utimes(a, c, d, (T2) => o(T2 && S2)) : o());
147000
+ import_node_fs13.default.futimes(l, c, d, (S2) => S2 ? import_node_fs13.default.utimes(a, c, d, (T2) => o(T2 && S2)) : o());
147172
147001
  }
147173
147002
  if (typeof l == "number" && this[ge](t2)) {
147174
147003
  n++;
147175
147004
  let c = this[be](t2), d = this[_e](t2);
147176
- typeof c == "number" && typeof d == "number" && import_node_fs12.default.fchown(l, c, d, (S2) => S2 ? import_node_fs12.default.chown(a, c, d, (T2) => o(T2 && S2)) : o());
147005
+ typeof c == "number" && typeof d == "number" && import_node_fs13.default.fchown(l, c, d, (S2) => S2 ? import_node_fs13.default.chown(a, c, d, (T2) => o(T2 && S2)) : o());
147177
147006
  }
147178
147007
  o();
147179
147008
  });
@@ -147192,20 +147021,20 @@ var Xt = class extends rt {
147192
147021
  let n = 1, o = () => {
147193
147022
  --n === 0 && (e(), this[$t](), t2.resume());
147194
147023
  };
147195
- t2.mtime && !this.noMtime && (n++, import_node_fs12.default.utimes(String(t2.absolute), t2.atime || /* @__PURE__ */ new Date(), t2.mtime, o)), this[ge](t2) && (n++, import_node_fs12.default.chown(String(t2.absolute), Number(this[be](t2)), Number(this[_e](t2)), o)), o();
147024
+ t2.mtime && !this.noMtime && (n++, import_node_fs13.default.utimes(String(t2.absolute), t2.atime || /* @__PURE__ */ new Date(), t2.mtime, o)), this[ge](t2) && (n++, import_node_fs13.default.chown(String(t2.absolute), Number(this[be](t2)), Number(this[_e](t2)), o)), o();
147196
147025
  });
147197
147026
  }
147198
147027
  [Cr](t2) {
147199
147028
  t2.unsupported = true, this.warn("TAR_ENTRY_UNSUPPORTED", `unsupported entry type: ${t2.type}`, { entry: t2 }), t2.resume();
147200
147029
  }
147201
147030
  [Ar](t2, e) {
147202
- let i = f(import_node_path16.default.relative(this.cwd, import_node_path16.default.resolve(import_node_path16.default.dirname(String(t2.absolute)), String(t2.linkpath)))).split("/");
147031
+ let i = f(import_node_path18.default.relative(this.cwd, import_node_path18.default.resolve(import_node_path18.default.dirname(String(t2.absolute)), String(t2.linkpath)))).split("/");
147203
147032
  this[Re](t2, this.cwd, i, () => this[gi](t2, String(t2.linkpath), "symlink", e), (r) => {
147204
147033
  this[O2](r, t2), e();
147205
147034
  });
147206
147035
  }
147207
147036
  [Ir](t2, e) {
147208
- let i = f(import_node_path16.default.resolve(this.cwd, String(t2.linkpath))), r = f(String(t2.linkpath)).split("/");
147037
+ let i = f(import_node_path18.default.resolve(this.cwd, String(t2.linkpath))), r = f(String(t2.linkpath)).split("/");
147209
147038
  this[Re](t2, this.cwd, r, () => this[gi](t2, i, "link", e), (n) => {
147210
147039
  this[O2](n, t2), e();
147211
147040
  });
@@ -147213,10 +147042,10 @@ var Xt = class extends rt {
147213
147042
  [Re](t2, e, i, r, n) {
147214
147043
  let o = i.shift();
147215
147044
  if (this.preservePaths || o === void 0) return r();
147216
- let h = import_node_path16.default.resolve(e, o);
147217
- import_node_fs12.default.lstat(h, (a, l) => {
147045
+ let h = import_node_path18.default.resolve(e, o);
147046
+ import_node_fs13.default.lstat(h, (a, l) => {
147218
147047
  if (a) return r();
147219
- if (l?.isSymbolicLink()) return n(new St(h, import_node_path16.default.resolve(h, i.join("/"))));
147048
+ if (l?.isSymbolicLink()) return n(new St(h, import_node_path18.default.resolve(h, i.join("/"))));
147220
147049
  this[Re](t2, h, i, r, n);
147221
147050
  });
147222
147051
  }
@@ -147250,7 +147079,7 @@ var Xt = class extends rt {
147250
147079
  });
147251
147080
  }, n = () => {
147252
147081
  if (t2.absolute !== this.cwd) {
147253
- let h = f(import_node_path16.default.dirname(String(t2.absolute)));
147082
+ let h = f(import_node_path18.default.dirname(String(t2.absolute)));
147254
147083
  if (h !== this.cwd) return this[yt](h, this.dmode, (a) => {
147255
147084
  if (a) {
147256
147085
  this[O2](a, t2), i();
@@ -147261,7 +147090,7 @@ var Xt = class extends rt {
147261
147090
  }
147262
147091
  o();
147263
147092
  }, o = () => {
147264
- import_node_fs12.default.lstat(String(t2.absolute), (h, a) => {
147093
+ import_node_fs13.default.lstat(String(t2.absolute), (h, a) => {
147265
147094
  if (a && (this.keep || this.newer && a.mtime > (t2.mtime ?? a.mtime))) {
147266
147095
  this[Ls](t2), i();
147267
147096
  return;
@@ -147270,9 +147099,9 @@ var Xt = class extends rt {
147270
147099
  if (a.isDirectory()) {
147271
147100
  if (t2.type === "Directory") {
147272
147101
  let l = this.chmod && t2.mode && (a.mode & 4095) !== t2.mode, c = (d) => this[P2](d ?? null, t2, i);
147273
- return l ? import_node_fs12.default.chmod(String(t2.absolute), Number(t2.mode), c) : c();
147102
+ return l ? import_node_fs13.default.chmod(String(t2.absolute), Number(t2.mode), c) : c();
147274
147103
  }
147275
- if (t2.absolute !== this.cwd) return import_node_fs12.default.rmdir(String(t2.absolute), (l) => this[P2](l ?? null, t2, i));
147104
+ if (t2.absolute !== this.cwd) return import_node_fs13.default.rmdir(String(t2.absolute), (l) => this[P2](l ?? null, t2, i));
147276
147105
  }
147277
147106
  if (t2.absolute === this.cwd) return this[P2](null, t2, i);
147278
147107
  uo(String(t2.absolute), (l) => this[P2](l ?? null, t2, i));
@@ -147300,7 +147129,7 @@ var Xt = class extends rt {
147300
147129
  }
147301
147130
  }
147302
147131
  [gi](t2, e, i, r) {
147303
- import_node_fs12.default[i](e, String(t2.absolute), (n) => {
147132
+ import_node_fs13.default[i](e, String(t2.absolute), (n) => {
147304
147133
  n ? this[O2](n, t2) : (this[$t](), t2.resume()), r();
147305
147134
  });
147306
147135
  }
@@ -147325,23 +147154,23 @@ var xe = class extends Xt {
147325
147154
  this[Oe] = true;
147326
147155
  }
147327
147156
  if (t2.absolute !== this.cwd) {
147328
- let n = f(import_node_path16.default.dirname(String(t2.absolute)));
147157
+ let n = f(import_node_path18.default.dirname(String(t2.absolute)));
147329
147158
  if (n !== this.cwd) {
147330
147159
  let o = this[yt](n, this.dmode);
147331
147160
  if (o) return this[O2](o, t2);
147332
147161
  }
147333
147162
  }
147334
- let [e, i] = ye(() => import_node_fs12.default.lstatSync(String(t2.absolute)));
147163
+ let [e, i] = ye(() => import_node_fs13.default.lstatSync(String(t2.absolute)));
147335
147164
  if (i && (this.keep || this.newer && i.mtime > (t2.mtime ?? i.mtime))) return this[Ls](t2);
147336
147165
  if (e || this[Os](t2, i)) return this[P2](null, t2);
147337
147166
  if (i.isDirectory()) {
147338
147167
  if (t2.type === "Directory") {
147339
147168
  let o = this.chmod && t2.mode && (i.mode & 4095) !== t2.mode, [h] = o ? ye(() => {
147340
- import_node_fs12.default.chmodSync(String(t2.absolute), Number(t2.mode));
147169
+ import_node_fs13.default.chmodSync(String(t2.absolute), Number(t2.mode));
147341
147170
  }) : [];
147342
147171
  return this[P2](h, t2);
147343
147172
  }
147344
- let [n] = ye(() => import_node_fs12.default.rmdirSync(String(t2.absolute)));
147173
+ let [n] = ye(() => import_node_fs13.default.rmdirSync(String(t2.absolute)));
147345
147174
  this[P2](n, t2);
147346
147175
  }
147347
147176
  let [r] = t2.absolute === this.cwd ? [] : ye(() => po(String(t2.absolute)));
@@ -147351,21 +147180,21 @@ var xe = class extends Xt {
147351
147180
  let i = typeof t2.mode == "number" ? t2.mode & 4095 : this.fmode, r = (h) => {
147352
147181
  let a;
147353
147182
  try {
147354
- import_node_fs12.default.closeSync(n);
147183
+ import_node_fs13.default.closeSync(n);
147355
147184
  } catch (l) {
147356
147185
  a = l;
147357
147186
  }
147358
147187
  (h || a) && this[O2](h || a, t2), e();
147359
147188
  }, n;
147360
147189
  try {
147361
- n = import_node_fs12.default.openSync(String(t2.absolute), us(t2.size), i);
147190
+ n = import_node_fs13.default.openSync(String(t2.absolute), us(t2.size), i);
147362
147191
  } catch (h) {
147363
147192
  return r(h);
147364
147193
  }
147365
147194
  let o = this.transform && this.transform(t2) || t2;
147366
147195
  o !== t2 && (o.on("error", (h) => this[O2](h, t2)), t2.pipe(o)), o.on("data", (h) => {
147367
147196
  try {
147368
- import_node_fs12.default.writeSync(n, h, 0, h.length);
147197
+ import_node_fs13.default.writeSync(n, h, 0, h.length);
147369
147198
  } catch (a) {
147370
147199
  r(a);
147371
147200
  }
@@ -147374,10 +147203,10 @@ var xe = class extends Xt {
147374
147203
  if (t2.mtime && !this.noMtime) {
147375
147204
  let a = t2.atime || /* @__PURE__ */ new Date(), l = t2.mtime;
147376
147205
  try {
147377
- import_node_fs12.default.futimesSync(n, a, l);
147206
+ import_node_fs13.default.futimesSync(n, a, l);
147378
147207
  } catch (c) {
147379
147208
  try {
147380
- import_node_fs12.default.utimesSync(String(t2.absolute), a, l);
147209
+ import_node_fs13.default.utimesSync(String(t2.absolute), a, l);
147381
147210
  } catch {
147382
147211
  h = c;
147383
147212
  }
@@ -147386,10 +147215,10 @@ var xe = class extends Xt {
147386
147215
  if (this[ge](t2)) {
147387
147216
  let a = this[be](t2), l = this[_e](t2);
147388
147217
  try {
147389
- import_node_fs12.default.fchownSync(n, Number(a), Number(l));
147218
+ import_node_fs13.default.fchownSync(n, Number(a), Number(l));
147390
147219
  } catch (c) {
147391
147220
  try {
147392
- import_node_fs12.default.chownSync(String(t2.absolute), Number(a), Number(l));
147221
+ import_node_fs13.default.chownSync(String(t2.absolute), Number(a), Number(l));
147393
147222
  } catch {
147394
147223
  h = h || c;
147395
147224
  }
@@ -147405,11 +147234,11 @@ var xe = class extends Xt {
147405
147234
  return;
147406
147235
  }
147407
147236
  if (t2.mtime && !this.noMtime) try {
147408
- import_node_fs12.default.utimesSync(String(t2.absolute), t2.atime || /* @__PURE__ */ new Date(), t2.mtime);
147237
+ import_node_fs13.default.utimesSync(String(t2.absolute), t2.atime || /* @__PURE__ */ new Date(), t2.mtime);
147409
147238
  } catch {
147410
147239
  }
147411
147240
  if (this[ge](t2)) try {
147412
- import_node_fs12.default.chownSync(String(t2.absolute), Number(this[be](t2)), Number(this[_e](t2)));
147241
+ import_node_fs13.default.chownSync(String(t2.absolute), Number(this[be](t2)), Number(this[_e](t2)));
147413
147242
  } catch {
147414
147243
  }
147415
147244
  e(), t2.resume();
@@ -147425,30 +147254,30 @@ var xe = class extends Xt {
147425
147254
  if (this.preservePaths || i.length === 0) return r();
147426
147255
  let o = e;
147427
147256
  for (let h of i) {
147428
- o = import_node_path16.default.resolve(o, h);
147429
- let [a, l] = ye(() => import_node_fs12.default.lstatSync(o));
147257
+ o = import_node_path18.default.resolve(o, h);
147258
+ let [a, l] = ye(() => import_node_fs13.default.lstatSync(o));
147430
147259
  if (a) return r();
147431
- if (l.isSymbolicLink()) return n(new St(o, import_node_path16.default.resolve(e, i.join("/"))));
147260
+ if (l.isSymbolicLink()) return n(new St(o, import_node_path18.default.resolve(e, i.join("/"))));
147432
147261
  }
147433
147262
  r();
147434
147263
  }
147435
147264
  [gi](t2, e, i, r) {
147436
147265
  let n = `${i}Sync`;
147437
147266
  try {
147438
- import_node_fs12.default[n](e, String(t2.absolute)), r(), t2.resume();
147267
+ import_node_fs13.default[n](e, String(t2.absolute)), r(), t2.resume();
147439
147268
  } catch (o) {
147440
147269
  return this[O2](o, t2);
147441
147270
  }
147442
147271
  }
147443
147272
  };
147444
147273
  var Eo = (s3) => {
147445
- let t2 = new xe(s3), e = s3.file, i = import_node_fs11.default.statSync(e), r = s3.maxReadSize || 16 * 1024 * 1024;
147274
+ let t2 = new xe(s3), e = s3.file, i = import_node_fs12.default.statSync(e), r = s3.maxReadSize || 16 * 1024 * 1024;
147446
147275
  new Be(e, { readSize: r, size: i.size }).pipe(t2);
147447
147276
  };
147448
147277
  var wo = (s3, t2) => {
147449
147278
  let e = new Xt(s3), i = s3.maxReadSize || 16 * 1024 * 1024, r = s3.file;
147450
147279
  return new Promise((o, h) => {
147451
- e.on("error", h), e.on("close", o), import_node_fs11.default.stat(r, (a, l) => {
147280
+ e.on("error", h), e.on("close", o), import_node_fs12.default.stat(r, (a, l) => {
147452
147281
  if (a) h(a);
147453
147282
  else {
147454
147283
  let c = new _t(r, { readSize: i, size: l.size });
@@ -147464,15 +147293,15 @@ var yo = (s3, t2) => {
147464
147293
  let e = new kt(s3), i = true, r, n;
147465
147294
  try {
147466
147295
  try {
147467
- r = import_node_fs15.default.openSync(s3.file, "r+");
147296
+ r = import_node_fs16.default.openSync(s3.file, "r+");
147468
147297
  } catch (a) {
147469
- if (a?.code === "ENOENT") r = import_node_fs15.default.openSync(s3.file, "w+");
147298
+ if (a?.code === "ENOENT") r = import_node_fs16.default.openSync(s3.file, "w+");
147470
147299
  else throw a;
147471
147300
  }
147472
- let o = import_node_fs15.default.fstatSync(r), h = Buffer.alloc(512);
147301
+ let o = import_node_fs16.default.fstatSync(r), h = Buffer.alloc(512);
147473
147302
  t: for (n = 0; n < o.size; n += 512) {
147474
147303
  for (let c = 0, d = 0; c < 512; c += d) {
147475
- if (d = import_node_fs15.default.readSync(r, h, c, h.length - c, n + c), n === 0 && h[0] === 31 && h[1] === 139) throw new Error("cannot append to compressed archives");
147304
+ if (d = import_node_fs16.default.readSync(r, h, c, h.length - c, n + c), n === 0 && h[0] === 31 && h[1] === 139) throw new Error("cannot append to compressed archives");
147476
147305
  if (!d) break t;
147477
147306
  }
147478
147307
  let a = new F2(h);
@@ -147484,7 +147313,7 @@ var yo = (s3, t2) => {
147484
147313
  i = false, Ro(s3, e, n, r, t2);
147485
147314
  } finally {
147486
147315
  if (i) try {
147487
- import_node_fs15.default.closeSync(r);
147316
+ import_node_fs16.default.closeSync(r);
147488
147317
  } catch {
147489
147318
  }
147490
147319
  }
@@ -147497,29 +147326,29 @@ var go = (s3, t2) => {
147497
147326
  t2 = Array.from(t2);
147498
147327
  let e = new wt(s3), i = (n, o, h) => {
147499
147328
  let a = (T2, D2) => {
147500
- T2 ? import_node_fs15.default.close(n, (E2) => h(T2)) : h(null, D2);
147329
+ T2 ? import_node_fs16.default.close(n, (E2) => h(T2)) : h(null, D2);
147501
147330
  }, l = 0;
147502
147331
  if (o === 0) return a(null, 0);
147503
147332
  let c = 0, d = Buffer.alloc(512), S2 = (T2, D2) => {
147504
147333
  if (T2 || D2 === void 0) return a(T2);
147505
- if (c += D2, c < 512 && D2) return import_node_fs15.default.read(n, d, c, d.length - c, l + c, S2);
147334
+ if (c += D2, c < 512 && D2) return import_node_fs16.default.read(n, d, c, d.length - c, l + c, S2);
147506
147335
  if (l === 0 && d[0] === 31 && d[1] === 139) return a(new Error("cannot append to compressed archives"));
147507
147336
  if (c < 512) return a(null, l);
147508
147337
  let E2 = new F2(d);
147509
147338
  if (!E2.cksumValid) return a(null, l);
147510
147339
  let x2 = 512 * Math.ceil((E2.size ?? 0) / 512);
147511
147340
  if (l + x2 + 512 > o || (l += x2 + 512, l >= o)) return a(null, l);
147512
- s3.mtimeCache && E2.mtime && s3.mtimeCache.set(String(E2.path), E2.mtime), c = 0, import_node_fs15.default.read(n, d, 0, 512, l, S2);
147341
+ s3.mtimeCache && E2.mtime && s3.mtimeCache.set(String(E2.path), E2.mtime), c = 0, import_node_fs16.default.read(n, d, 0, 512, l, S2);
147513
147342
  };
147514
- import_node_fs15.default.read(n, d, 0, 512, l, S2);
147343
+ import_node_fs16.default.read(n, d, 0, 512, l, S2);
147515
147344
  };
147516
147345
  return new Promise((n, o) => {
147517
147346
  e.on("error", o);
147518
147347
  let h = "r+", a = (l, c) => {
147519
- if (l && l.code === "ENOENT" && h === "r+") return h = "w+", import_node_fs15.default.open(s3.file, h, a);
147348
+ if (l && l.code === "ENOENT" && h === "r+") return h = "w+", import_node_fs16.default.open(s3.file, h, a);
147520
147349
  if (l || !c) return o(l);
147521
- import_node_fs15.default.fstat(c, (d, S2) => {
147522
- if (d) return import_node_fs15.default.close(c, () => o(d));
147350
+ import_node_fs16.default.fstat(c, (d, S2) => {
147351
+ if (d) return import_node_fs16.default.close(c, () => o(d));
147523
147352
  i(c, S2.size, (T2, D2) => {
147524
147353
  if (T2) return o(T2);
147525
147354
  let E2 = new et(s3.file, { fd: c, start: D2 });
@@ -147527,16 +147356,16 @@ var go = (s3, t2) => {
147527
147356
  });
147528
147357
  });
147529
147358
  };
147530
- import_node_fs15.default.open(s3.file, h, a);
147359
+ import_node_fs16.default.open(s3.file, h, a);
147531
147360
  });
147532
147361
  };
147533
147362
  var bo = (s3, t2) => {
147534
147363
  t2.forEach((e) => {
147535
- e.charAt(0) === "@" ? Ct({ file: import_node_path20.default.resolve(s3.cwd, e.slice(1)), sync: true, noResume: true, onReadEntry: (i) => s3.add(i) }) : s3.add(e);
147364
+ e.charAt(0) === "@" ? Ct({ file: import_node_path22.default.resolve(s3.cwd, e.slice(1)), sync: true, noResume: true, onReadEntry: (i) => s3.add(i) }) : s3.add(e);
147536
147365
  }), s3.end();
147537
147366
  };
147538
147367
  var _o = async (s3, t2) => {
147539
- for (let e of t2) e.charAt(0) === "@" ? await Ct({ file: import_node_path20.default.resolve(String(s3.cwd), e.slice(1)), noResume: true, onReadEntry: (i) => s3.add(i) }) : s3.add(e);
147368
+ for (let e of t2) e.charAt(0) === "@" ? await Ct({ file: import_node_path22.default.resolve(String(s3.cwd), e.slice(1)), noResume: true, onReadEntry: (i) => s3.add(i) }) : s3.add(e);
147540
147369
  s3.end();
147541
147370
  };
147542
147371
  var vt = K2(yo, go, () => {
@@ -147559,19 +147388,34 @@ var To = (s3) => {
147559
147388
  // src/updater/unpack.ts
147560
147389
  async function unpackTarball(opts) {
147561
147390
  const { tarballPath, destDir } = opts;
147562
- (0, import_node_fs16.rmSync)(destDir, { recursive: true, force: true });
147563
- (0, import_node_fs16.mkdirSync)(destDir, { recursive: true });
147391
+ (0, import_node_fs17.rmSync)(destDir, { recursive: true, force: true });
147392
+ (0, import_node_fs17.mkdirSync)(destDir, { recursive: true });
147564
147393
  await So({ file: tarballPath, cwd: destDir });
147565
147394
  }
147566
147395
 
147396
+ // src/updater/update-log.ts
147397
+ var import_node_fs18 = require("fs");
147398
+ var import_node_path23 = require("path");
147399
+ var LOG_PATH = (0, import_node_path23.join)(THREADBASE_ROOT, "update.log");
147400
+ function appendUpdateLog(line) {
147401
+ try {
147402
+ (0, import_node_fs18.mkdirSync)(THREADBASE_ROOT, { recursive: true });
147403
+ (0, import_node_fs18.appendFileSync)(LOG_PATH, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
147404
+ `, "utf8");
147405
+ } catch {
147406
+ }
147407
+ }
147408
+
147567
147409
  // src/updater/install.ts
147568
147410
  async function runInstall(opts) {
147569
147411
  if (isBrewInstall()) {
147570
- return {
147412
+ const result = {
147571
147413
  kind: "unsupported-install",
147572
147414
  reason: "Installed via Homebrew \u2014 run `brew upgrade tb-streamer` to update.",
147573
147415
  current: opts.currentVersion
147574
147416
  };
147417
+ appendUpdateLog(`[no-op] ${result.reason}`);
147418
+ return result;
147575
147419
  }
147576
147420
  const check2 = await checkForUpdate({
147577
147421
  currentVersion: opts.currentVersion,
@@ -147579,6 +147423,9 @@ async function runInstall(opts) {
147579
147423
  pinnedVersion: opts.pinnedVersion,
147580
147424
  allowMajor: opts.allowMajor
147581
147425
  });
147426
+ appendUpdateLog(
147427
+ `[check] current=${check2.current} latest=${check2.latest ?? "none"} status=${check2.reason}`
147428
+ );
147582
147429
  if (!check2.wouldInstall) {
147583
147430
  return { kind: "no-op", reason: check2.reason, current: check2.current, latest: check2.latest };
147584
147431
  }
@@ -147604,33 +147451,27 @@ async function runInstall(opts) {
147604
147451
  const artifact = pickArtifact(manifest);
147605
147452
  if (opts.dryRun) {
147606
147453
  const asset = target.assets.find((a) => a.name === artifact.filename);
147607
- return {
147608
- kind: "dry-run",
147609
- latest: targetVersion,
147610
- tarballUrl: asset?.browserDownloadUrl ?? "(missing)"
147611
- };
147454
+ const tarballUrl = asset?.browserDownloadUrl ?? "(missing)";
147455
+ appendUpdateLog(
147456
+ `[dry-run] would install ${check2.current} \u2192 ${targetVersion} from ${tarballUrl}`
147457
+ );
147458
+ return { kind: "dry-run", latest: targetVersion, tarballUrl };
147612
147459
  }
147613
147460
  if (opts.config.defer_if_active_sessions && !opts.force && opts.runningServer) {
147614
147461
  const active = await countActiveSessions(opts.runningServer);
147615
147462
  if (active.kind === "count" && active.count > 0) {
147616
- return {
147617
- kind: "deferred",
147618
- reason: `${active.count} active session(s); use --force to interrupt`,
147619
- activeSessions: active.count,
147620
- latest: targetVersion
147621
- };
147463
+ const reason = `${active.count} active session(s); use --force to interrupt`;
147464
+ appendUpdateLog(`[deferred] ${check2.current} \u2192 ${targetVersion}: ${reason}`);
147465
+ return { kind: "deferred", reason, activeSessions: active.count, latest: targetVersion };
147622
147466
  }
147623
147467
  if (active.kind === "error") {
147624
- return {
147625
- kind: "deferred",
147626
- reason: `cannot determine active sessions (${active.reason}); use --force to override`,
147627
- activeSessions: -1,
147628
- latest: targetVersion
147629
- };
147468
+ const reason = `cannot determine active sessions (${active.reason}); use --force to override`;
147469
+ appendUpdateLog(`[deferred] ${check2.current} \u2192 ${targetVersion}: ${reason}`);
147470
+ return { kind: "deferred", reason, activeSessions: -1, latest: targetVersion };
147630
147471
  }
147631
147472
  }
147632
147473
  ensureReleasesDir();
147633
- (0, import_node_fs17.mkdirSync)(DOWNLOAD_DIR, { recursive: true });
147474
+ (0, import_node_fs19.mkdirSync)(DOWNLOAD_DIR, { recursive: true });
147634
147475
  const tarballPath = downloadPath(targetVersion, artifact.filename);
147635
147476
  await downloadAndVerify({ manifest, assets: target.assets, targetPath: tarballPath });
147636
147477
  const destDir = releaseDir(targetVersion);
@@ -147649,18 +147490,22 @@ async function runInstall(opts) {
147649
147490
  } catch (err) {
147650
147491
  restartMethod = `failed: ${err instanceof Error ? err.message : String(err)}`;
147651
147492
  }
147652
- return {
147493
+ const installed = {
147653
147494
  kind: "installed",
147654
147495
  previous: check2.current,
147655
147496
  installed: targetVersion,
147656
147497
  pruned,
147657
147498
  restart: { method: restartMethod }
147658
147499
  };
147500
+ appendUpdateLog(
147501
+ `[installed] ${installed.previous} \u2192 ${installed.installed} restart=${installed.restart.method}${pruned.length > 0 ? ` pruned=${pruned.length}` : ""}`
147502
+ );
147503
+ return installed;
147659
147504
  }
147660
147505
 
147661
147506
  // cli/prod.ts
147662
147507
  var import_node_child_process6 = require("child_process");
147663
- var import_node_fs19 = require("fs");
147508
+ var import_node_fs21 = require("fs");
147664
147509
  init_constants();
147665
147510
  init_launchd();
147666
147511
  init_marker();
@@ -147746,7 +147591,7 @@ async function runProdDoctor(opts) {
147746
147591
  return { findings, repairs };
147747
147592
  }
147748
147593
  var defaultSpawnTail = ({ files, lines, follow }) => {
147749
- const existing = files.filter((f2) => (0, import_node_fs19.existsSync)(f2));
147594
+ const existing = files.filter((f2) => (0, import_node_fs21.existsSync)(f2));
147750
147595
  if (existing.length === 0) {
147751
147596
  return Promise.resolve({
147752
147597
  ok: false,
@@ -147800,8 +147645,8 @@ function registerProdCommands(program3) {
147800
147645
  const prod = new Command("prod").description(
147801
147646
  "Manage the launchd-supervised prod streamer"
147802
147647
  );
147803
- prod.command("start").description("Restore prod after a user-held suspension").option("--preserve-logs", "Keep existing stdout + stderr logs", false).action(async (opts) => {
147804
- if (opts.preserveLogs !== true) clearSupervisorLogs();
147648
+ prod.command("start").description("Restore prod after a user-held suspension").option("--clear-logs", "Clear existing stdout + stderr logs", false).action(async (opts) => {
147649
+ if (opts.clearLogs === true) clearSupervisorLogs();
147805
147650
  const r = await runProdStart();
147806
147651
  log4.info(r.message, void 0, "console");
147807
147652
  if (!r.ok) process.exitCode = 1;
@@ -147819,10 +147664,10 @@ function registerProdCommands(program3) {
147819
147664
  ];
147820
147665
  log4.info(parts.join("\n "), void 0, "console");
147821
147666
  });
147822
- prod.command("restart").description("Stop + restart the supervised streamer (re-reads service definition)").option("--preserve-logs", "Keep existing stdout + stderr logs", false).action(async (opts) => {
147667
+ prod.command("restart").description("Stop + restart the supervised streamer (re-reads service definition)").option("--clear-logs", "Clear existing stdout + stderr logs", false).action(async (opts) => {
147823
147668
  const sup = getSupervisor();
147824
147669
  const specPath = process.platform === "darwin" ? darwinPlistPath() : "";
147825
- if (opts.preserveLogs !== true) clearSupervisorLogs();
147670
+ if (opts.clearLogs === true) clearSupervisorLogs();
147826
147671
  sup.bootoutAgent();
147827
147672
  sup.bootstrapAgent(specPath);
147828
147673
  const what = process.platform === "darwin" ? `agent restarted from ${specPath}` : `task '${TASK_NAME}' restarted`;
@@ -147876,6 +147721,7 @@ program2.command("serve").description("Start the streamer server").option("-p, -
147876
147721
  const apiKey = opts.apiKey ?? loadOrCreateApiKey();
147877
147722
  const publicUrl = opts.publicUrl ?? loadPublicUrl() ?? null;
147878
147723
  const isProdInvocation = opts.prod === true || process.ppid === 1;
147724
+ if (!isProdInvocation) appendDevSessionMarker();
147879
147725
  let resolvedPort = requestedPort;
147880
147726
  if (!isProdInvocation) {
147881
147727
  const { resolveDevPlan: resolveDevPlan2, detectProdActive: detectProdActive2, isPortInUse: isPortInUse2, findFreePort: findFreePort2, takeoverProd: takeoverProd2 } = await Promise.resolve().then(() => (init_dev_takeover(), dev_takeover_exports));
@@ -147902,6 +147748,7 @@ program2.command("serve").description("Start the streamer server").option("-p, -
147902
147748
  const server = new StreamerServer({
147903
147749
  port: resolvedPort,
147904
147750
  apiKey,
147751
+ apiKeySource: opts.apiKey ? "cli" : "config",
147905
147752
  localNoAuth: opts.localNoAuth,
147906
147753
  verbose: opts.verbose,
147907
147754
  logMenubarRequests: opts.logMenubarRequests,
@@ -147965,8 +147812,8 @@ program2.command("cache").description("Manage the local SQLite conversation cach
147965
147812
  `${process.env.HOME}/.threadbase/cache`
147966
147813
  ).action((opts) => {
147967
147814
  const { rmSync: rmSync6, existsSync: existsSync11 } = require("fs");
147968
- const { join: join24 } = require("path");
147969
- const dbPath = join24(opts.cacheDir, "cache.db");
147815
+ const { join: join26 } = require("path");
147816
+ const dbPath = join26(opts.cacheDir, "cache.db");
147970
147817
  for (const suffix of ["", "-shm", "-wal"]) {
147971
147818
  const f2 = dbPath + suffix;
147972
147819
  if (existsSync11(f2)) {
@@ -148015,6 +147862,9 @@ program2.command("update").description("Check for streamer updates from GitHub R
148015
147862
  pinnedVersion: opts.version,
148016
147863
  allowMajor: opts.allowMajor
148017
147864
  });
147865
+ appendUpdateLog(
147866
+ `[check] current=${result2.current} latest=${result2.latest ?? "none"} status=${result2.reason}`
147867
+ );
148018
147868
  log7.info(`Current : ${result2.current}`, void 0, "console");
148019
147869
  log7.info(`Latest : ${result2.latest ?? "(none)"}`, void 0, "console");
148020
147870
  log7.info(`Channel : ${cfg.channel}`, void 0, "console");
@@ -148067,6 +147917,7 @@ program2.command("update").description("Check for streamer updates from GitHub R
148067
147917
  }
148068
147918
  } catch (err) {
148069
147919
  const message = err instanceof Error ? err.message : String(err);
147920
+ appendUpdateLog(`[error] ${message}`);
148070
147921
  log7.error(`Update failed: ${message}`, { error: message }, "console");
148071
147922
  process.exitCode = 1;
148072
147923
  }