@yhong91/vibetime 0.1.61 → 0.1.62
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 +122 -106
- 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.62" : "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;
|
|
@@ -3364,9 +3364,12 @@ async function isHooksJsonInstalled(filePath, command) {
|
|
|
3364
3364
|
if (!isPlainObject(config) || !isPlainObject(config.hooks)) {
|
|
3365
3365
|
return false;
|
|
3366
3366
|
}
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3367
|
+
const hookScopes = [config.hooks, isPlainObject(config.hooks.events) ? config.hooks.events : {}];
|
|
3368
|
+
return hookScopes.some(
|
|
3369
|
+
(scope) => Object.values(scope).some(
|
|
3370
|
+
(groups) => Array.isArray(groups) && groups.some(
|
|
3371
|
+
(group) => isPlainObject(group) && Array.isArray(group.hooks) && group.hooks.some((hook) => hook.command === command)
|
|
3372
|
+
)
|
|
3370
3373
|
)
|
|
3371
3374
|
);
|
|
3372
3375
|
} catch {
|
|
@@ -3375,11 +3378,7 @@ async function isHooksJsonInstalled(filePath, command) {
|
|
|
3375
3378
|
}
|
|
3376
3379
|
|
|
3377
3380
|
// src/adapters/claude-code.ts
|
|
3378
|
-
init_fs();
|
|
3379
3381
|
async function parseClaudeCodeSessionFile(filePath, options) {
|
|
3380
|
-
if (path7.basename(filePath) === "usage.jsonl" && path7.basename(path7.dirname(filePath)) === ".viberouter") {
|
|
3381
|
-
return parseClaudeRouterUsageFile(filePath, options);
|
|
3382
|
-
}
|
|
3383
3382
|
const text = await readFile3(filePath, "utf8");
|
|
3384
3383
|
const lines = text.split("\n").filter(Boolean);
|
|
3385
3384
|
const projectContext = await claudeProjectContextFromLines(filePath, lines, options);
|
|
@@ -3646,86 +3645,6 @@ async function parseClaudeCodeSessionFile(filePath, options) {
|
|
|
3646
3645
|
}
|
|
3647
3646
|
return state.events.filter((event) => validateCanonicalEvent(event).valid);
|
|
3648
3647
|
}
|
|
3649
|
-
async function parseClaudeRouterUsageFile(filePath, options) {
|
|
3650
|
-
const rows = (await readFile3(filePath, "utf8")).split("\n").map(parseJsonLine).filter((row) => Boolean(
|
|
3651
|
-
row && row.surface === "claude" && (numberField(row, "timestamp") ?? 0) > 0 && Object.keys(objectField(row, "usage")).length > 0
|
|
3652
|
-
));
|
|
3653
|
-
if (rows.length === 0) {
|
|
3654
|
-
return [];
|
|
3655
|
-
}
|
|
3656
|
-
const timestamps = rows.map((row) => numberField(row, "timestamp") ?? 0);
|
|
3657
|
-
const firstTs = Math.min(...timestamps) - 6e4;
|
|
3658
|
-
const lastTs = Math.max(...timestamps) + 6e4;
|
|
3659
|
-
const home = path7.resolve(stringOption(options.home) || path7.dirname(path7.dirname(filePath)));
|
|
3660
|
-
const transcriptCounts = /* @__PURE__ */ new Map();
|
|
3661
|
-
for (const transcript of await listJsonlFiles(path7.join(claudeConfigDir(home, process.env), "projects"))) {
|
|
3662
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3663
|
-
for (const line of (await readFile3(transcript, "utf8")).split("\n")) {
|
|
3664
|
-
const raw = parseJsonLine(line);
|
|
3665
|
-
const ts = raw ? Date.parse(timestampFrom(raw.timestamp) || "") : Number.NaN;
|
|
3666
|
-
if (!raw || stringField(raw, "type") !== "assistant" || ts < firstTs || ts > lastTs) {
|
|
3667
|
-
continue;
|
|
3668
|
-
}
|
|
3669
|
-
const message = objectField(raw, "message");
|
|
3670
|
-
const messageId = stringField(message, "id");
|
|
3671
|
-
const usageKey = messageId ? `${messageId}:${stringField(raw, "requestId")}` : null;
|
|
3672
|
-
if (usageKey && seen.has(usageKey)) {
|
|
3673
|
-
continue;
|
|
3674
|
-
}
|
|
3675
|
-
if (usageKey) {
|
|
3676
|
-
seen.add(usageKey);
|
|
3677
|
-
}
|
|
3678
|
-
const usage = claudeUsageFromMessage(message);
|
|
3679
|
-
if (!usage) {
|
|
3680
|
-
continue;
|
|
3681
|
-
}
|
|
3682
|
-
const key = `${usage.tokensInput || 0}:${usage.tokensOutput || 0}`;
|
|
3683
|
-
transcriptCounts.set(key, (transcriptCounts.get(key) || 0) + 1);
|
|
3684
|
-
}
|
|
3685
|
-
}
|
|
3686
|
-
const sourcePathHash = `sha256:${createStableHash(filePath)}`;
|
|
3687
|
-
const events = [];
|
|
3688
|
-
for (const row of rows) {
|
|
3689
|
-
const usage = objectField(row, "usage");
|
|
3690
|
-
const input = numberField(usage, "inputTokens") || 0;
|
|
3691
|
-
const output = numberField(usage, "outputTokens") || 0;
|
|
3692
|
-
const key = `${input}:${output}`;
|
|
3693
|
-
const matched = transcriptCounts.get(key) || 0;
|
|
3694
|
-
if (matched > 0) {
|
|
3695
|
-
transcriptCounts.set(key, matched - 1);
|
|
3696
|
-
continue;
|
|
3697
|
-
}
|
|
3698
|
-
const timestamp = numberField(row, "timestamp") ?? 0;
|
|
3699
|
-
const requestId = stringField(row, "requestId") || createStableHash(row).slice(0, 24);
|
|
3700
|
-
const cacheCreation = numberField(usage, "cacheCreationInputTokens") || 0;
|
|
3701
|
-
const cacheRead = numberField(usage, "cacheReadInputTokens") || 0;
|
|
3702
|
-
const cached = numberField(usage, "cachedInputTokens") || cacheCreation + cacheRead;
|
|
3703
|
-
const event = baseClaudeEvent({
|
|
3704
|
-
ts: new Date(timestamp).toISOString(),
|
|
3705
|
-
type: "model.usage",
|
|
3706
|
-
sessionId: `viberouter:${new Date(timestamp).toISOString().slice(0, 10)}`,
|
|
3707
|
-
project: "unknown",
|
|
3708
|
-
model: stringField(row, "resolvedModel") || stringField(row, "requestedModel") || stringField(row, "model"),
|
|
3709
|
-
provider: stringField(row, "provider"),
|
|
3710
|
-
confidence: "exact",
|
|
3711
|
-
metrics: {
|
|
3712
|
-
tokensInput: input || void 0,
|
|
3713
|
-
tokensCachedInput: cached || void 0,
|
|
3714
|
-
tokensCacheCreationInput: cacheCreation || void 0,
|
|
3715
|
-
tokensCacheReadInput: cacheRead || void 0,
|
|
3716
|
-
tokensOutput: output || void 0,
|
|
3717
|
-
tokensReasoningOutput: numberField(usage, "reasoningOutputTokens") || void 0,
|
|
3718
|
-
tokensTotal: numberField(usage, "totalTokens") || input + output || void 0,
|
|
3719
|
-
modelCalls: 1
|
|
3720
|
-
},
|
|
3721
|
-
refs: stringRefs({ sourceId: requestId, sourcePathHash, importKey: `claude-code:viberouter:${requestId}` })
|
|
3722
|
-
});
|
|
3723
|
-
if (validateCanonicalEvent(event).valid) {
|
|
3724
|
-
events.push(event);
|
|
3725
|
-
}
|
|
3726
|
-
}
|
|
3727
|
-
return events;
|
|
3728
|
-
}
|
|
3729
3648
|
function baseClaudeEvent(event) {
|
|
3730
3649
|
return {
|
|
3731
3650
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -4062,7 +3981,6 @@ function createClaudeCodeAdapter() {
|
|
|
4062
3981
|
const base = claudeConfigDir(home, env);
|
|
4063
3982
|
return [
|
|
4064
3983
|
path7.join(base, "projects"),
|
|
4065
|
-
path7.join(home, ".viberouter", "usage.jsonl"),
|
|
4066
3984
|
path7.join(base, ".claude.json"),
|
|
4067
3985
|
path7.join(home, ".claude.json")
|
|
4068
3986
|
];
|
|
@@ -13233,7 +13151,6 @@ import { execFile } from "node:child_process";
|
|
|
13233
13151
|
import { readFile as readFile15, stat as stat14 } from "node:fs/promises";
|
|
13234
13152
|
import path22 from "node:path";
|
|
13235
13153
|
import { promisify as promisify2 } from "node:util";
|
|
13236
|
-
init_fs();
|
|
13237
13154
|
var execFileAsync = promisify2(execFile);
|
|
13238
13155
|
function zcodeCliDir(home, env) {
|
|
13239
13156
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
@@ -13245,6 +13162,27 @@ function zcodeCliDir(home, env) {
|
|
|
13245
13162
|
function zcodeDbPath(home, env) {
|
|
13246
13163
|
return path22.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
13247
13164
|
}
|
|
13165
|
+
function zcodeConfigPath(home, env) {
|
|
13166
|
+
return path22.join(zcodeCliDir(home, env), "config.json");
|
|
13167
|
+
}
|
|
13168
|
+
var zcodeHandler = (msg) => hookHandler("zcode", msg);
|
|
13169
|
+
function hookConfig9() {
|
|
13170
|
+
const anyTool = [{ matcher: ".*", hooks: [zcodeHandler("Reporting tool activity")] }];
|
|
13171
|
+
return {
|
|
13172
|
+
hooks: {
|
|
13173
|
+
enabled: true,
|
|
13174
|
+
events: {
|
|
13175
|
+
SessionStart: [{ hooks: [zcodeHandler("Reporting session start")] }],
|
|
13176
|
+
UserPromptSubmit: [{ hooks: [zcodeHandler("Reporting prompt activity")] }],
|
|
13177
|
+
PreToolUse: anyTool,
|
|
13178
|
+
PermissionRequest: anyTool,
|
|
13179
|
+
PostToolUse: anyTool,
|
|
13180
|
+
PostToolUseFailure: anyTool,
|
|
13181
|
+
Stop: [{ hooks: [zcodeHandler("Reporting turn completion")] }]
|
|
13182
|
+
}
|
|
13183
|
+
}
|
|
13184
|
+
};
|
|
13185
|
+
}
|
|
13248
13186
|
var providerNameCache = null;
|
|
13249
13187
|
async function loadProviderNames(configPath2) {
|
|
13250
13188
|
let fileMtime = 0;
|
|
@@ -13326,10 +13264,14 @@ async function readZCodeRows(dbPath) {
|
|
|
13326
13264
|
'id',id,
|
|
13327
13265
|
'parent_id',parent_id,
|
|
13328
13266
|
'directory',directory,
|
|
13267
|
+
'workspace_id',workspace_id,
|
|
13329
13268
|
'title',title,
|
|
13330
13269
|
'task_type',task_type,
|
|
13331
13270
|
'time_created',time_created,
|
|
13332
|
-
'time_updated',time_updated
|
|
13271
|
+
'time_updated',time_updated,
|
|
13272
|
+
'summary_additions',summary_additions,
|
|
13273
|
+
'summary_deletions',summary_deletions,
|
|
13274
|
+
'summary_files',summary_files
|
|
13333
13275
|
) from session order by time_created, id;`,
|
|
13334
13276
|
`select json_object(
|
|
13335
13277
|
'kind','turn',
|
|
@@ -13356,6 +13298,7 @@ async function readZCodeRows(dbPath) {
|
|
|
13356
13298
|
'query_source',query_source,
|
|
13357
13299
|
'provider_id',provider_id,
|
|
13358
13300
|
'model_id',model_id,
|
|
13301
|
+
'variant',variant,
|
|
13359
13302
|
'agent',agent,
|
|
13360
13303
|
'mode',mode,
|
|
13361
13304
|
'status',status,
|
|
@@ -13369,7 +13312,9 @@ async function readZCodeRows(dbPath) {
|
|
|
13369
13312
|
'cache_read_input_tokens',cache_read_input_tokens,
|
|
13370
13313
|
'provider_total_tokens',provider_total_tokens,
|
|
13371
13314
|
'computed_total_tokens',computed_total_tokens,
|
|
13372
|
-
'tool_call_count',tool_call_count
|
|
13315
|
+
'tool_call_count',tool_call_count,
|
|
13316
|
+
'retry_count',retry_count,
|
|
13317
|
+
'error_type',error_type
|
|
13373
13318
|
) from model_usage order by started_at, id;`,
|
|
13374
13319
|
`select json_object(
|
|
13375
13320
|
'kind','tool',
|
|
@@ -13387,7 +13332,8 @@ async function readZCodeRows(dbPath) {
|
|
|
13387
13332
|
'completed_at',completed_at,
|
|
13388
13333
|
'duration_ms',duration_ms,
|
|
13389
13334
|
'output_bytes',output_bytes,
|
|
13390
|
-
'exit_code',exit_code
|
|
13335
|
+
'exit_code',exit_code,
|
|
13336
|
+
'error_type',error_type
|
|
13391
13337
|
) from tool_usage order by started_at, id;`
|
|
13392
13338
|
];
|
|
13393
13339
|
const results = await Promise.all(queries.map((query) => sqliteJsonRows(dbPath, query)));
|
|
@@ -13409,6 +13355,7 @@ function modelMetrics(row) {
|
|
|
13409
13355
|
const alignedInput = input > 0 ? input + (cacheIsSeparate ? cached : 0) : cached;
|
|
13410
13356
|
const alignedTotal = alignedInput + output;
|
|
13411
13357
|
const durationMs = numberField(row, "duration_ms");
|
|
13358
|
+
const variant = stringField(row, "variant");
|
|
13412
13359
|
return {
|
|
13413
13360
|
tokensInput: alignedInput || void 0,
|
|
13414
13361
|
tokensOutput: output,
|
|
@@ -13417,6 +13364,7 @@ function modelMetrics(row) {
|
|
|
13417
13364
|
tokensCacheCreationInput: cacheCreation,
|
|
13418
13365
|
tokensCacheReadInput: cacheRead,
|
|
13419
13366
|
tokensTotal: alignedTotal,
|
|
13367
|
+
reasoningEffort: variant || void 0,
|
|
13420
13368
|
modelDurationMs: durationMs,
|
|
13421
13369
|
durationMs,
|
|
13422
13370
|
modelCalls: 1,
|
|
@@ -13446,13 +13394,14 @@ function sessionContext(row, sessions) {
|
|
|
13446
13394
|
const cwd = stringField(session, "directory");
|
|
13447
13395
|
const project = projectFromDirectory(cwd);
|
|
13448
13396
|
const rootSessionId = resolveRootSessionId2(sessionId, sessions);
|
|
13397
|
+
const workspaceId = stringField(session, "workspace_id") || createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
13449
13398
|
return {
|
|
13450
13399
|
rawSessionId: sessionId,
|
|
13451
13400
|
sessionId: `zcode:${rootSessionId}`,
|
|
13452
13401
|
isSubagent: rootSessionId !== sessionId,
|
|
13453
13402
|
cwd,
|
|
13454
13403
|
project,
|
|
13455
|
-
workspaceId
|
|
13404
|
+
workspaceId,
|
|
13456
13405
|
parentSessionId: stringField(session, "parent_id") ? `zcode:${stringField(session, "parent_id")}` : void 0
|
|
13457
13406
|
};
|
|
13458
13407
|
}
|
|
@@ -13516,6 +13465,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13516
13465
|
if (event) events.push(event);
|
|
13517
13466
|
const completedTs = isoFromMs(numberField(row, "time_updated"));
|
|
13518
13467
|
if (completedTs && completedTs !== ts) {
|
|
13468
|
+
const linesAdded = numberField(row, "summary_additions");
|
|
13469
|
+
const linesRemoved = numberField(row, "summary_deletions");
|
|
13470
|
+
const filesChanged = numberField(row, "summary_files");
|
|
13519
13471
|
const completed = makeEvent2({
|
|
13520
13472
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13521
13473
|
ts: completedTs,
|
|
@@ -13528,6 +13480,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13528
13480
|
parentAgentInstanceId: ctx.parentSessionId,
|
|
13529
13481
|
agent: "zcode",
|
|
13530
13482
|
confidence: "exact",
|
|
13483
|
+
metrics: linesAdded || linesRemoved || filesChanged ? { linesAdded: linesAdded || void 0, linesRemoved: linesRemoved || void 0, filesChanged: filesChanged || void 0 } : void 0,
|
|
13531
13484
|
refs: { sourceId: `${id}:session:ended` }
|
|
13532
13485
|
}, row, rowNumber, filePath, options);
|
|
13533
13486
|
if (completed) events.push(completed);
|
|
@@ -13616,7 +13569,10 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13616
13569
|
sourceId: stringField(row, "id") || `${ctx.rawSessionId}:model:${rowNumber}`,
|
|
13617
13570
|
zcodeQuerySource: stringField(row, "query_source"),
|
|
13618
13571
|
zcodeMode: stringField(row, "mode"),
|
|
13619
|
-
zcodeStatus: stringField(row, "status")
|
|
13572
|
+
zcodeStatus: stringField(row, "status"),
|
|
13573
|
+
zcodeVariant: stringField(row, "variant"),
|
|
13574
|
+
zcodeErrorType: stringField(row, "error_type"),
|
|
13575
|
+
zcodeRetryCount: numberField(row, "retry_count") || void 0
|
|
13620
13576
|
})
|
|
13621
13577
|
}, row, rowNumber, filePath, options);
|
|
13622
13578
|
if (usage) events.push(usage);
|
|
@@ -13679,7 +13635,8 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13679
13635
|
refs: refs({
|
|
13680
13636
|
sourceId: `${toolCallId}:completed`,
|
|
13681
13637
|
zcodeStatus: status,
|
|
13682
|
-
zcodeExitCode: numberField(row, "exit_code")
|
|
13638
|
+
zcodeExitCode: numberField(row, "exit_code"),
|
|
13639
|
+
zcodeErrorType: stringField(row, "error_type")
|
|
13683
13640
|
})
|
|
13684
13641
|
}, row, rowNumber, filePath, options);
|
|
13685
13642
|
if (completed) events.push(completed);
|
|
@@ -13693,7 +13650,15 @@ async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
|
13693
13650
|
const filePath = candidate.endsWith(".sqlite") ? candidate : path22.join(candidate, "db", "db.sqlite");
|
|
13694
13651
|
try {
|
|
13695
13652
|
const info = await stat14(filePath);
|
|
13696
|
-
|
|
13653
|
+
let modifiedMs = info.mtimeMs;
|
|
13654
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
13655
|
+
try {
|
|
13656
|
+
const sidecar = await stat14(`${filePath}${suffix}`);
|
|
13657
|
+
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
13658
|
+
} catch {
|
|
13659
|
+
}
|
|
13660
|
+
}
|
|
13661
|
+
return [{ path: filePath, modifiedAt: new Date(modifiedMs).toISOString() }];
|
|
13697
13662
|
} catch {
|
|
13698
13663
|
return [];
|
|
13699
13664
|
}
|
|
@@ -13708,13 +13673,20 @@ function createZCodeAdapter() {
|
|
|
13708
13673
|
return zcodeCliDir(home, env);
|
|
13709
13674
|
},
|
|
13710
13675
|
installedPath(home, env) {
|
|
13711
|
-
return
|
|
13676
|
+
return zcodeConfigPath(home, env);
|
|
13712
13677
|
},
|
|
13713
13678
|
async isInstalled(home, env) {
|
|
13714
|
-
return
|
|
13679
|
+
return isHooksJsonInstalled(
|
|
13680
|
+
zcodeConfigPath(home, env),
|
|
13681
|
+
"vibetime hook --agent zcode"
|
|
13682
|
+
);
|
|
13715
13683
|
},
|
|
13716
|
-
installEntries() {
|
|
13717
|
-
return [
|
|
13684
|
+
installEntries(home, env) {
|
|
13685
|
+
return [{
|
|
13686
|
+
kind: "hooks-json",
|
|
13687
|
+
path: zcodeConfigPath(home, env),
|
|
13688
|
+
content: hookConfig9()
|
|
13689
|
+
}];
|
|
13718
13690
|
},
|
|
13719
13691
|
sourcePaths(home, env) {
|
|
13720
13692
|
return [zcodeDbPath(home, env)];
|
|
@@ -14640,11 +14612,24 @@ function mergeHookObjects(existing, addition) {
|
|
|
14640
14612
|
const additionHooks = isPlainObject(additionObject.hooks) ? additionObject.hooks : {};
|
|
14641
14613
|
merged.hooks = isPlainObject(merged.hooks) ? merged.hooks : {};
|
|
14642
14614
|
const mergedHooks = merged.hooks;
|
|
14643
|
-
|
|
14615
|
+
mergeHookEvents(mergedHooks, additionHooks);
|
|
14616
|
+
const additionEvents = isPlainObject(additionHooks.events) ? additionHooks.events : {};
|
|
14617
|
+
if (Object.keys(additionEvents).length > 0) {
|
|
14618
|
+
const mergedEvents = isPlainObject(mergedHooks.events) ? mergedHooks.events : {};
|
|
14619
|
+
mergeHookEvents(mergedEvents, additionEvents);
|
|
14620
|
+
mergedHooks.events = mergedEvents;
|
|
14621
|
+
if (additionHooks.enabled === true) {
|
|
14622
|
+
mergedHooks.enabled = true;
|
|
14623
|
+
}
|
|
14624
|
+
}
|
|
14625
|
+
return merged;
|
|
14626
|
+
}
|
|
14627
|
+
function mergeHookEvents(target, addition) {
|
|
14628
|
+
for (const [event, groups] of Object.entries(addition)) {
|
|
14644
14629
|
if (!Array.isArray(groups)) {
|
|
14645
14630
|
continue;
|
|
14646
14631
|
}
|
|
14647
|
-
const existingGroups = Array.isArray(
|
|
14632
|
+
const existingGroups = Array.isArray(target[event]) ? target[event] : [];
|
|
14648
14633
|
const nextGroups = [...existingGroups];
|
|
14649
14634
|
for (const group of groups) {
|
|
14650
14635
|
const command = hookCommandFromGroup(group);
|
|
@@ -14655,9 +14640,8 @@ function mergeHookObjects(existing, addition) {
|
|
|
14655
14640
|
nextGroups.push(group);
|
|
14656
14641
|
}
|
|
14657
14642
|
}
|
|
14658
|
-
|
|
14643
|
+
target[event] = nextGroups;
|
|
14659
14644
|
}
|
|
14660
|
-
return merged;
|
|
14661
14645
|
}
|
|
14662
14646
|
function hookCommandFromGroup(group) {
|
|
14663
14647
|
if (!isPlainObject(group) || !Array.isArray(group.hooks)) {
|
|
@@ -14746,6 +14730,12 @@ function collectHookCommandsFromJsonContent(content) {
|
|
|
14746
14730
|
for (const groups of Object.values(content.hooks)) {
|
|
14747
14731
|
walkGroups(groups);
|
|
14748
14732
|
}
|
|
14733
|
+
const nestedEvents = content.hooks.events;
|
|
14734
|
+
if (isPlainObject(nestedEvents)) {
|
|
14735
|
+
for (const groups of Object.values(nestedEvents)) {
|
|
14736
|
+
walkGroups(groups);
|
|
14737
|
+
}
|
|
14738
|
+
}
|
|
14749
14739
|
}
|
|
14750
14740
|
for (const [key, value] of Object.entries(content)) {
|
|
14751
14741
|
if (key === "hooks" || key === "enable_json_hooks" || !isPlainObject(value)) {
|
|
@@ -14810,7 +14800,33 @@ async function uninstallHooksJson(filePath, content, { dryRun, onWrite }) {
|
|
|
14810
14800
|
}
|
|
14811
14801
|
}
|
|
14812
14802
|
}
|
|
14813
|
-
if (isPlainObject(next.hooks
|
|
14803
|
+
if (isPlainObject(next.hooks.events)) {
|
|
14804
|
+
for (const [event, groups] of Object.entries(next.hooks.events)) {
|
|
14805
|
+
const stripped = stripHookCommandsFromGroups(groups, commands);
|
|
14806
|
+
if (JSON.stringify(stripped) !== JSON.stringify(groups)) {
|
|
14807
|
+
changed = true;
|
|
14808
|
+
if (Array.isArray(stripped) && stripped.length === 0) {
|
|
14809
|
+
delete next.hooks.events[event];
|
|
14810
|
+
} else {
|
|
14811
|
+
next.hooks.events[event] = stripped;
|
|
14812
|
+
}
|
|
14813
|
+
}
|
|
14814
|
+
}
|
|
14815
|
+
if (Object.keys(next.hooks.events).length === 0) {
|
|
14816
|
+
delete next.hooks.events;
|
|
14817
|
+
}
|
|
14818
|
+
}
|
|
14819
|
+
const eventsObject = isPlainObject(next.hooks.events) ? next.hooks.events : {};
|
|
14820
|
+
const hooksHasGroups = Object.values(next.hooks).some((value) => Array.isArray(value) && value.length > 0) || Object.values(eventsObject).some((value) => Array.isArray(value) && value.length > 0);
|
|
14821
|
+
if (!hooksHasGroups) {
|
|
14822
|
+
if (next.hooks.enabled !== void 0) {
|
|
14823
|
+
delete next.hooks.enabled;
|
|
14824
|
+
}
|
|
14825
|
+
if (Object.keys(next.hooks).length === 0) {
|
|
14826
|
+
delete next.hooks;
|
|
14827
|
+
changed = true;
|
|
14828
|
+
}
|
|
14829
|
+
} else if (isPlainObject(next.hooks) && Object.keys(next.hooks).length === 0) {
|
|
14814
14830
|
delete next.hooks;
|
|
14815
14831
|
changed = true;
|
|
14816
14832
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yhong91/vibetime",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.62",
|
|
5
5
|
"description": "vibetime CLI — install AI-agent hooks (Claude Code, Codex, OpenCode, Pi, Cursor) and report activity to vibetime.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"publishConfig": {
|