devrage 0.5.6 → 0.5.8
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.js +145 -46
- package/dist/cli.js.map +4 -4
- package/dist/lib/adapters/codex.js +42 -0
- package/dist/lib/adapters/codex.js.map +1 -1
- package/dist/lib/adapters/cursor.d.ts.map +1 -1
- package/dist/lib/adapters/cursor.js +8 -8
- package/dist/lib/adapters/cursor.js.map +1 -1
- package/dist/lib/adapters/opencode.d.ts.map +1 -1
- package/dist/lib/adapters/opencode.js +5 -9
- package/dist/lib/adapters/opencode.js.map +1 -1
- package/dist/lib/adapters/sqlite.d.ts +15 -0
- package/dist/lib/adapters/sqlite.d.ts.map +1 -0
- package/dist/lib/adapters/sqlite.js +95 -0
- package/dist/lib/adapters/sqlite.js.map +1 -0
- package/dist/lib/adapters/t3code.d.ts.map +1 -1
- package/dist/lib/adapters/t3code.js +2 -8
- package/dist/lib/adapters/t3code.js.map +1 -1
- package/dist/lib/adapters/zed.d.ts.map +1 -1
- package/dist/lib/adapters/zed.js +6 -20
- package/dist/lib/adapters/zed.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -670,6 +670,7 @@ async function* parseCodexUsageJsonl(filePath, context) {
|
|
|
670
670
|
let previousUsageSignature = null;
|
|
671
671
|
let session = context.session;
|
|
672
672
|
let sawSessionMeta = false;
|
|
673
|
+
let forkReplayStartedAt = null;
|
|
673
674
|
for await (const line of rl) {
|
|
674
675
|
if (!line.trim()) {
|
|
675
676
|
continue;
|
|
@@ -682,6 +683,15 @@ async function* parseCodexUsageJsonl(filePath, context) {
|
|
|
682
683
|
if (metaSession && !sawSessionMeta) {
|
|
683
684
|
session = metaSession;
|
|
684
685
|
sawSessionMeta = true;
|
|
686
|
+
if (payload?.["thread_source"] === "subagent") {
|
|
687
|
+
forkReplayStartedAt = uuidV7Timestamp(metaSession) ?? timestampMilliseconds(entry["timestamp"]) ?? timestampMilliseconds(payload["timestamp"]);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
if (forkReplayStartedAt !== null) {
|
|
693
|
+
if (isLiveForkTaskStart(entry, payload, forkReplayStartedAt)) {
|
|
694
|
+
forkReplayStartedAt = null;
|
|
685
695
|
}
|
|
686
696
|
continue;
|
|
687
697
|
}
|
|
@@ -813,6 +823,35 @@ function numberValue2(value) {
|
|
|
813
823
|
function stringValue2(value) {
|
|
814
824
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
815
825
|
}
|
|
826
|
+
function isLiveForkTaskStart(entry, payload, forkStartedAt) {
|
|
827
|
+
if (entry["type"] !== "event_msg" || payload?.["type"] !== "task_started") {
|
|
828
|
+
return false;
|
|
829
|
+
}
|
|
830
|
+
const taskIdStartedAt = uuidV7Timestamp(stringValue2(payload["turn_id"]));
|
|
831
|
+
if (taskIdStartedAt !== null) {
|
|
832
|
+
return taskIdStartedAt >= forkStartedAt;
|
|
833
|
+
}
|
|
834
|
+
const taskStartedAt = timestampMilliseconds(payload["started_at"]);
|
|
835
|
+
return taskStartedAt !== null && taskStartedAt >= Math.floor(forkStartedAt / 1e3) * 1e3;
|
|
836
|
+
}
|
|
837
|
+
function uuidV7Timestamp(value) {
|
|
838
|
+
const normalized = value?.replaceAll("-", "");
|
|
839
|
+
if (!normalized || !/^[0-9a-f]{12}7/i.test(normalized)) {
|
|
840
|
+
return null;
|
|
841
|
+
}
|
|
842
|
+
const timestamp = Number.parseInt(normalized.slice(0, 12), 16);
|
|
843
|
+
return Number.isSafeInteger(timestamp) ? timestamp : null;
|
|
844
|
+
}
|
|
845
|
+
function timestampMilliseconds(value) {
|
|
846
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
847
|
+
return value >= 1e12 ? value : value * 1e3;
|
|
848
|
+
}
|
|
849
|
+
if (typeof value === "string") {
|
|
850
|
+
const timestamp = Date.parse(value);
|
|
851
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
852
|
+
}
|
|
853
|
+
return null;
|
|
854
|
+
}
|
|
816
855
|
function asRecord3(value) {
|
|
817
856
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
818
857
|
return null;
|
|
@@ -825,6 +864,97 @@ import { existsSync as existsSync2 } from "node:fs";
|
|
|
825
864
|
import { readdir as readdir5 } from "node:fs/promises";
|
|
826
865
|
import { homedir as homedir5 } from "node:os";
|
|
827
866
|
import { join as join5 } from "node:path";
|
|
867
|
+
|
|
868
|
+
// src/adapters/sqlite.ts
|
|
869
|
+
async function openReadonlySqliteDatabase(dbPath) {
|
|
870
|
+
const requestedDriver = process.env["DEVRAGE_SQLITE_DRIVER"];
|
|
871
|
+
if (requestedDriver) {
|
|
872
|
+
const loader = driverLoader(requestedDriver);
|
|
873
|
+
if (!loader) {
|
|
874
|
+
return null;
|
|
875
|
+
}
|
|
876
|
+
try {
|
|
877
|
+
return await loader(dbPath);
|
|
878
|
+
} catch {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
const loaders = isBunRuntime() ? [openWithBunSqlite, openWithNodeSqlite, openWithBetterSqlite3] : [openWithNodeSqlite, openWithBetterSqlite3];
|
|
883
|
+
for (const loader of loaders) {
|
|
884
|
+
try {
|
|
885
|
+
return await loader(dbPath);
|
|
886
|
+
} catch {
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
function driverLoader(driver) {
|
|
893
|
+
switch (driver) {
|
|
894
|
+
case "bun":
|
|
895
|
+
case "bun:sqlite":
|
|
896
|
+
return openWithBunSqlite;
|
|
897
|
+
case "node":
|
|
898
|
+
case "node:sqlite":
|
|
899
|
+
return openWithNodeSqlite;
|
|
900
|
+
case "better-sqlite3":
|
|
901
|
+
return openWithBetterSqlite3;
|
|
902
|
+
default:
|
|
903
|
+
return null;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
function isBunRuntime() {
|
|
907
|
+
return Boolean(process.versions["bun"]);
|
|
908
|
+
}
|
|
909
|
+
async function openWithBunSqlite(dbPath) {
|
|
910
|
+
const specifier = "bun:sqlite";
|
|
911
|
+
const sqlite = await import(specifier);
|
|
912
|
+
const db = new sqlite.Database(dbPath, { readonly: true, create: false });
|
|
913
|
+
return {
|
|
914
|
+
prepare(sql) {
|
|
915
|
+
const prepare = db.prepare ?? db.query;
|
|
916
|
+
return prepare.call(db, sql);
|
|
917
|
+
},
|
|
918
|
+
close() {
|
|
919
|
+
db.close();
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
async function openWithNodeSqlite(dbPath) {
|
|
924
|
+
const sqlite = await importNodeSqlite();
|
|
925
|
+
return new sqlite.DatabaseSync(dbPath, { open: true, readOnly: true, timeout: 5e3 });
|
|
926
|
+
}
|
|
927
|
+
async function openWithBetterSqlite3(dbPath) {
|
|
928
|
+
const BetterSqlite3 = await import("better-sqlite3");
|
|
929
|
+
const Ctor = BetterSqlite3.default ?? BetterSqlite3;
|
|
930
|
+
return new Ctor(dbPath, {
|
|
931
|
+
readonly: true,
|
|
932
|
+
fileMustExist: true
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
async function importNodeSqlite() {
|
|
936
|
+
const originalEmitWarning = process.emitWarning;
|
|
937
|
+
process.emitWarning = ((warning, ...args) => {
|
|
938
|
+
const message = typeof warning === "string" ? warning : warning.message;
|
|
939
|
+
const type = typeof args[0] === "string" ? args[0] : void 0;
|
|
940
|
+
if (message === "SQLite is an experimental feature and might change at any time" && type === "ExperimentalWarning") {
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
originalEmitWarning(warning, ...args);
|
|
944
|
+
});
|
|
945
|
+
try {
|
|
946
|
+
const specifier = "node:sqlite";
|
|
947
|
+
const sqlite = await import(specifier);
|
|
948
|
+
if (typeof sqlite.DatabaseSync !== "function") {
|
|
949
|
+
throw new Error("node:sqlite DatabaseSync is unavailable");
|
|
950
|
+
}
|
|
951
|
+
return sqlite;
|
|
952
|
+
} finally {
|
|
953
|
+
process.emitWarning = originalEmitWarning;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// src/adapters/cursor.ts
|
|
828
958
|
var CANDIDATE_KEY_PREFIXES = [
|
|
829
959
|
"bubbleId:",
|
|
830
960
|
"composerData:",
|
|
@@ -978,16 +1108,7 @@ async function* parseCursorUsageStore(store, options) {
|
|
|
978
1108
|
}
|
|
979
1109
|
}
|
|
980
1110
|
async function openCursorDb(dbPath) {
|
|
981
|
-
|
|
982
|
-
const BetterSqlite3 = await import("better-sqlite3");
|
|
983
|
-
const Ctor = BetterSqlite3.default ?? BetterSqlite3;
|
|
984
|
-
return new Ctor(
|
|
985
|
-
dbPath,
|
|
986
|
-
{ readonly: true }
|
|
987
|
-
);
|
|
988
|
-
} catch {
|
|
989
|
-
return null;
|
|
990
|
-
}
|
|
1111
|
+
return openReadonlySqliteDatabase(dbPath);
|
|
991
1112
|
}
|
|
992
1113
|
function readStateRows(db) {
|
|
993
1114
|
const rows = [];
|
|
@@ -1048,6 +1169,12 @@ function decodeStateValue(value) {
|
|
|
1048
1169
|
if (Buffer.isBuffer(value)) {
|
|
1049
1170
|
return value.toString("utf-8");
|
|
1050
1171
|
}
|
|
1172
|
+
if (value instanceof Uint8Array) {
|
|
1173
|
+
return Buffer.from(value).toString("utf-8");
|
|
1174
|
+
}
|
|
1175
|
+
if (ArrayBuffer.isView(value)) {
|
|
1176
|
+
return Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString("utf-8");
|
|
1177
|
+
}
|
|
1051
1178
|
return null;
|
|
1052
1179
|
}
|
|
1053
1180
|
function extractCursorMessages(root, rowKey) {
|
|
@@ -1410,17 +1537,11 @@ async function openOpencodeDb() {
|
|
|
1410
1537
|
if (!dbPath) {
|
|
1411
1538
|
return null;
|
|
1412
1539
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
return new Ctor(
|
|
1417
|
-
dbPath,
|
|
1418
|
-
{ readonly: true }
|
|
1419
|
-
);
|
|
1420
|
-
} catch {
|
|
1421
|
-
console.warn("devrage: better-sqlite3 not available, skipping OpenCode sessions");
|
|
1422
|
-
return null;
|
|
1540
|
+
const db = await openReadonlySqliteDatabase(dbPath);
|
|
1541
|
+
if (!db) {
|
|
1542
|
+
console.warn("devrage: SQLite support not available, skipping OpenCode sessions");
|
|
1423
1543
|
}
|
|
1544
|
+
return db;
|
|
1424
1545
|
}
|
|
1425
1546
|
function* queryUserMessages(db, options) {
|
|
1426
1547
|
let query = `
|
|
@@ -1763,16 +1884,7 @@ function resolveHomePath(value) {
|
|
|
1763
1884
|
return isAbsolute(value) ? value : resolve(value);
|
|
1764
1885
|
}
|
|
1765
1886
|
async function openT3Db(dbPath) {
|
|
1766
|
-
|
|
1767
|
-
const BetterSqlite3 = await import("better-sqlite3");
|
|
1768
|
-
const Ctor = BetterSqlite3.default ?? BetterSqlite3;
|
|
1769
|
-
return new Ctor(
|
|
1770
|
-
dbPath,
|
|
1771
|
-
{ readonly: true, fileMustExist: true }
|
|
1772
|
-
);
|
|
1773
|
-
} catch {
|
|
1774
|
-
return null;
|
|
1775
|
-
}
|
|
1887
|
+
return openReadonlySqliteDatabase(dbPath);
|
|
1776
1888
|
}
|
|
1777
1889
|
function* queryUserMessages2(db, location, options) {
|
|
1778
1890
|
if (!hasColumns(db, "projection_thread_messages", ["thread_id", "role", "text", "created_at"])) {
|
|
@@ -2190,21 +2302,10 @@ async function* parseAgentThreads(dbDir, _options) {
|
|
|
2190
2302
|
if (dbFiles.length === 0) {
|
|
2191
2303
|
return;
|
|
2192
2304
|
}
|
|
2193
|
-
let Database;
|
|
2194
|
-
try {
|
|
2195
|
-
const mod = await import("better-sqlite3");
|
|
2196
|
-
Database = mod.default ?? mod;
|
|
2197
|
-
} catch {
|
|
2198
|
-
return;
|
|
2199
|
-
}
|
|
2200
2305
|
for (const dbFile of dbFiles) {
|
|
2201
2306
|
const dbPath = join9(dbDir, dbFile);
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
db = new Database(dbPath, {
|
|
2205
|
-
readonly: true
|
|
2206
|
-
});
|
|
2207
|
-
} catch {
|
|
2307
|
+
const db = await openReadonlySqliteDatabase(dbPath);
|
|
2308
|
+
if (!db) {
|
|
2208
2309
|
continue;
|
|
2209
2310
|
}
|
|
2210
2311
|
try {
|
|
@@ -2214,14 +2315,12 @@ async function* parseAgentThreads(dbDir, _options) {
|
|
|
2214
2315
|
(t) => t === "messages" || t === "thread_messages" || t.includes("message")
|
|
2215
2316
|
);
|
|
2216
2317
|
if (!msgTable) {
|
|
2217
|
-
db.close();
|
|
2218
2318
|
continue;
|
|
2219
2319
|
}
|
|
2220
2320
|
const columns = db.prepare(`PRAGMA table_info("${msgTable}")`).all();
|
|
2221
2321
|
const colNames = columns.map((c2) => c2.name);
|
|
2222
2322
|
const hasRole = colNames.includes("role");
|
|
2223
2323
|
if (!hasRole) {
|
|
2224
|
-
db.close();
|
|
2225
2324
|
continue;
|
|
2226
2325
|
}
|
|
2227
2326
|
const contentCol = colNames.includes("content") ? "content" : colNames.includes("body") ? "body" : "text";
|
|
@@ -3667,7 +3766,7 @@ async function main() {
|
|
|
3667
3766
|
process.exit(0);
|
|
3668
3767
|
}
|
|
3669
3768
|
if (command === "--version") {
|
|
3670
|
-
console.log("0.5.
|
|
3769
|
+
console.log("0.5.8");
|
|
3671
3770
|
process.exit(0);
|
|
3672
3771
|
}
|
|
3673
3772
|
const parsed = parseCommand(args);
|