@yhong91/vibetime 0.1.3 → 0.1.5
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 +148 -24
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -1195,7 +1195,7 @@ function countTextLines(text) {
|
|
|
1195
1195
|
}
|
|
1196
1196
|
|
|
1197
1197
|
// src/lib/constants.ts
|
|
1198
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
1198
|
+
var PACKAGE_VERSION = true ? "0.1.5" : "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;
|
|
@@ -3024,6 +3024,7 @@ function createClaudeCoworkAdapter() {
|
|
|
3024
3024
|
// src/adapters/codebuddy.ts
|
|
3025
3025
|
import { readFile as readFile5, readdir as readdir4 } from "node:fs/promises";
|
|
3026
3026
|
import path8 from "node:path";
|
|
3027
|
+
var ENDPOINT_MODEL_ID_RE = /^(?:ep|endpoint)-/i;
|
|
3027
3028
|
async function parseCodebuddyTraceFile(filePath, options) {
|
|
3028
3029
|
const text = await readFile5(filePath, "utf8");
|
|
3029
3030
|
const sourcePathHash = `sha256:${createStableHash(filePath)}`;
|
|
@@ -3051,7 +3052,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
3051
3052
|
}
|
|
3052
3053
|
const project = cwd ? path8.basename(cwd) : void 0;
|
|
3053
3054
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
3054
|
-
const model = trace
|
|
3055
|
+
const model = resolveCodebuddyModel(trace, spans);
|
|
3055
3056
|
const baseEvent = (event) => ({
|
|
3056
3057
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
3057
3058
|
source: "codebuddy",
|
|
@@ -3314,6 +3315,87 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
3314
3315
|
}
|
|
3315
3316
|
return events.filter((event) => validateCanonicalEvent(event).valid);
|
|
3316
3317
|
}
|
|
3318
|
+
function resolveCodebuddyModel(trace, spans) {
|
|
3319
|
+
const spanModel = modelFromSpans(spans);
|
|
3320
|
+
if (spanModel) {
|
|
3321
|
+
return spanModel;
|
|
3322
|
+
}
|
|
3323
|
+
const metadataModel = findHumanModelName(trace.metadata);
|
|
3324
|
+
if (metadataModel) {
|
|
3325
|
+
return metadataModel;
|
|
3326
|
+
}
|
|
3327
|
+
for (const candidate of trace.modelInfo?.models || []) {
|
|
3328
|
+
const normalized = normalizeModelCandidate(candidate);
|
|
3329
|
+
if (normalized) {
|
|
3330
|
+
return normalized;
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
return void 0;
|
|
3334
|
+
}
|
|
3335
|
+
function modelFromSpans(spans) {
|
|
3336
|
+
for (const span of spans) {
|
|
3337
|
+
const parsedOutput = parseEmbeddedJson(span.toolOutput);
|
|
3338
|
+
const outputModel = findHumanModelName(parsedOutput);
|
|
3339
|
+
if (outputModel) {
|
|
3340
|
+
return outputModel;
|
|
3341
|
+
}
|
|
3342
|
+
const parsedInput = parseEmbeddedJson(span.toolInput);
|
|
3343
|
+
const inputModel = findHumanModelName(parsedInput);
|
|
3344
|
+
if (inputModel) {
|
|
3345
|
+
return inputModel;
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
return void 0;
|
|
3349
|
+
}
|
|
3350
|
+
function parseEmbeddedJson(value) {
|
|
3351
|
+
if (!value?.trim()) {
|
|
3352
|
+
return void 0;
|
|
3353
|
+
}
|
|
3354
|
+
try {
|
|
3355
|
+
return JSON.parse(value);
|
|
3356
|
+
} catch {
|
|
3357
|
+
return void 0;
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
function findHumanModelName(value) {
|
|
3361
|
+
const queue = [value];
|
|
3362
|
+
while (queue.length > 0) {
|
|
3363
|
+
const current = queue.shift();
|
|
3364
|
+
if (Array.isArray(current)) {
|
|
3365
|
+
queue.push(...current);
|
|
3366
|
+
continue;
|
|
3367
|
+
}
|
|
3368
|
+
if (!isPlainObject(current)) {
|
|
3369
|
+
continue;
|
|
3370
|
+
}
|
|
3371
|
+
const preferred = [
|
|
3372
|
+
stringField(current, "requestModelName"),
|
|
3373
|
+
stringField(current, "modelName"),
|
|
3374
|
+
stringField(current, "model_name"),
|
|
3375
|
+
stringField(current, "model"),
|
|
3376
|
+
stringField(current, "requestModelId"),
|
|
3377
|
+
stringField(current, "modelId")
|
|
3378
|
+
];
|
|
3379
|
+
for (const candidate of preferred) {
|
|
3380
|
+
const normalized = normalizeModelCandidate(candidate);
|
|
3381
|
+
if (normalized) {
|
|
3382
|
+
return normalized;
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
queue.push(...Object.values(current));
|
|
3386
|
+
}
|
|
3387
|
+
return void 0;
|
|
3388
|
+
}
|
|
3389
|
+
function normalizeModelCandidate(value) {
|
|
3390
|
+
if (!value) {
|
|
3391
|
+
return void 0;
|
|
3392
|
+
}
|
|
3393
|
+
const trimmed = value.trim();
|
|
3394
|
+
if (!trimmed || ENDPOINT_MODEL_ID_RE.test(trimmed)) {
|
|
3395
|
+
return void 0;
|
|
3396
|
+
}
|
|
3397
|
+
return trimmed;
|
|
3398
|
+
}
|
|
3317
3399
|
function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
|
|
3318
3400
|
const info = trace.modelInfo;
|
|
3319
3401
|
if (!info || !info.totalInputTokens && !info.totalOutputTokens && !trace.totalTokens) {
|
|
@@ -8072,7 +8154,7 @@ async function deleteMachine(remote, id) {
|
|
|
8072
8154
|
}
|
|
8073
8155
|
|
|
8074
8156
|
// src/lib/types.ts
|
|
8075
|
-
var BACKFILL_STATE_SCHEMA_VERSION =
|
|
8157
|
+
var BACKFILL_STATE_SCHEMA_VERSION = 5;
|
|
8076
8158
|
|
|
8077
8159
|
// src/cli.ts
|
|
8078
8160
|
function createRegistry() {
|
|
@@ -8593,10 +8675,12 @@ async function importBackfillPlan(plan, options, ctx, registry) {
|
|
|
8593
8675
|
return 1;
|
|
8594
8676
|
}
|
|
8595
8677
|
const sourceDefs = registry.all().filter((a) => supportedSources.has(a.id) && (source === "all" || a.id === source)).map((a) => ({ id: a.id, label: a.label, paths: a.sourcePaths(home, ctx.env) }));
|
|
8678
|
+
const remote = resolveRemoteFromOptions(options, ctx);
|
|
8679
|
+
const remoteKey = backfillRemoteKey(remote?.baseUrl ?? DEFAULT_API_URL);
|
|
8596
8680
|
if (options.force) {
|
|
8597
|
-
await purgeForcedSources(sourceDefs, home, options, ctx);
|
|
8681
|
+
await purgeForcedSources(sourceDefs, home, remoteKey, options, ctx);
|
|
8598
8682
|
}
|
|
8599
|
-
const incrementalState = shouldUseIncrementalBackfill(options) ? await readBackfillIncrementalState(home, ctx) : void 0;
|
|
8683
|
+
const incrementalState = shouldUseIncrementalBackfill(options) ? await readBackfillIncrementalState(home, remoteKey, ctx) : void 0;
|
|
8600
8684
|
if (!options.json) {
|
|
8601
8685
|
write(ctx.stdout, `importRun ${plan.importRun.importRunId}
|
|
8602
8686
|
`);
|
|
@@ -8624,13 +8708,15 @@ async function importBackfillPlan(plan, options, ctx, registry) {
|
|
|
8624
8708
|
`);
|
|
8625
8709
|
}
|
|
8626
8710
|
if (counts.failed === 0 && counts.conflicts === 0 && incrementalState) {
|
|
8627
|
-
await updateBackfillIncrementalState(home, incrementalState, selectedFilesBySource);
|
|
8711
|
+
await updateBackfillIncrementalState(home, remoteKey, incrementalState, selectedFilesBySource);
|
|
8628
8712
|
}
|
|
8629
8713
|
return counts.failed > 0 || counts.conflicts > 0 && !options["skip-conflicts"] ? 1 : 0;
|
|
8630
8714
|
}
|
|
8631
|
-
async function purgeForcedSources(sourceDefs, home, options, ctx) {
|
|
8715
|
+
async function purgeForcedSources(sourceDefs, home, remoteKey, options, ctx) {
|
|
8632
8716
|
try {
|
|
8633
|
-
await
|
|
8717
|
+
const file = await readBackfillIncrementalStateFile(home);
|
|
8718
|
+
delete file.remotes[remoteKey];
|
|
8719
|
+
await writeBackfillIncrementalStateFile(home, file);
|
|
8634
8720
|
} catch (error) {
|
|
8635
8721
|
debug(ctx, `Failed to clear backfill watermark: ${error.message}
|
|
8636
8722
|
`);
|
|
@@ -8826,36 +8912,75 @@ function syncLocalTriggerStatePath(home) {
|
|
|
8826
8912
|
function syncLocalTriggerLockPath(home) {
|
|
8827
8913
|
return path18.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
8828
8914
|
}
|
|
8829
|
-
|
|
8915
|
+
function backfillRemoteKey(baseUrl) {
|
|
8916
|
+
try {
|
|
8917
|
+
const url = new URL(baseUrl);
|
|
8918
|
+
return `${url.protocol}//${url.host}${url.pathname.replace(/\/+$/, "")}`;
|
|
8919
|
+
} catch {
|
|
8920
|
+
return baseUrl.replace(/\/+$/, "");
|
|
8921
|
+
}
|
|
8922
|
+
}
|
|
8923
|
+
function sanitizeBackfillSources(raw) {
|
|
8924
|
+
const sources = {};
|
|
8925
|
+
if (!isPlainObject(raw)) {
|
|
8926
|
+
return sources;
|
|
8927
|
+
}
|
|
8928
|
+
for (const source of BACKFILL_SOURCE_IDS) {
|
|
8929
|
+
const item = raw[source];
|
|
8930
|
+
if (isPlainObject(item) && typeof item.watermarkTs === "string" && !Number.isNaN(Date.parse(item.watermarkTs))) {
|
|
8931
|
+
sources[source] = { watermarkTs: item.watermarkTs };
|
|
8932
|
+
}
|
|
8933
|
+
}
|
|
8934
|
+
return sources;
|
|
8935
|
+
}
|
|
8936
|
+
async function readBackfillIncrementalStateFile(home, ctx) {
|
|
8937
|
+
const empty = { version: BACKFILL_STATE_SCHEMA_VERSION, remotes: {} };
|
|
8830
8938
|
const statePath = backfillIncrementalStatePath(home);
|
|
8831
8939
|
const state = await readJsonIfExists(statePath);
|
|
8832
8940
|
if (state === null) {
|
|
8833
|
-
return
|
|
8941
|
+
return empty;
|
|
8834
8942
|
}
|
|
8835
|
-
if (!isPlainObject(state)
|
|
8943
|
+
if (!isPlainObject(state)) {
|
|
8836
8944
|
if (ctx) {
|
|
8837
8945
|
debug(ctx, `backfill-state malformed at ${statePath}; ignoring watermarks
|
|
8838
8946
|
`);
|
|
8839
8947
|
}
|
|
8840
|
-
return
|
|
8948
|
+
return empty;
|
|
8841
8949
|
}
|
|
8842
8950
|
if (state.version !== BACKFILL_STATE_SCHEMA_VERSION) {
|
|
8843
8951
|
if (ctx) {
|
|
8844
8952
|
debug(ctx, `backfill-state version ${String(state.version)} at ${statePath} differs from current v${BACKFILL_STATE_SCHEMA_VERSION}; dropping watermarks so the next sync re-imports under the new parser
|
|
8845
8953
|
`);
|
|
8846
8954
|
}
|
|
8847
|
-
return
|
|
8955
|
+
return empty;
|
|
8848
8956
|
}
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8957
|
+
if (!isPlainObject(state.remotes)) {
|
|
8958
|
+
if (ctx) {
|
|
8959
|
+
debug(ctx, `backfill-state malformed at ${statePath}; ignoring watermarks
|
|
8960
|
+
`);
|
|
8961
|
+
}
|
|
8962
|
+
return empty;
|
|
8963
|
+
}
|
|
8964
|
+
const remotes = {};
|
|
8965
|
+
for (const [remoteKey, entry] of Object.entries(state.remotes)) {
|
|
8966
|
+
if (!isPlainObject(entry)) {
|
|
8967
|
+
continue;
|
|
8854
8968
|
}
|
|
8969
|
+
remotes[remoteKey] = { sources: sanitizeBackfillSources(entry.sources) };
|
|
8855
8970
|
}
|
|
8856
|
-
return { version: BACKFILL_STATE_SCHEMA_VERSION,
|
|
8971
|
+
return { version: BACKFILL_STATE_SCHEMA_VERSION, remotes };
|
|
8857
8972
|
}
|
|
8858
|
-
async function
|
|
8973
|
+
async function writeBackfillIncrementalStateFile(home, file) {
|
|
8974
|
+
const statePath = backfillIncrementalStatePath(home);
|
|
8975
|
+
await mkdir4(path18.dirname(statePath), { recursive: true });
|
|
8976
|
+
await writeFile3(statePath, `${JSON.stringify(file, null, 2)}
|
|
8977
|
+
`, "utf8");
|
|
8978
|
+
}
|
|
8979
|
+
async function readBackfillIncrementalState(home, remoteKey, ctx) {
|
|
8980
|
+
const file = await readBackfillIncrementalStateFile(home, ctx);
|
|
8981
|
+
return { version: BACKFILL_STATE_SCHEMA_VERSION, sources: file.remotes[remoteKey]?.sources ?? {} };
|
|
8982
|
+
}
|
|
8983
|
+
async function updateBackfillIncrementalState(home, remoteKey, state, selectedFilesBySource) {
|
|
8859
8984
|
for (const [source, files] of selectedFilesBySource.entries()) {
|
|
8860
8985
|
const latest = maxTimestamp(files.map((f) => f.modifiedAt));
|
|
8861
8986
|
if (!latest) {
|
|
@@ -8863,10 +8988,9 @@ async function updateBackfillIncrementalState(home, state, selectedFilesBySource
|
|
|
8863
8988
|
}
|
|
8864
8989
|
state.sources[source] = { watermarkTs: latest };
|
|
8865
8990
|
}
|
|
8866
|
-
const
|
|
8867
|
-
|
|
8868
|
-
await
|
|
8869
|
-
`, "utf8");
|
|
8991
|
+
const file = await readBackfillIncrementalStateFile(home);
|
|
8992
|
+
file.remotes[remoteKey] = { sources: state.sources };
|
|
8993
|
+
await writeBackfillIncrementalStateFile(home, file);
|
|
8870
8994
|
}
|
|
8871
8995
|
async function readSyncLocalTriggerState(statePath) {
|
|
8872
8996
|
let state;
|
package/package.json
CHANGED