@yhong91/vibetime 0.1.40 → 0.1.42

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 +167 -19
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -1928,7 +1928,7 @@ function countTextLines(text) {
1928
1928
  }
1929
1929
 
1930
1930
  // src/lib/constants.ts
1931
- var PACKAGE_VERSION = true ? "0.1.40" : "0.1.1";
1931
+ var PACKAGE_VERSION = true ? "0.1.42" : "0.1.1";
1932
1932
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
1933
1933
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
1934
1934
  var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
@@ -3308,7 +3308,11 @@ async function isHooksJsonInstalled(filePath, command) {
3308
3308
  }
3309
3309
 
3310
3310
  // src/adapters/claude-code.ts
3311
+ init_fs();
3311
3312
  async function parseClaudeCodeSessionFile(filePath, options) {
3313
+ if (path7.basename(filePath) === "usage.jsonl" && path7.basename(path7.dirname(filePath)) === ".viberouter") {
3314
+ return parseClaudeRouterUsageFile(filePath, options);
3315
+ }
3312
3316
  const text = await readFile3(filePath, "utf8");
3313
3317
  const lines = text.split("\n").filter(Boolean);
3314
3318
  const projectContext = await claudeProjectContextFromLines(filePath, lines, options);
@@ -3575,6 +3579,86 @@ async function parseClaudeCodeSessionFile(filePath, options) {
3575
3579
  }
3576
3580
  return state.events.filter((event) => validateCanonicalEvent(event).valid);
3577
3581
  }
3582
+ async function parseClaudeRouterUsageFile(filePath, options) {
3583
+ const rows = (await readFile3(filePath, "utf8")).split("\n").map(parseJsonLine).filter((row) => Boolean(
3584
+ row && row.surface === "claude" && (numberField(row, "timestamp") ?? 0) > 0 && Object.keys(objectField(row, "usage")).length > 0
3585
+ ));
3586
+ if (rows.length === 0) {
3587
+ return [];
3588
+ }
3589
+ const timestamps = rows.map((row) => numberField(row, "timestamp") ?? 0);
3590
+ const firstTs = Math.min(...timestamps) - 6e4;
3591
+ const lastTs = Math.max(...timestamps) + 6e4;
3592
+ const home = path7.resolve(stringOption(options.home) || path7.dirname(path7.dirname(filePath)));
3593
+ const transcriptCounts = /* @__PURE__ */ new Map();
3594
+ for (const transcript of await listJsonlFiles(path7.join(claudeConfigDir(home, process.env), "projects"))) {
3595
+ const seen = /* @__PURE__ */ new Set();
3596
+ for (const line of (await readFile3(transcript, "utf8")).split("\n")) {
3597
+ const raw = parseJsonLine(line);
3598
+ const ts = raw ? Date.parse(timestampFrom(raw.timestamp) || "") : Number.NaN;
3599
+ if (!raw || stringField(raw, "type") !== "assistant" || ts < firstTs || ts > lastTs) {
3600
+ continue;
3601
+ }
3602
+ const message = objectField(raw, "message");
3603
+ const messageId = stringField(message, "id");
3604
+ const usageKey = messageId ? `${messageId}:${stringField(raw, "requestId")}` : null;
3605
+ if (usageKey && seen.has(usageKey)) {
3606
+ continue;
3607
+ }
3608
+ if (usageKey) {
3609
+ seen.add(usageKey);
3610
+ }
3611
+ const usage = claudeUsageFromMessage(message);
3612
+ if (!usage) {
3613
+ continue;
3614
+ }
3615
+ const key = `${usage.tokensInput || 0}:${usage.tokensOutput || 0}`;
3616
+ transcriptCounts.set(key, (transcriptCounts.get(key) || 0) + 1);
3617
+ }
3618
+ }
3619
+ const sourcePathHash = `sha256:${createStableHash(filePath)}`;
3620
+ const events = [];
3621
+ for (const row of rows) {
3622
+ const usage = objectField(row, "usage");
3623
+ const input = numberField(usage, "inputTokens") || 0;
3624
+ const output = numberField(usage, "outputTokens") || 0;
3625
+ const key = `${input}:${output}`;
3626
+ const matched = transcriptCounts.get(key) || 0;
3627
+ if (matched > 0) {
3628
+ transcriptCounts.set(key, matched - 1);
3629
+ continue;
3630
+ }
3631
+ const timestamp = numberField(row, "timestamp") ?? 0;
3632
+ const requestId = stringField(row, "requestId") || createStableHash(row).slice(0, 24);
3633
+ const cacheCreation = numberField(usage, "cacheCreationInputTokens") || 0;
3634
+ const cacheRead = numberField(usage, "cacheReadInputTokens") || 0;
3635
+ const cached = numberField(usage, "cachedInputTokens") || cacheCreation + cacheRead;
3636
+ const event = baseClaudeEvent({
3637
+ ts: new Date(timestamp).toISOString(),
3638
+ type: "model.usage",
3639
+ sessionId: `viberouter:${new Date(timestamp).toISOString().slice(0, 10)}`,
3640
+ project: "unknown",
3641
+ model: stringField(row, "resolvedModel") || stringField(row, "requestedModel") || stringField(row, "model"),
3642
+ provider: stringField(row, "provider"),
3643
+ confidence: "exact",
3644
+ metrics: {
3645
+ tokensInput: input || void 0,
3646
+ tokensCachedInput: cached || void 0,
3647
+ tokensCacheCreationInput: cacheCreation || void 0,
3648
+ tokensCacheReadInput: cacheRead || void 0,
3649
+ tokensOutput: output || void 0,
3650
+ tokensReasoningOutput: numberField(usage, "reasoningOutputTokens") || void 0,
3651
+ tokensTotal: numberField(usage, "totalTokens") || input + output || void 0,
3652
+ modelCalls: 1
3653
+ },
3654
+ refs: stringRefs({ sourceId: requestId, sourcePathHash, importKey: `claude-code:viberouter:${requestId}` })
3655
+ });
3656
+ if (validateCanonicalEvent(event).valid) {
3657
+ events.push(event);
3658
+ }
3659
+ }
3660
+ return events;
3661
+ }
3578
3662
  function baseClaudeEvent(event) {
3579
3663
  return {
3580
3664
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
@@ -3911,6 +3995,7 @@ function createClaudeCodeAdapter() {
3911
3995
  const base = claudeConfigDir(home, env);
3912
3996
  return [
3913
3997
  path7.join(base, "projects"),
3998
+ path7.join(home, ".viberouter", "usage.jsonl"),
3914
3999
  path7.join(base, ".claude.json"),
3915
4000
  path7.join(home, ".claude.json")
3916
4001
  ];
@@ -7491,6 +7576,11 @@ function createPiAdapter() {
7491
7576
  };
7492
7577
  }
7493
7578
 
7579
+ // src/adapters/qoder-cn.ts
7580
+ import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
7581
+ import os8 from "node:os";
7582
+ import path17 from "node:path";
7583
+
7494
7584
  // src/adapters/qoder-local-db.ts
7495
7585
  import { access } from "node:fs/promises";
7496
7586
  import os7 from "node:os";
@@ -7537,6 +7627,7 @@ async function loadQoderDbModelCalls(appDirName, sessionId, modelMap) {
7537
7627
  }
7538
7628
  const db = new DatabaseSync(dbPath, { readOnly: true });
7539
7629
  try {
7630
+ calls.rootSessionId = resolveRootSessionId(db, sessionId);
7540
7631
  const preferredModel = resolveSessionPreferredModel(db, sessionId, modelMap);
7541
7632
  const rows = db.prepare(
7542
7633
  `select request_id, token_info, model_info from chat_message where session_id = ? and role = 'assistant' and token_info != '' order by gmt_create asc`
@@ -7570,6 +7661,18 @@ async function loadQoderDbModelCalls(appDirName, sessionId, modelMap) {
7570
7661
  }
7571
7662
  return calls;
7572
7663
  }
7664
+ function resolveRootSessionId(db, sessionId) {
7665
+ let current = sessionId;
7666
+ for (let depth = 0; depth < 5; depth += 1) {
7667
+ const row = db.prepare("select parent_session_id from chat_session where session_id = ?").get(current);
7668
+ const parent = row ? stringField(row, "parent_session_id") : void 0;
7669
+ if (!parent) {
7670
+ return current === sessionId ? void 0 : current;
7671
+ }
7672
+ current = parent;
7673
+ }
7674
+ return current === sessionId ? void 0 : current;
7675
+ }
7573
7676
  function resolveSessionPreferredModel(db, sessionId, modelMap) {
7574
7677
  let current = sessionId;
7575
7678
  for (let depth = 0; depth < 5 && current; depth++) {
@@ -7595,9 +7698,6 @@ function resolveSessionPreferredModel(db, sessionId, modelMap) {
7595
7698
  }
7596
7699
 
7597
7700
  // src/adapters/qoder-cn.ts
7598
- import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
7599
- import os8 from "node:os";
7600
- import path17 from "node:path";
7601
7701
  function parseQoderCnPaths(filePath) {
7602
7702
  const parts = filePath.split(path17.sep);
7603
7703
  const subagentsIdx = parts.lastIndexOf("subagents");
@@ -7715,7 +7815,8 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
7715
7815
  async function parseQoderCnSessionFile(filePath, options) {
7716
7816
  const text = await readFile10(filePath, "utf8");
7717
7817
  const lines = text.split("\n").filter(Boolean);
7718
- const { configDir: configDir2 } = parseQoderCnPaths(filePath);
7818
+ const parsedPaths = parseQoderCnPaths(filePath);
7819
+ const { configDir: configDir2 } = parsedPaths;
7719
7820
  const projectContext = await qoderCnProjectContextFromLines(filePath, lines, options, configDir2);
7720
7821
  const pendingTools = /* @__PURE__ */ new Map();
7721
7822
  const seenUsageKeys = /* @__PURE__ */ new Set();
@@ -8043,6 +8144,16 @@ async function parseQoderCnSessionFile(filePath, options) {
8043
8144
  });
8044
8145
  }
8045
8146
  }
8147
+ dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", parsedPaths.sessionId, modelMap);
8148
+ if (dbModelCalls.rootSessionId) {
8149
+ const parentPath = path17.join(path17.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
8150
+ const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
8151
+ return validEvents.map((event) => rebuildEventIdentity2({
8152
+ ...event,
8153
+ sessionId: dbModelCalls.rootSessionId,
8154
+ refs: { ...event.refs, sourcePathHash: parentSourcePathHash }
8155
+ }));
8156
+ }
8046
8157
  return validEvents;
8047
8158
  }
8048
8159
  function baseQoderCnEvent(event) {
@@ -8530,7 +8641,8 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
8530
8641
  async function parseQoderSessionFile(filePath, options) {
8531
8642
  const text = await readFile11(filePath, "utf8");
8532
8643
  const lines = text.split("\n").filter(Boolean);
8533
- const { configDir: configDir2 } = parseQoderPaths(filePath);
8644
+ const parsedPaths = parseQoderPaths(filePath);
8645
+ const { configDir: configDir2 } = parsedPaths;
8534
8646
  const projectContext = await qoderProjectContextFromLines(filePath, lines, options, configDir2);
8535
8647
  const pendingTools = /* @__PURE__ */ new Map();
8536
8648
  const seenUsageKeys = /* @__PURE__ */ new Set();
@@ -8858,6 +8970,16 @@ async function parseQoderSessionFile(filePath, options) {
8858
8970
  });
8859
8971
  }
8860
8972
  }
8973
+ dbModelCalls ??= await loadQoderDbModelCalls("Qoder", parsedPaths.sessionId, modelMap);
8974
+ if (dbModelCalls.rootSessionId) {
8975
+ const parentPath = path18.join(path18.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
8976
+ const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
8977
+ return validEvents.map((event) => rebuildEventIdentity3({
8978
+ ...event,
8979
+ sessionId: dbModelCalls.rootSessionId,
8980
+ refs: { ...event.refs, sourcePathHash: parentSourcePathHash }
8981
+ }));
8982
+ }
8861
8983
  return validEvents;
8862
8984
  }
8863
8985
  function baseQoderEvent(event) {
@@ -9893,7 +10015,7 @@ function modelMetrics(row) {
9893
10015
  toolCalls: numberField(row, "tool_call_count")
9894
10016
  };
9895
10017
  }
9896
- function resolveRootSessionId(sessionId, sessions) {
10018
+ function resolveRootSessionId2(sessionId, sessions) {
9897
10019
  let current = sessionId;
9898
10020
  const visited = /* @__PURE__ */ new Set();
9899
10021
  while (true) {
@@ -9915,7 +10037,7 @@ function sessionContext(row, sessions) {
9915
10037
  const session = sessions.get(sessionId);
9916
10038
  const cwd = stringField(session, "directory");
9917
10039
  const project = projectFromDirectory(cwd);
9918
- const rootSessionId = resolveRootSessionId(sessionId, sessions);
10040
+ const rootSessionId = resolveRootSessionId2(sessionId, sessions);
9919
10041
  return {
9920
10042
  rawSessionId: sessionId,
9921
10043
  sessionId: `zcode:${rootSessionId}`,
@@ -11275,7 +11397,11 @@ async function postRollupBatch(remote, rollups, options = {}) {
11275
11397
  const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
11276
11398
  method: "POST",
11277
11399
  headers: buildHeaders(remote.token, options.machine),
11278
- body: JSON.stringify({ rollups, replace: options.replace !== false })
11400
+ body: JSON.stringify({
11401
+ rollups,
11402
+ replace: options.replace !== false,
11403
+ allowHistoricalRewrite: options.allowHistoricalRewrite === true
11404
+ })
11279
11405
  });
11280
11406
  if (!response.ok) {
11281
11407
  const body = await response.text();
@@ -11289,9 +11415,10 @@ async function postRollupBatch(remote, rollups, options = {}) {
11289
11415
  failed: 0
11290
11416
  };
11291
11417
  }
11292
- async function deleteRollupsBySource(remote, source, machine) {
11418
+ async function deleteRollupsBySource(remote, source, machine, options = {}) {
11419
+ const query = `source=${encodeURIComponent(source)}${options.preserveTokens ? "&preserveTokens=1" : ""}${options.allowHistoricalRewrite ? "&allowHistoricalRewrite=1" : ""}`;
11293
11420
  const response = await remote.fetchImpl(
11294
- joinUrl(remote.baseUrl, `/v3/agent/sessions?source=${encodeURIComponent(source)}`),
11421
+ joinUrl(remote.baseUrl, `/v3/agent/sessions?${query}`),
11295
11422
  { method: "DELETE", headers: buildHeaders(remote.token, machine) }
11296
11423
  );
11297
11424
  if (!response.ok) {
@@ -11337,6 +11464,7 @@ async function deleteMachine(remote, id) {
11337
11464
  var BACKFILL_STATE_SCHEMA_VERSION = 6;
11338
11465
 
11339
11466
  // src/cli.ts
11467
+ var SESSION_REWRITE_DAYS = 7;
11340
11468
  function createRegistry() {
11341
11469
  const registry = new AdapterRegistry();
11342
11470
  registry.register(createCodexAdapter());
@@ -11414,7 +11542,7 @@ function createCli(ctx, registry) {
11414
11542
  cli.command("hook", "Read agent hook JSON from stdin and report a throttled event").option("--agent <name>", "Agent name").option("--project <name>", "Project name").option("--min-interval <seconds>", "Minimum seconds between similar hook reports").action((options) => hookCommand(normalizeOptions(options), ctx));
11415
11543
  cli.command("sync-local-trigger", "Trigger one background local sync with throttle and locking").option("--min-interval <seconds>", "Minimum seconds between sync triggers").action((options) => syncLocalTriggerCommand(normalizeOptions(options), ctx, registry));
11416
11544
  cli.command("sync-local-runner", "Internal background local sync runner").option("--lock-file <path>", "Lock file for the active sync").option("--state-file <path>", "State file for trigger metadata").action((options) => syncLocalRunnerCommand(normalizeOptions(options), ctx, registry));
11417
- cli.command("backfill [action]", "Inspect local history import candidates").option("--source <source>", "Backfill source").option("--since <time>", "Only include history after this time").option("--until <time>", "Only include history before this time").option("--project <name>", "Project filter").option("--source-root <path>", "Override source history root").option("--include-source-path", "Include local source paths in output").option("--import-run <id>", "Import run id for verify/resume workflows").option("--limit <count>", "Maximum session files to parse").option("--batch-size <count>", "Max rollups per request (also bounded by --batch-bytes)").option("--batch-bytes <bytes>", "Soft byte cap for the JSON body of a single ingest POST").option("--replace", "Replace conflicting records during import (default)").option("--skip-conflicts", "Skip conflicting records instead of replacing them").option("--force", "Force full re-import: clear watermark and re-process all files").action((action, options) => backfillCommand({ ...normalizeOptions(options), action }, ctx, registry));
11545
+ cli.command("backfill [action]", "Inspect local history import candidates").option("--source <source>", "Backfill source").option("--since <time>", "Only include history after this time").option("--until <time>", "Only include history before this time").option("--project <name>", "Project filter").option("--source-root <path>", "Override source history root").option("--include-source-path", "Include local source paths in output").option("--import-run <id>", "Import run id for verify/resume workflows").option("--limit <count>", "Maximum session files to parse").option("--batch-size <count>", "Max rollups per request (also bounded by --batch-bytes)").option("--batch-bytes <bytes>", "Soft byte cap for the JSON body of a single ingest POST").option("--replace", "Replace conflicting records during import (default)").option("--skip-conflicts", "Skip conflicting records instead of replacing them").option("--force", "Force re-import of sessions active within the last 7 days").option("--purge-all", "With --force: unlock and replace history older than 7 days (DANGEROUS)").action((action, options) => backfillCommand({ ...normalizeOptions(options), action }, ctx, registry));
11418
11546
  cli.command("token [action] [value]", "Set, show, or clear the persisted API token").option("--remote <url>", "Override API base URL when setting a token").action((action, value, options) => tokenCommand(action, value, normalizeOptions(options), ctx));
11419
11547
  cli.command("machine [action]", "List or rename machines (requires login)").option("--name <name>", "New display name (used by `machine rename`)").option("--id <id>", "Machine id (defaults to current machine)").action((action, options) => machineCommand(action, normalizeOptions(options), ctx));
11420
11548
  return cli;
@@ -11433,7 +11561,8 @@ function normalizeOptions(options) {
11433
11561
  importRun: "import-run",
11434
11562
  batchSize: "batch-size",
11435
11563
  batchBytes: "batch-bytes",
11436
- skipConflicts: "skip-conflicts"
11564
+ skipConflicts: "skip-conflicts",
11565
+ purgeAll: "purge-all"
11437
11566
  };
11438
11567
  for (const [camel, dashed] of Object.entries(aliases)) {
11439
11568
  if (normalized[camel] !== void 0 && normalized[dashed] === void 0) {
@@ -11703,6 +11832,10 @@ async function backfillCommand(options, ctx, registry) {
11703
11832
  if (action === "verify") {
11704
11833
  return backfillVerifyCommand(options, ctx);
11705
11834
  }
11835
+ if (options["purge-all"] && !options.force) {
11836
+ write(ctx.stderr, "--purge-all requires --force\n");
11837
+ return 1;
11838
+ }
11706
11839
  if (action === "import" && !options["dry-run"]) {
11707
11840
  const requested = normalizeBackfillSource(stringOption(options.source) || "all");
11708
11841
  const supported = /* @__PURE__ */ new Set(["all", ...BACKFILL_SOURCE_IDS]);
@@ -11978,7 +12111,7 @@ async function importBackfillPlan(plan, options, ctx, registry) {
11978
12111
  options,
11979
12112
  ctx
11980
12113
  );
11981
- const rollups = buildSessionRollups(canonicalEvents);
12114
+ const rollups = selectRollupsForUpload(buildSessionRollups(canonicalEvents), options);
11982
12115
  const counts = await uploadSessionRollups(rollups, canonicalEvents.length, options, ctx);
11983
12116
  const result = {
11984
12117
  importRunId: plan.importRun.importRunId,
@@ -12005,11 +12138,13 @@ async function purgeForcedSources(sourceDefs, home, remoteKey, options, ctx) {
12005
12138
  debug(ctx, `Failed to clear backfill watermark: ${error.message}
12006
12139
  `);
12007
12140
  }
12141
+ const preserveTokens = !options["purge-all"];
12008
12142
  for (const item of sourceDefs) {
12009
12143
  try {
12010
- const deleted = await deleteSessionRollupsBySourceAPI(item.id, options, ctx);
12144
+ const deleted = await deleteSessionRollupsBySourceAPI(item.id, options, ctx, preserveTokens);
12011
12145
  if (!options.json) {
12012
- write(ctx.stdout, `purged ${item.id}: ${deleted} old rollups
12146
+ const suffix = preserveTokens ? " (token-bearing and sessions older than 7 days kept)" : "";
12147
+ write(ctx.stdout, `purged ${item.id}: ${deleted} old rollups${suffix}
12013
12148
  `);
12014
12149
  }
12015
12150
  } catch (error) {
@@ -12135,11 +12270,12 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
12135
12270
  };
12136
12271
  const result = await postRollupBatch(remote, rollups, {
12137
12272
  replace: options["skip-conflicts"] !== true,
12138
- machine
12273
+ machine,
12274
+ allowHistoricalRewrite: options["purge-all"] === true
12139
12275
  });
12140
12276
  return result;
12141
12277
  }
12142
- async function deleteSessionRollupsBySourceAPI(source, options, ctx) {
12278
+ async function deleteSessionRollupsBySourceAPI(source, options, ctx, preserveTokens) {
12143
12279
  const remote = resolveRemoteFromOptions(options, ctx);
12144
12280
  if (!remote) {
12145
12281
  throw new Error("No fetch available for HTTP delete");
@@ -12149,8 +12285,18 @@ async function deleteSessionRollupsBySourceAPI(source, options, ctx) {
12149
12285
  id: ensureLocalMachineId(home),
12150
12286
  hostname: defaultMachineName(),
12151
12287
  platform: process.platform
12288
+ }, {
12289
+ preserveTokens,
12290
+ allowHistoricalRewrite: options["purge-all"] === true
12152
12291
  });
12153
12292
  }
12293
+ function selectRollupsForUpload(rollups, options, now = /* @__PURE__ */ new Date()) {
12294
+ if (!options.force || options["purge-all"]) {
12295
+ return rollups;
12296
+ }
12297
+ const cutoff = now.getTime() - SESSION_REWRITE_DAYS * 24 * 60 * 60 * 1e3;
12298
+ return rollups.filter((rollup) => Date.parse(rollup.lastEventAt) >= cutoff);
12299
+ }
12154
12300
  function shouldUseIncrementalBackfill(options) {
12155
12301
  return !stringOption(options.since) && !stringOption(options.until) && !stringOption(options["source-root"]) && numberOption(options.limit) === void 0;
12156
12302
  }
@@ -12608,7 +12754,7 @@ Usage:
12608
12754
  vibetime install [--target codex,claude,opencode,pi] [--all] [--dry-run] [--force] [--home <path>]
12609
12755
  vibetime upgrade [--check]
12610
12756
  vibetime hook --agent <name>
12611
- vibetime backfill discover|plan|import|verify --source codex|claude-code|opencode|pi|all --dry-run [--json] [--batch-size <count>]
12757
+ vibetime backfill discover|plan|import|verify --source codex|claude-code|opencode|pi|all --dry-run [--json] [--batch-size <count>] [--force [--purge-all]]
12612
12758
  vibetime token set <token>
12613
12759
  vibetime token show
12614
12760
  vibetime token clear
@@ -12641,8 +12787,10 @@ Environment:
12641
12787
  `;
12642
12788
  }
12643
12789
  export {
12790
+ SESSION_REWRITE_DAYS,
12644
12791
  run,
12645
12792
  selectBackfillFilesForImport,
12793
+ selectRollupsForUpload,
12646
12794
  syncLocalRunnerEntryArgs
12647
12795
  };
12648
12796
  const code = await run(process.argv.slice(2));process.exitCode = code;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.40",
4
+ "version": "0.1.42",
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": {