@runtimescope/collector 0.7.1 → 0.8.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/{chunk-VZSMLTUQ.js → chunk-BKRGXAJB.js} +182 -44
- package/dist/chunk-BKRGXAJB.js.map +1 -0
- package/dist/index.d.ts +44 -5
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/standalone.js +1 -1
- package/package.json +4 -2
- package/dist/chunk-VZSMLTUQ.js.map +0 -1
|
@@ -233,6 +233,17 @@ var EventStore = class {
|
|
|
233
233
|
return true;
|
|
234
234
|
});
|
|
235
235
|
}
|
|
236
|
+
getUIInteractions(filter = {}) {
|
|
237
|
+
const since = filter.sinceSeconds ? Date.now() - filter.sinceSeconds * 1e3 : 0;
|
|
238
|
+
return this.buffer.query((e) => {
|
|
239
|
+
if (e.eventType !== "ui") return false;
|
|
240
|
+
if (filter.sessionId && e.sessionId !== filter.sessionId) return false;
|
|
241
|
+
const ue = e;
|
|
242
|
+
if (ue.timestamp < since) return false;
|
|
243
|
+
if (filter.action && ue.action !== filter.action) return false;
|
|
244
|
+
return true;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
236
247
|
// ============================================================
|
|
237
248
|
// Recon event queries — returns the most recent event of each type
|
|
238
249
|
// ============================================================
|
|
@@ -296,41 +307,94 @@ var EventStore = class {
|
|
|
296
307
|
};
|
|
297
308
|
|
|
298
309
|
// src/sqlite-store.ts
|
|
299
|
-
import
|
|
300
|
-
|
|
310
|
+
import { renameSync, existsSync } from "fs";
|
|
311
|
+
import { createRequire } from "module";
|
|
312
|
+
var DatabaseConstructor;
|
|
313
|
+
function getDatabase() {
|
|
314
|
+
if (!DatabaseConstructor) {
|
|
315
|
+
const require2 = createRequire(import.meta.url);
|
|
316
|
+
DatabaseConstructor = require2("better-sqlite3");
|
|
317
|
+
}
|
|
318
|
+
return DatabaseConstructor;
|
|
319
|
+
}
|
|
320
|
+
var SqliteStore = class _SqliteStore {
|
|
301
321
|
db;
|
|
302
322
|
writeBuffer = [];
|
|
303
323
|
flushTimer = null;
|
|
304
324
|
batchSize;
|
|
325
|
+
dbPath;
|
|
326
|
+
static MAX_SNAPSHOTS_PER_SESSION = 50;
|
|
305
327
|
insertEventStmt;
|
|
306
328
|
insertSessionStmt;
|
|
307
329
|
updateSessionDisconnectedStmt;
|
|
308
330
|
constructor(options) {
|
|
309
|
-
this.
|
|
331
|
+
this.dbPath = options.dbPath;
|
|
310
332
|
this.batchSize = options.batchSize ?? 50;
|
|
311
|
-
|
|
312
|
-
|
|
333
|
+
this.db = this.openDatabase(options);
|
|
334
|
+
const flushInterval = options.flushIntervalMs ?? 100;
|
|
335
|
+
this.flushTimer = setInterval(() => this.flush(), flushInterval);
|
|
336
|
+
}
|
|
337
|
+
openDatabase(options) {
|
|
338
|
+
const Db = getDatabase();
|
|
339
|
+
try {
|
|
340
|
+
const db = new Db(options.dbPath);
|
|
341
|
+
if (options.walMode !== false) {
|
|
342
|
+
db.pragma("journal_mode = WAL");
|
|
343
|
+
}
|
|
344
|
+
db.pragma("synchronous = NORMAL");
|
|
345
|
+
const check = db.pragma("integrity_check");
|
|
346
|
+
if (check[0]?.integrity_check !== "ok") {
|
|
347
|
+
throw new Error("Integrity check failed");
|
|
348
|
+
}
|
|
349
|
+
this.createSchema(db);
|
|
350
|
+
this.prepareStatements(db);
|
|
351
|
+
return db;
|
|
352
|
+
} catch (err) {
|
|
353
|
+
console.error(
|
|
354
|
+
`[RuntimeScope] SQLite database corrupt or unreadable (${err.message}), recreating...`
|
|
355
|
+
);
|
|
356
|
+
try {
|
|
357
|
+
if (existsSync(options.dbPath)) {
|
|
358
|
+
const backupPath = `${options.dbPath}.corrupt.${Date.now()}`;
|
|
359
|
+
renameSync(options.dbPath, backupPath);
|
|
360
|
+
console.error(`[RuntimeScope] Renamed corrupt DB to ${backupPath}`);
|
|
361
|
+
}
|
|
362
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
363
|
+
const p = options.dbPath + suffix;
|
|
364
|
+
if (existsSync(p)) {
|
|
365
|
+
renameSync(p, `${p}.corrupt.${Date.now()}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
370
|
+
const db = new Db(options.dbPath);
|
|
371
|
+
if (options.walMode !== false) {
|
|
372
|
+
db.pragma("journal_mode = WAL");
|
|
373
|
+
}
|
|
374
|
+
db.pragma("synchronous = NORMAL");
|
|
375
|
+
this.createSchema(db);
|
|
376
|
+
this.prepareStatements(db);
|
|
377
|
+
return db;
|
|
313
378
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
this.insertEventStmt =
|
|
379
|
+
}
|
|
380
|
+
prepareStatements(db) {
|
|
381
|
+
this.insertEventStmt = db.prepare(`
|
|
317
382
|
INSERT INTO events (event_id, session_id, project, event_type, timestamp, data)
|
|
318
383
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
319
384
|
`);
|
|
320
|
-
this.insertSessionStmt =
|
|
385
|
+
this.insertSessionStmt = db.prepare(`
|
|
321
386
|
INSERT OR REPLACE INTO sessions (
|
|
322
387
|
session_id, project, app_name, connected_at, sdk_version,
|
|
323
388
|
event_count, is_connected, build_meta
|
|
324
389
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
325
390
|
`);
|
|
326
|
-
this.updateSessionDisconnectedStmt =
|
|
391
|
+
this.updateSessionDisconnectedStmt = db.prepare(`
|
|
327
392
|
UPDATE sessions SET is_connected = 0, disconnected_at = ? WHERE session_id = ?
|
|
328
393
|
`);
|
|
329
|
-
const flushInterval = options.flushIntervalMs ?? 100;
|
|
330
|
-
this.flushTimer = setInterval(() => this.flush(), flushInterval);
|
|
331
394
|
}
|
|
332
|
-
createSchema() {
|
|
333
|
-
this.db
|
|
395
|
+
createSchema(db) {
|
|
396
|
+
const d = db ?? this.db;
|
|
397
|
+
d.exec(`
|
|
334
398
|
CREATE TABLE IF NOT EXISTS events (
|
|
335
399
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
336
400
|
event_id TEXT NOT NULL UNIQUE,
|
|
@@ -374,7 +438,7 @@ var SqliteStore = class {
|
|
|
374
438
|
CREATE INDEX IF NOT EXISTS idx_snapshots_session ON session_snapshots(session_id);
|
|
375
439
|
CREATE INDEX IF NOT EXISTS idx_snapshots_project ON session_snapshots(project, created_at);
|
|
376
440
|
`);
|
|
377
|
-
this.migrateSessionMetrics();
|
|
441
|
+
this.migrateSessionMetrics(d);
|
|
378
442
|
}
|
|
379
443
|
// --- Write Operations ---
|
|
380
444
|
addEvent(event, project) {
|
|
@@ -427,6 +491,21 @@ var SqliteStore = class {
|
|
|
427
491
|
INSERT INTO session_snapshots (session_id, project, label, metrics, created_at)
|
|
428
492
|
VALUES (?, ?, ?, ?, ?)
|
|
429
493
|
`).run(sessionId, project, label ?? null, JSON.stringify(metrics), Date.now());
|
|
494
|
+
this.pruneSnapshots(sessionId);
|
|
495
|
+
}
|
|
496
|
+
/** Remove oldest snapshots for a session beyond the retention limit */
|
|
497
|
+
pruneSnapshots(sessionId) {
|
|
498
|
+
const count = this.db.prepare("SELECT COUNT(*) as cnt FROM session_snapshots WHERE session_id = ?").get(sessionId).cnt;
|
|
499
|
+
if (count > _SqliteStore.MAX_SNAPSHOTS_PER_SESSION) {
|
|
500
|
+
this.db.prepare(`
|
|
501
|
+
DELETE FROM session_snapshots WHERE id IN (
|
|
502
|
+
SELECT id FROM session_snapshots
|
|
503
|
+
WHERE session_id = ?
|
|
504
|
+
ORDER BY created_at ASC
|
|
505
|
+
LIMIT ?
|
|
506
|
+
)
|
|
507
|
+
`).run(sessionId, count - _SqliteStore.MAX_SNAPSHOTS_PER_SESSION);
|
|
508
|
+
}
|
|
430
509
|
}
|
|
431
510
|
// --- Read Operations ---
|
|
432
511
|
getEvents(filter) {
|
|
@@ -552,17 +631,17 @@ var SqliteStore = class {
|
|
|
552
631
|
return rows.map((row) => JSON.parse(row.data));
|
|
553
632
|
}
|
|
554
633
|
// --- Migration ---
|
|
555
|
-
migrateSessionMetrics() {
|
|
556
|
-
const hasOldTable =
|
|
634
|
+
migrateSessionMetrics(db) {
|
|
635
|
+
const hasOldTable = db.prepare(
|
|
557
636
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='session_metrics'"
|
|
558
637
|
).get();
|
|
559
638
|
if (hasOldTable) {
|
|
560
|
-
|
|
639
|
+
db.exec(`
|
|
561
640
|
INSERT OR IGNORE INTO session_snapshots (session_id, project, label, metrics, created_at)
|
|
562
641
|
SELECT session_id, project, 'auto-disconnect', metrics, created_at
|
|
563
642
|
FROM session_metrics
|
|
564
643
|
`);
|
|
565
|
-
|
|
644
|
+
db.exec("DROP TABLE session_metrics");
|
|
566
645
|
}
|
|
567
646
|
}
|
|
568
647
|
// --- Maintenance ---
|
|
@@ -584,14 +663,14 @@ var SqliteStore = class {
|
|
|
584
663
|
};
|
|
585
664
|
|
|
586
665
|
// src/sqlite-check.ts
|
|
587
|
-
import { createRequire } from "module";
|
|
666
|
+
import { createRequire as createRequire2 } from "module";
|
|
588
667
|
var _checked = false;
|
|
589
668
|
var _available = false;
|
|
590
669
|
function isSqliteAvailable() {
|
|
591
670
|
if (_checked) return _available;
|
|
592
671
|
_checked = true;
|
|
593
672
|
try {
|
|
594
|
-
const require2 =
|
|
673
|
+
const require2 = createRequire2(import.meta.url);
|
|
595
674
|
require2("better-sqlite3");
|
|
596
675
|
_available = true;
|
|
597
676
|
} catch {
|
|
@@ -727,6 +806,7 @@ var CollectorServer = class {
|
|
|
727
806
|
connectCallbacks = [];
|
|
728
807
|
disconnectCallbacks = [];
|
|
729
808
|
pruneTimer = null;
|
|
809
|
+
heartbeatTimer = null;
|
|
730
810
|
tlsConfig = null;
|
|
731
811
|
constructor(options = {}) {
|
|
732
812
|
this.store = new EventStore(options.bufferSize ?? 1e4);
|
|
@@ -786,6 +866,8 @@ var CollectorServer = class {
|
|
|
786
866
|
httpsServer.on("listening", () => {
|
|
787
867
|
this.wss = wss;
|
|
788
868
|
this.setupConnectionHandler(wss);
|
|
869
|
+
this.setupPersistentErrorHandler(wss);
|
|
870
|
+
this.startHeartbeat(wss);
|
|
789
871
|
console.error(`[RuntimeScope] Collector listening on wss://${host}:${port}`);
|
|
790
872
|
resolve2();
|
|
791
873
|
});
|
|
@@ -799,6 +881,8 @@ var CollectorServer = class {
|
|
|
799
881
|
wss.on("listening", () => {
|
|
800
882
|
this.wss = wss;
|
|
801
883
|
this.setupConnectionHandler(wss);
|
|
884
|
+
this.setupPersistentErrorHandler(wss);
|
|
885
|
+
this.startHeartbeat(wss);
|
|
802
886
|
console.error(`[RuntimeScope] Collector listening on ws://${host}:${port}`);
|
|
803
887
|
resolve2();
|
|
804
888
|
});
|
|
@@ -844,8 +928,33 @@ var CollectorServer = class {
|
|
|
844
928
|
}
|
|
845
929
|
return sqliteStore;
|
|
846
930
|
}
|
|
931
|
+
/** Catch runtime errors on the WSS so an unhandled error doesn't crash the process */
|
|
932
|
+
setupPersistentErrorHandler(wss) {
|
|
933
|
+
wss.on("error", (err) => {
|
|
934
|
+
console.error("[RuntimeScope] WebSocket server runtime error:", err.message);
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
/** Ping all connected clients every 15s — terminate those that don't respond */
|
|
938
|
+
startHeartbeat(wss) {
|
|
939
|
+
this.heartbeatTimer = setInterval(() => {
|
|
940
|
+
for (const ws of wss.clients) {
|
|
941
|
+
const ext = ws;
|
|
942
|
+
if (ext._rsAlive === false) {
|
|
943
|
+
ws.terminate();
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
ext._rsAlive = false;
|
|
947
|
+
ws.ping();
|
|
948
|
+
}
|
|
949
|
+
}, 15e3);
|
|
950
|
+
}
|
|
847
951
|
setupConnectionHandler(wss) {
|
|
848
952
|
wss.on("connection", (ws) => {
|
|
953
|
+
const ext = ws;
|
|
954
|
+
ext._rsAlive = true;
|
|
955
|
+
ws.on("pong", () => {
|
|
956
|
+
ext._rsAlive = true;
|
|
957
|
+
});
|
|
849
958
|
if (this.authManager?.isEnabled()) {
|
|
850
959
|
this.pendingHandshakes.add(ws);
|
|
851
960
|
const authTimeout = setTimeout(() => {
|
|
@@ -1040,10 +1149,27 @@ var CollectorServer = class {
|
|
|
1040
1149
|
});
|
|
1041
1150
|
}
|
|
1042
1151
|
stop() {
|
|
1152
|
+
if (this.heartbeatTimer) {
|
|
1153
|
+
clearInterval(this.heartbeatTimer);
|
|
1154
|
+
this.heartbeatTimer = null;
|
|
1155
|
+
}
|
|
1043
1156
|
if (this.pruneTimer) {
|
|
1044
1157
|
clearInterval(this.pruneTimer);
|
|
1045
1158
|
this.pruneTimer = null;
|
|
1046
1159
|
}
|
|
1160
|
+
if (this.wss) {
|
|
1161
|
+
for (const client of this.wss.clients) {
|
|
1162
|
+
if (client.readyState === 1) {
|
|
1163
|
+
try {
|
|
1164
|
+
client.send(JSON.stringify({
|
|
1165
|
+
type: "__server_restart",
|
|
1166
|
+
timestamp: Date.now()
|
|
1167
|
+
}));
|
|
1168
|
+
} catch {
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1047
1173
|
for (const [name, sqliteStore] of this.sqliteStores) {
|
|
1048
1174
|
try {
|
|
1049
1175
|
sqliteStore.close();
|
|
@@ -1061,7 +1187,7 @@ var CollectorServer = class {
|
|
|
1061
1187
|
};
|
|
1062
1188
|
|
|
1063
1189
|
// src/project-manager.ts
|
|
1064
|
-
import { mkdirSync, readFileSync as readFileSync2, writeFileSync, existsSync, readdirSync } from "fs";
|
|
1190
|
+
import { mkdirSync, readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, readdirSync } from "fs";
|
|
1065
1191
|
import { join } from "path";
|
|
1066
1192
|
import { homedir } from "os";
|
|
1067
1193
|
var DEFAULT_GLOBAL_CONFIG = {
|
|
@@ -1093,7 +1219,7 @@ var ProjectManager = class {
|
|
|
1093
1219
|
this.mkdirp(this.baseDir);
|
|
1094
1220
|
this.mkdirp(join(this.baseDir, "projects"));
|
|
1095
1221
|
const configPath = join(this.baseDir, "config.json");
|
|
1096
|
-
if (!
|
|
1222
|
+
if (!existsSync2(configPath)) {
|
|
1097
1223
|
this.writeJson(configPath, DEFAULT_GLOBAL_CONFIG);
|
|
1098
1224
|
}
|
|
1099
1225
|
}
|
|
@@ -1101,7 +1227,7 @@ var ProjectManager = class {
|
|
|
1101
1227
|
const projectDir = this.getProjectDir(projectName);
|
|
1102
1228
|
this.mkdirp(projectDir);
|
|
1103
1229
|
const configPath = join(projectDir, "config.json");
|
|
1104
|
-
if (!
|
|
1230
|
+
if (!existsSync2(configPath)) {
|
|
1105
1231
|
const config = {
|
|
1106
1232
|
name: projectName,
|
|
1107
1233
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1115,7 +1241,7 @@ var ProjectManager = class {
|
|
|
1115
1241
|
// --- Config ---
|
|
1116
1242
|
getGlobalConfig() {
|
|
1117
1243
|
const configPath = join(this.baseDir, "config.json");
|
|
1118
|
-
if (!
|
|
1244
|
+
if (!existsSync2(configPath)) return { ...DEFAULT_GLOBAL_CONFIG };
|
|
1119
1245
|
return { ...DEFAULT_GLOBAL_CONFIG, ...this.readJson(configPath) };
|
|
1120
1246
|
}
|
|
1121
1247
|
saveGlobalConfig(config) {
|
|
@@ -1123,7 +1249,7 @@ var ProjectManager = class {
|
|
|
1123
1249
|
}
|
|
1124
1250
|
getProjectConfig(projectName) {
|
|
1125
1251
|
const configPath = join(this.getProjectDir(projectName), "config.json");
|
|
1126
|
-
if (!
|
|
1252
|
+
if (!existsSync2(configPath)) return null;
|
|
1127
1253
|
return this.readJson(configPath);
|
|
1128
1254
|
}
|
|
1129
1255
|
saveProjectConfig(projectName, config) {
|
|
@@ -1131,12 +1257,12 @@ var ProjectManager = class {
|
|
|
1131
1257
|
}
|
|
1132
1258
|
getInfrastructureConfig(projectName) {
|
|
1133
1259
|
const jsonPath = join(this.getProjectDir(projectName), "infrastructure.json");
|
|
1134
|
-
if (
|
|
1260
|
+
if (existsSync2(jsonPath)) {
|
|
1135
1261
|
const config = this.readJson(jsonPath);
|
|
1136
1262
|
return this.resolveConfigEnvVars(config);
|
|
1137
1263
|
}
|
|
1138
1264
|
const yamlPath = join(this.getProjectDir(projectName), "infrastructure.yaml");
|
|
1139
|
-
if (
|
|
1265
|
+
if (existsSync2(yamlPath)) {
|
|
1140
1266
|
try {
|
|
1141
1267
|
const content = readFileSync2(yamlPath, "utf-8");
|
|
1142
1268
|
return this.resolveConfigEnvVars(this.parseSimpleYaml(content));
|
|
@@ -1148,17 +1274,17 @@ var ProjectManager = class {
|
|
|
1148
1274
|
}
|
|
1149
1275
|
getClaudeInstructions(projectName) {
|
|
1150
1276
|
const filePath = join(this.getProjectDir(projectName), "claude-instructions.md");
|
|
1151
|
-
if (!
|
|
1277
|
+
if (!existsSync2(filePath)) return null;
|
|
1152
1278
|
return readFileSync2(filePath, "utf-8");
|
|
1153
1279
|
}
|
|
1154
1280
|
// --- Discovery ---
|
|
1155
1281
|
listProjects() {
|
|
1156
1282
|
const projectsDir = join(this.baseDir, "projects");
|
|
1157
|
-
if (!
|
|
1283
|
+
if (!existsSync2(projectsDir)) return [];
|
|
1158
1284
|
return readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
1159
1285
|
}
|
|
1160
1286
|
projectExists(projectName) {
|
|
1161
|
-
return
|
|
1287
|
+
return existsSync2(this.getProjectDir(projectName));
|
|
1162
1288
|
}
|
|
1163
1289
|
// --- Environment variable resolution ---
|
|
1164
1290
|
resolveEnvVars(value) {
|
|
@@ -1168,7 +1294,7 @@ var ProjectManager = class {
|
|
|
1168
1294
|
}
|
|
1169
1295
|
// --- Private helpers ---
|
|
1170
1296
|
mkdirp(dir) {
|
|
1171
|
-
if (!
|
|
1297
|
+
if (!existsSync2(dir)) {
|
|
1172
1298
|
mkdirSync(dir, { recursive: true });
|
|
1173
1299
|
}
|
|
1174
1300
|
}
|
|
@@ -1508,14 +1634,14 @@ var SessionManager = class {
|
|
|
1508
1634
|
// src/http-server.ts
|
|
1509
1635
|
import { createServer } from "http";
|
|
1510
1636
|
import { createServer as createHttpsServer2 } from "https";
|
|
1511
|
-
import { readFileSync as readFileSync3, existsSync as
|
|
1637
|
+
import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
|
|
1512
1638
|
import { resolve, dirname } from "path";
|
|
1513
1639
|
import { fileURLToPath } from "url";
|
|
1514
1640
|
import { WebSocketServer as WebSocketServer2 } from "ws";
|
|
1515
1641
|
|
|
1516
1642
|
// src/pm/pm-routes.ts
|
|
1517
1643
|
import { readdir, readFile, writeFile, unlink, mkdir } from "fs/promises";
|
|
1518
|
-
import { existsSync as
|
|
1644
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1519
1645
|
import { join as join2 } from "path";
|
|
1520
1646
|
import { homedir as homedir2 } from "os";
|
|
1521
1647
|
import { spawn, execSync, execFileSync } from "child_process";
|
|
@@ -2450,7 +2576,7 @@ function parseGitStatus(porcelain) {
|
|
|
2450
2576
|
}
|
|
2451
2577
|
async function readRuleFile(filePath) {
|
|
2452
2578
|
try {
|
|
2453
|
-
if (
|
|
2579
|
+
if (existsSync3(filePath)) {
|
|
2454
2580
|
const content = await readFile(filePath, "utf-8");
|
|
2455
2581
|
return { path: filePath, content, exists: true };
|
|
2456
2582
|
}
|
|
@@ -2653,6 +2779,15 @@ var HttpServer = class {
|
|
|
2653
2779
|
});
|
|
2654
2780
|
this.json(res, { data: events, count: events.length });
|
|
2655
2781
|
});
|
|
2782
|
+
this.routes.set("GET /api/events/ui", (_req, res, params) => {
|
|
2783
|
+
const action = params.get("action");
|
|
2784
|
+
const events = this.store.getUIInteractions({
|
|
2785
|
+
action: action ?? void 0,
|
|
2786
|
+
sinceSeconds: numParam(params, "since_seconds"),
|
|
2787
|
+
sessionId: params.get("session_id") ?? void 0
|
|
2788
|
+
});
|
|
2789
|
+
this.json(res, { data: events, count: events.length });
|
|
2790
|
+
});
|
|
2656
2791
|
this.routes.set("DELETE /api/events", (_req, res) => {
|
|
2657
2792
|
const result = this.store.clear();
|
|
2658
2793
|
this.json(res, result);
|
|
@@ -2700,6 +2835,9 @@ var HttpServer = class {
|
|
|
2700
2835
|
"dom_snapshot",
|
|
2701
2836
|
"performance",
|
|
2702
2837
|
"database",
|
|
2838
|
+
"custom",
|
|
2839
|
+
"navigation",
|
|
2840
|
+
"ui",
|
|
2703
2841
|
"recon_metadata",
|
|
2704
2842
|
"recon_design_tokens",
|
|
2705
2843
|
"recon_fonts",
|
|
@@ -2745,7 +2883,7 @@ var HttpServer = class {
|
|
|
2745
2883
|
// npm installed
|
|
2746
2884
|
];
|
|
2747
2885
|
for (const p of candidates) {
|
|
2748
|
-
if (
|
|
2886
|
+
if (existsSync4(p)) {
|
|
2749
2887
|
this.sdkBundlePath = p;
|
|
2750
2888
|
return p;
|
|
2751
2889
|
}
|
|
@@ -3018,11 +3156,11 @@ function numParam(params, key) {
|
|
|
3018
3156
|
}
|
|
3019
3157
|
|
|
3020
3158
|
// src/pm/pm-store.ts
|
|
3021
|
-
import
|
|
3159
|
+
import Database from "better-sqlite3";
|
|
3022
3160
|
var PmStore = class {
|
|
3023
3161
|
db;
|
|
3024
3162
|
constructor(options) {
|
|
3025
|
-
this.db = new
|
|
3163
|
+
this.db = new Database(options.dbPath);
|
|
3026
3164
|
if (options.walMode !== false) {
|
|
3027
3165
|
this.db.pragma("journal_mode = WAL");
|
|
3028
3166
|
}
|
|
@@ -4101,7 +4239,7 @@ async function parseSessionJsonl(jsonlPath, sessionId, projectId) {
|
|
|
4101
4239
|
// src/pm/project-discovery.ts
|
|
4102
4240
|
import { readdir as readdir2, readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
4103
4241
|
import { join as join3, basename as basename2 } from "path";
|
|
4104
|
-
import { existsSync as
|
|
4242
|
+
import { existsSync as existsSync5 } from "fs";
|
|
4105
4243
|
import { homedir as homedir3 } from "os";
|
|
4106
4244
|
var LOG_PREFIX = "[RuntimeScope PM]";
|
|
4107
4245
|
async function detectSdkInstalled(projectPath) {
|
|
@@ -4168,7 +4306,7 @@ function slugifyPath(fsPath) {
|
|
|
4168
4306
|
}
|
|
4169
4307
|
function decodeClaudeKey(key) {
|
|
4170
4308
|
const naive = "/" + key.slice(1).replace(/-/g, "/");
|
|
4171
|
-
if (
|
|
4309
|
+
if (existsSync5(naive)) return naive;
|
|
4172
4310
|
const parts = key.slice(1).split("-");
|
|
4173
4311
|
return resolvePathSegments(parts);
|
|
4174
4312
|
}
|
|
@@ -4176,16 +4314,16 @@ function resolvePathSegments(parts) {
|
|
|
4176
4314
|
if (parts.length === 0) return null;
|
|
4177
4315
|
function tryResolve(prefix, remaining) {
|
|
4178
4316
|
if (remaining.length === 0) {
|
|
4179
|
-
return
|
|
4317
|
+
return existsSync5(prefix) ? prefix : null;
|
|
4180
4318
|
}
|
|
4181
4319
|
for (let count = remaining.length; count >= 1; count--) {
|
|
4182
4320
|
const segment = remaining.slice(0, count).join("-");
|
|
4183
4321
|
const candidate = join3(prefix, segment);
|
|
4184
4322
|
if (count === remaining.length) {
|
|
4185
|
-
if (
|
|
4323
|
+
if (existsSync5(candidate)) return candidate;
|
|
4186
4324
|
} else {
|
|
4187
4325
|
try {
|
|
4188
|
-
if (
|
|
4326
|
+
if (existsSync5(candidate)) {
|
|
4189
4327
|
const result = tryResolve(candidate, remaining.slice(count));
|
|
4190
4328
|
if (result) return result;
|
|
4191
4329
|
}
|
|
@@ -4679,4 +4817,4 @@ export {
|
|
|
4679
4817
|
parseSessionJsonl,
|
|
4680
4818
|
ProjectDiscovery
|
|
4681
4819
|
};
|
|
4682
|
-
//# sourceMappingURL=chunk-
|
|
4820
|
+
//# sourceMappingURL=chunk-BKRGXAJB.js.map
|