vibeusage 0.2.23 → 0.3.1

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.
Files changed (143) hide show
  1. package/README.md +25 -20
  2. package/README.zh-CN.md +7 -2
  3. package/node_modules/@insforge/sdk/LICENSE +201 -201
  4. package/node_modules/@insforge/sdk/README.md +326 -259
  5. package/node_modules/@insforge/sdk/dist/index.d.mts +377 -182
  6. package/node_modules/@insforge/sdk/dist/index.d.ts +377 -182
  7. package/node_modules/@insforge/sdk/dist/index.js +1172 -677
  8. package/node_modules/@insforge/sdk/dist/index.js.map +1 -1
  9. package/node_modules/@insforge/sdk/dist/index.mjs +1171 -677
  10. package/node_modules/@insforge/sdk/dist/index.mjs.map +1 -1
  11. package/node_modules/@insforge/sdk/package.json +68 -68
  12. package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.d.ts +1120 -43
  13. package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.d.ts.map +1 -1
  14. package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.js +179 -5
  15. package/node_modules/@insforge/shared-schemas/dist/ai-api.schema.js.map +1 -1
  16. package/node_modules/@insforge/shared-schemas/dist/ai.schema.d.ts +25 -25
  17. package/node_modules/@insforge/shared-schemas/dist/ai.schema.d.ts.map +1 -1
  18. package/node_modules/@insforge/shared-schemas/dist/ai.schema.js +2 -2
  19. package/node_modules/@insforge/shared-schemas/dist/ai.schema.js.map +1 -1
  20. package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.d.ts +197 -51
  21. package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.d.ts.map +1 -1
  22. package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.js +87 -23
  23. package/node_modules/@insforge/shared-schemas/dist/auth-api.schema.js.map +1 -1
  24. package/node_modules/@insforge/shared-schemas/dist/auth.schema.d.ts +32 -3
  25. package/node_modules/@insforge/shared-schemas/dist/auth.schema.d.ts.map +1 -1
  26. package/node_modules/@insforge/shared-schemas/dist/auth.schema.js +21 -3
  27. package/node_modules/@insforge/shared-schemas/dist/auth.schema.js.map +1 -1
  28. package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.d.ts +380 -0
  29. package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.d.ts.map +1 -1
  30. package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.js +74 -0
  31. package/node_modules/@insforge/shared-schemas/dist/cloud-events.schema.js.map +1 -1
  32. package/node_modules/@insforge/shared-schemas/dist/database-api.schema.d.ts +13 -13
  33. package/node_modules/@insforge/shared-schemas/dist/database-api.schema.js +1 -1
  34. package/node_modules/@insforge/shared-schemas/dist/database-api.schema.js.map +1 -1
  35. package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.d.ts +735 -0
  36. package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.d.ts.map +1 -0
  37. package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.js +209 -0
  38. package/node_modules/@insforge/shared-schemas/dist/deployments-api.schema.js.map +1 -0
  39. package/node_modules/@insforge/shared-schemas/dist/deployments.schema.d.ts +37 -0
  40. package/node_modules/@insforge/shared-schemas/dist/deployments.schema.d.ts.map +1 -0
  41. package/node_modules/@insforge/shared-schemas/dist/deployments.schema.js +25 -0
  42. package/node_modules/@insforge/shared-schemas/dist/deployments.schema.js.map +1 -0
  43. package/node_modules/@insforge/shared-schemas/dist/docs.schema.d.ts +5 -1
  44. package/node_modules/@insforge/shared-schemas/dist/docs.schema.d.ts.map +1 -1
  45. package/node_modules/@insforge/shared-schemas/dist/docs.schema.js +34 -4
  46. package/node_modules/@insforge/shared-schemas/dist/docs.schema.js.map +1 -1
  47. package/node_modules/@insforge/shared-schemas/dist/email-api.schema.js +1 -1
  48. package/node_modules/@insforge/shared-schemas/dist/email-api.schema.js.map +1 -1
  49. package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.d.ts +186 -6
  50. package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.d.ts.map +1 -1
  51. package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.js +21 -2
  52. package/node_modules/@insforge/shared-schemas/dist/functions-api.schema.js.map +1 -1
  53. package/node_modules/@insforge/shared-schemas/dist/functions.schema.d.ts +5 -5
  54. package/node_modules/@insforge/shared-schemas/dist/functions.schema.js +1 -1
  55. package/node_modules/@insforge/shared-schemas/dist/functions.schema.js.map +1 -1
  56. package/node_modules/@insforge/shared-schemas/dist/index.d.ts +24 -18
  57. package/node_modules/@insforge/shared-schemas/dist/index.d.ts.map +1 -1
  58. package/node_modules/@insforge/shared-schemas/dist/index.js +24 -18
  59. package/node_modules/@insforge/shared-schemas/dist/index.js.map +1 -1
  60. package/node_modules/@insforge/shared-schemas/dist/logs-api.schema.js +1 -1
  61. package/node_modules/@insforge/shared-schemas/dist/logs-api.schema.js.map +1 -1
  62. package/node_modules/@insforge/shared-schemas/dist/logs.schema.d.ts +43 -0
  63. package/node_modules/@insforge/shared-schemas/dist/logs.schema.d.ts.map +1 -1
  64. package/node_modules/@insforge/shared-schemas/dist/logs.schema.js +11 -0
  65. package/node_modules/@insforge/shared-schemas/dist/logs.schema.js.map +1 -1
  66. package/node_modules/@insforge/shared-schemas/dist/metadata.schema.d.ts +229 -172
  67. package/node_modules/@insforge/shared-schemas/dist/metadata.schema.d.ts.map +1 -1
  68. package/node_modules/@insforge/shared-schemas/dist/metadata.schema.js +27 -7
  69. package/node_modules/@insforge/shared-schemas/dist/metadata.schema.js.map +1 -1
  70. package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.d.ts +51 -0
  71. package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.d.ts.map +1 -0
  72. package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.js +31 -0
  73. package/node_modules/@insforge/shared-schemas/dist/rate-limit-api.schema.js.map +1 -0
  74. package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.d.ts +31 -0
  75. package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.d.ts.map +1 -0
  76. package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.js +12 -0
  77. package/node_modules/@insforge/shared-schemas/dist/rate-limit.schema.js.map +1 -0
  78. package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.d.ts +39 -20
  79. package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.d.ts.map +1 -1
  80. package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.js +5 -1
  81. package/node_modules/@insforge/shared-schemas/dist/realtime-api.schema.js.map +1 -1
  82. package/node_modules/@insforge/shared-schemas/dist/realtime.schema.d.ts +12 -4
  83. package/node_modules/@insforge/shared-schemas/dist/realtime.schema.d.ts.map +1 -1
  84. package/node_modules/@insforge/shared-schemas/dist/realtime.schema.js +6 -0
  85. package/node_modules/@insforge/shared-schemas/dist/realtime.schema.js.map +1 -1
  86. package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.d.ts +287 -0
  87. package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.d.ts.map +1 -0
  88. package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.js +81 -0
  89. package/node_modules/@insforge/shared-schemas/dist/schedules-api.schema.js.map +1 -0
  90. package/node_modules/@insforge/shared-schemas/dist/schedules.schema.d.ts +77 -0
  91. package/node_modules/@insforge/shared-schemas/dist/schedules.schema.d.ts.map +1 -0
  92. package/node_modules/@insforge/shared-schemas/dist/schedules.schema.js +36 -0
  93. package/node_modules/@insforge/shared-schemas/dist/schedules.schema.js.map +1 -0
  94. package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.d.ts +113 -0
  95. package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.d.ts.map +1 -0
  96. package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.js +31 -0
  97. package/node_modules/@insforge/shared-schemas/dist/secrets-api.schema.js.map +1 -0
  98. package/node_modules/@insforge/shared-schemas/dist/secrets.schema.d.ts +31 -0
  99. package/node_modules/@insforge/shared-schemas/dist/secrets.schema.d.ts.map +1 -0
  100. package/node_modules/@insforge/shared-schemas/dist/secrets.schema.js +13 -0
  101. package/node_modules/@insforge/shared-schemas/dist/secrets.schema.js.map +1 -0
  102. package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.d.ts +27 -2
  103. package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.d.ts.map +1 -1
  104. package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.js +9 -1
  105. package/node_modules/@insforge/shared-schemas/dist/storage-api.schema.js.map +1 -1
  106. package/node_modules/@insforge/shared-schemas/dist/storage.schema.d.ts +17 -0
  107. package/node_modules/@insforge/shared-schemas/dist/storage.schema.d.ts.map +1 -1
  108. package/node_modules/@insforge/shared-schemas/dist/storage.schema.js +6 -0
  109. package/node_modules/@insforge/shared-schemas/dist/storage.schema.js.map +1 -1
  110. package/node_modules/@insforge/shared-schemas/package.json +2 -1
  111. package/package.json +5 -6
  112. package/src/cli.js +2 -2
  113. package/src/commands/init.js +20 -362
  114. package/src/commands/status.js +58 -51
  115. package/src/commands/sync.js +37 -25
  116. package/src/commands/uninstall.js +121 -104
  117. package/src/lib/claude-config.js +130 -35
  118. package/src/lib/diagnostics.js +88 -57
  119. package/src/lib/doctor.js +50 -0
  120. package/src/lib/insforge-client.js +13 -9
  121. package/src/lib/integrations/claude.js +106 -0
  122. package/src/lib/integrations/codex.js +88 -0
  123. package/src/lib/integrations/context.js +76 -0
  124. package/src/lib/integrations/every-code.js +88 -0
  125. package/src/lib/integrations/gemini.js +86 -0
  126. package/src/lib/integrations/index.js +85 -0
  127. package/src/lib/integrations/openclaw-legacy.js +123 -0
  128. package/src/lib/integrations/openclaw-session.js +132 -0
  129. package/src/lib/integrations/opencode.js +86 -0
  130. package/src/lib/integrations/utils.js +39 -0
  131. package/src/lib/opencode-sqlite.js +113 -0
  132. package/src/lib/opencode-usage-audit.js +3 -2
  133. package/src/lib/rollout.js +227 -1
  134. package/src/lib/runtime-config.js +7 -5
  135. package/src/lib/vibeusage-api.js +11 -7
  136. package/src/shared/copy-registry.cjs +142 -0
  137. package/src/shared/copy-registry.cjs.d.ts +33 -0
  138. package/src/shared/runtime-defaults.cjs +11 -0
  139. package/src/shared/runtime-defaults.cjs.d.ts +3 -0
  140. package/src/shared/vibeusage-function-contract.cjs +34 -0
  141. package/src/shared/vibeusage-function-contract.cjs.d.ts +4 -0
  142. package/src/commands/activate-if-needed.js +0 -41
  143. package/src/lib/activation-check.js +0 -341
@@ -13,34 +13,6 @@ const {
13
13
  chmod600IfPossible,
14
14
  } = require("../lib/fs");
15
15
  const { prompt, promptHidden } = require("../lib/prompt");
16
- const {
17
- upsertCodexNotify,
18
- upsertEveryCodeNotify,
19
- readCodexNotify,
20
- readEveryCodeNotify,
21
- } = require("../lib/codex-config");
22
- const {
23
- upsertClaudeHook,
24
- buildClaudeHookCommand,
25
- isClaudeHookConfigured,
26
- } = require("../lib/claude-config");
27
- const {
28
- resolveGeminiConfigDir,
29
- resolveGeminiSettingsPath,
30
- buildGeminiHookCommand,
31
- upsertGeminiHook,
32
- isGeminiHookConfigured,
33
- } = require("../lib/gemini-config");
34
- const {
35
- resolveOpencodeConfigDir,
36
- upsertOpencodePlugin,
37
- isOpencodePluginInstalled,
38
- } = require("../lib/opencode-config");
39
- const { removeOpenclawHookConfig, probeOpenclawHookState } = require("../lib/openclaw-hook");
40
- const {
41
- installOpenclawSessionPlugin,
42
- probeOpenclawSessionPluginState,
43
- } = require("../lib/openclaw-session-plugin");
44
16
  const { beginBrowserAuth, openInBrowser } = require("../lib/browser-auth");
45
17
  const {
46
18
  issueDeviceTokenWithPassword,
@@ -60,6 +32,13 @@ const {
60
32
  createSpinner,
61
33
  } = require("../lib/cli-ui");
62
34
  const { renderLocalReport, renderAuthTransition, renderSuccessBox } = require("../lib/init-flow");
35
+ const {
36
+ createIntegrationContext,
37
+ installIntegrations,
38
+ probeIntegrations,
39
+ summarizeProbeForInitPreview,
40
+ } = require("../lib/integrations");
41
+ const { DEFAULT_DASHBOARD_URL } = require("../shared/runtime-defaults.cjs");
63
42
 
64
43
  const ASCII_LOGO = [
65
44
  "██╗ ██╗██╗██████╗ ███████╗██╗ ██╗███████╗ █████╗ ██████╗ ███████╗",
@@ -71,16 +50,13 @@ const ASCII_LOGO = [
71
50
  ].join("\n");
72
51
 
73
52
  const DIVIDER = "----------------------------------------------";
74
- const DEFAULT_DASHBOARD_URL = "https://www.vibeusage.cc";
75
-
76
53
  async function cmdInit(argv) {
77
54
  const opts = parseArgs(argv);
78
55
  const home = os.homedir();
79
56
 
80
- const { rootDir, trackerDir, binDir } = await resolveTrackerPaths({ home });
57
+ const { trackerDir, binDir } = await resolveTrackerPaths({ home });
81
58
 
82
59
  const configPath = path.join(trackerDir, "config.json");
83
- const notifyOriginalPath = path.join(trackerDir, "codex_notify_original.json");
84
60
  const linkCodeStatePath = path.join(trackerDir, "link_code_state.json");
85
61
 
86
62
  const existingConfig = await readJson(configPath);
@@ -144,7 +120,6 @@ async function cmdInit(argv) {
144
120
  trackerDir,
145
121
  binDir,
146
122
  configPath,
147
- notifyOriginalPath,
148
123
  linkCodeStatePath,
149
124
  notifyPath,
150
125
  appDir,
@@ -253,8 +228,14 @@ function shouldUseBrowserAuth({ deviceToken, opts }) {
253
228
  async function buildDryRunSummary({ opts, home, trackerDir, notifyPath, runtime }) {
254
229
  const deviceToken = runtime?.deviceToken || null;
255
230
  const pendingBrowserAuth = shouldUseBrowserAuth({ deviceToken, opts });
256
- const context = buildIntegrationTargets({ home, trackerDir, notifyPath });
257
- const summary = await previewIntegrations({ context });
231
+ const context = await createIntegrationContext({
232
+ home,
233
+ env: process.env,
234
+ trackerPaths: { trackerDir, binDir: path.dirname(notifyPath), rootDir: path.dirname(trackerDir) },
235
+ notifyPath,
236
+ });
237
+ const probe = await probeIntegrations(context);
238
+ const summary = probe.map((item) => summarizeProbeForInitPreview(item));
258
239
  return { summary, pendingBrowserAuth, deviceToken };
259
240
  }
260
241
 
@@ -265,7 +246,6 @@ async function runSetup({
265
246
  trackerDir,
266
247
  binDir,
267
248
  configPath,
268
- notifyOriginalPath,
269
249
  linkCodeStatePath,
270
250
  notifyPath,
271
251
  appDir,
@@ -341,12 +321,13 @@ async function runSetup({
341
321
  );
342
322
  await fs.chmod(notifyPath, 0o755).catch(() => {});
343
323
 
344
- const summary = await applyIntegrationSetup({
324
+ const integrationContext = await createIntegrationContext({
345
325
  home,
346
- trackerDir,
326
+ env: process.env,
327
+ trackerPaths: { trackerDir, binDir, rootDir: path.dirname(trackerDir) },
347
328
  notifyPath,
348
- notifyOriginalPath,
349
329
  });
330
+ const summary = await installIntegrations(integrationContext);
350
331
 
351
332
  return {
352
333
  summary,
@@ -357,307 +338,6 @@ async function runSetup({
357
338
  };
358
339
  }
359
340
 
360
- function buildIntegrationTargets({ home, trackerDir, notifyPath }) {
361
- const codexHome = process.env.CODEX_HOME || path.join(home, ".codex");
362
- const codexConfigPath = path.join(codexHome, "config.toml");
363
- const codeHome = process.env.CODE_HOME || path.join(home, ".code");
364
- const codeConfigPath = path.join(codeHome, "config.toml");
365
- const notifyOriginalPath = path.join(trackerDir, "codex_notify_original.json");
366
- const codeNotifyOriginalPath = path.join(trackerDir, "code_notify_original.json");
367
- const notifyCmd = ["/usr/bin/env", "node", notifyPath];
368
- const codeNotifyCmd = ["/usr/bin/env", "node", notifyPath, "--source=every-code"];
369
- const claudeDir = path.join(home, ".claude");
370
- const claudeSettingsPath = path.join(claudeDir, "settings.json");
371
- const claudeHookCommand = buildClaudeHookCommand(notifyPath);
372
- const geminiConfigDir = resolveGeminiConfigDir({ home, env: process.env });
373
- const geminiSettingsPath = resolveGeminiSettingsPath({ configDir: geminiConfigDir });
374
- const geminiHookCommand = buildGeminiHookCommand(notifyPath);
375
- const opencodeConfigDir = resolveOpencodeConfigDir({ home, env: process.env });
376
-
377
- return {
378
- trackerDir,
379
- codexConfigPath,
380
- codeConfigPath,
381
- notifyOriginalPath,
382
- codeNotifyOriginalPath,
383
- notifyCmd,
384
- codeNotifyCmd,
385
- claudeDir,
386
- claudeSettingsPath,
387
- claudeHookCommand,
388
- geminiConfigDir,
389
- geminiSettingsPath,
390
- geminiHookCommand,
391
- opencodeConfigDir,
392
- };
393
- }
394
-
395
- async function applyIntegrationSetup({ home, trackerDir, notifyPath, notifyOriginalPath }) {
396
- const context = buildIntegrationTargets({ home, trackerDir, notifyPath });
397
- context.notifyOriginalPath = notifyOriginalPath;
398
-
399
- const summary = [];
400
-
401
- const codexProbe = await probeFile(context.codexConfigPath);
402
- if (codexProbe.exists) {
403
- const result = await upsertCodexNotify({
404
- codexConfigPath: context.codexConfigPath,
405
- notifyCmd: context.notifyCmd,
406
- notifyOriginalPath: context.notifyOriginalPath,
407
- });
408
- summary.push({
409
- label: "Codex CLI",
410
- status: result.changed ? "updated" : "set",
411
- detail: result.changed ? "Updated config" : "Config already set",
412
- });
413
- } else {
414
- summary.push({ label: "Codex CLI", status: "skipped", detail: renderSkipDetail(codexProbe) });
415
- }
416
-
417
- const claudeDirExists = await isDir(context.claudeDir);
418
- if (claudeDirExists) {
419
- await upsertClaudeHook({
420
- settingsPath: context.claudeSettingsPath,
421
- hookCommand: context.claudeHookCommand,
422
- });
423
- summary.push({ label: "Claude", status: "installed", detail: "Hooks installed" });
424
- } else {
425
- summary.push({ label: "Claude", status: "skipped", detail: "Config not found" });
426
- }
427
-
428
- const geminiConfigExists = await isDir(context.geminiConfigDir);
429
- if (geminiConfigExists) {
430
- await upsertGeminiHook({
431
- settingsPath: context.geminiSettingsPath,
432
- hookCommand: context.geminiHookCommand,
433
- });
434
- summary.push({ label: "Gemini", status: "installed", detail: "Hooks installed" });
435
- } else {
436
- summary.push({ label: "Gemini", status: "skipped", detail: "Config not found" });
437
- }
438
-
439
- const opencodeResult = await upsertOpencodePlugin({
440
- configDir: context.opencodeConfigDir,
441
- notifyPath,
442
- });
443
- if (opencodeResult?.skippedReason === "config-missing") {
444
- summary.push({ label: "Opencode Plugin", status: "skipped", detail: "Config not found" });
445
- } else {
446
- summary.push({
447
- label: "Opencode Plugin",
448
- status: opencodeResult?.changed ? "installed" : "set",
449
- detail: "Plugin installed",
450
- });
451
- }
452
-
453
- const openclawBefore = await probeOpenclawSessionPluginState({
454
- home,
455
- trackerDir,
456
- env: process.env,
457
- });
458
- const openclawInstall = await installOpenclawSessionPlugin({
459
- home,
460
- trackerDir,
461
- packageName: "vibeusage",
462
- env: process.env,
463
- });
464
- if (openclawInstall?.skippedReason === "openclaw-cli-missing") {
465
- summary.push({
466
- label: "OpenClaw Session Plugin",
467
- status: "skipped",
468
- detail: "OpenClaw CLI not found",
469
- });
470
- } else if (openclawInstall?.skippedReason === "openclaw-plugins-install-failed") {
471
- summary.push({
472
- label: "OpenClaw Session Plugin",
473
- status: "skipped",
474
- detail: `Install failed${openclawInstall.error ? `: ${openclawInstall.error}` : ""}`,
475
- });
476
- } else if (openclawInstall?.skippedReason === "openclaw-config-unreadable") {
477
- summary.push({
478
- label: "OpenClaw Session Plugin",
479
- status: "skipped",
480
- detail: openclawInstall.error
481
- ? `OpenClaw config unreadable: ${openclawInstall.error}`
482
- : "OpenClaw config unreadable",
483
- });
484
- } else if (openclawInstall?.configured) {
485
- summary.push({
486
- label: "OpenClaw Session Plugin",
487
- status: openclawBefore?.configured ? "set" : "installed",
488
- detail: openclawBefore?.configured
489
- ? "Session plugin already linked"
490
- : "Session plugin linked (restart OpenClaw gateway to activate)",
491
- });
492
- } else {
493
- summary.push({
494
- label: "OpenClaw Session Plugin",
495
- status: "skipped",
496
- detail: "OpenClaw session plugin unavailable",
497
- });
498
- }
499
-
500
- const legacyHookState = await probeOpenclawHookState({ home, trackerDir, env: process.env });
501
- if (legacyHookState?.configured || legacyHookState?.linked || legacyHookState?.enabled) {
502
- await removeOpenclawHookConfig({ home, trackerDir, env: process.env });
503
- summary.push({
504
- label: "OpenClaw Hook (legacy)",
505
- status: "updated",
506
- detail: "Removed legacy command hook (migrated to session plugin)",
507
- });
508
- }
509
-
510
- const codeProbe = await probeFile(context.codeConfigPath);
511
- if (codeProbe.exists) {
512
- const result = await upsertEveryCodeNotify({
513
- codeConfigPath: context.codeConfigPath,
514
- notifyCmd: context.codeNotifyCmd,
515
- notifyOriginalPath: context.codeNotifyOriginalPath,
516
- });
517
- summary.push({
518
- label: "Every Code",
519
- status: result.changed ? "updated" : "set",
520
- detail: result.changed ? "Updated config" : "Config already set",
521
- });
522
- } else {
523
- summary.push({ label: "Every Code", status: "skipped", detail: renderSkipDetail(codeProbe) });
524
- }
525
-
526
- return summary;
527
- }
528
-
529
- async function previewIntegrations({ context }) {
530
- const summary = [];
531
- const home = os.homedir();
532
-
533
- const codexProbe = await probeFile(context.codexConfigPath);
534
- if (codexProbe.exists) {
535
- const existing = await readCodexNotify(context.codexConfigPath);
536
- const matches = arraysEqual(existing, context.notifyCmd);
537
- summary.push({
538
- label: "Codex CLI",
539
- status: matches ? "set" : "updated",
540
- detail: matches ? "Already configured" : "Will update config",
541
- });
542
- } else {
543
- summary.push({ label: "Codex CLI", status: "skipped", detail: renderSkipDetail(codexProbe) });
544
- }
545
-
546
- const claudeDirExists = await isDir(context.claudeDir);
547
- if (claudeDirExists) {
548
- const configured = await isClaudeHookConfigured({
549
- settingsPath: context.claudeSettingsPath,
550
- hookCommand: context.claudeHookCommand,
551
- });
552
- summary.push({
553
- label: "Claude",
554
- status: "installed",
555
- detail: configured ? "Hooks already installed" : "Will install hooks",
556
- });
557
- } else {
558
- summary.push({ label: "Claude", status: "skipped", detail: "Config not found" });
559
- }
560
-
561
- const geminiConfigExists = await isDir(context.geminiConfigDir);
562
- if (geminiConfigExists) {
563
- const configured = await isGeminiHookConfigured({
564
- settingsPath: context.geminiSettingsPath,
565
- hookCommand: context.geminiHookCommand,
566
- });
567
- summary.push({
568
- label: "Gemini",
569
- status: "installed",
570
- detail: configured ? "Hooks already installed" : "Will install hooks",
571
- });
572
- } else {
573
- summary.push({ label: "Gemini", status: "skipped", detail: "Config not found" });
574
- }
575
-
576
- const opencodeDirExists = await isDir(context.opencodeConfigDir);
577
- const installed = await isOpencodePluginInstalled({ configDir: context.opencodeConfigDir });
578
- const opencodeDetail = installed
579
- ? "Plugin already installed"
580
- : opencodeDirExists
581
- ? "Will install plugin"
582
- : "Will create config and install plugin";
583
- summary.push({
584
- label: "Opencode Plugin",
585
- status: "installed",
586
- detail: opencodeDetail,
587
- });
588
-
589
- const openclawState = await probeOpenclawSessionPluginState({
590
- home,
591
- trackerDir: context.trackerDir,
592
- env: process.env,
593
- });
594
- if (openclawState?.skippedReason === "openclaw-config-missing") {
595
- summary.push({
596
- label: "OpenClaw Session Plugin",
597
- status: "skipped",
598
- detail: "OpenClaw config not found",
599
- });
600
- } else if (openclawState?.skippedReason === "openclaw-config-unreadable") {
601
- summary.push({
602
- label: "OpenClaw Session Plugin",
603
- status: "skipped",
604
- detail: openclawState.error
605
- ? `OpenClaw config unreadable: ${openclawState.error}`
606
- : "OpenClaw config unreadable",
607
- });
608
- } else {
609
- summary.push({
610
- label: "OpenClaw Session Plugin",
611
- status: openclawState?.configured ? "set" : "installed",
612
- detail: openclawState?.configured
613
- ? "Session plugin already linked"
614
- : "Will link session plugin (restart OpenClaw gateway to activate)",
615
- });
616
- }
617
-
618
- const legacyHookState = await probeOpenclawHookState({
619
- home,
620
- trackerDir: context.trackerDir,
621
- env: process.env,
622
- });
623
- if (legacyHookState?.configured || legacyHookState?.linked || legacyHookState?.enabled) {
624
- summary.push({
625
- label: "OpenClaw Hook (legacy)",
626
- status: "updated",
627
- detail: "Will remove legacy command hook during migration",
628
- });
629
- }
630
-
631
- const codeProbe = await probeFile(context.codeConfigPath);
632
- if (codeProbe.exists) {
633
- const existing = await readEveryCodeNotify(context.codeConfigPath);
634
- const matches = arraysEqual(existing, context.codeNotifyCmd);
635
- summary.push({
636
- label: "Every Code",
637
- status: matches ? "set" : "updated",
638
- detail: matches ? "Already configured" : "Will update config",
639
- });
640
- } else {
641
- summary.push({ label: "Every Code", status: "skipped", detail: renderSkipDetail(codeProbe) });
642
- }
643
-
644
- return summary;
645
- }
646
-
647
- function renderSkipDetail(probe) {
648
- if (!probe || probe.reason === "missing") return "Config not found";
649
- if (probe.reason === "permission-denied") return "Permission denied";
650
- if (probe.reason === "not-file") return "Invalid config";
651
- return "Unavailable";
652
- }
653
-
654
- function arraysEqual(a, b) {
655
- if (!Array.isArray(a) || !Array.isArray(b)) return false;
656
- if (a.length !== b.length) return false;
657
- for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
658
- return true;
659
- }
660
-
661
341
  function parseArgs(argv) {
662
342
  const out = {
663
343
  baseUrl: null,
@@ -853,28 +533,6 @@ function isSelfNotify(cmd) {
853
533
 
854
534
  module.exports = { cmdInit };
855
535
 
856
- async function probeFile(p) {
857
- try {
858
- const st = await fs.stat(p);
859
- if (st.isFile()) return { exists: true, reason: null };
860
- return { exists: false, reason: "not-file" };
861
- } catch (e) {
862
- if (e?.code === "ENOENT" || e?.code === "ENOTDIR") return { exists: false, reason: "missing" };
863
- if (e?.code === "EACCES" || e?.code === "EPERM")
864
- return { exists: false, reason: "permission-denied" };
865
- return { exists: false, reason: "error", code: e?.code || "unknown" };
866
- }
867
- }
868
-
869
- async function isDir(p) {
870
- try {
871
- const st = await fs.stat(p);
872
- return st.isDirectory();
873
- } catch (_e) {
874
- return false;
875
- }
876
- }
877
-
878
536
  async function installLocalTrackerApp({ appDir }) {
879
537
  // Copy the current package's runtime (bin + src) into ~/.vibeusage so notify can run sync without npx.
880
538
  const packageRoot = path.resolve(__dirname, "../..");
@@ -3,20 +3,10 @@ const path = require("node:path");
3
3
  const fs = require("node:fs/promises");
4
4
 
5
5
  const { readJson } = require("../lib/fs");
6
- const { readCodexNotify, readEveryCodeNotify } = require("../lib/codex-config");
7
- const { isClaudeHookConfigured, buildClaudeHookCommand } = require("../lib/claude-config");
8
- const {
9
- resolveGeminiConfigDir,
10
- resolveGeminiSettingsPath,
11
- isGeminiHookConfigured,
12
- buildGeminiHookCommand,
13
- } = require("../lib/gemini-config");
14
- const { resolveOpencodeConfigDir, isOpencodePluginInstalled } = require("../lib/opencode-config");
15
6
  const { collectLocalSubscriptions } = require("../lib/subscriptions");
16
7
  const { normalizeState: normalizeUploadState } = require("../lib/upload-throttle");
17
8
  const { collectTrackerDiagnostics } = require("../lib/diagnostics");
18
- const { probeOpenclawHookState } = require("../lib/openclaw-hook");
19
- const { probeOpenclawSessionPluginState } = require("../lib/openclaw-session-plugin");
9
+ const { createIntegrationContext, listIntegrations, probeIntegrations } = require("../lib/integrations");
20
10
  const { resolveTrackerPaths } = require("../lib/tracker-paths");
21
11
 
22
12
  async function cmdStatus(argv = []) {
@@ -28,7 +18,7 @@ async function cmdStatus(argv = []) {
28
18
  }
29
19
 
30
20
  const home = os.homedir();
31
- const { trackerDir, binDir } = await resolveTrackerPaths({ home });
21
+ const { trackerDir } = await resolveTrackerPaths({ home });
32
22
  const configPath = path.join(trackerDir, "config.json");
33
23
  const queuePath = path.join(trackerDir, "queue.jsonl");
34
24
  const queueStatePath = path.join(trackerDir, "queue.state.json");
@@ -38,17 +28,9 @@ async function cmdStatus(argv = []) {
38
28
  const throttlePath = path.join(trackerDir, "sync.throttle");
39
29
  const uploadThrottlePath = path.join(trackerDir, "upload.throttle.json");
40
30
  const autoRetryPath = path.join(trackerDir, "auto.retry.json");
41
- const codexHome = process.env.CODEX_HOME || path.join(home, ".codex");
42
- const codexConfigPath = path.join(codexHome, "config.toml");
43
- const codeHome = process.env.CODE_HOME || path.join(home, ".code");
44
- const codeConfigPath = path.join(codeHome, "config.toml");
45
- const claudeSettingsPath = path.join(home, ".claude", "settings.json");
46
- const geminiConfigDir = resolveGeminiConfigDir({ home, env: process.env });
47
- const geminiSettingsPath = resolveGeminiSettingsPath({ configDir: geminiConfigDir });
48
- const opencodeConfigDir = resolveOpencodeConfigDir({ home, env: process.env });
49
- const notifyPath = path.join(binDir, "notify.cjs");
50
- const claudeHookCommand = buildClaudeHookCommand(notifyPath);
51
- const geminiHookCommand = buildGeminiHookCommand(notifyPath);
31
+ const xdgDataHome = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
32
+ const opencodeHome = process.env.OPENCODE_HOME || path.join(xdgDataHome, "opencode");
33
+ const opencodeDbPath = path.join(opencodeHome, "opencode.db");
52
34
 
53
35
  const config = await readJson(configPath);
54
36
  const cursors = await readJson(cursorsPath);
@@ -63,27 +45,10 @@ async function cmdStatus(argv = []) {
63
45
  const lastOpenclawSync = (await safeReadText(openclawSignalPath))?.trim() || null;
64
46
  const lastNotifySpawn = parseEpochMsToIso((await safeReadText(throttlePath))?.trim() || null);
65
47
 
66
- const codexNotify = await readCodexNotify(codexConfigPath);
67
- const notifyConfigured = Array.isArray(codexNotify) && codexNotify.length > 0;
68
- const everyCodeNotify = await readEveryCodeNotify(codeConfigPath);
69
- const everyCodeConfigured = Array.isArray(everyCodeNotify) && everyCodeNotify.length > 0;
70
- const claudeHookConfigured = await isClaudeHookConfigured({
71
- settingsPath: claudeSettingsPath,
72
- hookCommand: claudeHookCommand,
73
- });
74
- const geminiHookConfigured = await isGeminiHookConfigured({
75
- settingsPath: geminiSettingsPath,
76
- hookCommand: geminiHookCommand,
77
- });
78
- const opencodePluginConfigured = await isOpencodePluginInstalled({
79
- configDir: opencodeConfigDir,
80
- });
81
- const openclawSessionPluginState = await probeOpenclawSessionPluginState({
82
- home,
83
- trackerDir,
84
- env: process.env,
85
- });
86
- const openclawHookState = await probeOpenclawHookState({ home, trackerDir, env: process.env });
48
+ const integrationContext = await createIntegrationContext({ home, env: process.env });
49
+ const probes = await probeIntegrations(integrationContext);
50
+ const descriptors = new Map(listIntegrations().map((integration) => [integration.name, integration]));
51
+ const probeByName = new Map(probes.map((probe) => [probe.name, probe]));
87
52
 
88
53
  const lastUpload = uploadThrottle.lastSuccessMs
89
54
  ? parseEpochMsToIso(uploadThrottle.lastSuccessMs)
@@ -110,6 +75,22 @@ async function cmdStatus(argv = []) {
110
75
  });
111
76
  const subscriptionLines =
112
77
  subscriptions.length > 0 ? subscriptions.map(formatSubscriptionLine) : [];
78
+ const codexProbe = probeByName.get("codex");
79
+ const everyCodeProbe = probeByName.get("every-code");
80
+ const claudeProbe = probeByName.get("claude");
81
+ const geminiProbe = probeByName.get("gemini");
82
+ const opencodeProbe = probeByName.get("opencode");
83
+ const openclawSessionProbe = probeByName.get("openclaw-session");
84
+ const openclawLegacyProbe = probeByName.get("openclaw-legacy");
85
+ const opencodeDbPresent = Boolean((await safeStat(opencodeDbPath))?.isFile?.());
86
+ const opencodeSqliteState =
87
+ cursors?.opencodeSqlite && typeof cursors.opencodeSqlite === "object"
88
+ ? cursors.opencodeSqlite
89
+ : {};
90
+ const opencodeSqliteReader =
91
+ typeof opencodeSqliteState.lastStatus === "string" && opencodeSqliteState.lastStatus.trim()
92
+ ? opencodeSqliteState.lastStatus.trim()
93
+ : "never_checked";
113
94
 
114
95
  process.stdout.write(
115
96
  [
@@ -126,13 +107,21 @@ async function cmdStatus(argv = []) {
126
107
  `- Backoff until: ${backoffUntil || "never"}`,
127
108
  lastUploadError ? `- Last upload error: ${lastUploadError}` : null,
128
109
  autoRetryLine,
129
- `- Codex notify: ${notifyConfigured ? JSON.stringify(codexNotify) : "unset"}`,
130
- `- Every Code notify: ${everyCodeConfigured ? JSON.stringify(everyCodeNotify) : "unset"}`,
131
- `- Claude hooks: ${claudeHookConfigured ? "set" : "unset"}`,
132
- `- Gemini hooks: ${geminiHookConfigured ? "set" : "unset"}`,
133
- `- Opencode plugin: ${opencodePluginConfigured ? "set" : "unset"}`,
134
- `- OpenClaw session plugin: ${openclawSessionPluginState?.configured ? "set" : "unset"}`,
135
- `- OpenClaw hook (legacy): ${openclawHookState?.configured ? "set" : "unset"}`,
110
+ `- Codex notify: ${renderIntegrationStatus(descriptors.get("codex"), codexProbe)}`,
111
+ `- Every Code notify: ${renderIntegrationStatus(descriptors.get("every-code"), everyCodeProbe)}`,
112
+ `- Claude hooks: ${renderIntegrationStatus(descriptors.get("claude"), claudeProbe)}`,
113
+ `- Gemini hooks: ${renderIntegrationStatus(descriptors.get("gemini"), geminiProbe)}`,
114
+ `- Opencode plugin: ${renderIntegrationStatus(descriptors.get("opencode"), opencodeProbe)}`,
115
+ `- OpenCode SQLite DB: ${opencodeDbPresent ? "present" : "missing"}`,
116
+ `- OpenCode SQLite reader: ${opencodeSqliteReader}`,
117
+ `- OpenClaw session plugin: ${renderIntegrationStatus(
118
+ descriptors.get("openclaw-session"),
119
+ openclawSessionProbe,
120
+ )}`,
121
+ `- OpenClaw hook (legacy): ${renderIntegrationStatus(
122
+ descriptors.get("openclaw-legacy"),
123
+ openclawLegacyProbe,
124
+ )}`,
136
125
  ...subscriptionLines,
137
126
  "",
138
127
  ]
@@ -141,6 +130,16 @@ async function cmdStatus(argv = []) {
141
130
  );
142
131
  }
143
132
 
133
+ function renderIntegrationStatus(descriptor, probe) {
134
+ if (!probe) return "unknown";
135
+ if (descriptor && typeof descriptor.renderStatusValue === "function") {
136
+ return descriptor.renderStatusValue(probe);
137
+ }
138
+ if (probe.status === "ready") return "set";
139
+ if (probe.status === "not_installed") return "unset";
140
+ return probe.status || "unknown";
141
+ }
142
+
144
143
  function formatSubscriptionLine(entry = {}) {
145
144
  const tool = String(entry.tool || "");
146
145
  const provider = String(entry.provider || "");
@@ -196,6 +195,14 @@ async function safeStatSize(p) {
196
195
  }
197
196
  }
198
197
 
198
+ async function safeStat(p) {
199
+ try {
200
+ return await fs.stat(p);
201
+ } catch (_e) {
202
+ return null;
203
+ }
204
+ }
205
+
199
206
  async function safeReadText(p) {
200
207
  try {
201
208
  return await fs.readFile(p, "utf8");