@yhong91/vibetime 0.1.17 → 0.1.19
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/bin/vibetime.mjs +611 -277
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -158,11 +158,11 @@ var init_fs = __esm({
|
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
// src/cli.ts
|
|
161
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
161
|
+
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
162
162
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
163
|
-
import { mkdir as mkdir5, rename as rename2, rm, stat as
|
|
163
|
+
import { mkdir as mkdir5, open, rename as rename2, rm, stat as stat12, writeFile as writeFile4 } from "node:fs/promises";
|
|
164
164
|
import os9 from "node:os";
|
|
165
|
-
import
|
|
165
|
+
import path21 from "node:path";
|
|
166
166
|
import { fileURLToPath } from "node:url";
|
|
167
167
|
|
|
168
168
|
// ../shared/src/index.ts
|
|
@@ -296,6 +296,12 @@ function validateMetricBag(value, errors, prefix) {
|
|
|
296
296
|
}
|
|
297
297
|
for (const key of Object.keys(value)) {
|
|
298
298
|
const metric = value[key];
|
|
299
|
+
if (key === "reasoningEffort") {
|
|
300
|
+
if (metric !== void 0 && typeof metric !== "string") {
|
|
301
|
+
errors.push(`${prefix}.${key} must be a string`);
|
|
302
|
+
}
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
299
305
|
if (metric !== void 0 && (typeof metric !== "number" || !Number.isFinite(metric))) {
|
|
300
306
|
errors.push(`${prefix}.${key} must be a finite number`);
|
|
301
307
|
}
|
|
@@ -978,10 +984,10 @@ var cac = (name = "") => new CAC(name);
|
|
|
978
984
|
|
|
979
985
|
// src/adapters/agy.ts
|
|
980
986
|
import { exec } from "node:child_process";
|
|
981
|
-
import {
|
|
987
|
+
import { mkdir as mkdir2, readFile as readFile2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
982
988
|
import * as https from "node:https";
|
|
983
989
|
import * as os from "node:os";
|
|
984
|
-
import
|
|
990
|
+
import path5 from "node:path";
|
|
985
991
|
import { promisify } from "node:util";
|
|
986
992
|
|
|
987
993
|
// src/lib/activity.ts
|
|
@@ -1196,7 +1202,7 @@ function countTextLines(text) {
|
|
|
1196
1202
|
}
|
|
1197
1203
|
|
|
1198
1204
|
// src/lib/constants.ts
|
|
1199
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
1205
|
+
var PACKAGE_VERSION = true ? "0.1.19" : "0.1.1";
|
|
1200
1206
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
1201
1207
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
1202
1208
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -1433,6 +1439,254 @@ var SessionParserState = class {
|
|
|
1433
1439
|
}
|
|
1434
1440
|
};
|
|
1435
1441
|
|
|
1442
|
+
// src/adapters/agy-legacy-db.ts
|
|
1443
|
+
import { spawn } from "node:child_process";
|
|
1444
|
+
import { stat as stat2 } from "node:fs/promises";
|
|
1445
|
+
import path4 from "node:path";
|
|
1446
|
+
function readVarint(buffer, offset) {
|
|
1447
|
+
let value = 0n;
|
|
1448
|
+
let shift = 0n;
|
|
1449
|
+
let cursor = offset;
|
|
1450
|
+
while (cursor < buffer.length && shift <= 63n) {
|
|
1451
|
+
const byte = buffer[cursor++];
|
|
1452
|
+
value |= BigInt(byte & 127) << shift;
|
|
1453
|
+
if ((byte & 128) === 0) {
|
|
1454
|
+
return { value, offset: cursor };
|
|
1455
|
+
}
|
|
1456
|
+
shift += 7n;
|
|
1457
|
+
}
|
|
1458
|
+
throw new TypeError("invalid protobuf varint");
|
|
1459
|
+
}
|
|
1460
|
+
function decodeFields(buffer) {
|
|
1461
|
+
const fields = [];
|
|
1462
|
+
let offset = 0;
|
|
1463
|
+
while (offset < buffer.length) {
|
|
1464
|
+
const key = readVarint(buffer, offset);
|
|
1465
|
+
offset = key.offset;
|
|
1466
|
+
const keyNumber = Number(key.value);
|
|
1467
|
+
if (!Number.isSafeInteger(keyNumber)) {
|
|
1468
|
+
throw new TypeError("protobuf key exceeds safe integer range");
|
|
1469
|
+
}
|
|
1470
|
+
const field = keyNumber >>> 3;
|
|
1471
|
+
const wire = keyNumber & 7;
|
|
1472
|
+
if (field === 0) {
|
|
1473
|
+
throw new Error("invalid protobuf field");
|
|
1474
|
+
}
|
|
1475
|
+
switch (wire) {
|
|
1476
|
+
case 0: {
|
|
1477
|
+
const decoded = readVarint(buffer, offset);
|
|
1478
|
+
offset = decoded.offset;
|
|
1479
|
+
fields.push({ field, wire, value: decoded.value });
|
|
1480
|
+
break;
|
|
1481
|
+
}
|
|
1482
|
+
case 1: {
|
|
1483
|
+
if (offset + 8 > buffer.length) {
|
|
1484
|
+
throw new TypeError("truncated protobuf fixed64");
|
|
1485
|
+
}
|
|
1486
|
+
fields.push({ field, wire, value: buffer.subarray(offset, offset + 8) });
|
|
1487
|
+
offset += 8;
|
|
1488
|
+
break;
|
|
1489
|
+
}
|
|
1490
|
+
case 2: {
|
|
1491
|
+
const decoded = readVarint(buffer, offset);
|
|
1492
|
+
offset = decoded.offset;
|
|
1493
|
+
const length = Number(decoded.value);
|
|
1494
|
+
if (!Number.isSafeInteger(length)) {
|
|
1495
|
+
throw new TypeError("protobuf byte length exceeds safe integer range");
|
|
1496
|
+
}
|
|
1497
|
+
const end = offset + length;
|
|
1498
|
+
if (end > buffer.length) {
|
|
1499
|
+
throw new TypeError("truncated protobuf bytes");
|
|
1500
|
+
}
|
|
1501
|
+
fields.push({ field, wire, value: buffer.subarray(offset, end) });
|
|
1502
|
+
offset = end;
|
|
1503
|
+
break;
|
|
1504
|
+
}
|
|
1505
|
+
case 5: {
|
|
1506
|
+
if (offset + 4 > buffer.length) {
|
|
1507
|
+
throw new TypeError("truncated protobuf fixed32");
|
|
1508
|
+
}
|
|
1509
|
+
fields.push({ field, wire, value: buffer.subarray(offset, offset + 4) });
|
|
1510
|
+
offset += 4;
|
|
1511
|
+
break;
|
|
1512
|
+
}
|
|
1513
|
+
default: {
|
|
1514
|
+
throw new TypeError(`unsupported protobuf wire type ${wire}`);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
return fields;
|
|
1519
|
+
}
|
|
1520
|
+
function bytesField(fields, field) {
|
|
1521
|
+
const value = fields.find((item) => item.field === field && item.wire === 2)?.value;
|
|
1522
|
+
return value instanceof Uint8Array ? value : void 0;
|
|
1523
|
+
}
|
|
1524
|
+
function numberField2(fields, field) {
|
|
1525
|
+
const value = fields.find((item) => item.field === field && item.wire === 0)?.value;
|
|
1526
|
+
if (typeof value !== "bigint") {
|
|
1527
|
+
return void 0;
|
|
1528
|
+
}
|
|
1529
|
+
const number = Number(value);
|
|
1530
|
+
return Number.isSafeInteger(number) ? number : void 0;
|
|
1531
|
+
}
|
|
1532
|
+
function stringField2(fields, field) {
|
|
1533
|
+
const value = bytesField(fields, field);
|
|
1534
|
+
if (!value) {
|
|
1535
|
+
return void 0;
|
|
1536
|
+
}
|
|
1537
|
+
return new TextDecoder().decode(value);
|
|
1538
|
+
}
|
|
1539
|
+
function decodePackedVarints(buffer) {
|
|
1540
|
+
if (!buffer) {
|
|
1541
|
+
return [];
|
|
1542
|
+
}
|
|
1543
|
+
const values = [];
|
|
1544
|
+
let offset = 0;
|
|
1545
|
+
while (offset < buffer.length) {
|
|
1546
|
+
const decoded = readVarint(buffer, offset);
|
|
1547
|
+
const value = Number(decoded.value);
|
|
1548
|
+
if (!Number.isSafeInteger(value)) {
|
|
1549
|
+
throw new TypeError("packed protobuf varint exceeds safe integer range");
|
|
1550
|
+
}
|
|
1551
|
+
values.push(value);
|
|
1552
|
+
offset = decoded.offset;
|
|
1553
|
+
}
|
|
1554
|
+
return values;
|
|
1555
|
+
}
|
|
1556
|
+
function decodeTimestamp(buffer) {
|
|
1557
|
+
if (!buffer) {
|
|
1558
|
+
return void 0;
|
|
1559
|
+
}
|
|
1560
|
+
const fields = decodeFields(buffer);
|
|
1561
|
+
const seconds = numberField2(fields, 1);
|
|
1562
|
+
if (seconds === void 0) {
|
|
1563
|
+
return void 0;
|
|
1564
|
+
}
|
|
1565
|
+
const nanos = numberField2(fields, 2) ?? 0;
|
|
1566
|
+
const date = new Date(seconds * 1e3 + Math.floor(nanos / 1e6));
|
|
1567
|
+
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
1568
|
+
}
|
|
1569
|
+
function decodeLegacyAgyGeneratorMetadata(data) {
|
|
1570
|
+
try {
|
|
1571
|
+
const fields = decodeFields(data);
|
|
1572
|
+
const stepIndices = decodePackedVarints(bytesField(fields, 2));
|
|
1573
|
+
const chatModelBytes = bytesField(fields, 1);
|
|
1574
|
+
if (stepIndices.length === 0 || !chatModelBytes) {
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
const chatModelFields = decodeFields(chatModelBytes);
|
|
1578
|
+
const usageBytes = bytesField(chatModelFields, 4);
|
|
1579
|
+
if (!usageBytes) {
|
|
1580
|
+
return null;
|
|
1581
|
+
}
|
|
1582
|
+
const usageFields = decodeFields(usageBytes);
|
|
1583
|
+
const inputTokens = numberField2(usageFields, 2);
|
|
1584
|
+
const outputTokens = numberField2(usageFields, 3);
|
|
1585
|
+
if (inputTokens === void 0 || outputTokens === void 0) {
|
|
1586
|
+
return null;
|
|
1587
|
+
}
|
|
1588
|
+
const cacheReadTokens = numberField2(usageFields, 5);
|
|
1589
|
+
const thinkingOutputTokens = numberField2(usageFields, 9);
|
|
1590
|
+
const createdAt = decodeTimestamp(bytesField(
|
|
1591
|
+
decodeFields(bytesField(chatModelFields, 9) ?? new Uint8Array()),
|
|
1592
|
+
4
|
|
1593
|
+
));
|
|
1594
|
+
const modelDisplayName = stringField2(chatModelFields, 21);
|
|
1595
|
+
const responseModel = stringField2(chatModelFields, 19);
|
|
1596
|
+
return {
|
|
1597
|
+
stepIndices,
|
|
1598
|
+
chatModel: {
|
|
1599
|
+
usage: {
|
|
1600
|
+
inputTokens: String(inputTokens),
|
|
1601
|
+
outputTokens: String(outputTokens),
|
|
1602
|
+
...cacheReadTokens === void 0 ? {} : { cacheReadTokens: String(cacheReadTokens) },
|
|
1603
|
+
...thinkingOutputTokens === void 0 ? {} : { thinkingOutputTokens: String(thinkingOutputTokens) }
|
|
1604
|
+
},
|
|
1605
|
+
...modelDisplayName ? { modelDisplayName } : {},
|
|
1606
|
+
...responseModel ? { responseModel } : {},
|
|
1607
|
+
...createdAt ? { chatStartMetadata: { createdAt } } : {}
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
} catch {
|
|
1611
|
+
return null;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
async function readRowsWithNodeSqlite(dbPath) {
|
|
1615
|
+
try {
|
|
1616
|
+
const sqlite = await import("node:sqlite");
|
|
1617
|
+
const db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
|
|
1618
|
+
try {
|
|
1619
|
+
return db.prepare("SELECT data FROM gen_metadata ORDER BY idx").all().map(
|
|
1620
|
+
(row) => ({ data: row.data })
|
|
1621
|
+
);
|
|
1622
|
+
} finally {
|
|
1623
|
+
db.close();
|
|
1624
|
+
}
|
|
1625
|
+
} catch {
|
|
1626
|
+
return null;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
async function readRowsWithSqliteCli(dbPath) {
|
|
1630
|
+
return new Promise((resolve) => {
|
|
1631
|
+
const child = spawn("sqlite3", [
|
|
1632
|
+
"-readonly",
|
|
1633
|
+
dbPath,
|
|
1634
|
+
"SELECT hex(data) FROM gen_metadata ORDER BY idx;"
|
|
1635
|
+
], {
|
|
1636
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1637
|
+
});
|
|
1638
|
+
const rows = [];
|
|
1639
|
+
let pending = "";
|
|
1640
|
+
let failed = false;
|
|
1641
|
+
child.stdout.setEncoding("utf8");
|
|
1642
|
+
child.stdout.on("data", (chunk) => {
|
|
1643
|
+
pending += chunk;
|
|
1644
|
+
let newline = pending.indexOf("\n");
|
|
1645
|
+
while (newline >= 0) {
|
|
1646
|
+
const line = pending.slice(0, newline).trim();
|
|
1647
|
+
pending = pending.slice(newline + 1);
|
|
1648
|
+
if (line) {
|
|
1649
|
+
try {
|
|
1650
|
+
rows.push({ data: Buffer.from(line, "hex") });
|
|
1651
|
+
} catch {
|
|
1652
|
+
failed = true;
|
|
1653
|
+
child.kill();
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
newline = pending.indexOf("\n");
|
|
1658
|
+
}
|
|
1659
|
+
});
|
|
1660
|
+
child.on("error", () => resolve(null));
|
|
1661
|
+
child.on("close", (code) => {
|
|
1662
|
+
if (!failed && code === 0) {
|
|
1663
|
+
const line = pending.trim();
|
|
1664
|
+
if (line) {
|
|
1665
|
+
rows.push({ data: Buffer.from(line, "hex") });
|
|
1666
|
+
}
|
|
1667
|
+
resolve(rows);
|
|
1668
|
+
} else {
|
|
1669
|
+
resolve(null);
|
|
1670
|
+
}
|
|
1671
|
+
});
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
async function readLegacyAgyGeneratorMetadata(transcriptPath, sessionId) {
|
|
1675
|
+
const antigravityCliDir = path4.resolve(path4.dirname(transcriptPath), "../../../..");
|
|
1676
|
+
const dbPath = path4.join(antigravityCliDir, "conversations", `${sessionId}.db`);
|
|
1677
|
+
try {
|
|
1678
|
+
await stat2(dbPath);
|
|
1679
|
+
} catch {
|
|
1680
|
+
return null;
|
|
1681
|
+
}
|
|
1682
|
+
const rows = await readRowsWithNodeSqlite(dbPath) ?? await readRowsWithSqliteCli(dbPath);
|
|
1683
|
+
if (!rows || rows.length === 0) {
|
|
1684
|
+
return null;
|
|
1685
|
+
}
|
|
1686
|
+
const metadata = rows.map((row) => decodeLegacyAgyGeneratorMetadata(row.data)).filter((item) => item !== null);
|
|
1687
|
+
return metadata.length > 0 ? metadata : null;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1436
1690
|
// src/adapters/agy.ts
|
|
1437
1691
|
var execAsync = promisify(exec);
|
|
1438
1692
|
var cachedRpcConnections = null;
|
|
@@ -1652,7 +1906,7 @@ function detectModel(content, currentModel) {
|
|
|
1652
1906
|
return currentModel;
|
|
1653
1907
|
}
|
|
1654
1908
|
function resolveModelName(text) {
|
|
1655
|
-
const cleaned = text.
|
|
1909
|
+
const cleaned = text.replaceAll(/\s*\([^)]*\)\s*/g, " ").trim();
|
|
1656
1910
|
if (cleaned.includes("Claude Opus 4.7") || cleaned.includes("claude-opus-4.7")) {
|
|
1657
1911
|
return "claude-opus-4.7";
|
|
1658
1912
|
}
|
|
@@ -1721,11 +1975,11 @@ function usageMetadataFromGenerator(item) {
|
|
|
1721
1975
|
};
|
|
1722
1976
|
}
|
|
1723
1977
|
async function readAgyModelSetting(filePath) {
|
|
1724
|
-
const settingsPath =
|
|
1978
|
+
const settingsPath = path5.resolve(path5.dirname(filePath), "../../../..", "settings.json");
|
|
1725
1979
|
try {
|
|
1726
1980
|
const [text, info] = await Promise.all([
|
|
1727
1981
|
readFile2(settingsPath, "utf8"),
|
|
1728
|
-
|
|
1982
|
+
stat3(settingsPath)
|
|
1729
1983
|
]);
|
|
1730
1984
|
const configured = JSON.parse(text)?.model;
|
|
1731
1985
|
const rawModel = typeof configured === "string" ? configured : null;
|
|
@@ -1748,16 +2002,16 @@ function extractProjectContext(rawLines) {
|
|
|
1748
2002
|
if (args.DirectoryPath) {
|
|
1749
2003
|
candidate = normalizePath(args.DirectoryPath);
|
|
1750
2004
|
} else if (args.AbsolutePath) {
|
|
1751
|
-
candidate =
|
|
2005
|
+
candidate = path5.dirname(normalizePath(args.AbsolutePath));
|
|
1752
2006
|
} else if (args.SearchPath) {
|
|
1753
2007
|
candidate = normalizePath(args.SearchPath);
|
|
1754
2008
|
} else if (args.TargetFile) {
|
|
1755
|
-
candidate =
|
|
2009
|
+
candidate = path5.dirname(normalizePath(args.TargetFile));
|
|
1756
2010
|
} else if (args.Cwd) {
|
|
1757
2011
|
candidate = normalizePath(args.Cwd);
|
|
1758
2012
|
}
|
|
1759
2013
|
if (candidate) {
|
|
1760
|
-
const norm = candidate.
|
|
2014
|
+
const norm = candidate.replaceAll("\\", "/").toLowerCase();
|
|
1761
2015
|
const isTemp = norm.startsWith("/var/") || norm.startsWith("/private/var/") || norm.startsWith("/tmp/") || norm.startsWith("/private/tmp/") || norm.includes("/tmp.");
|
|
1762
2016
|
if (isTemp) {
|
|
1763
2017
|
if (!fallbackCwd) {
|
|
@@ -1780,7 +2034,7 @@ function extractProjectContext(rawLines) {
|
|
|
1780
2034
|
}
|
|
1781
2035
|
if (cwd) {
|
|
1782
2036
|
const match = cwd.match(/[/\\]projects[/\\]([^/\\]+)/i);
|
|
1783
|
-
project = match && match[1] ? match[1] :
|
|
2037
|
+
project = match && match[1] ? match[1] : path5.basename(cwd);
|
|
1784
2038
|
}
|
|
1785
2039
|
return { cwd, project };
|
|
1786
2040
|
}
|
|
@@ -1792,7 +2046,7 @@ function normalizePath(p) {
|
|
|
1792
2046
|
if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
1793
2047
|
cleaned = cleaned.slice(1, -1);
|
|
1794
2048
|
}
|
|
1795
|
-
return
|
|
2049
|
+
return path5.normalize(cleaned);
|
|
1796
2050
|
}
|
|
1797
2051
|
async function parseAgySessionFile(filePath, options) {
|
|
1798
2052
|
const text = await readFile2(filePath, "utf8");
|
|
@@ -1811,8 +2065,8 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
1811
2065
|
const sessionId = getSessionId(filePath);
|
|
1812
2066
|
const modelSetting = await readAgyModelSetting(filePath);
|
|
1813
2067
|
let generatorMetadata = options?.mockTrajectoryMetadata || await getTrajectoryGeneratorMetadata(sessionId).catch(() => null);
|
|
1814
|
-
const cacheDir =
|
|
1815
|
-
const cacheFile =
|
|
2068
|
+
const cacheDir = path5.join(path5.dirname(path5.dirname(filePath)), "cache");
|
|
2069
|
+
const cacheFile = path5.join(cacheDir, "trajectory_metadata.json");
|
|
1816
2070
|
if (generatorMetadata) {
|
|
1817
2071
|
try {
|
|
1818
2072
|
await mkdir2(cacheDir, { recursive: true });
|
|
@@ -1828,6 +2082,16 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
1828
2082
|
} catch {
|
|
1829
2083
|
}
|
|
1830
2084
|
}
|
|
2085
|
+
if (!generatorMetadata) {
|
|
2086
|
+
generatorMetadata = await readLegacyAgyGeneratorMetadata(filePath, sessionId);
|
|
2087
|
+
if (generatorMetadata) {
|
|
2088
|
+
try {
|
|
2089
|
+
await mkdir2(cacheDir, { recursive: true });
|
|
2090
|
+
await writeFile2(cacheFile, JSON.stringify(generatorMetadata, null, 2), "utf8");
|
|
2091
|
+
} catch {
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
1831
2095
|
const usageMap = /* @__PURE__ */ new Map();
|
|
1832
2096
|
const usageEntries = [];
|
|
1833
2097
|
const matchedUsageEntries = /* @__PURE__ */ new Set();
|
|
@@ -1932,7 +2196,6 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
1932
2196
|
})
|
|
1933
2197
|
}), lineNumber, raw.type);
|
|
1934
2198
|
} else if (raw.type === "PLANNER_RESPONSE") {
|
|
1935
|
-
const content = stringField(raw, "content") || "";
|
|
1936
2199
|
const usageMetadata = usageMap.get(raw.step_index);
|
|
1937
2200
|
if (usageMetadata) {
|
|
1938
2201
|
matchedUsageEntries.add(usageMetadata);
|
|
@@ -2144,27 +2407,27 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
2144
2407
|
function agyDataDirs(home, env) {
|
|
2145
2408
|
const override = env?.ANTIGRAVITY_DATA_DIR || env?.AGY_DATA_DIR;
|
|
2146
2409
|
if (override && override.trim()) {
|
|
2147
|
-
return override.split(",").map((entry) => entry.trim()).filter(Boolean).map((entry) =>
|
|
2410
|
+
return override.split(",").map((entry) => entry.trim()).filter(Boolean).map((entry) => path5.resolve(entry));
|
|
2148
2411
|
}
|
|
2149
|
-
return [
|
|
2412
|
+
return [path5.join(home, ".gemini", "antigravity-cli", "brain")];
|
|
2150
2413
|
}
|
|
2151
2414
|
async function agyBackfillFiles(sourceRoot, home, env) {
|
|
2152
|
-
const roots = sourceRoot ? [
|
|
2415
|
+
const roots = sourceRoot ? [path5.resolve(sourceRoot)] : agyDataDirs(home, env);
|
|
2153
2416
|
const fileLists = await Promise.all(roots.map((root) => listFilesByExtensions(root, [".jsonl"])));
|
|
2154
2417
|
const files = fileLists.flat().filter((f) => f.endsWith("transcript.jsonl")).sort();
|
|
2155
2418
|
return Promise.all(files.map(async (filePath) => {
|
|
2156
|
-
const info = await
|
|
2419
|
+
const info = await stat3(filePath);
|
|
2157
2420
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
2158
2421
|
}));
|
|
2159
2422
|
}
|
|
2160
|
-
|
|
2423
|
+
function agyHandler(msg) {
|
|
2161
2424
|
return {
|
|
2162
2425
|
type: "command",
|
|
2163
2426
|
command: "vibetime hook --agent agy",
|
|
2164
2427
|
timeout: 10,
|
|
2165
2428
|
statusMessage: msg
|
|
2166
2429
|
};
|
|
2167
|
-
}
|
|
2430
|
+
}
|
|
2168
2431
|
function hookConfig() {
|
|
2169
2432
|
const anyTool = [{ matcher: "", hooks: [agyHandler("Reporting tool activity")] }];
|
|
2170
2433
|
const lifecycle = (msg) => [{ matcher: "", hooks: [agyHandler(msg)] }];
|
|
@@ -2229,18 +2492,18 @@ function createAgyAdapter() {
|
|
|
2229
2492
|
return agyDataDirs(home, env)[0];
|
|
2230
2493
|
},
|
|
2231
2494
|
installedPath(home, env) {
|
|
2232
|
-
return
|
|
2495
|
+
return path5.join(path5.dirname(agyDataDirs(home, env)[0]), "hooks.json");
|
|
2233
2496
|
},
|
|
2234
2497
|
async isInstalled(home, env) {
|
|
2235
|
-
const base =
|
|
2236
|
-
const settingsPath =
|
|
2237
|
-
const hooksPath =
|
|
2498
|
+
const base = path5.dirname(agyDataDirs(home, env)[0]);
|
|
2499
|
+
const settingsPath = path5.join(base, "settings.json");
|
|
2500
|
+
const hooksPath = path5.join(base, "hooks.json");
|
|
2238
2501
|
return await checkEnableJsonHooks(settingsPath) && await isAgyHooksInstalled(hooksPath, "vibetime hook --agent agy");
|
|
2239
2502
|
},
|
|
2240
2503
|
installEntries(home, env) {
|
|
2241
|
-
const base =
|
|
2242
|
-
const settingsPath =
|
|
2243
|
-
const hooksPath =
|
|
2504
|
+
const base = path5.dirname(agyDataDirs(home, env)[0]);
|
|
2505
|
+
const settingsPath = path5.join(base, "settings.json");
|
|
2506
|
+
const hooksPath = path5.join(base, "hooks.json");
|
|
2244
2507
|
return [
|
|
2245
2508
|
{
|
|
2246
2509
|
kind: "hooks-json",
|
|
@@ -2262,12 +2525,12 @@ function createAgyAdapter() {
|
|
|
2262
2525
|
}
|
|
2263
2526
|
|
|
2264
2527
|
// src/adapters/claude-code.ts
|
|
2265
|
-
import { readdir as readdir2, readFile as readFile3, stat as
|
|
2528
|
+
import { readdir as readdir2, readFile as readFile3, stat as stat4 } from "node:fs/promises";
|
|
2266
2529
|
import os2 from "node:os";
|
|
2267
|
-
import
|
|
2530
|
+
import path7 from "node:path";
|
|
2268
2531
|
|
|
2269
2532
|
// src/lib/adapter-helpers.ts
|
|
2270
|
-
import
|
|
2533
|
+
import path6 from "node:path";
|
|
2271
2534
|
var TURN_IDLE_MS = 6e4;
|
|
2272
2535
|
function isTurnIdle(lastEventAt) {
|
|
2273
2536
|
if (!lastEventAt) {
|
|
@@ -2280,7 +2543,7 @@ function isTurnIdle(lastEventAt) {
|
|
|
2280
2543
|
return Date.now() - lastMs > TURN_IDLE_MS;
|
|
2281
2544
|
}
|
|
2282
2545
|
function sessionIdFromFilePath(filePath, prefix) {
|
|
2283
|
-
const match =
|
|
2546
|
+
const match = path6.basename(filePath).match(/([0-9a-f]{8}-[0-9a-f-]{27,})/);
|
|
2284
2547
|
return match?.[1] || `${prefix}_${createStableHash(filePath).slice(0, 24)}`;
|
|
2285
2548
|
}
|
|
2286
2549
|
function hookHandler(agentId, statusMessage) {
|
|
@@ -2344,7 +2607,7 @@ async function parseClaudeCodeSessionFile(filePath, options) {
|
|
|
2344
2607
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
2345
2608
|
state.sessionId = sessionId;
|
|
2346
2609
|
cwd = stringField(raw, "cwd") || cwd;
|
|
2347
|
-
project = projectContext.project || (cwd ?
|
|
2610
|
+
project = projectContext.project || (cwd ? path7.basename(cwd) : project || await claudeProjectFromFilePath(filePath, options));
|
|
2348
2611
|
if (!ts) {
|
|
2349
2612
|
continue;
|
|
2350
2613
|
}
|
|
@@ -2716,17 +2979,17 @@ function claudeTextStats(value) {
|
|
|
2716
2979
|
};
|
|
2717
2980
|
}
|
|
2718
2981
|
async function claudeProjectContextFromLines(filePath, lines, options) {
|
|
2719
|
-
const projectDir =
|
|
2982
|
+
const projectDir = path7.basename(path7.dirname(filePath));
|
|
2720
2983
|
const cwds = [];
|
|
2721
2984
|
for (const line of lines) {
|
|
2722
2985
|
const raw = parseJsonLine(line);
|
|
2723
2986
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
2724
|
-
if (cwd &&
|
|
2987
|
+
if (cwd && path7.isAbsolute(cwd)) {
|
|
2725
2988
|
cwds.push(cwd);
|
|
2726
2989
|
}
|
|
2727
2990
|
}
|
|
2728
2991
|
const root = await gitRootFromCwds(cwds) || claudeProjectRootFromCwds(projectDir, cwds);
|
|
2729
|
-
const project = cwds.length > 0 ?
|
|
2992
|
+
const project = cwds.length > 0 ? path7.basename(cwds[0]) : root ? path7.basename(root) : await claudeProjectFromFilePath(filePath, options);
|
|
2730
2993
|
return {
|
|
2731
2994
|
project,
|
|
2732
2995
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -2735,15 +2998,15 @@ async function claudeProjectContextFromLines(filePath, lines, options) {
|
|
|
2735
2998
|
async function gitRootFromCwds(cwds) {
|
|
2736
2999
|
const seen = /* @__PURE__ */ new Set();
|
|
2737
3000
|
for (const cwd of cwds) {
|
|
2738
|
-
let current =
|
|
3001
|
+
let current = path7.resolve(cwd);
|
|
2739
3002
|
while (!seen.has(current)) {
|
|
2740
3003
|
seen.add(current);
|
|
2741
3004
|
try {
|
|
2742
|
-
await
|
|
3005
|
+
await stat4(path7.join(current, ".git"));
|
|
2743
3006
|
return current;
|
|
2744
3007
|
} catch {
|
|
2745
3008
|
}
|
|
2746
|
-
const parent =
|
|
3009
|
+
const parent = path7.dirname(current);
|
|
2747
3010
|
if (parent === current) {
|
|
2748
3011
|
break;
|
|
2749
3012
|
}
|
|
@@ -2754,12 +3017,12 @@ async function gitRootFromCwds(cwds) {
|
|
|
2754
3017
|
}
|
|
2755
3018
|
function claudeProjectRootFromCwds(projectDir, cwds) {
|
|
2756
3019
|
for (const cwd of cwds) {
|
|
2757
|
-
let current =
|
|
3020
|
+
let current = path7.resolve(cwd);
|
|
2758
3021
|
while (true) {
|
|
2759
3022
|
if (encodeClaudeProjectPath(current) === projectDir) {
|
|
2760
3023
|
return current;
|
|
2761
3024
|
}
|
|
2762
|
-
const parent =
|
|
3025
|
+
const parent = path7.dirname(current);
|
|
2763
3026
|
if (parent === current) {
|
|
2764
3027
|
break;
|
|
2765
3028
|
}
|
|
@@ -2769,10 +3032,10 @@ function claudeProjectRootFromCwds(projectDir, cwds) {
|
|
|
2769
3032
|
return void 0;
|
|
2770
3033
|
}
|
|
2771
3034
|
function encodeClaudeProjectPath(value) {
|
|
2772
|
-
return
|
|
3035
|
+
return path7.resolve(value).split(path7.sep).join("-").replace(/_/g, "-");
|
|
2773
3036
|
}
|
|
2774
3037
|
function rawClaudeProjectPath(value) {
|
|
2775
|
-
return
|
|
3038
|
+
return path7.resolve(value).split(path7.sep).join("-");
|
|
2776
3039
|
}
|
|
2777
3040
|
function claudeEncodedVariants(value) {
|
|
2778
3041
|
const raw = rawClaudeProjectPath(value);
|
|
@@ -2788,11 +3051,11 @@ function claudeEncodedProjectSuffix(projectDir, home) {
|
|
|
2788
3051
|
return void 0;
|
|
2789
3052
|
}
|
|
2790
3053
|
async function claudeProjectFromFilePath(filePath, options) {
|
|
2791
|
-
const projectDir =
|
|
2792
|
-
const home = options ?
|
|
3054
|
+
const projectDir = path7.basename(path7.dirname(filePath));
|
|
3055
|
+
const home = options ? path7.resolve(stringOption(options.home) || os2.homedir()) : os2.homedir();
|
|
2793
3056
|
const resolved = await resolveClaudeProjectPath(projectDir, home);
|
|
2794
3057
|
if (resolved) {
|
|
2795
|
-
return
|
|
3058
|
+
return path7.basename(resolved);
|
|
2796
3059
|
}
|
|
2797
3060
|
const suffix = claudeEncodedProjectSuffix(projectDir, home);
|
|
2798
3061
|
if (suffix) {
|
|
@@ -2818,7 +3081,7 @@ async function resolveClaudeProjectPath(projectDir, home) {
|
|
|
2818
3081
|
if (!entry.isDirectory()) {
|
|
2819
3082
|
continue;
|
|
2820
3083
|
}
|
|
2821
|
-
const candidate =
|
|
3084
|
+
const candidate = path7.join(current, entry.name);
|
|
2822
3085
|
const candidateVariants = claudeEncodedVariants(candidate);
|
|
2823
3086
|
if (candidateVariants.includes(projectDir)) {
|
|
2824
3087
|
return candidate;
|
|
@@ -2863,9 +3126,9 @@ function hookConfig2() {
|
|
|
2863
3126
|
function claudeConfigDir(home, env) {
|
|
2864
3127
|
const override = env?.CLAUDE_CONFIG_DIR;
|
|
2865
3128
|
if (override && override.trim()) {
|
|
2866
|
-
return
|
|
3129
|
+
return path7.resolve(override);
|
|
2867
3130
|
}
|
|
2868
|
-
return
|
|
3131
|
+
return path7.join(home, ".claude");
|
|
2869
3132
|
}
|
|
2870
3133
|
function createClaudeCodeAdapter() {
|
|
2871
3134
|
return {
|
|
@@ -2877,27 +3140,27 @@ function createClaudeCodeAdapter() {
|
|
|
2877
3140
|
return claudeConfigDir(home, env);
|
|
2878
3141
|
},
|
|
2879
3142
|
installedPath(home, env) {
|
|
2880
|
-
return
|
|
3143
|
+
return path7.join(claudeConfigDir(home, env), "settings.json");
|
|
2881
3144
|
},
|
|
2882
3145
|
async isInstalled(home, env) {
|
|
2883
3146
|
return isHooksJsonInstalled(
|
|
2884
|
-
|
|
3147
|
+
path7.join(claudeConfigDir(home, env), "settings.json"),
|
|
2885
3148
|
"vibetime hook --agent claude"
|
|
2886
3149
|
);
|
|
2887
3150
|
},
|
|
2888
3151
|
installEntries(home, env) {
|
|
2889
3152
|
return [{
|
|
2890
3153
|
kind: "hooks-json",
|
|
2891
|
-
path:
|
|
3154
|
+
path: path7.join(claudeConfigDir(home, env), "settings.json"),
|
|
2892
3155
|
content: hookConfig2()
|
|
2893
3156
|
}];
|
|
2894
3157
|
},
|
|
2895
3158
|
sourcePaths(home, env) {
|
|
2896
3159
|
const base = claudeConfigDir(home, env);
|
|
2897
3160
|
return [
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
3161
|
+
path7.join(base, "projects"),
|
|
3162
|
+
path7.join(base, ".claude.json"),
|
|
3163
|
+
path7.join(home, ".claude.json")
|
|
2901
3164
|
];
|
|
2902
3165
|
},
|
|
2903
3166
|
parseSessionFile: parseClaudeCodeSessionFile
|
|
@@ -2905,21 +3168,21 @@ function createClaudeCodeAdapter() {
|
|
|
2905
3168
|
}
|
|
2906
3169
|
|
|
2907
3170
|
// src/adapters/claude-cowork.ts
|
|
2908
|
-
import { readdir as readdir3, readFile as readFile4, stat as
|
|
3171
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat5 } from "node:fs/promises";
|
|
2909
3172
|
import os3 from "node:os";
|
|
2910
|
-
import
|
|
3173
|
+
import path8 from "node:path";
|
|
2911
3174
|
init_fs();
|
|
2912
3175
|
var COWORK_PREFIX = "cowork:";
|
|
2913
3176
|
function coworkDataDirs(home, env) {
|
|
2914
3177
|
const override = env?.COWORK_DIR || env?.CLAUDE_COWORK_DIR;
|
|
2915
3178
|
if (override && override.trim()) {
|
|
2916
|
-
return override.split(",").map((item) => item.trim()).filter(Boolean).map((item) =>
|
|
3179
|
+
return override.split(",").map((item) => item.trim()).filter(Boolean).map((item) => path8.resolve(item));
|
|
2917
3180
|
}
|
|
2918
3181
|
return [
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
3182
|
+
path8.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions"),
|
|
3183
|
+
path8.join(home, ".config", "Claude", "local-agent-mode-sessions"),
|
|
3184
|
+
path8.join(home, "AppData", "Local", "Packages", "Claude_pzs8sxrjxfjjc", "LocalCache", "Roaming", "Claude", "local-agent-mode-sessions"),
|
|
3185
|
+
path8.join(home, "AppData", "Roaming", "Claude", "local-agent-mode-sessions")
|
|
2923
3186
|
];
|
|
2924
3187
|
}
|
|
2925
3188
|
function isCoworkMetaFileName(name) {
|
|
@@ -2935,7 +3198,7 @@ async function readCoworkMeta(filePath) {
|
|
|
2935
3198
|
}
|
|
2936
3199
|
async function isRegularFile(filePath) {
|
|
2937
3200
|
try {
|
|
2938
|
-
return (await
|
|
3201
|
+
return (await stat5(filePath)).isFile();
|
|
2939
3202
|
} catch {
|
|
2940
3203
|
return false;
|
|
2941
3204
|
}
|
|
@@ -2944,7 +3207,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
|
|
|
2944
3207
|
if (!sessionDir || !cliSessionId) {
|
|
2945
3208
|
return void 0;
|
|
2946
3209
|
}
|
|
2947
|
-
const projectsDir =
|
|
3210
|
+
const projectsDir = path8.join(sessionDir, ".claude", "projects");
|
|
2948
3211
|
let entries;
|
|
2949
3212
|
try {
|
|
2950
3213
|
entries = await readdir3(projectsDir, { withFileTypes: true });
|
|
@@ -2956,7 +3219,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
|
|
|
2956
3219
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
2957
3220
|
continue;
|
|
2958
3221
|
}
|
|
2959
|
-
const candidate =
|
|
3222
|
+
const candidate = path8.join(projectsDir, entry.name, target);
|
|
2960
3223
|
if (await isRegularFile(candidate)) {
|
|
2961
3224
|
return candidate;
|
|
2962
3225
|
}
|
|
@@ -2964,7 +3227,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
|
|
|
2964
3227
|
return void 0;
|
|
2965
3228
|
}
|
|
2966
3229
|
async function coworkSubagentTranscripts(mainTranscript, cliSessionId) {
|
|
2967
|
-
const root =
|
|
3230
|
+
const root = path8.join(path8.dirname(mainTranscript), cliSessionId, "subagents");
|
|
2968
3231
|
const out = [];
|
|
2969
3232
|
async function walk(dir) {
|
|
2970
3233
|
let entries;
|
|
@@ -2974,7 +3237,7 @@ async function coworkSubagentTranscripts(mainTranscript, cliSessionId) {
|
|
|
2974
3237
|
return;
|
|
2975
3238
|
}
|
|
2976
3239
|
await Promise.all(entries.map(async (entry) => {
|
|
2977
|
-
const entryPath =
|
|
3240
|
+
const entryPath = path8.join(dir, entry.name);
|
|
2978
3241
|
if (entry.isDirectory()) {
|
|
2979
3242
|
await walk(entryPath);
|
|
2980
3243
|
return;
|
|
@@ -2997,7 +3260,7 @@ async function discoverCoworkTranscripts(root) {
|
|
|
2997
3260
|
return;
|
|
2998
3261
|
}
|
|
2999
3262
|
await Promise.all(entries.map(async (entry) => {
|
|
3000
|
-
const entryPath =
|
|
3263
|
+
const entryPath = path8.join(dir, entry.name);
|
|
3001
3264
|
if (entry.isDirectory()) {
|
|
3002
3265
|
if (entry.name.startsWith("local_") || entry.name === "skills-plugin" || entry.name === "node_modules" || entry.name === ".git") {
|
|
3003
3266
|
return;
|
|
@@ -3027,7 +3290,7 @@ async function discoverCoworkTranscripts(root) {
|
|
|
3027
3290
|
return transcripts.sort((a, b) => a.transcriptPath.localeCompare(b.transcriptPath));
|
|
3028
3291
|
}
|
|
3029
3292
|
function coworkMetaPathForTranscript(transcriptPath) {
|
|
3030
|
-
const marker = `${
|
|
3293
|
+
const marker = `${path8.sep}.claude${path8.sep}projects${path8.sep}`;
|
|
3031
3294
|
const index = transcriptPath.indexOf(marker);
|
|
3032
3295
|
if (index < 0) {
|
|
3033
3296
|
return void 0;
|
|
@@ -3042,9 +3305,9 @@ function projectFromMeta(meta) {
|
|
|
3042
3305
|
if (!folder) {
|
|
3043
3306
|
return { project: "cowork" };
|
|
3044
3307
|
}
|
|
3045
|
-
const resolved =
|
|
3308
|
+
const resolved = path8.resolve(folder);
|
|
3046
3309
|
return {
|
|
3047
|
-
project:
|
|
3310
|
+
project: path8.basename(resolved).replace(/-/g, "_") || "cowork",
|
|
3048
3311
|
cwd: resolved
|
|
3049
3312
|
};
|
|
3050
3313
|
}
|
|
@@ -3104,13 +3367,13 @@ async function parseClaudeCoworkSessionFile(filePath, options) {
|
|
|
3104
3367
|
});
|
|
3105
3368
|
}
|
|
3106
3369
|
async function claudeCoworkBackfillFiles(sourceRoot, home, env) {
|
|
3107
|
-
const roots = sourceRoot ? [
|
|
3370
|
+
const roots = sourceRoot ? [path8.resolve(sourceRoot)] : coworkDataDirs(home, env);
|
|
3108
3371
|
const discovered = (await Promise.all(roots.map(discoverCoworkTranscripts))).flat();
|
|
3109
3372
|
return Promise.all(discovered.map(async ({ transcriptPath, metadataPath }) => {
|
|
3110
|
-
const transcriptInfo = await
|
|
3373
|
+
const transcriptInfo = await stat5(transcriptPath);
|
|
3111
3374
|
let modifiedAt = transcriptInfo.mtime;
|
|
3112
3375
|
try {
|
|
3113
|
-
const metaInfo = await
|
|
3376
|
+
const metaInfo = await stat5(metadataPath);
|
|
3114
3377
|
if (metaInfo.mtime > modifiedAt) {
|
|
3115
3378
|
modifiedAt = metaInfo.mtime;
|
|
3116
3379
|
}
|
|
@@ -3126,7 +3389,7 @@ function createClaudeCoworkAdapter() {
|
|
|
3126
3389
|
agentName: "claude-cowork",
|
|
3127
3390
|
kind: "agent",
|
|
3128
3391
|
detectPath(home, env) {
|
|
3129
|
-
return coworkDataDirs(home, env)[0] ||
|
|
3392
|
+
return coworkDataDirs(home, env)[0] || path8.join(os3.homedir(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
|
|
3130
3393
|
},
|
|
3131
3394
|
installedPath(home, env) {
|
|
3132
3395
|
return this.detectPath(home, env);
|
|
@@ -3151,7 +3414,7 @@ function createClaudeCoworkAdapter() {
|
|
|
3151
3414
|
|
|
3152
3415
|
// src/adapters/codebuddy.ts
|
|
3153
3416
|
import { readFile as readFile5, readdir as readdir4 } from "node:fs/promises";
|
|
3154
|
-
import
|
|
3417
|
+
import path9 from "node:path";
|
|
3155
3418
|
var ENDPOINT_MODEL_ID_RE = /^(?:ep|endpoint)-/i;
|
|
3156
3419
|
async function parseCodebuddyTraceFile(filePath, options) {
|
|
3157
3420
|
const text = await readFile5(filePath, "utf8");
|
|
@@ -3168,8 +3431,9 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
3168
3431
|
}
|
|
3169
3432
|
const trace = traceFile.trace;
|
|
3170
3433
|
const spans = Array.isArray(traceFile.spans) ? traceFile.spans : [];
|
|
3434
|
+
const hasGenerationSpans = spans.some((s) => s.type === "generation");
|
|
3171
3435
|
const hasFunctionSpans = spans.some((s) => s.type === "function");
|
|
3172
|
-
const isTrivial = !
|
|
3436
|
+
const isTrivial = !hasGenerationSpans && !hasFunctionSpans;
|
|
3173
3437
|
if (isTrivial) {
|
|
3174
3438
|
return [];
|
|
3175
3439
|
}
|
|
@@ -3178,7 +3442,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
3178
3442
|
if (!cwd && trace.startedAt) {
|
|
3179
3443
|
cwd = await cwdFromHistoryFile(trace.startedAt, options);
|
|
3180
3444
|
}
|
|
3181
|
-
const project = cwd ?
|
|
3445
|
+
const project = cwd ? path9.basename(cwd) : void 0;
|
|
3182
3446
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
3183
3447
|
const model = resolveCodebuddyModel(trace, spans);
|
|
3184
3448
|
const baseEvent = (event) => ({
|
|
@@ -3345,7 +3609,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
3345
3609
|
}
|
|
3346
3610
|
if (span.type === "generation") {
|
|
3347
3611
|
generationCount++;
|
|
3348
|
-
const usage = modelUsageFromTrace(trace, generationCount, totalGenerations);
|
|
3612
|
+
const usage = extractUsageFromGenerationSpan(span) ?? modelUsageFromTrace(trace, generationCount, totalGenerations);
|
|
3349
3613
|
push(baseEvent({
|
|
3350
3614
|
ts,
|
|
3351
3615
|
type: "model.usage",
|
|
@@ -3524,6 +3788,32 @@ function normalizeModelCandidate(value) {
|
|
|
3524
3788
|
}
|
|
3525
3789
|
return trimmed;
|
|
3526
3790
|
}
|
|
3791
|
+
function extractUsageFromGenerationSpan(span) {
|
|
3792
|
+
const parsed = parseEmbeddedJson(span.toolOutput);
|
|
3793
|
+
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
3794
|
+
return void 0;
|
|
3795
|
+
}
|
|
3796
|
+
const first = parsed[0];
|
|
3797
|
+
if (!isPlainObject(first)) {
|
|
3798
|
+
return void 0;
|
|
3799
|
+
}
|
|
3800
|
+
const usage = objectField(first, "usage");
|
|
3801
|
+
if (!isPlainObject(usage)) {
|
|
3802
|
+
return void 0;
|
|
3803
|
+
}
|
|
3804
|
+
const inputTokens = numberField(usage, "prompt_tokens");
|
|
3805
|
+
const outputTokens = numberField(usage, "completion_tokens");
|
|
3806
|
+
const totalTokens = numberField(usage, "total_tokens");
|
|
3807
|
+
const details = objectField(usage, "prompt_tokens_details");
|
|
3808
|
+
const cachedTokens = isPlainObject(details) ? numberField(details, "cached_tokens") : void 0;
|
|
3809
|
+
return {
|
|
3810
|
+
tokensInput: inputTokens || void 0,
|
|
3811
|
+
tokensCachedInput: cachedTokens || void 0,
|
|
3812
|
+
tokensOutput: outputTokens || void 0,
|
|
3813
|
+
tokensTotal: totalTokens || void 0,
|
|
3814
|
+
modelCalls: 1
|
|
3815
|
+
};
|
|
3816
|
+
}
|
|
3527
3817
|
function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
|
|
3528
3818
|
const info = trace.modelInfo;
|
|
3529
3819
|
if (!info || !info.totalInputTokens && !info.totalOutputTokens && !trace.totalTokens) {
|
|
@@ -3545,11 +3835,11 @@ function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
|
|
|
3545
3835
|
return { modelCalls: 1 };
|
|
3546
3836
|
}
|
|
3547
3837
|
function sessionIdFromTracePath(filePath) {
|
|
3548
|
-
const match =
|
|
3838
|
+
const match = path9.basename(filePath).match(/trace_([0-9a-f]{32})/);
|
|
3549
3839
|
return match?.[1] ? `codebuddy_${match[1]}` : `codebuddy_${createStableHash(filePath).slice(0, 24)}`;
|
|
3550
3840
|
}
|
|
3551
3841
|
function resolveHome(options) {
|
|
3552
|
-
return options.home ?
|
|
3842
|
+
return options.home ? path9.resolve(String(options.home)) : process.env.HOME || __require("node:os").homedir();
|
|
3553
3843
|
}
|
|
3554
3844
|
async function readCwdFromSession(sessionPath, matchSessionId) {
|
|
3555
3845
|
try {
|
|
@@ -3570,9 +3860,9 @@ async function readCwdFromSession(sessionPath, matchSessionId) {
|
|
|
3570
3860
|
}
|
|
3571
3861
|
async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
3572
3862
|
const home = resolveHome(options);
|
|
3573
|
-
const sessionsDir =
|
|
3863
|
+
const sessionsDir = path9.join(home, ".codebuddy", "sessions");
|
|
3574
3864
|
if (pid) {
|
|
3575
|
-
const cwd = await readCwdFromSession(
|
|
3865
|
+
const cwd = await readCwdFromSession(path9.join(sessionsDir, `${pid}.json`));
|
|
3576
3866
|
if (cwd) {
|
|
3577
3867
|
return cwd;
|
|
3578
3868
|
}
|
|
@@ -3585,7 +3875,7 @@ async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
|
3585
3875
|
continue;
|
|
3586
3876
|
}
|
|
3587
3877
|
const cwd = await readCwdFromSession(
|
|
3588
|
-
|
|
3878
|
+
path9.join(sessionsDir, f),
|
|
3589
3879
|
traceSessionId
|
|
3590
3880
|
);
|
|
3591
3881
|
if (cwd) {
|
|
@@ -3599,7 +3889,7 @@ async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
|
3599
3889
|
}
|
|
3600
3890
|
async function cwdFromHistoryFile(traceStartedAt, options) {
|
|
3601
3891
|
const home = resolveHome(options);
|
|
3602
|
-
const historyPath =
|
|
3892
|
+
const historyPath = path9.join(home, ".codebuddy", "history.jsonl");
|
|
3603
3893
|
const traceMs = Date.parse(traceStartedAt);
|
|
3604
3894
|
if (Number.isNaN(traceMs)) {
|
|
3605
3895
|
return void 0;
|
|
@@ -3661,9 +3951,9 @@ function hookConfig3() {
|
|
|
3661
3951
|
function codebuddyConfigDir(home, env) {
|
|
3662
3952
|
const override = env?.CODEBUDDY_CONFIG_DIR;
|
|
3663
3953
|
if (override && override.trim()) {
|
|
3664
|
-
return
|
|
3954
|
+
return path9.resolve(override);
|
|
3665
3955
|
}
|
|
3666
|
-
return
|
|
3956
|
+
return path9.join(home, ".codebuddy");
|
|
3667
3957
|
}
|
|
3668
3958
|
function createCodebuddyAdapter() {
|
|
3669
3959
|
return {
|
|
@@ -3675,32 +3965,32 @@ function createCodebuddyAdapter() {
|
|
|
3675
3965
|
return codebuddyConfigDir(home, env);
|
|
3676
3966
|
},
|
|
3677
3967
|
installedPath(home, env) {
|
|
3678
|
-
return
|
|
3968
|
+
return path9.join(codebuddyConfigDir(home, env), "settings.json");
|
|
3679
3969
|
},
|
|
3680
3970
|
async isInstalled(home, env) {
|
|
3681
3971
|
return isHooksJsonInstalled(
|
|
3682
|
-
|
|
3972
|
+
path9.join(codebuddyConfigDir(home, env), "settings.json"),
|
|
3683
3973
|
"vibetime hook --agent codebuddy"
|
|
3684
3974
|
);
|
|
3685
3975
|
},
|
|
3686
3976
|
installEntries(home, env) {
|
|
3687
3977
|
return [{
|
|
3688
3978
|
kind: "hooks-json",
|
|
3689
|
-
path:
|
|
3979
|
+
path: path9.join(codebuddyConfigDir(home, env), "settings.json"),
|
|
3690
3980
|
content: hookConfig3()
|
|
3691
3981
|
}];
|
|
3692
3982
|
},
|
|
3693
3983
|
sourcePaths(home, env) {
|
|
3694
3984
|
const base = codebuddyConfigDir(home, env);
|
|
3695
3985
|
return [
|
|
3696
|
-
|
|
3986
|
+
path9.join(base, "traces")
|
|
3697
3987
|
];
|
|
3698
3988
|
},
|
|
3699
3989
|
parseSessionFile: parseCodebuddyTraceFile
|
|
3700
3990
|
};
|
|
3701
3991
|
}
|
|
3702
3992
|
async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
3703
|
-
const base = sourceRoot ||
|
|
3993
|
+
const base = sourceRoot || path9.join(codebuddyConfigDir(home, env), "traces");
|
|
3704
3994
|
const files = [];
|
|
3705
3995
|
try {
|
|
3706
3996
|
const pidDirs = await readdir4(base, { withFileTypes: true });
|
|
@@ -3708,17 +3998,17 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
3708
3998
|
if (!pidDir.isDirectory()) {
|
|
3709
3999
|
continue;
|
|
3710
4000
|
}
|
|
3711
|
-
const traceDir =
|
|
4001
|
+
const traceDir = path9.join(base, pidDir.name);
|
|
3712
4002
|
try {
|
|
3713
4003
|
const entries = await readdir4(traceDir);
|
|
3714
4004
|
for (const entry of entries) {
|
|
3715
4005
|
if (!entry.endsWith(".json") || !entry.startsWith("trace_")) {
|
|
3716
4006
|
continue;
|
|
3717
4007
|
}
|
|
3718
|
-
const filePath =
|
|
4008
|
+
const filePath = path9.join(traceDir, entry);
|
|
3719
4009
|
try {
|
|
3720
|
-
const
|
|
3721
|
-
files.push({ path: filePath, modifiedAt:
|
|
4010
|
+
const stat13 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
|
|
4011
|
+
files.push({ path: filePath, modifiedAt: stat13.mtime.toISOString() });
|
|
3722
4012
|
} catch {
|
|
3723
4013
|
}
|
|
3724
4014
|
}
|
|
@@ -3732,7 +4022,7 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
3732
4022
|
|
|
3733
4023
|
// src/adapters/codex.ts
|
|
3734
4024
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
3735
|
-
import
|
|
4025
|
+
import path11 from "node:path";
|
|
3736
4026
|
|
|
3737
4027
|
// src/lib/diff.ts
|
|
3738
4028
|
function diffStats(diff) {
|
|
@@ -3781,16 +4071,16 @@ function fileActivitiesFromPatchChanges(changes, ts, cwd, displayFilePath3) {
|
|
|
3781
4071
|
init_fs();
|
|
3782
4072
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
3783
4073
|
import os4 from "node:os";
|
|
3784
|
-
import
|
|
4074
|
+
import path10 from "node:path";
|
|
3785
4075
|
var SESSION_CONTEXT_VERSION = 1;
|
|
3786
4076
|
function sessionContextDir(home) {
|
|
3787
|
-
return
|
|
4077
|
+
return path10.join(home, ".vibetime", "session-context");
|
|
3788
4078
|
}
|
|
3789
4079
|
function sessionContextPath(home, sessionId) {
|
|
3790
|
-
return
|
|
4080
|
+
return path10.join(sessionContextDir(home), `${encodeURIComponent(sessionId)}.json`);
|
|
3791
4081
|
}
|
|
3792
4082
|
function resolveHome2(options) {
|
|
3793
|
-
return options ?
|
|
4083
|
+
return options ? path10.resolve(stringOption(options.home) || os4.homedir()) : os4.homedir();
|
|
3794
4084
|
}
|
|
3795
4085
|
async function readPersistedSessionContext(home, sessionId) {
|
|
3796
4086
|
const raw = await readJsonIfExists(sessionContextPath(home, sessionId));
|
|
@@ -3816,10 +4106,10 @@ async function persistHookSessionContext(home, payload) {
|
|
|
3816
4106
|
}
|
|
3817
4107
|
const sessionId = typeof payload.session_id === "string" ? payload.session_id.trim() : typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
|
|
3818
4108
|
const cwd = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
|
|
3819
|
-
if (!sessionId || !cwd || !
|
|
4109
|
+
if (!sessionId || !cwd || !path10.isAbsolute(cwd)) {
|
|
3820
4110
|
return;
|
|
3821
4111
|
}
|
|
3822
|
-
const project =
|
|
4112
|
+
const project = path10.basename(cwd) || void 0;
|
|
3823
4113
|
const context = {
|
|
3824
4114
|
version: SESSION_CONTEXT_VERSION,
|
|
3825
4115
|
sessionId,
|
|
@@ -3870,7 +4160,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3870
4160
|
const inherited = forkedFromId ? await readPersistedSessionContextFromOptions(options, forkedFromId) : void 0;
|
|
3871
4161
|
sessionId = stringField(payload, "id") || sessionId;
|
|
3872
4162
|
cwd = inherited?.cwd || stringField(payload, "cwd") || cwd;
|
|
3873
|
-
project = inherited?.project || (cwd ?
|
|
4163
|
+
project = inherited?.project || (cwd ? path11.basename(cwd) : project);
|
|
3874
4164
|
model = stringField(payload, "model_provider") || model;
|
|
3875
4165
|
events.push(withBackfillRefs({
|
|
3876
4166
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -3891,7 +4181,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3891
4181
|
if (topType === "turn_context") {
|
|
3892
4182
|
currentTurnId = stringField(payload, "turn_id") || currentTurnId;
|
|
3893
4183
|
cwd = stringField(payload, "cwd") || cwd;
|
|
3894
|
-
project = cwd ?
|
|
4184
|
+
project = cwd ? path11.basename(cwd) : project;
|
|
3895
4185
|
model = stringField(payload, "model") || model;
|
|
3896
4186
|
const effort = stringField(payload, "effort") || stringField(objectField(objectField(payload, "collaboration_mode"), "settings"), "reasoning_effort");
|
|
3897
4187
|
if (effort) {
|
|
@@ -4338,11 +4628,11 @@ function functionCallArguments(payload) {
|
|
|
4338
4628
|
}
|
|
4339
4629
|
}
|
|
4340
4630
|
function displayFilePath2(filePath, cwd) {
|
|
4341
|
-
if (!cwd || !
|
|
4631
|
+
if (!cwd || !path11.isAbsolute(filePath)) {
|
|
4342
4632
|
return filePath;
|
|
4343
4633
|
}
|
|
4344
|
-
const relative =
|
|
4345
|
-
return relative && !relative.startsWith("..") && !
|
|
4634
|
+
const relative = path11.relative(cwd, filePath);
|
|
4635
|
+
return relative && !relative.startsWith("..") && !path11.isAbsolute(relative) ? relative : filePath;
|
|
4346
4636
|
}
|
|
4347
4637
|
var codexHandler = (msg) => hookHandler("codex", msg);
|
|
4348
4638
|
function hookConfig4() {
|
|
@@ -4361,9 +4651,9 @@ function hookConfig4() {
|
|
|
4361
4651
|
function codexHome(home, env) {
|
|
4362
4652
|
const override = env?.CODEX_HOME;
|
|
4363
4653
|
if (override && override.trim()) {
|
|
4364
|
-
return
|
|
4654
|
+
return path11.resolve(override);
|
|
4365
4655
|
}
|
|
4366
|
-
return
|
|
4656
|
+
return path11.join(home, ".codex");
|
|
4367
4657
|
}
|
|
4368
4658
|
function createCodexAdapter() {
|
|
4369
4659
|
return {
|
|
@@ -4375,26 +4665,26 @@ function createCodexAdapter() {
|
|
|
4375
4665
|
return codexHome(home, env);
|
|
4376
4666
|
},
|
|
4377
4667
|
installedPath(home, env) {
|
|
4378
|
-
return
|
|
4668
|
+
return path11.join(codexHome(home, env), "hooks.json");
|
|
4379
4669
|
},
|
|
4380
4670
|
async isInstalled(home, env) {
|
|
4381
4671
|
return isHooksJsonInstalled(
|
|
4382
|
-
|
|
4672
|
+
path11.join(codexHome(home, env), "hooks.json"),
|
|
4383
4673
|
"vibetime hook --agent codex"
|
|
4384
4674
|
);
|
|
4385
4675
|
},
|
|
4386
4676
|
installEntries(home, env) {
|
|
4387
4677
|
return [{
|
|
4388
4678
|
kind: "hooks-json",
|
|
4389
|
-
path:
|
|
4679
|
+
path: path11.join(codexHome(home, env), "hooks.json"),
|
|
4390
4680
|
content: hookConfig4()
|
|
4391
4681
|
}];
|
|
4392
4682
|
},
|
|
4393
4683
|
sourcePaths(home, env) {
|
|
4394
4684
|
const base = codexHome(home, env);
|
|
4395
4685
|
return [
|
|
4396
|
-
|
|
4397
|
-
|
|
4686
|
+
path11.join(base, "sessions"),
|
|
4687
|
+
path11.join(base, "history.jsonl")
|
|
4398
4688
|
];
|
|
4399
4689
|
},
|
|
4400
4690
|
parseSessionFile: parseCodexSessionFile
|
|
@@ -4402,9 +4692,9 @@ function createCodexAdapter() {
|
|
|
4402
4692
|
}
|
|
4403
4693
|
|
|
4404
4694
|
// src/adapters/copilot.ts
|
|
4405
|
-
import { readdir as readdir5, readFile as readFile7, stat as
|
|
4695
|
+
import { readdir as readdir5, readFile as readFile7, stat as stat6 } from "node:fs/promises";
|
|
4406
4696
|
import os5 from "node:os";
|
|
4407
|
-
import
|
|
4697
|
+
import path12 from "node:path";
|
|
4408
4698
|
async function parseCopilotSessionFile(filePath, options) {
|
|
4409
4699
|
const text = await readFile7(filePath, "utf8");
|
|
4410
4700
|
const lines = text.split("\n").filter(Boolean);
|
|
@@ -4440,7 +4730,7 @@ async function parseCopilotSessionFile(filePath, options) {
|
|
|
4440
4730
|
}
|
|
4441
4731
|
const context = objectField(data, "context");
|
|
4442
4732
|
cwd = stringField(context, "cwd") || stringField(context, "gitRoot") || cwd;
|
|
4443
|
-
project = stringField(context, "repository") || (cwd ?
|
|
4733
|
+
project = stringField(context, "repository") || (cwd ? path12.basename(cwd) : void 0);
|
|
4444
4734
|
sessionStartedAt = ts;
|
|
4445
4735
|
events.push(baseCopilotEvent({
|
|
4446
4736
|
ts,
|
|
@@ -4672,7 +4962,7 @@ function baseCopilotEvent(event) {
|
|
|
4672
4962
|
};
|
|
4673
4963
|
}
|
|
4674
4964
|
async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
|
|
4675
|
-
const sessionDir = sourceRoot ||
|
|
4965
|
+
const sessionDir = sourceRoot || path12.join(home, ".copilot", "session-state");
|
|
4676
4966
|
const results = [];
|
|
4677
4967
|
let entries;
|
|
4678
4968
|
try {
|
|
@@ -4684,8 +4974,8 @@ async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
|
|
|
4684
4974
|
if (entry.startsWith("pending-session")) {
|
|
4685
4975
|
continue;
|
|
4686
4976
|
}
|
|
4687
|
-
const eventsPath =
|
|
4688
|
-
const info = await
|
|
4977
|
+
const eventsPath = path12.join(sessionDir, entry, "events.jsonl");
|
|
4978
|
+
const info = await stat6(eventsPath).catch(() => null);
|
|
4689
4979
|
if (info) {
|
|
4690
4980
|
results.push({ path: eventsPath, modifiedAt: info.mtime.toISOString() });
|
|
4691
4981
|
}
|
|
@@ -4702,9 +4992,9 @@ function copilotPluginContent() {
|
|
|
4702
4992
|
function copilotHome(home, env) {
|
|
4703
4993
|
const override = env?.COPILOT_HOME;
|
|
4704
4994
|
if (override && override.trim()) {
|
|
4705
|
-
return
|
|
4995
|
+
return path12.resolve(override);
|
|
4706
4996
|
}
|
|
4707
|
-
return
|
|
4997
|
+
return path12.join(home, ".copilot");
|
|
4708
4998
|
}
|
|
4709
4999
|
function createCopilotAdapter() {
|
|
4710
5000
|
return {
|
|
@@ -4716,12 +5006,12 @@ function createCopilotAdapter() {
|
|
|
4716
5006
|
return copilotHome(home, env);
|
|
4717
5007
|
},
|
|
4718
5008
|
installedPath(home, env) {
|
|
4719
|
-
return
|
|
5009
|
+
return path12.join(copilotHome(home, env), ".vibetime");
|
|
4720
5010
|
},
|
|
4721
5011
|
async isInstalled(home, env) {
|
|
4722
5012
|
try {
|
|
4723
5013
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4724
|
-
return await pathExists2(
|
|
5014
|
+
return await pathExists2(path12.join(copilotHome(home, env), ".vibetime"));
|
|
4725
5015
|
} catch {
|
|
4726
5016
|
return false;
|
|
4727
5017
|
}
|
|
@@ -4729,12 +5019,12 @@ function createCopilotAdapter() {
|
|
|
4729
5019
|
installEntries(home, env) {
|
|
4730
5020
|
return [{
|
|
4731
5021
|
kind: "file",
|
|
4732
|
-
path:
|
|
5022
|
+
path: path12.join(copilotHome(home, env), ".vibetime"),
|
|
4733
5023
|
content: copilotPluginContent()
|
|
4734
5024
|
}];
|
|
4735
5025
|
},
|
|
4736
5026
|
sourcePaths(home, env) {
|
|
4737
|
-
return [
|
|
5027
|
+
return [path12.join(copilotHome(home, env), "session-state")];
|
|
4738
5028
|
},
|
|
4739
5029
|
parseSessionFile: parseCopilotSessionFile
|
|
4740
5030
|
};
|
|
@@ -4742,7 +5032,7 @@ function createCopilotAdapter() {
|
|
|
4742
5032
|
|
|
4743
5033
|
// src/adapters/opencode.ts
|
|
4744
5034
|
import os6 from "node:os";
|
|
4745
|
-
import
|
|
5035
|
+
import path13 from "node:path";
|
|
4746
5036
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
4747
5037
|
const { DatabaseSync } = await import("node:sqlite");
|
|
4748
5038
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -4773,7 +5063,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4773
5063
|
for (const session of sessions) {
|
|
4774
5064
|
const sessionId = session.id;
|
|
4775
5065
|
const cwd = session.directory || session.path || void 0;
|
|
4776
|
-
const project = cwd ?
|
|
5066
|
+
const project = cwd ? path13.basename(cwd) : void 0;
|
|
4777
5067
|
const sessionTs = msToIso(session.time_created);
|
|
4778
5068
|
events.push(baseOpenCodeEvent({
|
|
4779
5069
|
ts: sessionTs,
|
|
@@ -4881,7 +5171,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4881
5171
|
const provider = currentProvider;
|
|
4882
5172
|
const pathObj = objectField(info, "path");
|
|
4883
5173
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
4884
|
-
const assistantProject = assistantCwd ?
|
|
5174
|
+
const assistantProject = assistantCwd ? path13.basename(assistantCwd) : project;
|
|
4885
5175
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
4886
5176
|
const createdTs = timeCreated;
|
|
4887
5177
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -5127,33 +5417,33 @@ function opencodeUsageFromInfo(info) {
|
|
|
5127
5417
|
function opencodeConfigDir(home, env) {
|
|
5128
5418
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
5129
5419
|
if (override && override.trim()) {
|
|
5130
|
-
return
|
|
5420
|
+
return path13.resolve(override);
|
|
5131
5421
|
}
|
|
5132
5422
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
5133
5423
|
if (xdgConfig && xdgConfig.trim()) {
|
|
5134
|
-
return
|
|
5424
|
+
return path13.join(path13.resolve(xdgConfig), "opencode");
|
|
5135
5425
|
}
|
|
5136
|
-
return
|
|
5426
|
+
return path13.join(home, ".config", "opencode");
|
|
5137
5427
|
}
|
|
5138
5428
|
function opencodeDataCandidates(home, env) {
|
|
5139
5429
|
const xdgData = env?.XDG_DATA_HOME;
|
|
5140
|
-
const primary = xdgData && xdgData.trim() ?
|
|
5141
|
-
return [primary,
|
|
5430
|
+
const primary = xdgData && xdgData.trim() ? path13.join(path13.resolve(xdgData), "opencode", "opencode.db") : path13.join(home, ".local", "share", "opencode", "opencode.db");
|
|
5431
|
+
return [primary, path13.join(home, ".opencode", "opencode.db")];
|
|
5142
5432
|
}
|
|
5143
5433
|
async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
|
|
5144
|
-
const { stat:
|
|
5434
|
+
const { stat: stat13 } = await import("node:fs/promises");
|
|
5145
5435
|
if (sourceRoot) {
|
|
5146
5436
|
if (!sourceRoot.endsWith(".db")) {
|
|
5147
5437
|
return [];
|
|
5148
5438
|
}
|
|
5149
|
-
const info = await
|
|
5439
|
+
const info = await stat13(sourceRoot).catch(() => null);
|
|
5150
5440
|
if (!info) {
|
|
5151
5441
|
return [];
|
|
5152
5442
|
}
|
|
5153
5443
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
5154
5444
|
}
|
|
5155
5445
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
5156
|
-
const info = await
|
|
5446
|
+
const info = await stat13(candidatePath).catch(() => null);
|
|
5157
5447
|
if (info) {
|
|
5158
5448
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
5159
5449
|
}
|
|
@@ -5228,12 +5518,12 @@ function createOpenCodeAdapter() {
|
|
|
5228
5518
|
return opencodeConfigDir(home, env);
|
|
5229
5519
|
},
|
|
5230
5520
|
installedPath(home, env) {
|
|
5231
|
-
return
|
|
5521
|
+
return path13.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
5232
5522
|
},
|
|
5233
5523
|
async isInstalled(home, env) {
|
|
5234
5524
|
try {
|
|
5235
5525
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5236
|
-
return await pathExists2(
|
|
5526
|
+
return await pathExists2(path13.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path13.join(".opencode", PLUGIN_PATH));
|
|
5237
5527
|
} catch {
|
|
5238
5528
|
return false;
|
|
5239
5529
|
}
|
|
@@ -5241,7 +5531,7 @@ function createOpenCodeAdapter() {
|
|
|
5241
5531
|
installEntries(home, env) {
|
|
5242
5532
|
return [{
|
|
5243
5533
|
kind: "file",
|
|
5244
|
-
path:
|
|
5534
|
+
path: path13.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
5245
5535
|
content: opencodePluginContent()
|
|
5246
5536
|
}];
|
|
5247
5537
|
},
|
|
@@ -5254,7 +5544,7 @@ function createOpenCodeAdapter() {
|
|
|
5254
5544
|
|
|
5255
5545
|
// src/adapters/pi.ts
|
|
5256
5546
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
5257
|
-
import
|
|
5547
|
+
import path14 from "node:path";
|
|
5258
5548
|
async function parsePiSessionFile(filePath, options) {
|
|
5259
5549
|
const text = await readFile8(filePath, "utf8");
|
|
5260
5550
|
const lines = text.split("\n").filter(Boolean);
|
|
@@ -5287,7 +5577,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
5287
5577
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
5288
5578
|
state.sessionId = sessionId || state.sessionId;
|
|
5289
5579
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5290
|
-
project = cwd ?
|
|
5580
|
+
project = cwd ? path14.basename(cwd) : project;
|
|
5291
5581
|
continue;
|
|
5292
5582
|
}
|
|
5293
5583
|
if (entryType === "model_change") {
|
|
@@ -5696,16 +5986,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
5696
5986
|
function piAgentDir(home, env) {
|
|
5697
5987
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
5698
5988
|
if (override && override.trim()) {
|
|
5699
|
-
return
|
|
5989
|
+
return path14.resolve(override);
|
|
5700
5990
|
}
|
|
5701
|
-
return
|
|
5991
|
+
return path14.join(home, ".pi", "agent");
|
|
5702
5992
|
}
|
|
5703
5993
|
function piSessionDir(home, env) {
|
|
5704
5994
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
5705
5995
|
if (override && override.trim()) {
|
|
5706
|
-
return
|
|
5996
|
+
return path14.resolve(override);
|
|
5707
5997
|
}
|
|
5708
|
-
return
|
|
5998
|
+
return path14.join(piAgentDir(home, env), "sessions");
|
|
5709
5999
|
}
|
|
5710
6000
|
function createPiAdapter() {
|
|
5711
6001
|
return {
|
|
@@ -5717,12 +6007,12 @@ function createPiAdapter() {
|
|
|
5717
6007
|
return piAgentDir(home, env);
|
|
5718
6008
|
},
|
|
5719
6009
|
installedPath(home, env) {
|
|
5720
|
-
return
|
|
6010
|
+
return path14.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
5721
6011
|
},
|
|
5722
6012
|
async isInstalled(home, env) {
|
|
5723
6013
|
try {
|
|
5724
6014
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5725
|
-
return await pathExists2(
|
|
6015
|
+
return await pathExists2(path14.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
5726
6016
|
} catch {
|
|
5727
6017
|
return false;
|
|
5728
6018
|
}
|
|
@@ -5730,7 +6020,7 @@ function createPiAdapter() {
|
|
|
5730
6020
|
installEntries(home, env) {
|
|
5731
6021
|
return [{
|
|
5732
6022
|
kind: "file",
|
|
5733
|
-
path:
|
|
6023
|
+
path: path14.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
5734
6024
|
content: piExtensionContent()
|
|
5735
6025
|
}];
|
|
5736
6026
|
},
|
|
@@ -5742,11 +6032,11 @@ function createPiAdapter() {
|
|
|
5742
6032
|
}
|
|
5743
6033
|
|
|
5744
6034
|
// src/adapters/qoder-cn.ts
|
|
5745
|
-
import { readdir as readdir6, readFile as readFile9, stat as
|
|
6035
|
+
import { readdir as readdir6, readFile as readFile9, stat as stat7 } from "node:fs/promises";
|
|
5746
6036
|
import os7 from "node:os";
|
|
5747
|
-
import
|
|
6037
|
+
import path15 from "node:path";
|
|
5748
6038
|
function parseQoderCnPaths(filePath) {
|
|
5749
|
-
const parts = filePath.split(
|
|
6039
|
+
const parts = filePath.split(path15.sep);
|
|
5750
6040
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
5751
6041
|
let sessionId = "";
|
|
5752
6042
|
let projectName = "";
|
|
@@ -5755,19 +6045,19 @@ function parseQoderCnPaths(filePath) {
|
|
|
5755
6045
|
sessionId = parts[subagentsIdx - 1];
|
|
5756
6046
|
projectName = parts[subagentsIdx - 2];
|
|
5757
6047
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5758
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6048
|
+
configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
|
|
5759
6049
|
} else {
|
|
5760
6050
|
const filename = parts.at(-1) || "";
|
|
5761
|
-
sessionId =
|
|
6051
|
+
sessionId = path15.basename(filename, ".jsonl");
|
|
5762
6052
|
projectName = parts.at(-2) || "";
|
|
5763
6053
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5764
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6054
|
+
configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
|
|
5765
6055
|
}
|
|
5766
6056
|
return { configDir: configDir2, projectName, sessionId };
|
|
5767
6057
|
}
|
|
5768
6058
|
async function loadQoderCnModelNames(configDir2) {
|
|
5769
6059
|
try {
|
|
5770
|
-
const dynamicTextsPath =
|
|
6060
|
+
const dynamicTextsPath = path15.join(configDir2, ".auth", "dynamic-texts.json");
|
|
5771
6061
|
const content = await readFile9(dynamicTextsPath, "utf8");
|
|
5772
6062
|
const json = JSON.parse(content);
|
|
5773
6063
|
const texts = json.texts || {};
|
|
@@ -5785,7 +6075,7 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
5785
6075
|
}
|
|
5786
6076
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
5787
6077
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
5788
|
-
const segmentsPath =
|
|
6078
|
+
const segmentsPath = path15.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
5789
6079
|
const modelCalls = [];
|
|
5790
6080
|
try {
|
|
5791
6081
|
const files = await readdir6(segmentsPath);
|
|
@@ -5793,7 +6083,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
5793
6083
|
if (!file.endsWith(".jsonl")) {
|
|
5794
6084
|
continue;
|
|
5795
6085
|
}
|
|
5796
|
-
const content = await readFile9(
|
|
6086
|
+
const content = await readFile9(path15.join(segmentsPath, file), "utf8");
|
|
5797
6087
|
let currentTurnIsSubagent = false;
|
|
5798
6088
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
5799
6089
|
const raw = parseJsonLine(line);
|
|
@@ -5861,7 +6151,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
5861
6151
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
5862
6152
|
state.sessionId = sessionId;
|
|
5863
6153
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5864
|
-
project = projectContext.project || (cwd ?
|
|
6154
|
+
project = projectContext.project || (cwd ? path15.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
5865
6155
|
if (!ts) {
|
|
5866
6156
|
continue;
|
|
5867
6157
|
}
|
|
@@ -6290,28 +6580,28 @@ function isNoisePrompt(text) {
|
|
|
6290
6580
|
}
|
|
6291
6581
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6292
6582
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
6293
|
-
const isSubagent = filePath.includes(`${
|
|
6583
|
+
const isSubagent = filePath.includes(`${path15.sep}subagents${path15.sep}`);
|
|
6294
6584
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
6295
6585
|
let cwds = [];
|
|
6296
6586
|
for (const line of lines) {
|
|
6297
6587
|
const raw = parseJsonLine(line);
|
|
6298
6588
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6299
|
-
if (cwd &&
|
|
6589
|
+
if (cwd && path15.isAbsolute(cwd)) {
|
|
6300
6590
|
cwds.push(cwd);
|
|
6301
6591
|
}
|
|
6302
6592
|
}
|
|
6303
6593
|
if (isSubagent) {
|
|
6304
|
-
if (inherited?.cwd &&
|
|
6594
|
+
if (inherited?.cwd && path15.isAbsolute(inherited.cwd)) {
|
|
6305
6595
|
cwds = [inherited.cwd];
|
|
6306
6596
|
} else {
|
|
6307
|
-
const parentSessionPath =
|
|
6597
|
+
const parentSessionPath = path15.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
6308
6598
|
try {
|
|
6309
6599
|
const parentText = await readFile9(parentSessionPath, "utf8");
|
|
6310
6600
|
const parentCwds = [];
|
|
6311
6601
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
6312
6602
|
const raw = parseJsonLine(line);
|
|
6313
6603
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6314
|
-
if (cwd &&
|
|
6604
|
+
if (cwd && path15.isAbsolute(cwd)) {
|
|
6315
6605
|
parentCwds.push(cwd);
|
|
6316
6606
|
}
|
|
6317
6607
|
}
|
|
@@ -6323,7 +6613,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
6323
6613
|
}
|
|
6324
6614
|
}
|
|
6325
6615
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
6326
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
6616
|
+
const project = inherited?.project || (cwds.length > 0 ? path15.basename(cwds[0]) : root ? path15.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
|
|
6327
6617
|
return {
|
|
6328
6618
|
project,
|
|
6329
6619
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6332,15 +6622,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
6332
6622
|
async function gitRootFromCwds2(cwds) {
|
|
6333
6623
|
const seen = /* @__PURE__ */ new Set();
|
|
6334
6624
|
for (const cwd of cwds) {
|
|
6335
|
-
let current =
|
|
6625
|
+
let current = path15.resolve(cwd);
|
|
6336
6626
|
while (!seen.has(current)) {
|
|
6337
6627
|
seen.add(current);
|
|
6338
6628
|
try {
|
|
6339
|
-
await
|
|
6629
|
+
await stat7(path15.join(current, ".git"));
|
|
6340
6630
|
return current;
|
|
6341
6631
|
} catch {
|
|
6342
6632
|
}
|
|
6343
|
-
const parent =
|
|
6633
|
+
const parent = path15.dirname(current);
|
|
6344
6634
|
if (parent === current) {
|
|
6345
6635
|
break;
|
|
6346
6636
|
}
|
|
@@ -6351,12 +6641,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
6351
6641
|
}
|
|
6352
6642
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
6353
6643
|
for (const cwd of cwds) {
|
|
6354
|
-
let current =
|
|
6644
|
+
let current = path15.resolve(cwd);
|
|
6355
6645
|
while (true) {
|
|
6356
6646
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
6357
6647
|
return current;
|
|
6358
6648
|
}
|
|
6359
|
-
const parent =
|
|
6649
|
+
const parent = path15.dirname(current);
|
|
6360
6650
|
if (parent === current) {
|
|
6361
6651
|
break;
|
|
6362
6652
|
}
|
|
@@ -6366,14 +6656,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
6366
6656
|
return void 0;
|
|
6367
6657
|
}
|
|
6368
6658
|
function encodeQoderCnProjectPath(value) {
|
|
6369
|
-
return
|
|
6659
|
+
return path15.resolve(value).split(path15.sep).join("-").replace(/_/g, "-");
|
|
6370
6660
|
}
|
|
6371
6661
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
6372
|
-
const projectDir =
|
|
6373
|
-
const home = options ?
|
|
6662
|
+
const projectDir = path15.basename(path15.dirname(filePath));
|
|
6663
|
+
const home = options ? path15.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
|
|
6374
6664
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
6375
6665
|
if (resolved) {
|
|
6376
|
-
return
|
|
6666
|
+
return path15.basename(resolved);
|
|
6377
6667
|
}
|
|
6378
6668
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
6379
6669
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -6398,7 +6688,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
6398
6688
|
if (!entry.isDirectory()) {
|
|
6399
6689
|
continue;
|
|
6400
6690
|
}
|
|
6401
|
-
const candidate =
|
|
6691
|
+
const candidate = path15.join(current, entry.name);
|
|
6402
6692
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
6403
6693
|
if (encoded === projectDir) {
|
|
6404
6694
|
return candidate;
|
|
@@ -6443,9 +6733,9 @@ function hookConfig5() {
|
|
|
6443
6733
|
function qoderCnConfigDir(home, env) {
|
|
6444
6734
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
6445
6735
|
if (override && override.trim()) {
|
|
6446
|
-
return
|
|
6736
|
+
return path15.resolve(override);
|
|
6447
6737
|
}
|
|
6448
|
-
return
|
|
6738
|
+
return path15.join(home, ".qoder-cn");
|
|
6449
6739
|
}
|
|
6450
6740
|
function createQoderCnAdapter() {
|
|
6451
6741
|
return {
|
|
@@ -6457,27 +6747,27 @@ function createQoderCnAdapter() {
|
|
|
6457
6747
|
return qoderCnConfigDir(home, env);
|
|
6458
6748
|
},
|
|
6459
6749
|
installedPath(home, env) {
|
|
6460
|
-
return
|
|
6750
|
+
return path15.join(qoderCnConfigDir(home, env), "settings.json");
|
|
6461
6751
|
},
|
|
6462
6752
|
async isInstalled(home, env) {
|
|
6463
6753
|
return isHooksJsonInstalled(
|
|
6464
|
-
|
|
6754
|
+
path15.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6465
6755
|
"vibetime hook --agent qoder-cn"
|
|
6466
6756
|
);
|
|
6467
6757
|
},
|
|
6468
6758
|
installEntries(home, env) {
|
|
6469
6759
|
return [{
|
|
6470
6760
|
kind: "hooks-json",
|
|
6471
|
-
path:
|
|
6761
|
+
path: path15.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6472
6762
|
content: hookConfig5()
|
|
6473
6763
|
}];
|
|
6474
6764
|
},
|
|
6475
6765
|
sourcePaths(home, env) {
|
|
6476
6766
|
const base = qoderCnConfigDir(home, env);
|
|
6477
6767
|
return [
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6768
|
+
path15.join(base, "projects"),
|
|
6769
|
+
path15.join(base, ".qoder.json"),
|
|
6770
|
+
path15.join(home, ".qoder.json")
|
|
6481
6771
|
];
|
|
6482
6772
|
},
|
|
6483
6773
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -6485,11 +6775,11 @@ function createQoderCnAdapter() {
|
|
|
6485
6775
|
}
|
|
6486
6776
|
|
|
6487
6777
|
// src/adapters/qoder.ts
|
|
6488
|
-
import { readdir as readdir7, readFile as readFile10, stat as
|
|
6778
|
+
import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
|
|
6489
6779
|
import os8 from "node:os";
|
|
6490
|
-
import
|
|
6780
|
+
import path16 from "node:path";
|
|
6491
6781
|
function parseQoderPaths(filePath) {
|
|
6492
|
-
const parts = filePath.split(
|
|
6782
|
+
const parts = filePath.split(path16.sep);
|
|
6493
6783
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
6494
6784
|
let sessionId = "";
|
|
6495
6785
|
let projectName = "";
|
|
@@ -6498,19 +6788,19 @@ function parseQoderPaths(filePath) {
|
|
|
6498
6788
|
sessionId = parts[subagentsIdx - 1];
|
|
6499
6789
|
projectName = parts[subagentsIdx - 2];
|
|
6500
6790
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6501
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6791
|
+
configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
|
|
6502
6792
|
} else {
|
|
6503
6793
|
const filename = parts.at(-1) || "";
|
|
6504
|
-
sessionId =
|
|
6794
|
+
sessionId = path16.basename(filename, ".jsonl");
|
|
6505
6795
|
projectName = parts.at(-2) || "";
|
|
6506
6796
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6507
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6797
|
+
configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
|
|
6508
6798
|
}
|
|
6509
6799
|
return { configDir: configDir2, projectName, sessionId };
|
|
6510
6800
|
}
|
|
6511
6801
|
async function loadQoderModelNames(configDir2) {
|
|
6512
6802
|
try {
|
|
6513
|
-
const dynamicTextsPath =
|
|
6803
|
+
const dynamicTextsPath = path16.join(configDir2, ".auth", "dynamic-texts.json");
|
|
6514
6804
|
const content = await readFile10(dynamicTextsPath, "utf8");
|
|
6515
6805
|
const json = JSON.parse(content);
|
|
6516
6806
|
const texts = json.texts || {};
|
|
@@ -6528,7 +6818,7 @@ async function loadQoderModelNames(configDir2) {
|
|
|
6528
6818
|
}
|
|
6529
6819
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
6530
6820
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
6531
|
-
const segmentsPath =
|
|
6821
|
+
const segmentsPath = path16.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
6532
6822
|
const modelCalls = [];
|
|
6533
6823
|
try {
|
|
6534
6824
|
const files = await readdir7(segmentsPath);
|
|
@@ -6536,7 +6826,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
6536
6826
|
if (!file.endsWith(".jsonl")) {
|
|
6537
6827
|
continue;
|
|
6538
6828
|
}
|
|
6539
|
-
const content = await readFile10(
|
|
6829
|
+
const content = await readFile10(path16.join(segmentsPath, file), "utf8");
|
|
6540
6830
|
let currentTurnIsSubagent = false;
|
|
6541
6831
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
6542
6832
|
const raw = parseJsonLine(line);
|
|
@@ -6604,7 +6894,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
6604
6894
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
6605
6895
|
state.sessionId = sessionId;
|
|
6606
6896
|
cwd = stringField(raw, "cwd") || cwd;
|
|
6607
|
-
project = projectContext.project || (cwd ?
|
|
6897
|
+
project = projectContext.project || (cwd ? path16.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
6608
6898
|
if (!ts) {
|
|
6609
6899
|
continue;
|
|
6610
6900
|
}
|
|
@@ -6999,28 +7289,28 @@ function qoderExtractText(value) {
|
|
|
6999
7289
|
}
|
|
7000
7290
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
7001
7291
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
7002
|
-
const isSubagent = filePath.includes(`${
|
|
7292
|
+
const isSubagent = filePath.includes(`${path16.sep}subagents${path16.sep}`);
|
|
7003
7293
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
7004
7294
|
let cwds = [];
|
|
7005
7295
|
for (const line of lines) {
|
|
7006
7296
|
const raw = parseJsonLine(line);
|
|
7007
7297
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7008
|
-
if (cwd &&
|
|
7298
|
+
if (cwd && path16.isAbsolute(cwd)) {
|
|
7009
7299
|
cwds.push(cwd);
|
|
7010
7300
|
}
|
|
7011
7301
|
}
|
|
7012
7302
|
if (isSubagent) {
|
|
7013
|
-
if (inherited?.cwd &&
|
|
7303
|
+
if (inherited?.cwd && path16.isAbsolute(inherited.cwd)) {
|
|
7014
7304
|
cwds = [inherited.cwd];
|
|
7015
7305
|
} else {
|
|
7016
|
-
const parentSessionPath =
|
|
7306
|
+
const parentSessionPath = path16.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
7017
7307
|
try {
|
|
7018
7308
|
const parentText = await readFile10(parentSessionPath, "utf8");
|
|
7019
7309
|
const parentCwds = [];
|
|
7020
7310
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
7021
7311
|
const raw = parseJsonLine(line);
|
|
7022
7312
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7023
|
-
if (cwd &&
|
|
7313
|
+
if (cwd && path16.isAbsolute(cwd)) {
|
|
7024
7314
|
parentCwds.push(cwd);
|
|
7025
7315
|
}
|
|
7026
7316
|
}
|
|
@@ -7032,7 +7322,7 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
7032
7322
|
}
|
|
7033
7323
|
}
|
|
7034
7324
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
7035
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
7325
|
+
const project = inherited?.project || (cwds.length > 0 ? path16.basename(cwds[0]) : root ? path16.basename(root) : await qoderProjectFromFilePath(filePath, options));
|
|
7036
7326
|
return {
|
|
7037
7327
|
project,
|
|
7038
7328
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -7041,15 +7331,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
7041
7331
|
async function gitRootFromCwds3(cwds) {
|
|
7042
7332
|
const seen = /* @__PURE__ */ new Set();
|
|
7043
7333
|
for (const cwd of cwds) {
|
|
7044
|
-
let current =
|
|
7334
|
+
let current = path16.resolve(cwd);
|
|
7045
7335
|
while (!seen.has(current)) {
|
|
7046
7336
|
seen.add(current);
|
|
7047
7337
|
try {
|
|
7048
|
-
await
|
|
7338
|
+
await stat8(path16.join(current, ".git"));
|
|
7049
7339
|
return current;
|
|
7050
7340
|
} catch {
|
|
7051
7341
|
}
|
|
7052
|
-
const parent =
|
|
7342
|
+
const parent = path16.dirname(current);
|
|
7053
7343
|
if (parent === current) {
|
|
7054
7344
|
break;
|
|
7055
7345
|
}
|
|
@@ -7060,12 +7350,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
7060
7350
|
}
|
|
7061
7351
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
7062
7352
|
for (const cwd of cwds) {
|
|
7063
|
-
let current =
|
|
7353
|
+
let current = path16.resolve(cwd);
|
|
7064
7354
|
while (true) {
|
|
7065
7355
|
if (encodeQoderProjectPath(current) === projectDir) {
|
|
7066
7356
|
return current;
|
|
7067
7357
|
}
|
|
7068
|
-
const parent =
|
|
7358
|
+
const parent = path16.dirname(current);
|
|
7069
7359
|
if (parent === current) {
|
|
7070
7360
|
break;
|
|
7071
7361
|
}
|
|
@@ -7075,10 +7365,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
7075
7365
|
return void 0;
|
|
7076
7366
|
}
|
|
7077
7367
|
function encodeQoderProjectPath(value) {
|
|
7078
|
-
return
|
|
7368
|
+
return path16.resolve(value).split(path16.sep).join("-").replace(/_/g, "-");
|
|
7079
7369
|
}
|
|
7080
7370
|
function rawQoderProjectPath(value) {
|
|
7081
|
-
return
|
|
7371
|
+
return path16.resolve(value).split(path16.sep).join("-");
|
|
7082
7372
|
}
|
|
7083
7373
|
function qoderEncodedVariants(value) {
|
|
7084
7374
|
const raw = rawQoderProjectPath(value);
|
|
@@ -7094,11 +7384,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
7094
7384
|
return void 0;
|
|
7095
7385
|
}
|
|
7096
7386
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
7097
|
-
const projectDir =
|
|
7098
|
-
const home = options ?
|
|
7387
|
+
const projectDir = path16.basename(path16.dirname(filePath));
|
|
7388
|
+
const home = options ? path16.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
|
|
7099
7389
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
7100
7390
|
if (resolved) {
|
|
7101
|
-
return
|
|
7391
|
+
return path16.basename(resolved);
|
|
7102
7392
|
}
|
|
7103
7393
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
7104
7394
|
if (suffix) {
|
|
@@ -7124,7 +7414,7 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
7124
7414
|
if (!entry.isDirectory()) {
|
|
7125
7415
|
continue;
|
|
7126
7416
|
}
|
|
7127
|
-
const candidate =
|
|
7417
|
+
const candidate = path16.join(current, entry.name);
|
|
7128
7418
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
7129
7419
|
if (candidateVariants.includes(projectDir)) {
|
|
7130
7420
|
return candidate;
|
|
@@ -7169,9 +7459,9 @@ function hookConfig6() {
|
|
|
7169
7459
|
function qoderConfigDir(home, env) {
|
|
7170
7460
|
const override = env?.QODER_CONFIG_DIR;
|
|
7171
7461
|
if (override && override.trim()) {
|
|
7172
|
-
return
|
|
7462
|
+
return path16.resolve(override);
|
|
7173
7463
|
}
|
|
7174
|
-
return
|
|
7464
|
+
return path16.join(home, ".qoder");
|
|
7175
7465
|
}
|
|
7176
7466
|
function createQoderAdapter() {
|
|
7177
7467
|
return {
|
|
@@ -7183,27 +7473,27 @@ function createQoderAdapter() {
|
|
|
7183
7473
|
return qoderConfigDir(home, env);
|
|
7184
7474
|
},
|
|
7185
7475
|
installedPath(home, env) {
|
|
7186
|
-
return
|
|
7476
|
+
return path16.join(qoderConfigDir(home, env), "settings.json");
|
|
7187
7477
|
},
|
|
7188
7478
|
async isInstalled(home, env) {
|
|
7189
7479
|
return isHooksJsonInstalled(
|
|
7190
|
-
|
|
7480
|
+
path16.join(qoderConfigDir(home, env), "settings.json"),
|
|
7191
7481
|
"vibetime hook --agent qoder"
|
|
7192
7482
|
);
|
|
7193
7483
|
},
|
|
7194
7484
|
installEntries(home, env) {
|
|
7195
7485
|
return [{
|
|
7196
7486
|
kind: "hooks-json",
|
|
7197
|
-
path:
|
|
7487
|
+
path: path16.join(qoderConfigDir(home, env), "settings.json"),
|
|
7198
7488
|
content: hookConfig6()
|
|
7199
7489
|
}];
|
|
7200
7490
|
},
|
|
7201
7491
|
sourcePaths(home, env) {
|
|
7202
7492
|
const base = qoderConfigDir(home, env);
|
|
7203
7493
|
return [
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7494
|
+
path16.join(base, "projects"),
|
|
7495
|
+
path16.join(base, ".qoder.json"),
|
|
7496
|
+
path16.join(home, ".qoder.json")
|
|
7207
7497
|
];
|
|
7208
7498
|
},
|
|
7209
7499
|
parseSessionFile: parseQoderSessionFile
|
|
@@ -7238,21 +7528,21 @@ function normalizeId(id) {
|
|
|
7238
7528
|
}
|
|
7239
7529
|
|
|
7240
7530
|
// src/adapters/workbuddy.ts
|
|
7241
|
-
import { readFile as readFile11, readdir as readdir8, stat as
|
|
7242
|
-
import
|
|
7531
|
+
import { readFile as readFile11, readdir as readdir8, stat as stat9 } from "node:fs/promises";
|
|
7532
|
+
import path17 from "node:path";
|
|
7243
7533
|
init_fs();
|
|
7244
7534
|
function workbuddyProjectsDir(home, env) {
|
|
7245
7535
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
7246
7536
|
if (override && override.trim()) {
|
|
7247
|
-
return
|
|
7537
|
+
return path17.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
7248
7538
|
}
|
|
7249
|
-
return
|
|
7539
|
+
return path17.join(home, ".workbuddy", "projects");
|
|
7250
7540
|
}
|
|
7251
7541
|
function projectFromCwd(cwd, fallback) {
|
|
7252
7542
|
if (!cwd) {
|
|
7253
7543
|
return fallback;
|
|
7254
7544
|
}
|
|
7255
|
-
return
|
|
7545
|
+
return path17.basename(cwd) || fallback;
|
|
7256
7546
|
}
|
|
7257
7547
|
function sourceHash(filePath) {
|
|
7258
7548
|
return `sha256:${createStableHash(filePath)}`;
|
|
@@ -7354,8 +7644,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
7354
7644
|
}
|
|
7355
7645
|
const events = [];
|
|
7356
7646
|
const first = lines[0].record;
|
|
7357
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
7358
|
-
const fallbackProject =
|
|
7647
|
+
const sessionId = stringField(first, "sessionId") || path17.basename(filePath, ".jsonl");
|
|
7648
|
+
const fallbackProject = path17.basename(path17.dirname(filePath));
|
|
7359
7649
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
7360
7650
|
const project = projectFromCwd(cwd, fallbackProject);
|
|
7361
7651
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
@@ -7529,12 +7819,12 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
7529
7819
|
if (!project.isDirectory()) {
|
|
7530
7820
|
continue;
|
|
7531
7821
|
}
|
|
7532
|
-
const projectDir =
|
|
7822
|
+
const projectDir = path17.join(base, project.name);
|
|
7533
7823
|
const entries = await readdir8(projectDir, { withFileTypes: true });
|
|
7534
7824
|
for (const entry of entries) {
|
|
7535
7825
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
7536
|
-
const filePath =
|
|
7537
|
-
const info = await
|
|
7826
|
+
const filePath = path17.join(projectDir, entry.name);
|
|
7827
|
+
const info = await stat9(filePath);
|
|
7538
7828
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
7539
7829
|
}
|
|
7540
7830
|
}
|
|
@@ -7571,26 +7861,26 @@ function createWorkbuddyAdapter() {
|
|
|
7571
7861
|
|
|
7572
7862
|
// src/adapters/zcode.ts
|
|
7573
7863
|
import { execFile } from "node:child_process";
|
|
7574
|
-
import { readFile as readFile12, stat as
|
|
7575
|
-
import
|
|
7864
|
+
import { readFile as readFile12, stat as stat10 } from "node:fs/promises";
|
|
7865
|
+
import path18 from "node:path";
|
|
7576
7866
|
import { promisify as promisify2 } from "node:util";
|
|
7577
7867
|
init_fs();
|
|
7578
7868
|
var execFileAsync = promisify2(execFile);
|
|
7579
7869
|
function zcodeCliDir(home, env) {
|
|
7580
7870
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
7581
7871
|
if (override && override.trim()) {
|
|
7582
|
-
return
|
|
7872
|
+
return path18.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
7583
7873
|
}
|
|
7584
|
-
return
|
|
7874
|
+
return path18.join(home, ".zcode", "cli");
|
|
7585
7875
|
}
|
|
7586
7876
|
function zcodeDbPath(home, env) {
|
|
7587
|
-
return
|
|
7877
|
+
return path18.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
7588
7878
|
}
|
|
7589
7879
|
var providerNameCache = null;
|
|
7590
7880
|
async function loadProviderNames(configPath2) {
|
|
7591
7881
|
let fileMtime = 0;
|
|
7592
7882
|
try {
|
|
7593
|
-
const info = await
|
|
7883
|
+
const info = await stat10(configPath2);
|
|
7594
7884
|
fileMtime = info.mtimeMs;
|
|
7595
7885
|
} catch {
|
|
7596
7886
|
return /* @__PURE__ */ new Map();
|
|
@@ -7618,7 +7908,7 @@ function sourceHash2(filePath) {
|
|
|
7618
7908
|
return `sha256:${createStableHash(filePath)}`;
|
|
7619
7909
|
}
|
|
7620
7910
|
function projectFromDirectory(directory) {
|
|
7621
|
-
return directory ?
|
|
7911
|
+
return directory ? path18.basename(directory) || "zcode" : "zcode";
|
|
7622
7912
|
}
|
|
7623
7913
|
function isoFromMs(value) {
|
|
7624
7914
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
@@ -7774,16 +8064,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7774
8064
|
if (rows.length === 0) {
|
|
7775
8065
|
return [];
|
|
7776
8066
|
}
|
|
7777
|
-
let candidate =
|
|
8067
|
+
let candidate = path18.resolve(filePath);
|
|
7778
8068
|
let configPath2 = "";
|
|
7779
8069
|
for (let i = 0; i < 12; i++) {
|
|
7780
|
-
const probe =
|
|
8070
|
+
const probe = path18.join(candidate, ".zcode", "v2", "config.json");
|
|
7781
8071
|
try {
|
|
7782
|
-
await
|
|
8072
|
+
await stat10(probe);
|
|
7783
8073
|
configPath2 = probe;
|
|
7784
8074
|
break;
|
|
7785
8075
|
} catch {
|
|
7786
|
-
const parent =
|
|
8076
|
+
const parent = path18.dirname(candidate);
|
|
7787
8077
|
if (parent === candidate) break;
|
|
7788
8078
|
candidate = parent;
|
|
7789
8079
|
}
|
|
@@ -7999,9 +8289,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7999
8289
|
}
|
|
8000
8290
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
8001
8291
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
8002
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
8292
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path18.join(candidate, "db", "db.sqlite");
|
|
8003
8293
|
try {
|
|
8004
|
-
const info = await
|
|
8294
|
+
const info = await stat10(filePath);
|
|
8005
8295
|
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
8006
8296
|
} catch {
|
|
8007
8297
|
return [];
|
|
@@ -8473,15 +8763,15 @@ function hookCommandFromGroup(group) {
|
|
|
8473
8763
|
import { randomUUID } from "node:crypto";
|
|
8474
8764
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8475
8765
|
import { homedir, hostname } from "node:os";
|
|
8476
|
-
import
|
|
8766
|
+
import path19 from "node:path";
|
|
8477
8767
|
function configDir(home = homedir()) {
|
|
8478
|
-
return
|
|
8768
|
+
return path19.join(home, ".vibetime");
|
|
8479
8769
|
}
|
|
8480
8770
|
function configPath(home = homedir()) {
|
|
8481
|
-
return
|
|
8771
|
+
return path19.join(configDir(home), "config.json");
|
|
8482
8772
|
}
|
|
8483
8773
|
function machineIdPath(home = homedir()) {
|
|
8484
|
-
return
|
|
8774
|
+
return path19.join(configDir(home), "machine-id");
|
|
8485
8775
|
}
|
|
8486
8776
|
function readConfig(home = homedir()) {
|
|
8487
8777
|
const file = configPath(home);
|
|
@@ -8528,15 +8818,15 @@ function defaultMachineName() {
|
|
|
8528
8818
|
init_fs();
|
|
8529
8819
|
|
|
8530
8820
|
// src/lib/logger.ts
|
|
8531
|
-
import { appendFile, mkdir as mkdir4, rename, stat as
|
|
8821
|
+
import { appendFile, mkdir as mkdir4, rename, stat as stat11 } from "node:fs/promises";
|
|
8532
8822
|
import { homedir as homedir2 } from "node:os";
|
|
8533
|
-
import
|
|
8823
|
+
import path20 from "node:path";
|
|
8534
8824
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
8535
8825
|
function logDir(home = homedir2()) {
|
|
8536
|
-
return
|
|
8826
|
+
return path20.join(home, ".vibetime", "logs");
|
|
8537
8827
|
}
|
|
8538
8828
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
8539
|
-
return
|
|
8829
|
+
return path20.join(logDir(home), name);
|
|
8540
8830
|
}
|
|
8541
8831
|
function serializeError(error) {
|
|
8542
8832
|
if (error instanceof Error) {
|
|
@@ -8546,7 +8836,7 @@ function serializeError(error) {
|
|
|
8546
8836
|
}
|
|
8547
8837
|
async function rotateIfNeeded(file) {
|
|
8548
8838
|
try {
|
|
8549
|
-
const info = await
|
|
8839
|
+
const info = await stat11(file);
|
|
8550
8840
|
if (info.size > MAX_BYTES) {
|
|
8551
8841
|
await rename(file, `${file}.1`).catch(() => {
|
|
8552
8842
|
});
|
|
@@ -8711,8 +9001,8 @@ function buildHeaders(token, machine) {
|
|
|
8711
9001
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
8712
9002
|
};
|
|
8713
9003
|
}
|
|
8714
|
-
function joinUrl(base,
|
|
8715
|
-
return new URL(
|
|
9004
|
+
function joinUrl(base, path22) {
|
|
9005
|
+
return new URL(path22, base.endsWith("/") ? base : `${base}/`).toString();
|
|
8716
9006
|
}
|
|
8717
9007
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
8718
9008
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -8777,7 +9067,7 @@ async function deleteMachine(remote, id) {
|
|
|
8777
9067
|
}
|
|
8778
9068
|
|
|
8779
9069
|
// src/lib/types.ts
|
|
8780
|
-
var BACKFILL_STATE_SCHEMA_VERSION =
|
|
9070
|
+
var BACKFILL_STATE_SCHEMA_VERSION = 6;
|
|
8781
9071
|
|
|
8782
9072
|
// src/cli.ts
|
|
8783
9073
|
function createRegistry() {
|
|
@@ -8802,7 +9092,7 @@ var defaultContext = {
|
|
|
8802
9092
|
stdout: process.stdout,
|
|
8803
9093
|
stderr: process.stderr,
|
|
8804
9094
|
fetch: globalThis.fetch,
|
|
8805
|
-
spawn
|
|
9095
|
+
spawn: spawn2
|
|
8806
9096
|
};
|
|
8807
9097
|
async function run(argv, context = {}) {
|
|
8808
9098
|
const ctx = { ...defaultContext, ...context };
|
|
@@ -8953,7 +9243,9 @@ async function fetchLatestVersion() {
|
|
|
8953
9243
|
headers: { Accept: "application/json" },
|
|
8954
9244
|
signal: AbortSignal.timeout(1e4)
|
|
8955
9245
|
});
|
|
8956
|
-
if (!response.ok)
|
|
9246
|
+
if (!response.ok) {
|
|
9247
|
+
return null;
|
|
9248
|
+
}
|
|
8957
9249
|
const data = await response.json();
|
|
8958
9250
|
return typeof data.version === "string" ? data.version : null;
|
|
8959
9251
|
} catch {
|
|
@@ -8966,8 +9258,12 @@ function compareVersions(a, b) {
|
|
|
8966
9258
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
8967
9259
|
const na = pa[i] ?? 0;
|
|
8968
9260
|
const nb = pb[i] ?? 0;
|
|
8969
|
-
if (na > nb)
|
|
8970
|
-
|
|
9261
|
+
if (na > nb) {
|
|
9262
|
+
return 1;
|
|
9263
|
+
}
|
|
9264
|
+
if (na < nb) {
|
|
9265
|
+
return -1;
|
|
9266
|
+
}
|
|
8971
9267
|
}
|
|
8972
9268
|
return 0;
|
|
8973
9269
|
}
|
|
@@ -9070,15 +9366,35 @@ async function syncLocalTriggerCommand(options, ctx, _registry) {
|
|
|
9070
9366
|
`);
|
|
9071
9367
|
return 0;
|
|
9072
9368
|
}
|
|
9073
|
-
const
|
|
9074
|
-
|
|
9075
|
-
|
|
9369
|
+
const acquired = await acquireSyncLocalLock(lockPath, {
|
|
9370
|
+
pid: process.pid,
|
|
9371
|
+
startedAt: now
|
|
9372
|
+
});
|
|
9373
|
+
if (!acquired) {
|
|
9374
|
+
const current = await readSyncLocalLock(lockPath);
|
|
9375
|
+
if (options.json) {
|
|
9376
|
+
write(ctx.stdout, `${JSON.stringify({
|
|
9377
|
+
status: "already-running",
|
|
9378
|
+
...current ? { pid: current.pid, startedAt: current.startedAt } : {}
|
|
9379
|
+
}, null, 2)}
|
|
9380
|
+
`);
|
|
9381
|
+
}
|
|
9382
|
+
return 0;
|
|
9383
|
+
}
|
|
9384
|
+
try {
|
|
9385
|
+
const child = spawnSyncLocalRunner({ options, ctx, home, lockPath, statePath, triggeredAt: now });
|
|
9386
|
+
if (typeof child.pid !== "number") {
|
|
9387
|
+
throw new TypeError("Could not start background sync-local runner");
|
|
9388
|
+
}
|
|
9389
|
+
state.lastTriggeredAt = now;
|
|
9390
|
+
state.pid = child.pid;
|
|
9391
|
+
await writeSyncLocalTriggerState(statePath, state);
|
|
9392
|
+
await writeSyncLocalLock(lockPath, { pid: child.pid, startedAt: now });
|
|
9393
|
+
return 0;
|
|
9394
|
+
} catch (error) {
|
|
9395
|
+
await clearSyncLocalLock(lockPath);
|
|
9396
|
+
throw error;
|
|
9076
9397
|
}
|
|
9077
|
-
state.lastTriggeredAt = now;
|
|
9078
|
-
state.pid = child.pid;
|
|
9079
|
-
await writeSyncLocalTriggerState(statePath, state);
|
|
9080
|
-
await writeSyncLocalLock(lockPath, { pid: child.pid, startedAt: now });
|
|
9081
|
-
return 0;
|
|
9082
9398
|
}
|
|
9083
9399
|
async function syncLocalRunnerCommand(options, ctx, _registry) {
|
|
9084
9400
|
const home = resolveHome3(options, ctx);
|
|
@@ -9284,7 +9600,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
9284
9600
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
9285
9601
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
9286
9602
|
return Promise.all(files.map(async (filePath) => {
|
|
9287
|
-
const info = await
|
|
9603
|
+
const info = await stat12(filePath);
|
|
9288
9604
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
9289
9605
|
}));
|
|
9290
9606
|
}
|
|
@@ -9597,13 +9913,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
9597
9913
|
});
|
|
9598
9914
|
}
|
|
9599
9915
|
function backfillIncrementalStatePath(home) {
|
|
9600
|
-
return
|
|
9916
|
+
return path21.join(home, ".vibetime", "backfill-state.json");
|
|
9601
9917
|
}
|
|
9602
9918
|
function syncLocalTriggerStatePath(home) {
|
|
9603
|
-
return
|
|
9919
|
+
return path21.join(home, ".vibetime", "sync-local-trigger.json");
|
|
9604
9920
|
}
|
|
9605
9921
|
function syncLocalTriggerLockPath(home) {
|
|
9606
|
-
return
|
|
9922
|
+
return path21.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
9607
9923
|
}
|
|
9608
9924
|
function backfillRemoteKey(baseUrl) {
|
|
9609
9925
|
try {
|
|
@@ -9665,7 +9981,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
9665
9981
|
}
|
|
9666
9982
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
9667
9983
|
const statePath = backfillIncrementalStatePath(home);
|
|
9668
|
-
await mkdir5(
|
|
9984
|
+
await mkdir5(path21.dirname(statePath), { recursive: true });
|
|
9669
9985
|
await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
|
|
9670
9986
|
`, "utf8");
|
|
9671
9987
|
}
|
|
@@ -9714,7 +10030,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
9714
10030
|
return nextState;
|
|
9715
10031
|
}
|
|
9716
10032
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
9717
|
-
await mkdir5(
|
|
10033
|
+
await mkdir5(path21.dirname(statePath), { recursive: true });
|
|
9718
10034
|
const tmpPath = `${statePath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
9719
10035
|
await writeFile4(tmpPath, `${JSON.stringify(state, null, 2)}
|
|
9720
10036
|
`, "utf8");
|
|
@@ -9731,10 +10047,28 @@ async function readSyncLocalLock(lockPath) {
|
|
|
9731
10047
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
9732
10048
|
}
|
|
9733
10049
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
9734
|
-
await mkdir5(
|
|
10050
|
+
await mkdir5(path21.dirname(lockPath), { recursive: true });
|
|
9735
10051
|
await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
9736
10052
|
`, "utf8");
|
|
9737
10053
|
}
|
|
10054
|
+
async function acquireSyncLocalLock(lockPath, lock) {
|
|
10055
|
+
await mkdir5(path21.dirname(lockPath), { recursive: true });
|
|
10056
|
+
try {
|
|
10057
|
+
const handle = await open(lockPath, "wx");
|
|
10058
|
+
try {
|
|
10059
|
+
await handle.writeFile(`${JSON.stringify(lock, null, 2)}
|
|
10060
|
+
`, "utf8");
|
|
10061
|
+
} finally {
|
|
10062
|
+
await handle.close();
|
|
10063
|
+
}
|
|
10064
|
+
return true;
|
|
10065
|
+
} catch (error) {
|
|
10066
|
+
if (error.code === "EEXIST") {
|
|
10067
|
+
return false;
|
|
10068
|
+
}
|
|
10069
|
+
throw error;
|
|
10070
|
+
}
|
|
10071
|
+
}
|
|
9738
10072
|
async function clearSyncLocalLock(lockPath) {
|
|
9739
10073
|
try {
|
|
9740
10074
|
await rm(lockPath, { force: true });
|
|
@@ -9798,10 +10132,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
9798
10132
|
if (cliPath.endsWith(".ts")) {
|
|
9799
10133
|
return ["--import", "tsx", cliPath];
|
|
9800
10134
|
}
|
|
9801
|
-
return [
|
|
10135
|
+
return [path21.resolve(path21.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
9802
10136
|
}
|
|
9803
10137
|
function resolveHome3(options, ctx) {
|
|
9804
|
-
return
|
|
10138
|
+
return path21.resolve(stringOption(options.home) || ctx.env.HOME || os9.homedir());
|
|
9805
10139
|
}
|
|
9806
10140
|
function requestedTargets(options) {
|
|
9807
10141
|
const value = options.target || options.targets;
|