@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.
Files changed (2) hide show
  1. package/bin/vibetime.mjs +1190 -181
  2. 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 stat7, writeFile as writeFile3 } from "node:fs/promises";
163
- import os6 from "node:os";
164
- import path15 from "node:path";
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 refs = { ...item };
353
- delete refs.payloadHash;
354
- result[key] = removeVolatileHashFields(refs);
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.1" : "0.1.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 refs = {};
1227
+ const refs2 = {};
1228
1228
  for (const [key, item] of Object.entries(value || {})) {
1229
1229
  if (typeof item === "string" && item.length > 0) {
1230
- refs[key] = item;
1230
+ refs2[key] = item;
1231
1231
  }
1232
1232
  }
1233
- return refs;
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 refs = {
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
- refs.transcriptPath = context.filePath;
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/codebuddy.ts
2780
- import { readFile as readFile4, readdir as readdir3 } from "node:fs/promises";
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 readFile4(filePath, "utf8");
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 ? path7.basename(cwd) : void 0;
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 = path7.basename(filePath).match(/trace_([0-9a-f]{32})/);
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 ? path7.resolve(String(options.home)) : process.env.HOME || __require("node:os").homedir();
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 readFile4(sessionPath, "utf8");
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 = path7.join(home, ".codebuddy", "sessions");
3363
+ const sessionsDir = path8.join(home, ".codebuddy", "sessions");
3119
3364
  if (pid) {
3120
- const cwd = await readCwdFromSession(path7.join(sessionsDir, `${pid}.json`));
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 readdir3(sessionsDir);
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
- path7.join(sessionsDir, f),
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 = path7.join(home, ".codebuddy", "history.jsonl");
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 readFile4(historyPath, "utf8");
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 path7.resolve(override);
3454
+ return path8.resolve(override);
3210
3455
  }
3211
- return path7.join(home, ".codebuddy");
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 path7.join(codebuddyConfigDir(home, env), "settings.json");
3468
+ return path8.join(codebuddyConfigDir(home, env), "settings.json");
3224
3469
  },
3225
3470
  async isInstalled(home, env) {
3226
3471
  return isHooksJsonInstalled(
3227
- path7.join(codebuddyConfigDir(home, env), "settings.json"),
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: path7.join(codebuddyConfigDir(home, env), "settings.json"),
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
- path7.join(base, "traces")
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 || path7.join(codebuddyConfigDir(home, env), "traces");
3493
+ const base = sourceRoot || path8.join(codebuddyConfigDir(home, env), "traces");
3249
3494
  const files = [];
3250
3495
  try {
3251
- const pidDirs = await readdir3(base, { withFileTypes: true });
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 = path7.join(base, pidDir.name);
3501
+ const traceDir = path8.join(base, pidDir.name);
3257
3502
  try {
3258
- const entries = await readdir3(traceDir);
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 = path7.join(traceDir, entry);
3508
+ const filePath = path8.join(traceDir, entry);
3264
3509
  try {
3265
- const stat8 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
3266
- files.push({ path: filePath, modifiedAt: stat8.mtime.toISOString() });
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 readFile5 } from "node:fs/promises";
3280
- import path8 from "node:path";
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 readFile5(filePath, "utf8");
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 ? path8.basename(cwd) : project;
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 ? path8.basename(cwd) : project;
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 || !path8.isAbsolute(filePath)) {
4068
+ if (!cwd || !path9.isAbsolute(filePath)) {
3824
4069
  return filePath;
3825
4070
  }
3826
- const relative = path8.relative(cwd, filePath);
3827
- return relative && !relative.startsWith("..") && !path8.isAbsolute(relative) ? relative : filePath;
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 path8.resolve(override);
4091
+ return path9.resolve(override);
3847
4092
  }
3848
- return path8.join(home, ".codex");
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 path8.join(codexHome(home, env), "hooks.json");
4105
+ return path9.join(codexHome(home, env), "hooks.json");
3861
4106
  },
3862
4107
  async isInstalled(home, env) {
3863
4108
  return isHooksJsonInstalled(
3864
- path8.join(codexHome(home, env), "hooks.json"),
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: path8.join(codexHome(home, env), "hooks.json"),
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
- path8.join(base, "sessions"),
3879
- path8.join(base, "history.jsonl")
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 os3 from "node:os";
3888
- import path9 from "node:path";
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 ? path9.basename(cwd) : void 0;
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 ? path9.basename(assistantCwd) : project;
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 path9.resolve(override);
4502
+ return path10.resolve(override);
4258
4503
  }
4259
4504
  const xdgConfig = env?.XDG_CONFIG_HOME;
4260
4505
  if (xdgConfig && xdgConfig.trim()) {
4261
- return path9.join(path9.resolve(xdgConfig), "opencode");
4506
+ return path10.join(path10.resolve(xdgConfig), "opencode");
4262
4507
  }
4263
- return path9.join(home, ".config", "opencode");
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() ? path9.join(path9.resolve(xdgData), "opencode", "opencode.db") : path9.join(home, ".local", "share", "opencode", "opencode.db");
4268
- return [primary, path9.join(home, ".opencode", "opencode.db")];
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 = os3.homedir(), env) {
4271
- const { stat: stat8 } = await import("node:fs/promises");
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 stat8(sourceRoot).catch(() => null);
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 stat8(candidatePath).catch(() => null);
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 path9.join(opencodeConfigDir(home, env), PLUGIN_PATH);
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(path9.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path9.join(".opencode", PLUGIN_PATH));
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: path9.join(opencodeConfigDir(home, env), PLUGIN_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 readFile6 } from "node:fs/promises";
4374
- import path10 from "node:path";
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 readFile6(filePath, "utf8");
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 ? path10.basename(cwd) : project;
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 path10.resolve(override);
5052
+ return path11.resolve(override);
4808
5053
  }
4809
- return path10.join(home, ".pi", "agent");
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 path10.resolve(override);
5059
+ return path11.resolve(override);
4815
5060
  }
4816
- return path10.join(piAgentDir(home, env), "sessions");
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 path10.join(piAgentDir(home, env), "extensions", "vibetime.ts");
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(path10.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
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: path10.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
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 readdir4, readFile as readFile7, stat as stat4 } from "node:fs/promises";
4854
- import os4 from "node:os";
4855
- import path11 from "node:path";
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(path11.sep);
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(path11.sep);
5111
+ configDir2 = parts.slice(0, projectsIdx).join(path12.sep);
4867
5112
  } else {
4868
5113
  const filename = parts.at(-1) || "";
4869
- sessionId = path11.basename(filename, ".jsonl");
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(path11.sep);
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 = path11.join(configDir2, ".auth", "dynamic-texts.json");
4879
- const content = await readFile7(dynamicTextsPath, "utf8");
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 = path11.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
5141
+ const segmentsPath = path12.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
4897
5142
  const modelCalls = [];
4898
5143
  try {
4899
- const files = await readdir4(segmentsPath);
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 readFile7(path11.join(segmentsPath, file), "utf8");
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 readFile7(filePath, "utf8");
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 ? path11.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
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(`${path11.sep}subagents${path11.sep}`);
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 && path11.isAbsolute(cwd)) {
5651
+ if (cwd && path12.isAbsolute(cwd)) {
5407
5652
  cwds.push(cwd);
5408
5653
  }
5409
5654
  }
5410
5655
  if (isSubagent) {
5411
- const parentSessionPath = path11.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
5656
+ const parentSessionPath = path12.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
5412
5657
  try {
5413
- const parentText = await readFile7(parentSessionPath, "utf8");
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 && path11.isAbsolute(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 ? path11.basename(cwds[0]) : root ? path11.basename(root) : await qoderCnProjectFromFilePath(filePath, options);
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 = path11.resolve(cwd);
5683
+ let current = path12.resolve(cwd);
5439
5684
  while (!seen.has(current)) {
5440
5685
  seen.add(current);
5441
5686
  try {
5442
- await stat4(path11.join(current, ".git"));
5687
+ await stat5(path12.join(current, ".git"));
5443
5688
  return current;
5444
5689
  } catch {
5445
5690
  }
5446
- const parent = path11.dirname(current);
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 = path11.resolve(cwd);
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 = path11.dirname(current);
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 path11.resolve(value).split(path11.sep).join("-").replace(/_/g, "-");
5717
+ return path12.resolve(value).split(path12.sep).join("-").replace(/_/g, "-");
5473
5718
  }
5474
5719
  async function qoderCnProjectFromFilePath(filePath, options) {
5475
- const projectDir = path11.basename(path11.dirname(filePath));
5476
- const home = options ? path11.resolve(stringOption(options.home) || os4.homedir()) : os4.homedir();
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 path11.basename(resolved);
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 readdir4(current, { withFileTypes: true });
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 = path11.join(current, entry.name);
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 path11.resolve(override);
5794
+ return path12.resolve(override);
5550
5795
  }
5551
- return path11.join(home, ".qoder-cn");
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 path11.join(qoderCnConfigDir(home, env), "settings.json");
5808
+ return path12.join(qoderCnConfigDir(home, env), "settings.json");
5564
5809
  },
5565
5810
  async isInstalled(home, env) {
5566
5811
  return isHooksJsonInstalled(
5567
- path11.join(qoderCnConfigDir(home, env), "settings.json"),
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: path11.join(qoderCnConfigDir(home, env), "settings.json"),
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
- path11.join(base, "projects"),
5582
- path11.join(base, ".qoder.json"),
5583
- path11.join(home, ".qoder.json")
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 readdir5, readFile as readFile8, stat as stat5 } from "node:fs/promises";
5592
- import os5 from "node:os";
5593
- import path12 from "node:path";
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(path12.sep);
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(path12.sep);
5849
+ configDir2 = parts.slice(0, projectsIdx).join(path13.sep);
5605
5850
  } else {
5606
5851
  const filename = parts.at(-1) || "";
5607
- sessionId = path12.basename(filename, ".jsonl");
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(path12.sep);
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 = path12.join(configDir2, ".auth", "dynamic-texts.json");
5617
- const content = await readFile8(dynamicTextsPath, "utf8");
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 = path12.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
5879
+ const segmentsPath = path13.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
5635
5880
  const modelCalls = [];
5636
5881
  try {
5637
- const files = await readdir5(segmentsPath);
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 readFile8(path12.join(segmentsPath, file), "utf8");
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 readFile8(filePath, "utf8");
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 ? path12.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
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(`${path12.sep}subagents${path12.sep}`);
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 && path12.isAbsolute(cwd)) {
6355
+ if (cwd && path13.isAbsolute(cwd)) {
6111
6356
  cwds.push(cwd);
6112
6357
  }
6113
6358
  }
6114
6359
  if (isSubagent) {
6115
- const parentSessionPath = path12.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
6360
+ const parentSessionPath = path13.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
6116
6361
  try {
6117
- const parentText = await readFile8(parentSessionPath, "utf8");
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 && path12.isAbsolute(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 ? path12.basename(cwds[0]) : root ? path12.basename(root) : await qoderProjectFromFilePath(filePath, options);
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 = path12.resolve(cwd);
6387
+ let current = path13.resolve(cwd);
6143
6388
  while (!seen.has(current)) {
6144
6389
  seen.add(current);
6145
6390
  try {
6146
- await stat5(path12.join(current, ".git"));
6391
+ await stat6(path13.join(current, ".git"));
6147
6392
  return current;
6148
6393
  } catch {
6149
6394
  }
6150
- const parent = path12.dirname(current);
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 = path12.resolve(cwd);
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 = path12.dirname(current);
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 path12.resolve(value).split(path12.sep).join("-").replace(/_/g, "-");
6421
+ return path13.resolve(value).split(path13.sep).join("-").replace(/_/g, "-");
6177
6422
  }
6178
6423
  function rawQoderProjectPath(value) {
6179
- return path12.resolve(value).split(path12.sep).join("-");
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 = path12.basename(path12.dirname(filePath));
6196
- const home = options ? path12.resolve(stringOption(options.home) || os5.homedir()) : os5.homedir();
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 path12.basename(resolved);
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 readdir5(current, { withFileTypes: true });
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 = path12.join(current, entry.name);
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 path12.resolve(override);
6515
+ return path13.resolve(override);
6271
6516
  }
6272
- return path12.join(home, ".qoder");
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 path12.join(qoderConfigDir(home, env), "settings.json");
6529
+ return path13.join(qoderConfigDir(home, env), "settings.json");
6285
6530
  },
6286
6531
  async isInstalled(home, env) {
6287
6532
  return isHooksJsonInstalled(
6288
- path12.join(qoderConfigDir(home, env), "settings.json"),
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: path12.join(qoderConfigDir(home, env), "settings.json"),
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
- path12.join(base, "projects"),
6303
- path12.join(base, ".qoder.json"),
6304
- path12.join(home, ".qoder.json")
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 path13 from "node:path";
7771
+ import path16 from "node:path";
6775
7772
  function configDir(home = homedir()) {
6776
- return path13.join(home, ".vibetime");
7773
+ return path16.join(home, ".vibetime");
6777
7774
  }
6778
7775
  function configPath(home = homedir()) {
6779
- return path13.join(configDir(home), "config.json");
7776
+ return path16.join(configDir(home), "config.json");
6780
7777
  }
6781
7778
  function machineIdPath(home = homedir()) {
6782
- return path13.join(configDir(home), "machine-id");
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 stat6 } from "node:fs/promises";
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 path14 from "node:path";
7828
+ import path17 from "node:path";
6832
7829
  var MAX_BYTES = 1 * 1024 * 1024;
6833
7830
  function logDir(home = homedir2()) {
6834
- return path14.join(home, ".vibetime", "logs");
7831
+ return path17.join(home, ".vibetime", "logs");
6835
7832
  }
6836
7833
  function logPath(home = homedir2(), name = "cli.log") {
6837
- return path14.join(logDir(home), name);
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 stat6(file);
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, path16) {
7013
- return new URL(path16, base.endsWith("/") ? base : `${base}/`).toString();
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 stat7(filePath);
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 path15.join(home, ".vibetime", "backfill-state.json");
8821
+ return path18.join(home, ".vibetime", "backfill-state.json");
7813
8822
  }
7814
8823
  function syncLocalTriggerStatePath(home) {
7815
- return path15.join(home, ".vibetime", "sync-local-trigger.json");
8824
+ return path18.join(home, ".vibetime", "sync-local-trigger.json");
7816
8825
  }
7817
8826
  function syncLocalTriggerLockPath(home) {
7818
- return path15.join(home, ".vibetime", "sync-local-trigger.lock");
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(path15.dirname(statePath), { recursive: true });
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(path15.dirname(statePath), { recursive: true });
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(path15.dirname(lockPath), { recursive: true });
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 [path15.resolve(path15.dirname(cliPath), "../bin/vibetime.mjs")];
8977
+ return [path18.resolve(path18.dirname(cliPath), "../bin/vibetime.mjs")];
7969
8978
  }
7970
8979
  function resolveHome2(options, ctx) {
7971
- return path15.resolve(stringOption(options.home) || ctx.env.HOME || os6.homedir());
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;