vibeusage 0.3.0 → 0.3.2
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/README.md +19 -11
- package/README.zh-CN.md +10 -8
- package/node_modules/@insforge/sdk/LICENSE +201 -201
- package/node_modules/@insforge/sdk/README.md +326 -259
- package/node_modules/@insforge/sdk/dist/index.d.mts +377 -182
- package/node_modules/@insforge/sdk/dist/index.d.ts +377 -182
- package/node_modules/@insforge/sdk/dist/index.js +1172 -677
- package/node_modules/@insforge/sdk/dist/index.js.map +1 -1
- package/node_modules/@insforge/sdk/dist/index.mjs +1171 -677
- package/node_modules/@insforge/sdk/dist/index.mjs.map +1 -1
- package/node_modules/@insforge/sdk/package.json +68 -68
- package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.d.ts +1120 -43
- package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.js +179 -5
- package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/ai.schema.d.ts +25 -25
- package/node_modules/@insforge/shared-schemas/dist/ai.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/ai.schema.js +2 -2
- package/node_modules/@insforge/shared-schemas/dist/ai.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.d.ts +197 -51
- package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.js +87 -23
- package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/auth.schema.d.ts +32 -3
- package/node_modules/@insforge/shared-schemas/dist/auth.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/auth.schema.js +21 -3
- package/node_modules/@insforge/shared-schemas/dist/auth.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.d.ts +380 -0
- package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.js +74 -0
- package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/database-api.schema.d.ts +13 -13
- package/node_modules/@insforge/shared-schemas/dist/database-api.schema.js +1 -1
- package/node_modules/@insforge/shared-schemas/dist/database-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.d.ts +735 -0
- package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.js +209 -0
- package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/deployments.schema.d.ts +37 -0
- package/node_modules/@insforge/shared-schemas/dist/deployments.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/deployments.schema.js +25 -0
- package/node_modules/@insforge/shared-schemas/dist/deployments.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/docs.schema.d.ts +5 -1
- package/node_modules/@insforge/shared-schemas/dist/docs.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/docs.schema.js +34 -4
- package/node_modules/@insforge/shared-schemas/dist/docs.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/email-api.schema.js +1 -1
- package/node_modules/@insforge/shared-schemas/dist/email-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.d.ts +186 -6
- package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.js +21 -2
- package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/functions.schema.d.ts +5 -5
- package/node_modules/@insforge/shared-schemas/dist/functions.schema.js +1 -1
- package/node_modules/@insforge/shared-schemas/dist/functions.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/index.d.ts +24 -18
- package/node_modules/@insforge/shared-schemas/dist/index.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/index.js +24 -18
- package/node_modules/@insforge/shared-schemas/dist/index.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/logs-api.schema.js +1 -1
- package/node_modules/@insforge/shared-schemas/dist/logs-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/logs.schema.d.ts +43 -0
- package/node_modules/@insforge/shared-schemas/dist/logs.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/logs.schema.js +11 -0
- package/node_modules/@insforge/shared-schemas/dist/logs.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/metadata.schema.d.ts +229 -172
- package/node_modules/@insforge/shared-schemas/dist/metadata.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/metadata.schema.js +27 -7
- package/node_modules/@insforge/shared-schemas/dist/metadata.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.d.ts +51 -0
- package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.js +31 -0
- package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.d.ts +31 -0
- package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.js +12 -0
- package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.d.ts +39 -20
- package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.js +5 -1
- package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/realtime.schema.d.ts +12 -4
- package/node_modules/@insforge/shared-schemas/dist/realtime.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/realtime.schema.js +6 -0
- package/node_modules/@insforge/shared-schemas/dist/realtime.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.d.ts +287 -0
- package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.js +81 -0
- package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/schedules.schema.d.ts +77 -0
- package/node_modules/@insforge/shared-schemas/dist/schedules.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/schedules.schema.js +36 -0
- package/node_modules/@insforge/shared-schemas/dist/schedules.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.d.ts +113 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.js +31 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets.schema.d.ts +31 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets.schema.d.ts.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets.schema.js +13 -0
- package/node_modules/@insforge/shared-schemas/dist/secrets.schema.js.map +1 -0
- package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.d.ts +27 -2
- package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.js +9 -1
- package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/storage.schema.d.ts +17 -0
- package/node_modules/@insforge/shared-schemas/dist/storage.schema.d.ts.map +1 -1
- package/node_modules/@insforge/shared-schemas/dist/storage.schema.js +6 -0
- package/node_modules/@insforge/shared-schemas/dist/storage.schema.js.map +1 -1
- package/node_modules/@insforge/shared-schemas/package.json +2 -1
- package/package.json +2 -2
- package/src/commands/status.js +22 -5
- package/src/commands/sync.js +100 -197
- package/src/commands/uninstall.js +0 -11
- package/src/lib/diagnostics.js +34 -9
- package/src/lib/doctor.js +24 -15
- package/src/lib/insforge-client.js +13 -9
- package/src/lib/integrations/context.js +0 -6
- package/src/lib/integrations/index.js +0 -2
- package/src/lib/openclaw-session-plugin.js +48 -138
- package/src/lib/openclaw-usage-ledger.js +237 -0
- package/src/lib/opencode-sqlite.js +113 -0
- package/src/lib/opencode-usage-audit.js +3 -2
- package/src/lib/rollout.js +229 -153
- package/src/lib/vibeusage-api.js +2 -2
- package/src/lib/integrations/openclaw-legacy.js +0 -123
- package/src/lib/openclaw-hook.js +0 -420
package/src/lib/rollout.js
CHANGED
|
@@ -4,6 +4,7 @@ const path = require("node:path");
|
|
|
4
4
|
const readline = require("node:readline");
|
|
5
5
|
|
|
6
6
|
const { ensureDir } = require("./fs");
|
|
7
|
+
const { readOpencodeSqliteRows } = require("./opencode-sqlite");
|
|
7
8
|
const { hashRepoRoot, resolveGitHubPublicStatus } = require("./vibeusage-public-repo");
|
|
8
9
|
|
|
9
10
|
const DEFAULT_SOURCE = "codex";
|
|
@@ -398,12 +399,14 @@ async function parseGeminiIncremental({
|
|
|
398
399
|
|
|
399
400
|
async function parseOpencodeIncremental({
|
|
400
401
|
messageFiles,
|
|
402
|
+
opencodeDbPath,
|
|
401
403
|
cursors,
|
|
402
404
|
queuePath,
|
|
403
405
|
projectQueuePath,
|
|
404
406
|
onProgress,
|
|
405
407
|
source,
|
|
406
408
|
publicRepoResolver,
|
|
409
|
+
readSqliteRows,
|
|
407
410
|
}) {
|
|
408
411
|
await ensureDir(path.dirname(queuePath));
|
|
409
412
|
let filesProcessed = 0;
|
|
@@ -419,9 +422,13 @@ async function parseOpencodeIncremental({
|
|
|
419
422
|
const projectMetaCache = projectEnabled ? new Map() : null;
|
|
420
423
|
const publicRepoCache = projectEnabled ? new Map() : null;
|
|
421
424
|
const opencodeState = normalizeOpencodeState(cursors?.opencode);
|
|
425
|
+
const opencodeSqliteState = normalizeOpencodeSqliteState(cursors?.opencodeSqlite);
|
|
422
426
|
const messageIndex = opencodeState.messages;
|
|
423
427
|
const touchedBuckets = new Set();
|
|
424
428
|
const defaultSource = normalizeSourceInput(source) || "opencode";
|
|
429
|
+
let sqliteStatus = opencodeSqliteState.lastStatus || "never_checked";
|
|
430
|
+
let sqliteCheckedAt = opencodeSqliteState.lastCheckedAt || null;
|
|
431
|
+
let sqliteErrorCode = opencodeSqliteState.lastErrorCode || null;
|
|
425
432
|
|
|
426
433
|
if (!cursors.files || typeof cursors.files !== "object") {
|
|
427
434
|
cursors.files = {};
|
|
@@ -522,93 +529,88 @@ async function parseOpencodeIncremental({
|
|
|
522
529
|
}
|
|
523
530
|
}
|
|
524
531
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
cursors.opencode = opencodeState;
|
|
533
|
-
if (projectState) {
|
|
534
|
-
projectState.updatedAt = new Date().toISOString();
|
|
535
|
-
cursors.projectHourly = projectState;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
return { filesProcessed, eventsAggregated, bucketsQueued, projectBucketsQueued };
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
async function parseOpenclawIncremental({
|
|
542
|
-
sessionFiles,
|
|
543
|
-
cursors,
|
|
544
|
-
queuePath,
|
|
545
|
-
projectQueuePath,
|
|
546
|
-
onProgress,
|
|
547
|
-
source,
|
|
548
|
-
}) {
|
|
549
|
-
await ensureDir(path.dirname(queuePath));
|
|
550
|
-
let filesProcessed = 0;
|
|
551
|
-
let eventsAggregated = 0;
|
|
552
|
-
|
|
553
|
-
const cb = typeof onProgress === "function" ? onProgress : null;
|
|
554
|
-
const files = Array.isArray(sessionFiles) ? sessionFiles : [];
|
|
555
|
-
const totalFiles = files.length;
|
|
556
|
-
const hourlyState = normalizeHourlyState(cursors?.hourly);
|
|
557
|
-
const projectEnabled = typeof projectQueuePath === "string" && projectQueuePath.length > 0;
|
|
558
|
-
const projectState = projectEnabled ? normalizeProjectState(cursors?.projectHourly) : null;
|
|
559
|
-
const projectTouchedBuckets = projectEnabled ? new Set() : null;
|
|
560
|
-
const touchedBuckets = new Set();
|
|
561
|
-
const defaultSource = normalizeSourceInput(source) || "openclaw";
|
|
562
|
-
|
|
563
|
-
if (!cursors.files || typeof cursors.files !== "object") {
|
|
564
|
-
cursors.files = {};
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
for (let idx = 0; idx < files.length; idx++) {
|
|
568
|
-
const entry = files[idx];
|
|
569
|
-
const filePath = typeof entry === "string" ? entry : entry?.path;
|
|
570
|
-
if (!filePath) continue;
|
|
571
|
-
const fileSource =
|
|
572
|
-
typeof entry === "string"
|
|
573
|
-
? defaultSource
|
|
574
|
-
: normalizeSourceInput(entry?.source) || defaultSource;
|
|
575
|
-
const st = await fs.stat(filePath).catch(() => null);
|
|
576
|
-
if (!st || !st.isFile()) continue;
|
|
577
|
-
|
|
578
|
-
const key = filePath;
|
|
579
|
-
const prev = cursors.files[key] || null;
|
|
580
|
-
const inode = st.ino || 0;
|
|
581
|
-
const startOffset = prev && prev.inode === inode ? prev.offset || 0 : 0;
|
|
582
|
-
|
|
583
|
-
const result = await parseOpenclawSessionFile({
|
|
584
|
-
filePath,
|
|
585
|
-
startOffset,
|
|
586
|
-
hourlyState,
|
|
587
|
-
touchedBuckets,
|
|
588
|
-
source: fileSource,
|
|
589
|
-
projectState,
|
|
590
|
-
projectTouchedBuckets,
|
|
532
|
+
if (typeof opencodeDbPath === "string" && opencodeDbPath.length > 0) {
|
|
533
|
+
const readRows =
|
|
534
|
+
typeof readSqliteRows === "function" ? readSqliteRows : readOpencodeSqliteRows;
|
|
535
|
+
const sqliteResult = await readRows({
|
|
536
|
+
dbPath: opencodeDbPath,
|
|
537
|
+
lastTimeCreated: opencodeSqliteState.lastTimeCreated,
|
|
538
|
+
expectedInode: opencodeSqliteState.inode,
|
|
591
539
|
});
|
|
592
540
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
541
|
+
sqliteStatus =
|
|
542
|
+
typeof sqliteResult?.status === "string" && sqliteResult.status.trim()
|
|
543
|
+
? sqliteResult.status.trim()
|
|
544
|
+
: "query-failed";
|
|
545
|
+
sqliteCheckedAt =
|
|
546
|
+
typeof sqliteResult?.checkedAt === "string" && sqliteResult.checkedAt.trim()
|
|
547
|
+
? sqliteResult.checkedAt.trim()
|
|
548
|
+
: new Date().toISOString();
|
|
549
|
+
sqliteErrorCode =
|
|
550
|
+
typeof sqliteResult?.errorCode === "string" && sqliteResult.errorCode.trim()
|
|
551
|
+
? sqliteResult.errorCode.trim()
|
|
552
|
+
: typeof sqliteResult?.error?.code === "string" && sqliteResult.error.code.trim()
|
|
553
|
+
? sqliteResult.error.code.trim()
|
|
554
|
+
: null;
|
|
555
|
+
|
|
556
|
+
opencodeSqliteState.lastStatus = sqliteStatus;
|
|
557
|
+
opencodeSqliteState.lastCheckedAt = sqliteCheckedAt;
|
|
558
|
+
opencodeSqliteState.lastErrorCode = sqliteErrorCode;
|
|
559
|
+
opencodeSqliteState.updatedAt = new Date().toISOString();
|
|
560
|
+
|
|
561
|
+
if (sqliteStatus === "ok") {
|
|
562
|
+
const sameDb =
|
|
563
|
+
!sqliteResult.cursorReset &&
|
|
564
|
+
opencodeSqliteState.inode &&
|
|
565
|
+
sqliteResult.inode &&
|
|
566
|
+
opencodeSqliteState.inode === sqliteResult.inode;
|
|
567
|
+
const prevProcessedIds = new Set(sameDb ? opencodeSqliteState.lastProcessedIds : []);
|
|
568
|
+
const rawRows = Array.isArray(sqliteResult.rows) ? sqliteResult.rows : [];
|
|
569
|
+
const rows = prevProcessedIds.size
|
|
570
|
+
? rawRows.filter((row) => !prevProcessedIds.has(row?.id))
|
|
571
|
+
: rawRows;
|
|
572
|
+
const knownMessageKeys = new Set([
|
|
573
|
+
...Object.keys(messageIndex || {}),
|
|
574
|
+
...Object.values(cursors.files || {})
|
|
575
|
+
.map((entry) => entry?.messageKey)
|
|
576
|
+
.filter((entry) => typeof entry === "string" && entry.trim()),
|
|
577
|
+
]);
|
|
578
|
+
|
|
579
|
+
for (const row of rows) {
|
|
580
|
+
const result = await parseOpencodeSqliteRow({
|
|
581
|
+
row,
|
|
582
|
+
messageIndex,
|
|
583
|
+
knownMessageKeys,
|
|
584
|
+
hourlyState,
|
|
585
|
+
touchedBuckets,
|
|
586
|
+
source: defaultSource,
|
|
587
|
+
projectState,
|
|
588
|
+
projectTouchedBuckets,
|
|
589
|
+
projectMetaCache,
|
|
590
|
+
publicRepoCache,
|
|
591
|
+
publicRepoResolver,
|
|
592
|
+
});
|
|
593
|
+
eventsAggregated += result.eventsAggregated;
|
|
594
|
+
}
|
|
601
595
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
596
|
+
const lastTimeCreated = sameDb ? opencodeSqliteState.lastTimeCreated : 0;
|
|
597
|
+
const maxTime =
|
|
598
|
+
rawRows.length > 0
|
|
599
|
+
? Math.max(
|
|
600
|
+
lastTimeCreated,
|
|
601
|
+
...rawRows.map((row) =>
|
|
602
|
+
Number.isFinite(Number(row?.time_created)) ? Number(row.time_created) : 0,
|
|
603
|
+
),
|
|
604
|
+
)
|
|
605
|
+
: lastTimeCreated;
|
|
606
|
+
opencodeSqliteState.lastTimeCreated = maxTime;
|
|
607
|
+
opencodeSqliteState.lastProcessedIds = rawRows
|
|
608
|
+
.filter((row) => Number(row?.time_created) === maxTime)
|
|
609
|
+
.map((row) => row?.id)
|
|
610
|
+
.filter((value) => typeof value === "string" && value.trim());
|
|
611
|
+
opencodeSqliteState.inode = sqliteResult.inode || opencodeSqliteState.inode || 0;
|
|
611
612
|
}
|
|
613
|
+
cursors.opencodeSqlite = opencodeSqliteState;
|
|
612
614
|
}
|
|
613
615
|
|
|
614
616
|
const bucketsQueued = await enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets });
|
|
@@ -617,80 +619,22 @@ async function parseOpenclawIncremental({
|
|
|
617
619
|
: 0;
|
|
618
620
|
hourlyState.updatedAt = new Date().toISOString();
|
|
619
621
|
cursors.hourly = hourlyState;
|
|
622
|
+
opencodeState.updatedAt = new Date().toISOString();
|
|
623
|
+
cursors.opencode = opencodeState;
|
|
620
624
|
if (projectState) {
|
|
621
625
|
projectState.updatedAt = new Date().toISOString();
|
|
622
626
|
cursors.projectHourly = projectState;
|
|
623
627
|
}
|
|
624
628
|
|
|
625
|
-
return {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
projectState,
|
|
635
|
-
projectTouchedBuckets,
|
|
636
|
-
}) {
|
|
637
|
-
const st = await fs.stat(filePath);
|
|
638
|
-
const endOffset = st.size;
|
|
639
|
-
if (startOffset >= endOffset) return { endOffset, eventsAggregated: 0 };
|
|
640
|
-
|
|
641
|
-
const stream = fssync.createReadStream(filePath, { encoding: "utf8", start: startOffset });
|
|
642
|
-
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
643
|
-
|
|
644
|
-
let eventsAggregated = 0;
|
|
645
|
-
for await (const line of rl) {
|
|
646
|
-
if (!line) continue;
|
|
647
|
-
// Fast-path filter: OpenClaw assistant messages include message.usage.totalTokens.
|
|
648
|
-
if (!line.includes('"usage"') || !line.includes("totalTokens")) continue;
|
|
649
|
-
|
|
650
|
-
let obj;
|
|
651
|
-
try {
|
|
652
|
-
obj = JSON.parse(line);
|
|
653
|
-
} catch (_e) {
|
|
654
|
-
continue;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
if (obj?.type !== "message") continue;
|
|
658
|
-
const msg = obj?.message;
|
|
659
|
-
if (!msg || typeof msg !== "object") continue;
|
|
660
|
-
|
|
661
|
-
const usage = msg.usage;
|
|
662
|
-
if (!usage || typeof usage !== "object") continue;
|
|
663
|
-
|
|
664
|
-
const tokenTimestamp = typeof obj?.timestamp === "string" ? obj.timestamp : null;
|
|
665
|
-
if (!tokenTimestamp) continue;
|
|
666
|
-
|
|
667
|
-
const model = normalizeModelInput(msg.model) || DEFAULT_MODEL;
|
|
668
|
-
|
|
669
|
-
const delta = {
|
|
670
|
-
input_tokens: Number(usage.input || 0),
|
|
671
|
-
cached_input_tokens: Number((usage.cacheRead || 0) + (usage.cacheWrite || 0)),
|
|
672
|
-
output_tokens: Number(usage.output || 0),
|
|
673
|
-
reasoning_output_tokens: 0,
|
|
674
|
-
total_tokens: Number(usage.totalTokens || 0),
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
if (isAllZeroUsage(delta)) continue;
|
|
678
|
-
|
|
679
|
-
const bucketStart = toUtcHalfHourStart(tokenTimestamp);
|
|
680
|
-
if (!bucketStart) continue;
|
|
681
|
-
|
|
682
|
-
const bucket = getHourlyBucket(hourlyState, source, model, bucketStart);
|
|
683
|
-
addTotals(bucket.totals, delta);
|
|
684
|
-
touchedBuckets.add(bucketKey(source, model, bucketStart));
|
|
685
|
-
|
|
686
|
-
// Project-level OpenClaw attribution is not supported yet (no stable cwd info).
|
|
687
|
-
// If OpenClaw later records cwd per event, we can mirror rollout's project logic.
|
|
688
|
-
eventsAggregated += 1;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
rl.close();
|
|
692
|
-
stream.close?.();
|
|
693
|
-
return { endOffset, eventsAggregated };
|
|
629
|
+
return {
|
|
630
|
+
filesProcessed,
|
|
631
|
+
eventsAggregated,
|
|
632
|
+
bucketsQueued,
|
|
633
|
+
projectBucketsQueued,
|
|
634
|
+
sqliteStatus,
|
|
635
|
+
sqliteCheckedAt,
|
|
636
|
+
sqliteErrorCode,
|
|
637
|
+
};
|
|
694
638
|
}
|
|
695
639
|
|
|
696
640
|
async function parseRolloutFile({
|
|
@@ -1062,6 +1006,107 @@ async function parseOpencodeMessageFile({
|
|
|
1062
1006
|
return { messageKey, lastTotals: currentTotals, eventsAggregated: 1, shouldUpdate: true };
|
|
1063
1007
|
}
|
|
1064
1008
|
|
|
1009
|
+
async function parseOpencodeSqliteRow({
|
|
1010
|
+
row,
|
|
1011
|
+
messageIndex,
|
|
1012
|
+
knownMessageKeys,
|
|
1013
|
+
hourlyState,
|
|
1014
|
+
touchedBuckets,
|
|
1015
|
+
source,
|
|
1016
|
+
projectState,
|
|
1017
|
+
projectTouchedBuckets,
|
|
1018
|
+
projectMetaCache,
|
|
1019
|
+
publicRepoCache,
|
|
1020
|
+
publicRepoResolver,
|
|
1021
|
+
}) {
|
|
1022
|
+
if (!row || typeof row !== "object") {
|
|
1023
|
+
return { eventsAggregated: 0 };
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
let msg;
|
|
1027
|
+
try {
|
|
1028
|
+
msg = JSON.parse(String(row.data || ""));
|
|
1029
|
+
} catch (_e) {
|
|
1030
|
+
return { eventsAggregated: 0 };
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const rowRole =
|
|
1034
|
+
normalizeMessageKeyPart(row.role) ||
|
|
1035
|
+
normalizeMessageKeyPart(msg?.role) ||
|
|
1036
|
+
normalizeMessageKeyPart(msg?.type);
|
|
1037
|
+
if (rowRole && rowRole !== "assistant") {
|
|
1038
|
+
return { eventsAggregated: 0 };
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const messageKey = deriveOpencodeMessageKey(msg, null);
|
|
1042
|
+
if (!messageKey || knownMessageKeys.has(messageKey)) {
|
|
1043
|
+
return { eventsAggregated: 0 };
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
const currentTotals = normalizeOpencodeTokens(msg?.tokens);
|
|
1047
|
+
if (!currentTotals || isAllZeroUsage(currentTotals)) {
|
|
1048
|
+
return { eventsAggregated: 0 };
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
const timestampMs = coerceEpochMs(msg?.time?.completed) || coerceEpochMs(msg?.time?.created);
|
|
1052
|
+
if (!timestampMs) {
|
|
1053
|
+
return { eventsAggregated: 0 };
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
const bucketStart = toUtcHalfHourStart(new Date(timestampMs).toISOString());
|
|
1057
|
+
if (!bucketStart) {
|
|
1058
|
+
return { eventsAggregated: 0 };
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
const model = normalizeModelInput(msg?.modelID || msg?.model || msg?.modelId) || DEFAULT_MODEL;
|
|
1062
|
+
const bucket = getHourlyBucket(hourlyState, source, model, bucketStart);
|
|
1063
|
+
addTotals(bucket.totals, currentTotals);
|
|
1064
|
+
touchedBuckets.add(bucketKey(source, model, bucketStart));
|
|
1065
|
+
|
|
1066
|
+
const projectWorktree =
|
|
1067
|
+
typeof row.project_worktree === "string" && row.project_worktree.trim()
|
|
1068
|
+
? row.project_worktree.trim()
|
|
1069
|
+
: null;
|
|
1070
|
+
if (
|
|
1071
|
+
projectWorktree &&
|
|
1072
|
+
projectState &&
|
|
1073
|
+
projectTouchedBuckets &&
|
|
1074
|
+
projectMetaCache &&
|
|
1075
|
+
publicRepoCache
|
|
1076
|
+
) {
|
|
1077
|
+
const projectContext = await resolveProjectContextForPath({
|
|
1078
|
+
startDir: projectWorktree,
|
|
1079
|
+
projectMetaCache,
|
|
1080
|
+
publicRepoCache,
|
|
1081
|
+
publicRepoResolver,
|
|
1082
|
+
projectState,
|
|
1083
|
+
});
|
|
1084
|
+
const projectRef = projectContext?.projectRef || null;
|
|
1085
|
+
const projectKey = projectContext?.projectKey || null;
|
|
1086
|
+
if (projectKey) {
|
|
1087
|
+
const projectBucket = getProjectBucket(
|
|
1088
|
+
projectState,
|
|
1089
|
+
projectKey,
|
|
1090
|
+
source,
|
|
1091
|
+
bucketStart,
|
|
1092
|
+
projectRef,
|
|
1093
|
+
);
|
|
1094
|
+
addTotals(projectBucket.totals, currentTotals);
|
|
1095
|
+
projectTouchedBuckets.add(projectBucketKey(projectKey, source, bucketStart));
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
if (messageIndex && typeof messageIndex === "object") {
|
|
1100
|
+
messageIndex[messageKey] = {
|
|
1101
|
+
lastTotals: currentTotals,
|
|
1102
|
+
updatedAt: new Date().toISOString(),
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
knownMessageKeys.add(messageKey);
|
|
1106
|
+
|
|
1107
|
+
return { eventsAggregated: 1 };
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1065
1110
|
async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets }) {
|
|
1066
1111
|
if (!touchedBuckets || touchedBuckets.size === 0) return 0;
|
|
1067
1112
|
|
|
@@ -1559,6 +1604,32 @@ function normalizeOpencodeState(raw) {
|
|
|
1559
1604
|
};
|
|
1560
1605
|
}
|
|
1561
1606
|
|
|
1607
|
+
function normalizeOpencodeSqliteState(raw) {
|
|
1608
|
+
const state = raw && typeof raw === "object" ? raw : {};
|
|
1609
|
+
return {
|
|
1610
|
+
lastTimeCreated: Number.isFinite(Number(state.lastTimeCreated))
|
|
1611
|
+
? Number(state.lastTimeCreated)
|
|
1612
|
+
: 0,
|
|
1613
|
+
lastProcessedIds: Array.isArray(state.lastProcessedIds)
|
|
1614
|
+
? state.lastProcessedIds
|
|
1615
|
+
.filter((value) => typeof value === "string" && value.trim())
|
|
1616
|
+
.map((value) => value.trim())
|
|
1617
|
+
: [],
|
|
1618
|
+
inode: Number.isFinite(Number(state.inode)) ? Number(state.inode) : 0,
|
|
1619
|
+
updatedAt: typeof state.updatedAt === "string" ? state.updatedAt : null,
|
|
1620
|
+
lastStatus:
|
|
1621
|
+
typeof state.lastStatus === "string" && state.lastStatus.trim() ? state.lastStatus.trim() : null,
|
|
1622
|
+
lastCheckedAt:
|
|
1623
|
+
typeof state.lastCheckedAt === "string" && state.lastCheckedAt.trim()
|
|
1624
|
+
? state.lastCheckedAt.trim()
|
|
1625
|
+
: null,
|
|
1626
|
+
lastErrorCode:
|
|
1627
|
+
typeof state.lastErrorCode === "string" && state.lastErrorCode.trim()
|
|
1628
|
+
? state.lastErrorCode.trim()
|
|
1629
|
+
: null,
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1562
1633
|
function normalizeMessageKeyPart(value) {
|
|
1563
1634
|
if (typeof value !== "string") return "";
|
|
1564
1635
|
return value.trim();
|
|
@@ -2227,5 +2298,10 @@ module.exports = {
|
|
|
2227
2298
|
parseClaudeIncremental,
|
|
2228
2299
|
parseGeminiIncremental,
|
|
2229
2300
|
parseOpencodeIncremental,
|
|
2230
|
-
|
|
2301
|
+
normalizeHourlyState,
|
|
2302
|
+
getHourlyBucket,
|
|
2303
|
+
addTotals,
|
|
2304
|
+
bucketKey,
|
|
2305
|
+
enqueueTouchedBuckets,
|
|
2306
|
+
toUtcHalfHourStart,
|
|
2231
2307
|
};
|
package/src/lib/vibeusage-api.js
CHANGED
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
} = require("../shared/vibeusage-function-contract.cjs");
|
|
8
8
|
|
|
9
9
|
async function signInWithPassword({ baseUrl, email, password }) {
|
|
10
|
-
const client = createInsforgeClient({ baseUrl });
|
|
10
|
+
const client = await createInsforgeClient({ baseUrl });
|
|
11
11
|
const { data, error } = await client.auth.signInWithPassword({ email, password });
|
|
12
12
|
if (error) throw normalizeSdkError(error, "Sign-in failed");
|
|
13
13
|
|
|
@@ -121,7 +121,7 @@ module.exports = {
|
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
async function invokeFunction({ baseUrl, accessToken, slug, method, body, errorPrefix }) {
|
|
124
|
-
const client = createInsforgeClient({ baseUrl, accessToken });
|
|
124
|
+
const client = await createInsforgeClient({ baseUrl, accessToken });
|
|
125
125
|
const { data, error } = await client.functions.invoke(slug, { method, body });
|
|
126
126
|
if (error) throw normalizeSdkError(error, errorPrefix);
|
|
127
127
|
return data;
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
const { probeOpenclawHookState, removeOpenclawHookConfig } = require("../openclaw-hook");
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
4
|
-
name: "openclaw-legacy",
|
|
5
|
-
summaryLabel: "OpenClaw Hook (legacy)",
|
|
6
|
-
statusLabel: "OpenClaw hook (legacy)",
|
|
7
|
-
async probe(ctx) {
|
|
8
|
-
const state = await probeOpenclawHookState({
|
|
9
|
-
home: ctx.home,
|
|
10
|
-
trackerDir: ctx.trackerPaths.trackerDir,
|
|
11
|
-
env: ctx.env,
|
|
12
|
-
});
|
|
13
|
-
if (state?.skippedReason === "openclaw-config-missing") {
|
|
14
|
-
return baseProbe(this, { status: "not_installed", detail: "OpenClaw config not found" });
|
|
15
|
-
}
|
|
16
|
-
if (state?.skippedReason === "openclaw-config-unreadable") {
|
|
17
|
-
return baseProbe(this, {
|
|
18
|
-
status: "unreadable",
|
|
19
|
-
detail: state.error
|
|
20
|
-
? `OpenClaw config unreadable: ${state.error}`
|
|
21
|
-
: "OpenClaw config unreadable",
|
|
22
|
-
linked: Boolean(state.linked),
|
|
23
|
-
enabled: Boolean(state.enabled),
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
if (state?.configured || state?.linked || state?.enabled) {
|
|
27
|
-
return baseProbe(this, {
|
|
28
|
-
status: "unsupported_legacy",
|
|
29
|
-
detail: "Legacy OpenClaw hook detected; run vibeusage init",
|
|
30
|
-
linked: Boolean(state.linked),
|
|
31
|
-
enabled: Boolean(state.enabled),
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
return baseProbe(this, { status: "not_installed", detail: "Legacy hook not installed" });
|
|
35
|
-
},
|
|
36
|
-
async install(ctx) {
|
|
37
|
-
const state = await probeOpenclawHookState({
|
|
38
|
-
home: ctx.home,
|
|
39
|
-
trackerDir: ctx.trackerPaths.trackerDir,
|
|
40
|
-
env: ctx.env,
|
|
41
|
-
});
|
|
42
|
-
if (state?.skippedReason === "openclaw-config-unreadable") {
|
|
43
|
-
return action(
|
|
44
|
-
this,
|
|
45
|
-
"skipped",
|
|
46
|
-
false,
|
|
47
|
-
state.error ? `OpenClaw config unreadable: ${state.error}` : "OpenClaw config unreadable",
|
|
48
|
-
{ skippedReason: state.skippedReason },
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
if (!(state?.configured || state?.linked || state?.enabled)) {
|
|
52
|
-
return action(this, "unchanged", false, "no change");
|
|
53
|
-
}
|
|
54
|
-
const result = await removeOpenclawHookConfig({
|
|
55
|
-
home: ctx.home,
|
|
56
|
-
trackerDir: ctx.trackerPaths.trackerDir,
|
|
57
|
-
env: ctx.env,
|
|
58
|
-
});
|
|
59
|
-
if (result?.removed) {
|
|
60
|
-
return action(this, "updated", true, "Removed legacy command hook");
|
|
61
|
-
}
|
|
62
|
-
if (result?.skippedReason === "openclaw-config-unreadable") {
|
|
63
|
-
return action(
|
|
64
|
-
this,
|
|
65
|
-
"skipped",
|
|
66
|
-
false,
|
|
67
|
-
result.error ? `OpenClaw config unreadable: ${result.error}` : "OpenClaw config unreadable",
|
|
68
|
-
{ skippedReason: result.skippedReason },
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
return action(this, "unchanged", false, "no change");
|
|
72
|
-
},
|
|
73
|
-
async uninstall(ctx) {
|
|
74
|
-
const result = await removeOpenclawHookConfig({
|
|
75
|
-
home: ctx.home,
|
|
76
|
-
trackerDir: ctx.trackerPaths.trackerDir,
|
|
77
|
-
env: ctx.env,
|
|
78
|
-
});
|
|
79
|
-
if (result?.removed) {
|
|
80
|
-
return action(this, "removed", true, result.openclawConfigPath);
|
|
81
|
-
}
|
|
82
|
-
if (result?.skippedReason === "openclaw-config-missing") {
|
|
83
|
-
return action(this, "skipped", false, "openclaw config not found", {
|
|
84
|
-
skippedReason: result.skippedReason,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
if (result?.skippedReason === "openclaw-config-unreadable") {
|
|
88
|
-
return action(
|
|
89
|
-
this,
|
|
90
|
-
"skipped",
|
|
91
|
-
false,
|
|
92
|
-
result.error ? `openclaw config unreadable: ${result.error}` : "openclaw config unreadable",
|
|
93
|
-
{ skippedReason: result.skippedReason },
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
return action(this, "unchanged", false, "no change");
|
|
97
|
-
},
|
|
98
|
-
renderStatusValue(probe) {
|
|
99
|
-
if (probe.status === "not_installed") return "unset";
|
|
100
|
-
return probe.status;
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
function baseProbe(descriptor, values) {
|
|
105
|
-
return {
|
|
106
|
-
name: descriptor.name,
|
|
107
|
-
summaryLabel: descriptor.summaryLabel,
|
|
108
|
-
statusLabel: descriptor.statusLabel,
|
|
109
|
-
configured: false,
|
|
110
|
-
...values,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function action(descriptor, status, changed, detail, extras = {}) {
|
|
115
|
-
return {
|
|
116
|
-
name: descriptor.name,
|
|
117
|
-
label: descriptor.summaryLabel,
|
|
118
|
-
status,
|
|
119
|
-
changed,
|
|
120
|
-
detail,
|
|
121
|
-
...extras,
|
|
122
|
-
};
|
|
123
|
-
}
|