@yhong91/vibetime 0.1.54 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/vibetime.mjs +61 -59
- 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.
|
|
2050
|
+
var PACKAGE_VERSION = true ? "0.1.56" : "0.1.1";
|
|
2051
2051
|
var GENERATED_MARKER = "Generated by vibetime.";
|
|
2052
2052
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
2053
2053
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
@@ -8154,6 +8154,29 @@ import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node
|
|
|
8154
8154
|
import os7 from "node:os";
|
|
8155
8155
|
import path16 from "node:path";
|
|
8156
8156
|
init_fs();
|
|
8157
|
+
function piHostSessionIdFromBasename(basename) {
|
|
8158
|
+
const withoutExt = basename.endsWith(".jsonl") ? basename.slice(0, -".jsonl".length) : basename;
|
|
8159
|
+
if (!withoutExt || withoutExt === "session") {
|
|
8160
|
+
return void 0;
|
|
8161
|
+
}
|
|
8162
|
+
const underscore = withoutExt.indexOf("_");
|
|
8163
|
+
if (underscore <= 0 || underscore === withoutExt.length - 1) {
|
|
8164
|
+
return withoutExt;
|
|
8165
|
+
}
|
|
8166
|
+
return withoutExt.slice(underscore + 1);
|
|
8167
|
+
}
|
|
8168
|
+
function resolvePiBackfillGroupId(filePath) {
|
|
8169
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
8170
|
+
const base = path16.basename(filePath);
|
|
8171
|
+
const nest = normalized.match(/([^/]+)\/[^/]+\/run-\d+\/session\.jsonl$/);
|
|
8172
|
+
if (nest) {
|
|
8173
|
+
return piHostSessionIdFromBasename(nest[1]);
|
|
8174
|
+
}
|
|
8175
|
+
if (base.endsWith(".jsonl") && base !== "session.jsonl") {
|
|
8176
|
+
return piHostSessionIdFromBasename(base);
|
|
8177
|
+
}
|
|
8178
|
+
return void 0;
|
|
8179
|
+
}
|
|
8157
8180
|
function parsePiSubagentLink(filePath, headerParentSession) {
|
|
8158
8181
|
if (headerParentSession) {
|
|
8159
8182
|
const parentFile = path16.isAbsolute(headerParentSession) ? headerParentSession : void 0;
|
|
@@ -8805,6 +8828,17 @@ function piSessionDir(home, env) {
|
|
|
8805
8828
|
function piWorkflowProjectsDir(home) {
|
|
8806
8829
|
return path16.join(home, ".pi", "workflows", "projects");
|
|
8807
8830
|
}
|
|
8831
|
+
async function workflowRunGroupId(filePath) {
|
|
8832
|
+
try {
|
|
8833
|
+
const raw = JSON.parse(await readFile10(filePath, "utf8"));
|
|
8834
|
+
if (!isPlainObject(raw)) {
|
|
8835
|
+
return void 0;
|
|
8836
|
+
}
|
|
8837
|
+
return stringField(raw, "sessionId");
|
|
8838
|
+
} catch {
|
|
8839
|
+
return void 0;
|
|
8840
|
+
}
|
|
8841
|
+
}
|
|
8808
8842
|
async function piBackfillFiles(sourceRoot, home = os7.homedir(), env) {
|
|
8809
8843
|
const lists = sourceRoot ? [await listFilesByExtensions(sourceRoot, [".jsonl", ".json"])] : await Promise.all([
|
|
8810
8844
|
listFilesByExtensions(piSessionDir(home, env), [".jsonl"]),
|
|
@@ -8813,7 +8847,15 @@ async function piBackfillFiles(sourceRoot, home = os7.homedir(), env) {
|
|
|
8813
8847
|
const files = lists.flat().sort();
|
|
8814
8848
|
return Promise.all(files.map(async (filePath) => {
|
|
8815
8849
|
const info = await stat8(filePath);
|
|
8816
|
-
|
|
8850
|
+
let groupId = resolvePiBackfillGroupId(filePath);
|
|
8851
|
+
if (!groupId && filePath.endsWith(".json")) {
|
|
8852
|
+
groupId = await workflowRunGroupId(filePath);
|
|
8853
|
+
}
|
|
8854
|
+
return {
|
|
8855
|
+
path: filePath,
|
|
8856
|
+
modifiedAt: info.mtime.toISOString(),
|
|
8857
|
+
...groupId ? { groupId } : {}
|
|
8858
|
+
};
|
|
8817
8859
|
}));
|
|
8818
8860
|
}
|
|
8819
8861
|
function createPiAdapter() {
|
|
@@ -9532,10 +9574,11 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
9532
9574
|
const { sessionId: parentSessionId, mainTranscriptPath } = parseQoderCnPaths(filePath);
|
|
9533
9575
|
if (parentSessionId && mainTranscriptPath) {
|
|
9534
9576
|
const parentSourcePathHash = `sha256:${createStableHash(mainTranscriptPath)}`;
|
|
9535
|
-
return validEvents.map((event) => {
|
|
9577
|
+
return withoutSubagentTurnEvents(validEvents).map((event) => {
|
|
9536
9578
|
const mapped = {
|
|
9537
9579
|
...event,
|
|
9538
9580
|
sessionId: parentSessionId,
|
|
9581
|
+
turnId: void 0,
|
|
9539
9582
|
refs: {
|
|
9540
9583
|
...event.refs,
|
|
9541
9584
|
sourcePathHash: parentSourcePathHash,
|
|
@@ -9550,9 +9593,10 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
9550
9593
|
if (dbModelCalls.rootSessionId) {
|
|
9551
9594
|
const parentPath = path18.join(path18.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
9552
9595
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
9553
|
-
return validEvents.map((event) => rebuildEventIdentity3({
|
|
9596
|
+
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity3({
|
|
9554
9597
|
...event,
|
|
9555
9598
|
sessionId: dbModelCalls.rootSessionId,
|
|
9599
|
+
turnId: void 0,
|
|
9556
9600
|
refs: {
|
|
9557
9601
|
...event.refs,
|
|
9558
9602
|
sourcePathHash: parentSourcePathHash,
|
|
@@ -10386,10 +10430,11 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
10386
10430
|
const { sessionId: parentSessionId, mainTranscriptPath } = parseQoderPaths(filePath);
|
|
10387
10431
|
if (parentSessionId && mainTranscriptPath) {
|
|
10388
10432
|
const parentSourcePathHash = `sha256:${createStableHash(mainTranscriptPath)}`;
|
|
10389
|
-
return validEvents.map((event) => {
|
|
10433
|
+
return withoutSubagentTurnEvents(validEvents).map((event) => {
|
|
10390
10434
|
const mapped = {
|
|
10391
10435
|
...event,
|
|
10392
10436
|
sessionId: parentSessionId,
|
|
10437
|
+
turnId: void 0,
|
|
10393
10438
|
refs: {
|
|
10394
10439
|
...event.refs,
|
|
10395
10440
|
sourcePathHash: parentSourcePathHash,
|
|
@@ -10404,9 +10449,10 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
10404
10449
|
if (dbModelCalls.rootSessionId) {
|
|
10405
10450
|
const parentPath = path19.join(path19.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
10406
10451
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
10407
|
-
return validEvents.map((event) => rebuildEventIdentity4({
|
|
10452
|
+
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity4({
|
|
10408
10453
|
...event,
|
|
10409
10454
|
sessionId: dbModelCalls.rootSessionId,
|
|
10455
|
+
turnId: void 0,
|
|
10410
10456
|
refs: {
|
|
10411
10457
|
...event.refs,
|
|
10412
10458
|
sourcePathHash: parentSourcePathHash,
|
|
@@ -13205,10 +13251,9 @@ async function deleteMachine(remote, id) {
|
|
|
13205
13251
|
}
|
|
13206
13252
|
|
|
13207
13253
|
// src/lib/types.ts
|
|
13208
|
-
var BACKFILL_STATE_SCHEMA_VERSION =
|
|
13254
|
+
var BACKFILL_STATE_SCHEMA_VERSION = 7;
|
|
13209
13255
|
|
|
13210
13256
|
// src/cli.ts
|
|
13211
|
-
var SESSION_REWRITE_DAYS = 7;
|
|
13212
13257
|
function createRegistry() {
|
|
13213
13258
|
const registry = new AdapterRegistry();
|
|
13214
13259
|
registry.register(createCodexAdapter());
|
|
@@ -13288,7 +13333,7 @@ function createCli(ctx, registry) {
|
|
|
13288
13333
|
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));
|
|
13289
13334
|
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));
|
|
13290
13335
|
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));
|
|
13291
|
-
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", "
|
|
13336
|
+
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", "Re-import everything and rewrite matching server rollups (history lock unlocked; nothing is deleted)").action((action, options) => backfillCommand({ ...normalizeOptions(options), action }, ctx, registry));
|
|
13292
13337
|
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));
|
|
13293
13338
|
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));
|
|
13294
13339
|
return cli;
|
|
@@ -13307,8 +13352,7 @@ function normalizeOptions(options) {
|
|
|
13307
13352
|
importRun: "import-run",
|
|
13308
13353
|
batchSize: "batch-size",
|
|
13309
13354
|
batchBytes: "batch-bytes",
|
|
13310
|
-
skipConflicts: "skip-conflicts"
|
|
13311
|
-
purgeAll: "purge-all"
|
|
13355
|
+
skipConflicts: "skip-conflicts"
|
|
13312
13356
|
};
|
|
13313
13357
|
for (const [camel, dashed] of Object.entries(aliases)) {
|
|
13314
13358
|
if (normalized[camel] !== void 0 && normalized[dashed] === void 0) {
|
|
@@ -13616,10 +13660,6 @@ async function backfillCommand(options, ctx, registry) {
|
|
|
13616
13660
|
if (action === "verify") {
|
|
13617
13661
|
return backfillVerifyCommand(options, ctx);
|
|
13618
13662
|
}
|
|
13619
|
-
if (options["purge-all"] && !options.force) {
|
|
13620
|
-
write(ctx.stderr, "--purge-all requires --force\n");
|
|
13621
|
-
return 1;
|
|
13622
|
-
}
|
|
13623
13663
|
if (action === "import" && !options["dry-run"]) {
|
|
13624
13664
|
const requested = normalizeBackfillSource(stringOption(options.source) || "all");
|
|
13625
13665
|
const supported = /* @__PURE__ */ new Set(["all", ...BACKFILL_SOURCE_IDS]);
|
|
@@ -13882,7 +13922,7 @@ async function importBackfillPlan(plan, options, ctx, registry) {
|
|
|
13882
13922
|
const remote = resolveRemoteFromOptions(options, ctx);
|
|
13883
13923
|
const remoteKey = backfillRemoteKey(remote?.baseUrl ?? DEFAULT_API_URL);
|
|
13884
13924
|
if (options.force) {
|
|
13885
|
-
await
|
|
13925
|
+
await resetForcedWatermarks(home, remoteKey, options, ctx);
|
|
13886
13926
|
}
|
|
13887
13927
|
const incrementalState = shouldUseIncrementalBackfill(options) ? await readBackfillIncrementalState(home, remoteKey, ctx) : void 0;
|
|
13888
13928
|
if (!options.json) {
|
|
@@ -13898,7 +13938,7 @@ async function importBackfillPlan(plan, options, ctx, registry) {
|
|
|
13898
13938
|
options,
|
|
13899
13939
|
ctx
|
|
13900
13940
|
);
|
|
13901
|
-
const rollups =
|
|
13941
|
+
const rollups = buildSessionRollups(canonicalEvents);
|
|
13902
13942
|
const counts = await uploadSessionRollups(rollups, canonicalEvents.length, options, ctx);
|
|
13903
13943
|
const result = {
|
|
13904
13944
|
importRunId: plan.importRun.importRunId,
|
|
@@ -13916,7 +13956,7 @@ async function importBackfillPlan(plan, options, ctx, registry) {
|
|
|
13916
13956
|
}
|
|
13917
13957
|
return counts.failed > 0 || counts.conflicts > 0 && !options["skip-conflicts"] ? 1 : 0;
|
|
13918
13958
|
}
|
|
13919
|
-
async function
|
|
13959
|
+
async function resetForcedWatermarks(home, remoteKey, options, ctx) {
|
|
13920
13960
|
try {
|
|
13921
13961
|
const file = await readBackfillIncrementalStateFile(home);
|
|
13922
13962
|
delete file.remotes[remoteKey];
|
|
@@ -13925,20 +13965,6 @@ async function purgeForcedSources(sourceDefs, home, remoteKey, options, ctx) {
|
|
|
13925
13965
|
debug(ctx, `Failed to clear backfill watermark: ${error.message}
|
|
13926
13966
|
`);
|
|
13927
13967
|
}
|
|
13928
|
-
const preserveTokens = !options["purge-all"];
|
|
13929
|
-
for (const item of sourceDefs) {
|
|
13930
|
-
try {
|
|
13931
|
-
const deleted = await deleteSessionRollupsBySourceAPI(item.id, options, ctx, preserveTokens);
|
|
13932
|
-
if (!options.json) {
|
|
13933
|
-
const suffix = preserveTokens ? " (token-bearing and sessions older than 7 days kept)" : "";
|
|
13934
|
-
write(ctx.stdout, `purged ${item.id}: ${deleted} old rollups${suffix}
|
|
13935
|
-
`);
|
|
13936
|
-
}
|
|
13937
|
-
} catch (error) {
|
|
13938
|
-
debug(ctx, `Failed to purge ${item.id} rollups: ${error.message}
|
|
13939
|
-
`);
|
|
13940
|
-
}
|
|
13941
|
-
}
|
|
13942
13968
|
}
|
|
13943
13969
|
async function collectCanonicalEvents(sourceDefs, registry, incrementalState, options, ctx) {
|
|
13944
13970
|
const selectedFilesBySource = /* @__PURE__ */ new Map();
|
|
@@ -14058,7 +14084,7 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
|
|
|
14058
14084
|
const result = await postRollupBatch(remote, rollups, {
|
|
14059
14085
|
replace: options["skip-conflicts"] !== true,
|
|
14060
14086
|
machine,
|
|
14061
|
-
allowHistoricalRewrite: options
|
|
14087
|
+
allowHistoricalRewrite: options.force === true
|
|
14062
14088
|
});
|
|
14063
14089
|
if (options.force && result.conflicts === 0) {
|
|
14064
14090
|
for (const rollup of rollups) {
|
|
@@ -14066,7 +14092,7 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
|
|
|
14066
14092
|
try {
|
|
14067
14093
|
await deleteRollupsBySource(remote, rollup.source, machine, {
|
|
14068
14094
|
rollupKey: createImportKey(["rollup", rollup.source, sessionId]),
|
|
14069
|
-
allowHistoricalRewrite: options
|
|
14095
|
+
allowHistoricalRewrite: options.force === true
|
|
14070
14096
|
});
|
|
14071
14097
|
} catch (error) {
|
|
14072
14098
|
debug(ctx, `Failed to delete superseded ${rollup.source} session ${sessionId}: ${error.message}
|
|
@@ -14077,28 +14103,6 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
|
|
|
14077
14103
|
}
|
|
14078
14104
|
return result;
|
|
14079
14105
|
}
|
|
14080
|
-
async function deleteSessionRollupsBySourceAPI(source, options, ctx, preserveTokens) {
|
|
14081
|
-
const remote = resolveRemoteFromOptions(options, ctx);
|
|
14082
|
-
if (!remote) {
|
|
14083
|
-
throw new Error("No fetch available for HTTP delete");
|
|
14084
|
-
}
|
|
14085
|
-
const home = resolveHome3(options, ctx);
|
|
14086
|
-
return deleteRollupsBySource(remote, source, {
|
|
14087
|
-
id: ensureLocalMachineId(home),
|
|
14088
|
-
hostname: defaultMachineName(),
|
|
14089
|
-
platform: process.platform
|
|
14090
|
-
}, {
|
|
14091
|
-
preserveTokens,
|
|
14092
|
-
allowHistoricalRewrite: options["purge-all"] === true
|
|
14093
|
-
});
|
|
14094
|
-
}
|
|
14095
|
-
function selectRollupsForUpload(rollups, options, now = /* @__PURE__ */ new Date()) {
|
|
14096
|
-
if (!options.force || options["purge-all"]) {
|
|
14097
|
-
return rollups;
|
|
14098
|
-
}
|
|
14099
|
-
const cutoff = now.getTime() - SESSION_REWRITE_DAYS * 24 * 60 * 60 * 1e3;
|
|
14100
|
-
return rollups.filter((rollup) => Date.parse(rollup.lastEventAt) >= cutoff);
|
|
14101
|
-
}
|
|
14102
14106
|
function shouldUseIncrementalBackfill(options) {
|
|
14103
14107
|
return !stringOption(options.since) && !stringOption(options.until) && !stringOption(options["source-root"]) && numberOption(options.limit) === void 0;
|
|
14104
14108
|
}
|
|
@@ -14557,7 +14561,7 @@ Usage:
|
|
|
14557
14561
|
vibetime uninstall [--target codex,claude,opencode,pi] [--all] [--dry-run] [--home <path>]
|
|
14558
14562
|
vibetime upgrade [--check]
|
|
14559
14563
|
vibetime hook --agent <name>
|
|
14560
|
-
vibetime backfill discover|plan|import|verify --source codex|claude-code|opencode|pi|all --dry-run [--json] [--batch-size <count>] [--force
|
|
14564
|
+
vibetime backfill discover|plan|import|verify --source codex|claude-code|opencode|pi|all --dry-run [--json] [--batch-size <count>] [--force]
|
|
14561
14565
|
vibetime token set <token>
|
|
14562
14566
|
vibetime token show
|
|
14563
14567
|
vibetime token clear
|
|
@@ -14591,10 +14595,8 @@ Environment:
|
|
|
14591
14595
|
`;
|
|
14592
14596
|
}
|
|
14593
14597
|
export {
|
|
14594
|
-
SESSION_REWRITE_DAYS,
|
|
14595
14598
|
run,
|
|
14596
14599
|
selectBackfillFilesForImport,
|
|
14597
|
-
selectRollupsForUpload,
|
|
14598
14600
|
syncLocalRunnerEntryArgs
|
|
14599
14601
|
};
|
|
14600
14602
|
const code = await run(process.argv.slice(2));process.exitCode = code;
|
package/package.json
CHANGED