vibeusage 0.3.2 → 0.3.4

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.
@@ -337,31 +337,79 @@ function buildSessionPluginMeta() {
337
337
  )}\n`;
338
338
  }
339
339
 
340
- function buildSessionPluginIndex({ trackerDir }) {
340
+ function buildSessionPluginIndex({ trackerDir, packageName = "vibeusage" }) {
341
341
  const ledgerModuleUrl = pathToFileURL(
342
342
  path.join(trackerDir, "app", "src", "lib", "openclaw-usage-ledger.js"),
343
343
  ).href;
344
+ const trackerBinPath = path.join(trackerDir, "app", "bin", "tracker.js");
345
+ const fallbackPkg = packageName || "vibeusage";
344
346
 
345
347
  return (
348
+ `import fs from 'node:fs';\n` +
349
+ `import path from 'node:path';\n` +
350
+ `import cp from 'node:child_process';\n` +
346
351
  `import { appendOpenclawUsageEvent } from ${JSON.stringify(ledgerModuleUrl)};\n` +
347
352
  `\n` +
348
353
  `const trackerDir = ${JSON.stringify(trackerDir)};\n` +
354
+ `const trackerBinPath = ${JSON.stringify(trackerBinPath)};\n` +
355
+ `const fallbackPkg = ${JSON.stringify(fallbackPkg)};\n` +
356
+ `const depsMarkerPath = path.join(trackerDir, 'app', 'node_modules', '@insforge', 'sdk', 'package.json');\n` +
357
+ `const triggerStatePath = path.join(trackerDir, 'openclaw.session-sync.trigger-state.json');\n` +
358
+ `const SESSION_TRIGGER_THROTTLE_MS = 15_000;\n` +
349
359
  `\n` +
350
360
  `export default function register(api) {\n` +
351
361
  ` api.on('llm_output', async (event, ctx) => {\n` +
352
362
  ` try {\n` +
353
363
  ` const payload = buildPayload(event, ctx);\n` +
354
364
  ` if (!payload) return;\n` +
355
- ` await appendOpenclawUsageEvent({ trackerDir, payload });\n` +
365
+ ` const result = await appendOpenclawUsageEvent({ trackerDir, payload });\n` +
366
+ ` if (!result || result.appended === false) return;\n` +
367
+ ` const scope = normalize(ctx && ctx.agentId) || 'openclaw';\n` +
368
+ ` const target = resolveSessionRef(event, ctx) || normalize(payload.eventId) || 'unknown';\n` +
369
+ ` if (!allowTrigger('llm_output', scope, target)) return;\n` +
370
+ ` spawnSync({ args: ['sync', '--auto', '--from-openclaw'] });\n` +
356
371
  ` } catch (_) {}\n` +
357
372
  ` });\n` +
358
373
  `}\n` +
359
374
  `\n` +
375
+ `function spawnSync({ args }) {\n` +
376
+ ` const hasLocalRuntime = fs.existsSync(trackerBinPath);\n` +
377
+ ` const hasLocalDeps = fs.existsSync(depsMarkerPath);\n` +
378
+ ` const argv = Array.isArray(args) && args.length > 0 ? args : ['sync', '--auto'];\n` +
379
+ ` const cmd = hasLocalRuntime && hasLocalDeps\n` +
380
+ ` ? [process.execPath, trackerBinPath, ...argv]\n` +
381
+ ` : ['npx', '--yes', fallbackPkg, ...argv];\n` +
382
+ ` const child = cp.spawn(cmd[0], cmd.slice(1), {\n` +
383
+ ` detached: true,\n` +
384
+ ` stdio: 'ignore',\n` +
385
+ ` env: { ...process.env }\n` +
386
+ ` });\n` +
387
+ ` child.unref();\n` +
388
+ `}\n` +
389
+ `\n` +
390
+ `function allowTrigger(kind, scope, target) {\n` +
391
+ ` const key = [kind, scope || 'na', target || 'na'].join(':');\n` +
392
+ ` const now = Date.now();\n` +
393
+ ` let state = {};\n` +
394
+ ` try {\n` +
395
+ ` state = JSON.parse(fs.readFileSync(triggerStatePath, 'utf8'));\n` +
396
+ ` if (!state || typeof state !== 'object') state = {};\n` +
397
+ ` } catch (_) {}\n` +
398
+ ` const last = Number(state[key] || 0);\n` +
399
+ ` if (Number.isFinite(last) && now - last < SESSION_TRIGGER_THROTTLE_MS) return false;\n` +
400
+ ` state[key] = now;\n` +
401
+ ` try {\n` +
402
+ ` fs.mkdirSync(path.dirname(triggerStatePath), { recursive: true });\n` +
403
+ ` fs.writeFileSync(triggerStatePath, JSON.stringify(state), 'utf8');\n` +
404
+ ` } catch (_) {}\n` +
405
+ ` return true;\n` +
406
+ `}\n` +
407
+ `\n` +
360
408
  `function buildPayload(event, ctx) {\n` +
361
409
  ` const usage = normalizeUsage(event);\n` +
362
410
  ` if (!usage) return null;\n` +
363
411
  `\n` +
364
- ` const sessionKey = normalize(ctx && ctx.sessionKey);\n` +
412
+ ` const sessionKey = resolveSessionRef(event, ctx);\n` +
365
413
  ` if (!sessionKey) return null;\n` +
366
414
  `\n` +
367
415
  ` return {\n` +
@@ -378,6 +426,22 @@ function buildSessionPluginIndex({ trackerDir }) {
378
426
  ` };\n` +
379
427
  `}\n` +
380
428
  `\n` +
429
+ `function resolveSessionRef(event, ctx) {\n` +
430
+ ` const explicit = normalize(ctx && ctx.sessionKey);\n` +
431
+ ` if (explicit) return explicit;\n` +
432
+ ` const eventSessionId = normalize(event && event.sessionId);\n` +
433
+ ` if (eventSessionId) {\n` +
434
+ ` const agentId = normalize(ctx && ctx.agentId) || 'openclaw';\n` +
435
+ ` return 'agent:' + agentId + ':session:' + eventSessionId;\n` +
436
+ ` }\n` +
437
+ ` const ctxSessionId = normalize(ctx && ctx.sessionId);\n` +
438
+ ` if (ctxSessionId) {\n` +
439
+ ` const agentId = normalize(ctx && ctx.agentId) || 'openclaw';\n` +
440
+ ` return 'agent:' + agentId + ':session:' + ctxSessionId;\n` +
441
+ ` }\n` +
442
+ ` return null;\n` +
443
+ `}\n` +
444
+ `\n` +
381
445
  `function normalizeUsage(event) {\n` +
382
446
  ` const usage = event && typeof event.usage === 'object' ? event.usage : event || {};\n` +
383
447
  ` const normalized = {\n` +
@@ -385,7 +449,7 @@ function buildSessionPluginIndex({ trackerDir }) {
385
449
  ` cachedInputTokens: toNonNegativeInt(usage.cachedInputTokens ?? usage.cached_input_tokens ?? usage.cacheRead ?? 0) + toNonNegativeInt(usage.cacheWrite ?? 0),\n` +
386
450
  ` outputTokens: toNonNegativeInt(usage.outputTokens ?? usage.output_tokens ?? usage.output),\n` +
387
451
  ` reasoningOutputTokens: toNonNegativeInt(usage.reasoningOutputTokens ?? usage.reasoning_output_tokens),\n` +
388
- ` totalTokens: toNonNegativeInt(usage.totalTokens ?? usage.total_tokens)\n` +
452
+ ` totalTokens: toNonNegativeInt(usage.totalTokens ?? usage.total_tokens ?? usage.total)\n` +
389
453
  ` };\n` +
390
454
  ` const sum = normalized.inputTokens + normalized.cachedInputTokens + normalized.outputTokens + normalized.reasoningOutputTokens + normalized.totalTokens;\n` +
391
455
  ` return sum > 0 ? normalized : null;\n` +