@yhong91/vibetime 0.1.11 → 0.1.12
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 +515 -176
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -159,9 +159,9 @@ var init_fs = __esm({
|
|
|
159
159
|
|
|
160
160
|
// src/cli.ts
|
|
161
161
|
import { spawn } from "node:child_process";
|
|
162
|
-
import { mkdir as mkdir4, rename as rename2, rm, stat as
|
|
163
|
-
import
|
|
164
|
-
import
|
|
162
|
+
import { mkdir as mkdir4, rename as rename2, rm, stat as stat11, writeFile as writeFile3 } from "node:fs/promises";
|
|
163
|
+
import os8 from "node:os";
|
|
164
|
+
import path19 from "node:path";
|
|
165
165
|
import { fileURLToPath } from "node:url";
|
|
166
166
|
|
|
167
167
|
// ../shared/src/index.ts
|
|
@@ -197,7 +197,7 @@ var TELEMETRY_EVENT_TYPES = [
|
|
|
197
197
|
"agent.operation"
|
|
198
198
|
];
|
|
199
199
|
var FILE_ACTIVITY_OPERATIONS = ["read", "search", "create", "write", "edit", "delete"];
|
|
200
|
-
var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode"];
|
|
200
|
+
var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode"];
|
|
201
201
|
function createWorkspaceId(input) {
|
|
202
202
|
const basis = input.repoUrl || input.repoRoot || input.projectName || "unknown";
|
|
203
203
|
return `workspace_${fnv1a(basis)}`;
|
|
@@ -1195,7 +1195,7 @@ function countTextLines(text) {
|
|
|
1195
1195
|
}
|
|
1196
1196
|
|
|
1197
1197
|
// src/lib/constants.ts
|
|
1198
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
1198
|
+
var PACKAGE_VERSION = true ? "0.1.12" : "0.1.1";
|
|
1199
1199
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
1200
1200
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
1201
1201
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -1651,49 +1651,52 @@ function detectModel(content, currentModel) {
|
|
|
1651
1651
|
return currentModel;
|
|
1652
1652
|
}
|
|
1653
1653
|
function resolveModelName(text) {
|
|
1654
|
-
|
|
1654
|
+
const cleaned = text.replace(/\s*\([^)]*\)\s*/g, " ").trim();
|
|
1655
|
+
if (cleaned.includes("Claude Opus 4.7") || cleaned.includes("claude-opus-4.7")) {
|
|
1655
1656
|
return "claude-opus-4.7";
|
|
1656
1657
|
}
|
|
1657
|
-
if (
|
|
1658
|
+
if (cleaned.includes("Claude Opus 4.6") || cleaned.includes("claude-opus-4.6")) {
|
|
1658
1659
|
return "claude-opus-4.6";
|
|
1659
1660
|
}
|
|
1660
|
-
if (
|
|
1661
|
+
if (cleaned.includes("Claude Sonnet 4.6") || cleaned.includes("claude-sonnet-4.6")) {
|
|
1661
1662
|
return "claude-sonnet-4.6";
|
|
1662
1663
|
}
|
|
1663
|
-
if (
|
|
1664
|
+
if (cleaned.includes("Claude Sonnet 4.5") || cleaned.includes("claude-sonnet-4.5")) {
|
|
1664
1665
|
return "claude-sonnet-4.5";
|
|
1665
1666
|
}
|
|
1666
|
-
if (
|
|
1667
|
+
if (cleaned.includes("Claude Haiku") || cleaned.includes("claude-haiku")) {
|
|
1667
1668
|
return "claude-haiku-4.5";
|
|
1668
1669
|
}
|
|
1669
|
-
if (
|
|
1670
|
+
if (cleaned.includes("Gemini 3.5 Flash") || cleaned.includes("gemini-3.5-flash")) {
|
|
1670
1671
|
return "gemini-3.5-flash";
|
|
1671
1672
|
}
|
|
1672
|
-
if (
|
|
1673
|
+
if (cleaned.includes("Gemini 3.5 Pro") || cleaned.includes("gemini-3.5-pro")) {
|
|
1673
1674
|
return "gemini-3.5-pro";
|
|
1674
1675
|
}
|
|
1675
|
-
if (
|
|
1676
|
+
if (cleaned.includes("Gemini 2.5 Flash") || cleaned.includes("gemini-2.5-flash")) {
|
|
1676
1677
|
return "gemini-2.5-flash";
|
|
1677
1678
|
}
|
|
1678
|
-
if (
|
|
1679
|
+
if (cleaned.includes("Gemini 2.5 Pro") || cleaned.includes("gemini-2.5-pro")) {
|
|
1679
1680
|
return "gemini-2.5-pro";
|
|
1680
1681
|
}
|
|
1681
1682
|
return null;
|
|
1682
1683
|
}
|
|
1683
1684
|
var AGY_USAGE_TIME_MATCH_TOLERANCE_MS = 5 * 60 * 1e3;
|
|
1685
|
+
var AGY_RESPONSE_MODEL_ALIASES = {
|
|
1686
|
+
"gemini-3-flash-a": "Gemini 3.5 Flash (Medium)",
|
|
1687
|
+
"gemini-3-flash-b": "Gemini 3.5 Flash (High)",
|
|
1688
|
+
"claude-sonnet-4-6": "Claude Sonnet 4.6 (Thinking)",
|
|
1689
|
+
"claude-opus-4-6-thinking": "Claude Opus 4.6 (Thinking)"
|
|
1690
|
+
};
|
|
1684
1691
|
function usageMetadataFromGenerator(item) {
|
|
1685
1692
|
const usage = item.chatModel?.usage;
|
|
1686
1693
|
if (!usage) {
|
|
1687
1694
|
return null;
|
|
1688
1695
|
}
|
|
1689
1696
|
const chatModel = item.chatModel;
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
usage.model,
|
|
1694
|
-
chatModel.model
|
|
1695
|
-
];
|
|
1696
|
-
const model = modelCandidates.filter((candidate) => typeof candidate === "string" && !candidate.startsWith("MODEL_PLACEHOLDER_")).map(resolveModelName).find(Boolean) ?? null;
|
|
1697
|
+
const modelDisplayName = typeof chatModel.modelDisplayName === "string" && !chatModel.modelDisplayName.startsWith("MODEL_PLACEHOLDER_") ? chatModel.modelDisplayName : null;
|
|
1698
|
+
const responseModel = typeof chatModel.responseModel === "string" && !chatModel.responseModel.startsWith("MODEL_PLACEHOLDER_") ? AGY_RESPONSE_MODEL_ALIASES[chatModel.responseModel] ?? chatModel.responseModel : null;
|
|
1699
|
+
const model = modelDisplayName ?? responseModel ?? null;
|
|
1697
1700
|
const occurredAt = Date.parse(chatModel.chatStartMetadata?.createdAt ?? "");
|
|
1698
1701
|
return {
|
|
1699
1702
|
usage,
|
|
@@ -1709,7 +1712,7 @@ async function readAgyModelSetting(filePath) {
|
|
|
1709
1712
|
stat2(settingsPath)
|
|
1710
1713
|
]);
|
|
1711
1714
|
const configured = JSON.parse(text)?.model;
|
|
1712
|
-
const model = typeof configured === "string" ?
|
|
1715
|
+
const model = typeof configured === "string" ? configured : null;
|
|
1713
1716
|
return model ? { model, changedAt: info.mtimeMs } : null;
|
|
1714
1717
|
} catch {
|
|
1715
1718
|
return null;
|
|
@@ -3695,8 +3698,8 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
3695
3698
|
}
|
|
3696
3699
|
const filePath = path8.join(traceDir, entry);
|
|
3697
3700
|
try {
|
|
3698
|
-
const
|
|
3699
|
-
files.push({ path: filePath, modifiedAt:
|
|
3701
|
+
const stat12 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
|
|
3702
|
+
files.push({ path: filePath, modifiedAt: stat12.mtime.toISOString() });
|
|
3700
3703
|
} catch {
|
|
3701
3704
|
}
|
|
3702
3705
|
}
|
|
@@ -4316,9 +4319,341 @@ function createCodexAdapter() {
|
|
|
4316
4319
|
};
|
|
4317
4320
|
}
|
|
4318
4321
|
|
|
4319
|
-
// src/adapters/
|
|
4322
|
+
// src/adapters/copilot.ts
|
|
4323
|
+
import { readdir as readdir5, readFile as readFile7, stat as stat5 } from "node:fs/promises";
|
|
4320
4324
|
import os4 from "node:os";
|
|
4321
4325
|
import path10 from "node:path";
|
|
4326
|
+
async function parseCopilotSessionFile(filePath, options) {
|
|
4327
|
+
const text = await readFile7(filePath, "utf8");
|
|
4328
|
+
const lines = text.split("\n").filter(Boolean);
|
|
4329
|
+
const events = [];
|
|
4330
|
+
let sessionId;
|
|
4331
|
+
let cwd;
|
|
4332
|
+
let project;
|
|
4333
|
+
let model;
|
|
4334
|
+
let currentTurnId;
|
|
4335
|
+
let sessionStartedAt;
|
|
4336
|
+
const pendingTools = /* @__PURE__ */ new Map();
|
|
4337
|
+
const turnTokenAccum = /* @__PURE__ */ new Map();
|
|
4338
|
+
for (const [index, line] of lines.entries()) {
|
|
4339
|
+
const lineNumber = index + 1;
|
|
4340
|
+
const raw = parseJsonLine(line);
|
|
4341
|
+
if (!raw) {
|
|
4342
|
+
continue;
|
|
4343
|
+
}
|
|
4344
|
+
const eventType = stringField(raw, "type");
|
|
4345
|
+
const ts = timestampFrom(raw.timestamp);
|
|
4346
|
+
if (!ts) {
|
|
4347
|
+
continue;
|
|
4348
|
+
}
|
|
4349
|
+
const data = objectField(raw, "data");
|
|
4350
|
+
switch (eventType) {
|
|
4351
|
+
case "session.start": {
|
|
4352
|
+
sessionId = stringField(data, "sessionId") || sessionId;
|
|
4353
|
+
model = stringField(data, "selectedModel") || model;
|
|
4354
|
+
const context = objectField(data, "context");
|
|
4355
|
+
cwd = stringField(context, "cwd") || stringField(context, "gitRoot") || cwd;
|
|
4356
|
+
project = stringField(context, "repository") || (cwd ? path10.basename(cwd) : void 0);
|
|
4357
|
+
sessionStartedAt = ts;
|
|
4358
|
+
events.push(baseCopilotEvent({
|
|
4359
|
+
ts,
|
|
4360
|
+
type: "session.started",
|
|
4361
|
+
sessionId,
|
|
4362
|
+
cwd,
|
|
4363
|
+
project,
|
|
4364
|
+
model,
|
|
4365
|
+
operation: "session start",
|
|
4366
|
+
confidence: "exact"
|
|
4367
|
+
}));
|
|
4368
|
+
break;
|
|
4369
|
+
}
|
|
4370
|
+
case "user.message": {
|
|
4371
|
+
currentTurnId = `turn_${createStableHash([sessionId, lineNumber]).slice(0, 24)}`;
|
|
4372
|
+
events.push(baseCopilotEvent({
|
|
4373
|
+
ts,
|
|
4374
|
+
type: "turn.started",
|
|
4375
|
+
sessionId,
|
|
4376
|
+
turnId: currentTurnId,
|
|
4377
|
+
cwd,
|
|
4378
|
+
project,
|
|
4379
|
+
model,
|
|
4380
|
+
confidence: "exact"
|
|
4381
|
+
}));
|
|
4382
|
+
const content = stringField(data, "content");
|
|
4383
|
+
if (content) {
|
|
4384
|
+
events.push(baseCopilotEvent({
|
|
4385
|
+
ts,
|
|
4386
|
+
type: "prompt.submitted",
|
|
4387
|
+
sessionId,
|
|
4388
|
+
turnId: currentTurnId,
|
|
4389
|
+
cwd,
|
|
4390
|
+
project,
|
|
4391
|
+
model,
|
|
4392
|
+
confidence: "exact",
|
|
4393
|
+
metrics: {
|
|
4394
|
+
prompts: 1,
|
|
4395
|
+
promptChars: content.length
|
|
4396
|
+
},
|
|
4397
|
+
refs: stringRefs({
|
|
4398
|
+
promptHash: `sha256:${createStableHash(content)}`
|
|
4399
|
+
})
|
|
4400
|
+
}));
|
|
4401
|
+
}
|
|
4402
|
+
break;
|
|
4403
|
+
}
|
|
4404
|
+
case "assistant.message": {
|
|
4405
|
+
const msgModel = stringField(data, "model");
|
|
4406
|
+
if (msgModel) {
|
|
4407
|
+
model = msgModel;
|
|
4408
|
+
}
|
|
4409
|
+
const msgTurnId = stringField(data, "turnId");
|
|
4410
|
+
const turnId = msgTurnId !== void 0 ? `turn_${createStableHash([sessionId, msgTurnId]).slice(0, 24)}` : currentTurnId;
|
|
4411
|
+
const outputTokens = numberField(data, "outputTokens");
|
|
4412
|
+
if (outputTokens && outputTokens > 0) {
|
|
4413
|
+
const key = turnId || "unknown";
|
|
4414
|
+
const accum = turnTokenAccum.get(key) || { tokensOutput: 0, modelCalls: 0 };
|
|
4415
|
+
accum.tokensOutput = (accum.tokensOutput || 0) + outputTokens;
|
|
4416
|
+
accum.modelCalls = (accum.modelCalls || 0) + 1;
|
|
4417
|
+
turnTokenAccum.set(key, accum);
|
|
4418
|
+
}
|
|
4419
|
+
break;
|
|
4420
|
+
}
|
|
4421
|
+
case "tool.execution_start": {
|
|
4422
|
+
const toolCallId = stringField(data, "toolCallId");
|
|
4423
|
+
const toolName = stringField(data, "toolName") || "tool";
|
|
4424
|
+
const toolTurnId = stringField(data, "turnId");
|
|
4425
|
+
const turnId = toolTurnId !== void 0 ? `turn_${createStableHash([sessionId, toolTurnId]).slice(0, 24)}` : currentTurnId;
|
|
4426
|
+
if (toolCallId) {
|
|
4427
|
+
pendingTools.set(toolCallId, { tool: toolName, startedAt: ts, turnId });
|
|
4428
|
+
}
|
|
4429
|
+
events.push(baseCopilotEvent({
|
|
4430
|
+
ts,
|
|
4431
|
+
type: "tool.started",
|
|
4432
|
+
operation: `${toolName} started`,
|
|
4433
|
+
sessionId,
|
|
4434
|
+
turnId,
|
|
4435
|
+
cwd,
|
|
4436
|
+
project,
|
|
4437
|
+
model,
|
|
4438
|
+
tool: toolName,
|
|
4439
|
+
confidence: "exact",
|
|
4440
|
+
metrics: { toolCalls: 1 },
|
|
4441
|
+
refs: stringRefs({ sourceId: toolCallId })
|
|
4442
|
+
}));
|
|
4443
|
+
break;
|
|
4444
|
+
}
|
|
4445
|
+
case "tool.execution_complete": {
|
|
4446
|
+
const toolCallId = stringField(data, "toolCallId");
|
|
4447
|
+
const pending = toolCallId ? pendingTools.get(toolCallId) : void 0;
|
|
4448
|
+
if (toolCallId) {
|
|
4449
|
+
pendingTools.delete(toolCallId);
|
|
4450
|
+
}
|
|
4451
|
+
const success = data.success !== false;
|
|
4452
|
+
const durationMs = pending ? Math.max(0, new Date(ts).getTime() - new Date(pending.startedAt).getTime()) : void 0;
|
|
4453
|
+
events.push(baseCopilotEvent({
|
|
4454
|
+
ts,
|
|
4455
|
+
type: success ? "tool.completed" : "tool.failed",
|
|
4456
|
+
operation: pending ? `${pending.tool} completed` : "tool completed",
|
|
4457
|
+
sessionId,
|
|
4458
|
+
turnId: pending?.turnId || currentTurnId,
|
|
4459
|
+
cwd,
|
|
4460
|
+
project,
|
|
4461
|
+
model,
|
|
4462
|
+
tool: pending?.tool,
|
|
4463
|
+
success,
|
|
4464
|
+
confidence: "exact",
|
|
4465
|
+
metrics: durationMs !== void 0 ? { toolDurationMs: durationMs, durationMs } : void 0,
|
|
4466
|
+
refs: stringRefs({ sourceId: toolCallId })
|
|
4467
|
+
}));
|
|
4468
|
+
const toolLower = (pending?.tool || "").toLowerCase();
|
|
4469
|
+
if (toolLower === "bash" || toolLower === "shell" || toolLower === "execute_command") {
|
|
4470
|
+
events.push(baseCopilotEvent({
|
|
4471
|
+
ts,
|
|
4472
|
+
type: success ? "command.completed" : "command.failed",
|
|
4473
|
+
operation: "command completed",
|
|
4474
|
+
sessionId,
|
|
4475
|
+
turnId: pending?.turnId || currentTurnId,
|
|
4476
|
+
cwd,
|
|
4477
|
+
project,
|
|
4478
|
+
model,
|
|
4479
|
+
tool: pending?.tool,
|
|
4480
|
+
success,
|
|
4481
|
+
confidence: "derived",
|
|
4482
|
+
metrics: {
|
|
4483
|
+
commandCalls: 1,
|
|
4484
|
+
commandDurationMs: durationMs,
|
|
4485
|
+
durationMs
|
|
4486
|
+
},
|
|
4487
|
+
refs: stringRefs({ sourceId: toolCallId })
|
|
4488
|
+
}));
|
|
4489
|
+
}
|
|
4490
|
+
break;
|
|
4491
|
+
}
|
|
4492
|
+
case "assistant.turn_end": {
|
|
4493
|
+
const endTurnId = stringField(data, "turnId");
|
|
4494
|
+
const turnId = endTurnId !== void 0 ? `turn_${createStableHash([sessionId, endTurnId]).slice(0, 24)}` : currentTurnId;
|
|
4495
|
+
const accum = turnId ? turnTokenAccum.get(turnId) : void 0;
|
|
4496
|
+
if (accum && accum.tokensOutput && accum.tokensOutput > 0) {
|
|
4497
|
+
events.push(baseCopilotEvent({
|
|
4498
|
+
ts,
|
|
4499
|
+
type: "model.usage",
|
|
4500
|
+
sessionId,
|
|
4501
|
+
turnId,
|
|
4502
|
+
cwd,
|
|
4503
|
+
project,
|
|
4504
|
+
model,
|
|
4505
|
+
confidence: "partial",
|
|
4506
|
+
metrics: accum
|
|
4507
|
+
}));
|
|
4508
|
+
turnTokenAccum.delete(turnId);
|
|
4509
|
+
}
|
|
4510
|
+
events.push(baseCopilotEvent({
|
|
4511
|
+
ts,
|
|
4512
|
+
type: "turn.completed",
|
|
4513
|
+
sessionId,
|
|
4514
|
+
turnId,
|
|
4515
|
+
cwd,
|
|
4516
|
+
project,
|
|
4517
|
+
model,
|
|
4518
|
+
confidence: "derived"
|
|
4519
|
+
}));
|
|
4520
|
+
break;
|
|
4521
|
+
}
|
|
4522
|
+
case "session.shutdown": {
|
|
4523
|
+
const modelMetrics2 = objectField(data, "modelMetrics");
|
|
4524
|
+
for (const [modelName, metricsRaw] of Object.entries(modelMetrics2)) {
|
|
4525
|
+
if (!isPlainObject(metricsRaw)) {
|
|
4526
|
+
continue;
|
|
4527
|
+
}
|
|
4528
|
+
const usage = objectField(metricsRaw, "usage");
|
|
4529
|
+
const inputTokens = numberField(usage, "inputTokens") || 0;
|
|
4530
|
+
const outputTokens = numberField(usage, "outputTokens") || 0;
|
|
4531
|
+
const cacheReadTokens = numberField(usage, "cacheReadTokens") || 0;
|
|
4532
|
+
const cacheWriteTokens = numberField(usage, "cacheWriteTokens") || 0;
|
|
4533
|
+
const reasoningTokens = numberField(usage, "reasoningTokens") || 0;
|
|
4534
|
+
const totalInput = inputTokens + cacheReadTokens + cacheWriteTokens;
|
|
4535
|
+
const total = totalInput + outputTokens + reasoningTokens;
|
|
4536
|
+
if (total <= 0) {
|
|
4537
|
+
continue;
|
|
4538
|
+
}
|
|
4539
|
+
const requests = objectField(metricsRaw, "requests");
|
|
4540
|
+
const requestCount = numberField(requests, "count");
|
|
4541
|
+
events.push(baseCopilotEvent({
|
|
4542
|
+
ts,
|
|
4543
|
+
type: "model.usage",
|
|
4544
|
+
sessionId,
|
|
4545
|
+
cwd,
|
|
4546
|
+
project,
|
|
4547
|
+
model: modelName,
|
|
4548
|
+
confidence: "exact",
|
|
4549
|
+
metrics: {
|
|
4550
|
+
tokensInput: totalInput || void 0,
|
|
4551
|
+
tokensOutput: outputTokens || void 0,
|
|
4552
|
+
tokensCachedInput: cacheReadTokens + cacheWriteTokens || void 0,
|
|
4553
|
+
tokensCacheReadInput: cacheReadTokens || void 0,
|
|
4554
|
+
tokensCacheCreationInput: cacheWriteTokens || void 0,
|
|
4555
|
+
tokensReasoningOutput: reasoningTokens || void 0,
|
|
4556
|
+
tokensTotal: total,
|
|
4557
|
+
modelCalls: requestCount || void 0
|
|
4558
|
+
}
|
|
4559
|
+
}));
|
|
4560
|
+
}
|
|
4561
|
+
events.push(baseCopilotEvent({
|
|
4562
|
+
ts,
|
|
4563
|
+
type: "session.ended",
|
|
4564
|
+
sessionId,
|
|
4565
|
+
cwd,
|
|
4566
|
+
project,
|
|
4567
|
+
model,
|
|
4568
|
+
operation: "session end"
|
|
4569
|
+
}));
|
|
4570
|
+
break;
|
|
4571
|
+
}
|
|
4572
|
+
}
|
|
4573
|
+
}
|
|
4574
|
+
return events.filter((event) => validateCanonicalEvent(event).valid);
|
|
4575
|
+
}
|
|
4576
|
+
function baseCopilotEvent(event) {
|
|
4577
|
+
return {
|
|
4578
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
4579
|
+
source: "copilot",
|
|
4580
|
+
agent: "copilot",
|
|
4581
|
+
workspaceId: createWorkspaceId({ projectName: event.project, repoRoot: event.cwd }),
|
|
4582
|
+
...event
|
|
4583
|
+
};
|
|
4584
|
+
}
|
|
4585
|
+
async function copilotBackfillFiles(sourceRoot, home = os4.homedir(), _env) {
|
|
4586
|
+
const sessionDir = sourceRoot || path10.join(home, ".copilot", "session-state");
|
|
4587
|
+
const results = [];
|
|
4588
|
+
let entries;
|
|
4589
|
+
try {
|
|
4590
|
+
entries = await readdir5(sessionDir);
|
|
4591
|
+
} catch {
|
|
4592
|
+
return [];
|
|
4593
|
+
}
|
|
4594
|
+
for (const entry of entries) {
|
|
4595
|
+
if (entry.startsWith("pending-session")) {
|
|
4596
|
+
continue;
|
|
4597
|
+
}
|
|
4598
|
+
const eventsPath = path10.join(sessionDir, entry, "events.jsonl");
|
|
4599
|
+
const info = await stat5(eventsPath).catch(() => null);
|
|
4600
|
+
if (info) {
|
|
4601
|
+
results.push({ path: eventsPath, modifiedAt: info.mtime.toISOString() });
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
return results;
|
|
4605
|
+
}
|
|
4606
|
+
function copilotPluginContent() {
|
|
4607
|
+
return `// Agent Time plugin for GitHub Copilot CLI
|
|
4608
|
+
// Generated by vibetime.
|
|
4609
|
+
// Copilot does not support hooks \u2014 this file is a placeholder for detection.
|
|
4610
|
+
// Backfill reads session data from ~/.copilot/session-state/*/events.jsonl.
|
|
4611
|
+
`;
|
|
4612
|
+
}
|
|
4613
|
+
function copilotHome(home, env) {
|
|
4614
|
+
const override = env?.COPILOT_HOME;
|
|
4615
|
+
if (override && override.trim()) {
|
|
4616
|
+
return path10.resolve(override);
|
|
4617
|
+
}
|
|
4618
|
+
return path10.join(home, ".copilot");
|
|
4619
|
+
}
|
|
4620
|
+
function createCopilotAdapter() {
|
|
4621
|
+
return {
|
|
4622
|
+
id: "copilot",
|
|
4623
|
+
label: "GitHub Copilot",
|
|
4624
|
+
agentName: "copilot",
|
|
4625
|
+
kind: "agent",
|
|
4626
|
+
detectPath(home, env) {
|
|
4627
|
+
return copilotHome(home, env);
|
|
4628
|
+
},
|
|
4629
|
+
installedPath(home, env) {
|
|
4630
|
+
return path10.join(copilotHome(home, env), ".vibetime");
|
|
4631
|
+
},
|
|
4632
|
+
async isInstalled(home, env) {
|
|
4633
|
+
try {
|
|
4634
|
+
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4635
|
+
return await pathExists2(path10.join(copilotHome(home, env), ".vibetime"));
|
|
4636
|
+
} catch {
|
|
4637
|
+
return false;
|
|
4638
|
+
}
|
|
4639
|
+
},
|
|
4640
|
+
installEntries(home, env) {
|
|
4641
|
+
return [{
|
|
4642
|
+
kind: "file",
|
|
4643
|
+
path: path10.join(copilotHome(home, env), ".vibetime"),
|
|
4644
|
+
content: copilotPluginContent()
|
|
4645
|
+
}];
|
|
4646
|
+
},
|
|
4647
|
+
sourcePaths(home, env) {
|
|
4648
|
+
return [path10.join(copilotHome(home, env), "session-state")];
|
|
4649
|
+
},
|
|
4650
|
+
parseSessionFile: parseCopilotSessionFile
|
|
4651
|
+
};
|
|
4652
|
+
}
|
|
4653
|
+
|
|
4654
|
+
// src/adapters/opencode.ts
|
|
4655
|
+
import os5 from "node:os";
|
|
4656
|
+
import path11 from "node:path";
|
|
4322
4657
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
4323
4658
|
const { DatabaseSync } = await import("node:sqlite");
|
|
4324
4659
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -4349,7 +4684,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4349
4684
|
for (const session of sessions) {
|
|
4350
4685
|
const sessionId = session.id;
|
|
4351
4686
|
const cwd = session.directory || session.path || void 0;
|
|
4352
|
-
const project = cwd ?
|
|
4687
|
+
const project = cwd ? path11.basename(cwd) : void 0;
|
|
4353
4688
|
const sessionTs = msToIso(session.time_created);
|
|
4354
4689
|
events.push(baseOpenCodeEvent({
|
|
4355
4690
|
ts: sessionTs,
|
|
@@ -4443,7 +4778,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4443
4778
|
const provider = currentProvider;
|
|
4444
4779
|
const pathObj = objectField(info, "path");
|
|
4445
4780
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
4446
|
-
const assistantProject = assistantCwd ?
|
|
4781
|
+
const assistantProject = assistantCwd ? path11.basename(assistantCwd) : project;
|
|
4447
4782
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
4448
4783
|
const createdTs = timeCreated;
|
|
4449
4784
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -4687,33 +5022,33 @@ function opencodeUsageFromInfo(info) {
|
|
|
4687
5022
|
function opencodeConfigDir(home, env) {
|
|
4688
5023
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
4689
5024
|
if (override && override.trim()) {
|
|
4690
|
-
return
|
|
5025
|
+
return path11.resolve(override);
|
|
4691
5026
|
}
|
|
4692
5027
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
4693
5028
|
if (xdgConfig && xdgConfig.trim()) {
|
|
4694
|
-
return
|
|
5029
|
+
return path11.join(path11.resolve(xdgConfig), "opencode");
|
|
4695
5030
|
}
|
|
4696
|
-
return
|
|
5031
|
+
return path11.join(home, ".config", "opencode");
|
|
4697
5032
|
}
|
|
4698
5033
|
function opencodeDataCandidates(home, env) {
|
|
4699
5034
|
const xdgData = env?.XDG_DATA_HOME;
|
|
4700
|
-
const primary = xdgData && xdgData.trim() ?
|
|
4701
|
-
return [primary,
|
|
5035
|
+
const primary = xdgData && xdgData.trim() ? path11.join(path11.resolve(xdgData), "opencode", "opencode.db") : path11.join(home, ".local", "share", "opencode", "opencode.db");
|
|
5036
|
+
return [primary, path11.join(home, ".opencode", "opencode.db")];
|
|
4702
5037
|
}
|
|
4703
|
-
async function opencodeBackfillFiles(sourceRoot, home =
|
|
4704
|
-
const { stat:
|
|
5038
|
+
async function opencodeBackfillFiles(sourceRoot, home = os5.homedir(), env) {
|
|
5039
|
+
const { stat: stat12 } = await import("node:fs/promises");
|
|
4705
5040
|
if (sourceRoot) {
|
|
4706
5041
|
if (!sourceRoot.endsWith(".db")) {
|
|
4707
5042
|
return [];
|
|
4708
5043
|
}
|
|
4709
|
-
const info = await
|
|
5044
|
+
const info = await stat12(sourceRoot).catch(() => null);
|
|
4710
5045
|
if (!info) {
|
|
4711
5046
|
return [];
|
|
4712
5047
|
}
|
|
4713
5048
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
4714
5049
|
}
|
|
4715
5050
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
4716
|
-
const info = await
|
|
5051
|
+
const info = await stat12(candidatePath).catch(() => null);
|
|
4717
5052
|
if (info) {
|
|
4718
5053
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
4719
5054
|
}
|
|
@@ -4778,12 +5113,12 @@ function createOpenCodeAdapter() {
|
|
|
4778
5113
|
return opencodeConfigDir(home, env);
|
|
4779
5114
|
},
|
|
4780
5115
|
installedPath(home, env) {
|
|
4781
|
-
return
|
|
5116
|
+
return path11.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
4782
5117
|
},
|
|
4783
5118
|
async isInstalled(home, env) {
|
|
4784
5119
|
try {
|
|
4785
5120
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4786
|
-
return await pathExists2(
|
|
5121
|
+
return await pathExists2(path11.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path11.join(".opencode", PLUGIN_PATH));
|
|
4787
5122
|
} catch {
|
|
4788
5123
|
return false;
|
|
4789
5124
|
}
|
|
@@ -4791,7 +5126,7 @@ function createOpenCodeAdapter() {
|
|
|
4791
5126
|
installEntries(home, env) {
|
|
4792
5127
|
return [{
|
|
4793
5128
|
kind: "file",
|
|
4794
|
-
path:
|
|
5129
|
+
path: path11.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
4795
5130
|
content: opencodePluginContent()
|
|
4796
5131
|
}];
|
|
4797
5132
|
},
|
|
@@ -4803,10 +5138,10 @@ function createOpenCodeAdapter() {
|
|
|
4803
5138
|
}
|
|
4804
5139
|
|
|
4805
5140
|
// src/adapters/pi.ts
|
|
4806
|
-
import { readFile as
|
|
4807
|
-
import
|
|
5141
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
5142
|
+
import path12 from "node:path";
|
|
4808
5143
|
async function parsePiSessionFile(filePath, options) {
|
|
4809
|
-
const text = await
|
|
5144
|
+
const text = await readFile8(filePath, "utf8");
|
|
4810
5145
|
const lines = text.split("\n").filter(Boolean);
|
|
4811
5146
|
let sessionId;
|
|
4812
5147
|
let cwd;
|
|
@@ -4836,7 +5171,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
4836
5171
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
4837
5172
|
state.sessionId = sessionId || state.sessionId;
|
|
4838
5173
|
cwd = stringField(raw, "cwd") || cwd;
|
|
4839
|
-
project = cwd ?
|
|
5174
|
+
project = cwd ? path12.basename(cwd) : project;
|
|
4840
5175
|
continue;
|
|
4841
5176
|
}
|
|
4842
5177
|
if (entryType === "model_change") {
|
|
@@ -5237,16 +5572,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
5237
5572
|
function piAgentDir(home, env) {
|
|
5238
5573
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
5239
5574
|
if (override && override.trim()) {
|
|
5240
|
-
return
|
|
5575
|
+
return path12.resolve(override);
|
|
5241
5576
|
}
|
|
5242
|
-
return
|
|
5577
|
+
return path12.join(home, ".pi", "agent");
|
|
5243
5578
|
}
|
|
5244
5579
|
function piSessionDir(home, env) {
|
|
5245
5580
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
5246
5581
|
if (override && override.trim()) {
|
|
5247
|
-
return
|
|
5582
|
+
return path12.resolve(override);
|
|
5248
5583
|
}
|
|
5249
|
-
return
|
|
5584
|
+
return path12.join(piAgentDir(home, env), "sessions");
|
|
5250
5585
|
}
|
|
5251
5586
|
function createPiAdapter() {
|
|
5252
5587
|
return {
|
|
@@ -5258,12 +5593,12 @@ function createPiAdapter() {
|
|
|
5258
5593
|
return piAgentDir(home, env);
|
|
5259
5594
|
},
|
|
5260
5595
|
installedPath(home, env) {
|
|
5261
|
-
return
|
|
5596
|
+
return path12.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
5262
5597
|
},
|
|
5263
5598
|
async isInstalled(home, env) {
|
|
5264
5599
|
try {
|
|
5265
5600
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5266
|
-
return await pathExists2(
|
|
5601
|
+
return await pathExists2(path12.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
5267
5602
|
} catch {
|
|
5268
5603
|
return false;
|
|
5269
5604
|
}
|
|
@@ -5271,7 +5606,7 @@ function createPiAdapter() {
|
|
|
5271
5606
|
installEntries(home, env) {
|
|
5272
5607
|
return [{
|
|
5273
5608
|
kind: "file",
|
|
5274
|
-
path:
|
|
5609
|
+
path: path12.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
5275
5610
|
content: piExtensionContent()
|
|
5276
5611
|
}];
|
|
5277
5612
|
},
|
|
@@ -5283,11 +5618,11 @@ function createPiAdapter() {
|
|
|
5283
5618
|
}
|
|
5284
5619
|
|
|
5285
5620
|
// src/adapters/qoder-cn.ts
|
|
5286
|
-
import { readdir as
|
|
5287
|
-
import
|
|
5288
|
-
import
|
|
5621
|
+
import { readdir as readdir6, readFile as readFile9, stat as stat6 } from "node:fs/promises";
|
|
5622
|
+
import os6 from "node:os";
|
|
5623
|
+
import path13 from "node:path";
|
|
5289
5624
|
function parseQoderCnPaths(filePath) {
|
|
5290
|
-
const parts = filePath.split(
|
|
5625
|
+
const parts = filePath.split(path13.sep);
|
|
5291
5626
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
5292
5627
|
let sessionId = "";
|
|
5293
5628
|
let projectName = "";
|
|
@@ -5296,20 +5631,20 @@ function parseQoderCnPaths(filePath) {
|
|
|
5296
5631
|
sessionId = parts[subagentsIdx - 1];
|
|
5297
5632
|
projectName = parts[subagentsIdx - 2];
|
|
5298
5633
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5299
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5634
|
+
configDir2 = parts.slice(0, projectsIdx).join(path13.sep);
|
|
5300
5635
|
} else {
|
|
5301
5636
|
const filename = parts.at(-1) || "";
|
|
5302
|
-
sessionId =
|
|
5637
|
+
sessionId = path13.basename(filename, ".jsonl");
|
|
5303
5638
|
projectName = parts.at(-2) || "";
|
|
5304
5639
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5305
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5640
|
+
configDir2 = parts.slice(0, projectsIdx).join(path13.sep);
|
|
5306
5641
|
}
|
|
5307
5642
|
return { configDir: configDir2, projectName, sessionId };
|
|
5308
5643
|
}
|
|
5309
5644
|
async function loadQoderCnModelNames(configDir2) {
|
|
5310
5645
|
try {
|
|
5311
|
-
const dynamicTextsPath =
|
|
5312
|
-
const content = await
|
|
5646
|
+
const dynamicTextsPath = path13.join(configDir2, ".auth", "dynamic-texts.json");
|
|
5647
|
+
const content = await readFile9(dynamicTextsPath, "utf8");
|
|
5313
5648
|
const json = JSON.parse(content);
|
|
5314
5649
|
const texts = json.texts || {};
|
|
5315
5650
|
const map = {};
|
|
@@ -5326,15 +5661,15 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
5326
5661
|
}
|
|
5327
5662
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
5328
5663
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
5329
|
-
const segmentsPath =
|
|
5664
|
+
const segmentsPath = path13.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
5330
5665
|
const modelCalls = [];
|
|
5331
5666
|
try {
|
|
5332
|
-
const files = await
|
|
5667
|
+
const files = await readdir6(segmentsPath);
|
|
5333
5668
|
for (const file of files) {
|
|
5334
5669
|
if (!file.endsWith(".jsonl")) {
|
|
5335
5670
|
continue;
|
|
5336
5671
|
}
|
|
5337
|
-
const content = await
|
|
5672
|
+
const content = await readFile9(path13.join(segmentsPath, file), "utf8");
|
|
5338
5673
|
let currentTurnIsSubagent = false;
|
|
5339
5674
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
5340
5675
|
const raw = parseJsonLine(line);
|
|
@@ -5367,7 +5702,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
5367
5702
|
return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
|
|
5368
5703
|
}
|
|
5369
5704
|
async function parseQoderCnSessionFile(filePath, options) {
|
|
5370
|
-
const text = await
|
|
5705
|
+
const text = await readFile9(filePath, "utf8");
|
|
5371
5706
|
const lines = text.split("\n").filter(Boolean);
|
|
5372
5707
|
const { configDir: configDir2 } = parseQoderCnPaths(filePath);
|
|
5373
5708
|
const projectContext = await qoderCnProjectContextFromLines(filePath, lines, options, configDir2);
|
|
@@ -5402,7 +5737,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
5402
5737
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
5403
5738
|
state.sessionId = sessionId;
|
|
5404
5739
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5405
|
-
project = projectContext.project || (cwd ?
|
|
5740
|
+
project = projectContext.project || (cwd ? path13.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
5406
5741
|
if (!ts) {
|
|
5407
5742
|
continue;
|
|
5408
5743
|
}
|
|
@@ -5831,24 +6166,24 @@ function isNoisePrompt(text) {
|
|
|
5831
6166
|
}
|
|
5832
6167
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
5833
6168
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
5834
|
-
const isSubagent = filePath.includes(`${
|
|
6169
|
+
const isSubagent = filePath.includes(`${path13.sep}subagents${path13.sep}`);
|
|
5835
6170
|
let cwds = [];
|
|
5836
6171
|
for (const line of lines) {
|
|
5837
6172
|
const raw = parseJsonLine(line);
|
|
5838
6173
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
5839
|
-
if (cwd &&
|
|
6174
|
+
if (cwd && path13.isAbsolute(cwd)) {
|
|
5840
6175
|
cwds.push(cwd);
|
|
5841
6176
|
}
|
|
5842
6177
|
}
|
|
5843
6178
|
if (isSubagent) {
|
|
5844
|
-
const parentSessionPath =
|
|
6179
|
+
const parentSessionPath = path13.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
5845
6180
|
try {
|
|
5846
|
-
const parentText = await
|
|
6181
|
+
const parentText = await readFile9(parentSessionPath, "utf8");
|
|
5847
6182
|
const parentCwds = [];
|
|
5848
6183
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
5849
6184
|
const raw = parseJsonLine(line);
|
|
5850
6185
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
5851
|
-
if (cwd &&
|
|
6186
|
+
if (cwd && path13.isAbsolute(cwd)) {
|
|
5852
6187
|
parentCwds.push(cwd);
|
|
5853
6188
|
}
|
|
5854
6189
|
}
|
|
@@ -5859,7 +6194,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
5859
6194
|
}
|
|
5860
6195
|
}
|
|
5861
6196
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
5862
|
-
const project = cwds.length > 0 ?
|
|
6197
|
+
const project = cwds.length > 0 ? path13.basename(cwds[0]) : root ? path13.basename(root) : await qoderCnProjectFromFilePath(filePath, options);
|
|
5863
6198
|
return {
|
|
5864
6199
|
project,
|
|
5865
6200
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -5868,15 +6203,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
5868
6203
|
async function gitRootFromCwds2(cwds) {
|
|
5869
6204
|
const seen = /* @__PURE__ */ new Set();
|
|
5870
6205
|
for (const cwd of cwds) {
|
|
5871
|
-
let current =
|
|
6206
|
+
let current = path13.resolve(cwd);
|
|
5872
6207
|
while (!seen.has(current)) {
|
|
5873
6208
|
seen.add(current);
|
|
5874
6209
|
try {
|
|
5875
|
-
await
|
|
6210
|
+
await stat6(path13.join(current, ".git"));
|
|
5876
6211
|
return current;
|
|
5877
6212
|
} catch {
|
|
5878
6213
|
}
|
|
5879
|
-
const parent =
|
|
6214
|
+
const parent = path13.dirname(current);
|
|
5880
6215
|
if (parent === current) {
|
|
5881
6216
|
break;
|
|
5882
6217
|
}
|
|
@@ -5887,12 +6222,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
5887
6222
|
}
|
|
5888
6223
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
5889
6224
|
for (const cwd of cwds) {
|
|
5890
|
-
let current =
|
|
6225
|
+
let current = path13.resolve(cwd);
|
|
5891
6226
|
while (true) {
|
|
5892
6227
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
5893
6228
|
return current;
|
|
5894
6229
|
}
|
|
5895
|
-
const parent =
|
|
6230
|
+
const parent = path13.dirname(current);
|
|
5896
6231
|
if (parent === current) {
|
|
5897
6232
|
break;
|
|
5898
6233
|
}
|
|
@@ -5902,14 +6237,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
5902
6237
|
return void 0;
|
|
5903
6238
|
}
|
|
5904
6239
|
function encodeQoderCnProjectPath(value) {
|
|
5905
|
-
return
|
|
6240
|
+
return path13.resolve(value).split(path13.sep).join("-").replace(/_/g, "-");
|
|
5906
6241
|
}
|
|
5907
6242
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
5908
|
-
const projectDir =
|
|
5909
|
-
const home = options ?
|
|
6243
|
+
const projectDir = path13.basename(path13.dirname(filePath));
|
|
6244
|
+
const home = options ? path13.resolve(stringOption(options.home) || os6.homedir()) : os6.homedir();
|
|
5910
6245
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
5911
6246
|
if (resolved) {
|
|
5912
|
-
return
|
|
6247
|
+
return path13.basename(resolved);
|
|
5913
6248
|
}
|
|
5914
6249
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
5915
6250
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -5929,12 +6264,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
5929
6264
|
while (projectDir.startsWith(`${currentEncoded}-`)) {
|
|
5930
6265
|
let matchedChild;
|
|
5931
6266
|
try {
|
|
5932
|
-
const entries = await
|
|
6267
|
+
const entries = await readdir6(current, { withFileTypes: true });
|
|
5933
6268
|
for (const entry of entries) {
|
|
5934
6269
|
if (!entry.isDirectory()) {
|
|
5935
6270
|
continue;
|
|
5936
6271
|
}
|
|
5937
|
-
const candidate =
|
|
6272
|
+
const candidate = path13.join(current, entry.name);
|
|
5938
6273
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
5939
6274
|
if (encoded === projectDir) {
|
|
5940
6275
|
return candidate;
|
|
@@ -5979,9 +6314,9 @@ function hookConfig5() {
|
|
|
5979
6314
|
function qoderCnConfigDir(home, env) {
|
|
5980
6315
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
5981
6316
|
if (override && override.trim()) {
|
|
5982
|
-
return
|
|
6317
|
+
return path13.resolve(override);
|
|
5983
6318
|
}
|
|
5984
|
-
return
|
|
6319
|
+
return path13.join(home, ".qoder-cn");
|
|
5985
6320
|
}
|
|
5986
6321
|
function createQoderCnAdapter() {
|
|
5987
6322
|
return {
|
|
@@ -5993,27 +6328,27 @@ function createQoderCnAdapter() {
|
|
|
5993
6328
|
return qoderCnConfigDir(home, env);
|
|
5994
6329
|
},
|
|
5995
6330
|
installedPath(home, env) {
|
|
5996
|
-
return
|
|
6331
|
+
return path13.join(qoderCnConfigDir(home, env), "settings.json");
|
|
5997
6332
|
},
|
|
5998
6333
|
async isInstalled(home, env) {
|
|
5999
6334
|
return isHooksJsonInstalled(
|
|
6000
|
-
|
|
6335
|
+
path13.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6001
6336
|
"vibetime hook --agent qoder-cn"
|
|
6002
6337
|
);
|
|
6003
6338
|
},
|
|
6004
6339
|
installEntries(home, env) {
|
|
6005
6340
|
return [{
|
|
6006
6341
|
kind: "hooks-json",
|
|
6007
|
-
path:
|
|
6342
|
+
path: path13.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6008
6343
|
content: hookConfig5()
|
|
6009
6344
|
}];
|
|
6010
6345
|
},
|
|
6011
6346
|
sourcePaths(home, env) {
|
|
6012
6347
|
const base = qoderCnConfigDir(home, env);
|
|
6013
6348
|
return [
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6349
|
+
path13.join(base, "projects"),
|
|
6350
|
+
path13.join(base, ".qoder.json"),
|
|
6351
|
+
path13.join(home, ".qoder.json")
|
|
6017
6352
|
];
|
|
6018
6353
|
},
|
|
6019
6354
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -6021,11 +6356,11 @@ function createQoderCnAdapter() {
|
|
|
6021
6356
|
}
|
|
6022
6357
|
|
|
6023
6358
|
// src/adapters/qoder.ts
|
|
6024
|
-
import { readdir as
|
|
6025
|
-
import
|
|
6026
|
-
import
|
|
6359
|
+
import { readdir as readdir7, readFile as readFile10, stat as stat7 } from "node:fs/promises";
|
|
6360
|
+
import os7 from "node:os";
|
|
6361
|
+
import path14 from "node:path";
|
|
6027
6362
|
function parseQoderPaths(filePath) {
|
|
6028
|
-
const parts = filePath.split(
|
|
6363
|
+
const parts = filePath.split(path14.sep);
|
|
6029
6364
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
6030
6365
|
let sessionId = "";
|
|
6031
6366
|
let projectName = "";
|
|
@@ -6034,20 +6369,20 @@ function parseQoderPaths(filePath) {
|
|
|
6034
6369
|
sessionId = parts[subagentsIdx - 1];
|
|
6035
6370
|
projectName = parts[subagentsIdx - 2];
|
|
6036
6371
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6037
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6372
|
+
configDir2 = parts.slice(0, projectsIdx).join(path14.sep);
|
|
6038
6373
|
} else {
|
|
6039
6374
|
const filename = parts.at(-1) || "";
|
|
6040
|
-
sessionId =
|
|
6375
|
+
sessionId = path14.basename(filename, ".jsonl");
|
|
6041
6376
|
projectName = parts.at(-2) || "";
|
|
6042
6377
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6043
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6378
|
+
configDir2 = parts.slice(0, projectsIdx).join(path14.sep);
|
|
6044
6379
|
}
|
|
6045
6380
|
return { configDir: configDir2, projectName, sessionId };
|
|
6046
6381
|
}
|
|
6047
6382
|
async function loadQoderModelNames(configDir2) {
|
|
6048
6383
|
try {
|
|
6049
|
-
const dynamicTextsPath =
|
|
6050
|
-
const content = await
|
|
6384
|
+
const dynamicTextsPath = path14.join(configDir2, ".auth", "dynamic-texts.json");
|
|
6385
|
+
const content = await readFile10(dynamicTextsPath, "utf8");
|
|
6051
6386
|
const json = JSON.parse(content);
|
|
6052
6387
|
const texts = json.texts || {};
|
|
6053
6388
|
const map = {};
|
|
@@ -6064,15 +6399,15 @@ async function loadQoderModelNames(configDir2) {
|
|
|
6064
6399
|
}
|
|
6065
6400
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
6066
6401
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
6067
|
-
const segmentsPath =
|
|
6402
|
+
const segmentsPath = path14.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
6068
6403
|
const modelCalls = [];
|
|
6069
6404
|
try {
|
|
6070
|
-
const files = await
|
|
6405
|
+
const files = await readdir7(segmentsPath);
|
|
6071
6406
|
for (const file of files) {
|
|
6072
6407
|
if (!file.endsWith(".jsonl")) {
|
|
6073
6408
|
continue;
|
|
6074
6409
|
}
|
|
6075
|
-
const content = await
|
|
6410
|
+
const content = await readFile10(path14.join(segmentsPath, file), "utf8");
|
|
6076
6411
|
let currentTurnIsSubagent = false;
|
|
6077
6412
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
6078
6413
|
const raw = parseJsonLine(line);
|
|
@@ -6105,7 +6440,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
6105
6440
|
return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
|
|
6106
6441
|
}
|
|
6107
6442
|
async function parseQoderSessionFile(filePath, options) {
|
|
6108
|
-
const text = await
|
|
6443
|
+
const text = await readFile10(filePath, "utf8");
|
|
6109
6444
|
const lines = text.split("\n").filter(Boolean);
|
|
6110
6445
|
const { configDir: configDir2 } = parseQoderPaths(filePath);
|
|
6111
6446
|
const projectContext = await qoderProjectContextFromLines(filePath, lines, options, configDir2);
|
|
@@ -6140,7 +6475,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
6140
6475
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
6141
6476
|
state.sessionId = sessionId;
|
|
6142
6477
|
cwd = stringField(raw, "cwd") || cwd;
|
|
6143
|
-
project = projectContext.project || (cwd ?
|
|
6478
|
+
project = projectContext.project || (cwd ? path14.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
6144
6479
|
if (!ts) {
|
|
6145
6480
|
continue;
|
|
6146
6481
|
}
|
|
@@ -6535,24 +6870,24 @@ function qoderExtractText(value) {
|
|
|
6535
6870
|
}
|
|
6536
6871
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6537
6872
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
6538
|
-
const isSubagent = filePath.includes(`${
|
|
6873
|
+
const isSubagent = filePath.includes(`${path14.sep}subagents${path14.sep}`);
|
|
6539
6874
|
let cwds = [];
|
|
6540
6875
|
for (const line of lines) {
|
|
6541
6876
|
const raw = parseJsonLine(line);
|
|
6542
6877
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6543
|
-
if (cwd &&
|
|
6878
|
+
if (cwd && path14.isAbsolute(cwd)) {
|
|
6544
6879
|
cwds.push(cwd);
|
|
6545
6880
|
}
|
|
6546
6881
|
}
|
|
6547
6882
|
if (isSubagent) {
|
|
6548
|
-
const parentSessionPath =
|
|
6883
|
+
const parentSessionPath = path14.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
6549
6884
|
try {
|
|
6550
|
-
const parentText = await
|
|
6885
|
+
const parentText = await readFile10(parentSessionPath, "utf8");
|
|
6551
6886
|
const parentCwds = [];
|
|
6552
6887
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
6553
6888
|
const raw = parseJsonLine(line);
|
|
6554
6889
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6555
|
-
if (cwd &&
|
|
6890
|
+
if (cwd && path14.isAbsolute(cwd)) {
|
|
6556
6891
|
parentCwds.push(cwd);
|
|
6557
6892
|
}
|
|
6558
6893
|
}
|
|
@@ -6563,7 +6898,7 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
6563
6898
|
}
|
|
6564
6899
|
}
|
|
6565
6900
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
6566
|
-
const project = cwds.length > 0 ?
|
|
6901
|
+
const project = cwds.length > 0 ? path14.basename(cwds[0]) : root ? path14.basename(root) : await qoderProjectFromFilePath(filePath, options);
|
|
6567
6902
|
return {
|
|
6568
6903
|
project,
|
|
6569
6904
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6572,15 +6907,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
6572
6907
|
async function gitRootFromCwds3(cwds) {
|
|
6573
6908
|
const seen = /* @__PURE__ */ new Set();
|
|
6574
6909
|
for (const cwd of cwds) {
|
|
6575
|
-
let current =
|
|
6910
|
+
let current = path14.resolve(cwd);
|
|
6576
6911
|
while (!seen.has(current)) {
|
|
6577
6912
|
seen.add(current);
|
|
6578
6913
|
try {
|
|
6579
|
-
await
|
|
6914
|
+
await stat7(path14.join(current, ".git"));
|
|
6580
6915
|
return current;
|
|
6581
6916
|
} catch {
|
|
6582
6917
|
}
|
|
6583
|
-
const parent =
|
|
6918
|
+
const parent = path14.dirname(current);
|
|
6584
6919
|
if (parent === current) {
|
|
6585
6920
|
break;
|
|
6586
6921
|
}
|
|
@@ -6591,12 +6926,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
6591
6926
|
}
|
|
6592
6927
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
6593
6928
|
for (const cwd of cwds) {
|
|
6594
|
-
let current =
|
|
6929
|
+
let current = path14.resolve(cwd);
|
|
6595
6930
|
while (true) {
|
|
6596
6931
|
if (encodeQoderProjectPath(current) === projectDir) {
|
|
6597
6932
|
return current;
|
|
6598
6933
|
}
|
|
6599
|
-
const parent =
|
|
6934
|
+
const parent = path14.dirname(current);
|
|
6600
6935
|
if (parent === current) {
|
|
6601
6936
|
break;
|
|
6602
6937
|
}
|
|
@@ -6606,10 +6941,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
6606
6941
|
return void 0;
|
|
6607
6942
|
}
|
|
6608
6943
|
function encodeQoderProjectPath(value) {
|
|
6609
|
-
return
|
|
6944
|
+
return path14.resolve(value).split(path14.sep).join("-").replace(/_/g, "-");
|
|
6610
6945
|
}
|
|
6611
6946
|
function rawQoderProjectPath(value) {
|
|
6612
|
-
return
|
|
6947
|
+
return path14.resolve(value).split(path14.sep).join("-");
|
|
6613
6948
|
}
|
|
6614
6949
|
function qoderEncodedVariants(value) {
|
|
6615
6950
|
const raw = rawQoderProjectPath(value);
|
|
@@ -6625,11 +6960,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
6625
6960
|
return void 0;
|
|
6626
6961
|
}
|
|
6627
6962
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
6628
|
-
const projectDir =
|
|
6629
|
-
const home = options ?
|
|
6963
|
+
const projectDir = path14.basename(path14.dirname(filePath));
|
|
6964
|
+
const home = options ? path14.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
|
|
6630
6965
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
6631
6966
|
if (resolved) {
|
|
6632
|
-
return
|
|
6967
|
+
return path14.basename(resolved);
|
|
6633
6968
|
}
|
|
6634
6969
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
6635
6970
|
if (suffix) {
|
|
@@ -6650,12 +6985,12 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
6650
6985
|
while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
|
|
6651
6986
|
let matchedChild;
|
|
6652
6987
|
try {
|
|
6653
|
-
const entries = await
|
|
6988
|
+
const entries = await readdir7(current, { withFileTypes: true });
|
|
6654
6989
|
for (const entry of entries) {
|
|
6655
6990
|
if (!entry.isDirectory()) {
|
|
6656
6991
|
continue;
|
|
6657
6992
|
}
|
|
6658
|
-
const candidate =
|
|
6993
|
+
const candidate = path14.join(current, entry.name);
|
|
6659
6994
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
6660
6995
|
if (candidateVariants.includes(projectDir)) {
|
|
6661
6996
|
return candidate;
|
|
@@ -6700,9 +7035,9 @@ function hookConfig6() {
|
|
|
6700
7035
|
function qoderConfigDir(home, env) {
|
|
6701
7036
|
const override = env?.QODER_CONFIG_DIR;
|
|
6702
7037
|
if (override && override.trim()) {
|
|
6703
|
-
return
|
|
7038
|
+
return path14.resolve(override);
|
|
6704
7039
|
}
|
|
6705
|
-
return
|
|
7040
|
+
return path14.join(home, ".qoder");
|
|
6706
7041
|
}
|
|
6707
7042
|
function createQoderAdapter() {
|
|
6708
7043
|
return {
|
|
@@ -6714,27 +7049,27 @@ function createQoderAdapter() {
|
|
|
6714
7049
|
return qoderConfigDir(home, env);
|
|
6715
7050
|
},
|
|
6716
7051
|
installedPath(home, env) {
|
|
6717
|
-
return
|
|
7052
|
+
return path14.join(qoderConfigDir(home, env), "settings.json");
|
|
6718
7053
|
},
|
|
6719
7054
|
async isInstalled(home, env) {
|
|
6720
7055
|
return isHooksJsonInstalled(
|
|
6721
|
-
|
|
7056
|
+
path14.join(qoderConfigDir(home, env), "settings.json"),
|
|
6722
7057
|
"vibetime hook --agent qoder"
|
|
6723
7058
|
);
|
|
6724
7059
|
},
|
|
6725
7060
|
installEntries(home, env) {
|
|
6726
7061
|
return [{
|
|
6727
7062
|
kind: "hooks-json",
|
|
6728
|
-
path:
|
|
7063
|
+
path: path14.join(qoderConfigDir(home, env), "settings.json"),
|
|
6729
7064
|
content: hookConfig6()
|
|
6730
7065
|
}];
|
|
6731
7066
|
},
|
|
6732
7067
|
sourcePaths(home, env) {
|
|
6733
7068
|
const base = qoderConfigDir(home, env);
|
|
6734
7069
|
return [
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
7070
|
+
path14.join(base, "projects"),
|
|
7071
|
+
path14.join(base, ".qoder.json"),
|
|
7072
|
+
path14.join(home, ".qoder.json")
|
|
6738
7073
|
];
|
|
6739
7074
|
},
|
|
6740
7075
|
parseSessionFile: parseQoderSessionFile
|
|
@@ -6769,21 +7104,21 @@ function normalizeId(id) {
|
|
|
6769
7104
|
}
|
|
6770
7105
|
|
|
6771
7106
|
// src/adapters/workbuddy.ts
|
|
6772
|
-
import { readFile as
|
|
6773
|
-
import
|
|
7107
|
+
import { readFile as readFile11, readdir as readdir8, stat as stat8 } from "node:fs/promises";
|
|
7108
|
+
import path15 from "node:path";
|
|
6774
7109
|
init_fs();
|
|
6775
7110
|
function workbuddyProjectsDir(home, env) {
|
|
6776
7111
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
6777
7112
|
if (override && override.trim()) {
|
|
6778
|
-
return
|
|
7113
|
+
return path15.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
6779
7114
|
}
|
|
6780
|
-
return
|
|
7115
|
+
return path15.join(home, ".workbuddy", "projects");
|
|
6781
7116
|
}
|
|
6782
7117
|
function projectFromCwd(cwd, fallback) {
|
|
6783
7118
|
if (!cwd) {
|
|
6784
7119
|
return fallback;
|
|
6785
7120
|
}
|
|
6786
|
-
return
|
|
7121
|
+
return path15.basename(cwd) || fallback;
|
|
6787
7122
|
}
|
|
6788
7123
|
function sourceHash(filePath) {
|
|
6789
7124
|
return `sha256:${createStableHash(filePath)}`;
|
|
@@ -6865,7 +7200,7 @@ function contentLength(value) {
|
|
|
6865
7200
|
return 0;
|
|
6866
7201
|
}
|
|
6867
7202
|
async function readWorkbuddyLines(filePath) {
|
|
6868
|
-
const text = await
|
|
7203
|
+
const text = await readFile11(filePath, "utf8");
|
|
6869
7204
|
return text.split(/\r?\n/).map((line, index) => {
|
|
6870
7205
|
if (!line.trim()) {
|
|
6871
7206
|
return void 0;
|
|
@@ -6885,8 +7220,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
6885
7220
|
}
|
|
6886
7221
|
const events = [];
|
|
6887
7222
|
const first = lines[0].record;
|
|
6888
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
6889
|
-
const fallbackProject =
|
|
7223
|
+
const sessionId = stringField(first, "sessionId") || path15.basename(filePath, ".jsonl");
|
|
7224
|
+
const fallbackProject = path15.basename(path15.dirname(filePath));
|
|
6890
7225
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
6891
7226
|
const project = projectFromCwd(cwd, fallbackProject);
|
|
6892
7227
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
@@ -7055,17 +7390,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
7055
7390
|
const base = sourceRoot || workbuddyProjectsDir(home, env);
|
|
7056
7391
|
const files = [];
|
|
7057
7392
|
try {
|
|
7058
|
-
const projects = await
|
|
7393
|
+
const projects = await readdir8(base, { withFileTypes: true });
|
|
7059
7394
|
for (const project of projects) {
|
|
7060
7395
|
if (!project.isDirectory()) {
|
|
7061
7396
|
continue;
|
|
7062
7397
|
}
|
|
7063
|
-
const projectDir =
|
|
7064
|
-
const entries = await
|
|
7398
|
+
const projectDir = path15.join(base, project.name);
|
|
7399
|
+
const entries = await readdir8(projectDir, { withFileTypes: true });
|
|
7065
7400
|
for (const entry of entries) {
|
|
7066
7401
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
7067
|
-
const filePath =
|
|
7068
|
-
const info = await
|
|
7402
|
+
const filePath = path15.join(projectDir, entry.name);
|
|
7403
|
+
const info = await stat8(filePath);
|
|
7069
7404
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
7070
7405
|
}
|
|
7071
7406
|
}
|
|
@@ -7102,26 +7437,26 @@ function createWorkbuddyAdapter() {
|
|
|
7102
7437
|
|
|
7103
7438
|
// src/adapters/zcode.ts
|
|
7104
7439
|
import { execFile } from "node:child_process";
|
|
7105
|
-
import { readFile as
|
|
7106
|
-
import
|
|
7440
|
+
import { readFile as readFile12, stat as stat9 } from "node:fs/promises";
|
|
7441
|
+
import path16 from "node:path";
|
|
7107
7442
|
import { promisify as promisify2 } from "node:util";
|
|
7108
7443
|
init_fs();
|
|
7109
7444
|
var execFileAsync = promisify2(execFile);
|
|
7110
7445
|
function zcodeCliDir(home, env) {
|
|
7111
7446
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
7112
7447
|
if (override && override.trim()) {
|
|
7113
|
-
return
|
|
7448
|
+
return path16.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
7114
7449
|
}
|
|
7115
|
-
return
|
|
7450
|
+
return path16.join(home, ".zcode", "cli");
|
|
7116
7451
|
}
|
|
7117
7452
|
function zcodeDbPath(home, env) {
|
|
7118
|
-
return
|
|
7453
|
+
return path16.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
7119
7454
|
}
|
|
7120
7455
|
var providerNameCache = null;
|
|
7121
7456
|
async function loadProviderNames(configPath2) {
|
|
7122
7457
|
let fileMtime = 0;
|
|
7123
7458
|
try {
|
|
7124
|
-
const info = await
|
|
7459
|
+
const info = await stat9(configPath2);
|
|
7125
7460
|
fileMtime = info.mtimeMs;
|
|
7126
7461
|
} catch {
|
|
7127
7462
|
return /* @__PURE__ */ new Map();
|
|
@@ -7131,7 +7466,7 @@ async function loadProviderNames(configPath2) {
|
|
|
7131
7466
|
}
|
|
7132
7467
|
const map = /* @__PURE__ */ new Map();
|
|
7133
7468
|
try {
|
|
7134
|
-
const raw = await
|
|
7469
|
+
const raw = await readFile12(configPath2, "utf-8");
|
|
7135
7470
|
const config = JSON.parse(raw);
|
|
7136
7471
|
const providers = config?.provider;
|
|
7137
7472
|
if (isPlainObject(providers)) {
|
|
@@ -7149,7 +7484,7 @@ function sourceHash2(filePath) {
|
|
|
7149
7484
|
return `sha256:${createStableHash(filePath)}`;
|
|
7150
7485
|
}
|
|
7151
7486
|
function projectFromDirectory(directory) {
|
|
7152
|
-
return directory ?
|
|
7487
|
+
return directory ? path16.basename(directory) || "zcode" : "zcode";
|
|
7153
7488
|
}
|
|
7154
7489
|
function isoFromMs(value) {
|
|
7155
7490
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
@@ -7305,16 +7640,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7305
7640
|
if (rows.length === 0) {
|
|
7306
7641
|
return [];
|
|
7307
7642
|
}
|
|
7308
|
-
let candidate =
|
|
7643
|
+
let candidate = path16.resolve(filePath);
|
|
7309
7644
|
let configPath2 = "";
|
|
7310
7645
|
for (let i = 0; i < 12; i++) {
|
|
7311
|
-
const probe =
|
|
7646
|
+
const probe = path16.join(candidate, ".zcode", "v2", "config.json");
|
|
7312
7647
|
try {
|
|
7313
|
-
await
|
|
7648
|
+
await stat9(probe);
|
|
7314
7649
|
configPath2 = probe;
|
|
7315
7650
|
break;
|
|
7316
7651
|
} catch {
|
|
7317
|
-
const parent =
|
|
7652
|
+
const parent = path16.dirname(candidate);
|
|
7318
7653
|
if (parent === candidate) break;
|
|
7319
7654
|
candidate = parent;
|
|
7320
7655
|
}
|
|
@@ -7530,9 +7865,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7530
7865
|
}
|
|
7531
7866
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
7532
7867
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
7533
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
7868
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path16.join(candidate, "db", "db.sqlite");
|
|
7534
7869
|
try {
|
|
7535
|
-
const info = await
|
|
7870
|
+
const info = await stat9(filePath);
|
|
7536
7871
|
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
7537
7872
|
} catch {
|
|
7538
7873
|
return [];
|
|
@@ -7999,15 +8334,15 @@ function hookCommandFromGroup(group) {
|
|
|
7999
8334
|
import { randomUUID } from "node:crypto";
|
|
8000
8335
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8001
8336
|
import { homedir, hostname } from "node:os";
|
|
8002
|
-
import
|
|
8337
|
+
import path17 from "node:path";
|
|
8003
8338
|
function configDir(home = homedir()) {
|
|
8004
|
-
return
|
|
8339
|
+
return path17.join(home, ".vibetime");
|
|
8005
8340
|
}
|
|
8006
8341
|
function configPath(home = homedir()) {
|
|
8007
|
-
return
|
|
8342
|
+
return path17.join(configDir(home), "config.json");
|
|
8008
8343
|
}
|
|
8009
8344
|
function machineIdPath(home = homedir()) {
|
|
8010
|
-
return
|
|
8345
|
+
return path17.join(configDir(home), "machine-id");
|
|
8011
8346
|
}
|
|
8012
8347
|
function readConfig(home = homedir()) {
|
|
8013
8348
|
const file = configPath(home);
|
|
@@ -8054,15 +8389,15 @@ function defaultMachineName() {
|
|
|
8054
8389
|
init_fs();
|
|
8055
8390
|
|
|
8056
8391
|
// src/lib/logger.ts
|
|
8057
|
-
import { appendFile, mkdir as mkdir3, rename, stat as
|
|
8392
|
+
import { appendFile, mkdir as mkdir3, rename, stat as stat10 } from "node:fs/promises";
|
|
8058
8393
|
import { homedir as homedir2 } from "node:os";
|
|
8059
|
-
import
|
|
8394
|
+
import path18 from "node:path";
|
|
8060
8395
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
8061
8396
|
function logDir(home = homedir2()) {
|
|
8062
|
-
return
|
|
8397
|
+
return path18.join(home, ".vibetime", "logs");
|
|
8063
8398
|
}
|
|
8064
8399
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
8065
|
-
return
|
|
8400
|
+
return path18.join(logDir(home), name);
|
|
8066
8401
|
}
|
|
8067
8402
|
function serializeError(error) {
|
|
8068
8403
|
if (error instanceof Error) {
|
|
@@ -8072,7 +8407,7 @@ function serializeError(error) {
|
|
|
8072
8407
|
}
|
|
8073
8408
|
async function rotateIfNeeded(file) {
|
|
8074
8409
|
try {
|
|
8075
|
-
const info = await
|
|
8410
|
+
const info = await stat10(file);
|
|
8076
8411
|
if (info.size > MAX_BYTES) {
|
|
8077
8412
|
await rename(file, `${file}.1`).catch(() => {
|
|
8078
8413
|
});
|
|
@@ -8237,8 +8572,8 @@ function buildHeaders(token, machine) {
|
|
|
8237
8572
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
8238
8573
|
};
|
|
8239
8574
|
}
|
|
8240
|
-
function joinUrl(base,
|
|
8241
|
-
return new URL(
|
|
8575
|
+
function joinUrl(base, path20) {
|
|
8576
|
+
return new URL(path20, base.endsWith("/") ? base : `${base}/`).toString();
|
|
8242
8577
|
}
|
|
8243
8578
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
8244
8579
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -8309,6 +8644,7 @@ var BACKFILL_STATE_SCHEMA_VERSION = 5;
|
|
|
8309
8644
|
function createRegistry() {
|
|
8310
8645
|
const registry = new AdapterRegistry();
|
|
8311
8646
|
registry.register(createCodexAdapter());
|
|
8647
|
+
registry.register(createCopilotAdapter());
|
|
8312
8648
|
registry.register(createClaudeCodeAdapter());
|
|
8313
8649
|
registry.register(createClaudeCoworkAdapter());
|
|
8314
8650
|
registry.register(createPiAdapter());
|
|
@@ -8736,11 +9072,14 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
8736
9072
|
if (source.id === "zcode") {
|
|
8737
9073
|
return zcodeBackfillFiles(stringOption(options["source-root"]), resolveHome2(options, ctx), ctx.env);
|
|
8738
9074
|
}
|
|
9075
|
+
if (source.id === "copilot") {
|
|
9076
|
+
return copilotBackfillFiles(stringOption(options["source-root"]), resolveHome2(options, ctx), ctx.env);
|
|
9077
|
+
}
|
|
8739
9078
|
const roots = stringOption(options["source-root"]) ? [requiredOption(options, "source-root")] : source.paths;
|
|
8740
9079
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
8741
9080
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
8742
9081
|
return Promise.all(files.map(async (filePath) => {
|
|
8743
|
-
const info = await
|
|
9082
|
+
const info = await stat11(filePath);
|
|
8744
9083
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
8745
9084
|
}));
|
|
8746
9085
|
}
|
|
@@ -9053,13 +9392,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
9053
9392
|
});
|
|
9054
9393
|
}
|
|
9055
9394
|
function backfillIncrementalStatePath(home) {
|
|
9056
|
-
return
|
|
9395
|
+
return path19.join(home, ".vibetime", "backfill-state.json");
|
|
9057
9396
|
}
|
|
9058
9397
|
function syncLocalTriggerStatePath(home) {
|
|
9059
|
-
return
|
|
9398
|
+
return path19.join(home, ".vibetime", "sync-local-trigger.json");
|
|
9060
9399
|
}
|
|
9061
9400
|
function syncLocalTriggerLockPath(home) {
|
|
9062
|
-
return
|
|
9401
|
+
return path19.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
9063
9402
|
}
|
|
9064
9403
|
function backfillRemoteKey(baseUrl) {
|
|
9065
9404
|
try {
|
|
@@ -9121,7 +9460,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
9121
9460
|
}
|
|
9122
9461
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
9123
9462
|
const statePath = backfillIncrementalStatePath(home);
|
|
9124
|
-
await mkdir4(
|
|
9463
|
+
await mkdir4(path19.dirname(statePath), { recursive: true });
|
|
9125
9464
|
await writeFile3(statePath, `${JSON.stringify(file, null, 2)}
|
|
9126
9465
|
`, "utf8");
|
|
9127
9466
|
}
|
|
@@ -9170,7 +9509,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
9170
9509
|
return nextState;
|
|
9171
9510
|
}
|
|
9172
9511
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
9173
|
-
await mkdir4(
|
|
9512
|
+
await mkdir4(path19.dirname(statePath), { recursive: true });
|
|
9174
9513
|
const tmpPath = `${statePath}.tmp`;
|
|
9175
9514
|
await writeFile3(tmpPath, `${JSON.stringify(state, null, 2)}
|
|
9176
9515
|
`, "utf8");
|
|
@@ -9187,7 +9526,7 @@ async function readSyncLocalLock(lockPath) {
|
|
|
9187
9526
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
9188
9527
|
}
|
|
9189
9528
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
9190
|
-
await mkdir4(
|
|
9529
|
+
await mkdir4(path19.dirname(lockPath), { recursive: true });
|
|
9191
9530
|
await writeFile3(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
9192
9531
|
`, "utf8");
|
|
9193
9532
|
}
|
|
@@ -9247,10 +9586,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
9247
9586
|
if (cliPath.endsWith(".ts")) {
|
|
9248
9587
|
return ["--import", "tsx", cliPath];
|
|
9249
9588
|
}
|
|
9250
|
-
return [
|
|
9589
|
+
return [path19.resolve(path19.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
9251
9590
|
}
|
|
9252
9591
|
function resolveHome2(options, ctx) {
|
|
9253
|
-
return
|
|
9592
|
+
return path19.resolve(stringOption(options.home) || ctx.env.HOME || os8.homedir());
|
|
9254
9593
|
}
|
|
9255
9594
|
function requestedTargets(options) {
|
|
9256
9595
|
const value = options.target || options.targets;
|