@yhong91/vibetime 0.1.47 → 0.1.49

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 +109 -9
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -2047,7 +2047,7 @@ function claudeStyleFileMetrics(tool, input) {
2047
2047
  }
2048
2048
 
2049
2049
  // src/lib/constants.ts
2050
- var PACKAGE_VERSION = true ? "0.1.47" : "0.1.1";
2050
+ var PACKAGE_VERSION = true ? "0.1.49" : "0.1.1";
2051
2051
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
2052
2052
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
2053
2053
  var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
@@ -5157,7 +5157,7 @@ async function parseCodexSessionFile(filePath, options) {
5157
5157
  let sessionId = sessionIdFromFilePath(filePath, "codex");
5158
5158
  let cwd;
5159
5159
  let project;
5160
- let model;
5160
+ let model = firstTurnContextModel(lines);
5161
5161
  let sessionStartEmitted = false;
5162
5162
  let serviceTier;
5163
5163
  let reasoningEffort;
@@ -5191,7 +5191,6 @@ async function parseCodexSessionFile(filePath, options) {
5191
5191
  sessionId = stringField(payload, "id") || sessionId;
5192
5192
  cwd = inherited?.cwd || stringField(payload, "cwd") || cwd;
5193
5193
  project = inherited?.project || (cwd ? path11.basename(cwd) : project);
5194
- model = stringField(payload, "model_provider") || model;
5195
5194
  events.push(withBackfillRefs({
5196
5195
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
5197
5196
  ts,
@@ -5599,6 +5598,21 @@ async function parseCodexSessionFile(filePath, options) {
5599
5598
  }
5600
5599
  return events.filter((event) => validateCanonicalEvent(event).valid);
5601
5600
  }
5601
+ function firstTurnContextModel(lines) {
5602
+ for (const line of lines) {
5603
+ if (!line.includes("turn_context")) {
5604
+ continue;
5605
+ }
5606
+ const raw = parseJsonLine(line);
5607
+ if (raw && stringField(raw, "type") === "turn_context") {
5608
+ const model = stringField(objectField(raw, "payload"), "model");
5609
+ if (model) {
5610
+ return model;
5611
+ }
5612
+ }
5613
+ }
5614
+ return void 0;
5615
+ }
5602
5616
  function rewriteCodexModelForTier(model, serviceTier) {
5603
5617
  if (!model) {
5604
5618
  return model;
@@ -7487,6 +7501,79 @@ function createOpenCodeAdapter() {
7487
7501
  // src/adapters/pi.ts
7488
7502
  import { readFile as readFile9 } from "node:fs/promises";
7489
7503
  import path15 from "node:path";
7504
+ function parsePiSubagentLink(filePath, headerParentSession) {
7505
+ if (headerParentSession) {
7506
+ const parentFile = path15.isAbsolute(headerParentSession) ? headerParentSession : void 0;
7507
+ const parentSessionId2 = parentFile ? path15.basename(parentFile, ".jsonl") : headerParentSession;
7508
+ return { parentSessionId: parentSessionId2, parentSessionFile: parentFile, explicit: true };
7509
+ }
7510
+ const normalized = filePath.replaceAll("\\", "/");
7511
+ const match = normalized.match(/([^/]+)\/[^/]+\/run-\d+\/session\.jsonl$/);
7512
+ if (!match) {
7513
+ return void 0;
7514
+ }
7515
+ const parentBasename = match[1];
7516
+ if (!parentBasename || parentBasename === "session") {
7517
+ return void 0;
7518
+ }
7519
+ const parentSessionId = parentBasename.endsWith(".jsonl") ? parentBasename.slice(0, -".jsonl".length) : parentBasename;
7520
+ const parentDir = path15.dirname(path15.dirname(path15.dirname(filePath)));
7521
+ const parentSessionFile = path15.join(path15.dirname(parentDir), `${parentBasename}.jsonl`);
7522
+ return { parentSessionId, parentSessionFile, explicit: false };
7523
+ }
7524
+ async function resolveParentContext(link, options) {
7525
+ if (link.parentSessionFile) {
7526
+ try {
7527
+ const text = await readFile9(link.parentSessionFile, "utf8");
7528
+ const firstLine = text.split("\n").find((line) => line.trim().length > 0);
7529
+ const raw = firstLine ? parseJsonLine(firstLine) : void 0;
7530
+ if (raw) {
7531
+ const id = stringField(raw, "id");
7532
+ const cwd = stringField(raw, "cwd");
7533
+ const project = cwd ? path15.basename(cwd) : void 0;
7534
+ if (id || cwd || project) {
7535
+ return { sessionId: id, cwd, project };
7536
+ }
7537
+ }
7538
+ } catch {
7539
+ }
7540
+ }
7541
+ const persisted = await readPersistedSessionContextFromOptions(options, link.parentSessionId);
7542
+ if (persisted) {
7543
+ return { cwd: persisted.cwd, project: persisted.project };
7544
+ }
7545
+ return void 0;
7546
+ }
7547
+ function foldEventsIntoParent(events, link) {
7548
+ const childSessionId = events.find((event) => event.sessionId)?.sessionId;
7549
+ return events.map((event) => {
7550
+ const rewritten = {
7551
+ ...event,
7552
+ sessionId: link.parentSessionId
7553
+ };
7554
+ if (childSessionId && childSessionId !== link.parentSessionId) {
7555
+ rewritten.refs = {
7556
+ ...event.refs,
7557
+ supersededSessionId: childSessionId
7558
+ };
7559
+ }
7560
+ return rebuildEventIdentity2(rewritten);
7561
+ });
7562
+ }
7563
+ function rebuildEventIdentity2(event) {
7564
+ const importKey = createImportKey([
7565
+ event.source,
7566
+ event.refs?.sourcePathHash,
7567
+ event.refs?.sourceLine,
7568
+ event.type,
7569
+ event.refs?.sourceId
7570
+ ]);
7571
+ return {
7572
+ ...event,
7573
+ id: createStableEventId(importKey),
7574
+ refs: { ...event.refs, importKey }
7575
+ };
7576
+ }
7490
7577
  async function parsePiSessionFile(filePath, options) {
7491
7578
  const text = await readFile9(filePath, "utf8");
7492
7579
  const lines = text.split("\n").filter(Boolean);
@@ -7497,6 +7584,7 @@ async function parsePiSessionFile(filePath, options) {
7497
7584
  let provider;
7498
7585
  let turnStartedAt;
7499
7586
  let reasoningEffort;
7587
+ let headerParentSession;
7500
7588
  const pendingToolCalls = /* @__PURE__ */ new Map();
7501
7589
  const state = new SessionParserState(filePath, options, (event) => basePiEvent({ ...event, cwd, project, model }));
7502
7590
  const push = (event, ln) => {
@@ -7520,6 +7608,7 @@ async function parsePiSessionFile(filePath, options) {
7520
7608
  state.sessionId = sessionId || state.sessionId;
7521
7609
  cwd = stringField(raw, "cwd") || cwd;
7522
7610
  project = cwd ? path15.basename(cwd) : project;
7611
+ headerParentSession = stringField(raw, "parentSession") || headerParentSession;
7523
7612
  continue;
7524
7613
  }
7525
7614
  if (entryType === "model_change") {
@@ -7703,6 +7792,17 @@ async function parsePiSessionFile(filePath, options) {
7703
7792
  if (isTurnIdle(state.currentTurnLastEventAt)) {
7704
7793
  state.closeTurn(state.currentTurnLastEventAt, lines.length);
7705
7794
  }
7795
+ const link = parsePiSubagentLink(filePath, headerParentSession);
7796
+ if (link) {
7797
+ const parentContext = await resolveParentContext(link, options);
7798
+ const effectiveLink = parentContext?.sessionId ? { ...link, parentSessionId: parentContext.sessionId } : link;
7799
+ if (parentContext) {
7800
+ cwd = cwd || parentContext.cwd;
7801
+ project = project || parentContext.project;
7802
+ }
7803
+ const events = state.events.filter((event) => matchesBackfillFilters(event, options));
7804
+ return foldEventsIntoParent(events, effectiveLink);
7805
+ }
7706
7806
  return state.events.filter((event) => matchesBackfillFilters(event, options));
7707
7807
  }
7708
7808
  function basePiEvent(event) {
@@ -8132,7 +8232,7 @@ function parseQoderCnPaths(filePath) {
8132
8232
  }
8133
8233
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
8134
8234
  }
8135
- function rebuildEventIdentity2(event) {
8235
+ function rebuildEventIdentity3(event) {
8136
8236
  const importKey = createImportKey([
8137
8237
  event.source,
8138
8238
  event.refs?.sourcePathHash,
@@ -8553,7 +8653,7 @@ async function parseQoderCnSessionFile(filePath, options) {
8553
8653
  ...event.sessionId && event.sessionId !== parentSessionId ? { supersededSessionId: event.sessionId } : {}
8554
8654
  }
8555
8655
  };
8556
- return rebuildEventIdentity2(mapped);
8656
+ return rebuildEventIdentity3(mapped);
8557
8657
  });
8558
8658
  }
8559
8659
  }
@@ -8561,7 +8661,7 @@ async function parseQoderCnSessionFile(filePath, options) {
8561
8661
  if (dbModelCalls.rootSessionId) {
8562
8662
  const parentPath = path17.join(path17.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
8563
8663
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
8564
- return validEvents.map((event) => rebuildEventIdentity2({
8664
+ return validEvents.map((event) => rebuildEventIdentity3({
8565
8665
  ...event,
8566
8666
  sessionId: dbModelCalls.rootSessionId,
8567
8667
  refs: {
@@ -8910,7 +9010,7 @@ function parseQoderPaths(filePath) {
8910
9010
  }
8911
9011
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
8912
9012
  }
8913
- function rebuildEventIdentity3(event) {
9013
+ function rebuildEventIdentity4(event) {
8914
9014
  const importKey = createImportKey([
8915
9015
  event.source,
8916
9016
  event.refs?.sourcePathHash,
@@ -9331,7 +9431,7 @@ async function parseQoderSessionFile(filePath, options) {
9331
9431
  ...event.sessionId && event.sessionId !== parentSessionId ? { supersededSessionId: event.sessionId } : {}
9332
9432
  }
9333
9433
  };
9334
- return rebuildEventIdentity3(mapped);
9434
+ return rebuildEventIdentity4(mapped);
9335
9435
  });
9336
9436
  }
9337
9437
  }
@@ -9339,7 +9439,7 @@ async function parseQoderSessionFile(filePath, options) {
9339
9439
  if (dbModelCalls.rootSessionId) {
9340
9440
  const parentPath = path18.join(path18.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
9341
9441
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
9342
- return validEvents.map((event) => rebuildEventIdentity3({
9442
+ return validEvents.map((event) => rebuildEventIdentity4({
9343
9443
  ...event,
9344
9444
  sessionId: dbModelCalls.rootSessionId,
9345
9445
  refs: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.47",
4
+ "version": "0.1.49",
5
5
  "description": "vibetime CLI — install AI-agent hooks (Claude Code, Codex, OpenCode, Pi) and report activity to vibetime.",
6
6
  "license": "MIT",
7
7
  "publishConfig": {