@yhong91/vibetime 0.1.1 → 0.1.3
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 +1190 -181
- package/package.json +8 -9
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 stat10, writeFile as writeFile3 } from "node:fs/promises";
|
|
163
|
+
import os7 from "node:os";
|
|
164
|
+
import path18 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", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn"];
|
|
200
|
+
var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "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)}`;
|
|
@@ -349,9 +349,9 @@ function removeVolatileHashFields(value) {
|
|
|
349
349
|
continue;
|
|
350
350
|
}
|
|
351
351
|
if (key === "refs" && isRecord(item)) {
|
|
352
|
-
const
|
|
353
|
-
delete
|
|
354
|
-
result[key] = removeVolatileHashFields(
|
|
352
|
+
const refs2 = { ...item };
|
|
353
|
+
delete refs2.payloadHash;
|
|
354
|
+
result[key] = removeVolatileHashFields(refs2);
|
|
355
355
|
continue;
|
|
356
356
|
}
|
|
357
357
|
result[key] = removeVolatileHashFields(item);
|
|
@@ -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.3" : "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;
|
|
@@ -1224,13 +1224,13 @@ function isPlainObject(value) {
|
|
|
1224
1224
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1225
1225
|
}
|
|
1226
1226
|
function stringRefs(value) {
|
|
1227
|
-
const
|
|
1227
|
+
const refs2 = {};
|
|
1228
1228
|
for (const [key, item] of Object.entries(value || {})) {
|
|
1229
1229
|
if (typeof item === "string" && item.length > 0) {
|
|
1230
|
-
|
|
1230
|
+
refs2[key] = item;
|
|
1231
1231
|
}
|
|
1232
1232
|
}
|
|
1233
|
-
return
|
|
1233
|
+
return refs2;
|
|
1234
1234
|
}
|
|
1235
1235
|
function stringOption(value) {
|
|
1236
1236
|
if (Array.isArray(value)) {
|
|
@@ -1308,7 +1308,7 @@ function withBackfillRefs(event, context) {
|
|
|
1308
1308
|
event.type,
|
|
1309
1309
|
event.refs?.sourceId
|
|
1310
1310
|
]);
|
|
1311
|
-
const
|
|
1311
|
+
const refs2 = {
|
|
1312
1312
|
...stringRefs(event.refs),
|
|
1313
1313
|
importKey,
|
|
1314
1314
|
sourcePathHash: context.sourcePathHash,
|
|
@@ -1318,12 +1318,12 @@ function withBackfillRefs(event, context) {
|
|
|
1318
1318
|
parserVersion: PACKAGE_VERSION
|
|
1319
1319
|
};
|
|
1320
1320
|
if (context.options.includeSourcePath) {
|
|
1321
|
-
|
|
1321
|
+
refs2.transcriptPath = context.filePath;
|
|
1322
1322
|
}
|
|
1323
1323
|
return {
|
|
1324
1324
|
...event,
|
|
1325
1325
|
id: createStableEventId(importKey),
|
|
1326
|
-
refs
|
|
1326
|
+
refs: refs2
|
|
1327
1327
|
};
|
|
1328
1328
|
}
|
|
1329
1329
|
function matchesBackfillFilters(event, options) {
|
|
@@ -2776,11 +2776,256 @@ function createClaudeCodeAdapter() {
|
|
|
2776
2776
|
};
|
|
2777
2777
|
}
|
|
2778
2778
|
|
|
2779
|
-
// src/adapters/
|
|
2780
|
-
import { readFile as readFile4,
|
|
2779
|
+
// src/adapters/claude-cowork.ts
|
|
2780
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat4 } from "node:fs/promises";
|
|
2781
|
+
import os3 from "node:os";
|
|
2781
2782
|
import path7 from "node:path";
|
|
2783
|
+
init_fs();
|
|
2784
|
+
var COWORK_PREFIX = "cowork:";
|
|
2785
|
+
function coworkDataDirs(home, env) {
|
|
2786
|
+
const override = env?.COWORK_DIR || env?.CLAUDE_COWORK_DIR;
|
|
2787
|
+
if (override && override.trim()) {
|
|
2788
|
+
return override.split(",").map((item) => item.trim()).filter(Boolean).map((item) => path7.resolve(item));
|
|
2789
|
+
}
|
|
2790
|
+
return [
|
|
2791
|
+
path7.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions"),
|
|
2792
|
+
path7.join(home, ".config", "Claude", "local-agent-mode-sessions"),
|
|
2793
|
+
path7.join(home, "AppData", "Local", "Packages", "Claude_pzs8sxrjxfjjc", "LocalCache", "Roaming", "Claude", "local-agent-mode-sessions"),
|
|
2794
|
+
path7.join(home, "AppData", "Roaming", "Claude", "local-agent-mode-sessions")
|
|
2795
|
+
];
|
|
2796
|
+
}
|
|
2797
|
+
function isCoworkMetaFileName(name) {
|
|
2798
|
+
return /^local_[\w-]+\.json$/.test(name);
|
|
2799
|
+
}
|
|
2800
|
+
async function readCoworkMeta(filePath) {
|
|
2801
|
+
try {
|
|
2802
|
+
const raw = JSON.parse(await readFile4(filePath, "utf8"));
|
|
2803
|
+
return raw && typeof raw === "object" ? raw : {};
|
|
2804
|
+
} catch {
|
|
2805
|
+
return {};
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
async function isRegularFile(filePath) {
|
|
2809
|
+
try {
|
|
2810
|
+
return (await stat4(filePath)).isFile();
|
|
2811
|
+
} catch {
|
|
2812
|
+
return false;
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
async function resolveCoworkTranscript(sessionDir, cliSessionId) {
|
|
2816
|
+
if (!sessionDir || !cliSessionId) {
|
|
2817
|
+
return void 0;
|
|
2818
|
+
}
|
|
2819
|
+
const projectsDir = path7.join(sessionDir, ".claude", "projects");
|
|
2820
|
+
let entries;
|
|
2821
|
+
try {
|
|
2822
|
+
entries = await readdir3(projectsDir, { withFileTypes: true });
|
|
2823
|
+
} catch {
|
|
2824
|
+
return void 0;
|
|
2825
|
+
}
|
|
2826
|
+
const target = `${cliSessionId}.jsonl`;
|
|
2827
|
+
for (const entry of entries) {
|
|
2828
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
2829
|
+
continue;
|
|
2830
|
+
}
|
|
2831
|
+
const candidate = path7.join(projectsDir, entry.name, target);
|
|
2832
|
+
if (await isRegularFile(candidate)) {
|
|
2833
|
+
return candidate;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
return void 0;
|
|
2837
|
+
}
|
|
2838
|
+
async function coworkSubagentTranscripts(mainTranscript, cliSessionId) {
|
|
2839
|
+
const root = path7.join(path7.dirname(mainTranscript), cliSessionId, "subagents");
|
|
2840
|
+
const out = [];
|
|
2841
|
+
async function walk(dir) {
|
|
2842
|
+
let entries;
|
|
2843
|
+
try {
|
|
2844
|
+
entries = await readdir3(dir, { withFileTypes: true });
|
|
2845
|
+
} catch {
|
|
2846
|
+
return;
|
|
2847
|
+
}
|
|
2848
|
+
await Promise.all(entries.map(async (entry) => {
|
|
2849
|
+
const entryPath = path7.join(dir, entry.name);
|
|
2850
|
+
if (entry.isDirectory()) {
|
|
2851
|
+
await walk(entryPath);
|
|
2852
|
+
return;
|
|
2853
|
+
}
|
|
2854
|
+
if (entry.isFile() && /^agent-.+\.jsonl$/.test(entry.name)) {
|
|
2855
|
+
out.push(entryPath);
|
|
2856
|
+
}
|
|
2857
|
+
}));
|
|
2858
|
+
}
|
|
2859
|
+
await walk(root);
|
|
2860
|
+
return out.sort();
|
|
2861
|
+
}
|
|
2862
|
+
async function discoverCoworkTranscripts(root) {
|
|
2863
|
+
const transcripts = [];
|
|
2864
|
+
async function walk(dir) {
|
|
2865
|
+
let entries;
|
|
2866
|
+
try {
|
|
2867
|
+
entries = await readdir3(dir, { withFileTypes: true });
|
|
2868
|
+
} catch {
|
|
2869
|
+
return;
|
|
2870
|
+
}
|
|
2871
|
+
await Promise.all(entries.map(async (entry) => {
|
|
2872
|
+
const entryPath = path7.join(dir, entry.name);
|
|
2873
|
+
if (entry.isDirectory()) {
|
|
2874
|
+
if (entry.name.startsWith("local_") || entry.name === "skills-plugin" || entry.name === "node_modules" || entry.name === ".git") {
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
await walk(entryPath);
|
|
2878
|
+
return;
|
|
2879
|
+
}
|
|
2880
|
+
if (!entry.isFile() || !isCoworkMetaFileName(entry.name)) {
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
const metadata = await readCoworkMeta(entryPath);
|
|
2884
|
+
if (!metadata.cliSessionId) {
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2887
|
+
const sessionDir = entryPath.slice(0, -".json".length);
|
|
2888
|
+
const mainTranscript = await resolveCoworkTranscript(sessionDir, metadata.cliSessionId);
|
|
2889
|
+
if (!mainTranscript) {
|
|
2890
|
+
return;
|
|
2891
|
+
}
|
|
2892
|
+
transcripts.push({ transcriptPath: mainTranscript, metadataPath: entryPath, metadata });
|
|
2893
|
+
for (const subagentPath of await coworkSubagentTranscripts(mainTranscript, metadata.cliSessionId)) {
|
|
2894
|
+
transcripts.push({ transcriptPath: subagentPath, metadataPath: entryPath, metadata });
|
|
2895
|
+
}
|
|
2896
|
+
}));
|
|
2897
|
+
}
|
|
2898
|
+
await walk(root);
|
|
2899
|
+
return transcripts.sort((a, b) => a.transcriptPath.localeCompare(b.transcriptPath));
|
|
2900
|
+
}
|
|
2901
|
+
function coworkMetaPathForTranscript(transcriptPath) {
|
|
2902
|
+
const marker = `${path7.sep}.claude${path7.sep}projects${path7.sep}`;
|
|
2903
|
+
const index = transcriptPath.indexOf(marker);
|
|
2904
|
+
if (index < 0) {
|
|
2905
|
+
return void 0;
|
|
2906
|
+
}
|
|
2907
|
+
return `${transcriptPath.slice(0, index)}.json`;
|
|
2908
|
+
}
|
|
2909
|
+
function selectedFolder(meta) {
|
|
2910
|
+
return meta.userSelectedFolders?.find((item) => typeof item === "string" && item.trim());
|
|
2911
|
+
}
|
|
2912
|
+
function projectFromMeta(meta) {
|
|
2913
|
+
const folder = selectedFolder(meta);
|
|
2914
|
+
if (!folder) {
|
|
2915
|
+
return { project: "cowork" };
|
|
2916
|
+
}
|
|
2917
|
+
const resolved = path7.resolve(folder);
|
|
2918
|
+
return {
|
|
2919
|
+
project: path7.basename(resolved).replace(/-/g, "_") || "cowork",
|
|
2920
|
+
cwd: resolved
|
|
2921
|
+
};
|
|
2922
|
+
}
|
|
2923
|
+
function prefixCoworkId(value) {
|
|
2924
|
+
if (!value) {
|
|
2925
|
+
return void 0;
|
|
2926
|
+
}
|
|
2927
|
+
return value.startsWith(COWORK_PREFIX) ? value : `${COWORK_PREFIX}${value}`;
|
|
2928
|
+
}
|
|
2929
|
+
function rebuildEventIdentity(event) {
|
|
2930
|
+
const importKey = createImportKey([
|
|
2931
|
+
event.source,
|
|
2932
|
+
event.refs?.sourcePathHash,
|
|
2933
|
+
event.refs?.sourceLine,
|
|
2934
|
+
event.type,
|
|
2935
|
+
event.refs?.sourceId
|
|
2936
|
+
]);
|
|
2937
|
+
return {
|
|
2938
|
+
...event,
|
|
2939
|
+
id: createStableEventId(importKey),
|
|
2940
|
+
refs: {
|
|
2941
|
+
...event.refs,
|
|
2942
|
+
importKey
|
|
2943
|
+
}
|
|
2944
|
+
};
|
|
2945
|
+
}
|
|
2946
|
+
async function parseClaudeCoworkSessionFile(filePath, options) {
|
|
2947
|
+
const metaPath = coworkMetaPathForTranscript(filePath);
|
|
2948
|
+
const metadata = metaPath ? await readCoworkMeta(metaPath) : {};
|
|
2949
|
+
const { project, cwd } = projectFromMeta(metadata);
|
|
2950
|
+
const parser = createClaudeCodeAdapter().parseSessionFile;
|
|
2951
|
+
if (!parser) {
|
|
2952
|
+
return [];
|
|
2953
|
+
}
|
|
2954
|
+
const events = await parser(filePath, options);
|
|
2955
|
+
return events.map((event) => {
|
|
2956
|
+
const sessionId = prefixCoworkId(event.sessionId);
|
|
2957
|
+
const turnId = prefixCoworkId(event.turnId);
|
|
2958
|
+
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
2959
|
+
const refs2 = { ...event.refs };
|
|
2960
|
+
if (metadata.title) {
|
|
2961
|
+
refs2.coworkTitleHash = `sha256:${createStableHash(metadata.title)}`;
|
|
2962
|
+
}
|
|
2963
|
+
const mapped = {
|
|
2964
|
+
...event,
|
|
2965
|
+
schemaVersion: event.schemaVersion || AGENT_TIME_SCHEMA_VERSION,
|
|
2966
|
+
source: "claude-cowork",
|
|
2967
|
+
agent: "claude-cowork",
|
|
2968
|
+
workspaceId,
|
|
2969
|
+
cwd: cwd || event.cwd,
|
|
2970
|
+
project,
|
|
2971
|
+
sessionId,
|
|
2972
|
+
turnId,
|
|
2973
|
+
refs: refs2
|
|
2974
|
+
};
|
|
2975
|
+
return rebuildEventIdentity(mapped);
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2978
|
+
async function claudeCoworkBackfillFiles(sourceRoot, home, env) {
|
|
2979
|
+
const roots = sourceRoot ? [path7.resolve(sourceRoot)] : coworkDataDirs(home, env);
|
|
2980
|
+
const discovered = (await Promise.all(roots.map(discoverCoworkTranscripts))).flat();
|
|
2981
|
+
return Promise.all(discovered.map(async ({ transcriptPath, metadataPath }) => {
|
|
2982
|
+
const transcriptInfo = await stat4(transcriptPath);
|
|
2983
|
+
let modifiedAt = transcriptInfo.mtime;
|
|
2984
|
+
try {
|
|
2985
|
+
const metaInfo = await stat4(metadataPath);
|
|
2986
|
+
if (metaInfo.mtime > modifiedAt) {
|
|
2987
|
+
modifiedAt = metaInfo.mtime;
|
|
2988
|
+
}
|
|
2989
|
+
} catch {
|
|
2990
|
+
}
|
|
2991
|
+
return { path: transcriptPath, modifiedAt: modifiedAt.toISOString() };
|
|
2992
|
+
}));
|
|
2993
|
+
}
|
|
2994
|
+
function createClaudeCoworkAdapter() {
|
|
2995
|
+
return {
|
|
2996
|
+
id: "claude-cowork",
|
|
2997
|
+
label: "Claude Cowork",
|
|
2998
|
+
agentName: "claude-cowork",
|
|
2999
|
+
kind: "agent",
|
|
3000
|
+
detectPath(home, env) {
|
|
3001
|
+
return coworkDataDirs(home, env)[0] || path7.join(os3.homedir(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
|
|
3002
|
+
},
|
|
3003
|
+
installedPath(home, env) {
|
|
3004
|
+
return this.detectPath(home, env);
|
|
3005
|
+
},
|
|
3006
|
+
async isInstalled() {
|
|
3007
|
+
return false;
|
|
3008
|
+
},
|
|
3009
|
+
installEntries() {
|
|
3010
|
+
return [];
|
|
3011
|
+
},
|
|
3012
|
+
sourcePaths(home, env) {
|
|
3013
|
+
return coworkDataDirs(home, env);
|
|
3014
|
+
},
|
|
3015
|
+
async parseSessionFile(filePath, options) {
|
|
3016
|
+
if (!await pathExists(filePath)) {
|
|
3017
|
+
return [];
|
|
3018
|
+
}
|
|
3019
|
+
return parseClaudeCoworkSessionFile(filePath, options);
|
|
3020
|
+
}
|
|
3021
|
+
};
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
// src/adapters/codebuddy.ts
|
|
3025
|
+
import { readFile as readFile5, readdir as readdir4 } from "node:fs/promises";
|
|
3026
|
+
import path8 from "node:path";
|
|
2782
3027
|
async function parseCodebuddyTraceFile(filePath, options) {
|
|
2783
|
-
const text = await
|
|
3028
|
+
const text = await readFile5(filePath, "utf8");
|
|
2784
3029
|
const sourcePathHash = `sha256:${createStableHash(filePath)}`;
|
|
2785
3030
|
const events = [];
|
|
2786
3031
|
let traceFile;
|
|
@@ -2804,7 +3049,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
2804
3049
|
if (!cwd && trace.startedAt) {
|
|
2805
3050
|
cwd = await cwdFromHistoryFile(trace.startedAt, options);
|
|
2806
3051
|
}
|
|
2807
|
-
const project = cwd ?
|
|
3052
|
+
const project = cwd ? path8.basename(cwd) : void 0;
|
|
2808
3053
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
2809
3054
|
const model = trace.modelInfo?.models?.[0];
|
|
2810
3055
|
const baseEvent = (event) => ({
|
|
@@ -3090,15 +3335,15 @@ function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
|
|
|
3090
3335
|
return { modelCalls: 1 };
|
|
3091
3336
|
}
|
|
3092
3337
|
function sessionIdFromTracePath(filePath) {
|
|
3093
|
-
const match =
|
|
3338
|
+
const match = path8.basename(filePath).match(/trace_([0-9a-f]{32})/);
|
|
3094
3339
|
return match?.[1] ? `codebuddy_${match[1]}` : `codebuddy_${createStableHash(filePath).slice(0, 24)}`;
|
|
3095
3340
|
}
|
|
3096
3341
|
function resolveHome(options) {
|
|
3097
|
-
return options.home ?
|
|
3342
|
+
return options.home ? path8.resolve(String(options.home)) : process.env.HOME || __require("node:os").homedir();
|
|
3098
3343
|
}
|
|
3099
3344
|
async function readCwdFromSession(sessionPath, matchSessionId) {
|
|
3100
3345
|
try {
|
|
3101
|
-
const text = await
|
|
3346
|
+
const text = await readFile5(sessionPath, "utf8");
|
|
3102
3347
|
const session = JSON.parse(text);
|
|
3103
3348
|
if (!isPlainObject(session)) {
|
|
3104
3349
|
return void 0;
|
|
@@ -3115,22 +3360,22 @@ async function readCwdFromSession(sessionPath, matchSessionId) {
|
|
|
3115
3360
|
}
|
|
3116
3361
|
async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
3117
3362
|
const home = resolveHome(options);
|
|
3118
|
-
const sessionsDir =
|
|
3363
|
+
const sessionsDir = path8.join(home, ".codebuddy", "sessions");
|
|
3119
3364
|
if (pid) {
|
|
3120
|
-
const cwd = await readCwdFromSession(
|
|
3365
|
+
const cwd = await readCwdFromSession(path8.join(sessionsDir, `${pid}.json`));
|
|
3121
3366
|
if (cwd) {
|
|
3122
3367
|
return cwd;
|
|
3123
3368
|
}
|
|
3124
3369
|
}
|
|
3125
3370
|
if (traceSessionId) {
|
|
3126
3371
|
try {
|
|
3127
|
-
const files = await
|
|
3372
|
+
const files = await readdir4(sessionsDir);
|
|
3128
3373
|
for (const f of files) {
|
|
3129
3374
|
if (!f.endsWith(".json")) {
|
|
3130
3375
|
continue;
|
|
3131
3376
|
}
|
|
3132
3377
|
const cwd = await readCwdFromSession(
|
|
3133
|
-
|
|
3378
|
+
path8.join(sessionsDir, f),
|
|
3134
3379
|
traceSessionId
|
|
3135
3380
|
);
|
|
3136
3381
|
if (cwd) {
|
|
@@ -3144,13 +3389,13 @@ async function cwdFromSessionFile(pid, traceSessionId, options) {
|
|
|
3144
3389
|
}
|
|
3145
3390
|
async function cwdFromHistoryFile(traceStartedAt, options) {
|
|
3146
3391
|
const home = resolveHome(options);
|
|
3147
|
-
const historyPath =
|
|
3392
|
+
const historyPath = path8.join(home, ".codebuddy", "history.jsonl");
|
|
3148
3393
|
const traceMs = Date.parse(traceStartedAt);
|
|
3149
3394
|
if (Number.isNaN(traceMs)) {
|
|
3150
3395
|
return void 0;
|
|
3151
3396
|
}
|
|
3152
3397
|
try {
|
|
3153
|
-
const text = await
|
|
3398
|
+
const text = await readFile5(historyPath, "utf8");
|
|
3154
3399
|
let bestCwd;
|
|
3155
3400
|
let bestDistance = Infinity;
|
|
3156
3401
|
for (const line of text.split("\n")) {
|
|
@@ -3206,9 +3451,9 @@ function hookConfig3() {
|
|
|
3206
3451
|
function codebuddyConfigDir(home, env) {
|
|
3207
3452
|
const override = env?.CODEBUDDY_CONFIG_DIR;
|
|
3208
3453
|
if (override && override.trim()) {
|
|
3209
|
-
return
|
|
3454
|
+
return path8.resolve(override);
|
|
3210
3455
|
}
|
|
3211
|
-
return
|
|
3456
|
+
return path8.join(home, ".codebuddy");
|
|
3212
3457
|
}
|
|
3213
3458
|
function createCodebuddyAdapter() {
|
|
3214
3459
|
return {
|
|
@@ -3220,50 +3465,50 @@ function createCodebuddyAdapter() {
|
|
|
3220
3465
|
return codebuddyConfigDir(home, env);
|
|
3221
3466
|
},
|
|
3222
3467
|
installedPath(home, env) {
|
|
3223
|
-
return
|
|
3468
|
+
return path8.join(codebuddyConfigDir(home, env), "settings.json");
|
|
3224
3469
|
},
|
|
3225
3470
|
async isInstalled(home, env) {
|
|
3226
3471
|
return isHooksJsonInstalled(
|
|
3227
|
-
|
|
3472
|
+
path8.join(codebuddyConfigDir(home, env), "settings.json"),
|
|
3228
3473
|
"vibetime hook --agent codebuddy"
|
|
3229
3474
|
);
|
|
3230
3475
|
},
|
|
3231
3476
|
installEntries(home, env) {
|
|
3232
3477
|
return [{
|
|
3233
3478
|
kind: "hooks-json",
|
|
3234
|
-
path:
|
|
3479
|
+
path: path8.join(codebuddyConfigDir(home, env), "settings.json"),
|
|
3235
3480
|
content: hookConfig3()
|
|
3236
3481
|
}];
|
|
3237
3482
|
},
|
|
3238
3483
|
sourcePaths(home, env) {
|
|
3239
3484
|
const base = codebuddyConfigDir(home, env);
|
|
3240
3485
|
return [
|
|
3241
|
-
|
|
3486
|
+
path8.join(base, "traces")
|
|
3242
3487
|
];
|
|
3243
3488
|
},
|
|
3244
3489
|
parseSessionFile: parseCodebuddyTraceFile
|
|
3245
3490
|
};
|
|
3246
3491
|
}
|
|
3247
3492
|
async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
3248
|
-
const base = sourceRoot ||
|
|
3493
|
+
const base = sourceRoot || path8.join(codebuddyConfigDir(home, env), "traces");
|
|
3249
3494
|
const files = [];
|
|
3250
3495
|
try {
|
|
3251
|
-
const pidDirs = await
|
|
3496
|
+
const pidDirs = await readdir4(base, { withFileTypes: true });
|
|
3252
3497
|
for (const pidDir of pidDirs) {
|
|
3253
3498
|
if (!pidDir.isDirectory()) {
|
|
3254
3499
|
continue;
|
|
3255
3500
|
}
|
|
3256
|
-
const traceDir =
|
|
3501
|
+
const traceDir = path8.join(base, pidDir.name);
|
|
3257
3502
|
try {
|
|
3258
|
-
const entries = await
|
|
3503
|
+
const entries = await readdir4(traceDir);
|
|
3259
3504
|
for (const entry of entries) {
|
|
3260
3505
|
if (!entry.endsWith(".json") || !entry.startsWith("trace_")) {
|
|
3261
3506
|
continue;
|
|
3262
3507
|
}
|
|
3263
|
-
const filePath =
|
|
3508
|
+
const filePath = path8.join(traceDir, entry);
|
|
3264
3509
|
try {
|
|
3265
|
-
const
|
|
3266
|
-
files.push({ path: filePath, modifiedAt:
|
|
3510
|
+
const stat11 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
|
|
3511
|
+
files.push({ path: filePath, modifiedAt: stat11.mtime.toISOString() });
|
|
3267
3512
|
} catch {
|
|
3268
3513
|
}
|
|
3269
3514
|
}
|
|
@@ -3276,8 +3521,8 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
3276
3521
|
}
|
|
3277
3522
|
|
|
3278
3523
|
// src/adapters/codex.ts
|
|
3279
|
-
import { readFile as
|
|
3280
|
-
import
|
|
3524
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
3525
|
+
import path9 from "node:path";
|
|
3281
3526
|
|
|
3282
3527
|
// src/lib/diff.ts
|
|
3283
3528
|
function diffStats(diff) {
|
|
@@ -3324,7 +3569,7 @@ function fileActivitiesFromPatchChanges(changes, ts, cwd, displayFilePath3) {
|
|
|
3324
3569
|
|
|
3325
3570
|
// src/adapters/codex.ts
|
|
3326
3571
|
async function parseCodexSessionFile(filePath, options) {
|
|
3327
|
-
const text = await
|
|
3572
|
+
const text = await readFile6(filePath, "utf8");
|
|
3328
3573
|
const lines = text.split("\n").filter(Boolean);
|
|
3329
3574
|
const sourcePathHash = `sha256:${createStableHash(filePath)}`;
|
|
3330
3575
|
const events = [];
|
|
@@ -3357,7 +3602,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3357
3602
|
sessionMetaLocked = true;
|
|
3358
3603
|
sessionId = stringField(payload, "id") || sessionId;
|
|
3359
3604
|
cwd = stringField(payload, "cwd") || cwd;
|
|
3360
|
-
project = cwd ?
|
|
3605
|
+
project = cwd ? path9.basename(cwd) : project;
|
|
3361
3606
|
model = stringField(payload, "model_provider") || model;
|
|
3362
3607
|
events.push(withBackfillRefs({
|
|
3363
3608
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -3378,7 +3623,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3378
3623
|
if (topType === "turn_context") {
|
|
3379
3624
|
currentTurnId = stringField(payload, "turn_id") || currentTurnId;
|
|
3380
3625
|
cwd = stringField(payload, "cwd") || cwd;
|
|
3381
|
-
project = cwd ?
|
|
3626
|
+
project = cwd ? path9.basename(cwd) : project;
|
|
3382
3627
|
model = stringField(payload, "model") || model;
|
|
3383
3628
|
const tier = stringField(payload, "service_tier");
|
|
3384
3629
|
if (tier) {
|
|
@@ -3820,11 +4065,11 @@ function functionCallArguments(payload) {
|
|
|
3820
4065
|
}
|
|
3821
4066
|
}
|
|
3822
4067
|
function displayFilePath2(filePath, cwd) {
|
|
3823
|
-
if (!cwd || !
|
|
4068
|
+
if (!cwd || !path9.isAbsolute(filePath)) {
|
|
3824
4069
|
return filePath;
|
|
3825
4070
|
}
|
|
3826
|
-
const relative =
|
|
3827
|
-
return relative && !relative.startsWith("..") && !
|
|
4071
|
+
const relative = path9.relative(cwd, filePath);
|
|
4072
|
+
return relative && !relative.startsWith("..") && !path9.isAbsolute(relative) ? relative : filePath;
|
|
3828
4073
|
}
|
|
3829
4074
|
var codexHandler = (msg) => hookHandler("codex", msg);
|
|
3830
4075
|
function hookConfig4() {
|
|
@@ -3843,9 +4088,9 @@ function hookConfig4() {
|
|
|
3843
4088
|
function codexHome(home, env) {
|
|
3844
4089
|
const override = env?.CODEX_HOME;
|
|
3845
4090
|
if (override && override.trim()) {
|
|
3846
|
-
return
|
|
4091
|
+
return path9.resolve(override);
|
|
3847
4092
|
}
|
|
3848
|
-
return
|
|
4093
|
+
return path9.join(home, ".codex");
|
|
3849
4094
|
}
|
|
3850
4095
|
function createCodexAdapter() {
|
|
3851
4096
|
return {
|
|
@@ -3857,26 +4102,26 @@ function createCodexAdapter() {
|
|
|
3857
4102
|
return codexHome(home, env);
|
|
3858
4103
|
},
|
|
3859
4104
|
installedPath(home, env) {
|
|
3860
|
-
return
|
|
4105
|
+
return path9.join(codexHome(home, env), "hooks.json");
|
|
3861
4106
|
},
|
|
3862
4107
|
async isInstalled(home, env) {
|
|
3863
4108
|
return isHooksJsonInstalled(
|
|
3864
|
-
|
|
4109
|
+
path9.join(codexHome(home, env), "hooks.json"),
|
|
3865
4110
|
"vibetime hook --agent codex"
|
|
3866
4111
|
);
|
|
3867
4112
|
},
|
|
3868
4113
|
installEntries(home, env) {
|
|
3869
4114
|
return [{
|
|
3870
4115
|
kind: "hooks-json",
|
|
3871
|
-
path:
|
|
4116
|
+
path: path9.join(codexHome(home, env), "hooks.json"),
|
|
3872
4117
|
content: hookConfig4()
|
|
3873
4118
|
}];
|
|
3874
4119
|
},
|
|
3875
4120
|
sourcePaths(home, env) {
|
|
3876
4121
|
const base = codexHome(home, env);
|
|
3877
4122
|
return [
|
|
3878
|
-
|
|
3879
|
-
|
|
4123
|
+
path9.join(base, "sessions"),
|
|
4124
|
+
path9.join(base, "history.jsonl")
|
|
3880
4125
|
];
|
|
3881
4126
|
},
|
|
3882
4127
|
parseSessionFile: parseCodexSessionFile
|
|
@@ -3884,8 +4129,8 @@ function createCodexAdapter() {
|
|
|
3884
4129
|
}
|
|
3885
4130
|
|
|
3886
4131
|
// src/adapters/opencode.ts
|
|
3887
|
-
import
|
|
3888
|
-
import
|
|
4132
|
+
import os4 from "node:os";
|
|
4133
|
+
import path10 from "node:path";
|
|
3889
4134
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
3890
4135
|
const { DatabaseSync } = await import("node:sqlite");
|
|
3891
4136
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -3916,7 +4161,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
3916
4161
|
for (const session of sessions) {
|
|
3917
4162
|
const sessionId = session.id;
|
|
3918
4163
|
const cwd = session.directory || session.path || void 0;
|
|
3919
|
-
const project = cwd ?
|
|
4164
|
+
const project = cwd ? path10.basename(cwd) : void 0;
|
|
3920
4165
|
const sessionTs = msToIso(session.time_created);
|
|
3921
4166
|
events.push(baseOpenCodeEvent({
|
|
3922
4167
|
ts: sessionTs,
|
|
@@ -4010,7 +4255,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4010
4255
|
const provider = currentProvider;
|
|
4011
4256
|
const pathObj = objectField(info, "path");
|
|
4012
4257
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
4013
|
-
const assistantProject = assistantCwd ?
|
|
4258
|
+
const assistantProject = assistantCwd ? path10.basename(assistantCwd) : project;
|
|
4014
4259
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
4015
4260
|
const createdTs = timeCreated;
|
|
4016
4261
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -4254,33 +4499,33 @@ function opencodeUsageFromInfo(info) {
|
|
|
4254
4499
|
function opencodeConfigDir(home, env) {
|
|
4255
4500
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
4256
4501
|
if (override && override.trim()) {
|
|
4257
|
-
return
|
|
4502
|
+
return path10.resolve(override);
|
|
4258
4503
|
}
|
|
4259
4504
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
4260
4505
|
if (xdgConfig && xdgConfig.trim()) {
|
|
4261
|
-
return
|
|
4506
|
+
return path10.join(path10.resolve(xdgConfig), "opencode");
|
|
4262
4507
|
}
|
|
4263
|
-
return
|
|
4508
|
+
return path10.join(home, ".config", "opencode");
|
|
4264
4509
|
}
|
|
4265
4510
|
function opencodeDataCandidates(home, env) {
|
|
4266
4511
|
const xdgData = env?.XDG_DATA_HOME;
|
|
4267
|
-
const primary = xdgData && xdgData.trim() ?
|
|
4268
|
-
return [primary,
|
|
4512
|
+
const primary = xdgData && xdgData.trim() ? path10.join(path10.resolve(xdgData), "opencode", "opencode.db") : path10.join(home, ".local", "share", "opencode", "opencode.db");
|
|
4513
|
+
return [primary, path10.join(home, ".opencode", "opencode.db")];
|
|
4269
4514
|
}
|
|
4270
|
-
async function opencodeBackfillFiles(sourceRoot, home =
|
|
4271
|
-
const { stat:
|
|
4515
|
+
async function opencodeBackfillFiles(sourceRoot, home = os4.homedir(), env) {
|
|
4516
|
+
const { stat: stat11 } = await import("node:fs/promises");
|
|
4272
4517
|
if (sourceRoot) {
|
|
4273
4518
|
if (!sourceRoot.endsWith(".db")) {
|
|
4274
4519
|
return [];
|
|
4275
4520
|
}
|
|
4276
|
-
const info = await
|
|
4521
|
+
const info = await stat11(sourceRoot).catch(() => null);
|
|
4277
4522
|
if (!info) {
|
|
4278
4523
|
return [];
|
|
4279
4524
|
}
|
|
4280
4525
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
4281
4526
|
}
|
|
4282
4527
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
4283
|
-
const info = await
|
|
4528
|
+
const info = await stat11(candidatePath).catch(() => null);
|
|
4284
4529
|
if (info) {
|
|
4285
4530
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
4286
4531
|
}
|
|
@@ -4345,12 +4590,12 @@ function createOpenCodeAdapter() {
|
|
|
4345
4590
|
return opencodeConfigDir(home, env);
|
|
4346
4591
|
},
|
|
4347
4592
|
installedPath(home, env) {
|
|
4348
|
-
return
|
|
4593
|
+
return path10.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
4349
4594
|
},
|
|
4350
4595
|
async isInstalled(home, env) {
|
|
4351
4596
|
try {
|
|
4352
4597
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4353
|
-
return await pathExists2(
|
|
4598
|
+
return await pathExists2(path10.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path10.join(".opencode", PLUGIN_PATH));
|
|
4354
4599
|
} catch {
|
|
4355
4600
|
return false;
|
|
4356
4601
|
}
|
|
@@ -4358,7 +4603,7 @@ function createOpenCodeAdapter() {
|
|
|
4358
4603
|
installEntries(home, env) {
|
|
4359
4604
|
return [{
|
|
4360
4605
|
kind: "file",
|
|
4361
|
-
path:
|
|
4606
|
+
path: path10.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
4362
4607
|
content: opencodePluginContent()
|
|
4363
4608
|
}];
|
|
4364
4609
|
},
|
|
@@ -4370,10 +4615,10 @@ function createOpenCodeAdapter() {
|
|
|
4370
4615
|
}
|
|
4371
4616
|
|
|
4372
4617
|
// src/adapters/pi.ts
|
|
4373
|
-
import { readFile as
|
|
4374
|
-
import
|
|
4618
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
4619
|
+
import path11 from "node:path";
|
|
4375
4620
|
async function parsePiSessionFile(filePath, options) {
|
|
4376
|
-
const text = await
|
|
4621
|
+
const text = await readFile7(filePath, "utf8");
|
|
4377
4622
|
const lines = text.split("\n").filter(Boolean);
|
|
4378
4623
|
let sessionId;
|
|
4379
4624
|
let cwd;
|
|
@@ -4403,7 +4648,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
4403
4648
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
4404
4649
|
state.sessionId = sessionId || state.sessionId;
|
|
4405
4650
|
cwd = stringField(raw, "cwd") || cwd;
|
|
4406
|
-
project = cwd ?
|
|
4651
|
+
project = cwd ? path11.basename(cwd) : project;
|
|
4407
4652
|
continue;
|
|
4408
4653
|
}
|
|
4409
4654
|
if (entryType === "model_change") {
|
|
@@ -4804,16 +5049,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
4804
5049
|
function piAgentDir(home, env) {
|
|
4805
5050
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
4806
5051
|
if (override && override.trim()) {
|
|
4807
|
-
return
|
|
5052
|
+
return path11.resolve(override);
|
|
4808
5053
|
}
|
|
4809
|
-
return
|
|
5054
|
+
return path11.join(home, ".pi", "agent");
|
|
4810
5055
|
}
|
|
4811
5056
|
function piSessionDir(home, env) {
|
|
4812
5057
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
4813
5058
|
if (override && override.trim()) {
|
|
4814
|
-
return
|
|
5059
|
+
return path11.resolve(override);
|
|
4815
5060
|
}
|
|
4816
|
-
return
|
|
5061
|
+
return path11.join(piAgentDir(home, env), "sessions");
|
|
4817
5062
|
}
|
|
4818
5063
|
function createPiAdapter() {
|
|
4819
5064
|
return {
|
|
@@ -4825,12 +5070,12 @@ function createPiAdapter() {
|
|
|
4825
5070
|
return piAgentDir(home, env);
|
|
4826
5071
|
},
|
|
4827
5072
|
installedPath(home, env) {
|
|
4828
|
-
return
|
|
5073
|
+
return path11.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
4829
5074
|
},
|
|
4830
5075
|
async isInstalled(home, env) {
|
|
4831
5076
|
try {
|
|
4832
5077
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4833
|
-
return await pathExists2(
|
|
5078
|
+
return await pathExists2(path11.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
4834
5079
|
} catch {
|
|
4835
5080
|
return false;
|
|
4836
5081
|
}
|
|
@@ -4838,7 +5083,7 @@ function createPiAdapter() {
|
|
|
4838
5083
|
installEntries(home, env) {
|
|
4839
5084
|
return [{
|
|
4840
5085
|
kind: "file",
|
|
4841
|
-
path:
|
|
5086
|
+
path: path11.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
4842
5087
|
content: piExtensionContent()
|
|
4843
5088
|
}];
|
|
4844
5089
|
},
|
|
@@ -4850,11 +5095,11 @@ function createPiAdapter() {
|
|
|
4850
5095
|
}
|
|
4851
5096
|
|
|
4852
5097
|
// src/adapters/qoder-cn.ts
|
|
4853
|
-
import { readdir as
|
|
4854
|
-
import
|
|
4855
|
-
import
|
|
5098
|
+
import { readdir as readdir5, readFile as readFile8, stat as stat5 } from "node:fs/promises";
|
|
5099
|
+
import os5 from "node:os";
|
|
5100
|
+
import path12 from "node:path";
|
|
4856
5101
|
function parseQoderCnPaths(filePath) {
|
|
4857
|
-
const parts = filePath.split(
|
|
5102
|
+
const parts = filePath.split(path12.sep);
|
|
4858
5103
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
4859
5104
|
let sessionId = "";
|
|
4860
5105
|
let projectName = "";
|
|
@@ -4863,20 +5108,20 @@ function parseQoderCnPaths(filePath) {
|
|
|
4863
5108
|
sessionId = parts[subagentsIdx - 1];
|
|
4864
5109
|
projectName = parts[subagentsIdx - 2];
|
|
4865
5110
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
4866
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5111
|
+
configDir2 = parts.slice(0, projectsIdx).join(path12.sep);
|
|
4867
5112
|
} else {
|
|
4868
5113
|
const filename = parts.at(-1) || "";
|
|
4869
|
-
sessionId =
|
|
5114
|
+
sessionId = path12.basename(filename, ".jsonl");
|
|
4870
5115
|
projectName = parts.at(-2) || "";
|
|
4871
5116
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
4872
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5117
|
+
configDir2 = parts.slice(0, projectsIdx).join(path12.sep);
|
|
4873
5118
|
}
|
|
4874
5119
|
return { configDir: configDir2, projectName, sessionId };
|
|
4875
5120
|
}
|
|
4876
5121
|
async function loadQoderCnModelNames(configDir2) {
|
|
4877
5122
|
try {
|
|
4878
|
-
const dynamicTextsPath =
|
|
4879
|
-
const content = await
|
|
5123
|
+
const dynamicTextsPath = path12.join(configDir2, ".auth", "dynamic-texts.json");
|
|
5124
|
+
const content = await readFile8(dynamicTextsPath, "utf8");
|
|
4880
5125
|
const json = JSON.parse(content);
|
|
4881
5126
|
const texts = json.texts || {};
|
|
4882
5127
|
const map = {};
|
|
@@ -4893,15 +5138,15 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
4893
5138
|
}
|
|
4894
5139
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
4895
5140
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
4896
|
-
const segmentsPath =
|
|
5141
|
+
const segmentsPath = path12.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
4897
5142
|
const modelCalls = [];
|
|
4898
5143
|
try {
|
|
4899
|
-
const files = await
|
|
5144
|
+
const files = await readdir5(segmentsPath);
|
|
4900
5145
|
for (const file of files) {
|
|
4901
5146
|
if (!file.endsWith(".jsonl")) {
|
|
4902
5147
|
continue;
|
|
4903
5148
|
}
|
|
4904
|
-
const content = await
|
|
5149
|
+
const content = await readFile8(path12.join(segmentsPath, file), "utf8");
|
|
4905
5150
|
let currentTurnIsSubagent = false;
|
|
4906
5151
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
4907
5152
|
const raw = parseJsonLine(line);
|
|
@@ -4934,7 +5179,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
4934
5179
|
return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
|
|
4935
5180
|
}
|
|
4936
5181
|
async function parseQoderCnSessionFile(filePath, options) {
|
|
4937
|
-
const text = await
|
|
5182
|
+
const text = await readFile8(filePath, "utf8");
|
|
4938
5183
|
const lines = text.split("\n").filter(Boolean);
|
|
4939
5184
|
const { configDir: configDir2 } = parseQoderCnPaths(filePath);
|
|
4940
5185
|
const projectContext = await qoderCnProjectContextFromLines(filePath, lines, options, configDir2);
|
|
@@ -4969,7 +5214,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
4969
5214
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
4970
5215
|
state.sessionId = sessionId;
|
|
4971
5216
|
cwd = stringField(raw, "cwd") || cwd;
|
|
4972
|
-
project = projectContext.project || (cwd ?
|
|
5217
|
+
project = projectContext.project || (cwd ? path12.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
4973
5218
|
if (!ts) {
|
|
4974
5219
|
continue;
|
|
4975
5220
|
}
|
|
@@ -5398,24 +5643,24 @@ function isNoisePrompt(text) {
|
|
|
5398
5643
|
}
|
|
5399
5644
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
5400
5645
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
5401
|
-
const isSubagent = filePath.includes(`${
|
|
5646
|
+
const isSubagent = filePath.includes(`${path12.sep}subagents${path12.sep}`);
|
|
5402
5647
|
let cwds = [];
|
|
5403
5648
|
for (const line of lines) {
|
|
5404
5649
|
const raw = parseJsonLine(line);
|
|
5405
5650
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
5406
|
-
if (cwd &&
|
|
5651
|
+
if (cwd && path12.isAbsolute(cwd)) {
|
|
5407
5652
|
cwds.push(cwd);
|
|
5408
5653
|
}
|
|
5409
5654
|
}
|
|
5410
5655
|
if (isSubagent) {
|
|
5411
|
-
const parentSessionPath =
|
|
5656
|
+
const parentSessionPath = path12.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
5412
5657
|
try {
|
|
5413
|
-
const parentText = await
|
|
5658
|
+
const parentText = await readFile8(parentSessionPath, "utf8");
|
|
5414
5659
|
const parentCwds = [];
|
|
5415
5660
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
5416
5661
|
const raw = parseJsonLine(line);
|
|
5417
5662
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
5418
|
-
if (cwd &&
|
|
5663
|
+
if (cwd && path12.isAbsolute(cwd)) {
|
|
5419
5664
|
parentCwds.push(cwd);
|
|
5420
5665
|
}
|
|
5421
5666
|
}
|
|
@@ -5426,7 +5671,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
5426
5671
|
}
|
|
5427
5672
|
}
|
|
5428
5673
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
5429
|
-
const project = cwds.length > 0 ?
|
|
5674
|
+
const project = cwds.length > 0 ? path12.basename(cwds[0]) : root ? path12.basename(root) : await qoderCnProjectFromFilePath(filePath, options);
|
|
5430
5675
|
return {
|
|
5431
5676
|
project,
|
|
5432
5677
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -5435,15 +5680,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
5435
5680
|
async function gitRootFromCwds2(cwds) {
|
|
5436
5681
|
const seen = /* @__PURE__ */ new Set();
|
|
5437
5682
|
for (const cwd of cwds) {
|
|
5438
|
-
let current =
|
|
5683
|
+
let current = path12.resolve(cwd);
|
|
5439
5684
|
while (!seen.has(current)) {
|
|
5440
5685
|
seen.add(current);
|
|
5441
5686
|
try {
|
|
5442
|
-
await
|
|
5687
|
+
await stat5(path12.join(current, ".git"));
|
|
5443
5688
|
return current;
|
|
5444
5689
|
} catch {
|
|
5445
5690
|
}
|
|
5446
|
-
const parent =
|
|
5691
|
+
const parent = path12.dirname(current);
|
|
5447
5692
|
if (parent === current) {
|
|
5448
5693
|
break;
|
|
5449
5694
|
}
|
|
@@ -5454,12 +5699,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
5454
5699
|
}
|
|
5455
5700
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
5456
5701
|
for (const cwd of cwds) {
|
|
5457
|
-
let current =
|
|
5702
|
+
let current = path12.resolve(cwd);
|
|
5458
5703
|
while (true) {
|
|
5459
5704
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
5460
5705
|
return current;
|
|
5461
5706
|
}
|
|
5462
|
-
const parent =
|
|
5707
|
+
const parent = path12.dirname(current);
|
|
5463
5708
|
if (parent === current) {
|
|
5464
5709
|
break;
|
|
5465
5710
|
}
|
|
@@ -5469,14 +5714,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
5469
5714
|
return void 0;
|
|
5470
5715
|
}
|
|
5471
5716
|
function encodeQoderCnProjectPath(value) {
|
|
5472
|
-
return
|
|
5717
|
+
return path12.resolve(value).split(path12.sep).join("-").replace(/_/g, "-");
|
|
5473
5718
|
}
|
|
5474
5719
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
5475
|
-
const projectDir =
|
|
5476
|
-
const home = options ?
|
|
5720
|
+
const projectDir = path12.basename(path12.dirname(filePath));
|
|
5721
|
+
const home = options ? path12.resolve(stringOption(options.home) || os5.homedir()) : os5.homedir();
|
|
5477
5722
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
5478
5723
|
if (resolved) {
|
|
5479
|
-
return
|
|
5724
|
+
return path12.basename(resolved);
|
|
5480
5725
|
}
|
|
5481
5726
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
5482
5727
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -5496,12 +5741,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
5496
5741
|
while (projectDir.startsWith(`${currentEncoded}-`)) {
|
|
5497
5742
|
let matchedChild;
|
|
5498
5743
|
try {
|
|
5499
|
-
const entries = await
|
|
5744
|
+
const entries = await readdir5(current, { withFileTypes: true });
|
|
5500
5745
|
for (const entry of entries) {
|
|
5501
5746
|
if (!entry.isDirectory()) {
|
|
5502
5747
|
continue;
|
|
5503
5748
|
}
|
|
5504
|
-
const candidate =
|
|
5749
|
+
const candidate = path12.join(current, entry.name);
|
|
5505
5750
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
5506
5751
|
if (encoded === projectDir) {
|
|
5507
5752
|
return candidate;
|
|
@@ -5546,9 +5791,9 @@ function hookConfig5() {
|
|
|
5546
5791
|
function qoderCnConfigDir(home, env) {
|
|
5547
5792
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
5548
5793
|
if (override && override.trim()) {
|
|
5549
|
-
return
|
|
5794
|
+
return path12.resolve(override);
|
|
5550
5795
|
}
|
|
5551
|
-
return
|
|
5796
|
+
return path12.join(home, ".qoder-cn");
|
|
5552
5797
|
}
|
|
5553
5798
|
function createQoderCnAdapter() {
|
|
5554
5799
|
return {
|
|
@@ -5560,27 +5805,27 @@ function createQoderCnAdapter() {
|
|
|
5560
5805
|
return qoderCnConfigDir(home, env);
|
|
5561
5806
|
},
|
|
5562
5807
|
installedPath(home, env) {
|
|
5563
|
-
return
|
|
5808
|
+
return path12.join(qoderCnConfigDir(home, env), "settings.json");
|
|
5564
5809
|
},
|
|
5565
5810
|
async isInstalled(home, env) {
|
|
5566
5811
|
return isHooksJsonInstalled(
|
|
5567
|
-
|
|
5812
|
+
path12.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
5568
5813
|
"vibetime hook --agent qoder-cn"
|
|
5569
5814
|
);
|
|
5570
5815
|
},
|
|
5571
5816
|
installEntries(home, env) {
|
|
5572
5817
|
return [{
|
|
5573
5818
|
kind: "hooks-json",
|
|
5574
|
-
path:
|
|
5819
|
+
path: path12.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
5575
5820
|
content: hookConfig5()
|
|
5576
5821
|
}];
|
|
5577
5822
|
},
|
|
5578
5823
|
sourcePaths(home, env) {
|
|
5579
5824
|
const base = qoderCnConfigDir(home, env);
|
|
5580
5825
|
return [
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5826
|
+
path12.join(base, "projects"),
|
|
5827
|
+
path12.join(base, ".qoder.json"),
|
|
5828
|
+
path12.join(home, ".qoder.json")
|
|
5584
5829
|
];
|
|
5585
5830
|
},
|
|
5586
5831
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -5588,11 +5833,11 @@ function createQoderCnAdapter() {
|
|
|
5588
5833
|
}
|
|
5589
5834
|
|
|
5590
5835
|
// src/adapters/qoder.ts
|
|
5591
|
-
import { readdir as
|
|
5592
|
-
import
|
|
5593
|
-
import
|
|
5836
|
+
import { readdir as readdir6, readFile as readFile9, stat as stat6 } from "node:fs/promises";
|
|
5837
|
+
import os6 from "node:os";
|
|
5838
|
+
import path13 from "node:path";
|
|
5594
5839
|
function parseQoderPaths(filePath) {
|
|
5595
|
-
const parts = filePath.split(
|
|
5840
|
+
const parts = filePath.split(path13.sep);
|
|
5596
5841
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
5597
5842
|
let sessionId = "";
|
|
5598
5843
|
let projectName = "";
|
|
@@ -5601,20 +5846,20 @@ function parseQoderPaths(filePath) {
|
|
|
5601
5846
|
sessionId = parts[subagentsIdx - 1];
|
|
5602
5847
|
projectName = parts[subagentsIdx - 2];
|
|
5603
5848
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5604
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5849
|
+
configDir2 = parts.slice(0, projectsIdx).join(path13.sep);
|
|
5605
5850
|
} else {
|
|
5606
5851
|
const filename = parts.at(-1) || "";
|
|
5607
|
-
sessionId =
|
|
5852
|
+
sessionId = path13.basename(filename, ".jsonl");
|
|
5608
5853
|
projectName = parts.at(-2) || "";
|
|
5609
5854
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5610
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5855
|
+
configDir2 = parts.slice(0, projectsIdx).join(path13.sep);
|
|
5611
5856
|
}
|
|
5612
5857
|
return { configDir: configDir2, projectName, sessionId };
|
|
5613
5858
|
}
|
|
5614
5859
|
async function loadQoderModelNames(configDir2) {
|
|
5615
5860
|
try {
|
|
5616
|
-
const dynamicTextsPath =
|
|
5617
|
-
const content = await
|
|
5861
|
+
const dynamicTextsPath = path13.join(configDir2, ".auth", "dynamic-texts.json");
|
|
5862
|
+
const content = await readFile9(dynamicTextsPath, "utf8");
|
|
5618
5863
|
const json = JSON.parse(content);
|
|
5619
5864
|
const texts = json.texts || {};
|
|
5620
5865
|
const map = {};
|
|
@@ -5631,15 +5876,15 @@ async function loadQoderModelNames(configDir2) {
|
|
|
5631
5876
|
}
|
|
5632
5877
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
5633
5878
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
5634
|
-
const segmentsPath =
|
|
5879
|
+
const segmentsPath = path13.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
5635
5880
|
const modelCalls = [];
|
|
5636
5881
|
try {
|
|
5637
|
-
const files = await
|
|
5882
|
+
const files = await readdir6(segmentsPath);
|
|
5638
5883
|
for (const file of files) {
|
|
5639
5884
|
if (!file.endsWith(".jsonl")) {
|
|
5640
5885
|
continue;
|
|
5641
5886
|
}
|
|
5642
|
-
const content = await
|
|
5887
|
+
const content = await readFile9(path13.join(segmentsPath, file), "utf8");
|
|
5643
5888
|
let currentTurnIsSubagent = false;
|
|
5644
5889
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
5645
5890
|
const raw = parseJsonLine(line);
|
|
@@ -5672,7 +5917,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
5672
5917
|
return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
|
|
5673
5918
|
}
|
|
5674
5919
|
async function parseQoderSessionFile(filePath, options) {
|
|
5675
|
-
const text = await
|
|
5920
|
+
const text = await readFile9(filePath, "utf8");
|
|
5676
5921
|
const lines = text.split("\n").filter(Boolean);
|
|
5677
5922
|
const { configDir: configDir2 } = parseQoderPaths(filePath);
|
|
5678
5923
|
const projectContext = await qoderProjectContextFromLines(filePath, lines, options, configDir2);
|
|
@@ -5707,7 +5952,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
5707
5952
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
5708
5953
|
state.sessionId = sessionId;
|
|
5709
5954
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5710
|
-
project = projectContext.project || (cwd ?
|
|
5955
|
+
project = projectContext.project || (cwd ? path13.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
5711
5956
|
if (!ts) {
|
|
5712
5957
|
continue;
|
|
5713
5958
|
}
|
|
@@ -6102,24 +6347,24 @@ function qoderExtractText(value) {
|
|
|
6102
6347
|
}
|
|
6103
6348
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6104
6349
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
6105
|
-
const isSubagent = filePath.includes(`${
|
|
6350
|
+
const isSubagent = filePath.includes(`${path13.sep}subagents${path13.sep}`);
|
|
6106
6351
|
let cwds = [];
|
|
6107
6352
|
for (const line of lines) {
|
|
6108
6353
|
const raw = parseJsonLine(line);
|
|
6109
6354
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6110
|
-
if (cwd &&
|
|
6355
|
+
if (cwd && path13.isAbsolute(cwd)) {
|
|
6111
6356
|
cwds.push(cwd);
|
|
6112
6357
|
}
|
|
6113
6358
|
}
|
|
6114
6359
|
if (isSubagent) {
|
|
6115
|
-
const parentSessionPath =
|
|
6360
|
+
const parentSessionPath = path13.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
6116
6361
|
try {
|
|
6117
|
-
const parentText = await
|
|
6362
|
+
const parentText = await readFile9(parentSessionPath, "utf8");
|
|
6118
6363
|
const parentCwds = [];
|
|
6119
6364
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
6120
6365
|
const raw = parseJsonLine(line);
|
|
6121
6366
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6122
|
-
if (cwd &&
|
|
6367
|
+
if (cwd && path13.isAbsolute(cwd)) {
|
|
6123
6368
|
parentCwds.push(cwd);
|
|
6124
6369
|
}
|
|
6125
6370
|
}
|
|
@@ -6130,7 +6375,7 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
6130
6375
|
}
|
|
6131
6376
|
}
|
|
6132
6377
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
6133
|
-
const project = cwds.length > 0 ?
|
|
6378
|
+
const project = cwds.length > 0 ? path13.basename(cwds[0]) : root ? path13.basename(root) : await qoderProjectFromFilePath(filePath, options);
|
|
6134
6379
|
return {
|
|
6135
6380
|
project,
|
|
6136
6381
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6139,15 +6384,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
6139
6384
|
async function gitRootFromCwds3(cwds) {
|
|
6140
6385
|
const seen = /* @__PURE__ */ new Set();
|
|
6141
6386
|
for (const cwd of cwds) {
|
|
6142
|
-
let current =
|
|
6387
|
+
let current = path13.resolve(cwd);
|
|
6143
6388
|
while (!seen.has(current)) {
|
|
6144
6389
|
seen.add(current);
|
|
6145
6390
|
try {
|
|
6146
|
-
await
|
|
6391
|
+
await stat6(path13.join(current, ".git"));
|
|
6147
6392
|
return current;
|
|
6148
6393
|
} catch {
|
|
6149
6394
|
}
|
|
6150
|
-
const parent =
|
|
6395
|
+
const parent = path13.dirname(current);
|
|
6151
6396
|
if (parent === current) {
|
|
6152
6397
|
break;
|
|
6153
6398
|
}
|
|
@@ -6158,12 +6403,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
6158
6403
|
}
|
|
6159
6404
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
6160
6405
|
for (const cwd of cwds) {
|
|
6161
|
-
let current =
|
|
6406
|
+
let current = path13.resolve(cwd);
|
|
6162
6407
|
while (true) {
|
|
6163
6408
|
if (encodeQoderProjectPath(current) === projectDir) {
|
|
6164
6409
|
return current;
|
|
6165
6410
|
}
|
|
6166
|
-
const parent =
|
|
6411
|
+
const parent = path13.dirname(current);
|
|
6167
6412
|
if (parent === current) {
|
|
6168
6413
|
break;
|
|
6169
6414
|
}
|
|
@@ -6173,10 +6418,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
6173
6418
|
return void 0;
|
|
6174
6419
|
}
|
|
6175
6420
|
function encodeQoderProjectPath(value) {
|
|
6176
|
-
return
|
|
6421
|
+
return path13.resolve(value).split(path13.sep).join("-").replace(/_/g, "-");
|
|
6177
6422
|
}
|
|
6178
6423
|
function rawQoderProjectPath(value) {
|
|
6179
|
-
return
|
|
6424
|
+
return path13.resolve(value).split(path13.sep).join("-");
|
|
6180
6425
|
}
|
|
6181
6426
|
function qoderEncodedVariants(value) {
|
|
6182
6427
|
const raw = rawQoderProjectPath(value);
|
|
@@ -6192,11 +6437,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
6192
6437
|
return void 0;
|
|
6193
6438
|
}
|
|
6194
6439
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
6195
|
-
const projectDir =
|
|
6196
|
-
const home = options ?
|
|
6440
|
+
const projectDir = path13.basename(path13.dirname(filePath));
|
|
6441
|
+
const home = options ? path13.resolve(stringOption(options.home) || os6.homedir()) : os6.homedir();
|
|
6197
6442
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
6198
6443
|
if (resolved) {
|
|
6199
|
-
return
|
|
6444
|
+
return path13.basename(resolved);
|
|
6200
6445
|
}
|
|
6201
6446
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
6202
6447
|
if (suffix) {
|
|
@@ -6217,12 +6462,12 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
6217
6462
|
while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
|
|
6218
6463
|
let matchedChild;
|
|
6219
6464
|
try {
|
|
6220
|
-
const entries = await
|
|
6465
|
+
const entries = await readdir6(current, { withFileTypes: true });
|
|
6221
6466
|
for (const entry of entries) {
|
|
6222
6467
|
if (!entry.isDirectory()) {
|
|
6223
6468
|
continue;
|
|
6224
6469
|
}
|
|
6225
|
-
const candidate =
|
|
6470
|
+
const candidate = path13.join(current, entry.name);
|
|
6226
6471
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
6227
6472
|
if (candidateVariants.includes(projectDir)) {
|
|
6228
6473
|
return candidate;
|
|
@@ -6267,9 +6512,9 @@ function hookConfig6() {
|
|
|
6267
6512
|
function qoderConfigDir(home, env) {
|
|
6268
6513
|
const override = env?.QODER_CONFIG_DIR;
|
|
6269
6514
|
if (override && override.trim()) {
|
|
6270
|
-
return
|
|
6515
|
+
return path13.resolve(override);
|
|
6271
6516
|
}
|
|
6272
|
-
return
|
|
6517
|
+
return path13.join(home, ".qoder");
|
|
6273
6518
|
}
|
|
6274
6519
|
function createQoderAdapter() {
|
|
6275
6520
|
return {
|
|
@@ -6281,27 +6526,27 @@ function createQoderAdapter() {
|
|
|
6281
6526
|
return qoderConfigDir(home, env);
|
|
6282
6527
|
},
|
|
6283
6528
|
installedPath(home, env) {
|
|
6284
|
-
return
|
|
6529
|
+
return path13.join(qoderConfigDir(home, env), "settings.json");
|
|
6285
6530
|
},
|
|
6286
6531
|
async isInstalled(home, env) {
|
|
6287
6532
|
return isHooksJsonInstalled(
|
|
6288
|
-
|
|
6533
|
+
path13.join(qoderConfigDir(home, env), "settings.json"),
|
|
6289
6534
|
"vibetime hook --agent qoder"
|
|
6290
6535
|
);
|
|
6291
6536
|
},
|
|
6292
6537
|
installEntries(home, env) {
|
|
6293
6538
|
return [{
|
|
6294
6539
|
kind: "hooks-json",
|
|
6295
|
-
path:
|
|
6540
|
+
path: path13.join(qoderConfigDir(home, env), "settings.json"),
|
|
6296
6541
|
content: hookConfig6()
|
|
6297
6542
|
}];
|
|
6298
6543
|
},
|
|
6299
6544
|
sourcePaths(home, env) {
|
|
6300
6545
|
const base = qoderConfigDir(home, env);
|
|
6301
6546
|
return [
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6547
|
+
path13.join(base, "projects"),
|
|
6548
|
+
path13.join(base, ".qoder.json"),
|
|
6549
|
+
path13.join(home, ".qoder.json")
|
|
6305
6550
|
];
|
|
6306
6551
|
},
|
|
6307
6552
|
parseSessionFile: parseQoderSessionFile
|
|
@@ -6335,6 +6580,758 @@ function normalizeId(id) {
|
|
|
6335
6580
|
return id;
|
|
6336
6581
|
}
|
|
6337
6582
|
|
|
6583
|
+
// src/adapters/workbuddy.ts
|
|
6584
|
+
import { readFile as readFile10, readdir as readdir7, stat as stat7 } from "node:fs/promises";
|
|
6585
|
+
import path14 from "node:path";
|
|
6586
|
+
init_fs();
|
|
6587
|
+
function workbuddyProjectsDir(home, env) {
|
|
6588
|
+
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
6589
|
+
if (override && override.trim()) {
|
|
6590
|
+
return path14.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
6591
|
+
}
|
|
6592
|
+
return path14.join(home, ".workbuddy", "projects");
|
|
6593
|
+
}
|
|
6594
|
+
function projectFromCwd(cwd, fallback) {
|
|
6595
|
+
if (!cwd) {
|
|
6596
|
+
return fallback;
|
|
6597
|
+
}
|
|
6598
|
+
return path14.basename(cwd) || fallback;
|
|
6599
|
+
}
|
|
6600
|
+
function sourceHash(filePath) {
|
|
6601
|
+
return `sha256:${createStableHash(filePath)}`;
|
|
6602
|
+
}
|
|
6603
|
+
function makeEvent(event, line, filePath, options) {
|
|
6604
|
+
const withRefs = withBackfillRefs(event, {
|
|
6605
|
+
filePath,
|
|
6606
|
+
sourcePathHash: sourceHash(filePath),
|
|
6607
|
+
lineNumber: line.lineNumber,
|
|
6608
|
+
topType: stringField(line.record, "type"),
|
|
6609
|
+
payloadType: stringField(line.record, "role") || stringField(line.record, "name"),
|
|
6610
|
+
options
|
|
6611
|
+
});
|
|
6612
|
+
return validateCanonicalEvent(withRefs).valid ? withRefs : void 0;
|
|
6613
|
+
}
|
|
6614
|
+
function workbuddyUsageMetrics(record) {
|
|
6615
|
+
const providerData = objectField(record, "providerData");
|
|
6616
|
+
const usage = objectField(providerData, "usage");
|
|
6617
|
+
const rawUsage = objectField(providerData, "rawUsage");
|
|
6618
|
+
if (Object.keys(usage).length === 0 && Object.keys(rawUsage).length === 0) {
|
|
6619
|
+
return void 0;
|
|
6620
|
+
}
|
|
6621
|
+
const input = numberField(usage, "inputTokens") ?? numberField(rawUsage, "prompt_tokens") ?? 0;
|
|
6622
|
+
const output = numberField(usage, "outputTokens") ?? numberField(rawUsage, "completion_tokens") ?? 0;
|
|
6623
|
+
const total = numberField(usage, "totalTokens") ?? numberField(rawUsage, "total_tokens") ?? 0;
|
|
6624
|
+
const cacheRead = workbuddyCachedTokens(usage, rawUsage);
|
|
6625
|
+
const cacheCreate = numberField(rawUsage, "cache_creation_input_tokens") ?? numberField(rawUsage, "prompt_cache_write_tokens") ?? 0;
|
|
6626
|
+
const reasoning = workbuddyReasoningTokens(usage, rawUsage);
|
|
6627
|
+
if (!input && !output && !total && !cacheRead && !cacheCreate && !reasoning) {
|
|
6628
|
+
return void 0;
|
|
6629
|
+
}
|
|
6630
|
+
return {
|
|
6631
|
+
tokensInput: input,
|
|
6632
|
+
tokensOutput: output,
|
|
6633
|
+
tokensCachedInput: cacheRead + cacheCreate,
|
|
6634
|
+
tokensCacheCreationInput: cacheCreate,
|
|
6635
|
+
tokensCacheReadInput: cacheRead,
|
|
6636
|
+
tokensReasoningOutput: reasoning,
|
|
6637
|
+
tokensTotal: total || input + output,
|
|
6638
|
+
modelCalls: 1
|
|
6639
|
+
};
|
|
6640
|
+
}
|
|
6641
|
+
function workbuddyCachedTokens(usage, rawUsage) {
|
|
6642
|
+
const rawCache = numberField(rawUsage, "cache_read_input_tokens") ?? numberField(rawUsage, "prompt_cache_hit_tokens") ?? numberField(rawUsage, "cached_tokens");
|
|
6643
|
+
if (rawCache !== void 0) {
|
|
6644
|
+
return rawCache;
|
|
6645
|
+
}
|
|
6646
|
+
const details = usage.inputTokensDetails;
|
|
6647
|
+
if (Array.isArray(details) && isPlainObject(details[0])) {
|
|
6648
|
+
return numberField(details[0], "cached_tokens") || 0;
|
|
6649
|
+
}
|
|
6650
|
+
const rawDetails = objectField(rawUsage, "prompt_tokens_details");
|
|
6651
|
+
return numberField(rawDetails, "cached_tokens") || 0;
|
|
6652
|
+
}
|
|
6653
|
+
function workbuddyReasoningTokens(usage, rawUsage) {
|
|
6654
|
+
const completionDetails = objectField(rawUsage, "completion_tokens_details");
|
|
6655
|
+
const raw = numberField(completionDetails, "reasoning_tokens") ?? numberField(rawUsage, "completion_thinking_tokens");
|
|
6656
|
+
if (raw !== void 0) {
|
|
6657
|
+
return raw;
|
|
6658
|
+
}
|
|
6659
|
+
const details = usage.outputTokensDetails;
|
|
6660
|
+
if (Array.isArray(details) && isPlainObject(details[0])) {
|
|
6661
|
+
return numberField(details[0], "reasoning_tokens") || 0;
|
|
6662
|
+
}
|
|
6663
|
+
return 0;
|
|
6664
|
+
}
|
|
6665
|
+
function contentLength(value) {
|
|
6666
|
+
if (typeof value === "string") {
|
|
6667
|
+
return value.length;
|
|
6668
|
+
}
|
|
6669
|
+
if (Array.isArray(value)) {
|
|
6670
|
+
return value.reduce((total, item) => {
|
|
6671
|
+
if (!isPlainObject(item)) {
|
|
6672
|
+
return total;
|
|
6673
|
+
}
|
|
6674
|
+
return total + (stringField(item, "text") || stringField(item, "input_text") || stringField(item, "output_text") || "").length;
|
|
6675
|
+
}, 0);
|
|
6676
|
+
}
|
|
6677
|
+
return 0;
|
|
6678
|
+
}
|
|
6679
|
+
async function readWorkbuddyLines(filePath) {
|
|
6680
|
+
const text = await readFile10(filePath, "utf8");
|
|
6681
|
+
return text.split(/\r?\n/).map((line, index) => {
|
|
6682
|
+
if (!line.trim()) {
|
|
6683
|
+
return void 0;
|
|
6684
|
+
}
|
|
6685
|
+
try {
|
|
6686
|
+
const record = JSON.parse(line);
|
|
6687
|
+
return isPlainObject(record) ? { lineNumber: index + 1, record } : void 0;
|
|
6688
|
+
} catch {
|
|
6689
|
+
return void 0;
|
|
6690
|
+
}
|
|
6691
|
+
}).filter((line) => Boolean(line));
|
|
6692
|
+
}
|
|
6693
|
+
async function parseWorkbuddySessionFile(filePath, options) {
|
|
6694
|
+
const lines = await readWorkbuddyLines(filePath);
|
|
6695
|
+
if (lines.length === 0) {
|
|
6696
|
+
return [];
|
|
6697
|
+
}
|
|
6698
|
+
const events = [];
|
|
6699
|
+
const first = lines[0].record;
|
|
6700
|
+
const sessionId = stringField(first, "sessionId") || path14.basename(filePath, ".jsonl");
|
|
6701
|
+
const fallbackProject = path14.basename(path14.dirname(filePath));
|
|
6702
|
+
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
6703
|
+
const project = projectFromCwd(cwd, fallbackProject);
|
|
6704
|
+
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
6705
|
+
const sessionPrefix = `workbuddy:${sessionId}`;
|
|
6706
|
+
const toolStarts = /* @__PURE__ */ new Map();
|
|
6707
|
+
let currentTurnId = `${sessionPrefix}:turn:0`;
|
|
6708
|
+
let turnIndex = 0;
|
|
6709
|
+
const firstTs = lines.map((line) => timestampFrom(numberField(line.record, "timestamp"))).find(Boolean);
|
|
6710
|
+
if (firstTs) {
|
|
6711
|
+
const event = makeEvent({
|
|
6712
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6713
|
+
ts: firstTs,
|
|
6714
|
+
type: "session.started",
|
|
6715
|
+
source: "workbuddy",
|
|
6716
|
+
workspaceId,
|
|
6717
|
+
project,
|
|
6718
|
+
cwd,
|
|
6719
|
+
sessionId: sessionPrefix,
|
|
6720
|
+
agent: "workbuddy",
|
|
6721
|
+
confidence: "derived",
|
|
6722
|
+
refs: { sourceId: `${sessionPrefix}:session` }
|
|
6723
|
+
}, lines[0], filePath, options);
|
|
6724
|
+
if (event) events.push(event);
|
|
6725
|
+
}
|
|
6726
|
+
for (const line of lines) {
|
|
6727
|
+
const record = line.record;
|
|
6728
|
+
const ts = timestampFrom(numberField(record, "timestamp"));
|
|
6729
|
+
if (!ts) {
|
|
6730
|
+
continue;
|
|
6731
|
+
}
|
|
6732
|
+
const type = stringField(record, "type");
|
|
6733
|
+
const sourceId = stringField(record, "id") || `${line.lineNumber}`;
|
|
6734
|
+
if (type === "message" && stringField(record, "role") === "user") {
|
|
6735
|
+
turnIndex += 1;
|
|
6736
|
+
currentTurnId = `${sessionPrefix}:turn:${turnIndex}`;
|
|
6737
|
+
const promptChars = contentLength(record.content);
|
|
6738
|
+
for (const event of [
|
|
6739
|
+
makeEvent({
|
|
6740
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6741
|
+
ts,
|
|
6742
|
+
type: "turn.started",
|
|
6743
|
+
source: "workbuddy",
|
|
6744
|
+
workspaceId,
|
|
6745
|
+
project,
|
|
6746
|
+
cwd,
|
|
6747
|
+
sessionId: sessionPrefix,
|
|
6748
|
+
turnId: currentTurnId,
|
|
6749
|
+
agent: "workbuddy",
|
|
6750
|
+
confidence: "derived",
|
|
6751
|
+
refs: { sourceId: `${sourceId}:turn` }
|
|
6752
|
+
}, line, filePath, options),
|
|
6753
|
+
makeEvent({
|
|
6754
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6755
|
+
ts,
|
|
6756
|
+
type: "prompt.submitted",
|
|
6757
|
+
source: "workbuddy",
|
|
6758
|
+
workspaceId,
|
|
6759
|
+
project,
|
|
6760
|
+
cwd,
|
|
6761
|
+
sessionId: sessionPrefix,
|
|
6762
|
+
turnId: currentTurnId,
|
|
6763
|
+
agent: "workbuddy",
|
|
6764
|
+
metrics: { promptChars, prompts: 1 },
|
|
6765
|
+
confidence: "partial",
|
|
6766
|
+
refs: { sourceId: `${sourceId}:prompt` }
|
|
6767
|
+
}, line, filePath, options)
|
|
6768
|
+
]) {
|
|
6769
|
+
if (event) events.push(event);
|
|
6770
|
+
}
|
|
6771
|
+
continue;
|
|
6772
|
+
}
|
|
6773
|
+
if (type === "function_call") {
|
|
6774
|
+
const tool = stringField(record, "name");
|
|
6775
|
+
const callId = stringField(record, "callId");
|
|
6776
|
+
if (tool && callId) {
|
|
6777
|
+
toolStarts.set(`${sessionId}:${callId}`, { line, ts, tool, callId });
|
|
6778
|
+
const started = makeEvent({
|
|
6779
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6780
|
+
ts,
|
|
6781
|
+
type: "tool.started",
|
|
6782
|
+
source: "workbuddy",
|
|
6783
|
+
workspaceId,
|
|
6784
|
+
project,
|
|
6785
|
+
cwd,
|
|
6786
|
+
sessionId: sessionPrefix,
|
|
6787
|
+
turnId: currentTurnId,
|
|
6788
|
+
spanId: `${sessionPrefix}:tool:${callId}`,
|
|
6789
|
+
agent: "workbuddy",
|
|
6790
|
+
tool,
|
|
6791
|
+
confidence: "exact",
|
|
6792
|
+
refs: { sourceId: `${callId}:start` }
|
|
6793
|
+
}, line, filePath, options);
|
|
6794
|
+
if (started) events.push(started);
|
|
6795
|
+
}
|
|
6796
|
+
const metrics = workbuddyUsageMetrics(record);
|
|
6797
|
+
const model = stringField(objectField(record, "providerData"), "model");
|
|
6798
|
+
if (metrics || model) {
|
|
6799
|
+
const usage = makeEvent({
|
|
6800
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6801
|
+
ts,
|
|
6802
|
+
type: "model.usage",
|
|
6803
|
+
source: "workbuddy",
|
|
6804
|
+
workspaceId,
|
|
6805
|
+
project,
|
|
6806
|
+
cwd,
|
|
6807
|
+
sessionId: sessionPrefix,
|
|
6808
|
+
turnId: currentTurnId,
|
|
6809
|
+
agent: "workbuddy",
|
|
6810
|
+
model,
|
|
6811
|
+
metrics,
|
|
6812
|
+
confidence: metrics ? "partial" : "derived",
|
|
6813
|
+
refs: { sourceId: `${sourceId}:usage:${callId || line.lineNumber}` }
|
|
6814
|
+
}, line, filePath, options);
|
|
6815
|
+
if (usage) events.push(usage);
|
|
6816
|
+
}
|
|
6817
|
+
continue;
|
|
6818
|
+
}
|
|
6819
|
+
if (type === "function_call_result") {
|
|
6820
|
+
const tool = stringField(record, "name") || "tool";
|
|
6821
|
+
const callId = stringField(record, "callId") || `${line.lineNumber}`;
|
|
6822
|
+
const start = toolStarts.get(`${sessionId}:${callId}`);
|
|
6823
|
+
const durationMs = start?.ts ? Math.max(0, Date.parse(ts) - Date.parse(start.ts)) : void 0;
|
|
6824
|
+
const status = stringField(record, "status");
|
|
6825
|
+
const completed = makeEvent({
|
|
6826
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6827
|
+
ts,
|
|
6828
|
+
type: status === "failed" ? "tool.failed" : "tool.completed",
|
|
6829
|
+
source: "workbuddy",
|
|
6830
|
+
workspaceId,
|
|
6831
|
+
project,
|
|
6832
|
+
cwd,
|
|
6833
|
+
sessionId: sessionPrefix,
|
|
6834
|
+
turnId: currentTurnId,
|
|
6835
|
+
spanId: `${sessionPrefix}:tool:${callId}`,
|
|
6836
|
+
agent: "workbuddy",
|
|
6837
|
+
tool,
|
|
6838
|
+
success: status !== "failed",
|
|
6839
|
+
metrics: { toolDurationMs: durationMs, durationMs },
|
|
6840
|
+
confidence: start ? "derived" : "partial",
|
|
6841
|
+
refs: { sourceId: `${callId}:result` }
|
|
6842
|
+
}, line, filePath, options);
|
|
6843
|
+
if (completed) events.push(completed);
|
|
6844
|
+
}
|
|
6845
|
+
}
|
|
6846
|
+
const lastLine = lines.at(-1);
|
|
6847
|
+
const lastTs = lastLine ? timestampFrom(numberField(lastLine.record, "timestamp")) : void 0;
|
|
6848
|
+
if (lastLine && lastTs) {
|
|
6849
|
+
const event = makeEvent({
|
|
6850
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
6851
|
+
ts: lastTs,
|
|
6852
|
+
type: "session.ended",
|
|
6853
|
+
source: "workbuddy",
|
|
6854
|
+
workspaceId,
|
|
6855
|
+
project,
|
|
6856
|
+
cwd,
|
|
6857
|
+
sessionId: sessionPrefix,
|
|
6858
|
+
agent: "workbuddy",
|
|
6859
|
+
confidence: "derived",
|
|
6860
|
+
refs: { sourceId: `${sessionPrefix}:ended` }
|
|
6861
|
+
}, lastLine, filePath, options);
|
|
6862
|
+
if (event) events.push(event);
|
|
6863
|
+
}
|
|
6864
|
+
return events;
|
|
6865
|
+
}
|
|
6866
|
+
async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
6867
|
+
const base = sourceRoot || workbuddyProjectsDir(home, env);
|
|
6868
|
+
const files = [];
|
|
6869
|
+
try {
|
|
6870
|
+
const projects = await readdir7(base, { withFileTypes: true });
|
|
6871
|
+
for (const project of projects) {
|
|
6872
|
+
if (!project.isDirectory()) {
|
|
6873
|
+
continue;
|
|
6874
|
+
}
|
|
6875
|
+
const projectDir = path14.join(base, project.name);
|
|
6876
|
+
const entries = await readdir7(projectDir, { withFileTypes: true });
|
|
6877
|
+
for (const entry of entries) {
|
|
6878
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
6879
|
+
const filePath = path14.join(projectDir, entry.name);
|
|
6880
|
+
const info = await stat7(filePath);
|
|
6881
|
+
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
} catch {
|
|
6886
|
+
return [];
|
|
6887
|
+
}
|
|
6888
|
+
return files.sort((a, b) => a.path.localeCompare(b.path));
|
|
6889
|
+
}
|
|
6890
|
+
function createWorkbuddyAdapter() {
|
|
6891
|
+
return {
|
|
6892
|
+
id: "workbuddy",
|
|
6893
|
+
label: "WorkBuddy",
|
|
6894
|
+
agentName: "workbuddy",
|
|
6895
|
+
kind: "agent",
|
|
6896
|
+
detectPath(home, env) {
|
|
6897
|
+
return workbuddyProjectsDir(home, env);
|
|
6898
|
+
},
|
|
6899
|
+
installedPath(home, env) {
|
|
6900
|
+
return workbuddyProjectsDir(home, env);
|
|
6901
|
+
},
|
|
6902
|
+
async isInstalled(home, env) {
|
|
6903
|
+
return pathExists(workbuddyProjectsDir(home, env));
|
|
6904
|
+
},
|
|
6905
|
+
installEntries() {
|
|
6906
|
+
return [];
|
|
6907
|
+
},
|
|
6908
|
+
sourcePaths(home, env) {
|
|
6909
|
+
return [workbuddyProjectsDir(home, env)];
|
|
6910
|
+
},
|
|
6911
|
+
parseSessionFile: parseWorkbuddySessionFile
|
|
6912
|
+
};
|
|
6913
|
+
}
|
|
6914
|
+
|
|
6915
|
+
// src/adapters/zcode.ts
|
|
6916
|
+
import { execFile } from "node:child_process";
|
|
6917
|
+
import { stat as stat8 } from "node:fs/promises";
|
|
6918
|
+
import path15 from "node:path";
|
|
6919
|
+
import { promisify as promisify2 } from "node:util";
|
|
6920
|
+
init_fs();
|
|
6921
|
+
var execFileAsync = promisify2(execFile);
|
|
6922
|
+
function zcodeCliDir(home, env) {
|
|
6923
|
+
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
6924
|
+
if (override && override.trim()) {
|
|
6925
|
+
return path15.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
6926
|
+
}
|
|
6927
|
+
return path15.join(home, ".zcode", "cli");
|
|
6928
|
+
}
|
|
6929
|
+
function zcodeDbPath(home, env) {
|
|
6930
|
+
return path15.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
6931
|
+
}
|
|
6932
|
+
function sourceHash2(filePath) {
|
|
6933
|
+
return `sha256:${createStableHash(filePath)}`;
|
|
6934
|
+
}
|
|
6935
|
+
function projectFromDirectory(directory) {
|
|
6936
|
+
return directory ? path15.basename(directory) || "zcode" : "zcode";
|
|
6937
|
+
}
|
|
6938
|
+
function isoFromMs(value) {
|
|
6939
|
+
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
6940
|
+
}
|
|
6941
|
+
function makeEvent2(event, row, rowNumber, filePath, options) {
|
|
6942
|
+
const withRefs = withBackfillRefs(event, {
|
|
6943
|
+
filePath,
|
|
6944
|
+
sourcePathHash: sourceHash2(filePath),
|
|
6945
|
+
lineNumber: rowNumber,
|
|
6946
|
+
topType: row.kind,
|
|
6947
|
+
payloadType: stringField(row, "status") || stringField(row, "query_source") || stringField(row, "tool_name"),
|
|
6948
|
+
options
|
|
6949
|
+
});
|
|
6950
|
+
return validateCanonicalEvent(withRefs).valid ? withRefs : void 0;
|
|
6951
|
+
}
|
|
6952
|
+
function refs(values) {
|
|
6953
|
+
const out = {};
|
|
6954
|
+
for (const [key, value] of Object.entries(values)) {
|
|
6955
|
+
if (value !== void 0 && value !== "") {
|
|
6956
|
+
out[key] = String(value);
|
|
6957
|
+
}
|
|
6958
|
+
}
|
|
6959
|
+
return out;
|
|
6960
|
+
}
|
|
6961
|
+
async function sqliteJsonRows(dbPath, sql) {
|
|
6962
|
+
try {
|
|
6963
|
+
const { stdout } = await execFileAsync("sqlite3", ["-readonly", dbPath, sql], {
|
|
6964
|
+
maxBuffer: 32 * 1024 * 1024
|
|
6965
|
+
});
|
|
6966
|
+
return stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
6967
|
+
try {
|
|
6968
|
+
const parsed = JSON.parse(line);
|
|
6969
|
+
return isPlainObject(parsed) ? parsed : void 0;
|
|
6970
|
+
} catch {
|
|
6971
|
+
return void 0;
|
|
6972
|
+
}
|
|
6973
|
+
}).filter((row) => Boolean(row));
|
|
6974
|
+
} catch {
|
|
6975
|
+
return [];
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
async function readZCodeRows(dbPath) {
|
|
6979
|
+
const queries = [
|
|
6980
|
+
`select json_object(
|
|
6981
|
+
'kind','session',
|
|
6982
|
+
'id',id,
|
|
6983
|
+
'parent_id',parent_id,
|
|
6984
|
+
'directory',directory,
|
|
6985
|
+
'title',title,
|
|
6986
|
+
'task_type',task_type,
|
|
6987
|
+
'time_created',time_created,
|
|
6988
|
+
'time_updated',time_updated
|
|
6989
|
+
) from session order by time_created, id;`,
|
|
6990
|
+
`select json_object(
|
|
6991
|
+
'kind','turn',
|
|
6992
|
+
'session_id',session_id,
|
|
6993
|
+
'turn_id',turn_id,
|
|
6994
|
+
'status',status,
|
|
6995
|
+
'started_at',started_at,
|
|
6996
|
+
'completed_at',completed_at,
|
|
6997
|
+
'duration_ms',duration_ms,
|
|
6998
|
+
'model_request_count',model_request_count,
|
|
6999
|
+
'tool_call_count',tool_call_count,
|
|
7000
|
+
'input_tokens',input_tokens,
|
|
7001
|
+
'output_tokens',output_tokens,
|
|
7002
|
+
'reasoning_tokens',reasoning_tokens,
|
|
7003
|
+
'cache_creation_input_tokens',cache_creation_input_tokens,
|
|
7004
|
+
'cache_read_input_tokens',cache_read_input_tokens,
|
|
7005
|
+
'computed_total_tokens',computed_total_tokens
|
|
7006
|
+
) from turn_usage order by started_at, session_id, turn_id;`,
|
|
7007
|
+
`select json_object(
|
|
7008
|
+
'kind','model',
|
|
7009
|
+
'id',id,
|
|
7010
|
+
'session_id',session_id,
|
|
7011
|
+
'turn_id',turn_id,
|
|
7012
|
+
'query_source',query_source,
|
|
7013
|
+
'provider_id',provider_id,
|
|
7014
|
+
'model_id',model_id,
|
|
7015
|
+
'agent',agent,
|
|
7016
|
+
'mode',mode,
|
|
7017
|
+
'status',status,
|
|
7018
|
+
'started_at',started_at,
|
|
7019
|
+
'completed_at',completed_at,
|
|
7020
|
+
'duration_ms',duration_ms,
|
|
7021
|
+
'input_tokens',input_tokens,
|
|
7022
|
+
'output_tokens',output_tokens,
|
|
7023
|
+
'reasoning_tokens',reasoning_tokens,
|
|
7024
|
+
'cache_creation_input_tokens',cache_creation_input_tokens,
|
|
7025
|
+
'cache_read_input_tokens',cache_read_input_tokens,
|
|
7026
|
+
'computed_total_tokens',computed_total_tokens,
|
|
7027
|
+
'tool_call_count',tool_call_count
|
|
7028
|
+
) from model_usage order by started_at, id;`,
|
|
7029
|
+
`select json_object(
|
|
7030
|
+
'kind','tool',
|
|
7031
|
+
'id',id,
|
|
7032
|
+
'session_id',session_id,
|
|
7033
|
+
'turn_id',turn_id,
|
|
7034
|
+
'tool_call_id',tool_call_id,
|
|
7035
|
+
'tool_name',tool_name,
|
|
7036
|
+
'side_effect_scope',side_effect_scope,
|
|
7037
|
+
'read_only',read_only,
|
|
7038
|
+
'destructive',destructive,
|
|
7039
|
+
'approval_status',approval_status,
|
|
7040
|
+
'status',status,
|
|
7041
|
+
'started_at',started_at,
|
|
7042
|
+
'completed_at',completed_at,
|
|
7043
|
+
'duration_ms',duration_ms,
|
|
7044
|
+
'output_bytes',output_bytes,
|
|
7045
|
+
'exit_code',exit_code
|
|
7046
|
+
) from tool_usage order by started_at, id;`
|
|
7047
|
+
];
|
|
7048
|
+
const results = await Promise.all(queries.map((query) => sqliteJsonRows(dbPath, query)));
|
|
7049
|
+
return results.flat();
|
|
7050
|
+
}
|
|
7051
|
+
function modelMetrics(row) {
|
|
7052
|
+
const input = numberField(row, "input_tokens") || 0;
|
|
7053
|
+
const output = numberField(row, "output_tokens") || 0;
|
|
7054
|
+
const reasoning = numberField(row, "reasoning_tokens") || 0;
|
|
7055
|
+
const cacheCreation = numberField(row, "cache_creation_input_tokens") || 0;
|
|
7056
|
+
const cacheRead = numberField(row, "cache_read_input_tokens") || 0;
|
|
7057
|
+
const total = numberField(row, "computed_total_tokens") || input + output + reasoning;
|
|
7058
|
+
const durationMs = numberField(row, "duration_ms");
|
|
7059
|
+
return {
|
|
7060
|
+
tokensInput: input,
|
|
7061
|
+
tokensOutput: output,
|
|
7062
|
+
tokensReasoningOutput: reasoning,
|
|
7063
|
+
tokensCachedInput: cacheCreation + cacheRead,
|
|
7064
|
+
tokensCacheCreationInput: cacheCreation,
|
|
7065
|
+
tokensCacheReadInput: cacheRead,
|
|
7066
|
+
tokensTotal: total,
|
|
7067
|
+
modelDurationMs: durationMs,
|
|
7068
|
+
durationMs,
|
|
7069
|
+
modelCalls: 1,
|
|
7070
|
+
toolCalls: numberField(row, "tool_call_count")
|
|
7071
|
+
};
|
|
7072
|
+
}
|
|
7073
|
+
function sessionContext(row, sessions) {
|
|
7074
|
+
const sessionId = stringField(row, "session_id") || stringField(row, "id") || "unknown";
|
|
7075
|
+
const session = sessions.get(sessionId);
|
|
7076
|
+
const cwd = stringField(session, "directory");
|
|
7077
|
+
const project = projectFromDirectory(cwd);
|
|
7078
|
+
return {
|
|
7079
|
+
rawSessionId: sessionId,
|
|
7080
|
+
sessionId: `zcode:${sessionId}`,
|
|
7081
|
+
cwd,
|
|
7082
|
+
project,
|
|
7083
|
+
workspaceId: createWorkspaceId({ projectName: project, repoRoot: cwd }),
|
|
7084
|
+
parentSessionId: stringField(session, "parent_id") ? `zcode:${stringField(session, "parent_id")}` : void 0
|
|
7085
|
+
};
|
|
7086
|
+
}
|
|
7087
|
+
async function parseZCodeDb(filePath, options) {
|
|
7088
|
+
const rows = await readZCodeRows(filePath);
|
|
7089
|
+
if (rows.length === 0) {
|
|
7090
|
+
return [];
|
|
7091
|
+
}
|
|
7092
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
7093
|
+
for (const row of rows) {
|
|
7094
|
+
if (row.kind === "session") {
|
|
7095
|
+
const id = stringField(row, "id");
|
|
7096
|
+
if (id) {
|
|
7097
|
+
sessions.set(id, row);
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
7101
|
+
const events = [];
|
|
7102
|
+
rows.forEach((row, index) => {
|
|
7103
|
+
const rowNumber = index + 1;
|
|
7104
|
+
if (row.kind === "session") {
|
|
7105
|
+
const id = stringField(row, "id");
|
|
7106
|
+
const ts = isoFromMs(numberField(row, "time_created"));
|
|
7107
|
+
if (!id || !ts) {
|
|
7108
|
+
return;
|
|
7109
|
+
}
|
|
7110
|
+
const ctx = sessionContext(row, sessions);
|
|
7111
|
+
const event = makeEvent2({
|
|
7112
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
7113
|
+
ts,
|
|
7114
|
+
type: "session.started",
|
|
7115
|
+
source: "zcode",
|
|
7116
|
+
workspaceId: ctx.workspaceId,
|
|
7117
|
+
project: ctx.project,
|
|
7118
|
+
cwd: ctx.cwd,
|
|
7119
|
+
sessionId: ctx.sessionId,
|
|
7120
|
+
parentAgentInstanceId: ctx.parentSessionId,
|
|
7121
|
+
agent: "zcode",
|
|
7122
|
+
confidence: "exact",
|
|
7123
|
+
refs: refs({
|
|
7124
|
+
sourceId: `${id}:session`,
|
|
7125
|
+
zcodeTaskType: stringField(row, "task_type"),
|
|
7126
|
+
zcodeTitleHash: stringField(row, "title") ? `sha256:${createStableHash(stringField(row, "title"))}` : void 0
|
|
7127
|
+
})
|
|
7128
|
+
}, row, rowNumber, filePath, options);
|
|
7129
|
+
if (event) events.push(event);
|
|
7130
|
+
const completedTs = isoFromMs(numberField(row, "time_updated"));
|
|
7131
|
+
if (completedTs && completedTs !== ts) {
|
|
7132
|
+
const completed = makeEvent2({
|
|
7133
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
7134
|
+
ts: completedTs,
|
|
7135
|
+
type: "session.ended",
|
|
7136
|
+
source: "zcode",
|
|
7137
|
+
workspaceId: ctx.workspaceId,
|
|
7138
|
+
project: ctx.project,
|
|
7139
|
+
cwd: ctx.cwd,
|
|
7140
|
+
sessionId: ctx.sessionId,
|
|
7141
|
+
parentAgentInstanceId: ctx.parentSessionId,
|
|
7142
|
+
agent: "zcode",
|
|
7143
|
+
confidence: "exact",
|
|
7144
|
+
refs: { sourceId: `${id}:session:ended` }
|
|
7145
|
+
}, row, rowNumber, filePath, options);
|
|
7146
|
+
if (completed) events.push(completed);
|
|
7147
|
+
}
|
|
7148
|
+
return;
|
|
7149
|
+
}
|
|
7150
|
+
if (row.kind === "turn") {
|
|
7151
|
+
const rawTurnId = stringField(row, "turn_id");
|
|
7152
|
+
const ts = isoFromMs(numberField(row, "started_at"));
|
|
7153
|
+
if (!rawTurnId || !ts) {
|
|
7154
|
+
return;
|
|
7155
|
+
}
|
|
7156
|
+
const ctx = sessionContext(row, sessions);
|
|
7157
|
+
const turnId = `zcode:${rawTurnId}`;
|
|
7158
|
+
const started = makeEvent2({
|
|
7159
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
7160
|
+
ts,
|
|
7161
|
+
type: "turn.started",
|
|
7162
|
+
source: "zcode",
|
|
7163
|
+
workspaceId: ctx.workspaceId,
|
|
7164
|
+
project: ctx.project,
|
|
7165
|
+
cwd: ctx.cwd,
|
|
7166
|
+
sessionId: ctx.sessionId,
|
|
7167
|
+
turnId,
|
|
7168
|
+
agent: "zcode",
|
|
7169
|
+
confidence: "exact",
|
|
7170
|
+
refs: { sourceId: `${rawTurnId}:start` }
|
|
7171
|
+
}, row, rowNumber, filePath, options);
|
|
7172
|
+
if (started) events.push(started);
|
|
7173
|
+
const completedTs = isoFromMs(numberField(row, "completed_at"));
|
|
7174
|
+
if (completedTs) {
|
|
7175
|
+
const status = stringField(row, "status");
|
|
7176
|
+
const completed = makeEvent2({
|
|
7177
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
7178
|
+
ts: completedTs,
|
|
7179
|
+
type: "turn.completed",
|
|
7180
|
+
source: "zcode",
|
|
7181
|
+
workspaceId: ctx.workspaceId,
|
|
7182
|
+
project: ctx.project,
|
|
7183
|
+
cwd: ctx.cwd,
|
|
7184
|
+
sessionId: ctx.sessionId,
|
|
7185
|
+
turnId,
|
|
7186
|
+
agent: "zcode",
|
|
7187
|
+
success: status === "completed",
|
|
7188
|
+
metrics: {
|
|
7189
|
+
durationMs: numberField(row, "duration_ms"),
|
|
7190
|
+
turns: 1,
|
|
7191
|
+
modelCalls: numberField(row, "model_request_count"),
|
|
7192
|
+
toolCalls: numberField(row, "tool_call_count")
|
|
7193
|
+
},
|
|
7194
|
+
confidence: "exact",
|
|
7195
|
+
refs: refs({ sourceId: `${rawTurnId}:completed`, zcodeStatus: status })
|
|
7196
|
+
}, row, rowNumber, filePath, options);
|
|
7197
|
+
if (completed) events.push(completed);
|
|
7198
|
+
}
|
|
7199
|
+
return;
|
|
7200
|
+
}
|
|
7201
|
+
if (row.kind === "model") {
|
|
7202
|
+
const ts = isoFromMs(numberField(row, "completed_at")) || isoFromMs(numberField(row, "started_at"));
|
|
7203
|
+
if (!ts) {
|
|
7204
|
+
return;
|
|
7205
|
+
}
|
|
7206
|
+
const ctx = sessionContext(row, sessions);
|
|
7207
|
+
const modelId = stringField(row, "model_id");
|
|
7208
|
+
const usage = makeEvent2({
|
|
7209
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
7210
|
+
ts,
|
|
7211
|
+
type: "model.usage",
|
|
7212
|
+
source: "zcode",
|
|
7213
|
+
workspaceId: ctx.workspaceId,
|
|
7214
|
+
project: ctx.project,
|
|
7215
|
+
cwd: ctx.cwd,
|
|
7216
|
+
sessionId: ctx.sessionId,
|
|
7217
|
+
turnId: stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0,
|
|
7218
|
+
agent: stringField(row, "agent") || "zcode",
|
|
7219
|
+
provider: stringField(row, "provider_id"),
|
|
7220
|
+
model: modelId,
|
|
7221
|
+
success: stringField(row, "status") === "completed",
|
|
7222
|
+
metrics: modelMetrics(row),
|
|
7223
|
+
confidence: "exact",
|
|
7224
|
+
refs: refs({
|
|
7225
|
+
sourceId: stringField(row, "id") || `${ctx.rawSessionId}:model:${rowNumber}`,
|
|
7226
|
+
zcodeQuerySource: stringField(row, "query_source"),
|
|
7227
|
+
zcodeMode: stringField(row, "mode"),
|
|
7228
|
+
zcodeStatus: stringField(row, "status")
|
|
7229
|
+
})
|
|
7230
|
+
}, row, rowNumber, filePath, options);
|
|
7231
|
+
if (usage) events.push(usage);
|
|
7232
|
+
return;
|
|
7233
|
+
}
|
|
7234
|
+
if (row.kind === "tool") {
|
|
7235
|
+
const startedTs = isoFromMs(numberField(row, "started_at"));
|
|
7236
|
+
const completedTs = isoFromMs(numberField(row, "completed_at")) || startedTs;
|
|
7237
|
+
const tool = stringField(row, "tool_name") || "tool";
|
|
7238
|
+
const toolCallId = stringField(row, "tool_call_id") || stringField(row, "id") || `${rowNumber}`;
|
|
7239
|
+
if (!startedTs) {
|
|
7240
|
+
return;
|
|
7241
|
+
}
|
|
7242
|
+
const ctx = sessionContext(row, sessions);
|
|
7243
|
+
const turnId = stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0;
|
|
7244
|
+
const spanId = `${ctx.sessionId}:tool:${toolCallId}`;
|
|
7245
|
+
const started = makeEvent2({
|
|
7246
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
7247
|
+
ts: startedTs,
|
|
7248
|
+
type: "tool.started",
|
|
7249
|
+
source: "zcode",
|
|
7250
|
+
workspaceId: ctx.workspaceId,
|
|
7251
|
+
project: ctx.project,
|
|
7252
|
+
cwd: ctx.cwd,
|
|
7253
|
+
sessionId: ctx.sessionId,
|
|
7254
|
+
turnId,
|
|
7255
|
+
spanId,
|
|
7256
|
+
agent: "zcode",
|
|
7257
|
+
tool,
|
|
7258
|
+
confidence: "exact",
|
|
7259
|
+
refs: refs({
|
|
7260
|
+
sourceId: `${toolCallId}:start`,
|
|
7261
|
+
zcodeSideEffectScope: stringField(row, "side_effect_scope"),
|
|
7262
|
+
zcodeApprovalStatus: stringField(row, "approval_status")
|
|
7263
|
+
})
|
|
7264
|
+
}, row, rowNumber, filePath, options);
|
|
7265
|
+
if (started) events.push(started);
|
|
7266
|
+
if (completedTs) {
|
|
7267
|
+
const status = stringField(row, "status");
|
|
7268
|
+
const completed = makeEvent2({
|
|
7269
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
7270
|
+
ts: completedTs,
|
|
7271
|
+
type: status === "completed" ? "tool.completed" : "tool.failed",
|
|
7272
|
+
source: "zcode",
|
|
7273
|
+
workspaceId: ctx.workspaceId,
|
|
7274
|
+
project: ctx.project,
|
|
7275
|
+
cwd: ctx.cwd,
|
|
7276
|
+
sessionId: ctx.sessionId,
|
|
7277
|
+
turnId,
|
|
7278
|
+
spanId,
|
|
7279
|
+
agent: "zcode",
|
|
7280
|
+
tool,
|
|
7281
|
+
success: status === "completed",
|
|
7282
|
+
metrics: {
|
|
7283
|
+
toolDurationMs: numberField(row, "duration_ms"),
|
|
7284
|
+
durationMs: numberField(row, "duration_ms"),
|
|
7285
|
+
bytesRead: numberField(row, "output_bytes")
|
|
7286
|
+
},
|
|
7287
|
+
confidence: "exact",
|
|
7288
|
+
refs: refs({
|
|
7289
|
+
sourceId: `${toolCallId}:completed`,
|
|
7290
|
+
zcodeStatus: status,
|
|
7291
|
+
zcodeExitCode: numberField(row, "exit_code")
|
|
7292
|
+
})
|
|
7293
|
+
}, row, rowNumber, filePath, options);
|
|
7294
|
+
if (completed) events.push(completed);
|
|
7295
|
+
}
|
|
7296
|
+
}
|
|
7297
|
+
});
|
|
7298
|
+
return events.sort((a, b) => a.ts.localeCompare(b.ts) || (a.id || "").localeCompare(b.id || ""));
|
|
7299
|
+
}
|
|
7300
|
+
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
7301
|
+
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
7302
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path15.join(candidate, "db", "db.sqlite");
|
|
7303
|
+
try {
|
|
7304
|
+
const info = await stat8(filePath);
|
|
7305
|
+
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
7306
|
+
} catch {
|
|
7307
|
+
return [];
|
|
7308
|
+
}
|
|
7309
|
+
}
|
|
7310
|
+
function createZCodeAdapter() {
|
|
7311
|
+
return {
|
|
7312
|
+
id: "zcode",
|
|
7313
|
+
label: "ZCode",
|
|
7314
|
+
agentName: "zcode",
|
|
7315
|
+
kind: "agent",
|
|
7316
|
+
detectPath(home, env) {
|
|
7317
|
+
return zcodeCliDir(home, env);
|
|
7318
|
+
},
|
|
7319
|
+
installedPath(home, env) {
|
|
7320
|
+
return zcodeDbPath(home, env);
|
|
7321
|
+
},
|
|
7322
|
+
async isInstalled(home, env) {
|
|
7323
|
+
return pathExists(zcodeDbPath(home, env));
|
|
7324
|
+
},
|
|
7325
|
+
installEntries() {
|
|
7326
|
+
return [];
|
|
7327
|
+
},
|
|
7328
|
+
sourcePaths(home, env) {
|
|
7329
|
+
return [zcodeDbPath(home, env)];
|
|
7330
|
+
},
|
|
7331
|
+
parseSessionFile: parseZCodeDb
|
|
7332
|
+
};
|
|
7333
|
+
}
|
|
7334
|
+
|
|
6338
7335
|
// src/lib/pricing.ts
|
|
6339
7336
|
function estimateEventCostUsd(event) {
|
|
6340
7337
|
if (event.type !== "model.usage") {
|
|
@@ -6771,15 +7768,15 @@ function hookCommandFromGroup(group) {
|
|
|
6771
7768
|
import { randomUUID } from "node:crypto";
|
|
6772
7769
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6773
7770
|
import { homedir, hostname } from "node:os";
|
|
6774
|
-
import
|
|
7771
|
+
import path16 from "node:path";
|
|
6775
7772
|
function configDir(home = homedir()) {
|
|
6776
|
-
return
|
|
7773
|
+
return path16.join(home, ".vibetime");
|
|
6777
7774
|
}
|
|
6778
7775
|
function configPath(home = homedir()) {
|
|
6779
|
-
return
|
|
7776
|
+
return path16.join(configDir(home), "config.json");
|
|
6780
7777
|
}
|
|
6781
7778
|
function machineIdPath(home = homedir()) {
|
|
6782
|
-
return
|
|
7779
|
+
return path16.join(configDir(home), "machine-id");
|
|
6783
7780
|
}
|
|
6784
7781
|
function readConfig(home = homedir()) {
|
|
6785
7782
|
const file = configPath(home);
|
|
@@ -6826,15 +7823,15 @@ function defaultMachineName() {
|
|
|
6826
7823
|
init_fs();
|
|
6827
7824
|
|
|
6828
7825
|
// src/lib/logger.ts
|
|
6829
|
-
import { appendFile, mkdir as mkdir3, rename, stat as
|
|
7826
|
+
import { appendFile, mkdir as mkdir3, rename, stat as stat9 } from "node:fs/promises";
|
|
6830
7827
|
import { homedir as homedir2 } from "node:os";
|
|
6831
|
-
import
|
|
7828
|
+
import path17 from "node:path";
|
|
6832
7829
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
6833
7830
|
function logDir(home = homedir2()) {
|
|
6834
|
-
return
|
|
7831
|
+
return path17.join(home, ".vibetime", "logs");
|
|
6835
7832
|
}
|
|
6836
7833
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
6837
|
-
return
|
|
7834
|
+
return path17.join(logDir(home), name);
|
|
6838
7835
|
}
|
|
6839
7836
|
function serializeError(error) {
|
|
6840
7837
|
if (error instanceof Error) {
|
|
@@ -6844,7 +7841,7 @@ function serializeError(error) {
|
|
|
6844
7841
|
}
|
|
6845
7842
|
async function rotateIfNeeded(file) {
|
|
6846
7843
|
try {
|
|
6847
|
-
const info = await
|
|
7844
|
+
const info = await stat9(file);
|
|
6848
7845
|
if (info.size > MAX_BYTES) {
|
|
6849
7846
|
await rename(file, `${file}.1`).catch(() => {
|
|
6850
7847
|
});
|
|
@@ -7009,8 +8006,8 @@ function buildHeaders(token, machine) {
|
|
|
7009
8006
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
7010
8007
|
};
|
|
7011
8008
|
}
|
|
7012
|
-
function joinUrl(base,
|
|
7013
|
-
return new URL(
|
|
8009
|
+
function joinUrl(base, path19) {
|
|
8010
|
+
return new URL(path19, base.endsWith("/") ? base : `${base}/`).toString();
|
|
7014
8011
|
}
|
|
7015
8012
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
7016
8013
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -7082,12 +8079,15 @@ function createRegistry() {
|
|
|
7082
8079
|
const registry = new AdapterRegistry();
|
|
7083
8080
|
registry.register(createCodexAdapter());
|
|
7084
8081
|
registry.register(createClaudeCodeAdapter());
|
|
8082
|
+
registry.register(createClaudeCoworkAdapter());
|
|
7085
8083
|
registry.register(createPiAdapter());
|
|
7086
8084
|
registry.register(createOpenCodeAdapter());
|
|
7087
8085
|
registry.register(createAgyAdapter());
|
|
7088
8086
|
registry.register(createCodebuddyAdapter());
|
|
7089
8087
|
registry.register(createQoderAdapter());
|
|
7090
8088
|
registry.register(createQoderCnAdapter());
|
|
8089
|
+
registry.register(createWorkbuddyAdapter());
|
|
8090
|
+
registry.register(createZCodeAdapter());
|
|
7091
8091
|
return registry;
|
|
7092
8092
|
}
|
|
7093
8093
|
var defaultContext = {
|
|
@@ -7493,14 +8493,23 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
7493
8493
|
if (source.id === "agy") {
|
|
7494
8494
|
return agyBackfillFiles(stringOption(options["source-root"]), resolveHome2(options, ctx), ctx.env);
|
|
7495
8495
|
}
|
|
8496
|
+
if (source.id === "claude-cowork") {
|
|
8497
|
+
return claudeCoworkBackfillFiles(stringOption(options["source-root"]), resolveHome2(options, ctx), ctx.env);
|
|
8498
|
+
}
|
|
7496
8499
|
if (source.id === "codebuddy") {
|
|
7497
8500
|
return codebuddyBackfillFiles(stringOption(options["source-root"]), resolveHome2(options, ctx), ctx.env);
|
|
7498
8501
|
}
|
|
8502
|
+
if (source.id === "workbuddy") {
|
|
8503
|
+
return workbuddyBackfillFiles(stringOption(options["source-root"]), resolveHome2(options, ctx), ctx.env);
|
|
8504
|
+
}
|
|
8505
|
+
if (source.id === "zcode") {
|
|
8506
|
+
return zcodeBackfillFiles(stringOption(options["source-root"]), resolveHome2(options, ctx), ctx.env);
|
|
8507
|
+
}
|
|
7499
8508
|
const roots = stringOption(options["source-root"]) ? [requiredOption(options, "source-root")] : source.paths;
|
|
7500
8509
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
7501
8510
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
7502
8511
|
return Promise.all(files.map(async (filePath) => {
|
|
7503
|
-
const info = await
|
|
8512
|
+
const info = await stat10(filePath);
|
|
7504
8513
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
7505
8514
|
}));
|
|
7506
8515
|
}
|
|
@@ -7809,13 +8818,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
7809
8818
|
});
|
|
7810
8819
|
}
|
|
7811
8820
|
function backfillIncrementalStatePath(home) {
|
|
7812
|
-
return
|
|
8821
|
+
return path18.join(home, ".vibetime", "backfill-state.json");
|
|
7813
8822
|
}
|
|
7814
8823
|
function syncLocalTriggerStatePath(home) {
|
|
7815
|
-
return
|
|
8824
|
+
return path18.join(home, ".vibetime", "sync-local-trigger.json");
|
|
7816
8825
|
}
|
|
7817
8826
|
function syncLocalTriggerLockPath(home) {
|
|
7818
|
-
return
|
|
8827
|
+
return path18.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
7819
8828
|
}
|
|
7820
8829
|
async function readBackfillIncrementalState(home, ctx) {
|
|
7821
8830
|
const statePath = backfillIncrementalStatePath(home);
|
|
@@ -7855,7 +8864,7 @@ async function updateBackfillIncrementalState(home, state, selectedFilesBySource
|
|
|
7855
8864
|
state.sources[source] = { watermarkTs: latest };
|
|
7856
8865
|
}
|
|
7857
8866
|
const statePath = backfillIncrementalStatePath(home);
|
|
7858
|
-
await mkdir4(
|
|
8867
|
+
await mkdir4(path18.dirname(statePath), { recursive: true });
|
|
7859
8868
|
await writeFile3(statePath, `${JSON.stringify(state, null, 2)}
|
|
7860
8869
|
`, "utf8");
|
|
7861
8870
|
}
|
|
@@ -7888,7 +8897,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
7888
8897
|
return nextState;
|
|
7889
8898
|
}
|
|
7890
8899
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
7891
|
-
await mkdir4(
|
|
8900
|
+
await mkdir4(path18.dirname(statePath), { recursive: true });
|
|
7892
8901
|
const tmpPath = `${statePath}.tmp`;
|
|
7893
8902
|
await writeFile3(tmpPath, `${JSON.stringify(state, null, 2)}
|
|
7894
8903
|
`, "utf8");
|
|
@@ -7905,7 +8914,7 @@ async function readSyncLocalLock(lockPath) {
|
|
|
7905
8914
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
7906
8915
|
}
|
|
7907
8916
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
7908
|
-
await mkdir4(
|
|
8917
|
+
await mkdir4(path18.dirname(lockPath), { recursive: true });
|
|
7909
8918
|
await writeFile3(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
7910
8919
|
`, "utf8");
|
|
7911
8920
|
}
|
|
@@ -7965,10 +8974,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
7965
8974
|
if (cliPath.endsWith(".ts")) {
|
|
7966
8975
|
return ["--import", "tsx", cliPath];
|
|
7967
8976
|
}
|
|
7968
|
-
return [
|
|
8977
|
+
return [path18.resolve(path18.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
7969
8978
|
}
|
|
7970
8979
|
function resolveHome2(options, ctx) {
|
|
7971
|
-
return
|
|
8980
|
+
return path18.resolve(stringOption(options.home) || ctx.env.HOME || os7.homedir());
|
|
7972
8981
|
}
|
|
7973
8982
|
function requestedTargets(options) {
|
|
7974
8983
|
const value = options.target || options.targets;
|