@threadbase-sh/streamer 1.20.0 → 1.21.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 +442 -616
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +154 -316
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +159 -321
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/cli.cjs
CHANGED
|
@@ -26078,7 +26078,7 @@ var require_thread_stream = __commonJS({
|
|
|
26078
26078
|
var { version: version2 } = require_package();
|
|
26079
26079
|
var { EventEmitter: EventEmitter6 } = require("events");
|
|
26080
26080
|
var { Worker: Worker2 } = require("worker_threads");
|
|
26081
|
-
var { join:
|
|
26081
|
+
var { join: join25 } = require("path");
|
|
26082
26082
|
var { pathToFileURL } = require("url");
|
|
26083
26083
|
var { wait } = require_wait();
|
|
26084
26084
|
var {
|
|
@@ -26129,7 +26129,7 @@ var require_thread_stream = __commonJS({
|
|
|
26129
26129
|
function createWorker(stream, opts) {
|
|
26130
26130
|
const { filename, workerData } = opts;
|
|
26131
26131
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
26132
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
26132
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join25(__dirname, "lib", "worker.js");
|
|
26133
26133
|
const worker = new Worker2(toExecute, {
|
|
26134
26134
|
...opts.workerOpts,
|
|
26135
26135
|
name: opts.workerOpts?.name || "thread-stream",
|
|
@@ -26597,7 +26597,7 @@ var require_transport = __commonJS({
|
|
|
26597
26597
|
var { createRequire } = require("module");
|
|
26598
26598
|
var { existsSync: existsSync11 } = require("fs");
|
|
26599
26599
|
var getCallers = require_caller();
|
|
26600
|
-
var { join:
|
|
26600
|
+
var { join: join25, isAbsolute: isAbsolute3, sep: sep2 } = require("path");
|
|
26601
26601
|
var { fileURLToPath: fileURLToPath3 } = require("url");
|
|
26602
26602
|
var sleep = require_atomic_sleep();
|
|
26603
26603
|
var onExit = require_on_exit_leak_free();
|
|
@@ -26750,7 +26750,7 @@ var require_transport = __commonJS({
|
|
|
26750
26750
|
throw new Error("only one of target or targets can be specified");
|
|
26751
26751
|
}
|
|
26752
26752
|
if (targets) {
|
|
26753
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
26753
|
+
target = bundlerOverrides["pino-worker"] || join25(__dirname, "worker.js");
|
|
26754
26754
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
26755
26755
|
return {
|
|
26756
26756
|
...dest,
|
|
@@ -26768,7 +26768,7 @@ var require_transport = __commonJS({
|
|
|
26768
26768
|
});
|
|
26769
26769
|
});
|
|
26770
26770
|
} else if (pipeline2) {
|
|
26771
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
26771
|
+
target = bundlerOverrides["pino-worker"] || join25(__dirname, "worker.js");
|
|
26772
26772
|
options.pipelines = [pipeline2.map((dest) => {
|
|
26773
26773
|
return {
|
|
26774
26774
|
...dest,
|
|
@@ -26791,7 +26791,7 @@ var require_transport = __commonJS({
|
|
|
26791
26791
|
return origin;
|
|
26792
26792
|
}
|
|
26793
26793
|
if (origin === "pino/file") {
|
|
26794
|
-
return
|
|
26794
|
+
return join25(__dirname, "..", "file.js");
|
|
26795
26795
|
}
|
|
26796
26796
|
let fixTarget2;
|
|
26797
26797
|
for (const filePath of callers) {
|
|
@@ -27772,7 +27772,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
27772
27772
|
return circularValue;
|
|
27773
27773
|
}
|
|
27774
27774
|
let res = "";
|
|
27775
|
-
let
|
|
27775
|
+
let join25 = ",";
|
|
27776
27776
|
const originalIndentation = indentation;
|
|
27777
27777
|
if (Array.isArray(value)) {
|
|
27778
27778
|
if (value.length === 0) {
|
|
@@ -27786,7 +27786,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
27786
27786
|
indentation += spacer;
|
|
27787
27787
|
res += `
|
|
27788
27788
|
${indentation}`;
|
|
27789
|
-
|
|
27789
|
+
join25 = `,
|
|
27790
27790
|
${indentation}`;
|
|
27791
27791
|
}
|
|
27792
27792
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -27794,13 +27794,13 @@ ${indentation}`;
|
|
|
27794
27794
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
27795
27795
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
27796
27796
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
27797
|
-
res +=
|
|
27797
|
+
res += join25;
|
|
27798
27798
|
}
|
|
27799
27799
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
27800
27800
|
res += tmp !== void 0 ? tmp : "null";
|
|
27801
27801
|
if (value.length - 1 > maximumBreadth) {
|
|
27802
27802
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
27803
|
-
res += `${
|
|
27803
|
+
res += `${join25}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
27804
27804
|
}
|
|
27805
27805
|
if (spacer !== "") {
|
|
27806
27806
|
res += `
|
|
@@ -27821,7 +27821,7 @@ ${originalIndentation}`;
|
|
|
27821
27821
|
let separator = "";
|
|
27822
27822
|
if (spacer !== "") {
|
|
27823
27823
|
indentation += spacer;
|
|
27824
|
-
|
|
27824
|
+
join25 = `,
|
|
27825
27825
|
${indentation}`;
|
|
27826
27826
|
whitespace = " ";
|
|
27827
27827
|
}
|
|
@@ -27835,13 +27835,13 @@ ${indentation}`;
|
|
|
27835
27835
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
27836
27836
|
if (tmp !== void 0) {
|
|
27837
27837
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
27838
|
-
separator =
|
|
27838
|
+
separator = join25;
|
|
27839
27839
|
}
|
|
27840
27840
|
}
|
|
27841
27841
|
if (keyLength > maximumBreadth) {
|
|
27842
27842
|
const removedKeys = keyLength - maximumBreadth;
|
|
27843
27843
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
27844
|
-
separator =
|
|
27844
|
+
separator = join25;
|
|
27845
27845
|
}
|
|
27846
27846
|
if (spacer !== "" && separator.length > 1) {
|
|
27847
27847
|
res = `
|
|
@@ -27882,7 +27882,7 @@ ${originalIndentation}`;
|
|
|
27882
27882
|
}
|
|
27883
27883
|
const originalIndentation = indentation;
|
|
27884
27884
|
let res = "";
|
|
27885
|
-
let
|
|
27885
|
+
let join25 = ",";
|
|
27886
27886
|
if (Array.isArray(value)) {
|
|
27887
27887
|
if (value.length === 0) {
|
|
27888
27888
|
return "[]";
|
|
@@ -27895,7 +27895,7 @@ ${originalIndentation}`;
|
|
|
27895
27895
|
indentation += spacer;
|
|
27896
27896
|
res += `
|
|
27897
27897
|
${indentation}`;
|
|
27898
|
-
|
|
27898
|
+
join25 = `,
|
|
27899
27899
|
${indentation}`;
|
|
27900
27900
|
}
|
|
27901
27901
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -27903,13 +27903,13 @@ ${indentation}`;
|
|
|
27903
27903
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
27904
27904
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
27905
27905
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
27906
|
-
res +=
|
|
27906
|
+
res += join25;
|
|
27907
27907
|
}
|
|
27908
27908
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
27909
27909
|
res += tmp !== void 0 ? tmp : "null";
|
|
27910
27910
|
if (value.length - 1 > maximumBreadth) {
|
|
27911
27911
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
27912
|
-
res += `${
|
|
27912
|
+
res += `${join25}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
27913
27913
|
}
|
|
27914
27914
|
if (spacer !== "") {
|
|
27915
27915
|
res += `
|
|
@@ -27922,7 +27922,7 @@ ${originalIndentation}`;
|
|
|
27922
27922
|
let whitespace = "";
|
|
27923
27923
|
if (spacer !== "") {
|
|
27924
27924
|
indentation += spacer;
|
|
27925
|
-
|
|
27925
|
+
join25 = `,
|
|
27926
27926
|
${indentation}`;
|
|
27927
27927
|
whitespace = " ";
|
|
27928
27928
|
}
|
|
@@ -27931,7 +27931,7 @@ ${indentation}`;
|
|
|
27931
27931
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
27932
27932
|
if (tmp !== void 0) {
|
|
27933
27933
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
27934
|
-
separator =
|
|
27934
|
+
separator = join25;
|
|
27935
27935
|
}
|
|
27936
27936
|
}
|
|
27937
27937
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -27989,20 +27989,20 @@ ${originalIndentation}`;
|
|
|
27989
27989
|
indentation += spacer;
|
|
27990
27990
|
let res2 = `
|
|
27991
27991
|
${indentation}`;
|
|
27992
|
-
const
|
|
27992
|
+
const join26 = `,
|
|
27993
27993
|
${indentation}`;
|
|
27994
27994
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
27995
27995
|
let i = 0;
|
|
27996
27996
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
27997
27997
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
27998
27998
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
27999
|
-
res2 +=
|
|
27999
|
+
res2 += join26;
|
|
28000
28000
|
}
|
|
28001
28001
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
28002
28002
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
28003
28003
|
if (value.length - 1 > maximumBreadth) {
|
|
28004
28004
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
28005
|
-
res2 += `${
|
|
28005
|
+
res2 += `${join26}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
28006
28006
|
}
|
|
28007
28007
|
res2 += `
|
|
28008
28008
|
${originalIndentation}`;
|
|
@@ -28018,16 +28018,16 @@ ${originalIndentation}`;
|
|
|
28018
28018
|
return '"[Object]"';
|
|
28019
28019
|
}
|
|
28020
28020
|
indentation += spacer;
|
|
28021
|
-
const
|
|
28021
|
+
const join25 = `,
|
|
28022
28022
|
${indentation}`;
|
|
28023
28023
|
let res = "";
|
|
28024
28024
|
let separator = "";
|
|
28025
28025
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
28026
28026
|
if (isTypedArrayWithEntries(value)) {
|
|
28027
|
-
res += stringifyTypedArray(value,
|
|
28027
|
+
res += stringifyTypedArray(value, join25, maximumBreadth);
|
|
28028
28028
|
keys = keys.slice(value.length);
|
|
28029
28029
|
maximumPropertiesToStringify -= value.length;
|
|
28030
|
-
separator =
|
|
28030
|
+
separator = join25;
|
|
28031
28031
|
}
|
|
28032
28032
|
if (deterministic) {
|
|
28033
28033
|
keys = sort(keys, comparator);
|
|
@@ -28038,13 +28038,13 @@ ${indentation}`;
|
|
|
28038
28038
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
28039
28039
|
if (tmp !== void 0) {
|
|
28040
28040
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
28041
|
-
separator =
|
|
28041
|
+
separator = join25;
|
|
28042
28042
|
}
|
|
28043
28043
|
}
|
|
28044
28044
|
if (keyLength > maximumBreadth) {
|
|
28045
28045
|
const removedKeys = keyLength - maximumBreadth;
|
|
28046
28046
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
28047
|
-
separator =
|
|
28047
|
+
separator = join25;
|
|
28048
28048
|
}
|
|
28049
28049
|
if (separator !== "") {
|
|
28050
28050
|
res = `
|
|
@@ -124399,20 +124399,20 @@ var require_semver2 = __commonJS({
|
|
|
124399
124399
|
|
|
124400
124400
|
// src/lifecycle/constants.ts
|
|
124401
124401
|
function installDir() {
|
|
124402
|
-
return process.env.THREADBASE_INSTALL_DIR ?? (0,
|
|
124402
|
+
return process.env.THREADBASE_INSTALL_DIR ?? (0, import_node_path22.join)((0, import_node_os4.homedir)(), ".threadbase");
|
|
124403
124403
|
}
|
|
124404
124404
|
function markerPath() {
|
|
124405
|
-
return (0,
|
|
124405
|
+
return (0, import_node_path22.join)(installDir(), "prod-suspended.json");
|
|
124406
124406
|
}
|
|
124407
124407
|
function prefsPath() {
|
|
124408
|
-
return (0,
|
|
124408
|
+
return (0, import_node_path22.join)(installDir(), "dev-prefs.json");
|
|
124409
124409
|
}
|
|
124410
|
-
var import_node_os4,
|
|
124410
|
+
var import_node_os4, import_node_path22, LAUNCHD_LABEL, TASK_NAME;
|
|
124411
124411
|
var init_constants = __esm({
|
|
124412
124412
|
"src/lifecycle/constants.ts"() {
|
|
124413
124413
|
"use strict";
|
|
124414
124414
|
import_node_os4 = require("os");
|
|
124415
|
-
|
|
124415
|
+
import_node_path22 = require("path");
|
|
124416
124416
|
LAUNCHD_LABEL = "com.ronen.threadbase";
|
|
124417
124417
|
TASK_NAME = process.env.THREADBASE_TASK_NAME ?? "Threadbase";
|
|
124418
124418
|
}
|
|
@@ -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,
|
|
124491
|
-
return { stdout: (0,
|
|
124490
|
+
const dir = (0, import_node_path23.join)(installDir(), "logs");
|
|
124491
|
+
return { stdout: (0, import_node_path23.join)(dir, "stdout.log"), stderr: (0, import_node_path23.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,
|
|
124511
|
+
var import_node_child_process4, import_node_path23, 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
|
-
|
|
124516
|
+
import_node_path23 = 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,
|
|
124541
|
+
if (!(0, import_node_fs19.existsSync)(markerPath())) return null;
|
|
124542
124542
|
try {
|
|
124543
|
-
const raw2 = (0,
|
|
124543
|
+
const raw2 = (0, import_node_fs19.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,
|
|
124555
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path24.dirname)(markerPath()), { recursive: true });
|
|
124556
124556
|
const tmp = `${markerPath()}.tmp`;
|
|
124557
|
-
(0,
|
|
124557
|
+
(0, import_node_fs19.writeFileSync)(tmp, `${JSON.stringify(marker, null, 2)}
|
|
124558
124558
|
`, { mode: 384 });
|
|
124559
|
-
(0,
|
|
124559
|
+
(0, import_node_fs19.renameSync)(tmp, markerPath());
|
|
124560
124560
|
}
|
|
124561
124561
|
function clearMarker() {
|
|
124562
|
-
if ((0,
|
|
124562
|
+
if ((0, import_node_fs19.existsSync)(markerPath())) (0, import_node_fs19.rmSync)(markerPath());
|
|
124563
124563
|
}
|
|
124564
|
-
var
|
|
124564
|
+
var import_node_fs19, import_node_path24, log3;
|
|
124565
124565
|
var init_marker = __esm({
|
|
124566
124566
|
"src/lifecycle/marker.ts"() {
|
|
124567
124567
|
"use strict";
|
|
124568
|
-
|
|
124569
|
-
|
|
124568
|
+
import_node_fs19 = require("fs");
|
|
124569
|
+
import_node_path24 = 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,
|
|
124664
|
+
if (!(0, import_node_fs21.existsSync)(path2)) return { repos: {} };
|
|
124665
124665
|
try {
|
|
124666
|
-
return PrefsSchema.parse(JSON.parse((0,
|
|
124666
|
+
return PrefsSchema.parse(JSON.parse((0, import_node_fs21.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,
|
|
124676
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
|
|
124677
124677
|
const tmp = `${path2}.tmp`;
|
|
124678
|
-
(0,
|
|
124678
|
+
(0, import_node_fs21.writeFileSync)(tmp, `${JSON.stringify(p2, null, 2)}
|
|
124679
124679
|
`, { mode: 384 });
|
|
124680
|
-
(0,
|
|
124680
|
+
(0, import_node_fs21.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,
|
|
124701
|
+
if ((0, import_node_fs21.existsSync)(path2)) (0, import_node_fs21.rmSync)(path2);
|
|
124702
124702
|
}
|
|
124703
|
-
var
|
|
124703
|
+
var import_node_fs21, import_node_path25, log5, PrefsSchema;
|
|
124704
124704
|
var init_prefs = __esm({
|
|
124705
124705
|
"src/lifecycle/prefs.ts"() {
|
|
124706
124706
|
"use strict";
|
|
124707
|
-
|
|
124708
|
-
|
|
124707
|
+
import_node_fs21 = require("fs");
|
|
124708
|
+
import_node_path25 = 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
|
});
|
|
@@ -136445,13 +136445,23 @@ var authMiddleware = (deps) => async (c, next) => {
|
|
|
136445
136445
|
};
|
|
136446
136446
|
|
|
136447
136447
|
// src/api/middleware/cors.middleware.ts
|
|
136448
|
+
var ALLOWED_ORIGINS = /* @__PURE__ */ new Set([
|
|
136449
|
+
"http://localhost:8081",
|
|
136450
|
+
"http://localhost:19006",
|
|
136451
|
+
"http://localhost:3000"
|
|
136452
|
+
]);
|
|
136448
136453
|
var corsMiddleware = () => async (c, next) => {
|
|
136449
|
-
c.
|
|
136450
|
-
|
|
136451
|
-
|
|
136452
|
-
|
|
136454
|
+
const origin = c.req.header("origin");
|
|
136455
|
+
const allowedOrigin = origin && ALLOWED_ORIGINS.has(origin) ? origin : null;
|
|
136456
|
+
if (allowedOrigin) {
|
|
136457
|
+
c.res.headers.set("Access-Control-Allow-Origin", allowedOrigin);
|
|
136458
|
+
c.res.headers.set("Vary", "Origin");
|
|
136459
|
+
c.res.headers.set("Access-Control-Allow-Methods", "GET, POST, PATCH, OPTIONS");
|
|
136460
|
+
c.res.headers.set("Access-Control-Allow-Headers", "Authorization, Content-Type, If-None-Match");
|
|
136461
|
+
c.res.headers.set("Access-Control-Expose-Headers", "ETag");
|
|
136462
|
+
}
|
|
136453
136463
|
if (c.req.method === "OPTIONS") {
|
|
136454
|
-
return c.newResponse(null, 204);
|
|
136464
|
+
return c.newResponse(null, allowedOrigin ? 204 : 403);
|
|
136455
136465
|
}
|
|
136456
136466
|
await next();
|
|
136457
136467
|
};
|
|
@@ -136595,6 +136605,19 @@ var createMiscRoutes = (deps) => {
|
|
|
136595
136605
|
});
|
|
136596
136606
|
});
|
|
136597
136607
|
app.get("/api/profiles", (c) => c.json([]));
|
|
136608
|
+
app.post("/api/auth/rotate", (c) => {
|
|
136609
|
+
if (deps.localNoAuth) {
|
|
136610
|
+
return c.json({ error: "key rotation is disabled while localNoAuth is active" }, 403);
|
|
136611
|
+
}
|
|
136612
|
+
const { newKey, persisted } = deps.rotateApiKey();
|
|
136613
|
+
return c.json({
|
|
136614
|
+
apiKey: newKey,
|
|
136615
|
+
persisted,
|
|
136616
|
+
...persisted ? {} : {
|
|
136617
|
+
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."
|
|
136618
|
+
}
|
|
136619
|
+
});
|
|
136620
|
+
});
|
|
136598
136621
|
app.post("/api/push/register", (c) => c.json({ ok: true }));
|
|
136599
136622
|
app.post("/api/__update", async (c) => {
|
|
136600
136623
|
const cfg = loadUpdateConfig();
|
|
@@ -136796,6 +136819,11 @@ var ALREADY_HANDLED4 = 597;
|
|
|
136796
136819
|
var alreadyHandled4 = () => new Response(null, { status: ALREADY_HANDLED4 });
|
|
136797
136820
|
var createProjectRoutes = (deps) => {
|
|
136798
136821
|
const app = new Hono2();
|
|
136822
|
+
app.get("/", (c) => {
|
|
136823
|
+
const url2 = new URL(c.req.url);
|
|
136824
|
+
deps.handleListProjects(url2, c.env.outgoing);
|
|
136825
|
+
return alreadyHandled4();
|
|
136826
|
+
});
|
|
136799
136827
|
app.get("/popular", (c) => {
|
|
136800
136828
|
const url2 = new URL(c.req.url);
|
|
136801
136829
|
deps.handleGetPopularProjects(url2, c.env.outgoing);
|
|
@@ -136814,11 +136842,6 @@ var createScannerRoutes = (deps) => {
|
|
|
136814
136842
|
await deps.handleSearch(url2, c.env.outgoing);
|
|
136815
136843
|
return alreadyHandled5();
|
|
136816
136844
|
});
|
|
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
136845
|
return app;
|
|
136823
136846
|
};
|
|
136824
136847
|
|
|
@@ -138082,517 +138105,39 @@ async function recordUpload(pool2, instanceId, row) {
|
|
|
138082
138105
|
);
|
|
138083
138106
|
}
|
|
138084
138107
|
|
|
138085
|
-
// src/
|
|
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
|
|
138108
|
+
// src/handlers/handleListProjects.ts
|
|
138409
138109
|
var import_fs18 = require("fs");
|
|
138410
138110
|
var import_os7 = require("os");
|
|
138411
138111
|
var import_path14 = require("path");
|
|
138412
|
-
|
|
138413
|
-
|
|
138414
|
-
|
|
138415
|
-
|
|
138416
|
-
|
|
138112
|
+
function decodeProjectPath(dirName) {
|
|
138113
|
+
return dirName.replace(/-/g, "/");
|
|
138114
|
+
}
|
|
138115
|
+
function handleListProjects(url2, res) {
|
|
138116
|
+
const limit = Math.max(1, parseInt(url2.searchParams.get("limit") ?? "50", 10) || 50);
|
|
138117
|
+
const offset = Math.max(0, parseInt(url2.searchParams.get("offset") ?? "0", 10) || 0);
|
|
138118
|
+
const projectsDir = (0, import_path14.join)((0, import_os7.homedir)(), ".claude", "projects");
|
|
138119
|
+
let entries;
|
|
138417
138120
|
try {
|
|
138418
|
-
|
|
138121
|
+
entries = (0, import_fs18.readdirSync)(projectsDir).map((dirName) => {
|
|
138122
|
+
const fullPath = (0, import_path14.join)(projectsDir, dirName);
|
|
138123
|
+
let mtime = 0;
|
|
138124
|
+
try {
|
|
138125
|
+
mtime = (0, import_fs18.statSync)(fullPath).mtimeMs;
|
|
138126
|
+
} catch {
|
|
138127
|
+
}
|
|
138128
|
+
const path2 = decodeProjectPath(dirName);
|
|
138129
|
+
const name = path2.split("/").filter(Boolean).pop() ?? dirName;
|
|
138130
|
+
return { name, path: path2, dirName, mtime };
|
|
138131
|
+
}).sort((a, b2) => b2.mtime - a.mtime);
|
|
138419
138132
|
} catch {
|
|
138420
|
-
|
|
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
|
-
);
|
|
138133
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
138134
|
+
res.end(JSON.stringify({ projects: [], total: 0 }));
|
|
138590
138135
|
return;
|
|
138591
138136
|
}
|
|
138592
|
-
const
|
|
138593
|
-
const
|
|
138137
|
+
const total = entries.length;
|
|
138138
|
+
const page = entries.slice(offset, offset + limit).map(({ name, path: path2, dirName }) => ({ name, path: path2, dirName }));
|
|
138594
138139
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
138595
|
-
res.end(JSON.stringify({
|
|
138140
|
+
res.end(JSON.stringify({ projects: page, total }));
|
|
138596
138141
|
}
|
|
138597
138142
|
|
|
138598
138143
|
// src/server.ts
|
|
@@ -141512,6 +141057,17 @@ function pruneAgentConversations(cache) {
|
|
|
141512
141057
|
return { scanned: rows.length, pruned, missing };
|
|
141513
141058
|
}
|
|
141514
141059
|
|
|
141060
|
+
// src/services/projectChats/deriveProjectChatTitle.ts
|
|
141061
|
+
function deriveProjectChatTitle(input) {
|
|
141062
|
+
const trimmed = input.title?.trim();
|
|
141063
|
+
if (trimmed) return trimmed;
|
|
141064
|
+
const name = input.projectName?.trim();
|
|
141065
|
+
if (name) return name;
|
|
141066
|
+
const pathSuffix = input.projectPath ? input.projectPath.split(/[/\\]/).filter(Boolean).slice(-2).join("/") : "";
|
|
141067
|
+
if (pathSuffix) return pathSuffix;
|
|
141068
|
+
return `Untitled \xB7 ${input.id.slice(0, 8)}`;
|
|
141069
|
+
}
|
|
141070
|
+
|
|
141515
141071
|
// src/services/questions/detectAskUserQuestion.ts
|
|
141516
141072
|
function normalizeContent2(raw2) {
|
|
141517
141073
|
if (Array.isArray(raw2)) return raw2;
|
|
@@ -141941,6 +141497,226 @@ function debounce(fn, waitMs) {
|
|
|
141941
141497
|
return debounced;
|
|
141942
141498
|
}
|
|
141943
141499
|
|
|
141500
|
+
// node_modules/date-fns/constants.js
|
|
141501
|
+
var daysInYear = 365.2425;
|
|
141502
|
+
var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1e3;
|
|
141503
|
+
var minTime = -maxTime;
|
|
141504
|
+
var millisecondsInMinute = 6e4;
|
|
141505
|
+
var millisecondsInHour = 36e5;
|
|
141506
|
+
var secondsInHour = 3600;
|
|
141507
|
+
var secondsInDay = secondsInHour * 24;
|
|
141508
|
+
var secondsInWeek = secondsInDay * 7;
|
|
141509
|
+
var secondsInYear = secondsInDay * daysInYear;
|
|
141510
|
+
var secondsInMonth = secondsInYear / 12;
|
|
141511
|
+
var secondsInQuarter = secondsInMonth * 3;
|
|
141512
|
+
var constructFromSymbol = /* @__PURE__ */ Symbol.for("constructDateFrom");
|
|
141513
|
+
|
|
141514
|
+
// node_modules/date-fns/constructFrom.js
|
|
141515
|
+
function constructFrom(date5, value) {
|
|
141516
|
+
if (typeof date5 === "function") return date5(value);
|
|
141517
|
+
if (date5 && typeof date5 === "object" && constructFromSymbol in date5)
|
|
141518
|
+
return date5[constructFromSymbol](value);
|
|
141519
|
+
if (date5 instanceof Date) return new date5.constructor(value);
|
|
141520
|
+
return new Date(value);
|
|
141521
|
+
}
|
|
141522
|
+
|
|
141523
|
+
// node_modules/date-fns/toDate.js
|
|
141524
|
+
function toDate(argument, context) {
|
|
141525
|
+
return constructFrom(context || argument, argument);
|
|
141526
|
+
}
|
|
141527
|
+
|
|
141528
|
+
// node_modules/date-fns/isDate.js
|
|
141529
|
+
function isDate(value) {
|
|
141530
|
+
return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
|
|
141531
|
+
}
|
|
141532
|
+
|
|
141533
|
+
// node_modules/date-fns/isValid.js
|
|
141534
|
+
function isValid(date5) {
|
|
141535
|
+
return !(!isDate(date5) && typeof date5 !== "number" || isNaN(+toDate(date5)));
|
|
141536
|
+
}
|
|
141537
|
+
|
|
141538
|
+
// node_modules/date-fns/parseISO.js
|
|
141539
|
+
function parseISO(argument, options) {
|
|
141540
|
+
const invalidDate = () => constructFrom(options?.in, NaN);
|
|
141541
|
+
const additionalDigits = options?.additionalDigits ?? 2;
|
|
141542
|
+
const dateStrings = splitDateString(argument);
|
|
141543
|
+
let date5;
|
|
141544
|
+
if (dateStrings.date) {
|
|
141545
|
+
const parseYearResult = parseYear(dateStrings.date, additionalDigits);
|
|
141546
|
+
date5 = parseDate(parseYearResult.restDateString, parseYearResult.year);
|
|
141547
|
+
}
|
|
141548
|
+
if (!date5 || isNaN(+date5)) return invalidDate();
|
|
141549
|
+
const timestamp = +date5;
|
|
141550
|
+
let time3 = 0;
|
|
141551
|
+
let offset;
|
|
141552
|
+
if (dateStrings.time) {
|
|
141553
|
+
time3 = parseTime(dateStrings.time);
|
|
141554
|
+
if (isNaN(time3)) return invalidDate();
|
|
141555
|
+
}
|
|
141556
|
+
if (dateStrings.timezone) {
|
|
141557
|
+
offset = parseTimezone(dateStrings.timezone);
|
|
141558
|
+
if (isNaN(offset)) return invalidDate();
|
|
141559
|
+
} else {
|
|
141560
|
+
const tmpDate = new Date(timestamp + time3);
|
|
141561
|
+
const result = toDate(0, options?.in);
|
|
141562
|
+
result.setFullYear(
|
|
141563
|
+
tmpDate.getUTCFullYear(),
|
|
141564
|
+
tmpDate.getUTCMonth(),
|
|
141565
|
+
tmpDate.getUTCDate()
|
|
141566
|
+
);
|
|
141567
|
+
result.setHours(
|
|
141568
|
+
tmpDate.getUTCHours(),
|
|
141569
|
+
tmpDate.getUTCMinutes(),
|
|
141570
|
+
tmpDate.getUTCSeconds(),
|
|
141571
|
+
tmpDate.getUTCMilliseconds()
|
|
141572
|
+
);
|
|
141573
|
+
return result;
|
|
141574
|
+
}
|
|
141575
|
+
return toDate(timestamp + time3 + offset, options?.in);
|
|
141576
|
+
}
|
|
141577
|
+
var patterns = {
|
|
141578
|
+
dateTimeDelimiter: /[T ]/,
|
|
141579
|
+
timeZoneDelimiter: /[Z ]/i,
|
|
141580
|
+
timezone: /([Z+-].*)$/
|
|
141581
|
+
};
|
|
141582
|
+
var dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
|
|
141583
|
+
var timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
|
|
141584
|
+
var timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
|
|
141585
|
+
function splitDateString(dateString) {
|
|
141586
|
+
const dateStrings = {};
|
|
141587
|
+
const array2 = dateString.split(patterns.dateTimeDelimiter);
|
|
141588
|
+
let timeString;
|
|
141589
|
+
if (array2.length > 2) {
|
|
141590
|
+
return dateStrings;
|
|
141591
|
+
}
|
|
141592
|
+
if (/:/.test(array2[0])) {
|
|
141593
|
+
timeString = array2[0];
|
|
141594
|
+
} else {
|
|
141595
|
+
dateStrings.date = array2[0];
|
|
141596
|
+
timeString = array2[1];
|
|
141597
|
+
if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
|
|
141598
|
+
dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
|
|
141599
|
+
timeString = dateString.substr(
|
|
141600
|
+
dateStrings.date.length,
|
|
141601
|
+
dateString.length
|
|
141602
|
+
);
|
|
141603
|
+
}
|
|
141604
|
+
}
|
|
141605
|
+
if (timeString) {
|
|
141606
|
+
const token = patterns.timezone.exec(timeString);
|
|
141607
|
+
if (token) {
|
|
141608
|
+
dateStrings.time = timeString.replace(token[1], "");
|
|
141609
|
+
dateStrings.timezone = token[1];
|
|
141610
|
+
} else {
|
|
141611
|
+
dateStrings.time = timeString;
|
|
141612
|
+
}
|
|
141613
|
+
}
|
|
141614
|
+
return dateStrings;
|
|
141615
|
+
}
|
|
141616
|
+
function parseYear(dateString, additionalDigits) {
|
|
141617
|
+
const regex = new RegExp(
|
|
141618
|
+
"^(?:(\\d{4}|[+-]\\d{" + (4 + additionalDigits) + "})|(\\d{2}|[+-]\\d{" + (2 + additionalDigits) + "})$)"
|
|
141619
|
+
);
|
|
141620
|
+
const captures = dateString.match(regex);
|
|
141621
|
+
if (!captures) return { year: NaN, restDateString: "" };
|
|
141622
|
+
const year = captures[1] ? parseInt(captures[1]) : null;
|
|
141623
|
+
const century = captures[2] ? parseInt(captures[2]) : null;
|
|
141624
|
+
return {
|
|
141625
|
+
year: century === null ? year : century * 100,
|
|
141626
|
+
restDateString: dateString.slice((captures[1] || captures[2]).length)
|
|
141627
|
+
};
|
|
141628
|
+
}
|
|
141629
|
+
function parseDate(dateString, year) {
|
|
141630
|
+
if (year === null) return /* @__PURE__ */ new Date(NaN);
|
|
141631
|
+
const captures = dateString.match(dateRegex);
|
|
141632
|
+
if (!captures) return /* @__PURE__ */ new Date(NaN);
|
|
141633
|
+
const isWeekDate = !!captures[4];
|
|
141634
|
+
const dayOfYear = parseDateUnit(captures[1]);
|
|
141635
|
+
const month = parseDateUnit(captures[2]) - 1;
|
|
141636
|
+
const day = parseDateUnit(captures[3]);
|
|
141637
|
+
const week = parseDateUnit(captures[4]);
|
|
141638
|
+
const dayOfWeek = parseDateUnit(captures[5]) - 1;
|
|
141639
|
+
if (isWeekDate) {
|
|
141640
|
+
if (!validateWeekDate(year, week, dayOfWeek)) {
|
|
141641
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
141642
|
+
}
|
|
141643
|
+
return dayOfISOWeekYear(year, week, dayOfWeek);
|
|
141644
|
+
} else {
|
|
141645
|
+
const date5 = /* @__PURE__ */ new Date(0);
|
|
141646
|
+
if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
|
|
141647
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
141648
|
+
}
|
|
141649
|
+
date5.setUTCFullYear(year, month, Math.max(dayOfYear, day));
|
|
141650
|
+
return date5;
|
|
141651
|
+
}
|
|
141652
|
+
}
|
|
141653
|
+
function parseDateUnit(value) {
|
|
141654
|
+
return value ? parseInt(value) : 1;
|
|
141655
|
+
}
|
|
141656
|
+
function parseTime(timeString) {
|
|
141657
|
+
const captures = timeString.match(timeRegex);
|
|
141658
|
+
if (!captures) return NaN;
|
|
141659
|
+
const hours = parseTimeUnit(captures[1]);
|
|
141660
|
+
const minutes = parseTimeUnit(captures[2]);
|
|
141661
|
+
const seconds = parseTimeUnit(captures[3]);
|
|
141662
|
+
if (!validateTime(hours, minutes, seconds)) {
|
|
141663
|
+
return NaN;
|
|
141664
|
+
}
|
|
141665
|
+
return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1e3;
|
|
141666
|
+
}
|
|
141667
|
+
function parseTimeUnit(value) {
|
|
141668
|
+
return value && parseFloat(value.replace(",", ".")) || 0;
|
|
141669
|
+
}
|
|
141670
|
+
function parseTimezone(timezoneString) {
|
|
141671
|
+
if (timezoneString === "Z") return 0;
|
|
141672
|
+
const captures = timezoneString.match(timezoneRegex);
|
|
141673
|
+
if (!captures) return 0;
|
|
141674
|
+
const sign = captures[1] === "+" ? -1 : 1;
|
|
141675
|
+
const hours = parseInt(captures[2]);
|
|
141676
|
+
const minutes = captures[3] && parseInt(captures[3]) || 0;
|
|
141677
|
+
if (!validateTimezone(hours, minutes)) {
|
|
141678
|
+
return NaN;
|
|
141679
|
+
}
|
|
141680
|
+
return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
|
|
141681
|
+
}
|
|
141682
|
+
function dayOfISOWeekYear(isoWeekYear, week, day) {
|
|
141683
|
+
const date5 = /* @__PURE__ */ new Date(0);
|
|
141684
|
+
date5.setUTCFullYear(isoWeekYear, 0, 4);
|
|
141685
|
+
const fourthOfJanuaryDay = date5.getUTCDay() || 7;
|
|
141686
|
+
const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
|
|
141687
|
+
date5.setUTCDate(date5.getUTCDate() + diff);
|
|
141688
|
+
return date5;
|
|
141689
|
+
}
|
|
141690
|
+
var daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
141691
|
+
function isLeapYearIndex(year) {
|
|
141692
|
+
return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
|
|
141693
|
+
}
|
|
141694
|
+
function validateDate(year, month, date5) {
|
|
141695
|
+
return month >= 0 && month <= 11 && date5 >= 1 && date5 <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
|
|
141696
|
+
}
|
|
141697
|
+
function validateDayOfYearDate(year, dayOfYear) {
|
|
141698
|
+
return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
|
|
141699
|
+
}
|
|
141700
|
+
function validateWeekDate(_year, week, day) {
|
|
141701
|
+
return week >= 1 && week <= 53 && day >= 0 && day <= 6;
|
|
141702
|
+
}
|
|
141703
|
+
function validateTime(hours, minutes, seconds) {
|
|
141704
|
+
if (hours === 24) {
|
|
141705
|
+
return minutes === 0 && seconds === 0;
|
|
141706
|
+
}
|
|
141707
|
+
return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
|
|
141708
|
+
}
|
|
141709
|
+
function validateTimezone(_hours, minutes) {
|
|
141710
|
+
return minutes >= 0 && minutes <= 59;
|
|
141711
|
+
}
|
|
141712
|
+
|
|
141713
|
+
// src/utils/dates.ts
|
|
141714
|
+
function parseIsoDateOrNull(value) {
|
|
141715
|
+
if (!value) return null;
|
|
141716
|
+
const parsed = parseISO(value);
|
|
141717
|
+
return isValid(parsed) ? parsed : null;
|
|
141718
|
+
}
|
|
141719
|
+
|
|
141944
141720
|
// src/utils/isScannedSnapshotStale.ts
|
|
141945
141721
|
var STALENESS_TOLERANCE_MS = 1e3;
|
|
141946
141722
|
function isScannedSnapshotStale(snapshotTimestamp, fileMtimeMs) {
|
|
@@ -142116,6 +141892,7 @@ var StreamerServer = class {
|
|
|
142116
141892
|
binding = false;
|
|
142117
141893
|
cacheReady = false;
|
|
142118
141894
|
apiKey;
|
|
141895
|
+
apiKeySource;
|
|
142119
141896
|
localNoAuth;
|
|
142120
141897
|
logMenubarRequests;
|
|
142121
141898
|
verbose;
|
|
@@ -142127,6 +141904,8 @@ var StreamerServer = class {
|
|
|
142127
141904
|
publicUrl = null;
|
|
142128
141905
|
pairTokens = new PairTokenStore();
|
|
142129
141906
|
exchangeAttempts = /* @__PURE__ */ new Map();
|
|
141907
|
+
sessionStartAttempts = /* @__PURE__ */ new Map();
|
|
141908
|
+
sessionInputAttempts = /* @__PURE__ */ new Map();
|
|
142130
141909
|
ptyGracePeriodMs;
|
|
142131
141910
|
defaultSystemPrompt;
|
|
142132
141911
|
// Map of sessionId → grace timer; fires to kill PTY after WS disconnect
|
|
@@ -142162,8 +141941,14 @@ var StreamerServer = class {
|
|
|
142162
141941
|
constructor(config2) {
|
|
142163
141942
|
this.sessionStatusBus.setMaxListeners(0);
|
|
142164
141943
|
this.apiKey = config2.apiKey;
|
|
141944
|
+
this.apiKeySource = config2.apiKeySource ?? "config";
|
|
142165
141945
|
this.localNoAuth = config2.localNoAuth ?? false;
|
|
142166
141946
|
this.logMenubarRequests = config2.logMenubarRequests ?? false;
|
|
141947
|
+
if (this.localNoAuth) {
|
|
141948
|
+
console.warn(
|
|
141949
|
+
"[WARN] localNoAuth is ENABLED \u2014 all requests from localhost bypass authentication. Do not run with --local-no-auth in shared or production environments."
|
|
141950
|
+
);
|
|
141951
|
+
}
|
|
142167
141952
|
this.verbose = config2.verbose ?? false;
|
|
142168
141953
|
this.disableDb = config2.disableDb ?? false;
|
|
142169
141954
|
this.scanProfiles = config2.scanProfiles;
|
|
@@ -142341,10 +142126,15 @@ var StreamerServer = class {
|
|
|
142341
142126
|
});
|
|
142342
142127
|
}
|
|
142343
142128
|
const agentClient = this.agentClient;
|
|
142129
|
+
const self2 = this;
|
|
142344
142130
|
const apiDeps = {
|
|
142345
|
-
|
|
142131
|
+
// ponytail: getter so rotateApiKey() takes effect without restarting the server
|
|
142132
|
+
get apiKey() {
|
|
142133
|
+
return self2.apiKey;
|
|
142134
|
+
},
|
|
142346
142135
|
localNoAuth: this.localNoAuth,
|
|
142347
142136
|
logMenubarRequests: this.logMenubarRequests,
|
|
142137
|
+
rotateApiKey: () => this.rotateApiKey(),
|
|
142348
142138
|
publicUrl: this.publicUrl,
|
|
142349
142139
|
browseRoot: this.browseRoot,
|
|
142350
142140
|
ptyManager: this.ptyManager,
|
|
@@ -142375,8 +142165,8 @@ var StreamerServer = class {
|
|
|
142375
142165
|
handleConversationsCount: (url2, res) => this.handleConversationsCount(url2, res),
|
|
142376
142166
|
handleGetConversation: (id, url2, res, ifNoneMatch) => this.handleGetConversation(id, url2, res, ifNoneMatch),
|
|
142377
142167
|
handleSearch: (url2, res) => this.handleSearch(url2, res),
|
|
142168
|
+
handleListProjects: (url2, res) => handleListProjects(url2, res),
|
|
142378
142169
|
handleGetPopularProjects: (url2, res) => this.handleGetPopularProjects(url2, res),
|
|
142379
|
-
handleListProjectChats: (url2, res) => this.handleListProjectChats(url2, res),
|
|
142380
142170
|
handlePairStart: (res) => this.handlePairStart(res),
|
|
142381
142171
|
handlePairExchange: (req, res) => this.handlePairExchange(req, res),
|
|
142382
142172
|
handleBrowse: (url2, res) => this.handleBrowse(url2, res),
|
|
@@ -142811,19 +142601,38 @@ var StreamerServer = class {
|
|
|
142811
142601
|
machineName: hostname4()
|
|
142812
142602
|
});
|
|
142813
142603
|
}
|
|
142814
|
-
|
|
142604
|
+
rotateApiKey() {
|
|
142605
|
+
const newKey = generateApiKey();
|
|
142606
|
+
const persisted = this.apiKeySource === "config";
|
|
142607
|
+
if (persisted) setApiKey(newKey);
|
|
142608
|
+
this.apiKey = newKey;
|
|
142609
|
+
return { newKey, persisted };
|
|
142610
|
+
}
|
|
142611
|
+
checkRateLimit(map2, key, limit, windowMs) {
|
|
142815
142612
|
const now = Date.now();
|
|
142816
|
-
const
|
|
142817
|
-
const limit = 5;
|
|
142818
|
-
const arr = (this.exchangeAttempts.get(ip) ?? []).filter((t2) => now - t2 < windowMs);
|
|
142613
|
+
const arr = (map2.get(key) ?? []).filter((t2) => now - t2 < windowMs);
|
|
142819
142614
|
if (arr.length >= limit) {
|
|
142820
|
-
|
|
142615
|
+
map2.set(key, arr);
|
|
142821
142616
|
return false;
|
|
142822
142617
|
}
|
|
142823
142618
|
arr.push(now);
|
|
142824
|
-
|
|
142619
|
+
map2.set(key, arr);
|
|
142620
|
+
setTimeout(() => {
|
|
142621
|
+
const remaining = (map2.get(key) ?? []).filter((t2) => Date.now() - t2 < windowMs);
|
|
142622
|
+
if (remaining.length === 0) map2.delete(key);
|
|
142623
|
+
else map2.set(key, remaining);
|
|
142624
|
+
}, windowMs);
|
|
142825
142625
|
return true;
|
|
142826
142626
|
}
|
|
142627
|
+
checkExchangeRateLimit(ip) {
|
|
142628
|
+
return this.checkRateLimit(this.exchangeAttempts, ip, 5, 6e4);
|
|
142629
|
+
}
|
|
142630
|
+
checkSessionStartRateLimit(ip) {
|
|
142631
|
+
return this.checkRateLimit(this.sessionStartAttempts, ip, 10, 6e4);
|
|
142632
|
+
}
|
|
142633
|
+
checkSessionInputRateLimit(sessionId) {
|
|
142634
|
+
return this.checkRateLimit(this.sessionInputAttempts, sessionId, 500, 6e4);
|
|
142635
|
+
}
|
|
142827
142636
|
async handleListConversations(url2, res) {
|
|
142828
142637
|
const limit = intParam(url2, "limit", 50);
|
|
142829
142638
|
const offset = intParam(url2, "offset", 0);
|
|
@@ -142985,21 +142794,6 @@ var StreamerServer = class {
|
|
|
142985
142794
|
const projects = this.cache.getPopularProjects(limit);
|
|
142986
142795
|
json2(res, 200, { projects, total: projects.length });
|
|
142987
142796
|
}
|
|
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
142797
|
buildStatCache(previousScanner) {
|
|
143004
142798
|
if (!this.cache) return void 0;
|
|
143005
142799
|
const dbStats = this.cache.getFileStats();
|
|
@@ -143476,6 +143270,10 @@ var StreamerServer = class {
|
|
|
143476
143270
|
}
|
|
143477
143271
|
}
|
|
143478
143272
|
async handleSendInput(sessionId, req, res) {
|
|
143273
|
+
if (!this.checkSessionInputRateLimit(sessionId)) {
|
|
143274
|
+
json2(res, 429, { error: "Too many input requests for this session. Please slow down." });
|
|
143275
|
+
return;
|
|
143276
|
+
}
|
|
143479
143277
|
if (this.agentConfig.enabled) {
|
|
143480
143278
|
const body2 = await readBody(req);
|
|
143481
143279
|
const cache = this.cache;
|
|
@@ -143757,6 +143555,13 @@ var StreamerServer = class {
|
|
|
143757
143555
|
json2(res, 201, { sessionId: session.id });
|
|
143758
143556
|
}
|
|
143759
143557
|
async handleStartSession(req, res) {
|
|
143558
|
+
const ip = req.socket?.remoteAddress ?? "unknown";
|
|
143559
|
+
if (!this.checkSessionStartRateLimit(ip)) {
|
|
143560
|
+
json2(res, 429, {
|
|
143561
|
+
error: "Too many session start requests. Please wait before trying again."
|
|
143562
|
+
});
|
|
143563
|
+
return;
|
|
143564
|
+
}
|
|
143760
143565
|
if (this.agentConfig.enabled) {
|
|
143761
143566
|
const body2 = await readBody(req);
|
|
143762
143567
|
const result = await handleStartAgentSession(body2, {
|
|
@@ -144280,7 +144085,7 @@ async function checkForUpdate(opts) {
|
|
|
144280
144085
|
}
|
|
144281
144086
|
|
|
144282
144087
|
// src/updater/install.ts
|
|
144283
|
-
var
|
|
144088
|
+
var import_node_fs18 = require("fs");
|
|
144284
144089
|
|
|
144285
144090
|
// src/updater/active-sessions.ts
|
|
144286
144091
|
async function countActiveSessions(opts) {
|
|
@@ -147564,14 +147369,29 @@ async function unpackTarball(opts) {
|
|
|
147564
147369
|
await So({ file: tarballPath, cwd: destDir });
|
|
147565
147370
|
}
|
|
147566
147371
|
|
|
147372
|
+
// src/updater/update-log.ts
|
|
147373
|
+
var import_node_fs17 = require("fs");
|
|
147374
|
+
var import_node_path21 = require("path");
|
|
147375
|
+
var LOG_PATH = (0, import_node_path21.join)(THREADBASE_ROOT, "update.log");
|
|
147376
|
+
function appendUpdateLog(line) {
|
|
147377
|
+
try {
|
|
147378
|
+
(0, import_node_fs17.mkdirSync)(THREADBASE_ROOT, { recursive: true });
|
|
147379
|
+
(0, import_node_fs17.appendFileSync)(LOG_PATH, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
147380
|
+
`, "utf8");
|
|
147381
|
+
} catch {
|
|
147382
|
+
}
|
|
147383
|
+
}
|
|
147384
|
+
|
|
147567
147385
|
// src/updater/install.ts
|
|
147568
147386
|
async function runInstall(opts) {
|
|
147569
147387
|
if (isBrewInstall()) {
|
|
147570
|
-
|
|
147388
|
+
const result = {
|
|
147571
147389
|
kind: "unsupported-install",
|
|
147572
147390
|
reason: "Installed via Homebrew \u2014 run `brew upgrade tb-streamer` to update.",
|
|
147573
147391
|
current: opts.currentVersion
|
|
147574
147392
|
};
|
|
147393
|
+
appendUpdateLog(`[no-op] ${result.reason}`);
|
|
147394
|
+
return result;
|
|
147575
147395
|
}
|
|
147576
147396
|
const check2 = await checkForUpdate({
|
|
147577
147397
|
currentVersion: opts.currentVersion,
|
|
@@ -147579,6 +147399,9 @@ async function runInstall(opts) {
|
|
|
147579
147399
|
pinnedVersion: opts.pinnedVersion,
|
|
147580
147400
|
allowMajor: opts.allowMajor
|
|
147581
147401
|
});
|
|
147402
|
+
appendUpdateLog(
|
|
147403
|
+
`[check] current=${check2.current} latest=${check2.latest ?? "none"} status=${check2.reason}`
|
|
147404
|
+
);
|
|
147582
147405
|
if (!check2.wouldInstall) {
|
|
147583
147406
|
return { kind: "no-op", reason: check2.reason, current: check2.current, latest: check2.latest };
|
|
147584
147407
|
}
|
|
@@ -147604,33 +147427,27 @@ async function runInstall(opts) {
|
|
|
147604
147427
|
const artifact = pickArtifact(manifest);
|
|
147605
147428
|
if (opts.dryRun) {
|
|
147606
147429
|
const asset = target.assets.find((a) => a.name === artifact.filename);
|
|
147607
|
-
|
|
147608
|
-
|
|
147609
|
-
|
|
147610
|
-
|
|
147611
|
-
};
|
|
147430
|
+
const tarballUrl = asset?.browserDownloadUrl ?? "(missing)";
|
|
147431
|
+
appendUpdateLog(
|
|
147432
|
+
`[dry-run] would install ${check2.current} \u2192 ${targetVersion} from ${tarballUrl}`
|
|
147433
|
+
);
|
|
147434
|
+
return { kind: "dry-run", latest: targetVersion, tarballUrl };
|
|
147612
147435
|
}
|
|
147613
147436
|
if (opts.config.defer_if_active_sessions && !opts.force && opts.runningServer) {
|
|
147614
147437
|
const active = await countActiveSessions(opts.runningServer);
|
|
147615
147438
|
if (active.kind === "count" && active.count > 0) {
|
|
147616
|
-
|
|
147617
|
-
|
|
147618
|
-
|
|
147619
|
-
activeSessions: active.count,
|
|
147620
|
-
latest: targetVersion
|
|
147621
|
-
};
|
|
147439
|
+
const reason = `${active.count} active session(s); use --force to interrupt`;
|
|
147440
|
+
appendUpdateLog(`[deferred] ${check2.current} \u2192 ${targetVersion}: ${reason}`);
|
|
147441
|
+
return { kind: "deferred", reason, activeSessions: active.count, latest: targetVersion };
|
|
147622
147442
|
}
|
|
147623
147443
|
if (active.kind === "error") {
|
|
147624
|
-
|
|
147625
|
-
|
|
147626
|
-
|
|
147627
|
-
activeSessions: -1,
|
|
147628
|
-
latest: targetVersion
|
|
147629
|
-
};
|
|
147444
|
+
const reason = `cannot determine active sessions (${active.reason}); use --force to override`;
|
|
147445
|
+
appendUpdateLog(`[deferred] ${check2.current} \u2192 ${targetVersion}: ${reason}`);
|
|
147446
|
+
return { kind: "deferred", reason, activeSessions: -1, latest: targetVersion };
|
|
147630
147447
|
}
|
|
147631
147448
|
}
|
|
147632
147449
|
ensureReleasesDir();
|
|
147633
|
-
(0,
|
|
147450
|
+
(0, import_node_fs18.mkdirSync)(DOWNLOAD_DIR, { recursive: true });
|
|
147634
147451
|
const tarballPath = downloadPath(targetVersion, artifact.filename);
|
|
147635
147452
|
await downloadAndVerify({ manifest, assets: target.assets, targetPath: tarballPath });
|
|
147636
147453
|
const destDir = releaseDir(targetVersion);
|
|
@@ -147649,18 +147466,22 @@ async function runInstall(opts) {
|
|
|
147649
147466
|
} catch (err) {
|
|
147650
147467
|
restartMethod = `failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
147651
147468
|
}
|
|
147652
|
-
|
|
147469
|
+
const installed = {
|
|
147653
147470
|
kind: "installed",
|
|
147654
147471
|
previous: check2.current,
|
|
147655
147472
|
installed: targetVersion,
|
|
147656
147473
|
pruned,
|
|
147657
147474
|
restart: { method: restartMethod }
|
|
147658
147475
|
};
|
|
147476
|
+
appendUpdateLog(
|
|
147477
|
+
`[installed] ${installed.previous} \u2192 ${installed.installed} restart=${installed.restart.method}${pruned.length > 0 ? ` pruned=${pruned.length}` : ""}`
|
|
147478
|
+
);
|
|
147479
|
+
return installed;
|
|
147659
147480
|
}
|
|
147660
147481
|
|
|
147661
147482
|
// cli/prod.ts
|
|
147662
147483
|
var import_node_child_process6 = require("child_process");
|
|
147663
|
-
var
|
|
147484
|
+
var import_node_fs20 = require("fs");
|
|
147664
147485
|
init_constants();
|
|
147665
147486
|
init_launchd();
|
|
147666
147487
|
init_marker();
|
|
@@ -147746,7 +147567,7 @@ async function runProdDoctor(opts) {
|
|
|
147746
147567
|
return { findings, repairs };
|
|
147747
147568
|
}
|
|
147748
147569
|
var defaultSpawnTail = ({ files, lines, follow }) => {
|
|
147749
|
-
const existing = files.filter((f2) => (0,
|
|
147570
|
+
const existing = files.filter((f2) => (0, import_node_fs20.existsSync)(f2));
|
|
147750
147571
|
if (existing.length === 0) {
|
|
147751
147572
|
return Promise.resolve({
|
|
147752
147573
|
ok: false,
|
|
@@ -147902,6 +147723,7 @@ program2.command("serve").description("Start the streamer server").option("-p, -
|
|
|
147902
147723
|
const server = new StreamerServer({
|
|
147903
147724
|
port: resolvedPort,
|
|
147904
147725
|
apiKey,
|
|
147726
|
+
apiKeySource: opts.apiKey ? "cli" : "config",
|
|
147905
147727
|
localNoAuth: opts.localNoAuth,
|
|
147906
147728
|
verbose: opts.verbose,
|
|
147907
147729
|
logMenubarRequests: opts.logMenubarRequests,
|
|
@@ -147965,8 +147787,8 @@ program2.command("cache").description("Manage the local SQLite conversation cach
|
|
|
147965
147787
|
`${process.env.HOME}/.threadbase/cache`
|
|
147966
147788
|
).action((opts) => {
|
|
147967
147789
|
const { rmSync: rmSync6, existsSync: existsSync11 } = require("fs");
|
|
147968
|
-
const { join:
|
|
147969
|
-
const dbPath =
|
|
147790
|
+
const { join: join25 } = require("path");
|
|
147791
|
+
const dbPath = join25(opts.cacheDir, "cache.db");
|
|
147970
147792
|
for (const suffix of ["", "-shm", "-wal"]) {
|
|
147971
147793
|
const f2 = dbPath + suffix;
|
|
147972
147794
|
if (existsSync11(f2)) {
|
|
@@ -148015,6 +147837,9 @@ program2.command("update").description("Check for streamer updates from GitHub R
|
|
|
148015
147837
|
pinnedVersion: opts.version,
|
|
148016
147838
|
allowMajor: opts.allowMajor
|
|
148017
147839
|
});
|
|
147840
|
+
appendUpdateLog(
|
|
147841
|
+
`[check] current=${result2.current} latest=${result2.latest ?? "none"} status=${result2.reason}`
|
|
147842
|
+
);
|
|
148018
147843
|
log7.info(`Current : ${result2.current}`, void 0, "console");
|
|
148019
147844
|
log7.info(`Latest : ${result2.latest ?? "(none)"}`, void 0, "console");
|
|
148020
147845
|
log7.info(`Channel : ${cfg.channel}`, void 0, "console");
|
|
@@ -148067,6 +147892,7 @@ program2.command("update").description("Check for streamer updates from GitHub R
|
|
|
148067
147892
|
}
|
|
148068
147893
|
} catch (err) {
|
|
148069
147894
|
const message = err instanceof Error ? err.message : String(err);
|
|
147895
|
+
appendUpdateLog(`[error] ${message}`);
|
|
148070
147896
|
log7.error(`Update failed: ${message}`, { error: message }, "console");
|
|
148071
147897
|
process.exitCode = 1;
|
|
148072
147898
|
}
|