@yhong91/vibetime 0.1.16 → 0.1.18
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 +711 -328
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -158,10 +158,11 @@ var init_fs = __esm({
|
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
// src/cli.ts
|
|
161
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
162
|
-
import {
|
|
163
|
-
import
|
|
164
|
-
import
|
|
161
|
+
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
162
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
163
|
+
import { mkdir as mkdir5, open, rename as rename2, rm, stat as stat12, writeFile as writeFile4 } from "node:fs/promises";
|
|
164
|
+
import os9 from "node:os";
|
|
165
|
+
import path21 from "node:path";
|
|
165
166
|
import { fileURLToPath } from "node:url";
|
|
166
167
|
|
|
167
168
|
// ../shared/src/index.ts
|
|
@@ -295,6 +296,12 @@ function validateMetricBag(value, errors, prefix) {
|
|
|
295
296
|
}
|
|
296
297
|
for (const key of Object.keys(value)) {
|
|
297
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
|
+
}
|
|
298
305
|
if (metric !== void 0 && (typeof metric !== "number" || !Number.isFinite(metric))) {
|
|
299
306
|
errors.push(`${prefix}.${key} must be a finite number`);
|
|
300
307
|
}
|
|
@@ -977,10 +984,10 @@ var cac = (name = "") => new CAC(name);
|
|
|
977
984
|
|
|
978
985
|
// src/adapters/agy.ts
|
|
979
986
|
import { exec } from "node:child_process";
|
|
980
|
-
import {
|
|
987
|
+
import { mkdir as mkdir2, readFile as readFile2, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
981
988
|
import * as https from "node:https";
|
|
982
989
|
import * as os from "node:os";
|
|
983
|
-
import
|
|
990
|
+
import path5 from "node:path";
|
|
984
991
|
import { promisify } from "node:util";
|
|
985
992
|
|
|
986
993
|
// src/lib/activity.ts
|
|
@@ -1195,7 +1202,7 @@ function countTextLines(text) {
|
|
|
1195
1202
|
}
|
|
1196
1203
|
|
|
1197
1204
|
// src/lib/constants.ts
|
|
1198
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
1205
|
+
var PACKAGE_VERSION = true ? "0.1.18" : "0.1.1";
|
|
1199
1206
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
1200
1207
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
1201
1208
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -1432,6 +1439,254 @@ var SessionParserState = class {
|
|
|
1432
1439
|
}
|
|
1433
1440
|
};
|
|
1434
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
|
+
|
|
1435
1690
|
// src/adapters/agy.ts
|
|
1436
1691
|
var execAsync = promisify(exec);
|
|
1437
1692
|
var cachedRpcConnections = null;
|
|
@@ -1651,7 +1906,7 @@ function detectModel(content, currentModel) {
|
|
|
1651
1906
|
return currentModel;
|
|
1652
1907
|
}
|
|
1653
1908
|
function resolveModelName(text) {
|
|
1654
|
-
const cleaned = text.
|
|
1909
|
+
const cleaned = text.replaceAll(/\s*\([^)]*\)\s*/g, " ").trim();
|
|
1655
1910
|
if (cleaned.includes("Claude Opus 4.7") || cleaned.includes("claude-opus-4.7")) {
|
|
1656
1911
|
return "claude-opus-4.7";
|
|
1657
1912
|
}
|
|
@@ -1720,11 +1975,11 @@ function usageMetadataFromGenerator(item) {
|
|
|
1720
1975
|
};
|
|
1721
1976
|
}
|
|
1722
1977
|
async function readAgyModelSetting(filePath) {
|
|
1723
|
-
const settingsPath =
|
|
1978
|
+
const settingsPath = path5.resolve(path5.dirname(filePath), "../../../..", "settings.json");
|
|
1724
1979
|
try {
|
|
1725
1980
|
const [text, info] = await Promise.all([
|
|
1726
1981
|
readFile2(settingsPath, "utf8"),
|
|
1727
|
-
|
|
1982
|
+
stat3(settingsPath)
|
|
1728
1983
|
]);
|
|
1729
1984
|
const configured = JSON.parse(text)?.model;
|
|
1730
1985
|
const rawModel = typeof configured === "string" ? configured : null;
|
|
@@ -1747,16 +2002,16 @@ function extractProjectContext(rawLines) {
|
|
|
1747
2002
|
if (args.DirectoryPath) {
|
|
1748
2003
|
candidate = normalizePath(args.DirectoryPath);
|
|
1749
2004
|
} else if (args.AbsolutePath) {
|
|
1750
|
-
candidate =
|
|
2005
|
+
candidate = path5.dirname(normalizePath(args.AbsolutePath));
|
|
1751
2006
|
} else if (args.SearchPath) {
|
|
1752
2007
|
candidate = normalizePath(args.SearchPath);
|
|
1753
2008
|
} else if (args.TargetFile) {
|
|
1754
|
-
candidate =
|
|
2009
|
+
candidate = path5.dirname(normalizePath(args.TargetFile));
|
|
1755
2010
|
} else if (args.Cwd) {
|
|
1756
2011
|
candidate = normalizePath(args.Cwd);
|
|
1757
2012
|
}
|
|
1758
2013
|
if (candidate) {
|
|
1759
|
-
const norm = candidate.
|
|
2014
|
+
const norm = candidate.replaceAll("\\", "/").toLowerCase();
|
|
1760
2015
|
const isTemp = norm.startsWith("/var/") || norm.startsWith("/private/var/") || norm.startsWith("/tmp/") || norm.startsWith("/private/tmp/") || norm.includes("/tmp.");
|
|
1761
2016
|
if (isTemp) {
|
|
1762
2017
|
if (!fallbackCwd) {
|
|
@@ -1779,7 +2034,7 @@ function extractProjectContext(rawLines) {
|
|
|
1779
2034
|
}
|
|
1780
2035
|
if (cwd) {
|
|
1781
2036
|
const match = cwd.match(/[/\\]projects[/\\]([^/\\]+)/i);
|
|
1782
|
-
project = match && match[1] ? match[1] :
|
|
2037
|
+
project = match && match[1] ? match[1] : path5.basename(cwd);
|
|
1783
2038
|
}
|
|
1784
2039
|
return { cwd, project };
|
|
1785
2040
|
}
|
|
@@ -1791,7 +2046,7 @@ function normalizePath(p) {
|
|
|
1791
2046
|
if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
1792
2047
|
cleaned = cleaned.slice(1, -1);
|
|
1793
2048
|
}
|
|
1794
|
-
return
|
|
2049
|
+
return path5.normalize(cleaned);
|
|
1795
2050
|
}
|
|
1796
2051
|
async function parseAgySessionFile(filePath, options) {
|
|
1797
2052
|
const text = await readFile2(filePath, "utf8");
|
|
@@ -1810,8 +2065,8 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
1810
2065
|
const sessionId = getSessionId(filePath);
|
|
1811
2066
|
const modelSetting = await readAgyModelSetting(filePath);
|
|
1812
2067
|
let generatorMetadata = options?.mockTrajectoryMetadata || await getTrajectoryGeneratorMetadata(sessionId).catch(() => null);
|
|
1813
|
-
const cacheDir =
|
|
1814
|
-
const cacheFile =
|
|
2068
|
+
const cacheDir = path5.join(path5.dirname(path5.dirname(filePath)), "cache");
|
|
2069
|
+
const cacheFile = path5.join(cacheDir, "trajectory_metadata.json");
|
|
1815
2070
|
if (generatorMetadata) {
|
|
1816
2071
|
try {
|
|
1817
2072
|
await mkdir2(cacheDir, { recursive: true });
|
|
@@ -1827,6 +2082,16 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
1827
2082
|
} catch {
|
|
1828
2083
|
}
|
|
1829
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
|
+
}
|
|
1830
2095
|
const usageMap = /* @__PURE__ */ new Map();
|
|
1831
2096
|
const usageEntries = [];
|
|
1832
2097
|
const matchedUsageEntries = /* @__PURE__ */ new Set();
|
|
@@ -1931,7 +2196,6 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
1931
2196
|
})
|
|
1932
2197
|
}), lineNumber, raw.type);
|
|
1933
2198
|
} else if (raw.type === "PLANNER_RESPONSE") {
|
|
1934
|
-
const content = stringField(raw, "content") || "";
|
|
1935
2199
|
const usageMetadata = usageMap.get(raw.step_index);
|
|
1936
2200
|
if (usageMetadata) {
|
|
1937
2201
|
matchedUsageEntries.add(usageMetadata);
|
|
@@ -2143,27 +2407,27 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
2143
2407
|
function agyDataDirs(home, env) {
|
|
2144
2408
|
const override = env?.ANTIGRAVITY_DATA_DIR || env?.AGY_DATA_DIR;
|
|
2145
2409
|
if (override && override.trim()) {
|
|
2146
|
-
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));
|
|
2147
2411
|
}
|
|
2148
|
-
return [
|
|
2412
|
+
return [path5.join(home, ".gemini", "antigravity-cli", "brain")];
|
|
2149
2413
|
}
|
|
2150
2414
|
async function agyBackfillFiles(sourceRoot, home, env) {
|
|
2151
|
-
const roots = sourceRoot ? [
|
|
2415
|
+
const roots = sourceRoot ? [path5.resolve(sourceRoot)] : agyDataDirs(home, env);
|
|
2152
2416
|
const fileLists = await Promise.all(roots.map((root) => listFilesByExtensions(root, [".jsonl"])));
|
|
2153
2417
|
const files = fileLists.flat().filter((f) => f.endsWith("transcript.jsonl")).sort();
|
|
2154
2418
|
return Promise.all(files.map(async (filePath) => {
|
|
2155
|
-
const info = await
|
|
2419
|
+
const info = await stat3(filePath);
|
|
2156
2420
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
2157
2421
|
}));
|
|
2158
2422
|
}
|
|
2159
|
-
|
|
2423
|
+
function agyHandler(msg) {
|
|
2160
2424
|
return {
|
|
2161
2425
|
type: "command",
|
|
2162
2426
|
command: "vibetime hook --agent agy",
|
|
2163
2427
|
timeout: 10,
|
|
2164
2428
|
statusMessage: msg
|
|
2165
2429
|
};
|
|
2166
|
-
}
|
|
2430
|
+
}
|
|
2167
2431
|
function hookConfig() {
|
|
2168
2432
|
const anyTool = [{ matcher: "", hooks: [agyHandler("Reporting tool activity")] }];
|
|
2169
2433
|
const lifecycle = (msg) => [{ matcher: "", hooks: [agyHandler(msg)] }];
|
|
@@ -2228,18 +2492,18 @@ function createAgyAdapter() {
|
|
|
2228
2492
|
return agyDataDirs(home, env)[0];
|
|
2229
2493
|
},
|
|
2230
2494
|
installedPath(home, env) {
|
|
2231
|
-
return
|
|
2495
|
+
return path5.join(path5.dirname(agyDataDirs(home, env)[0]), "hooks.json");
|
|
2232
2496
|
},
|
|
2233
2497
|
async isInstalled(home, env) {
|
|
2234
|
-
const base =
|
|
2235
|
-
const settingsPath =
|
|
2236
|
-
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");
|
|
2237
2501
|
return await checkEnableJsonHooks(settingsPath) && await isAgyHooksInstalled(hooksPath, "vibetime hook --agent agy");
|
|
2238
2502
|
},
|
|
2239
2503
|
installEntries(home, env) {
|
|
2240
|
-
const base =
|
|
2241
|
-
const settingsPath =
|
|
2242
|
-
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");
|
|
2243
2507
|
return [
|
|
2244
2508
|
{
|
|
2245
2509
|
kind: "hooks-json",
|
|
@@ -2261,12 +2525,12 @@ function createAgyAdapter() {
|
|
|
2261
2525
|
}
|
|
2262
2526
|
|
|
2263
2527
|
// src/adapters/claude-code.ts
|
|
2264
|
-
import { readdir as readdir2, readFile as readFile3, stat as
|
|
2528
|
+
import { readdir as readdir2, readFile as readFile3, stat as stat4 } from "node:fs/promises";
|
|
2265
2529
|
import os2 from "node:os";
|
|
2266
|
-
import
|
|
2530
|
+
import path7 from "node:path";
|
|
2267
2531
|
|
|
2268
2532
|
// src/lib/adapter-helpers.ts
|
|
2269
|
-
import
|
|
2533
|
+
import path6 from "node:path";
|
|
2270
2534
|
var TURN_IDLE_MS = 6e4;
|
|
2271
2535
|
function isTurnIdle(lastEventAt) {
|
|
2272
2536
|
if (!lastEventAt) {
|
|
@@ -2279,7 +2543,7 @@ function isTurnIdle(lastEventAt) {
|
|
|
2279
2543
|
return Date.now() - lastMs > TURN_IDLE_MS;
|
|
2280
2544
|
}
|
|
2281
2545
|
function sessionIdFromFilePath(filePath, prefix) {
|
|
2282
|
-
const match =
|
|
2546
|
+
const match = path6.basename(filePath).match(/([0-9a-f]{8}-[0-9a-f-]{27,})/);
|
|
2283
2547
|
return match?.[1] || `${prefix}_${createStableHash(filePath).slice(0, 24)}`;
|
|
2284
2548
|
}
|
|
2285
2549
|
function hookHandler(agentId, statusMessage) {
|
|
@@ -2343,7 +2607,7 @@ async function parseClaudeCodeSessionFile(filePath, options) {
|
|
|
2343
2607
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
2344
2608
|
state.sessionId = sessionId;
|
|
2345
2609
|
cwd = stringField(raw, "cwd") || cwd;
|
|
2346
|
-
project = projectContext.project || (cwd ?
|
|
2610
|
+
project = projectContext.project || (cwd ? path7.basename(cwd) : project || await claudeProjectFromFilePath(filePath, options));
|
|
2347
2611
|
if (!ts) {
|
|
2348
2612
|
continue;
|
|
2349
2613
|
}
|
|
@@ -2715,17 +2979,17 @@ function claudeTextStats(value) {
|
|
|
2715
2979
|
};
|
|
2716
2980
|
}
|
|
2717
2981
|
async function claudeProjectContextFromLines(filePath, lines, options) {
|
|
2718
|
-
const projectDir =
|
|
2982
|
+
const projectDir = path7.basename(path7.dirname(filePath));
|
|
2719
2983
|
const cwds = [];
|
|
2720
2984
|
for (const line of lines) {
|
|
2721
2985
|
const raw = parseJsonLine(line);
|
|
2722
2986
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
2723
|
-
if (cwd &&
|
|
2987
|
+
if (cwd && path7.isAbsolute(cwd)) {
|
|
2724
2988
|
cwds.push(cwd);
|
|
2725
2989
|
}
|
|
2726
2990
|
}
|
|
2727
2991
|
const root = await gitRootFromCwds(cwds) || claudeProjectRootFromCwds(projectDir, cwds);
|
|
2728
|
-
const project = cwds.length > 0 ?
|
|
2992
|
+
const project = cwds.length > 0 ? path7.basename(cwds[0]) : root ? path7.basename(root) : await claudeProjectFromFilePath(filePath, options);
|
|
2729
2993
|
return {
|
|
2730
2994
|
project,
|
|
2731
2995
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -2734,15 +2998,15 @@ async function claudeProjectContextFromLines(filePath, lines, options) {
|
|
|
2734
2998
|
async function gitRootFromCwds(cwds) {
|
|
2735
2999
|
const seen = /* @__PURE__ */ new Set();
|
|
2736
3000
|
for (const cwd of cwds) {
|
|
2737
|
-
let current =
|
|
3001
|
+
let current = path7.resolve(cwd);
|
|
2738
3002
|
while (!seen.has(current)) {
|
|
2739
3003
|
seen.add(current);
|
|
2740
3004
|
try {
|
|
2741
|
-
await
|
|
3005
|
+
await stat4(path7.join(current, ".git"));
|
|
2742
3006
|
return current;
|
|
2743
3007
|
} catch {
|
|
2744
3008
|
}
|
|
2745
|
-
const parent =
|
|
3009
|
+
const parent = path7.dirname(current);
|
|
2746
3010
|
if (parent === current) {
|
|
2747
3011
|
break;
|
|
2748
3012
|
}
|
|
@@ -2753,12 +3017,12 @@ async function gitRootFromCwds(cwds) {
|
|
|
2753
3017
|
}
|
|
2754
3018
|
function claudeProjectRootFromCwds(projectDir, cwds) {
|
|
2755
3019
|
for (const cwd of cwds) {
|
|
2756
|
-
let current =
|
|
3020
|
+
let current = path7.resolve(cwd);
|
|
2757
3021
|
while (true) {
|
|
2758
3022
|
if (encodeClaudeProjectPath(current) === projectDir) {
|
|
2759
3023
|
return current;
|
|
2760
3024
|
}
|
|
2761
|
-
const parent =
|
|
3025
|
+
const parent = path7.dirname(current);
|
|
2762
3026
|
if (parent === current) {
|
|
2763
3027
|
break;
|
|
2764
3028
|
}
|
|
@@ -2768,10 +3032,10 @@ function claudeProjectRootFromCwds(projectDir, cwds) {
|
|
|
2768
3032
|
return void 0;
|
|
2769
3033
|
}
|
|
2770
3034
|
function encodeClaudeProjectPath(value) {
|
|
2771
|
-
return
|
|
3035
|
+
return path7.resolve(value).split(path7.sep).join("-").replace(/_/g, "-");
|
|
2772
3036
|
}
|
|
2773
3037
|
function rawClaudeProjectPath(value) {
|
|
2774
|
-
return
|
|
3038
|
+
return path7.resolve(value).split(path7.sep).join("-");
|
|
2775
3039
|
}
|
|
2776
3040
|
function claudeEncodedVariants(value) {
|
|
2777
3041
|
const raw = rawClaudeProjectPath(value);
|
|
@@ -2787,11 +3051,11 @@ function claudeEncodedProjectSuffix(projectDir, home) {
|
|
|
2787
3051
|
return void 0;
|
|
2788
3052
|
}
|
|
2789
3053
|
async function claudeProjectFromFilePath(filePath, options) {
|
|
2790
|
-
const projectDir =
|
|
2791
|
-
const home = options ?
|
|
3054
|
+
const projectDir = path7.basename(path7.dirname(filePath));
|
|
3055
|
+
const home = options ? path7.resolve(stringOption(options.home) || os2.homedir()) : os2.homedir();
|
|
2792
3056
|
const resolved = await resolveClaudeProjectPath(projectDir, home);
|
|
2793
3057
|
if (resolved) {
|
|
2794
|
-
return
|
|
3058
|
+
return path7.basename(resolved);
|
|
2795
3059
|
}
|
|
2796
3060
|
const suffix = claudeEncodedProjectSuffix(projectDir, home);
|
|
2797
3061
|
if (suffix) {
|
|
@@ -2817,7 +3081,7 @@ async function resolveClaudeProjectPath(projectDir, home) {
|
|
|
2817
3081
|
if (!entry.isDirectory()) {
|
|
2818
3082
|
continue;
|
|
2819
3083
|
}
|
|
2820
|
-
const candidate =
|
|
3084
|
+
const candidate = path7.join(current, entry.name);
|
|
2821
3085
|
const candidateVariants = claudeEncodedVariants(candidate);
|
|
2822
3086
|
if (candidateVariants.includes(projectDir)) {
|
|
2823
3087
|
return candidate;
|
|
@@ -2862,9 +3126,9 @@ function hookConfig2() {
|
|
|
2862
3126
|
function claudeConfigDir(home, env) {
|
|
2863
3127
|
const override = env?.CLAUDE_CONFIG_DIR;
|
|
2864
3128
|
if (override && override.trim()) {
|
|
2865
|
-
return
|
|
3129
|
+
return path7.resolve(override);
|
|
2866
3130
|
}
|
|
2867
|
-
return
|
|
3131
|
+
return path7.join(home, ".claude");
|
|
2868
3132
|
}
|
|
2869
3133
|
function createClaudeCodeAdapter() {
|
|
2870
3134
|
return {
|
|
@@ -2876,27 +3140,27 @@ function createClaudeCodeAdapter() {
|
|
|
2876
3140
|
return claudeConfigDir(home, env);
|
|
2877
3141
|
},
|
|
2878
3142
|
installedPath(home, env) {
|
|
2879
|
-
return
|
|
3143
|
+
return path7.join(claudeConfigDir(home, env), "settings.json");
|
|
2880
3144
|
},
|
|
2881
3145
|
async isInstalled(home, env) {
|
|
2882
3146
|
return isHooksJsonInstalled(
|
|
2883
|
-
|
|
3147
|
+
path7.join(claudeConfigDir(home, env), "settings.json"),
|
|
2884
3148
|
"vibetime hook --agent claude"
|
|
2885
3149
|
);
|
|
2886
3150
|
},
|
|
2887
3151
|
installEntries(home, env) {
|
|
2888
3152
|
return [{
|
|
2889
3153
|
kind: "hooks-json",
|
|
2890
|
-
path:
|
|
3154
|
+
path: path7.join(claudeConfigDir(home, env), "settings.json"),
|
|
2891
3155
|
content: hookConfig2()
|
|
2892
3156
|
}];
|
|
2893
3157
|
},
|
|
2894
3158
|
sourcePaths(home, env) {
|
|
2895
3159
|
const base = claudeConfigDir(home, env);
|
|
2896
3160
|
return [
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
3161
|
+
path7.join(base, "projects"),
|
|
3162
|
+
path7.join(base, ".claude.json"),
|
|
3163
|
+
path7.join(home, ".claude.json")
|
|
2900
3164
|
];
|
|
2901
3165
|
},
|
|
2902
3166
|
parseSessionFile: parseClaudeCodeSessionFile
|
|
@@ -2904,21 +3168,21 @@ function createClaudeCodeAdapter() {
|
|
|
2904
3168
|
}
|
|
2905
3169
|
|
|
2906
3170
|
// src/adapters/claude-cowork.ts
|
|
2907
|
-
import { readdir as readdir3, readFile as readFile4, stat as
|
|
3171
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat5 } from "node:fs/promises";
|
|
2908
3172
|
import os3 from "node:os";
|
|
2909
|
-
import
|
|
3173
|
+
import path8 from "node:path";
|
|
2910
3174
|
init_fs();
|
|
2911
3175
|
var COWORK_PREFIX = "cowork:";
|
|
2912
3176
|
function coworkDataDirs(home, env) {
|
|
2913
3177
|
const override = env?.COWORK_DIR || env?.CLAUDE_COWORK_DIR;
|
|
2914
3178
|
if (override && override.trim()) {
|
|
2915
|
-
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));
|
|
2916
3180
|
}
|
|
2917
3181
|
return [
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
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")
|
|
2922
3186
|
];
|
|
2923
3187
|
}
|
|
2924
3188
|
function isCoworkMetaFileName(name) {
|
|
@@ -2934,7 +3198,7 @@ async function readCoworkMeta(filePath) {
|
|
|
2934
3198
|
}
|
|
2935
3199
|
async function isRegularFile(filePath) {
|
|
2936
3200
|
try {
|
|
2937
|
-
return (await
|
|
3201
|
+
return (await stat5(filePath)).isFile();
|
|
2938
3202
|
} catch {
|
|
2939
3203
|
return false;
|
|
2940
3204
|
}
|
|
@@ -2943,7 +3207,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
|
|
|
2943
3207
|
if (!sessionDir || !cliSessionId) {
|
|
2944
3208
|
return void 0;
|
|
2945
3209
|
}
|
|
2946
|
-
const projectsDir =
|
|
3210
|
+
const projectsDir = path8.join(sessionDir, ".claude", "projects");
|
|
2947
3211
|
let entries;
|
|
2948
3212
|
try {
|
|
2949
3213
|
entries = await readdir3(projectsDir, { withFileTypes: true });
|
|
@@ -2955,7 +3219,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
|
|
|
2955
3219
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
2956
3220
|
continue;
|
|
2957
3221
|
}
|
|
2958
|
-
const candidate =
|
|
3222
|
+
const candidate = path8.join(projectsDir, entry.name, target);
|
|
2959
3223
|
if (await isRegularFile(candidate)) {
|
|
2960
3224
|
return candidate;
|
|
2961
3225
|
}
|
|
@@ -2963,7 +3227,7 @@ async function resolveCoworkTranscript(sessionDir, cliSessionId) {
|
|
|
2963
3227
|
return void 0;
|
|
2964
3228
|
}
|
|
2965
3229
|
async function coworkSubagentTranscripts(mainTranscript, cliSessionId) {
|
|
2966
|
-
const root =
|
|
3230
|
+
const root = path8.join(path8.dirname(mainTranscript), cliSessionId, "subagents");
|
|
2967
3231
|
const out = [];
|
|
2968
3232
|
async function walk(dir) {
|
|
2969
3233
|
let entries;
|
|
@@ -2973,7 +3237,7 @@ async function coworkSubagentTranscripts(mainTranscript, cliSessionId) {
|
|
|
2973
3237
|
return;
|
|
2974
3238
|
}
|
|
2975
3239
|
await Promise.all(entries.map(async (entry) => {
|
|
2976
|
-
const entryPath =
|
|
3240
|
+
const entryPath = path8.join(dir, entry.name);
|
|
2977
3241
|
if (entry.isDirectory()) {
|
|
2978
3242
|
await walk(entryPath);
|
|
2979
3243
|
return;
|
|
@@ -2996,7 +3260,7 @@ async function discoverCoworkTranscripts(root) {
|
|
|
2996
3260
|
return;
|
|
2997
3261
|
}
|
|
2998
3262
|
await Promise.all(entries.map(async (entry) => {
|
|
2999
|
-
const entryPath =
|
|
3263
|
+
const entryPath = path8.join(dir, entry.name);
|
|
3000
3264
|
if (entry.isDirectory()) {
|
|
3001
3265
|
if (entry.name.startsWith("local_") || entry.name === "skills-plugin" || entry.name === "node_modules" || entry.name === ".git") {
|
|
3002
3266
|
return;
|
|
@@ -3026,7 +3290,7 @@ async function discoverCoworkTranscripts(root) {
|
|
|
3026
3290
|
return transcripts.sort((a, b) => a.transcriptPath.localeCompare(b.transcriptPath));
|
|
3027
3291
|
}
|
|
3028
3292
|
function coworkMetaPathForTranscript(transcriptPath) {
|
|
3029
|
-
const marker = `${
|
|
3293
|
+
const marker = `${path8.sep}.claude${path8.sep}projects${path8.sep}`;
|
|
3030
3294
|
const index = transcriptPath.indexOf(marker);
|
|
3031
3295
|
if (index < 0) {
|
|
3032
3296
|
return void 0;
|
|
@@ -3041,9 +3305,9 @@ function projectFromMeta(meta) {
|
|
|
3041
3305
|
if (!folder) {
|
|
3042
3306
|
return { project: "cowork" };
|
|
3043
3307
|
}
|
|
3044
|
-
const resolved =
|
|
3308
|
+
const resolved = path8.resolve(folder);
|
|
3045
3309
|
return {
|
|
3046
|
-
project:
|
|
3310
|
+
project: path8.basename(resolved).replace(/-/g, "_") || "cowork",
|
|
3047
3311
|
cwd: resolved
|
|
3048
3312
|
};
|
|
3049
3313
|
}
|
|
@@ -3103,13 +3367,13 @@ async function parseClaudeCoworkSessionFile(filePath, options) {
|
|
|
3103
3367
|
});
|
|
3104
3368
|
}
|
|
3105
3369
|
async function claudeCoworkBackfillFiles(sourceRoot, home, env) {
|
|
3106
|
-
const roots = sourceRoot ? [
|
|
3370
|
+
const roots = sourceRoot ? [path8.resolve(sourceRoot)] : coworkDataDirs(home, env);
|
|
3107
3371
|
const discovered = (await Promise.all(roots.map(discoverCoworkTranscripts))).flat();
|
|
3108
3372
|
return Promise.all(discovered.map(async ({ transcriptPath, metadataPath }) => {
|
|
3109
|
-
const transcriptInfo = await
|
|
3373
|
+
const transcriptInfo = await stat5(transcriptPath);
|
|
3110
3374
|
let modifiedAt = transcriptInfo.mtime;
|
|
3111
3375
|
try {
|
|
3112
|
-
const metaInfo = await
|
|
3376
|
+
const metaInfo = await stat5(metadataPath);
|
|
3113
3377
|
if (metaInfo.mtime > modifiedAt) {
|
|
3114
3378
|
modifiedAt = metaInfo.mtime;
|
|
3115
3379
|
}
|
|
@@ -3125,7 +3389,7 @@ function createClaudeCoworkAdapter() {
|
|
|
3125
3389
|
agentName: "claude-cowork",
|
|
3126
3390
|
kind: "agent",
|
|
3127
3391
|
detectPath(home, env) {
|
|
3128
|
-
return coworkDataDirs(home, env)[0] ||
|
|
3392
|
+
return coworkDataDirs(home, env)[0] || path8.join(os3.homedir(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
|
|
3129
3393
|
},
|
|
3130
3394
|
installedPath(home, env) {
|
|
3131
3395
|
return this.detectPath(home, env);
|
|
@@ -3150,7 +3414,7 @@ function createClaudeCoworkAdapter() {
|
|
|
3150
3414
|
|
|
3151
3415
|
// src/adapters/codebuddy.ts
|
|
3152
3416
|
import { readFile as readFile5, readdir as readdir4 } from "node:fs/promises";
|
|
3153
|
-
import
|
|
3417
|
+
import path9 from "node:path";
|
|
3154
3418
|
var ENDPOINT_MODEL_ID_RE = /^(?:ep|endpoint)-/i;
|
|
3155
3419
|
async function parseCodebuddyTraceFile(filePath, options) {
|
|
3156
3420
|
const text = await readFile5(filePath, "utf8");
|
|
@@ -3177,7 +3441,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
3177
3441
|
if (!cwd && trace.startedAt) {
|
|
3178
3442
|
cwd = await cwdFromHistoryFile(trace.startedAt, options);
|
|
3179
3443
|
}
|
|
3180
|
-
const project = cwd ?
|
|
3444
|
+
const project = cwd ? path9.basename(cwd) : void 0;
|
|
3181
3445
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
3182
3446
|
const model = resolveCodebuddyModel(trace, spans);
|
|
3183
3447
|
const baseEvent = (event) => ({
|
|
@@ -3544,11 +3808,11 @@ function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
|
|
|
3544
3808
|
return { modelCalls: 1 };
|
|
3545
3809
|
}
|
|
3546
3810
|
function sessionIdFromTracePath(filePath) {
|
|
3547
|
-
const match =
|
|
3811
|
+
const match = path9.basename(filePath).match(/trace_([0-9a-f]{32})/);
|
|
3548
3812
|
return match?.[1] ? `codebuddy_${match[1]}` : `codebuddy_${createStableHash(filePath).slice(0, 24)}`;
|
|
3549
3813
|
}
|
|
3550
3814
|
function resolveHome(options) {
|
|
3551
|
-
return options.home ?
|
|
3815
|
+
return options.home ? path9.resolve(String(options.home)) : process.env.HOME || __require("node:os").homedir();
|
|
3552
3816
|
}
|
|
3553
3817
|
async function readCwdFromSession(sessionPath, matchSessionId) {
|
|
3554
3818
|
try {
|
|
@@ -3569,9 +3833,9 @@ async function readCwdFromSession(sessionPath, matchSessionId) {
|
|
|
3569
3833
|
}
|
|
3570
3834
|
async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
3571
3835
|
const home = resolveHome(options);
|
|
3572
|
-
const sessionsDir =
|
|
3836
|
+
const sessionsDir = path9.join(home, ".codebuddy", "sessions");
|
|
3573
3837
|
if (pid) {
|
|
3574
|
-
const cwd = await readCwdFromSession(
|
|
3838
|
+
const cwd = await readCwdFromSession(path9.join(sessionsDir, `${pid}.json`));
|
|
3575
3839
|
if (cwd) {
|
|
3576
3840
|
return cwd;
|
|
3577
3841
|
}
|
|
@@ -3584,7 +3848,7 @@ async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
|
3584
3848
|
continue;
|
|
3585
3849
|
}
|
|
3586
3850
|
const cwd = await readCwdFromSession(
|
|
3587
|
-
|
|
3851
|
+
path9.join(sessionsDir, f),
|
|
3588
3852
|
traceSessionId
|
|
3589
3853
|
);
|
|
3590
3854
|
if (cwd) {
|
|
@@ -3598,7 +3862,7 @@ async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
|
3598
3862
|
}
|
|
3599
3863
|
async function cwdFromHistoryFile(traceStartedAt, options) {
|
|
3600
3864
|
const home = resolveHome(options);
|
|
3601
|
-
const historyPath =
|
|
3865
|
+
const historyPath = path9.join(home, ".codebuddy", "history.jsonl");
|
|
3602
3866
|
const traceMs = Date.parse(traceStartedAt);
|
|
3603
3867
|
if (Number.isNaN(traceMs)) {
|
|
3604
3868
|
return void 0;
|
|
@@ -3660,9 +3924,9 @@ function hookConfig3() {
|
|
|
3660
3924
|
function codebuddyConfigDir(home, env) {
|
|
3661
3925
|
const override = env?.CODEBUDDY_CONFIG_DIR;
|
|
3662
3926
|
if (override && override.trim()) {
|
|
3663
|
-
return
|
|
3927
|
+
return path9.resolve(override);
|
|
3664
3928
|
}
|
|
3665
|
-
return
|
|
3929
|
+
return path9.join(home, ".codebuddy");
|
|
3666
3930
|
}
|
|
3667
3931
|
function createCodebuddyAdapter() {
|
|
3668
3932
|
return {
|
|
@@ -3674,32 +3938,32 @@ function createCodebuddyAdapter() {
|
|
|
3674
3938
|
return codebuddyConfigDir(home, env);
|
|
3675
3939
|
},
|
|
3676
3940
|
installedPath(home, env) {
|
|
3677
|
-
return
|
|
3941
|
+
return path9.join(codebuddyConfigDir(home, env), "settings.json");
|
|
3678
3942
|
},
|
|
3679
3943
|
async isInstalled(home, env) {
|
|
3680
3944
|
return isHooksJsonInstalled(
|
|
3681
|
-
|
|
3945
|
+
path9.join(codebuddyConfigDir(home, env), "settings.json"),
|
|
3682
3946
|
"vibetime hook --agent codebuddy"
|
|
3683
3947
|
);
|
|
3684
3948
|
},
|
|
3685
3949
|
installEntries(home, env) {
|
|
3686
3950
|
return [{
|
|
3687
3951
|
kind: "hooks-json",
|
|
3688
|
-
path:
|
|
3952
|
+
path: path9.join(codebuddyConfigDir(home, env), "settings.json"),
|
|
3689
3953
|
content: hookConfig3()
|
|
3690
3954
|
}];
|
|
3691
3955
|
},
|
|
3692
3956
|
sourcePaths(home, env) {
|
|
3693
3957
|
const base = codebuddyConfigDir(home, env);
|
|
3694
3958
|
return [
|
|
3695
|
-
|
|
3959
|
+
path9.join(base, "traces")
|
|
3696
3960
|
];
|
|
3697
3961
|
},
|
|
3698
3962
|
parseSessionFile: parseCodebuddyTraceFile
|
|
3699
3963
|
};
|
|
3700
3964
|
}
|
|
3701
3965
|
async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
3702
|
-
const base = sourceRoot ||
|
|
3966
|
+
const base = sourceRoot || path9.join(codebuddyConfigDir(home, env), "traces");
|
|
3703
3967
|
const files = [];
|
|
3704
3968
|
try {
|
|
3705
3969
|
const pidDirs = await readdir4(base, { withFileTypes: true });
|
|
@@ -3707,17 +3971,17 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
3707
3971
|
if (!pidDir.isDirectory()) {
|
|
3708
3972
|
continue;
|
|
3709
3973
|
}
|
|
3710
|
-
const traceDir =
|
|
3974
|
+
const traceDir = path9.join(base, pidDir.name);
|
|
3711
3975
|
try {
|
|
3712
3976
|
const entries = await readdir4(traceDir);
|
|
3713
3977
|
for (const entry of entries) {
|
|
3714
3978
|
if (!entry.endsWith(".json") || !entry.startsWith("trace_")) {
|
|
3715
3979
|
continue;
|
|
3716
3980
|
}
|
|
3717
|
-
const filePath =
|
|
3981
|
+
const filePath = path9.join(traceDir, entry);
|
|
3718
3982
|
try {
|
|
3719
|
-
const
|
|
3720
|
-
files.push({ path: filePath, modifiedAt:
|
|
3983
|
+
const stat13 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
|
|
3984
|
+
files.push({ path: filePath, modifiedAt: stat13.mtime.toISOString() });
|
|
3721
3985
|
} catch {
|
|
3722
3986
|
}
|
|
3723
3987
|
}
|
|
@@ -3731,7 +3995,7 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
3731
3995
|
|
|
3732
3996
|
// src/adapters/codex.ts
|
|
3733
3997
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
3734
|
-
import
|
|
3998
|
+
import path11 from "node:path";
|
|
3735
3999
|
|
|
3736
4000
|
// src/lib/diff.ts
|
|
3737
4001
|
function diffStats(diff) {
|
|
@@ -3776,6 +4040,61 @@ function fileActivitiesFromPatchChanges(changes, ts, cwd, displayFilePath3) {
|
|
|
3776
4040
|
});
|
|
3777
4041
|
}
|
|
3778
4042
|
|
|
4043
|
+
// src/lib/session-context.ts
|
|
4044
|
+
init_fs();
|
|
4045
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
4046
|
+
import os4 from "node:os";
|
|
4047
|
+
import path10 from "node:path";
|
|
4048
|
+
var SESSION_CONTEXT_VERSION = 1;
|
|
4049
|
+
function sessionContextDir(home) {
|
|
4050
|
+
return path10.join(home, ".vibetime", "session-context");
|
|
4051
|
+
}
|
|
4052
|
+
function sessionContextPath(home, sessionId) {
|
|
4053
|
+
return path10.join(sessionContextDir(home), `${encodeURIComponent(sessionId)}.json`);
|
|
4054
|
+
}
|
|
4055
|
+
function resolveHome2(options) {
|
|
4056
|
+
return options ? path10.resolve(stringOption(options.home) || os4.homedir()) : os4.homedir();
|
|
4057
|
+
}
|
|
4058
|
+
async function readPersistedSessionContext(home, sessionId) {
|
|
4059
|
+
const raw = await readJsonIfExists(sessionContextPath(home, sessionId));
|
|
4060
|
+
if (!isPlainObject(raw)) {
|
|
4061
|
+
return void 0;
|
|
4062
|
+
}
|
|
4063
|
+
if (raw.version !== SESSION_CONTEXT_VERSION || raw.sessionId !== sessionId) {
|
|
4064
|
+
return void 0;
|
|
4065
|
+
}
|
|
4066
|
+
if (typeof raw.updatedAt !== "string") {
|
|
4067
|
+
return void 0;
|
|
4068
|
+
}
|
|
4069
|
+
const cwd = typeof raw.cwd === "string" && raw.cwd.length > 0 ? raw.cwd : void 0;
|
|
4070
|
+
const project = typeof raw.project === "string" && raw.project.length > 0 ? raw.project : void 0;
|
|
4071
|
+
return { version: SESSION_CONTEXT_VERSION, sessionId, cwd, project, updatedAt: raw.updatedAt };
|
|
4072
|
+
}
|
|
4073
|
+
async function readPersistedSessionContextFromOptions(options, sessionId) {
|
|
4074
|
+
return readPersistedSessionContext(resolveHome2(options), sessionId);
|
|
4075
|
+
}
|
|
4076
|
+
async function persistHookSessionContext(home, payload) {
|
|
4077
|
+
if (!isPlainObject(payload)) {
|
|
4078
|
+
return;
|
|
4079
|
+
}
|
|
4080
|
+
const sessionId = typeof payload.session_id === "string" ? payload.session_id.trim() : typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
|
|
4081
|
+
const cwd = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
|
|
4082
|
+
if (!sessionId || !cwd || !path10.isAbsolute(cwd)) {
|
|
4083
|
+
return;
|
|
4084
|
+
}
|
|
4085
|
+
const project = path10.basename(cwd) || void 0;
|
|
4086
|
+
const context = {
|
|
4087
|
+
version: SESSION_CONTEXT_VERSION,
|
|
4088
|
+
sessionId,
|
|
4089
|
+
cwd,
|
|
4090
|
+
project,
|
|
4091
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4092
|
+
};
|
|
4093
|
+
await mkdir3(sessionContextDir(home), { recursive: true });
|
|
4094
|
+
await writeFile3(sessionContextPath(home, sessionId), `${JSON.stringify(context, null, 2)}
|
|
4095
|
+
`, "utf8");
|
|
4096
|
+
}
|
|
4097
|
+
|
|
3779
4098
|
// src/adapters/codex.ts
|
|
3780
4099
|
async function parseCodexSessionFile(filePath, options) {
|
|
3781
4100
|
const text = await readFile6(filePath, "utf8");
|
|
@@ -3810,9 +4129,11 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3810
4129
|
continue;
|
|
3811
4130
|
}
|
|
3812
4131
|
sessionMetaLocked = true;
|
|
4132
|
+
const forkedFromId = stringField(payload, "forked_from_id");
|
|
4133
|
+
const inherited = forkedFromId ? await readPersistedSessionContextFromOptions(options, forkedFromId) : void 0;
|
|
3813
4134
|
sessionId = stringField(payload, "id") || sessionId;
|
|
3814
|
-
cwd = stringField(payload, "cwd") || cwd;
|
|
3815
|
-
project = cwd ?
|
|
4135
|
+
cwd = inherited?.cwd || stringField(payload, "cwd") || cwd;
|
|
4136
|
+
project = inherited?.project || (cwd ? path11.basename(cwd) : project);
|
|
3816
4137
|
model = stringField(payload, "model_provider") || model;
|
|
3817
4138
|
events.push(withBackfillRefs({
|
|
3818
4139
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -3833,7 +4154,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3833
4154
|
if (topType === "turn_context") {
|
|
3834
4155
|
currentTurnId = stringField(payload, "turn_id") || currentTurnId;
|
|
3835
4156
|
cwd = stringField(payload, "cwd") || cwd;
|
|
3836
|
-
project = cwd ?
|
|
4157
|
+
project = cwd ? path11.basename(cwd) : project;
|
|
3837
4158
|
model = stringField(payload, "model") || model;
|
|
3838
4159
|
const effort = stringField(payload, "effort") || stringField(objectField(objectField(payload, "collaboration_mode"), "settings"), "reasoning_effort");
|
|
3839
4160
|
if (effort) {
|
|
@@ -4280,11 +4601,11 @@ function functionCallArguments(payload) {
|
|
|
4280
4601
|
}
|
|
4281
4602
|
}
|
|
4282
4603
|
function displayFilePath2(filePath, cwd) {
|
|
4283
|
-
if (!cwd || !
|
|
4604
|
+
if (!cwd || !path11.isAbsolute(filePath)) {
|
|
4284
4605
|
return filePath;
|
|
4285
4606
|
}
|
|
4286
|
-
const relative =
|
|
4287
|
-
return relative && !relative.startsWith("..") && !
|
|
4607
|
+
const relative = path11.relative(cwd, filePath);
|
|
4608
|
+
return relative && !relative.startsWith("..") && !path11.isAbsolute(relative) ? relative : filePath;
|
|
4288
4609
|
}
|
|
4289
4610
|
var codexHandler = (msg) => hookHandler("codex", msg);
|
|
4290
4611
|
function hookConfig4() {
|
|
@@ -4303,9 +4624,9 @@ function hookConfig4() {
|
|
|
4303
4624
|
function codexHome(home, env) {
|
|
4304
4625
|
const override = env?.CODEX_HOME;
|
|
4305
4626
|
if (override && override.trim()) {
|
|
4306
|
-
return
|
|
4627
|
+
return path11.resolve(override);
|
|
4307
4628
|
}
|
|
4308
|
-
return
|
|
4629
|
+
return path11.join(home, ".codex");
|
|
4309
4630
|
}
|
|
4310
4631
|
function createCodexAdapter() {
|
|
4311
4632
|
return {
|
|
@@ -4317,26 +4638,26 @@ function createCodexAdapter() {
|
|
|
4317
4638
|
return codexHome(home, env);
|
|
4318
4639
|
},
|
|
4319
4640
|
installedPath(home, env) {
|
|
4320
|
-
return
|
|
4641
|
+
return path11.join(codexHome(home, env), "hooks.json");
|
|
4321
4642
|
},
|
|
4322
4643
|
async isInstalled(home, env) {
|
|
4323
4644
|
return isHooksJsonInstalled(
|
|
4324
|
-
|
|
4645
|
+
path11.join(codexHome(home, env), "hooks.json"),
|
|
4325
4646
|
"vibetime hook --agent codex"
|
|
4326
4647
|
);
|
|
4327
4648
|
},
|
|
4328
4649
|
installEntries(home, env) {
|
|
4329
4650
|
return [{
|
|
4330
4651
|
kind: "hooks-json",
|
|
4331
|
-
path:
|
|
4652
|
+
path: path11.join(codexHome(home, env), "hooks.json"),
|
|
4332
4653
|
content: hookConfig4()
|
|
4333
4654
|
}];
|
|
4334
4655
|
},
|
|
4335
4656
|
sourcePaths(home, env) {
|
|
4336
4657
|
const base = codexHome(home, env);
|
|
4337
4658
|
return [
|
|
4338
|
-
|
|
4339
|
-
|
|
4659
|
+
path11.join(base, "sessions"),
|
|
4660
|
+
path11.join(base, "history.jsonl")
|
|
4340
4661
|
];
|
|
4341
4662
|
},
|
|
4342
4663
|
parseSessionFile: parseCodexSessionFile
|
|
@@ -4344,9 +4665,9 @@ function createCodexAdapter() {
|
|
|
4344
4665
|
}
|
|
4345
4666
|
|
|
4346
4667
|
// src/adapters/copilot.ts
|
|
4347
|
-
import { readdir as readdir5, readFile as readFile7, stat as
|
|
4348
|
-
import
|
|
4349
|
-
import
|
|
4668
|
+
import { readdir as readdir5, readFile as readFile7, stat as stat6 } from "node:fs/promises";
|
|
4669
|
+
import os5 from "node:os";
|
|
4670
|
+
import path12 from "node:path";
|
|
4350
4671
|
async function parseCopilotSessionFile(filePath, options) {
|
|
4351
4672
|
const text = await readFile7(filePath, "utf8");
|
|
4352
4673
|
const lines = text.split("\n").filter(Boolean);
|
|
@@ -4382,7 +4703,7 @@ async function parseCopilotSessionFile(filePath, options) {
|
|
|
4382
4703
|
}
|
|
4383
4704
|
const context = objectField(data, "context");
|
|
4384
4705
|
cwd = stringField(context, "cwd") || stringField(context, "gitRoot") || cwd;
|
|
4385
|
-
project = stringField(context, "repository") || (cwd ?
|
|
4706
|
+
project = stringField(context, "repository") || (cwd ? path12.basename(cwd) : void 0);
|
|
4386
4707
|
sessionStartedAt = ts;
|
|
4387
4708
|
events.push(baseCopilotEvent({
|
|
4388
4709
|
ts,
|
|
@@ -4613,8 +4934,8 @@ function baseCopilotEvent(event) {
|
|
|
4613
4934
|
...event
|
|
4614
4935
|
};
|
|
4615
4936
|
}
|
|
4616
|
-
async function copilotBackfillFiles(sourceRoot, home =
|
|
4617
|
-
const sessionDir = sourceRoot ||
|
|
4937
|
+
async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
|
|
4938
|
+
const sessionDir = sourceRoot || path12.join(home, ".copilot", "session-state");
|
|
4618
4939
|
const results = [];
|
|
4619
4940
|
let entries;
|
|
4620
4941
|
try {
|
|
@@ -4626,8 +4947,8 @@ async function copilotBackfillFiles(sourceRoot, home = os4.homedir(), _env) {
|
|
|
4626
4947
|
if (entry.startsWith("pending-session")) {
|
|
4627
4948
|
continue;
|
|
4628
4949
|
}
|
|
4629
|
-
const eventsPath =
|
|
4630
|
-
const info = await
|
|
4950
|
+
const eventsPath = path12.join(sessionDir, entry, "events.jsonl");
|
|
4951
|
+
const info = await stat6(eventsPath).catch(() => null);
|
|
4631
4952
|
if (info) {
|
|
4632
4953
|
results.push({ path: eventsPath, modifiedAt: info.mtime.toISOString() });
|
|
4633
4954
|
}
|
|
@@ -4644,9 +4965,9 @@ function copilotPluginContent() {
|
|
|
4644
4965
|
function copilotHome(home, env) {
|
|
4645
4966
|
const override = env?.COPILOT_HOME;
|
|
4646
4967
|
if (override && override.trim()) {
|
|
4647
|
-
return
|
|
4968
|
+
return path12.resolve(override);
|
|
4648
4969
|
}
|
|
4649
|
-
return
|
|
4970
|
+
return path12.join(home, ".copilot");
|
|
4650
4971
|
}
|
|
4651
4972
|
function createCopilotAdapter() {
|
|
4652
4973
|
return {
|
|
@@ -4658,12 +4979,12 @@ function createCopilotAdapter() {
|
|
|
4658
4979
|
return copilotHome(home, env);
|
|
4659
4980
|
},
|
|
4660
4981
|
installedPath(home, env) {
|
|
4661
|
-
return
|
|
4982
|
+
return path12.join(copilotHome(home, env), ".vibetime");
|
|
4662
4983
|
},
|
|
4663
4984
|
async isInstalled(home, env) {
|
|
4664
4985
|
try {
|
|
4665
4986
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4666
|
-
return await pathExists2(
|
|
4987
|
+
return await pathExists2(path12.join(copilotHome(home, env), ".vibetime"));
|
|
4667
4988
|
} catch {
|
|
4668
4989
|
return false;
|
|
4669
4990
|
}
|
|
@@ -4671,20 +4992,20 @@ function createCopilotAdapter() {
|
|
|
4671
4992
|
installEntries(home, env) {
|
|
4672
4993
|
return [{
|
|
4673
4994
|
kind: "file",
|
|
4674
|
-
path:
|
|
4995
|
+
path: path12.join(copilotHome(home, env), ".vibetime"),
|
|
4675
4996
|
content: copilotPluginContent()
|
|
4676
4997
|
}];
|
|
4677
4998
|
},
|
|
4678
4999
|
sourcePaths(home, env) {
|
|
4679
|
-
return [
|
|
5000
|
+
return [path12.join(copilotHome(home, env), "session-state")];
|
|
4680
5001
|
},
|
|
4681
5002
|
parseSessionFile: parseCopilotSessionFile
|
|
4682
5003
|
};
|
|
4683
5004
|
}
|
|
4684
5005
|
|
|
4685
5006
|
// src/adapters/opencode.ts
|
|
4686
|
-
import
|
|
4687
|
-
import
|
|
5007
|
+
import os6 from "node:os";
|
|
5008
|
+
import path13 from "node:path";
|
|
4688
5009
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
4689
5010
|
const { DatabaseSync } = await import("node:sqlite");
|
|
4690
5011
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -4715,7 +5036,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4715
5036
|
for (const session of sessions) {
|
|
4716
5037
|
const sessionId = session.id;
|
|
4717
5038
|
const cwd = session.directory || session.path || void 0;
|
|
4718
|
-
const project = cwd ?
|
|
5039
|
+
const project = cwd ? path13.basename(cwd) : void 0;
|
|
4719
5040
|
const sessionTs = msToIso(session.time_created);
|
|
4720
5041
|
events.push(baseOpenCodeEvent({
|
|
4721
5042
|
ts: sessionTs,
|
|
@@ -4823,7 +5144,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4823
5144
|
const provider = currentProvider;
|
|
4824
5145
|
const pathObj = objectField(info, "path");
|
|
4825
5146
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
4826
|
-
const assistantProject = assistantCwd ?
|
|
5147
|
+
const assistantProject = assistantCwd ? path13.basename(assistantCwd) : project;
|
|
4827
5148
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
4828
5149
|
const createdTs = timeCreated;
|
|
4829
5150
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -5069,33 +5390,33 @@ function opencodeUsageFromInfo(info) {
|
|
|
5069
5390
|
function opencodeConfigDir(home, env) {
|
|
5070
5391
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
5071
5392
|
if (override && override.trim()) {
|
|
5072
|
-
return
|
|
5393
|
+
return path13.resolve(override);
|
|
5073
5394
|
}
|
|
5074
5395
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
5075
5396
|
if (xdgConfig && xdgConfig.trim()) {
|
|
5076
|
-
return
|
|
5397
|
+
return path13.join(path13.resolve(xdgConfig), "opencode");
|
|
5077
5398
|
}
|
|
5078
|
-
return
|
|
5399
|
+
return path13.join(home, ".config", "opencode");
|
|
5079
5400
|
}
|
|
5080
5401
|
function opencodeDataCandidates(home, env) {
|
|
5081
5402
|
const xdgData = env?.XDG_DATA_HOME;
|
|
5082
|
-
const primary = xdgData && xdgData.trim() ?
|
|
5083
|
-
return [primary,
|
|
5403
|
+
const primary = xdgData && xdgData.trim() ? path13.join(path13.resolve(xdgData), "opencode", "opencode.db") : path13.join(home, ".local", "share", "opencode", "opencode.db");
|
|
5404
|
+
return [primary, path13.join(home, ".opencode", "opencode.db")];
|
|
5084
5405
|
}
|
|
5085
|
-
async function opencodeBackfillFiles(sourceRoot, home =
|
|
5086
|
-
const { stat:
|
|
5406
|
+
async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
|
|
5407
|
+
const { stat: stat13 } = await import("node:fs/promises");
|
|
5087
5408
|
if (sourceRoot) {
|
|
5088
5409
|
if (!sourceRoot.endsWith(".db")) {
|
|
5089
5410
|
return [];
|
|
5090
5411
|
}
|
|
5091
|
-
const info = await
|
|
5412
|
+
const info = await stat13(sourceRoot).catch(() => null);
|
|
5092
5413
|
if (!info) {
|
|
5093
5414
|
return [];
|
|
5094
5415
|
}
|
|
5095
5416
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
5096
5417
|
}
|
|
5097
5418
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
5098
|
-
const info = await
|
|
5419
|
+
const info = await stat13(candidatePath).catch(() => null);
|
|
5099
5420
|
if (info) {
|
|
5100
5421
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
5101
5422
|
}
|
|
@@ -5170,12 +5491,12 @@ function createOpenCodeAdapter() {
|
|
|
5170
5491
|
return opencodeConfigDir(home, env);
|
|
5171
5492
|
},
|
|
5172
5493
|
installedPath(home, env) {
|
|
5173
|
-
return
|
|
5494
|
+
return path13.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
5174
5495
|
},
|
|
5175
5496
|
async isInstalled(home, env) {
|
|
5176
5497
|
try {
|
|
5177
5498
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5178
|
-
return await pathExists2(
|
|
5499
|
+
return await pathExists2(path13.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path13.join(".opencode", PLUGIN_PATH));
|
|
5179
5500
|
} catch {
|
|
5180
5501
|
return false;
|
|
5181
5502
|
}
|
|
@@ -5183,7 +5504,7 @@ function createOpenCodeAdapter() {
|
|
|
5183
5504
|
installEntries(home, env) {
|
|
5184
5505
|
return [{
|
|
5185
5506
|
kind: "file",
|
|
5186
|
-
path:
|
|
5507
|
+
path: path13.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
5187
5508
|
content: opencodePluginContent()
|
|
5188
5509
|
}];
|
|
5189
5510
|
},
|
|
@@ -5196,7 +5517,7 @@ function createOpenCodeAdapter() {
|
|
|
5196
5517
|
|
|
5197
5518
|
// src/adapters/pi.ts
|
|
5198
5519
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
5199
|
-
import
|
|
5520
|
+
import path14 from "node:path";
|
|
5200
5521
|
async function parsePiSessionFile(filePath, options) {
|
|
5201
5522
|
const text = await readFile8(filePath, "utf8");
|
|
5202
5523
|
const lines = text.split("\n").filter(Boolean);
|
|
@@ -5229,7 +5550,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
5229
5550
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
5230
5551
|
state.sessionId = sessionId || state.sessionId;
|
|
5231
5552
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5232
|
-
project = cwd ?
|
|
5553
|
+
project = cwd ? path14.basename(cwd) : project;
|
|
5233
5554
|
continue;
|
|
5234
5555
|
}
|
|
5235
5556
|
if (entryType === "model_change") {
|
|
@@ -5638,16 +5959,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
5638
5959
|
function piAgentDir(home, env) {
|
|
5639
5960
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
5640
5961
|
if (override && override.trim()) {
|
|
5641
|
-
return
|
|
5962
|
+
return path14.resolve(override);
|
|
5642
5963
|
}
|
|
5643
|
-
return
|
|
5964
|
+
return path14.join(home, ".pi", "agent");
|
|
5644
5965
|
}
|
|
5645
5966
|
function piSessionDir(home, env) {
|
|
5646
5967
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
5647
5968
|
if (override && override.trim()) {
|
|
5648
|
-
return
|
|
5969
|
+
return path14.resolve(override);
|
|
5649
5970
|
}
|
|
5650
|
-
return
|
|
5971
|
+
return path14.join(piAgentDir(home, env), "sessions");
|
|
5651
5972
|
}
|
|
5652
5973
|
function createPiAdapter() {
|
|
5653
5974
|
return {
|
|
@@ -5659,12 +5980,12 @@ function createPiAdapter() {
|
|
|
5659
5980
|
return piAgentDir(home, env);
|
|
5660
5981
|
},
|
|
5661
5982
|
installedPath(home, env) {
|
|
5662
|
-
return
|
|
5983
|
+
return path14.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
5663
5984
|
},
|
|
5664
5985
|
async isInstalled(home, env) {
|
|
5665
5986
|
try {
|
|
5666
5987
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5667
|
-
return await pathExists2(
|
|
5988
|
+
return await pathExists2(path14.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
5668
5989
|
} catch {
|
|
5669
5990
|
return false;
|
|
5670
5991
|
}
|
|
@@ -5672,7 +5993,7 @@ function createPiAdapter() {
|
|
|
5672
5993
|
installEntries(home, env) {
|
|
5673
5994
|
return [{
|
|
5674
5995
|
kind: "file",
|
|
5675
|
-
path:
|
|
5996
|
+
path: path14.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
5676
5997
|
content: piExtensionContent()
|
|
5677
5998
|
}];
|
|
5678
5999
|
},
|
|
@@ -5684,11 +6005,11 @@ function createPiAdapter() {
|
|
|
5684
6005
|
}
|
|
5685
6006
|
|
|
5686
6007
|
// src/adapters/qoder-cn.ts
|
|
5687
|
-
import { readdir as readdir6, readFile as readFile9, stat as
|
|
5688
|
-
import
|
|
5689
|
-
import
|
|
6008
|
+
import { readdir as readdir6, readFile as readFile9, stat as stat7 } from "node:fs/promises";
|
|
6009
|
+
import os7 from "node:os";
|
|
6010
|
+
import path15 from "node:path";
|
|
5690
6011
|
function parseQoderCnPaths(filePath) {
|
|
5691
|
-
const parts = filePath.split(
|
|
6012
|
+
const parts = filePath.split(path15.sep);
|
|
5692
6013
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
5693
6014
|
let sessionId = "";
|
|
5694
6015
|
let projectName = "";
|
|
@@ -5697,19 +6018,19 @@ function parseQoderCnPaths(filePath) {
|
|
|
5697
6018
|
sessionId = parts[subagentsIdx - 1];
|
|
5698
6019
|
projectName = parts[subagentsIdx - 2];
|
|
5699
6020
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5700
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6021
|
+
configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
|
|
5701
6022
|
} else {
|
|
5702
6023
|
const filename = parts.at(-1) || "";
|
|
5703
|
-
sessionId =
|
|
6024
|
+
sessionId = path15.basename(filename, ".jsonl");
|
|
5704
6025
|
projectName = parts.at(-2) || "";
|
|
5705
6026
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5706
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6027
|
+
configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
|
|
5707
6028
|
}
|
|
5708
6029
|
return { configDir: configDir2, projectName, sessionId };
|
|
5709
6030
|
}
|
|
5710
6031
|
async function loadQoderCnModelNames(configDir2) {
|
|
5711
6032
|
try {
|
|
5712
|
-
const dynamicTextsPath =
|
|
6033
|
+
const dynamicTextsPath = path15.join(configDir2, ".auth", "dynamic-texts.json");
|
|
5713
6034
|
const content = await readFile9(dynamicTextsPath, "utf8");
|
|
5714
6035
|
const json = JSON.parse(content);
|
|
5715
6036
|
const texts = json.texts || {};
|
|
@@ -5727,7 +6048,7 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
5727
6048
|
}
|
|
5728
6049
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
5729
6050
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
5730
|
-
const segmentsPath =
|
|
6051
|
+
const segmentsPath = path15.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
5731
6052
|
const modelCalls = [];
|
|
5732
6053
|
try {
|
|
5733
6054
|
const files = await readdir6(segmentsPath);
|
|
@@ -5735,7 +6056,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
5735
6056
|
if (!file.endsWith(".jsonl")) {
|
|
5736
6057
|
continue;
|
|
5737
6058
|
}
|
|
5738
|
-
const content = await readFile9(
|
|
6059
|
+
const content = await readFile9(path15.join(segmentsPath, file), "utf8");
|
|
5739
6060
|
let currentTurnIsSubagent = false;
|
|
5740
6061
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
5741
6062
|
const raw = parseJsonLine(line);
|
|
@@ -5803,7 +6124,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
5803
6124
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
5804
6125
|
state.sessionId = sessionId;
|
|
5805
6126
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5806
|
-
project = projectContext.project || (cwd ?
|
|
6127
|
+
project = projectContext.project || (cwd ? path15.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
5807
6128
|
if (!ts) {
|
|
5808
6129
|
continue;
|
|
5809
6130
|
}
|
|
@@ -6232,35 +6553,40 @@ function isNoisePrompt(text) {
|
|
|
6232
6553
|
}
|
|
6233
6554
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6234
6555
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
6235
|
-
const isSubagent = filePath.includes(`${
|
|
6556
|
+
const isSubagent = filePath.includes(`${path15.sep}subagents${path15.sep}`);
|
|
6557
|
+
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
6236
6558
|
let cwds = [];
|
|
6237
6559
|
for (const line of lines) {
|
|
6238
6560
|
const raw = parseJsonLine(line);
|
|
6239
6561
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6240
|
-
if (cwd &&
|
|
6562
|
+
if (cwd && path15.isAbsolute(cwd)) {
|
|
6241
6563
|
cwds.push(cwd);
|
|
6242
6564
|
}
|
|
6243
6565
|
}
|
|
6244
6566
|
if (isSubagent) {
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
const
|
|
6249
|
-
|
|
6250
|
-
const
|
|
6251
|
-
const
|
|
6252
|
-
|
|
6253
|
-
|
|
6567
|
+
if (inherited?.cwd && path15.isAbsolute(inherited.cwd)) {
|
|
6568
|
+
cwds = [inherited.cwd];
|
|
6569
|
+
} else {
|
|
6570
|
+
const parentSessionPath = path15.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
6571
|
+
try {
|
|
6572
|
+
const parentText = await readFile9(parentSessionPath, "utf8");
|
|
6573
|
+
const parentCwds = [];
|
|
6574
|
+
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
6575
|
+
const raw = parseJsonLine(line);
|
|
6576
|
+
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6577
|
+
if (cwd && path15.isAbsolute(cwd)) {
|
|
6578
|
+
parentCwds.push(cwd);
|
|
6579
|
+
}
|
|
6254
6580
|
}
|
|
6581
|
+
if (parentCwds.length > 0) {
|
|
6582
|
+
cwds = parentCwds;
|
|
6583
|
+
}
|
|
6584
|
+
} catch {
|
|
6255
6585
|
}
|
|
6256
|
-
if (parentCwds.length > 0) {
|
|
6257
|
-
cwds = parentCwds;
|
|
6258
|
-
}
|
|
6259
|
-
} catch {
|
|
6260
6586
|
}
|
|
6261
6587
|
}
|
|
6262
6588
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
6263
|
-
const project = cwds.length > 0 ?
|
|
6589
|
+
const project = inherited?.project || (cwds.length > 0 ? path15.basename(cwds[0]) : root ? path15.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
|
|
6264
6590
|
return {
|
|
6265
6591
|
project,
|
|
6266
6592
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6269,15 +6595,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
6269
6595
|
async function gitRootFromCwds2(cwds) {
|
|
6270
6596
|
const seen = /* @__PURE__ */ new Set();
|
|
6271
6597
|
for (const cwd of cwds) {
|
|
6272
|
-
let current =
|
|
6598
|
+
let current = path15.resolve(cwd);
|
|
6273
6599
|
while (!seen.has(current)) {
|
|
6274
6600
|
seen.add(current);
|
|
6275
6601
|
try {
|
|
6276
|
-
await
|
|
6602
|
+
await stat7(path15.join(current, ".git"));
|
|
6277
6603
|
return current;
|
|
6278
6604
|
} catch {
|
|
6279
6605
|
}
|
|
6280
|
-
const parent =
|
|
6606
|
+
const parent = path15.dirname(current);
|
|
6281
6607
|
if (parent === current) {
|
|
6282
6608
|
break;
|
|
6283
6609
|
}
|
|
@@ -6288,12 +6614,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
6288
6614
|
}
|
|
6289
6615
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
6290
6616
|
for (const cwd of cwds) {
|
|
6291
|
-
let current =
|
|
6617
|
+
let current = path15.resolve(cwd);
|
|
6292
6618
|
while (true) {
|
|
6293
6619
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
6294
6620
|
return current;
|
|
6295
6621
|
}
|
|
6296
|
-
const parent =
|
|
6622
|
+
const parent = path15.dirname(current);
|
|
6297
6623
|
if (parent === current) {
|
|
6298
6624
|
break;
|
|
6299
6625
|
}
|
|
@@ -6303,14 +6629,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
6303
6629
|
return void 0;
|
|
6304
6630
|
}
|
|
6305
6631
|
function encodeQoderCnProjectPath(value) {
|
|
6306
|
-
return
|
|
6632
|
+
return path15.resolve(value).split(path15.sep).join("-").replace(/_/g, "-");
|
|
6307
6633
|
}
|
|
6308
6634
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
6309
|
-
const projectDir =
|
|
6310
|
-
const home = options ?
|
|
6635
|
+
const projectDir = path15.basename(path15.dirname(filePath));
|
|
6636
|
+
const home = options ? path15.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
|
|
6311
6637
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
6312
6638
|
if (resolved) {
|
|
6313
|
-
return
|
|
6639
|
+
return path15.basename(resolved);
|
|
6314
6640
|
}
|
|
6315
6641
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
6316
6642
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -6335,7 +6661,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
6335
6661
|
if (!entry.isDirectory()) {
|
|
6336
6662
|
continue;
|
|
6337
6663
|
}
|
|
6338
|
-
const candidate =
|
|
6664
|
+
const candidate = path15.join(current, entry.name);
|
|
6339
6665
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
6340
6666
|
if (encoded === projectDir) {
|
|
6341
6667
|
return candidate;
|
|
@@ -6380,9 +6706,9 @@ function hookConfig5() {
|
|
|
6380
6706
|
function qoderCnConfigDir(home, env) {
|
|
6381
6707
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
6382
6708
|
if (override && override.trim()) {
|
|
6383
|
-
return
|
|
6709
|
+
return path15.resolve(override);
|
|
6384
6710
|
}
|
|
6385
|
-
return
|
|
6711
|
+
return path15.join(home, ".qoder-cn");
|
|
6386
6712
|
}
|
|
6387
6713
|
function createQoderCnAdapter() {
|
|
6388
6714
|
return {
|
|
@@ -6394,27 +6720,27 @@ function createQoderCnAdapter() {
|
|
|
6394
6720
|
return qoderCnConfigDir(home, env);
|
|
6395
6721
|
},
|
|
6396
6722
|
installedPath(home, env) {
|
|
6397
|
-
return
|
|
6723
|
+
return path15.join(qoderCnConfigDir(home, env), "settings.json");
|
|
6398
6724
|
},
|
|
6399
6725
|
async isInstalled(home, env) {
|
|
6400
6726
|
return isHooksJsonInstalled(
|
|
6401
|
-
|
|
6727
|
+
path15.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6402
6728
|
"vibetime hook --agent qoder-cn"
|
|
6403
6729
|
);
|
|
6404
6730
|
},
|
|
6405
6731
|
installEntries(home, env) {
|
|
6406
6732
|
return [{
|
|
6407
6733
|
kind: "hooks-json",
|
|
6408
|
-
path:
|
|
6734
|
+
path: path15.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6409
6735
|
content: hookConfig5()
|
|
6410
6736
|
}];
|
|
6411
6737
|
},
|
|
6412
6738
|
sourcePaths(home, env) {
|
|
6413
6739
|
const base = qoderCnConfigDir(home, env);
|
|
6414
6740
|
return [
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6741
|
+
path15.join(base, "projects"),
|
|
6742
|
+
path15.join(base, ".qoder.json"),
|
|
6743
|
+
path15.join(home, ".qoder.json")
|
|
6418
6744
|
];
|
|
6419
6745
|
},
|
|
6420
6746
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -6422,11 +6748,11 @@ function createQoderCnAdapter() {
|
|
|
6422
6748
|
}
|
|
6423
6749
|
|
|
6424
6750
|
// src/adapters/qoder.ts
|
|
6425
|
-
import { readdir as readdir7, readFile as readFile10, stat as
|
|
6426
|
-
import
|
|
6427
|
-
import
|
|
6751
|
+
import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
|
|
6752
|
+
import os8 from "node:os";
|
|
6753
|
+
import path16 from "node:path";
|
|
6428
6754
|
function parseQoderPaths(filePath) {
|
|
6429
|
-
const parts = filePath.split(
|
|
6755
|
+
const parts = filePath.split(path16.sep);
|
|
6430
6756
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
6431
6757
|
let sessionId = "";
|
|
6432
6758
|
let projectName = "";
|
|
@@ -6435,19 +6761,19 @@ function parseQoderPaths(filePath) {
|
|
|
6435
6761
|
sessionId = parts[subagentsIdx - 1];
|
|
6436
6762
|
projectName = parts[subagentsIdx - 2];
|
|
6437
6763
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6438
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6764
|
+
configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
|
|
6439
6765
|
} else {
|
|
6440
6766
|
const filename = parts.at(-1) || "";
|
|
6441
|
-
sessionId =
|
|
6767
|
+
sessionId = path16.basename(filename, ".jsonl");
|
|
6442
6768
|
projectName = parts.at(-2) || "";
|
|
6443
6769
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6444
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6770
|
+
configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
|
|
6445
6771
|
}
|
|
6446
6772
|
return { configDir: configDir2, projectName, sessionId };
|
|
6447
6773
|
}
|
|
6448
6774
|
async function loadQoderModelNames(configDir2) {
|
|
6449
6775
|
try {
|
|
6450
|
-
const dynamicTextsPath =
|
|
6776
|
+
const dynamicTextsPath = path16.join(configDir2, ".auth", "dynamic-texts.json");
|
|
6451
6777
|
const content = await readFile10(dynamicTextsPath, "utf8");
|
|
6452
6778
|
const json = JSON.parse(content);
|
|
6453
6779
|
const texts = json.texts || {};
|
|
@@ -6465,7 +6791,7 @@ async function loadQoderModelNames(configDir2) {
|
|
|
6465
6791
|
}
|
|
6466
6792
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
6467
6793
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
6468
|
-
const segmentsPath =
|
|
6794
|
+
const segmentsPath = path16.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
6469
6795
|
const modelCalls = [];
|
|
6470
6796
|
try {
|
|
6471
6797
|
const files = await readdir7(segmentsPath);
|
|
@@ -6473,7 +6799,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
6473
6799
|
if (!file.endsWith(".jsonl")) {
|
|
6474
6800
|
continue;
|
|
6475
6801
|
}
|
|
6476
|
-
const content = await readFile10(
|
|
6802
|
+
const content = await readFile10(path16.join(segmentsPath, file), "utf8");
|
|
6477
6803
|
let currentTurnIsSubagent = false;
|
|
6478
6804
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
6479
6805
|
const raw = parseJsonLine(line);
|
|
@@ -6541,7 +6867,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
6541
6867
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
6542
6868
|
state.sessionId = sessionId;
|
|
6543
6869
|
cwd = stringField(raw, "cwd") || cwd;
|
|
6544
|
-
project = projectContext.project || (cwd ?
|
|
6870
|
+
project = projectContext.project || (cwd ? path16.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
6545
6871
|
if (!ts) {
|
|
6546
6872
|
continue;
|
|
6547
6873
|
}
|
|
@@ -6936,35 +7262,40 @@ function qoderExtractText(value) {
|
|
|
6936
7262
|
}
|
|
6937
7263
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6938
7264
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
6939
|
-
const isSubagent = filePath.includes(`${
|
|
7265
|
+
const isSubagent = filePath.includes(`${path16.sep}subagents${path16.sep}`);
|
|
7266
|
+
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
6940
7267
|
let cwds = [];
|
|
6941
7268
|
for (const line of lines) {
|
|
6942
7269
|
const raw = parseJsonLine(line);
|
|
6943
7270
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6944
|
-
if (cwd &&
|
|
7271
|
+
if (cwd && path16.isAbsolute(cwd)) {
|
|
6945
7272
|
cwds.push(cwd);
|
|
6946
7273
|
}
|
|
6947
7274
|
}
|
|
6948
7275
|
if (isSubagent) {
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
const
|
|
6953
|
-
|
|
6954
|
-
const
|
|
6955
|
-
const
|
|
6956
|
-
|
|
6957
|
-
|
|
7276
|
+
if (inherited?.cwd && path16.isAbsolute(inherited.cwd)) {
|
|
7277
|
+
cwds = [inherited.cwd];
|
|
7278
|
+
} else {
|
|
7279
|
+
const parentSessionPath = path16.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
7280
|
+
try {
|
|
7281
|
+
const parentText = await readFile10(parentSessionPath, "utf8");
|
|
7282
|
+
const parentCwds = [];
|
|
7283
|
+
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
7284
|
+
const raw = parseJsonLine(line);
|
|
7285
|
+
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7286
|
+
if (cwd && path16.isAbsolute(cwd)) {
|
|
7287
|
+
parentCwds.push(cwd);
|
|
7288
|
+
}
|
|
6958
7289
|
}
|
|
7290
|
+
if (parentCwds.length > 0) {
|
|
7291
|
+
cwds = parentCwds;
|
|
7292
|
+
}
|
|
7293
|
+
} catch {
|
|
6959
7294
|
}
|
|
6960
|
-
if (parentCwds.length > 0) {
|
|
6961
|
-
cwds = parentCwds;
|
|
6962
|
-
}
|
|
6963
|
-
} catch {
|
|
6964
7295
|
}
|
|
6965
7296
|
}
|
|
6966
7297
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
6967
|
-
const project = cwds.length > 0 ?
|
|
7298
|
+
const project = inherited?.project || (cwds.length > 0 ? path16.basename(cwds[0]) : root ? path16.basename(root) : await qoderProjectFromFilePath(filePath, options));
|
|
6968
7299
|
return {
|
|
6969
7300
|
project,
|
|
6970
7301
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6973,15 +7304,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
6973
7304
|
async function gitRootFromCwds3(cwds) {
|
|
6974
7305
|
const seen = /* @__PURE__ */ new Set();
|
|
6975
7306
|
for (const cwd of cwds) {
|
|
6976
|
-
let current =
|
|
7307
|
+
let current = path16.resolve(cwd);
|
|
6977
7308
|
while (!seen.has(current)) {
|
|
6978
7309
|
seen.add(current);
|
|
6979
7310
|
try {
|
|
6980
|
-
await
|
|
7311
|
+
await stat8(path16.join(current, ".git"));
|
|
6981
7312
|
return current;
|
|
6982
7313
|
} catch {
|
|
6983
7314
|
}
|
|
6984
|
-
const parent =
|
|
7315
|
+
const parent = path16.dirname(current);
|
|
6985
7316
|
if (parent === current) {
|
|
6986
7317
|
break;
|
|
6987
7318
|
}
|
|
@@ -6992,12 +7323,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
6992
7323
|
}
|
|
6993
7324
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
6994
7325
|
for (const cwd of cwds) {
|
|
6995
|
-
let current =
|
|
7326
|
+
let current = path16.resolve(cwd);
|
|
6996
7327
|
while (true) {
|
|
6997
7328
|
if (encodeQoderProjectPath(current) === projectDir) {
|
|
6998
7329
|
return current;
|
|
6999
7330
|
}
|
|
7000
|
-
const parent =
|
|
7331
|
+
const parent = path16.dirname(current);
|
|
7001
7332
|
if (parent === current) {
|
|
7002
7333
|
break;
|
|
7003
7334
|
}
|
|
@@ -7007,10 +7338,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
7007
7338
|
return void 0;
|
|
7008
7339
|
}
|
|
7009
7340
|
function encodeQoderProjectPath(value) {
|
|
7010
|
-
return
|
|
7341
|
+
return path16.resolve(value).split(path16.sep).join("-").replace(/_/g, "-");
|
|
7011
7342
|
}
|
|
7012
7343
|
function rawQoderProjectPath(value) {
|
|
7013
|
-
return
|
|
7344
|
+
return path16.resolve(value).split(path16.sep).join("-");
|
|
7014
7345
|
}
|
|
7015
7346
|
function qoderEncodedVariants(value) {
|
|
7016
7347
|
const raw = rawQoderProjectPath(value);
|
|
@@ -7026,11 +7357,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
7026
7357
|
return void 0;
|
|
7027
7358
|
}
|
|
7028
7359
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
7029
|
-
const projectDir =
|
|
7030
|
-
const home = options ?
|
|
7360
|
+
const projectDir = path16.basename(path16.dirname(filePath));
|
|
7361
|
+
const home = options ? path16.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
|
|
7031
7362
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
7032
7363
|
if (resolved) {
|
|
7033
|
-
return
|
|
7364
|
+
return path16.basename(resolved);
|
|
7034
7365
|
}
|
|
7035
7366
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
7036
7367
|
if (suffix) {
|
|
@@ -7056,7 +7387,7 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
7056
7387
|
if (!entry.isDirectory()) {
|
|
7057
7388
|
continue;
|
|
7058
7389
|
}
|
|
7059
|
-
const candidate =
|
|
7390
|
+
const candidate = path16.join(current, entry.name);
|
|
7060
7391
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
7061
7392
|
if (candidateVariants.includes(projectDir)) {
|
|
7062
7393
|
return candidate;
|
|
@@ -7101,9 +7432,9 @@ function hookConfig6() {
|
|
|
7101
7432
|
function qoderConfigDir(home, env) {
|
|
7102
7433
|
const override = env?.QODER_CONFIG_DIR;
|
|
7103
7434
|
if (override && override.trim()) {
|
|
7104
|
-
return
|
|
7435
|
+
return path16.resolve(override);
|
|
7105
7436
|
}
|
|
7106
|
-
return
|
|
7437
|
+
return path16.join(home, ".qoder");
|
|
7107
7438
|
}
|
|
7108
7439
|
function createQoderAdapter() {
|
|
7109
7440
|
return {
|
|
@@ -7115,27 +7446,27 @@ function createQoderAdapter() {
|
|
|
7115
7446
|
return qoderConfigDir(home, env);
|
|
7116
7447
|
},
|
|
7117
7448
|
installedPath(home, env) {
|
|
7118
|
-
return
|
|
7449
|
+
return path16.join(qoderConfigDir(home, env), "settings.json");
|
|
7119
7450
|
},
|
|
7120
7451
|
async isInstalled(home, env) {
|
|
7121
7452
|
return isHooksJsonInstalled(
|
|
7122
|
-
|
|
7453
|
+
path16.join(qoderConfigDir(home, env), "settings.json"),
|
|
7123
7454
|
"vibetime hook --agent qoder"
|
|
7124
7455
|
);
|
|
7125
7456
|
},
|
|
7126
7457
|
installEntries(home, env) {
|
|
7127
7458
|
return [{
|
|
7128
7459
|
kind: "hooks-json",
|
|
7129
|
-
path:
|
|
7460
|
+
path: path16.join(qoderConfigDir(home, env), "settings.json"),
|
|
7130
7461
|
content: hookConfig6()
|
|
7131
7462
|
}];
|
|
7132
7463
|
},
|
|
7133
7464
|
sourcePaths(home, env) {
|
|
7134
7465
|
const base = qoderConfigDir(home, env);
|
|
7135
7466
|
return [
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7467
|
+
path16.join(base, "projects"),
|
|
7468
|
+
path16.join(base, ".qoder.json"),
|
|
7469
|
+
path16.join(home, ".qoder.json")
|
|
7139
7470
|
];
|
|
7140
7471
|
},
|
|
7141
7472
|
parseSessionFile: parseQoderSessionFile
|
|
@@ -7170,21 +7501,21 @@ function normalizeId(id) {
|
|
|
7170
7501
|
}
|
|
7171
7502
|
|
|
7172
7503
|
// src/adapters/workbuddy.ts
|
|
7173
|
-
import { readFile as readFile11, readdir as readdir8, stat as
|
|
7174
|
-
import
|
|
7504
|
+
import { readFile as readFile11, readdir as readdir8, stat as stat9 } from "node:fs/promises";
|
|
7505
|
+
import path17 from "node:path";
|
|
7175
7506
|
init_fs();
|
|
7176
7507
|
function workbuddyProjectsDir(home, env) {
|
|
7177
7508
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
7178
7509
|
if (override && override.trim()) {
|
|
7179
|
-
return
|
|
7510
|
+
return path17.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
7180
7511
|
}
|
|
7181
|
-
return
|
|
7512
|
+
return path17.join(home, ".workbuddy", "projects");
|
|
7182
7513
|
}
|
|
7183
7514
|
function projectFromCwd(cwd, fallback) {
|
|
7184
7515
|
if (!cwd) {
|
|
7185
7516
|
return fallback;
|
|
7186
7517
|
}
|
|
7187
|
-
return
|
|
7518
|
+
return path17.basename(cwd) || fallback;
|
|
7188
7519
|
}
|
|
7189
7520
|
function sourceHash(filePath) {
|
|
7190
7521
|
return `sha256:${createStableHash(filePath)}`;
|
|
@@ -7286,8 +7617,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
7286
7617
|
}
|
|
7287
7618
|
const events = [];
|
|
7288
7619
|
const first = lines[0].record;
|
|
7289
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
7290
|
-
const fallbackProject =
|
|
7620
|
+
const sessionId = stringField(first, "sessionId") || path17.basename(filePath, ".jsonl");
|
|
7621
|
+
const fallbackProject = path17.basename(path17.dirname(filePath));
|
|
7291
7622
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
7292
7623
|
const project = projectFromCwd(cwd, fallbackProject);
|
|
7293
7624
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
@@ -7461,12 +7792,12 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
7461
7792
|
if (!project.isDirectory()) {
|
|
7462
7793
|
continue;
|
|
7463
7794
|
}
|
|
7464
|
-
const projectDir =
|
|
7795
|
+
const projectDir = path17.join(base, project.name);
|
|
7465
7796
|
const entries = await readdir8(projectDir, { withFileTypes: true });
|
|
7466
7797
|
for (const entry of entries) {
|
|
7467
7798
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
7468
|
-
const filePath =
|
|
7469
|
-
const info = await
|
|
7799
|
+
const filePath = path17.join(projectDir, entry.name);
|
|
7800
|
+
const info = await stat9(filePath);
|
|
7470
7801
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
7471
7802
|
}
|
|
7472
7803
|
}
|
|
@@ -7503,26 +7834,26 @@ function createWorkbuddyAdapter() {
|
|
|
7503
7834
|
|
|
7504
7835
|
// src/adapters/zcode.ts
|
|
7505
7836
|
import { execFile } from "node:child_process";
|
|
7506
|
-
import { readFile as readFile12, stat as
|
|
7507
|
-
import
|
|
7837
|
+
import { readFile as readFile12, stat as stat10 } from "node:fs/promises";
|
|
7838
|
+
import path18 from "node:path";
|
|
7508
7839
|
import { promisify as promisify2 } from "node:util";
|
|
7509
7840
|
init_fs();
|
|
7510
7841
|
var execFileAsync = promisify2(execFile);
|
|
7511
7842
|
function zcodeCliDir(home, env) {
|
|
7512
7843
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
7513
7844
|
if (override && override.trim()) {
|
|
7514
|
-
return
|
|
7845
|
+
return path18.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
7515
7846
|
}
|
|
7516
|
-
return
|
|
7847
|
+
return path18.join(home, ".zcode", "cli");
|
|
7517
7848
|
}
|
|
7518
7849
|
function zcodeDbPath(home, env) {
|
|
7519
|
-
return
|
|
7850
|
+
return path18.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
7520
7851
|
}
|
|
7521
7852
|
var providerNameCache = null;
|
|
7522
7853
|
async function loadProviderNames(configPath2) {
|
|
7523
7854
|
let fileMtime = 0;
|
|
7524
7855
|
try {
|
|
7525
|
-
const info = await
|
|
7856
|
+
const info = await stat10(configPath2);
|
|
7526
7857
|
fileMtime = info.mtimeMs;
|
|
7527
7858
|
} catch {
|
|
7528
7859
|
return /* @__PURE__ */ new Map();
|
|
@@ -7550,7 +7881,7 @@ function sourceHash2(filePath) {
|
|
|
7550
7881
|
return `sha256:${createStableHash(filePath)}`;
|
|
7551
7882
|
}
|
|
7552
7883
|
function projectFromDirectory(directory) {
|
|
7553
|
-
return directory ?
|
|
7884
|
+
return directory ? path18.basename(directory) || "zcode" : "zcode";
|
|
7554
7885
|
}
|
|
7555
7886
|
function isoFromMs(value) {
|
|
7556
7887
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
@@ -7706,16 +8037,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7706
8037
|
if (rows.length === 0) {
|
|
7707
8038
|
return [];
|
|
7708
8039
|
}
|
|
7709
|
-
let candidate =
|
|
8040
|
+
let candidate = path18.resolve(filePath);
|
|
7710
8041
|
let configPath2 = "";
|
|
7711
8042
|
for (let i = 0; i < 12; i++) {
|
|
7712
|
-
const probe =
|
|
8043
|
+
const probe = path18.join(candidate, ".zcode", "v2", "config.json");
|
|
7713
8044
|
try {
|
|
7714
|
-
await
|
|
8045
|
+
await stat10(probe);
|
|
7715
8046
|
configPath2 = probe;
|
|
7716
8047
|
break;
|
|
7717
8048
|
} catch {
|
|
7718
|
-
const parent =
|
|
8049
|
+
const parent = path18.dirname(candidate);
|
|
7719
8050
|
if (parent === candidate) break;
|
|
7720
8051
|
candidate = parent;
|
|
7721
8052
|
}
|
|
@@ -7931,9 +8262,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7931
8262
|
}
|
|
7932
8263
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
7933
8264
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
7934
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
8265
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path18.join(candidate, "db", "db.sqlite");
|
|
7935
8266
|
try {
|
|
7936
|
-
const info = await
|
|
8267
|
+
const info = await stat10(filePath);
|
|
7937
8268
|
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
7938
8269
|
} catch {
|
|
7939
8270
|
return [];
|
|
@@ -8305,7 +8636,7 @@ async function installEntry(entry, options) {
|
|
|
8305
8636
|
});
|
|
8306
8637
|
}
|
|
8307
8638
|
async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
|
|
8308
|
-
const { mkdir:
|
|
8639
|
+
const { mkdir: mkdir6, writeFile: writeFile5 } = await import("node:fs/promises");
|
|
8309
8640
|
const pathMod = await import("node:path");
|
|
8310
8641
|
if (dryRun) {
|
|
8311
8642
|
onWrite(`Would merge ${filePath}`);
|
|
@@ -8326,8 +8657,8 @@ async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
|
|
|
8326
8657
|
onWrite(`Already installed ${filePath}`);
|
|
8327
8658
|
return;
|
|
8328
8659
|
}
|
|
8329
|
-
await
|
|
8330
|
-
await
|
|
8660
|
+
await mkdir6(pathMod.dirname(filePath), { recursive: true });
|
|
8661
|
+
await writeFile5(filePath, nextText, "utf8");
|
|
8331
8662
|
onWrite(`Installed ${filePath}`);
|
|
8332
8663
|
}
|
|
8333
8664
|
function mergeAgyHooksJson(existing, addition) {
|
|
@@ -8405,15 +8736,15 @@ function hookCommandFromGroup(group) {
|
|
|
8405
8736
|
import { randomUUID } from "node:crypto";
|
|
8406
8737
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8407
8738
|
import { homedir, hostname } from "node:os";
|
|
8408
|
-
import
|
|
8739
|
+
import path19 from "node:path";
|
|
8409
8740
|
function configDir(home = homedir()) {
|
|
8410
|
-
return
|
|
8741
|
+
return path19.join(home, ".vibetime");
|
|
8411
8742
|
}
|
|
8412
8743
|
function configPath(home = homedir()) {
|
|
8413
|
-
return
|
|
8744
|
+
return path19.join(configDir(home), "config.json");
|
|
8414
8745
|
}
|
|
8415
8746
|
function machineIdPath(home = homedir()) {
|
|
8416
|
-
return
|
|
8747
|
+
return path19.join(configDir(home), "machine-id");
|
|
8417
8748
|
}
|
|
8418
8749
|
function readConfig(home = homedir()) {
|
|
8419
8750
|
const file = configPath(home);
|
|
@@ -8460,15 +8791,15 @@ function defaultMachineName() {
|
|
|
8460
8791
|
init_fs();
|
|
8461
8792
|
|
|
8462
8793
|
// src/lib/logger.ts
|
|
8463
|
-
import { appendFile, mkdir as
|
|
8794
|
+
import { appendFile, mkdir as mkdir4, rename, stat as stat11 } from "node:fs/promises";
|
|
8464
8795
|
import { homedir as homedir2 } from "node:os";
|
|
8465
|
-
import
|
|
8796
|
+
import path20 from "node:path";
|
|
8466
8797
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
8467
8798
|
function logDir(home = homedir2()) {
|
|
8468
|
-
return
|
|
8799
|
+
return path20.join(home, ".vibetime", "logs");
|
|
8469
8800
|
}
|
|
8470
8801
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
8471
|
-
return
|
|
8802
|
+
return path20.join(logDir(home), name);
|
|
8472
8803
|
}
|
|
8473
8804
|
function serializeError(error) {
|
|
8474
8805
|
if (error instanceof Error) {
|
|
@@ -8478,7 +8809,7 @@ function serializeError(error) {
|
|
|
8478
8809
|
}
|
|
8479
8810
|
async function rotateIfNeeded(file) {
|
|
8480
8811
|
try {
|
|
8481
|
-
const info = await
|
|
8812
|
+
const info = await stat11(file);
|
|
8482
8813
|
if (info.size > MAX_BYTES) {
|
|
8483
8814
|
await rename(file, `${file}.1`).catch(() => {
|
|
8484
8815
|
});
|
|
@@ -8489,7 +8820,7 @@ async function rotateIfNeeded(file) {
|
|
|
8489
8820
|
async function writeLog(entry, home = homedir2(), fileName = "cli.log") {
|
|
8490
8821
|
try {
|
|
8491
8822
|
const dir = logDir(home);
|
|
8492
|
-
await
|
|
8823
|
+
await mkdir4(dir, { recursive: true });
|
|
8493
8824
|
const file = logPath(home, fileName);
|
|
8494
8825
|
await rotateIfNeeded(file);
|
|
8495
8826
|
const record = {
|
|
@@ -8643,8 +8974,8 @@ function buildHeaders(token, machine) {
|
|
|
8643
8974
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
8644
8975
|
};
|
|
8645
8976
|
}
|
|
8646
|
-
function joinUrl(base,
|
|
8647
|
-
return new URL(
|
|
8977
|
+
function joinUrl(base, path22) {
|
|
8978
|
+
return new URL(path22, base.endsWith("/") ? base : `${base}/`).toString();
|
|
8648
8979
|
}
|
|
8649
8980
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
8650
8981
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -8709,7 +9040,7 @@ async function deleteMachine(remote, id) {
|
|
|
8709
9040
|
}
|
|
8710
9041
|
|
|
8711
9042
|
// src/lib/types.ts
|
|
8712
|
-
var BACKFILL_STATE_SCHEMA_VERSION =
|
|
9043
|
+
var BACKFILL_STATE_SCHEMA_VERSION = 6;
|
|
8713
9044
|
|
|
8714
9045
|
// src/cli.ts
|
|
8715
9046
|
function createRegistry() {
|
|
@@ -8734,7 +9065,7 @@ var defaultContext = {
|
|
|
8734
9065
|
stdout: process.stdout,
|
|
8735
9066
|
stderr: process.stderr,
|
|
8736
9067
|
fetch: globalThis.fetch,
|
|
8737
|
-
spawn
|
|
9068
|
+
spawn: spawn2
|
|
8738
9069
|
};
|
|
8739
9070
|
async function run(argv, context = {}) {
|
|
8740
9071
|
const ctx = { ...defaultContext, ...context };
|
|
@@ -8816,7 +9147,7 @@ function normalizeOptions(options) {
|
|
|
8816
9147
|
return normalized;
|
|
8817
9148
|
}
|
|
8818
9149
|
async function detectCommand(options, ctx, registry) {
|
|
8819
|
-
const home =
|
|
9150
|
+
const home = resolveHome3(options, ctx);
|
|
8820
9151
|
const env = ctx.env;
|
|
8821
9152
|
const adapters = registry.all();
|
|
8822
9153
|
const targets = await Promise.all(adapters.map(async (adapter) => {
|
|
@@ -8845,7 +9176,7 @@ async function detectCommand(options, ctx, registry) {
|
|
|
8845
9176
|
}
|
|
8846
9177
|
}
|
|
8847
9178
|
async function installCommand(options, ctx, registry) {
|
|
8848
|
-
const home =
|
|
9179
|
+
const home = resolveHome3(options, ctx);
|
|
8849
9180
|
const env = ctx.env;
|
|
8850
9181
|
const dryRun = Boolean(options["dry-run"]);
|
|
8851
9182
|
const force = Boolean(options.force);
|
|
@@ -8885,7 +9216,9 @@ async function fetchLatestVersion() {
|
|
|
8885
9216
|
headers: { Accept: "application/json" },
|
|
8886
9217
|
signal: AbortSignal.timeout(1e4)
|
|
8887
9218
|
});
|
|
8888
|
-
if (!response.ok)
|
|
9219
|
+
if (!response.ok) {
|
|
9220
|
+
return null;
|
|
9221
|
+
}
|
|
8889
9222
|
const data = await response.json();
|
|
8890
9223
|
return typeof data.version === "string" ? data.version : null;
|
|
8891
9224
|
} catch {
|
|
@@ -8898,8 +9231,12 @@ function compareVersions(a, b) {
|
|
|
8898
9231
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
8899
9232
|
const na = pa[i] ?? 0;
|
|
8900
9233
|
const nb = pb[i] ?? 0;
|
|
8901
|
-
if (na > nb)
|
|
8902
|
-
|
|
9234
|
+
if (na > nb) {
|
|
9235
|
+
return 1;
|
|
9236
|
+
}
|
|
9237
|
+
if (na < nb) {
|
|
9238
|
+
return -1;
|
|
9239
|
+
}
|
|
8903
9240
|
}
|
|
8904
9241
|
return 0;
|
|
8905
9242
|
}
|
|
@@ -8943,7 +9280,7 @@ Upgraded ${current} \u2192 ${latest}
|
|
|
8943
9280
|
return 0;
|
|
8944
9281
|
}
|
|
8945
9282
|
async function hookCommand(options, ctx) {
|
|
8946
|
-
const home =
|
|
9283
|
+
const home = resolveHome3(options, ctx);
|
|
8947
9284
|
try {
|
|
8948
9285
|
const agent = requiredOption(options, "agent");
|
|
8949
9286
|
const payload = await readHookPayload(ctx.stdin);
|
|
@@ -8956,6 +9293,7 @@ async function hookCommand(options, ctx) {
|
|
|
8956
9293
|
`);
|
|
8957
9294
|
return 0;
|
|
8958
9295
|
}
|
|
9296
|
+
await persistHookSessionContext(home, payload);
|
|
8959
9297
|
return await syncLocalTriggerCommand({
|
|
8960
9298
|
...options,
|
|
8961
9299
|
agent,
|
|
@@ -8969,7 +9307,7 @@ async function hookCommand(options, ctx) {
|
|
|
8969
9307
|
}
|
|
8970
9308
|
}
|
|
8971
9309
|
async function syncLocalTriggerCommand(options, ctx, _registry) {
|
|
8972
|
-
const home =
|
|
9310
|
+
const home = resolveHome3(options, ctx);
|
|
8973
9311
|
const statePath = syncLocalTriggerStatePath(home);
|
|
8974
9312
|
const lockPath = syncLocalTriggerLockPath(home);
|
|
8975
9313
|
const minIntervalSeconds = Math.max(0, Math.floor(numberOption(options["min-interval"]) ?? DEFAULT_HOOK_SYNC_MIN_INTERVAL_SECONDS));
|
|
@@ -9001,18 +9339,38 @@ async function syncLocalTriggerCommand(options, ctx, _registry) {
|
|
|
9001
9339
|
`);
|
|
9002
9340
|
return 0;
|
|
9003
9341
|
}
|
|
9004
|
-
const
|
|
9005
|
-
|
|
9006
|
-
|
|
9342
|
+
const acquired = await acquireSyncLocalLock(lockPath, {
|
|
9343
|
+
pid: process.pid,
|
|
9344
|
+
startedAt: now
|
|
9345
|
+
});
|
|
9346
|
+
if (!acquired) {
|
|
9347
|
+
const current = await readSyncLocalLock(lockPath);
|
|
9348
|
+
if (options.json) {
|
|
9349
|
+
write(ctx.stdout, `${JSON.stringify({
|
|
9350
|
+
status: "already-running",
|
|
9351
|
+
...current ? { pid: current.pid, startedAt: current.startedAt } : {}
|
|
9352
|
+
}, null, 2)}
|
|
9353
|
+
`);
|
|
9354
|
+
}
|
|
9355
|
+
return 0;
|
|
9356
|
+
}
|
|
9357
|
+
try {
|
|
9358
|
+
const child = spawnSyncLocalRunner({ options, ctx, home, lockPath, statePath, triggeredAt: now });
|
|
9359
|
+
if (typeof child.pid !== "number") {
|
|
9360
|
+
throw new TypeError("Could not start background sync-local runner");
|
|
9361
|
+
}
|
|
9362
|
+
state.lastTriggeredAt = now;
|
|
9363
|
+
state.pid = child.pid;
|
|
9364
|
+
await writeSyncLocalTriggerState(statePath, state);
|
|
9365
|
+
await writeSyncLocalLock(lockPath, { pid: child.pid, startedAt: now });
|
|
9366
|
+
return 0;
|
|
9367
|
+
} catch (error) {
|
|
9368
|
+
await clearSyncLocalLock(lockPath);
|
|
9369
|
+
throw error;
|
|
9007
9370
|
}
|
|
9008
|
-
state.lastTriggeredAt = now;
|
|
9009
|
-
state.pid = child.pid;
|
|
9010
|
-
await writeSyncLocalTriggerState(statePath, state);
|
|
9011
|
-
await writeSyncLocalLock(lockPath, { pid: child.pid, startedAt: now });
|
|
9012
|
-
return 0;
|
|
9013
9371
|
}
|
|
9014
9372
|
async function syncLocalRunnerCommand(options, ctx, _registry) {
|
|
9015
|
-
const home =
|
|
9373
|
+
const home = resolveHome3(options, ctx);
|
|
9016
9374
|
const lockPath = stringOption(options["lock-file"]) || syncLocalTriggerLockPath(home);
|
|
9017
9375
|
const statePath = stringOption(options["state-file"]) || syncLocalTriggerStatePath(home);
|
|
9018
9376
|
const state = await readSyncLocalTriggerState(statePath);
|
|
@@ -9072,7 +9430,7 @@ async function backfillCommand(options, ctx, registry) {
|
|
|
9072
9430
|
return importBackfillPlan(plan, options, ctx, reg);
|
|
9073
9431
|
}
|
|
9074
9432
|
async function createBackfillPlanFromOptions(options, ctx, action, registry) {
|
|
9075
|
-
const home =
|
|
9433
|
+
const home = resolveHome3(options, ctx);
|
|
9076
9434
|
const env = ctx.env;
|
|
9077
9435
|
const source = normalizeBackfillSource(stringOption(options.source) || "all");
|
|
9078
9436
|
const sourceDefs = source === "all" ? registry.all().map((a) => ({ id: a.id, label: a.label, paths: a.sourcePaths(home, env) })) : (() => {
|
|
@@ -9141,7 +9499,7 @@ async function createBackfillPlanFromOptions(options, ctx, action, registry) {
|
|
|
9141
9499
|
}
|
|
9142
9500
|
async function createBackfillEventsFromDefs(sourceDefs, options, registry, ctx, overrideFiles) {
|
|
9143
9501
|
const events = [];
|
|
9144
|
-
const home =
|
|
9502
|
+
const home = resolveHome3(options, ctx);
|
|
9145
9503
|
for (const item of sourceDefs) {
|
|
9146
9504
|
const parser = registry.getParser(item.id);
|
|
9147
9505
|
if (!parser) {
|
|
@@ -9191,31 +9549,31 @@ async function createBackfillCandidates(source, options) {
|
|
|
9191
9549
|
}
|
|
9192
9550
|
async function listBackfillSourceFiles(source, options, ctx) {
|
|
9193
9551
|
if (source.id === "opencode") {
|
|
9194
|
-
return opencodeBackfillFiles(stringOption(options["source-root"]),
|
|
9552
|
+
return opencodeBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9195
9553
|
}
|
|
9196
9554
|
if (source.id === "agy") {
|
|
9197
|
-
return agyBackfillFiles(stringOption(options["source-root"]),
|
|
9555
|
+
return agyBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9198
9556
|
}
|
|
9199
9557
|
if (source.id === "claude-cowork") {
|
|
9200
|
-
return claudeCoworkBackfillFiles(stringOption(options["source-root"]),
|
|
9558
|
+
return claudeCoworkBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9201
9559
|
}
|
|
9202
9560
|
if (source.id === "codebuddy") {
|
|
9203
|
-
return codebuddyBackfillFiles(stringOption(options["source-root"]),
|
|
9561
|
+
return codebuddyBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9204
9562
|
}
|
|
9205
9563
|
if (source.id === "workbuddy") {
|
|
9206
|
-
return workbuddyBackfillFiles(stringOption(options["source-root"]),
|
|
9564
|
+
return workbuddyBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9207
9565
|
}
|
|
9208
9566
|
if (source.id === "zcode") {
|
|
9209
|
-
return zcodeBackfillFiles(stringOption(options["source-root"]),
|
|
9567
|
+
return zcodeBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9210
9568
|
}
|
|
9211
9569
|
if (source.id === "copilot") {
|
|
9212
|
-
return copilotBackfillFiles(stringOption(options["source-root"]),
|
|
9570
|
+
return copilotBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9213
9571
|
}
|
|
9214
9572
|
const roots = stringOption(options["source-root"]) ? [requiredOption(options, "source-root")] : source.paths;
|
|
9215
9573
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
9216
9574
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
9217
9575
|
return Promise.all(files.map(async (filePath) => {
|
|
9218
|
-
const info = await
|
|
9576
|
+
const info = await stat12(filePath);
|
|
9219
9577
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
9220
9578
|
}));
|
|
9221
9579
|
}
|
|
@@ -9292,7 +9650,7 @@ function writeBackfillPlan(plan, options, ctx) {
|
|
|
9292
9650
|
async function importBackfillPlan(plan, options, ctx, registry) {
|
|
9293
9651
|
const source = normalizeBackfillSource(stringOption(options.source) || "all");
|
|
9294
9652
|
const supportedSources = new Set(BACKFILL_SOURCE_IDS);
|
|
9295
|
-
const home =
|
|
9653
|
+
const home = resolveHome3(options, ctx);
|
|
9296
9654
|
if (source !== "all" && !supportedSources.has(source)) {
|
|
9297
9655
|
write(ctx.stderr, `Unsupported backfill source: ${source}
|
|
9298
9656
|
`);
|
|
@@ -9361,7 +9719,7 @@ async function purgeForcedSources(sourceDefs, home, remoteKey, options, ctx) {
|
|
|
9361
9719
|
async function collectCanonicalEvents(sourceDefs, registry, incrementalState, options, ctx) {
|
|
9362
9720
|
const selectedFilesBySource = /* @__PURE__ */ new Map();
|
|
9363
9721
|
const canonicalEvents = [];
|
|
9364
|
-
const home =
|
|
9722
|
+
const home = resolveHome3(options, ctx);
|
|
9365
9723
|
for (const item of sourceDefs) {
|
|
9366
9724
|
const parser = registry.getParser(item.id);
|
|
9367
9725
|
if (!parser) {
|
|
@@ -9465,7 +9823,7 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
|
|
|
9465
9823
|
if (!remote) {
|
|
9466
9824
|
throw new Error("No fetch available for HTTP upload");
|
|
9467
9825
|
}
|
|
9468
|
-
const home =
|
|
9826
|
+
const home = resolveHome3(options, ctx);
|
|
9469
9827
|
const cfg = readConfig(home);
|
|
9470
9828
|
const machine = {
|
|
9471
9829
|
id: ensureLocalMachineId(home),
|
|
@@ -9484,7 +9842,7 @@ async function deleteSessionRollupsBySourceAPI(source, options, ctx) {
|
|
|
9484
9842
|
if (!remote) {
|
|
9485
9843
|
throw new Error("No fetch available for HTTP delete");
|
|
9486
9844
|
}
|
|
9487
|
-
const home =
|
|
9845
|
+
const home = resolveHome3(options, ctx);
|
|
9488
9846
|
return deleteRollupsBySource(remote, source, {
|
|
9489
9847
|
id: ensureLocalMachineId(home),
|
|
9490
9848
|
hostname: defaultMachineName(),
|
|
@@ -9528,13 +9886,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
9528
9886
|
});
|
|
9529
9887
|
}
|
|
9530
9888
|
function backfillIncrementalStatePath(home) {
|
|
9531
|
-
return
|
|
9889
|
+
return path21.join(home, ".vibetime", "backfill-state.json");
|
|
9532
9890
|
}
|
|
9533
9891
|
function syncLocalTriggerStatePath(home) {
|
|
9534
|
-
return
|
|
9892
|
+
return path21.join(home, ".vibetime", "sync-local-trigger.json");
|
|
9535
9893
|
}
|
|
9536
9894
|
function syncLocalTriggerLockPath(home) {
|
|
9537
|
-
return
|
|
9895
|
+
return path21.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
9538
9896
|
}
|
|
9539
9897
|
function backfillRemoteKey(baseUrl) {
|
|
9540
9898
|
try {
|
|
@@ -9596,8 +9954,8 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
9596
9954
|
}
|
|
9597
9955
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
9598
9956
|
const statePath = backfillIncrementalStatePath(home);
|
|
9599
|
-
await
|
|
9600
|
-
await
|
|
9957
|
+
await mkdir5(path21.dirname(statePath), { recursive: true });
|
|
9958
|
+
await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
|
|
9601
9959
|
`, "utf8");
|
|
9602
9960
|
}
|
|
9603
9961
|
async function readBackfillIncrementalState(home, remoteKey, ctx) {
|
|
@@ -9645,9 +10003,9 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
9645
10003
|
return nextState;
|
|
9646
10004
|
}
|
|
9647
10005
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
9648
|
-
await
|
|
9649
|
-
const tmpPath = `${statePath}.tmp`;
|
|
9650
|
-
await
|
|
10006
|
+
await mkdir5(path21.dirname(statePath), { recursive: true });
|
|
10007
|
+
const tmpPath = `${statePath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
10008
|
+
await writeFile4(tmpPath, `${JSON.stringify(state, null, 2)}
|
|
9651
10009
|
`, "utf8");
|
|
9652
10010
|
await rename2(tmpPath, statePath);
|
|
9653
10011
|
}
|
|
@@ -9662,10 +10020,28 @@ async function readSyncLocalLock(lockPath) {
|
|
|
9662
10020
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
9663
10021
|
}
|
|
9664
10022
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
9665
|
-
await
|
|
9666
|
-
await
|
|
10023
|
+
await mkdir5(path21.dirname(lockPath), { recursive: true });
|
|
10024
|
+
await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
9667
10025
|
`, "utf8");
|
|
9668
10026
|
}
|
|
10027
|
+
async function acquireSyncLocalLock(lockPath, lock) {
|
|
10028
|
+
await mkdir5(path21.dirname(lockPath), { recursive: true });
|
|
10029
|
+
try {
|
|
10030
|
+
const handle = await open(lockPath, "wx");
|
|
10031
|
+
try {
|
|
10032
|
+
await handle.writeFile(`${JSON.stringify(lock, null, 2)}
|
|
10033
|
+
`, "utf8");
|
|
10034
|
+
} finally {
|
|
10035
|
+
await handle.close();
|
|
10036
|
+
}
|
|
10037
|
+
return true;
|
|
10038
|
+
} catch (error) {
|
|
10039
|
+
if (error.code === "EEXIST") {
|
|
10040
|
+
return false;
|
|
10041
|
+
}
|
|
10042
|
+
throw error;
|
|
10043
|
+
}
|
|
10044
|
+
}
|
|
9669
10045
|
async function clearSyncLocalLock(lockPath) {
|
|
9670
10046
|
try {
|
|
9671
10047
|
await rm(lockPath, { force: true });
|
|
@@ -9701,12 +10077,19 @@ function spawnSyncLocalRunner(input) {
|
|
|
9701
10077
|
const child = input.ctx.spawn(process.execPath, args, {
|
|
9702
10078
|
detached: true,
|
|
9703
10079
|
stdio: "ignore",
|
|
9704
|
-
cwd:
|
|
9705
|
-
env:
|
|
10080
|
+
cwd: resolveSpawnCwd(input.home),
|
|
10081
|
+
env: input.ctx.env
|
|
9706
10082
|
});
|
|
9707
10083
|
child.unref();
|
|
9708
10084
|
return child;
|
|
9709
10085
|
}
|
|
10086
|
+
function resolveSpawnCwd(home) {
|
|
10087
|
+
try {
|
|
10088
|
+
return process.cwd();
|
|
10089
|
+
} catch {
|
|
10090
|
+
return home;
|
|
10091
|
+
}
|
|
10092
|
+
}
|
|
9710
10093
|
function syncLocalRunnerArgs(input) {
|
|
9711
10094
|
const args = syncLocalRunnerEntryArgs(fileURLToPath(import.meta.url));
|
|
9712
10095
|
args.push("sync-local-runner", "--home", input.home, "--lock-file", input.lockPath, "--state-file", input.statePath);
|
|
@@ -9722,10 +10105,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
9722
10105
|
if (cliPath.endsWith(".ts")) {
|
|
9723
10106
|
return ["--import", "tsx", cliPath];
|
|
9724
10107
|
}
|
|
9725
|
-
return [
|
|
10108
|
+
return [path21.resolve(path21.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
9726
10109
|
}
|
|
9727
|
-
function
|
|
9728
|
-
return
|
|
10110
|
+
function resolveHome3(options, ctx) {
|
|
10111
|
+
return path21.resolve(stringOption(options.home) || ctx.env.HOME || os9.homedir());
|
|
9729
10112
|
}
|
|
9730
10113
|
function requestedTargets(options) {
|
|
9731
10114
|
const value = options.target || options.targets;
|
|
@@ -9788,7 +10171,7 @@ function maskToken(token) {
|
|
|
9788
10171
|
}
|
|
9789
10172
|
async function tokenCommand(action, value, options, ctx) {
|
|
9790
10173
|
const verb = action || "show";
|
|
9791
|
-
const home =
|
|
10174
|
+
const home = resolveHome3(options, ctx);
|
|
9792
10175
|
if (verb === "set") {
|
|
9793
10176
|
if (!value || value.trim().length === 0) {
|
|
9794
10177
|
write(ctx.stderr, "Usage: vibetime token set <token> [--remote <url>]\n");
|
|
@@ -9860,7 +10243,7 @@ async function machineCommand(action, options, ctx) {
|
|
|
9860
10243
|
return 0;
|
|
9861
10244
|
}
|
|
9862
10245
|
if (verb === "rename") {
|
|
9863
|
-
const home =
|
|
10246
|
+
const home = resolveHome3(options, ctx);
|
|
9864
10247
|
const id = stringOption(options.id) || ensureLocalMachineId(home);
|
|
9865
10248
|
const name = stringOption(options.name);
|
|
9866
10249
|
if (!name) {
|