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