@threadbase-sh/streamer 1.54.2 → 1.55.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 +433 -351
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +252 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +160 -79
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3982,13 +3982,13 @@ async function readGitBranch(dir) {
|
|
|
3982
3982
|
// src/server.ts
|
|
3983
3983
|
var import_node_ws = require("@hono/node-ws");
|
|
3984
3984
|
var import_client = require("@temporalio/client");
|
|
3985
|
-
var
|
|
3985
|
+
var import_crypto12 = require("crypto");
|
|
3986
3986
|
var import_events = require("events");
|
|
3987
|
-
var
|
|
3987
|
+
var import_fs28 = require("fs");
|
|
3988
3988
|
var import_promises7 = require("fs/promises");
|
|
3989
3989
|
var import_http = require("http");
|
|
3990
|
-
var
|
|
3991
|
-
var
|
|
3990
|
+
var import_os14 = require("os");
|
|
3991
|
+
var import_path24 = require("path");
|
|
3992
3992
|
|
|
3993
3993
|
// src/api/app.ts
|
|
3994
3994
|
var import_hono18 = require("hono");
|
|
@@ -5160,7 +5160,7 @@ function createLogsRoutes() {
|
|
|
5160
5160
|
var import_node_child_process = require("child_process");
|
|
5161
5161
|
var import_node_crypto3 = require("crypto");
|
|
5162
5162
|
var import_hono11 = require("hono");
|
|
5163
|
-
var
|
|
5163
|
+
var import_os7 = require("os");
|
|
5164
5164
|
|
|
5165
5165
|
// src/config/update-config.ts
|
|
5166
5166
|
var import_node_fs4 = require("fs");
|
|
@@ -5452,6 +5452,66 @@ var PushRepository = class {
|
|
|
5452
5452
|
}
|
|
5453
5453
|
};
|
|
5454
5454
|
|
|
5455
|
+
// src/server-identity.ts
|
|
5456
|
+
var import_crypto5 = require("crypto");
|
|
5457
|
+
var import_fs8 = require("fs");
|
|
5458
|
+
var import_os6 = require("os");
|
|
5459
|
+
var import_path9 = require("path");
|
|
5460
|
+
var IDENTITY_FILE_VERSION = 1;
|
|
5461
|
+
function serverIdentityKeyPath() {
|
|
5462
|
+
const dir = process.env.THREADBASE_CONFIG_DIR ?? (0, import_path9.join)((0, import_os6.homedir)(), ".threadbase");
|
|
5463
|
+
return (0, import_path9.join)(dir, "keys", "server-identity.key");
|
|
5464
|
+
}
|
|
5465
|
+
function loadOrCreateServerIdentity() {
|
|
5466
|
+
const path = serverIdentityKeyPath();
|
|
5467
|
+
let raw;
|
|
5468
|
+
try {
|
|
5469
|
+
raw = (0, import_fs8.readFileSync)(path, "utf-8");
|
|
5470
|
+
} catch (err) {
|
|
5471
|
+
if (err.code !== "ENOENT") throw err;
|
|
5472
|
+
return generateIdentity(path);
|
|
5473
|
+
}
|
|
5474
|
+
let privateKey;
|
|
5475
|
+
try {
|
|
5476
|
+
privateKey = (0, import_crypto5.createPrivateKey)({ key: JSON.parse(raw).key, format: "jwk" });
|
|
5477
|
+
} catch {
|
|
5478
|
+
throw new Error(
|
|
5479
|
+
`Server identity key at ${path} could not be read. Refusing to generate a new one \u2014 that would invalidate every paired device. Repair or delete the file deliberately.`
|
|
5480
|
+
);
|
|
5481
|
+
}
|
|
5482
|
+
return { publicKey: publicKeyOf(privateKey), privateKey };
|
|
5483
|
+
}
|
|
5484
|
+
function serverIdentityPublicKey() {
|
|
5485
|
+
return loadOrCreateServerIdentity().publicKey;
|
|
5486
|
+
}
|
|
5487
|
+
function generateIdentity(path) {
|
|
5488
|
+
const { privateKey } = (0, import_crypto5.generateKeyPairSync)("x25519");
|
|
5489
|
+
const file = {
|
|
5490
|
+
v: IDENTITY_FILE_VERSION,
|
|
5491
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5492
|
+
key: privateKey.export({ format: "jwk" })
|
|
5493
|
+
};
|
|
5494
|
+
(0, import_fs8.mkdirSync)((0, import_path9.dirname)(path), { recursive: true, mode: 448 });
|
|
5495
|
+
const tmp = `${path}.tmp`;
|
|
5496
|
+
(0, import_fs8.writeFileSync)(tmp, `${JSON.stringify(file)}
|
|
5497
|
+
`, { encoding: "utf-8", mode: 384 });
|
|
5498
|
+
(0, import_fs8.chmodSync)(tmp, 384);
|
|
5499
|
+
(0, import_fs8.renameSync)(tmp, path);
|
|
5500
|
+
const publicKey = publicKeyOf(privateKey);
|
|
5501
|
+
getLogger("identity").info(`Generated server identity key ${publicKey}`, {
|
|
5502
|
+
event: "identity.key_generated",
|
|
5503
|
+
path
|
|
5504
|
+
});
|
|
5505
|
+
return { publicKey, privateKey };
|
|
5506
|
+
}
|
|
5507
|
+
function publicKeyOf(privateKey) {
|
|
5508
|
+
const jwk = (0, import_crypto5.createPublicKey)(privateKey).export({ format: "jwk" });
|
|
5509
|
+
if (jwk.crv !== "X25519" || typeof jwk.x !== "string") {
|
|
5510
|
+
throw new Error(`Server identity key at ${serverIdentityKeyPath()} is not an X25519 key`);
|
|
5511
|
+
}
|
|
5512
|
+
return jwk.x;
|
|
5513
|
+
}
|
|
5514
|
+
|
|
5455
5515
|
// src/services/push/apnsClient.ts
|
|
5456
5516
|
var import_node_crypto2 = require("crypto");
|
|
5457
5517
|
var import_node_http2 = require("http2");
|
|
@@ -5660,6 +5720,21 @@ function describePushCapability(liveActivityEnabled, env = process.env) {
|
|
|
5660
5720
|
liveActivityReason: describeMissingApnsCredentials(env) ?? "APNs credentials are set but the push token store is unavailable, so Live Activity push is disabled."
|
|
5661
5721
|
};
|
|
5662
5722
|
}
|
|
5723
|
+
var identityKeyFailureLogged = false;
|
|
5724
|
+
function describeServerIdentityKey() {
|
|
5725
|
+
try {
|
|
5726
|
+
return serverIdentityPublicKey();
|
|
5727
|
+
} catch (err) {
|
|
5728
|
+
if (!identityKeyFailureLogged) {
|
|
5729
|
+
identityKeyFailureLogged = true;
|
|
5730
|
+
getLogger("identity").error(
|
|
5731
|
+
`Server identity key unavailable, so /api/info will omit it: ${err instanceof Error ? err.message : String(err)}`,
|
|
5732
|
+
{ event: "identity.unavailable" }
|
|
5733
|
+
);
|
|
5734
|
+
}
|
|
5735
|
+
return void 0;
|
|
5736
|
+
}
|
|
5737
|
+
}
|
|
5663
5738
|
var clientLog = getLogger("client");
|
|
5664
5739
|
var createMiscRoutes = (deps) => {
|
|
5665
5740
|
const app = new import_hono11.Hono();
|
|
@@ -5667,7 +5742,7 @@ var createMiscRoutes = (deps) => {
|
|
|
5667
5742
|
const ptyIds = deps.ptyAttachedIds();
|
|
5668
5743
|
return c.json({
|
|
5669
5744
|
version: getVersion(),
|
|
5670
|
-
machineName: (0,
|
|
5745
|
+
machineName: (0, import_os7.hostname)(),
|
|
5671
5746
|
platform: process.platform,
|
|
5672
5747
|
activeSessions: deps.sessionStore.list(ptyIds).filter((s) => s.status === "running").length,
|
|
5673
5748
|
publicUrl: deps.publicUrl,
|
|
@@ -5693,7 +5768,13 @@ var createMiscRoutes = (deps) => {
|
|
|
5693
5768
|
// actually send a push, so mobile can hide an affordance instead of
|
|
5694
5769
|
// registering tokens nothing will ever send to. Absent on older servers,
|
|
5695
5770
|
// which a client should read as "unknown", not "unavailable".
|
|
5696
|
-
push: describePushCapability(deps.liveActivityPushEnabled())
|
|
5771
|
+
push: describePushCapability(deps.liveActivityPushEnabled()),
|
|
5772
|
+
// This server's long-term X25519 public key, base64url. The same value the
|
|
5773
|
+
// pair QR carries as `spk`, served here so an already-paired client can
|
|
5774
|
+
// learn it without re-scanning. Additive: absent means a server with no
|
|
5775
|
+
// readable identity key, which a client must read as "cannot verify this
|
|
5776
|
+
// server" — never as a reason to fail the rest of this response.
|
|
5777
|
+
serverIdentityKey: describeServerIdentityKey()
|
|
5697
5778
|
});
|
|
5698
5779
|
});
|
|
5699
5780
|
app.get("/api/profiles", (c) => c.json([]));
|
|
@@ -6204,16 +6285,16 @@ var createHonoApp = (deps, upgradeWebSocket) => {
|
|
|
6204
6285
|
|
|
6205
6286
|
// src/api/handlers/conversations.handlers.ts
|
|
6206
6287
|
var import_scanner3 = require("@threadbase-sh/scanner");
|
|
6207
|
-
var
|
|
6208
|
-
var
|
|
6288
|
+
var import_fs13 = require("fs");
|
|
6289
|
+
var import_path13 = require("path");
|
|
6209
6290
|
var import_readline = require("readline");
|
|
6210
6291
|
|
|
6211
6292
|
// src/conversation-cache.ts
|
|
6212
6293
|
var import_scanner2 = require("@threadbase-sh/scanner");
|
|
6213
6294
|
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
6214
|
-
var
|
|
6295
|
+
var import_fs11 = require("fs");
|
|
6215
6296
|
var import_promises2 = require("fs/promises");
|
|
6216
|
-
var
|
|
6297
|
+
var import_path12 = require("path");
|
|
6217
6298
|
var import_promises3 = require("timers/promises");
|
|
6218
6299
|
|
|
6219
6300
|
// src/db/query-timing.ts
|
|
@@ -6285,18 +6366,18 @@ function labelStatements(statements) {
|
|
|
6285
6366
|
}
|
|
6286
6367
|
|
|
6287
6368
|
// src/db/sqlite-migrate.ts
|
|
6288
|
-
var
|
|
6289
|
-
var
|
|
6369
|
+
var import_fs9 = require("fs");
|
|
6370
|
+
var import_path10 = require("path");
|
|
6290
6371
|
var import_url2 = require("url");
|
|
6291
6372
|
var import_meta2 = {};
|
|
6292
6373
|
function getMigrationsDir2() {
|
|
6293
6374
|
if (typeof import_meta2 !== "undefined" && import_meta2.url) {
|
|
6294
|
-
return (0,
|
|
6375
|
+
return (0, import_path10.dirname)((0, import_url2.fileURLToPath)(import_meta2.url));
|
|
6295
6376
|
}
|
|
6296
6377
|
return __dirname;
|
|
6297
6378
|
}
|
|
6298
6379
|
function resolveMigrationsDir(name = "migrations") {
|
|
6299
|
-
return (0,
|
|
6380
|
+
return (0, import_path10.join)(getMigrationsDir2(), name);
|
|
6300
6381
|
}
|
|
6301
6382
|
var SCHEMA_MIGRATIONS_SQL = `
|
|
6302
6383
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -6307,7 +6388,7 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
|
6307
6388
|
function runSqliteMigrations(db, migrationsDir) {
|
|
6308
6389
|
db.exec(SCHEMA_MIGRATIONS_SQL);
|
|
6309
6390
|
const dir = migrationsDir ?? resolveMigrationsDir();
|
|
6310
|
-
const files = (0,
|
|
6391
|
+
const files = (0, import_fs9.readdirSync)(dir).filter((f) => f.endsWith(".sql")).sort();
|
|
6311
6392
|
const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
|
|
6312
6393
|
const appliedSet = new Set(appliedRows.map((r) => r.id));
|
|
6313
6394
|
const recordApplied = db.prepare("INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)");
|
|
@@ -6318,7 +6399,7 @@ function runSqliteMigrations(db, migrationsDir) {
|
|
|
6318
6399
|
skipped.push(file);
|
|
6319
6400
|
continue;
|
|
6320
6401
|
}
|
|
6321
|
-
const sql = (0,
|
|
6402
|
+
const sql = (0, import_fs9.readFileSync)((0, import_path10.join)(dir, file), "utf-8");
|
|
6322
6403
|
const tx = db.transaction(() => {
|
|
6323
6404
|
db.exec(sql);
|
|
6324
6405
|
recordApplied.run(file, (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -6330,7 +6411,7 @@ function runSqliteMigrations(db, migrationsDir) {
|
|
|
6330
6411
|
}
|
|
6331
6412
|
|
|
6332
6413
|
// src/services/conversations/isAgentConversation.ts
|
|
6333
|
-
var
|
|
6414
|
+
var import_fs10 = require("fs");
|
|
6334
6415
|
var DEFAULT_AGENT_ENTRYPOINTS = /* @__PURE__ */ new Set(["sdk-cli", "claude-vscode"]);
|
|
6335
6416
|
var CHUNK_BYTES = 64 * 1024;
|
|
6336
6417
|
var ENTRYPOINT_PROBE = `"entrypoint":`;
|
|
@@ -6352,12 +6433,12 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
|
|
|
6352
6433
|
if (cached3 !== void 0) return cached3;
|
|
6353
6434
|
let fd;
|
|
6354
6435
|
try {
|
|
6355
|
-
fd = (0,
|
|
6436
|
+
fd = (0, import_fs10.openSync)(filePath, "r");
|
|
6356
6437
|
} catch {
|
|
6357
6438
|
return false;
|
|
6358
6439
|
}
|
|
6359
6440
|
try {
|
|
6360
|
-
const fileSize = (0,
|
|
6441
|
+
const fileSize = (0, import_fs10.statSync)(filePath).size;
|
|
6361
6442
|
if (fileSize === 0) {
|
|
6362
6443
|
fileDecisionCache.set(key, false);
|
|
6363
6444
|
return false;
|
|
@@ -6368,7 +6449,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
|
|
|
6368
6449
|
let carry = "";
|
|
6369
6450
|
while (offset < fileSize) {
|
|
6370
6451
|
const toRead = Math.min(CHUNK_BYTES, fileSize - offset);
|
|
6371
|
-
const got = (0,
|
|
6452
|
+
const got = (0, import_fs10.readSync)(fd, buf, 0, toRead, offset);
|
|
6372
6453
|
if (got <= 0) break;
|
|
6373
6454
|
const chunk = carry + buf.toString("utf8", 0, got);
|
|
6374
6455
|
for (const marker of markers) {
|
|
@@ -6389,7 +6470,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
|
|
|
6389
6470
|
} catch {
|
|
6390
6471
|
return false;
|
|
6391
6472
|
} finally {
|
|
6392
|
-
(0,
|
|
6473
|
+
(0, import_fs10.closeSync)(fd);
|
|
6393
6474
|
}
|
|
6394
6475
|
}
|
|
6395
6476
|
function parseAgentEntrypointsEnv(raw) {
|
|
@@ -6399,12 +6480,12 @@ function parseAgentEntrypointsEnv(raw) {
|
|
|
6399
6480
|
}
|
|
6400
6481
|
|
|
6401
6482
|
// src/utils/canonicalizeFilePath.ts
|
|
6402
|
-
var
|
|
6483
|
+
var import_path11 = require("path");
|
|
6403
6484
|
function canonicalizeFilePath(filePath) {
|
|
6404
6485
|
return filePath.trim().replace(/\\/g, "/");
|
|
6405
6486
|
}
|
|
6406
6487
|
function toNativeFilePath(filePath) {
|
|
6407
|
-
return (0,
|
|
6488
|
+
return (0, import_path11.normalize)(filePath.trim());
|
|
6408
6489
|
}
|
|
6409
6490
|
function canonicalLivePathSet(metas) {
|
|
6410
6491
|
const live = /* @__PURE__ */ new Set();
|
|
@@ -6424,11 +6505,11 @@ function joinStatCacheByNativePath(metas, canonicalStats) {
|
|
|
6424
6505
|
}
|
|
6425
6506
|
|
|
6426
6507
|
// src/utils/fileIdentity.ts
|
|
6427
|
-
var
|
|
6508
|
+
var import_crypto6 = require("crypto");
|
|
6428
6509
|
function fileIdentity(stat3, headBytes) {
|
|
6429
6510
|
if (stat3.ino && stat3.ino > 0) return `inode:${stat3.dev}:${stat3.ino}`;
|
|
6430
6511
|
const head = headBytes ?? Buffer.alloc(0);
|
|
6431
|
-
return `fp:${(0,
|
|
6512
|
+
return `fp:${(0, import_crypto6.createHash)("sha1").update(head).digest("hex")}`;
|
|
6432
6513
|
}
|
|
6433
6514
|
function splitCompleteLines(buf, baseOffset) {
|
|
6434
6515
|
const spans = [];
|
|
@@ -6995,7 +7076,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
6995
7076
|
if (!fileState) return null;
|
|
6996
7077
|
let stat3;
|
|
6997
7078
|
try {
|
|
6998
|
-
stat3 = (0,
|
|
7079
|
+
stat3 = (0, import_fs11.statSync)(filePath);
|
|
6999
7080
|
} catch {
|
|
7000
7081
|
return null;
|
|
7001
7082
|
}
|
|
@@ -7016,17 +7097,17 @@ var ConversationCache = class _ConversationCache {
|
|
|
7016
7097
|
);
|
|
7017
7098
|
if (rows.length === 0) return { messages: [], total, fromIndex: from };
|
|
7018
7099
|
const messages = [];
|
|
7019
|
-
const fd = (0,
|
|
7100
|
+
const fd = (0, import_fs11.openSync)(filePath, "r");
|
|
7020
7101
|
try {
|
|
7021
7102
|
const state = (0, import_scanner2.createJsonlParseState)();
|
|
7022
7103
|
for (const row of rows) {
|
|
7023
7104
|
const buf = Buffer.alloc(row.byte_length);
|
|
7024
|
-
(0,
|
|
7105
|
+
(0, import_fs11.readSync)(fd, buf, 0, row.byte_length, row.byte_offset);
|
|
7025
7106
|
const msg = (0, import_scanner2.parseJsonlLine)(buf.toString("utf-8"), state);
|
|
7026
7107
|
if (msg) messages.push(msg);
|
|
7027
7108
|
}
|
|
7028
7109
|
} finally {
|
|
7029
|
-
(0,
|
|
7110
|
+
(0, import_fs11.closeSync)(fd);
|
|
7030
7111
|
}
|
|
7031
7112
|
return { messages, total, fromIndex: from };
|
|
7032
7113
|
}
|
|
@@ -7054,14 +7135,14 @@ var ConversationCache = class _ConversationCache {
|
|
|
7054
7135
|
isAgentFileCached(filePath) {
|
|
7055
7136
|
let s;
|
|
7056
7137
|
try {
|
|
7057
|
-
s = (0,
|
|
7138
|
+
s = (0, import_fs11.statSync)(filePath);
|
|
7058
7139
|
} catch {
|
|
7059
7140
|
return false;
|
|
7060
7141
|
}
|
|
7061
7142
|
return this.classifyAgentFile(filePath, s.mtimeMs, s.size);
|
|
7062
7143
|
}
|
|
7063
7144
|
static open(dbPath, tailSize = 10, migrationsDir, options) {
|
|
7064
|
-
(0,
|
|
7145
|
+
(0, import_fs11.mkdirSync)((0, import_path12.dirname)(dbPath), { recursive: true });
|
|
7065
7146
|
const db = instrumentDatabase(new import_better_sqlite3.default(dbPath));
|
|
7066
7147
|
db.pragma("journal_mode = WAL");
|
|
7067
7148
|
db.pragma("foreign_keys = ON");
|
|
@@ -7265,7 +7346,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
7265
7346
|
let mtimeMs = null;
|
|
7266
7347
|
let fileSize = null;
|
|
7267
7348
|
try {
|
|
7268
|
-
const s = (0,
|
|
7349
|
+
const s = (0, import_fs11.statSync)(m.filePath);
|
|
7269
7350
|
mtimeMs = s.mtimeMs;
|
|
7270
7351
|
fileSize = s.size;
|
|
7271
7352
|
} catch {
|
|
@@ -7325,8 +7406,8 @@ var ConversationCache = class _ConversationCache {
|
|
|
7325
7406
|
let fileSize;
|
|
7326
7407
|
let fd;
|
|
7327
7408
|
try {
|
|
7328
|
-
fileSize = (0,
|
|
7329
|
-
fd = (0,
|
|
7409
|
+
fileSize = (0, import_fs11.statSync)(filePath).size;
|
|
7410
|
+
fd = (0, import_fs11.openSync)(filePath, "r");
|
|
7330
7411
|
} catch {
|
|
7331
7412
|
return false;
|
|
7332
7413
|
}
|
|
@@ -7339,7 +7420,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
7339
7420
|
while (pos > 0 && lines.length < this.tailSize * 4) {
|
|
7340
7421
|
const toRead = Math.min(CHUNK, pos);
|
|
7341
7422
|
pos -= toRead;
|
|
7342
|
-
(0,
|
|
7423
|
+
(0, import_fs11.readSync)(fd, buf, 0, toRead, pos);
|
|
7343
7424
|
const chunk = buf.subarray(0, toRead).toString("utf8");
|
|
7344
7425
|
const combined = chunk + partial;
|
|
7345
7426
|
const parts = combined.split("\n");
|
|
@@ -7350,7 +7431,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
7350
7431
|
}
|
|
7351
7432
|
if (partial) lines.push(partial);
|
|
7352
7433
|
} finally {
|
|
7353
|
-
(0,
|
|
7434
|
+
(0, import_fs11.closeSync)(fd);
|
|
7354
7435
|
}
|
|
7355
7436
|
const msgs = [];
|
|
7356
7437
|
for (let i = 0; i < lines.length && msgs.length < this.tailSize; i++) {
|
|
@@ -7563,7 +7644,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
7563
7644
|
* `handleGetConversation` can still serve the cached tail even when the
|
|
7564
7645
|
* JSONL has been deleted.
|
|
7565
7646
|
*/
|
|
7566
|
-
pruneGhostFiles(exists =
|
|
7647
|
+
pruneGhostFiles(exists = import_fs11.existsSync) {
|
|
7567
7648
|
const rows = this.stmts.allFilePaths.all();
|
|
7568
7649
|
const ghosts = [];
|
|
7569
7650
|
const prune = this.db.transaction((ids) => {
|
|
@@ -7618,7 +7699,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
7618
7699
|
* Returns the removed IDs.
|
|
7619
7700
|
*/
|
|
7620
7701
|
reconcileDeletions(livePaths, opts) {
|
|
7621
|
-
const exists = opts?.exists ??
|
|
7702
|
+
const exists = opts?.exists ?? import_fs11.existsSync;
|
|
7622
7703
|
const rows = this.stmts.allFilePaths.all();
|
|
7623
7704
|
const removed = [];
|
|
7624
7705
|
const drop = this.db.transaction((ids) => {
|
|
@@ -7653,7 +7734,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
7653
7734
|
* reports drift for the CacheIntegrityMonitor to classify. `tailed` flags
|
|
7654
7735
|
* rows that still have cached history (which pruneGhostFiles would keep).
|
|
7655
7736
|
*/
|
|
7656
|
-
listMissingFiles(exists =
|
|
7737
|
+
listMissingFiles(exists = import_fs11.existsSync) {
|
|
7657
7738
|
const rows = this.stmts.allFilePathsWithTitle.all();
|
|
7658
7739
|
const missing = [];
|
|
7659
7740
|
for (const row of rows) {
|
|
@@ -7994,10 +8075,10 @@ function createScanProgressThrottle() {
|
|
|
7994
8075
|
}
|
|
7995
8076
|
|
|
7996
8077
|
// src/api/handlers/http-helpers.ts
|
|
7997
|
-
var
|
|
8078
|
+
var import_fs12 = require("fs");
|
|
7998
8079
|
function classifyResumability(cwd) {
|
|
7999
8080
|
if (!cwd) return { resumable: true };
|
|
8000
|
-
if ((0,
|
|
8081
|
+
if ((0, import_fs12.existsSync)(cwd)) return { resumable: true };
|
|
8001
8082
|
const ranInWorktree = /\/\.worktrees\//.test(cwd) || /\/\.claude\/worktrees\//.test(cwd);
|
|
8002
8083
|
return {
|
|
8003
8084
|
resumable: false,
|
|
@@ -8352,15 +8433,15 @@ var ConversationHandlers = class {
|
|
|
8352
8433
|
findJsonlPath(uuid) {
|
|
8353
8434
|
const filename = `${uuid}.jsonl`;
|
|
8354
8435
|
for (const projectsDir of this.scannerManager.projectsDirs()) {
|
|
8355
|
-
if (!(0,
|
|
8356
|
-
for (const dir of (0,
|
|
8357
|
-
const fp = (0,
|
|
8358
|
-
if ((0,
|
|
8359
|
-
const projectDir = (0,
|
|
8436
|
+
if (!(0, import_fs13.existsSync)(projectsDir)) continue;
|
|
8437
|
+
for (const dir of (0, import_fs13.readdirSync)(projectsDir)) {
|
|
8438
|
+
const fp = (0, import_path13.join)(projectsDir, dir, filename);
|
|
8439
|
+
if ((0, import_fs13.existsSync)(fp)) return fp;
|
|
8440
|
+
const projectDir = (0, import_path13.join)(projectsDir, dir);
|
|
8360
8441
|
try {
|
|
8361
|
-
for (const sub of (0,
|
|
8362
|
-
const subagentPath = (0,
|
|
8363
|
-
if ((0,
|
|
8442
|
+
for (const sub of (0, import_fs13.readdirSync)(projectDir)) {
|
|
8443
|
+
const subagentPath = (0, import_path13.join)(projectDir, sub, "subagents", filename);
|
|
8444
|
+
if ((0, import_fs13.existsSync)(subagentPath)) return subagentPath;
|
|
8364
8445
|
}
|
|
8365
8446
|
} catch {
|
|
8366
8447
|
}
|
|
@@ -8370,7 +8451,7 @@ var ConversationHandlers = class {
|
|
|
8370
8451
|
}
|
|
8371
8452
|
async readCwdFromJsonl(filePath) {
|
|
8372
8453
|
return new Promise((resolve2) => {
|
|
8373
|
-
const rl = (0, import_readline.createInterface)({ input: (0,
|
|
8454
|
+
const rl = (0, import_readline.createInterface)({ input: (0, import_fs13.createReadStream)(filePath), crlfDelay: Infinity });
|
|
8374
8455
|
let found = false;
|
|
8375
8456
|
rl.on("line", (line) => {
|
|
8376
8457
|
if (found) return;
|
|
@@ -8833,11 +8914,11 @@ var ConversationHandlers = class {
|
|
|
8833
8914
|
};
|
|
8834
8915
|
|
|
8835
8916
|
// src/api/handlers/sessions.handlers.ts
|
|
8836
|
-
var
|
|
8837
|
-
var
|
|
8917
|
+
var import_fs15 = require("fs");
|
|
8918
|
+
var import_path16 = require("path");
|
|
8838
8919
|
|
|
8839
8920
|
// node_modules/nanoid/index.js
|
|
8840
|
-
var
|
|
8921
|
+
var import_crypto7 = __toESM(require("crypto"), 1);
|
|
8841
8922
|
|
|
8842
8923
|
// node_modules/nanoid/url-alphabet/index.js
|
|
8843
8924
|
var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
@@ -8851,10 +8932,10 @@ var fillPool = (bytes) => {
|
|
|
8851
8932
|
try {
|
|
8852
8933
|
if (!pool || pool.length < bytes) {
|
|
8853
8934
|
pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
|
|
8854
|
-
|
|
8935
|
+
import_crypto7.default.randomFillSync(pool);
|
|
8855
8936
|
poolOffset = 0;
|
|
8856
8937
|
} else if (poolOffset + bytes > pool.length) {
|
|
8857
|
-
|
|
8938
|
+
import_crypto7.default.randomFillSync(pool);
|
|
8858
8939
|
poolOffset = 0;
|
|
8859
8940
|
}
|
|
8860
8941
|
} catch (e) {
|
|
@@ -9093,7 +9174,7 @@ async function handleStartAgentSession(body, deps) {
|
|
|
9093
9174
|
|
|
9094
9175
|
// src/browse.ts
|
|
9095
9176
|
var import_promises4 = require("fs/promises");
|
|
9096
|
-
var
|
|
9177
|
+
var import_path14 = require("path");
|
|
9097
9178
|
var BrowsePathNotFoundError = class extends Error {
|
|
9098
9179
|
constructor(message) {
|
|
9099
9180
|
super(message);
|
|
@@ -9101,15 +9182,15 @@ var BrowsePathNotFoundError = class extends Error {
|
|
|
9101
9182
|
}
|
|
9102
9183
|
};
|
|
9103
9184
|
async function resolveBrowsePath(browseRoot, relativePath) {
|
|
9104
|
-
const normalizedRoot = (0,
|
|
9185
|
+
const normalizedRoot = (0, import_path14.resolve)(browseRoot);
|
|
9105
9186
|
let sanitized;
|
|
9106
9187
|
if (process.platform !== "win32" && relativePath.startsWith("/") && relativePath.length > 1 && relativePath.includes("/", 1)) {
|
|
9107
9188
|
sanitized = relativePath;
|
|
9108
9189
|
} else {
|
|
9109
9190
|
sanitized = relativePath.replace(/^[/\\]+/, "");
|
|
9110
9191
|
}
|
|
9111
|
-
const target = sanitized ? (0,
|
|
9112
|
-
const rootPrefix = normalizedRoot.endsWith(
|
|
9192
|
+
const target = sanitized ? (0, import_path14.resolve)(normalizedRoot, sanitized) : normalizedRoot;
|
|
9193
|
+
const rootPrefix = normalizedRoot.endsWith(import_path14.sep) ? normalizedRoot : `${normalizedRoot}${import_path14.sep}`;
|
|
9113
9194
|
if (!target.startsWith(rootPrefix) && target !== normalizedRoot) {
|
|
9114
9195
|
throw new Error("Path outside browse root");
|
|
9115
9196
|
}
|
|
@@ -9135,7 +9216,7 @@ async function createDirectory(parentAbsolutePath, name) {
|
|
|
9135
9216
|
if (name.includes("/") || name.includes("\\") || name === ".." || name === ".") {
|
|
9136
9217
|
throw new Error("Invalid directory name");
|
|
9137
9218
|
}
|
|
9138
|
-
const target = (0,
|
|
9219
|
+
const target = (0, import_path14.join)(parentAbsolutePath, name);
|
|
9139
9220
|
try {
|
|
9140
9221
|
const s = await (0, import_promises4.stat)(target);
|
|
9141
9222
|
if (s.isDirectory()) throw new Error("Directory already exists");
|
|
@@ -9298,7 +9379,7 @@ async function findRolloutOwner(rolloutPath, options = {}) {
|
|
|
9298
9379
|
}
|
|
9299
9380
|
|
|
9300
9381
|
// src/services/sessions/conversationBusy.ts
|
|
9301
|
-
var
|
|
9382
|
+
var import_fs14 = require("fs");
|
|
9302
9383
|
|
|
9303
9384
|
// src/utils/canonicalizeProjectPath.ts
|
|
9304
9385
|
function canonicalizeProjectPath(projectPath) {
|
|
@@ -9322,7 +9403,7 @@ function conversationBusy(input) {
|
|
|
9322
9403
|
let lastActivityMs = null;
|
|
9323
9404
|
if (input.jsonlPath) {
|
|
9324
9405
|
try {
|
|
9325
|
-
const mtimeMs = (0,
|
|
9406
|
+
const mtimeMs = (0, import_fs14.statSync)(input.jsonlPath).mtimeMs;
|
|
9326
9407
|
const age = now - mtimeMs;
|
|
9327
9408
|
lastActivityMs = Math.max(0, age);
|
|
9328
9409
|
const isSelfEcho = input.selfPtyEndedAt != null && mtimeMs <= input.selfPtyEndedAt + SELF_ACTIVITY_SKEW_MS;
|
|
@@ -9407,10 +9488,10 @@ function readIdempotencyKey(body) {
|
|
|
9407
9488
|
}
|
|
9408
9489
|
|
|
9409
9490
|
// src/uploads.ts
|
|
9410
|
-
var
|
|
9491
|
+
var import_crypto8 = require("crypto");
|
|
9411
9492
|
var import_promises5 = require("fs/promises");
|
|
9412
9493
|
var import_heic_convert = __toESM(require("heic-convert"), 1);
|
|
9413
|
-
var
|
|
9494
|
+
var import_path15 = require("path");
|
|
9414
9495
|
var UPLOAD_DIR_NAME = ".threadbase-uploads";
|
|
9415
9496
|
var MAX_BYTES = 25 * 1024 * 1024;
|
|
9416
9497
|
var HEIC_MIMES = /* @__PURE__ */ new Set(["image/heic", "image/heif"]);
|
|
@@ -9441,11 +9522,11 @@ async function saveUploadFile(input) {
|
|
|
9441
9522
|
mimeType = "image/jpeg";
|
|
9442
9523
|
originalName = originalName.replace(/\.(heic|heif)$/i, ".jpg");
|
|
9443
9524
|
}
|
|
9444
|
-
const id = `up_${(0,
|
|
9525
|
+
const id = `up_${(0, import_crypto8.randomBytes)(8).toString("hex")}`;
|
|
9445
9526
|
const safeName = sanitizeFilename(originalName) || `file${MIME_TO_EXT[mimeType] ?? ""}`;
|
|
9446
|
-
const dir = (0,
|
|
9527
|
+
const dir = (0, import_path15.join)(input.projectPath, UPLOAD_DIR_NAME, input.sessionId);
|
|
9447
9528
|
await (0, import_promises5.mkdir)(dir, { recursive: true });
|
|
9448
|
-
const filePath = (0,
|
|
9529
|
+
const filePath = (0, import_path15.join)(dir, `${Date.now()}-${id}-${safeName}`);
|
|
9449
9530
|
await (0, import_promises5.writeFile)(filePath, buffer);
|
|
9450
9531
|
return {
|
|
9451
9532
|
id,
|
|
@@ -9677,7 +9758,7 @@ var SessionHandlers = class {
|
|
|
9677
9758
|
const reconciled = this.deps.withReconciledLifecycle([base])[0];
|
|
9678
9759
|
const session = {
|
|
9679
9760
|
...base,
|
|
9680
|
-
...(0,
|
|
9761
|
+
...(0, import_fs15.existsSync)(base.projectPath) ? {} : { failureReason: `Project directory not found: ${base.projectPath}` },
|
|
9681
9762
|
lifecycle: reconciled.lifecycle,
|
|
9682
9763
|
lifecycleSource: reconciled.lifecycleSource
|
|
9683
9764
|
};
|
|
@@ -10289,7 +10370,7 @@ var SessionHandlers = class {
|
|
|
10289
10370
|
const jsonlCwd = jsonlPath ? await this.deps.readCwdFromJsonl(jsonlPath) : null;
|
|
10290
10371
|
if (jsonlCwd) {
|
|
10291
10372
|
projectPath = jsonlCwd;
|
|
10292
|
-
projectName = projectName || (0,
|
|
10373
|
+
projectName = projectName || (0, import_path16.basename)(jsonlCwd);
|
|
10293
10374
|
}
|
|
10294
10375
|
}
|
|
10295
10376
|
if (!projectPath) {
|
|
@@ -10366,7 +10447,7 @@ var SessionHandlers = class {
|
|
|
10366
10447
|
sessionStore: this.sessionStore,
|
|
10367
10448
|
// biome-ignore lint/style/noNonNullAssertion: agentClient is set when agentConfig.enabled is true
|
|
10368
10449
|
agentClient: this.agentClient,
|
|
10369
|
-
conversationsDir: this.cacheDir ? (0,
|
|
10450
|
+
conversationsDir: this.cacheDir ? (0, import_path16.join)((0, import_path16.dirname)(this.cacheDir), "conversations") : "",
|
|
10370
10451
|
agentConfig: this.agentConfig
|
|
10371
10452
|
});
|
|
10372
10453
|
json(res, result.status, result.body);
|
|
@@ -10721,7 +10802,7 @@ var ManagedSessionsRepository = class {
|
|
|
10721
10802
|
};
|
|
10722
10803
|
|
|
10723
10804
|
// src/db/repositories/projects.repository.ts
|
|
10724
|
-
var
|
|
10805
|
+
var import_crypto9 = require("crypto");
|
|
10725
10806
|
function rowToProject(row) {
|
|
10726
10807
|
return {
|
|
10727
10808
|
id: row.id,
|
|
@@ -10806,7 +10887,7 @@ var ProjectsRepository = class {
|
|
|
10806
10887
|
});
|
|
10807
10888
|
return rowToProject(this.getById.get(existing.id));
|
|
10808
10889
|
}
|
|
10809
|
-
const id = (0,
|
|
10890
|
+
const id = (0, import_crypto9.randomUUID)();
|
|
10810
10891
|
this.insert.run({
|
|
10811
10892
|
id,
|
|
10812
10893
|
path,
|
|
@@ -10843,10 +10924,10 @@ var SessionsRepository = class {
|
|
|
10843
10924
|
|
|
10844
10925
|
// src/db/runtime-store.ts
|
|
10845
10926
|
var import_better_sqlite32 = __toESM(require("better-sqlite3"), 1);
|
|
10846
|
-
var
|
|
10847
|
-
var
|
|
10927
|
+
var import_os8 = require("os");
|
|
10928
|
+
var import_path17 = require("path");
|
|
10848
10929
|
function resolveRuntimeDbPath(override) {
|
|
10849
|
-
return override ?? process.env.THREADBASE_RUNTIME_DB ?? (0,
|
|
10930
|
+
return override ?? process.env.THREADBASE_RUNTIME_DB ?? (0, import_path17.join)(process.env.THREADBASE_CONFIG_DIR ?? (0, import_path17.join)((0, import_os8.homedir)(), ".threadbase"), "runtime.db");
|
|
10850
10931
|
}
|
|
10851
10932
|
var RuntimeStore = class _RuntimeStore {
|
|
10852
10933
|
constructor(db) {
|
|
@@ -10936,7 +11017,7 @@ var RuntimeStore = class _RuntimeStore {
|
|
|
10936
11017
|
};
|
|
10937
11018
|
|
|
10938
11019
|
// src/external-tails.ts
|
|
10939
|
-
var
|
|
11020
|
+
var import_fs16 = require("fs");
|
|
10940
11021
|
var EXTERNAL_TAIL_RECENCY_MS = RESUME_BUSY_WINDOW_MS;
|
|
10941
11022
|
var EXTERNAL_TAIL_MAX = 32;
|
|
10942
11023
|
var EXTERNAL_TAIL_IDLE_MS = 3e5;
|
|
@@ -10969,7 +11050,7 @@ var ExternalTailManager = class {
|
|
|
10969
11050
|
if (this.isManagedTailPath(key)) return;
|
|
10970
11051
|
let mtimeMs;
|
|
10971
11052
|
try {
|
|
10972
|
-
mtimeMs = (0,
|
|
11053
|
+
mtimeMs = (0, import_fs16.statSync)(filePath).mtimeMs;
|
|
10973
11054
|
} catch {
|
|
10974
11055
|
return;
|
|
10975
11056
|
}
|
|
@@ -11106,7 +11187,7 @@ var ExternalTailManager = class {
|
|
|
11106
11187
|
};
|
|
11107
11188
|
|
|
11108
11189
|
// src/pair-store.ts
|
|
11109
|
-
var
|
|
11190
|
+
var import_crypto10 = require("crypto");
|
|
11110
11191
|
var DEFAULT_TTL_SECONDS = 180;
|
|
11111
11192
|
var SWEEP_INTERVAL_MS = 6e4;
|
|
11112
11193
|
var PairTokenStore = class {
|
|
@@ -11121,7 +11202,7 @@ var PairTokenStore = class {
|
|
|
11121
11202
|
}
|
|
11122
11203
|
}
|
|
11123
11204
|
mint() {
|
|
11124
|
-
const token = `pt_${(0,
|
|
11205
|
+
const token = `pt_${(0, import_crypto10.randomBytes)(16).toString("hex")}`;
|
|
11125
11206
|
const expiresAt = Date.now() + this.ttlMs;
|
|
11126
11207
|
this.current = { token, expiresAt, used: false };
|
|
11127
11208
|
return {
|
|
@@ -11243,9 +11324,9 @@ function spawnDetachedHost(socketPath, entryPoint) {
|
|
|
11243
11324
|
|
|
11244
11325
|
// src/scanner-manager.ts
|
|
11245
11326
|
var import_scanner4 = require("@threadbase-sh/scanner");
|
|
11246
|
-
var
|
|
11247
|
-
var
|
|
11248
|
-
var
|
|
11327
|
+
var import_fs18 = require("fs");
|
|
11328
|
+
var import_os10 = require("os");
|
|
11329
|
+
var import_path19 = require("path");
|
|
11249
11330
|
|
|
11250
11331
|
// src/services/cache/cacheMetadata.ts
|
|
11251
11332
|
function getCacheMetadata(repo, key) {
|
|
@@ -11344,22 +11425,22 @@ function refreshConversationCache(deps) {
|
|
|
11344
11425
|
}
|
|
11345
11426
|
|
|
11346
11427
|
// src/services/conversations/shouldRefreshProjectsFromHdd.ts
|
|
11347
|
-
var
|
|
11348
|
-
var
|
|
11349
|
-
var
|
|
11350
|
-
var DEFAULT_PROJECTS_DIR = (0,
|
|
11428
|
+
var import_fs17 = require("fs");
|
|
11429
|
+
var import_os9 = require("os");
|
|
11430
|
+
var import_path18 = require("path");
|
|
11431
|
+
var DEFAULT_PROJECTS_DIR = (0, import_path18.join)((0, import_os9.homedir)(), ".claude", "projects");
|
|
11351
11432
|
function maxProjectsTreeMtimeMs(projectsDir) {
|
|
11352
11433
|
let maxMs;
|
|
11353
11434
|
try {
|
|
11354
|
-
maxMs = (0,
|
|
11435
|
+
maxMs = (0, import_fs17.statSync)(projectsDir).mtimeMs;
|
|
11355
11436
|
} catch {
|
|
11356
11437
|
return null;
|
|
11357
11438
|
}
|
|
11358
11439
|
try {
|
|
11359
|
-
for (const ent of (0,
|
|
11440
|
+
for (const ent of (0, import_fs17.readdirSync)(projectsDir, { withFileTypes: true })) {
|
|
11360
11441
|
if (!ent.isDirectory()) continue;
|
|
11361
11442
|
try {
|
|
11362
|
-
const childMs = (0,
|
|
11443
|
+
const childMs = (0, import_fs17.statSync)((0, import_path18.join)(projectsDir, ent.name)).mtimeMs;
|
|
11363
11444
|
if (childMs > maxMs) maxMs = childMs;
|
|
11364
11445
|
} catch {
|
|
11365
11446
|
}
|
|
@@ -11531,9 +11612,9 @@ var ScannerManager = class {
|
|
|
11531
11612
|
projectsDirs() {
|
|
11532
11613
|
const profiles = this.deps.scanProfiles;
|
|
11533
11614
|
if (profiles && profiles.length > 0) {
|
|
11534
|
-
return profiles.filter((p) => p.enabled).map((p) => (0,
|
|
11615
|
+
return profiles.filter((p) => p.enabled).map((p) => (0, import_path19.join)(p.configDir, "projects"));
|
|
11535
11616
|
}
|
|
11536
|
-
return [(0,
|
|
11617
|
+
return [(0, import_path19.join)((0, import_os10.homedir)(), ".claude", "projects")];
|
|
11537
11618
|
}
|
|
11538
11619
|
// ─── staleness ────────────────────────────────────────────────────
|
|
11539
11620
|
// Drain the stale set and disarm the flag together. The caller owns the
|
|
@@ -11571,7 +11652,7 @@ var ScannerManager = class {
|
|
|
11571
11652
|
if (!conv.filePath) return false;
|
|
11572
11653
|
let mtimeMs = null;
|
|
11573
11654
|
try {
|
|
11574
|
-
mtimeMs = (0,
|
|
11655
|
+
mtimeMs = (0, import_fs18.statSync)(conv.filePath).mtimeMs;
|
|
11575
11656
|
} catch {
|
|
11576
11657
|
return false;
|
|
11577
11658
|
}
|
|
@@ -11810,27 +11891,27 @@ function seal(plaintext, recipientPublicKeyBase64) {
|
|
|
11810
11891
|
}
|
|
11811
11892
|
|
|
11812
11893
|
// src/server-wiring.ts
|
|
11813
|
-
var
|
|
11894
|
+
var import_fs20 = require("fs");
|
|
11814
11895
|
|
|
11815
11896
|
// src/handlers/handleListProjects.ts
|
|
11816
|
-
var
|
|
11817
|
-
var
|
|
11818
|
-
var
|
|
11897
|
+
var import_fs19 = require("fs");
|
|
11898
|
+
var import_os11 = require("os");
|
|
11899
|
+
var import_path20 = require("path");
|
|
11819
11900
|
var HEAD_BYTES = 64 * 1024;
|
|
11820
11901
|
var MAX_FILES_PROBED = 3;
|
|
11821
11902
|
function readRecordedCwd(dir) {
|
|
11822
11903
|
let files;
|
|
11823
11904
|
try {
|
|
11824
|
-
files = (0,
|
|
11905
|
+
files = (0, import_fs19.readdirSync)(dir).filter((f) => f.endsWith(".jsonl"));
|
|
11825
11906
|
} catch {
|
|
11826
11907
|
return null;
|
|
11827
11908
|
}
|
|
11828
11909
|
for (const file of files.slice(0, MAX_FILES_PROBED)) {
|
|
11829
11910
|
let fd;
|
|
11830
11911
|
try {
|
|
11831
|
-
fd = (0,
|
|
11912
|
+
fd = (0, import_fs19.openSync)((0, import_path20.join)(dir, file), "r");
|
|
11832
11913
|
const buf = Buffer.alloc(HEAD_BYTES);
|
|
11833
|
-
const bytes = (0,
|
|
11914
|
+
const bytes = (0, import_fs19.readSync)(fd, buf, 0, HEAD_BYTES, 0);
|
|
11834
11915
|
for (const line of buf.subarray(0, bytes).toString("utf8").split("\n")) {
|
|
11835
11916
|
if (!line.includes('"cwd"')) continue;
|
|
11836
11917
|
try {
|
|
@@ -11841,7 +11922,7 @@ function readRecordedCwd(dir) {
|
|
|
11841
11922
|
}
|
|
11842
11923
|
} catch {
|
|
11843
11924
|
} finally {
|
|
11844
|
-
if (fd !== void 0) (0,
|
|
11925
|
+
if (fd !== void 0) (0, import_fs19.closeSync)(fd);
|
|
11845
11926
|
}
|
|
11846
11927
|
}
|
|
11847
11928
|
return null;
|
|
@@ -11852,14 +11933,14 @@ function decodeProjectPath(dirName) {
|
|
|
11852
11933
|
function handleListProjects(url, res) {
|
|
11853
11934
|
const limit = Math.max(1, parseInt(url.searchParams.get("limit") ?? "50", 10) || 50);
|
|
11854
11935
|
const offset = Math.max(0, parseInt(url.searchParams.get("offset") ?? "0", 10) || 0);
|
|
11855
|
-
const projectsDir = (0,
|
|
11936
|
+
const projectsDir = (0, import_path20.join)((0, import_os11.homedir)(), ".claude", "projects");
|
|
11856
11937
|
let entries;
|
|
11857
11938
|
try {
|
|
11858
|
-
entries = (0,
|
|
11859
|
-
const fullPath = (0,
|
|
11939
|
+
entries = (0, import_fs19.readdirSync)(projectsDir).map((dirName) => {
|
|
11940
|
+
const fullPath = (0, import_path20.join)(projectsDir, dirName);
|
|
11860
11941
|
let mtime = 0;
|
|
11861
11942
|
try {
|
|
11862
|
-
mtime = (0,
|
|
11943
|
+
mtime = (0, import_fs19.statSync)(fullPath).mtimeMs;
|
|
11863
11944
|
} catch {
|
|
11864
11945
|
}
|
|
11865
11946
|
return { dirName: String(dirName), mtime };
|
|
@@ -11871,7 +11952,7 @@ function handleListProjects(url, res) {
|
|
|
11871
11952
|
}
|
|
11872
11953
|
const total = entries.length;
|
|
11873
11954
|
const page = entries.slice(offset, offset + limit).map(({ dirName }) => {
|
|
11874
|
-
const path = readRecordedCwd((0,
|
|
11955
|
+
const path = readRecordedCwd((0, import_path20.join)(projectsDir, dirName)) ?? decodeProjectPath(String(dirName));
|
|
11875
11956
|
const name = path.split(/[\\/]/).filter(Boolean).pop() ?? dirName;
|
|
11876
11957
|
return { name, path, dirName };
|
|
11877
11958
|
});
|
|
@@ -11893,7 +11974,7 @@ function createConversationWatcherEvents(deps) {
|
|
|
11893
11974
|
const seqs = cache.extendMessageIndex(
|
|
11894
11975
|
filePath,
|
|
11895
11976
|
spans,
|
|
11896
|
-
(0,
|
|
11977
|
+
(0, import_fs20.statSync)(filePath),
|
|
11897
11978
|
readFrom,
|
|
11898
11979
|
endOffset
|
|
11899
11980
|
);
|
|
@@ -11940,7 +12021,7 @@ function createConversationWatcherEvents(deps) {
|
|
|
11940
12021
|
},
|
|
11941
12022
|
onConversationChanged: (filePath) => {
|
|
11942
12023
|
try {
|
|
11943
|
-
(0,
|
|
12024
|
+
(0, import_fs20.statSync)(filePath);
|
|
11944
12025
|
} catch {
|
|
11945
12026
|
deps.externalTailManager().handleJsonlDeleted(filePath);
|
|
11946
12027
|
return;
|
|
@@ -12269,20 +12350,20 @@ function createApiDeps(deps) {
|
|
|
12269
12350
|
}
|
|
12270
12351
|
|
|
12271
12352
|
// src/services/cache-integrity/cacheIntegrityMonitor.ts
|
|
12272
|
-
var
|
|
12273
|
-
var
|
|
12353
|
+
var import_crypto11 = require("crypto");
|
|
12354
|
+
var import_fs23 = require("fs");
|
|
12274
12355
|
|
|
12275
12356
|
// src/services/cache-integrity/alertStore.ts
|
|
12276
|
-
var
|
|
12277
|
-
var
|
|
12278
|
-
var
|
|
12357
|
+
var import_fs21 = require("fs");
|
|
12358
|
+
var import_os12 = require("os");
|
|
12359
|
+
var import_path21 = require("path");
|
|
12279
12360
|
function alertStatePath() {
|
|
12280
|
-
const dir = process.env.THREADBASE_CONFIG_DIR ?? (0,
|
|
12281
|
-
return (0,
|
|
12361
|
+
const dir = process.env.THREADBASE_CONFIG_DIR ?? (0, import_path21.join)((0, import_os12.homedir)(), ".threadbase");
|
|
12362
|
+
return (0, import_path21.join)(dir, "cache-alert.json");
|
|
12282
12363
|
}
|
|
12283
12364
|
function loadAlertState() {
|
|
12284
12365
|
try {
|
|
12285
|
-
const parsed = JSON.parse((0,
|
|
12366
|
+
const parsed = JSON.parse((0, import_fs21.readFileSync)(alertStatePath(), "utf-8"));
|
|
12286
12367
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
12287
12368
|
} catch {
|
|
12288
12369
|
return {};
|
|
@@ -12290,14 +12371,14 @@ function loadAlertState() {
|
|
|
12290
12371
|
}
|
|
12291
12372
|
function saveAlertState(state) {
|
|
12292
12373
|
const path = alertStatePath();
|
|
12293
|
-
(0,
|
|
12294
|
-
(0,
|
|
12374
|
+
(0, import_fs21.mkdirSync)((0, import_path21.dirname)(path), { recursive: true });
|
|
12375
|
+
(0, import_fs21.writeFileSync)(path, `${JSON.stringify(state, null, 2)}
|
|
12295
12376
|
`);
|
|
12296
12377
|
}
|
|
12297
12378
|
|
|
12298
12379
|
// src/services/cache-integrity/backup.ts
|
|
12299
|
-
var
|
|
12300
|
-
var
|
|
12380
|
+
var import_fs22 = require("fs");
|
|
12381
|
+
var import_path22 = require("path");
|
|
12301
12382
|
var DEFAULT_RETAIN = 3;
|
|
12302
12383
|
function retainCount() {
|
|
12303
12384
|
const parsed = Number.parseInt(process.env.THREADBASE_CACHE_BACKUP_RETAIN ?? "", 10);
|
|
@@ -12308,17 +12389,17 @@ function timestamp(d) {
|
|
|
12308
12389
|
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
|
|
12309
12390
|
}
|
|
12310
12391
|
async function backupCacheDb(db, cacheDir) {
|
|
12311
|
-
const backupsDir = (0,
|
|
12312
|
-
(0,
|
|
12313
|
-
const destPath = (0,
|
|
12392
|
+
const backupsDir = (0, import_path22.join)(cacheDir, "backups");
|
|
12393
|
+
(0, import_fs22.mkdirSync)(backupsDir, { recursive: true });
|
|
12394
|
+
const destPath = (0, import_path22.join)(backupsDir, `cache-${timestamp(/* @__PURE__ */ new Date())}.db`);
|
|
12314
12395
|
await db.backup(destPath);
|
|
12315
12396
|
const retain = retainCount();
|
|
12316
|
-
const backups = (0,
|
|
12317
|
-
const full = (0,
|
|
12318
|
-
return { full, mtime: (0,
|
|
12397
|
+
const backups = (0, import_fs22.readdirSync)(backupsDir).filter((f) => f.startsWith("cache-") && f.endsWith(".db")).map((f) => {
|
|
12398
|
+
const full = (0, import_path22.join)(backupsDir, f);
|
|
12399
|
+
return { full, mtime: (0, import_fs22.statSync)(full).mtimeMs };
|
|
12319
12400
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
12320
12401
|
for (const stale of backups.slice(retain)) {
|
|
12321
|
-
if ((0,
|
|
12402
|
+
if ((0, import_fs22.existsSync)(stale.full)) (0, import_fs22.unlinkSync)(stale.full);
|
|
12322
12403
|
}
|
|
12323
12404
|
return destPath;
|
|
12324
12405
|
}
|
|
@@ -12334,7 +12415,7 @@ function envInt(name, fallback) {
|
|
|
12334
12415
|
}
|
|
12335
12416
|
function fingerprintOf(ids) {
|
|
12336
12417
|
const sorted = [...ids].sort();
|
|
12337
|
-
return `sha256:${(0,
|
|
12418
|
+
return `sha256:${(0, import_crypto11.createHash)("sha256").update(sorted.join("\n")).digest("hex")}`;
|
|
12338
12419
|
}
|
|
12339
12420
|
var CacheIntegrityMonitor = class {
|
|
12340
12421
|
constructor(cache, wsHub, log10, cacheDir, rescan, runDuringReset) {
|
|
@@ -12415,7 +12496,7 @@ var CacheIntegrityMonitor = class {
|
|
|
12415
12496
|
* the pending record, back up on high severity, and broadcast the alert.
|
|
12416
12497
|
*/
|
|
12417
12498
|
async runDetection(detectedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
12418
|
-
const all = this.cache.listMissingFiles(
|
|
12499
|
+
const all = this.cache.listMissingFiles(import_fs23.existsSync);
|
|
12419
12500
|
const missing = all.filter((m) => !this.ignoredIds.has(m.id));
|
|
12420
12501
|
if (missing.length === 0) {
|
|
12421
12502
|
if (this._pending) {
|
|
@@ -12519,7 +12600,7 @@ var CacheIntegrityMonitor = class {
|
|
|
12519
12600
|
case "prune_all": {
|
|
12520
12601
|
await this.ensureBackup(pending);
|
|
12521
12602
|
const backupPath = pending.backupPath;
|
|
12522
|
-
const stillMissing = pending.missing.filter((m) => !(0,
|
|
12603
|
+
const stillMissing = pending.missing.filter((m) => !(0, import_fs23.existsSync)(m.filePath)).map((m) => m.id);
|
|
12523
12604
|
const pruned = this.cache.dropRowsById(stillMissing);
|
|
12524
12605
|
this.applyDeferredUnlinks();
|
|
12525
12606
|
this.clearPending();
|
|
@@ -12581,7 +12662,7 @@ var CacheIntegrityMonitor = class {
|
|
|
12581
12662
|
|
|
12582
12663
|
// src/services/conversations/conversationWatcher.ts
|
|
12583
12664
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
12584
|
-
var
|
|
12665
|
+
var import_fs24 = require("fs");
|
|
12585
12666
|
var import_promises6 = require("fs/promises");
|
|
12586
12667
|
var ConversationWatcher = class {
|
|
12587
12668
|
files = /* @__PURE__ */ new Map();
|
|
@@ -12607,7 +12688,7 @@ var ConversationWatcher = class {
|
|
|
12607
12688
|
if (this.files.has(key)) return;
|
|
12608
12689
|
let offset;
|
|
12609
12690
|
try {
|
|
12610
|
-
offset = (0,
|
|
12691
|
+
offset = (0, import_fs24.statSync)(filePath).size;
|
|
12611
12692
|
} catch {
|
|
12612
12693
|
offset = 0;
|
|
12613
12694
|
}
|
|
@@ -12765,14 +12846,14 @@ var ConversationWatcher = class {
|
|
|
12765
12846
|
};
|
|
12766
12847
|
|
|
12767
12848
|
// src/services/conversations/pruneAgentConversations.ts
|
|
12768
|
-
var
|
|
12849
|
+
var import_fs25 = require("fs");
|
|
12769
12850
|
function pruneAgentConversations(cache) {
|
|
12770
12851
|
const db = cache.getDatabase();
|
|
12771
12852
|
const rows = db.prepare("SELECT id, file_path FROM conversation_meta").all();
|
|
12772
12853
|
let pruned = 0;
|
|
12773
12854
|
let missing = 0;
|
|
12774
12855
|
for (const row of rows) {
|
|
12775
|
-
if (!(0,
|
|
12856
|
+
if (!(0, import_fs25.existsSync)(row.file_path)) {
|
|
12776
12857
|
missing += 1;
|
|
12777
12858
|
continue;
|
|
12778
12859
|
}
|
|
@@ -13478,7 +13559,7 @@ function shouldBroadcastQuestion(args) {
|
|
|
13478
13559
|
}
|
|
13479
13560
|
|
|
13480
13561
|
// src/session-registry-boot.ts
|
|
13481
|
-
var
|
|
13562
|
+
var import_fs26 = require("fs");
|
|
13482
13563
|
|
|
13483
13564
|
// src/lifecycle/process-liveness.ts
|
|
13484
13565
|
function isPidAlive(pid) {
|
|
@@ -13724,7 +13805,7 @@ var SessionRegistryBoot = class {
|
|
|
13724
13805
|
const skippedBy = {};
|
|
13725
13806
|
for (const row of candidates) {
|
|
13726
13807
|
if (this.sessionStore.getManaged(row.session_id)) continue;
|
|
13727
|
-
const skip = rehydrateSkipReason(row, { now, projectExists:
|
|
13808
|
+
const skip = rehydrateSkipReason(row, { now, projectExists: import_fs26.existsSync });
|
|
13728
13809
|
if (skip) {
|
|
13729
13810
|
skippedBy[skip] = (skippedBy[skip] ?? 0) + 1;
|
|
13730
13811
|
this.log.info(`[rehydrate] skipped ${row.session_id}: ${skip}`, {
|
|
@@ -13766,7 +13847,7 @@ var SessionRegistryBoot = class {
|
|
|
13766
13847
|
async autoResumePreviousSessions(rows) {
|
|
13767
13848
|
if (!this.autoResumeOnBoot) return;
|
|
13768
13849
|
const now = Date.now();
|
|
13769
|
-
const baseOptions = { now, projectExists:
|
|
13850
|
+
const baseOptions = { now, projectExists: import_fs26.existsSync, historyExists: () => true };
|
|
13770
13851
|
const historyExists = /* @__PURE__ */ new Map();
|
|
13771
13852
|
const preflights = /* @__PURE__ */ new Set();
|
|
13772
13853
|
for (const row of rows) {
|
|
@@ -14282,9 +14363,9 @@ function discoveredToResponse(d, conversationId) {
|
|
|
14282
14363
|
}
|
|
14283
14364
|
|
|
14284
14365
|
// src/session-watchers.ts
|
|
14285
|
-
var
|
|
14286
|
-
var
|
|
14287
|
-
var
|
|
14366
|
+
var import_fs27 = require("fs");
|
|
14367
|
+
var import_os13 = require("os");
|
|
14368
|
+
var import_path23 = require("path");
|
|
14288
14369
|
var SessionWatchers = class {
|
|
14289
14370
|
constructor(deps) {
|
|
14290
14371
|
this.deps = deps;
|
|
@@ -14350,7 +14431,7 @@ var SessionWatchers = class {
|
|
|
14350
14431
|
// file isn't slurped in full.
|
|
14351
14432
|
readFirstLineSessionId(filePath) {
|
|
14352
14433
|
try {
|
|
14353
|
-
const content = (0,
|
|
14434
|
+
const content = (0, import_fs27.readFileSync)(filePath, "utf8");
|
|
14354
14435
|
const nl = content.indexOf("\n");
|
|
14355
14436
|
const firstLine = nl === -1 ? content : content.slice(0, nl);
|
|
14356
14437
|
if (!firstLine.trim()) return null;
|
|
@@ -14365,9 +14446,9 @@ var SessionWatchers = class {
|
|
|
14365
14446
|
// was passed to Claude via --session-id so the filename matches from the start.
|
|
14366
14447
|
watchForJsonl(sessionId, projectPath) {
|
|
14367
14448
|
const encoded = projectPath.replace(/[/\\:.]/g, "-");
|
|
14368
|
-
const projectsDir = (0,
|
|
14449
|
+
const projectsDir = (0, import_path23.join)((0, import_os13.homedir)(), ".claude", "projects", encoded);
|
|
14369
14450
|
const expectedFile = `${sessionId}.jsonl`;
|
|
14370
|
-
const filePath = (0,
|
|
14451
|
+
const filePath = (0, import_path23.join)(projectsDir, expectedFile);
|
|
14371
14452
|
const deadline = Date.now() + 12e4;
|
|
14372
14453
|
let watcher = null;
|
|
14373
14454
|
const cleanup = () => {
|
|
@@ -14385,14 +14466,14 @@ var SessionWatchers = class {
|
|
|
14385
14466
|
cleanup();
|
|
14386
14467
|
return;
|
|
14387
14468
|
}
|
|
14388
|
-
let resolvedFilePath = (0,
|
|
14389
|
-
if (!resolvedFilePath && (0,
|
|
14469
|
+
let resolvedFilePath = (0, import_fs27.existsSync)(filePath) ? filePath : null;
|
|
14470
|
+
if (!resolvedFilePath && (0, import_fs27.existsSync)(projectsDir)) {
|
|
14390
14471
|
try {
|
|
14391
14472
|
const now = Date.now();
|
|
14392
|
-
const match = (0,
|
|
14393
|
-
({ f }) => (0,
|
|
14473
|
+
const match = (0, import_fs27.readdirSync)(projectsDir).filter((f) => f.endsWith(".jsonl")).map((f) => ({ f, mtime: (0, import_fs27.statSync)((0, import_path23.join)(projectsDir, f)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).filter(
|
|
14474
|
+
({ f }) => (0, import_path23.basename)(f, ".jsonl") === sessionId || this.readFirstLineSessionId((0, import_path23.join)(projectsDir, f)) === sessionId
|
|
14394
14475
|
).sort((a, b) => b.mtime - a.mtime)[0];
|
|
14395
|
-
if (match) resolvedFilePath = (0,
|
|
14476
|
+
if (match) resolvedFilePath = (0, import_path23.join)(projectsDir, match.f);
|
|
14396
14477
|
} catch {
|
|
14397
14478
|
}
|
|
14398
14479
|
}
|
|
@@ -14400,7 +14481,7 @@ var SessionWatchers = class {
|
|
|
14400
14481
|
cleanup();
|
|
14401
14482
|
this.deps.sessionFileMap.set(sessionId, resolvedFilePath);
|
|
14402
14483
|
try {
|
|
14403
|
-
const existing = (0,
|
|
14484
|
+
const existing = (0, import_fs27.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
|
|
14404
14485
|
if (existing.length > 0) {
|
|
14405
14486
|
this.deps.broadcastConversationLines(sessionId, existing);
|
|
14406
14487
|
}
|
|
@@ -14420,7 +14501,7 @@ var SessionWatchers = class {
|
|
|
14420
14501
|
if (this.deps.sessionFileMap.has(sessionId)) return;
|
|
14421
14502
|
try {
|
|
14422
14503
|
require("fs").mkdirSync(projectsDir, { recursive: true });
|
|
14423
|
-
watcher = (0,
|
|
14504
|
+
watcher = (0, import_fs27.watch)(projectsDir, tryWire);
|
|
14424
14505
|
watcher.on("error", cleanup);
|
|
14425
14506
|
} catch {
|
|
14426
14507
|
}
|
|
@@ -14436,7 +14517,7 @@ var SessionWatchers = class {
|
|
|
14436
14517
|
watchForCodexRollout(sessionId, projectPath) {
|
|
14437
14518
|
const deadline = Date.now() + 12e4;
|
|
14438
14519
|
const now = /* @__PURE__ */ new Date();
|
|
14439
|
-
const dateDir = (0,
|
|
14520
|
+
const dateDir = (0, import_path23.join)(
|
|
14440
14521
|
String(now.getFullYear()),
|
|
14441
14522
|
String(now.getMonth() + 1).padStart(2, "0"),
|
|
14442
14523
|
String(now.getDate()).padStart(2, "0")
|
|
@@ -14449,7 +14530,7 @@ var SessionWatchers = class {
|
|
|
14449
14530
|
};
|
|
14450
14531
|
const matchesProjectPath = (candidatePath) => {
|
|
14451
14532
|
try {
|
|
14452
|
-
const firstLine = (0,
|
|
14533
|
+
const firstLine = (0, import_fs27.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
|
|
14453
14534
|
if (!firstLine) return null;
|
|
14454
14535
|
const parsed = JSON.parse(firstLine);
|
|
14455
14536
|
if (parsed?.type !== "session_meta") return null;
|
|
@@ -14477,18 +14558,18 @@ var SessionWatchers = class {
|
|
|
14477
14558
|
this.deps.sessionStore.listManaged().filter((s) => s.id !== sessionId && s.boundConversationId != null).map((s) => s.boundConversationId)
|
|
14478
14559
|
);
|
|
14479
14560
|
for (const root of this.deps.codexRoots) {
|
|
14480
|
-
const sessionsDir = (0,
|
|
14481
|
-
if (!(0,
|
|
14561
|
+
const sessionsDir = (0, import_path23.join)(root, dateDir);
|
|
14562
|
+
if (!(0, import_fs27.existsSync)(sessionsDir)) continue;
|
|
14482
14563
|
let candidateFiles;
|
|
14483
14564
|
try {
|
|
14484
|
-
candidateFiles = (0,
|
|
14565
|
+
candidateFiles = (0, import_fs27.readdirSync)(sessionsDir).filter((f) => f.endsWith(".jsonl"));
|
|
14485
14566
|
} catch {
|
|
14486
14567
|
continue;
|
|
14487
14568
|
}
|
|
14488
14569
|
const nowMs = Date.now();
|
|
14489
|
-
const recentCandidates = candidateFiles.map((f) => ({ f, mtime: (0,
|
|
14570
|
+
const recentCandidates = candidateFiles.map((f) => ({ f, mtime: (0, import_fs27.statSync)((0, import_path23.join)(sessionsDir, f)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b) => b.mtime - a.mtime);
|
|
14490
14571
|
for (const { f } of recentCandidates) {
|
|
14491
|
-
const candidatePath = (0,
|
|
14572
|
+
const candidatePath = (0, import_path23.join)(sessionsDir, f);
|
|
14492
14573
|
const match = matchesProjectPath(candidatePath);
|
|
14493
14574
|
if (!match) continue;
|
|
14494
14575
|
if (boundElsewhere.has(match.id)) continue;
|
|
@@ -14509,7 +14590,7 @@ var SessionWatchers = class {
|
|
|
14509
14590
|
this.deps.sessionFileMap.set(sessionId, candidatePath);
|
|
14510
14591
|
this.deps.fileWatcher.watch(candidatePath);
|
|
14511
14592
|
try {
|
|
14512
|
-
const existing = (0,
|
|
14593
|
+
const existing = (0, import_fs27.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
|
|
14513
14594
|
if (existing.length > 0) {
|
|
14514
14595
|
this.deps.broadcastConversationLines(sessionId, existing);
|
|
14515
14596
|
}
|
|
@@ -14840,7 +14921,7 @@ var StreamerServer = class {
|
|
|
14840
14921
|
runtimeStore = null;
|
|
14841
14922
|
// Identifies this streamer run. A registry row carrying a different id is a
|
|
14842
14923
|
// session that outlived the process that started it.
|
|
14843
|
-
streamerInstanceId = (0,
|
|
14924
|
+
streamerInstanceId = (0, import_crypto12.randomUUID)();
|
|
14844
14925
|
cacheMetadataRepo = null;
|
|
14845
14926
|
// Push registration + delivery state (C7). Null when the cache DB failed to
|
|
14846
14927
|
// open — registration then degrades to a no-op rather than 500ing.
|
|
@@ -14892,7 +14973,7 @@ var StreamerServer = class {
|
|
|
14892
14973
|
this.skipStartupWarmup = config.skipStartupWarmup ?? false;
|
|
14893
14974
|
this.autoResumeOnBoot = config.autoResumeOnBoot ?? false;
|
|
14894
14975
|
this.scanProfiles = config.scanProfiles;
|
|
14895
|
-
this.codexRoots = config.codexRoots ?? [(0,
|
|
14976
|
+
this.codexRoots = config.codexRoots ?? [(0, import_path24.join)((0, import_os14.homedir)(), ".codex", "sessions")];
|
|
14896
14977
|
this.ptyGracePeriodMs = config.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
|
|
14897
14978
|
this.defaultSystemPrompt = config.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
14898
14979
|
const flagResolution = resolveFeatureFlags({
|
|
@@ -14909,7 +14990,7 @@ var StreamerServer = class {
|
|
|
14909
14990
|
this.claudeFlagsPersistable = config.claudeFlags === void 0;
|
|
14910
14991
|
this.claudeFlags = config.claudeFlags ?? loadClaudeFlags();
|
|
14911
14992
|
this.claudeExtraArgs = config.claudeExtraArgs ?? loadClaudeExtraArgs();
|
|
14912
|
-
this.cacheDir = config.cacheDir ?? loadCacheDir() ?? (0,
|
|
14993
|
+
this.cacheDir = config.cacheDir ?? loadCacheDir() ?? (0, import_path24.join)((0, import_os14.homedir)(), ".threadbase", "cache");
|
|
14913
14994
|
this.runtimeDbPath = resolveRuntimeDbPath(config.runtimeDbPath);
|
|
14914
14995
|
this.tailSize = config.tailSize ?? loadTailSize() ?? 10;
|
|
14915
14996
|
this.directoryDebounceMs = parseDirScanDebounceEnv(process.env.THREADBASE_DIR_SCAN_DEBOUNCE_MS) ?? config.directoryScanDebounceMs ?? 1e3;
|
|
@@ -15086,7 +15167,7 @@ var StreamerServer = class {
|
|
|
15086
15167
|
temporalClient,
|
|
15087
15168
|
taskQueue: agentConfig.temporal.taskQueue
|
|
15088
15169
|
});
|
|
15089
|
-
const conversationsBaseDir = agentConfig.conversationsDir || (0,
|
|
15170
|
+
const conversationsBaseDir = agentConfig.conversationsDir || (0, import_path24.join)((0, import_path24.dirname)(this.cacheDir), "conversations");
|
|
15090
15171
|
conversationWriter = createConversationWriter({
|
|
15091
15172
|
baseDir: conversationsBaseDir
|
|
15092
15173
|
});
|
|
@@ -15338,14 +15419,14 @@ var StreamerServer = class {
|
|
|
15338
15419
|
}
|
|
15339
15420
|
this.apnsClient = new ApnsClient(creds);
|
|
15340
15421
|
const sender = new LiveActivitySender(this.apnsClient, pushRepo);
|
|
15341
|
-
const serverId = process.env.THREADBASE_INSTANCE_ID ?? (0,
|
|
15342
|
-
this.liveActivityNotifier = new LiveActivityNotifier(sender, serverId, (0,
|
|
15422
|
+
const serverId = process.env.THREADBASE_INSTANCE_ID ?? (0, import_os14.hostname)();
|
|
15423
|
+
this.liveActivityNotifier = new LiveActivityNotifier(sender, serverId, (0, import_os14.hostname)());
|
|
15343
15424
|
this.liveActivityRenewal = new LiveActivityRenewalScheduler({
|
|
15344
15425
|
repo: pushRepo,
|
|
15345
15426
|
sender,
|
|
15346
15427
|
sessionStore: this.sessionStore,
|
|
15347
15428
|
serverId,
|
|
15348
|
-
serverLabel: (0,
|
|
15429
|
+
serverLabel: (0, import_os14.hostname)()
|
|
15349
15430
|
});
|
|
15350
15431
|
this.liveActivityRenewal.start();
|
|
15351
15432
|
this.log.info("Live Activity push enabled", {
|
|
@@ -15365,7 +15446,7 @@ var StreamerServer = class {
|
|
|
15365
15446
|
*/
|
|
15366
15447
|
initWaitingInputPush(pushRepo) {
|
|
15367
15448
|
const sender = new ExpoPushSender(pushRepo, process.env.THREADBASE_EXPO_ACCESS_TOKEN);
|
|
15368
|
-
const serverId = process.env.THREADBASE_INSTANCE_ID ?? (0,
|
|
15449
|
+
const serverId = process.env.THREADBASE_INSTANCE_ID ?? (0, import_os14.hostname)();
|
|
15369
15450
|
this.waitingInputNotifier = new WaitingInputNotifier(
|
|
15370
15451
|
sender,
|
|
15371
15452
|
serverId,
|
|
@@ -15502,7 +15583,7 @@ var StreamerServer = class {
|
|
|
15502
15583
|
let sessions = null;
|
|
15503
15584
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
15504
15585
|
const transport = await connectOrSpawnHost({
|
|
15505
|
-
instanceId: process.env.THREADBASE_INSTANCE_ID ?? (0,
|
|
15586
|
+
instanceId: process.env.THREADBASE_INSTANCE_ID ?? (0, import_os14.hostname)()
|
|
15506
15587
|
});
|
|
15507
15588
|
try {
|
|
15508
15589
|
sessions = await this.ptyManager.useRemoteRunner(transport);
|
|
@@ -15579,7 +15660,7 @@ var StreamerServer = class {
|
|
|
15579
15660
|
}
|
|
15580
15661
|
try {
|
|
15581
15662
|
this.cache = ConversationCache.open(
|
|
15582
|
-
(0,
|
|
15663
|
+
(0, import_path24.join)(this.cacheDir, "cache.db"),
|
|
15583
15664
|
this.tailSize,
|
|
15584
15665
|
void 0,
|
|
15585
15666
|
{
|
|
@@ -15663,7 +15744,7 @@ var StreamerServer = class {
|
|
|
15663
15744
|
this.fileWatcher.watchDirectory(dir);
|
|
15664
15745
|
}
|
|
15665
15746
|
for (const dir of this.codexRoots) {
|
|
15666
|
-
if (!(0,
|
|
15747
|
+
if (!(0, import_fs28.existsSync)(dir)) continue;
|
|
15667
15748
|
this.fileWatcher.watchDirectory(dir);
|
|
15668
15749
|
}
|
|
15669
15750
|
} catch (err) {
|
|
@@ -15967,7 +16048,7 @@ var StreamerServer = class {
|
|
|
15967
16048
|
nonce: sealed.nonce,
|
|
15968
16049
|
ephemeralPublicKey: sealed.ephemeralPublicKey,
|
|
15969
16050
|
publicUrl: this.publicUrl,
|
|
15970
|
-
machineName: (0,
|
|
16051
|
+
machineName: (0, import_os14.hostname)(),
|
|
15971
16052
|
...device && {
|
|
15972
16053
|
deviceId: device.deviceId,
|
|
15973
16054
|
deviceToken: device.deviceToken,
|
|
@@ -16176,7 +16257,7 @@ var StreamerServer = class {
|
|
|
16176
16257
|
}
|
|
16177
16258
|
const cachedConvMeta = this.cache?.getMetaById(historyId);
|
|
16178
16259
|
const cachedPath = cachedConvMeta?.filePath ? toNativeFilePath(cachedConvMeta.filePath) : null;
|
|
16179
|
-
const cachedCodexPath = (registryProvider === CODEX_CLI_PROVIDER || cachedConvMeta?.provider === CODEX_CLI_PROVIDER) && cachedPath != null && (0,
|
|
16260
|
+
const cachedCodexPath = (registryProvider === CODEX_CLI_PROVIDER || cachedConvMeta?.provider === CODEX_CLI_PROVIDER) && cachedPath != null && (0, import_fs28.existsSync)(cachedPath) ? cachedPath : null;
|
|
16180
16261
|
const jsonlCwd = jsonlPath ? await this.conversationHandlers.readCwdFromJsonl(jsonlPath) : null;
|
|
16181
16262
|
const projectPath = jsonlCwd ?? conv?.projectPath ?? (cachedCodexPath ? cachedConvMeta?.projectPath : null);
|
|
16182
16263
|
if (!projectPath) {
|