@yhong91/vibetime 0.1.34 → 0.1.36
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 +165 -32
- 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.
|
|
1931
|
+
var PACKAGE_VERSION = true ? "0.1.36" : "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;
|
|
@@ -4248,7 +4248,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
4248
4248
|
confidence: "partial"
|
|
4249
4249
|
}), 0, "trace");
|
|
4250
4250
|
}
|
|
4251
|
-
if (
|
|
4251
|
+
if (traceStartedAt) {
|
|
4252
4252
|
const turnId = `turn_${createStableHash([sessionId, trace.traceId]).slice(0, 24)}`;
|
|
4253
4253
|
push(baseEvent({
|
|
4254
4254
|
ts: traceStartedAt,
|
|
@@ -4260,23 +4260,25 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
4260
4260
|
model,
|
|
4261
4261
|
confidence: "partial"
|
|
4262
4262
|
}), 0, "trace");
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4263
|
+
if (trace.prompt) {
|
|
4264
|
+
push(baseEvent({
|
|
4265
|
+
ts: traceStartedAt,
|
|
4266
|
+
type: "prompt.submitted",
|
|
4267
|
+
sessionId,
|
|
4268
|
+
turnId,
|
|
4269
|
+
cwd,
|
|
4270
|
+
project,
|
|
4271
|
+
model,
|
|
4272
|
+
confidence: "partial",
|
|
4273
|
+
metrics: {
|
|
4274
|
+
prompts: 1,
|
|
4275
|
+
promptChars: trace.prompt.length
|
|
4276
|
+
},
|
|
4277
|
+
refs: stringRefs({
|
|
4278
|
+
promptHash: `sha256:${createStableHash(trace.prompt)}`
|
|
4279
|
+
})
|
|
4280
|
+
}), 0, "trace");
|
|
4281
|
+
}
|
|
4280
4282
|
if (traceEndedAt) {
|
|
4281
4283
|
push(baseEvent({
|
|
4282
4284
|
ts: traceEndedAt,
|
|
@@ -9148,7 +9150,6 @@ function normalizeId(id) {
|
|
|
9148
9150
|
// src/adapters/workbuddy.ts
|
|
9149
9151
|
import { readFile as readFile12, readdir as readdir9, stat as stat10 } from "node:fs/promises";
|
|
9150
9152
|
import path19 from "node:path";
|
|
9151
|
-
init_fs();
|
|
9152
9153
|
function workbuddyProjectsDir(home, env) {
|
|
9153
9154
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
9154
9155
|
if (override && override.trim()) {
|
|
@@ -9156,6 +9157,13 @@ function workbuddyProjectsDir(home, env) {
|
|
|
9156
9157
|
}
|
|
9157
9158
|
return path19.join(home, ".workbuddy", "projects");
|
|
9158
9159
|
}
|
|
9160
|
+
function workbuddyBaseDir(home, env) {
|
|
9161
|
+
const override = env?.WORKBUDDY_HOME;
|
|
9162
|
+
if (override && override.trim()) {
|
|
9163
|
+
return path19.resolve(override);
|
|
9164
|
+
}
|
|
9165
|
+
return path19.join(home, ".workbuddy");
|
|
9166
|
+
}
|
|
9159
9167
|
function projectFromCwd(cwd, fallback) {
|
|
9160
9168
|
if (!cwd) {
|
|
9161
9169
|
return fallback;
|
|
@@ -9180,12 +9188,13 @@ function workbuddyUsageMetrics(record) {
|
|
|
9180
9188
|
const providerData = objectField(record, "providerData");
|
|
9181
9189
|
const usage = objectField(providerData, "usage");
|
|
9182
9190
|
const rawUsage = objectField(providerData, "rawUsage");
|
|
9183
|
-
|
|
9191
|
+
const messageUsage = objectField(objectField(record, "message"), "usage");
|
|
9192
|
+
if (Object.keys(usage).length === 0 && Object.keys(rawUsage).length === 0 && Object.keys(messageUsage).length === 0) {
|
|
9184
9193
|
return void 0;
|
|
9185
9194
|
}
|
|
9186
|
-
const input = numberField(usage, "inputTokens") ?? numberField(rawUsage, "prompt_tokens") ?? 0;
|
|
9187
|
-
const output = numberField(usage, "outputTokens") ?? numberField(rawUsage, "completion_tokens") ?? 0;
|
|
9188
|
-
const total = numberField(usage, "totalTokens") ?? numberField(rawUsage, "total_tokens") ?? 0;
|
|
9195
|
+
const input = numberField(usage, "inputTokens") ?? numberField(rawUsage, "prompt_tokens") ?? numberField(messageUsage, "input_tokens") ?? 0;
|
|
9196
|
+
const output = numberField(usage, "outputTokens") ?? numberField(rawUsage, "completion_tokens") ?? numberField(messageUsage, "output_tokens") ?? 0;
|
|
9197
|
+
const total = numberField(usage, "totalTokens") ?? numberField(rawUsage, "total_tokens") ?? numberField(messageUsage, "total_tokens") ?? 0;
|
|
9189
9198
|
const cacheRead = workbuddyCachedTokens(usage, rawUsage);
|
|
9190
9199
|
const cacheCreate = numberField(rawUsage, "cache_creation_input_tokens") ?? numberField(rawUsage, "prompt_cache_write_tokens") ?? 0;
|
|
9191
9200
|
const reasoning = workbuddyReasoningTokens(usage, rawUsage);
|
|
@@ -9242,6 +9251,40 @@ function contentLength(value) {
|
|
|
9242
9251
|
}
|
|
9243
9252
|
return 0;
|
|
9244
9253
|
}
|
|
9254
|
+
function isHiddenUserMessage(record) {
|
|
9255
|
+
const providerData = objectField(record, "providerData");
|
|
9256
|
+
return providerData.skipRun === true || providerData.isMeta === true || providerData.isCompactInternal === true || providerData.isCompact === true || providerData.isTeammateMessage === true || (stringField(providerData, "agentPurpose") || "").toLowerCase().includes("compact");
|
|
9257
|
+
}
|
|
9258
|
+
function workbuddySubagentRefs(lines) {
|
|
9259
|
+
const refs2 = {};
|
|
9260
|
+
const keys = [
|
|
9261
|
+
["parentSessionId", ["parent_session_id", "parentSessionId"]],
|
|
9262
|
+
["parentToolCallId", ["parent_tool_call_id", "parentToolCallId"]],
|
|
9263
|
+
["subagentId", ["agent_id", "agentId"]],
|
|
9264
|
+
["subagentType", ["agent_type", "agentType"]]
|
|
9265
|
+
];
|
|
9266
|
+
for (const line of lines) {
|
|
9267
|
+
const providerData = objectField(line.record, "providerData");
|
|
9268
|
+
for (const [ref, aliases] of keys) {
|
|
9269
|
+
if (refs2[ref]) {
|
|
9270
|
+
continue;
|
|
9271
|
+
}
|
|
9272
|
+
for (const alias of aliases) {
|
|
9273
|
+
const value = stringField(line.record, alias) || stringField(providerData, alias);
|
|
9274
|
+
if (value) {
|
|
9275
|
+
refs2[ref] = value;
|
|
9276
|
+
break;
|
|
9277
|
+
}
|
|
9278
|
+
}
|
|
9279
|
+
}
|
|
9280
|
+
}
|
|
9281
|
+
return refs2;
|
|
9282
|
+
}
|
|
9283
|
+
function toolCallFailed(record) {
|
|
9284
|
+
const providerData = objectField(record, "providerData");
|
|
9285
|
+
const status = stringField(record, "status");
|
|
9286
|
+
return status === "failed" || status === "incomplete" || record.is_error === true || providerData.error != null || providerData.isError === true;
|
|
9287
|
+
}
|
|
9245
9288
|
async function readWorkbuddyLines(filePath) {
|
|
9246
9289
|
const text = await readFile12(filePath, "utf8");
|
|
9247
9290
|
return text.split(/\r?\n/).map((line, index) => {
|
|
@@ -9270,8 +9313,32 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9270
9313
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
9271
9314
|
const sessionPrefix = `workbuddy:${sessionId}`;
|
|
9272
9315
|
const toolStarts = /* @__PURE__ */ new Map();
|
|
9316
|
+
const subagentRefs = workbuddySubagentRefs(lines);
|
|
9273
9317
|
let currentTurnId = `${sessionPrefix}:turn:0`;
|
|
9274
9318
|
let turnIndex = 0;
|
|
9319
|
+
let turnLastTs;
|
|
9320
|
+
let turnSawResponse = false;
|
|
9321
|
+
let turnLastAssistantStatus;
|
|
9322
|
+
const closeTurn = (line) => {
|
|
9323
|
+
if (turnIndex === 0 || !turnSawResponse || !turnLastTs) {
|
|
9324
|
+
return void 0;
|
|
9325
|
+
}
|
|
9326
|
+
const failed = turnLastAssistantStatus !== void 0 && ["incomplete", "failed", "cancelled"].includes(turnLastAssistantStatus);
|
|
9327
|
+
return makeEvent({
|
|
9328
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9329
|
+
ts: turnLastTs,
|
|
9330
|
+
type: failed ? "turn.failed" : "turn.completed",
|
|
9331
|
+
source: "workbuddy",
|
|
9332
|
+
workspaceId,
|
|
9333
|
+
project,
|
|
9334
|
+
cwd,
|
|
9335
|
+
sessionId: sessionPrefix,
|
|
9336
|
+
turnId: currentTurnId,
|
|
9337
|
+
agent: "workbuddy",
|
|
9338
|
+
confidence: "derived",
|
|
9339
|
+
refs: { sourceId: `${currentTurnId}:end` }
|
|
9340
|
+
}, line, filePath, options);
|
|
9341
|
+
};
|
|
9275
9342
|
const firstTs = lines.map((line) => timestampFrom(numberField(line.record, "timestamp"))).find(Boolean);
|
|
9276
9343
|
if (firstTs) {
|
|
9277
9344
|
const event = makeEvent({
|
|
@@ -9285,7 +9352,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9285
9352
|
sessionId: sessionPrefix,
|
|
9286
9353
|
agent: "workbuddy",
|
|
9287
9354
|
confidence: "derived",
|
|
9288
|
-
refs: { sourceId: `${sessionPrefix}:session
|
|
9355
|
+
refs: { sourceId: `${sessionPrefix}:session`, ...subagentRefs }
|
|
9289
9356
|
}, lines[0], filePath, options);
|
|
9290
9357
|
if (event) events.push(event);
|
|
9291
9358
|
}
|
|
@@ -9298,8 +9365,16 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9298
9365
|
const type = stringField(record, "type");
|
|
9299
9366
|
const sourceId = stringField(record, "id") || `${line.lineNumber}`;
|
|
9300
9367
|
if (type === "message" && stringField(record, "role") === "user") {
|
|
9368
|
+
if (isHiddenUserMessage(record)) {
|
|
9369
|
+
continue;
|
|
9370
|
+
}
|
|
9371
|
+
const ended = closeTurn(line);
|
|
9372
|
+
if (ended) events.push(ended);
|
|
9301
9373
|
turnIndex += 1;
|
|
9302
9374
|
currentTurnId = `${sessionPrefix}:turn:${turnIndex}`;
|
|
9375
|
+
turnLastTs = ts;
|
|
9376
|
+
turnSawResponse = false;
|
|
9377
|
+
turnLastAssistantStatus = void 0;
|
|
9303
9378
|
const promptChars = contentLength(record.content);
|
|
9304
9379
|
for (const event of [
|
|
9305
9380
|
makeEvent({
|
|
@@ -9336,7 +9411,36 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9336
9411
|
}
|
|
9337
9412
|
continue;
|
|
9338
9413
|
}
|
|
9414
|
+
if (type === "message" && stringField(record, "role") === "assistant") {
|
|
9415
|
+
turnLastTs = ts;
|
|
9416
|
+
turnSawResponse = true;
|
|
9417
|
+
turnLastAssistantStatus = stringField(record, "status") || turnLastAssistantStatus;
|
|
9418
|
+
const metrics = workbuddyUsageMetrics(record);
|
|
9419
|
+
if (metrics) {
|
|
9420
|
+
const model = stringField(objectField(record, "providerData"), "model");
|
|
9421
|
+
const usage = makeEvent({
|
|
9422
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9423
|
+
ts,
|
|
9424
|
+
type: "model.usage",
|
|
9425
|
+
source: "workbuddy",
|
|
9426
|
+
workspaceId,
|
|
9427
|
+
project,
|
|
9428
|
+
cwd,
|
|
9429
|
+
sessionId: sessionPrefix,
|
|
9430
|
+
turnId: currentTurnId,
|
|
9431
|
+
agent: "workbuddy",
|
|
9432
|
+
model,
|
|
9433
|
+
metrics,
|
|
9434
|
+
confidence: "partial",
|
|
9435
|
+
refs: { sourceId: `${sourceId}:usage` }
|
|
9436
|
+
}, line, filePath, options);
|
|
9437
|
+
if (usage) events.push(usage);
|
|
9438
|
+
}
|
|
9439
|
+
continue;
|
|
9440
|
+
}
|
|
9339
9441
|
if (type === "function_call") {
|
|
9442
|
+
turnLastTs = ts;
|
|
9443
|
+
turnSawResponse = true;
|
|
9340
9444
|
const tool = stringField(record, "name");
|
|
9341
9445
|
const callId = stringField(record, "callId");
|
|
9342
9446
|
if (tool && callId) {
|
|
@@ -9383,15 +9487,16 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9383
9487
|
continue;
|
|
9384
9488
|
}
|
|
9385
9489
|
if (type === "function_call_result") {
|
|
9490
|
+
turnLastTs = ts;
|
|
9386
9491
|
const tool = stringField(record, "name") || "tool";
|
|
9387
9492
|
const callId = stringField(record, "callId") || `${line.lineNumber}`;
|
|
9388
9493
|
const start = toolStarts.get(`${sessionId}:${callId}`);
|
|
9389
9494
|
const durationMs = start?.ts ? Math.max(0, Date.parse(ts) - Date.parse(start.ts)) : void 0;
|
|
9390
|
-
const
|
|
9495
|
+
const failed = toolCallFailed(record);
|
|
9391
9496
|
const completed = makeEvent({
|
|
9392
9497
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9393
9498
|
ts,
|
|
9394
|
-
type:
|
|
9499
|
+
type: failed ? "tool.failed" : "tool.completed",
|
|
9395
9500
|
source: "workbuddy",
|
|
9396
9501
|
workspaceId,
|
|
9397
9502
|
project,
|
|
@@ -9401,7 +9506,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9401
9506
|
spanId: `${sessionPrefix}:tool:${callId}`,
|
|
9402
9507
|
agent: "workbuddy",
|
|
9403
9508
|
tool,
|
|
9404
|
-
success:
|
|
9509
|
+
success: !failed,
|
|
9405
9510
|
metrics: { toolDurationMs: durationMs, durationMs },
|
|
9406
9511
|
confidence: start ? "derived" : "partial",
|
|
9407
9512
|
refs: { sourceId: `${callId}:result` }
|
|
@@ -9410,6 +9515,10 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9410
9515
|
}
|
|
9411
9516
|
}
|
|
9412
9517
|
const lastLine = lines.at(-1);
|
|
9518
|
+
if (lastLine) {
|
|
9519
|
+
const ended = closeTurn(lastLine);
|
|
9520
|
+
if (ended) events.push(ended);
|
|
9521
|
+
}
|
|
9413
9522
|
const lastTs = lastLine ? timestampFrom(numberField(lastLine.record, "timestamp")) : void 0;
|
|
9414
9523
|
if (lastLine && lastTs) {
|
|
9415
9524
|
const event = makeEvent({
|
|
@@ -9453,6 +9562,23 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
9453
9562
|
}
|
|
9454
9563
|
return files.sort((a, b) => a.path.localeCompare(b.path));
|
|
9455
9564
|
}
|
|
9565
|
+
var workbuddyHandler = (msg) => hookHandler("workbuddy", msg);
|
|
9566
|
+
function hookConfig8() {
|
|
9567
|
+
const anyTool = [{ matcher: ".*", hooks: [workbuddyHandler("Reporting tool activity")] }];
|
|
9568
|
+
return {
|
|
9569
|
+
hooks: {
|
|
9570
|
+
SessionEnd: [{ hooks: [workbuddyHandler("Reporting session end")] }],
|
|
9571
|
+
UserPromptSubmit: [{ hooks: [workbuddyHandler("Reporting prompt activity")] }],
|
|
9572
|
+
PreToolUse: anyTool,
|
|
9573
|
+
PostToolUse: anyTool,
|
|
9574
|
+
PostToolUseFailure: anyTool,
|
|
9575
|
+
Stop: [{ hooks: [workbuddyHandler("Reporting turn completion")] }],
|
|
9576
|
+
StopFailure: [{ hooks: [workbuddyHandler("Reporting turn failure")] }],
|
|
9577
|
+
SubagentStart: anyTool,
|
|
9578
|
+
SubagentStop: [{ hooks: [workbuddyHandler("Reporting subagent completion")] }]
|
|
9579
|
+
}
|
|
9580
|
+
};
|
|
9581
|
+
}
|
|
9456
9582
|
function createWorkbuddyAdapter() {
|
|
9457
9583
|
return {
|
|
9458
9584
|
id: "workbuddy",
|
|
@@ -9463,13 +9589,20 @@ function createWorkbuddyAdapter() {
|
|
|
9463
9589
|
return workbuddyProjectsDir(home, env);
|
|
9464
9590
|
},
|
|
9465
9591
|
installedPath(home, env) {
|
|
9466
|
-
return
|
|
9592
|
+
return path19.join(workbuddyBaseDir(home, env), "settings.json");
|
|
9467
9593
|
},
|
|
9468
9594
|
async isInstalled(home, env) {
|
|
9469
|
-
return
|
|
9595
|
+
return isHooksJsonInstalled(
|
|
9596
|
+
path19.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
9597
|
+
"vibetime hook --agent workbuddy"
|
|
9598
|
+
);
|
|
9470
9599
|
},
|
|
9471
|
-
installEntries() {
|
|
9472
|
-
return [
|
|
9600
|
+
installEntries(home, env) {
|
|
9601
|
+
return [{
|
|
9602
|
+
kind: "hooks-json",
|
|
9603
|
+
path: path19.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
9604
|
+
content: hookConfig8()
|
|
9605
|
+
}];
|
|
9473
9606
|
},
|
|
9474
9607
|
sourcePaths(home, env) {
|
|
9475
9608
|
return [workbuddyProjectsDir(home, env)];
|
package/package.json
CHANGED