vibeusage 0.2.20 → 0.2.22

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 (40) hide show
  1. package/README.md +306 -173
  2. package/README.old.md +324 -0
  3. package/README.zh-CN.md +304 -188
  4. package/package.json +32 -30
  5. package/src/cli.js +41 -37
  6. package/src/commands/activate-if-needed.js +41 -0
  7. package/src/commands/diagnostics.js +8 -9
  8. package/src/commands/doctor.js +31 -26
  9. package/src/commands/init.js +324 -208
  10. package/src/commands/status.js +86 -80
  11. package/src/commands/sync.js +182 -130
  12. package/src/commands/uninstall.js +69 -58
  13. package/src/lib/activation-check.js +290 -0
  14. package/src/lib/browser-auth.js +52 -54
  15. package/src/lib/claude-config.js +25 -25
  16. package/src/lib/cli-ui.js +35 -35
  17. package/src/lib/codex-config.js +40 -36
  18. package/src/lib/debug-flags.js +2 -2
  19. package/src/lib/diagnostics.js +73 -55
  20. package/src/lib/doctor.js +139 -132
  21. package/src/lib/fs.js +17 -17
  22. package/src/lib/gemini-config.js +44 -40
  23. package/src/lib/init-flow.js +16 -22
  24. package/src/lib/insforge-client.js +10 -10
  25. package/src/lib/insforge.js +9 -3
  26. package/src/lib/openclaw-hook.js +91 -67
  27. package/src/lib/openclaw-session-plugin.js +520 -0
  28. package/src/lib/opencode-config.js +31 -32
  29. package/src/lib/opencode-usage-audit.js +34 -31
  30. package/src/lib/progress.js +12 -13
  31. package/src/lib/project-usage-purge.js +23 -17
  32. package/src/lib/prompt.js +8 -4
  33. package/src/lib/rollout.js +342 -241
  34. package/src/lib/runtime-config.js +34 -22
  35. package/src/lib/subscriptions.js +94 -92
  36. package/src/lib/tracker-paths.js +6 -6
  37. package/src/lib/upload-throttle.js +35 -16
  38. package/src/lib/uploader.js +33 -29
  39. package/src/lib/vibeusage-api.js +72 -56
  40. package/src/lib/vibeusage-public-repo.js +41 -24
@@ -1,51 +1,52 @@
1
- const os = require('node:os');
2
- const path = require('node:path');
3
- const fs = require('node:fs/promises');
1
+ const os = require("node:os");
2
+ const path = require("node:path");
3
+ const fs = require("node:fs/promises");
4
4
 
5
- const { readJson } = require('../lib/fs');
6
- const { readCodexNotify, readEveryCodeNotify } = require('../lib/codex-config');
7
- const { isClaudeHookConfigured, buildClaudeHookCommand } = require('../lib/claude-config');
5
+ const { readJson } = require("../lib/fs");
6
+ const { readCodexNotify, readEveryCodeNotify } = require("../lib/codex-config");
7
+ const { isClaudeHookConfigured, buildClaudeHookCommand } = require("../lib/claude-config");
8
8
  const {
9
9
  resolveGeminiConfigDir,
10
10
  resolveGeminiSettingsPath,
11
11
  isGeminiHookConfigured,
12
- buildGeminiHookCommand
13
- } = require('../lib/gemini-config');
14
- const { resolveOpencodeConfigDir, isOpencodePluginInstalled } = require('../lib/opencode-config');
15
- const { collectLocalSubscriptions } = require('../lib/subscriptions');
16
- const { normalizeState: normalizeUploadState } = require('../lib/upload-throttle');
17
- const { collectTrackerDiagnostics } = require('../lib/diagnostics');
18
- const { probeOpenclawHookState } = require('../lib/openclaw-hook');
19
- const { resolveTrackerPaths } = require('../lib/tracker-paths');
12
+ buildGeminiHookCommand,
13
+ } = require("../lib/gemini-config");
14
+ const { resolveOpencodeConfigDir, isOpencodePluginInstalled } = require("../lib/opencode-config");
15
+ const { collectLocalSubscriptions } = require("../lib/subscriptions");
16
+ const { normalizeState: normalizeUploadState } = require("../lib/upload-throttle");
17
+ const { collectTrackerDiagnostics } = require("../lib/diagnostics");
18
+ const { probeOpenclawHookState } = require("../lib/openclaw-hook");
19
+ const { probeOpenclawSessionPluginState } = require("../lib/openclaw-session-plugin");
20
+ const { resolveTrackerPaths } = require("../lib/tracker-paths");
20
21
 
21
22
  async function cmdStatus(argv = []) {
22
23
  const opts = parseArgs(argv);
23
24
  if (opts.diagnostics) {
24
25
  const diagnostics = await collectTrackerDiagnostics();
25
- process.stdout.write(JSON.stringify(diagnostics, null, 2) + '\n');
26
+ process.stdout.write(JSON.stringify(diagnostics, null, 2) + "\n");
26
27
  return;
27
28
  }
28
29
 
29
30
  const home = os.homedir();
30
31
  const { trackerDir, binDir } = await resolveTrackerPaths({ home });
31
- const configPath = path.join(trackerDir, 'config.json');
32
- const queuePath = path.join(trackerDir, 'queue.jsonl');
33
- const queueStatePath = path.join(trackerDir, 'queue.state.json');
34
- const cursorsPath = path.join(trackerDir, 'cursors.json');
35
- const notifySignalPath = path.join(trackerDir, 'notify.signal');
36
- const openclawSignalPath = path.join(trackerDir, 'openclaw.signal');
37
- const throttlePath = path.join(trackerDir, 'sync.throttle');
38
- const uploadThrottlePath = path.join(trackerDir, 'upload.throttle.json');
39
- const autoRetryPath = path.join(trackerDir, 'auto.retry.json');
40
- const codexHome = process.env.CODEX_HOME || path.join(home, '.codex');
41
- const codexConfigPath = path.join(codexHome, 'config.toml');
42
- const codeHome = process.env.CODE_HOME || path.join(home, '.code');
43
- const codeConfigPath = path.join(codeHome, 'config.toml');
44
- const claudeSettingsPath = path.join(home, '.claude', 'settings.json');
32
+ const configPath = path.join(trackerDir, "config.json");
33
+ const queuePath = path.join(trackerDir, "queue.jsonl");
34
+ const queueStatePath = path.join(trackerDir, "queue.state.json");
35
+ const cursorsPath = path.join(trackerDir, "cursors.json");
36
+ const notifySignalPath = path.join(trackerDir, "notify.signal");
37
+ const openclawSignalPath = path.join(trackerDir, "openclaw.signal");
38
+ const throttlePath = path.join(trackerDir, "sync.throttle");
39
+ const uploadThrottlePath = path.join(trackerDir, "upload.throttle.json");
40
+ 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");
45
46
  const geminiConfigDir = resolveGeminiConfigDir({ home, env: process.env });
46
47
  const geminiSettingsPath = resolveGeminiSettingsPath({ configDir: geminiConfigDir });
47
48
  const opencodeConfigDir = resolveOpencodeConfigDir({ home, env: process.env });
48
- const notifyPath = path.join(binDir, 'notify.cjs');
49
+ const notifyPath = path.join(binDir, "notify.cjs");
49
50
  const claudeHookCommand = buildClaudeHookCommand(notifyPath);
50
51
  const geminiHookCommand = buildGeminiHookCommand(notifyPath);
51
52
 
@@ -68,29 +69,36 @@ async function cmdStatus(argv = []) {
68
69
  const everyCodeConfigured = Array.isArray(everyCodeNotify) && everyCodeNotify.length > 0;
69
70
  const claudeHookConfigured = await isClaudeHookConfigured({
70
71
  settingsPath: claudeSettingsPath,
71
- hookCommand: claudeHookCommand
72
+ hookCommand: claudeHookCommand,
72
73
  });
73
74
  const geminiHookConfigured = await isGeminiHookConfigured({
74
75
  settingsPath: geminiSettingsPath,
75
- hookCommand: geminiHookCommand
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,
76
85
  });
77
- const opencodePluginConfigured = await isOpencodePluginInstalled({ configDir: opencodeConfigDir });
78
86
  const openclawHookState = await probeOpenclawHookState({ home, trackerDir, env: process.env });
79
87
 
80
88
  const lastUpload = uploadThrottle.lastSuccessMs
81
89
  ? parseEpochMsToIso(uploadThrottle.lastSuccessMs)
82
- : typeof queueState.updatedAt === 'string'
90
+ : typeof queueState.updatedAt === "string"
83
91
  ? queueState.updatedAt
84
92
  : null;
85
93
  const nextUpload = parseEpochMsToIso(uploadThrottle.nextAllowedAtMs || null);
86
94
  const backoffUntil = parseEpochMsToIso(uploadThrottle.backoffUntilMs || null);
87
95
  const lastUploadError = uploadThrottle.lastError
88
- ? `${uploadThrottle.lastErrorAt || 'unknown'} ${uploadThrottle.lastError}`
96
+ ? `${uploadThrottle.lastErrorAt || "unknown"} ${uploadThrottle.lastError}`
89
97
  : null;
90
98
  const autoRetryAt = parseEpochMsToIso(autoRetry?.retryAtMs || null);
91
99
  const autoRetryLine = autoRetryAt
92
- ? `- Auto retry after: ${autoRetryAt} (${autoRetry?.reason || 'scheduled'}, pending ${Number(
93
- autoRetry?.pendingBytes || 0
100
+ ? `- Auto retry after: ${autoRetryAt} (${autoRetry?.reason || "scheduled"}, pending ${Number(
101
+ autoRetry?.pendingBytes || 0,
94
102
  )} bytes)`
95
103
  : null;
96
104
 
@@ -98,69 +106,68 @@ async function cmdStatus(argv = []) {
98
106
  home,
99
107
  env: process.env,
100
108
  probeKeychain: opts.probeKeychain,
101
- probeKeychainDetails: opts.probeKeychainDetails
109
+ probeKeychainDetails: opts.probeKeychainDetails,
102
110
  });
103
111
  const subscriptionLines =
104
- subscriptions.length > 0
105
- ? subscriptions.map(formatSubscriptionLine)
106
- : [];
112
+ subscriptions.length > 0 ? subscriptions.map(formatSubscriptionLine) : [];
107
113
 
108
114
  process.stdout.write(
109
115
  [
110
- 'Status:',
111
- `- Base URL: ${config?.baseUrl || 'unset'}`,
112
- `- Device token: ${config?.deviceToken ? 'set' : 'unset'}`,
116
+ "Status:",
117
+ `- Base URL: ${config?.baseUrl || "unset"}`,
118
+ `- Device token: ${config?.deviceToken ? "set" : "unset"}`,
113
119
  `- Queue: ${pendingBytes} bytes pending`,
114
- `- Last parse: ${cursors?.updatedAt || 'never'}`,
115
- `- Last notify: ${lastNotify || 'never'}`,
116
- `- Last OpenClaw-triggered sync: ${lastOpenclawSync || 'never'}`,
117
- `- Last notify-triggered sync: ${lastNotifySpawn || 'never'}`,
118
- `- Last upload: ${lastUpload || 'never'}`,
119
- `- Next upload after: ${nextUpload || 'never'}`,
120
- `- Backoff until: ${backoffUntil || 'never'}`,
120
+ `- Last parse: ${cursors?.updatedAt || "never"}`,
121
+ `- Last notify: ${lastNotify || "never"}`,
122
+ `- Last OpenClaw-triggered sync: ${lastOpenclawSync || "never"}`,
123
+ `- Last notify-triggered sync: ${lastNotifySpawn || "never"}`,
124
+ `- Last upload: ${lastUpload || "never"}`,
125
+ `- Next upload after: ${nextUpload || "never"}`,
126
+ `- Backoff until: ${backoffUntil || "never"}`,
121
127
  lastUploadError ? `- Last upload error: ${lastUploadError}` : null,
122
128
  autoRetryLine,
123
- `- Codex notify: ${notifyConfigured ? JSON.stringify(codexNotify) : 'unset'}`,
124
- `- Every Code notify: ${everyCodeConfigured ? JSON.stringify(everyCodeNotify) : 'unset'}`,
125
- `- Claude hooks: ${claudeHookConfigured ? 'set' : 'unset'}`,
126
- `- Gemini hooks: ${geminiHookConfigured ? 'set' : 'unset'}`,
127
- `- Opencode plugin: ${opencodePluginConfigured ? 'set' : 'unset'}`,
128
- `- OpenClaw hook: ${openclawHookState?.configured ? 'set' : 'unset'}`,
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"}`,
129
136
  ...subscriptionLines,
130
- ''
137
+ "",
131
138
  ]
132
139
  .filter(Boolean)
133
- .join('\n')
140
+ .join("\n"),
134
141
  );
135
142
  }
136
143
 
137
144
  function formatSubscriptionLine(entry = {}) {
138
- const tool = String(entry.tool || '');
139
- const provider = String(entry.provider || '');
140
- const product = String(entry.product || '');
141
- const planType = String(entry.planType || '');
142
- const rateLimitTier = String(entry.rateLimitTier || '');
145
+ const tool = String(entry.tool || "");
146
+ const provider = String(entry.provider || "");
147
+ const product = String(entry.product || "");
148
+ const planType = String(entry.planType || "");
149
+ const rateLimitTier = String(entry.rateLimitTier || "");
143
150
  const toolLabel =
144
- tool === 'codex'
145
- ? 'Codex'
146
- : tool === 'opencode'
147
- ? 'OpenCode'
148
- : tool === 'claude'
149
- ? 'Claude Code'
151
+ tool === "codex"
152
+ ? "Codex"
153
+ : tool === "opencode"
154
+ ? "OpenCode"
155
+ : tool === "claude"
156
+ ? "Claude Code"
150
157
  : tool;
151
158
 
152
159
  if (!planType) return null;
153
160
 
154
- if (tool === 'claude' && provider === 'anthropic' && product === 'subscription') {
155
- const suffix = rateLimitTier ? ` (rate limit tier: ${rateLimitTier})` : '';
161
+ if (tool === "claude" && provider === "anthropic" && product === "subscription") {
162
+ const suffix = rateLimitTier ? ` (rate limit tier: ${rateLimitTier})` : "";
156
163
  return `- ${toolLabel} subscription: ${planType}${suffix}`;
157
164
  }
158
165
 
159
- if (provider === 'openai' && product === 'chatgpt') {
166
+ if (provider === "openai" && product === "chatgpt") {
160
167
  return `- ${toolLabel} ChatGPT plan: ${planType}`;
161
168
  }
162
169
 
163
- const productLabel = product ? product.replace(/_/g, ' ') : 'subscription';
170
+ const productLabel = product ? product.replace(/_/g, " ") : "subscription";
164
171
  return `- ${toolLabel} ${productLabel}: ${planType}`;
165
172
  }
166
173
 
@@ -169,13 +176,12 @@ function parseArgs(argv) {
169
176
 
170
177
  for (let i = 0; i < argv.length; i++) {
171
178
  const a = argv[i];
172
- if (a === '--diagnostics' || a === '--json') out.diagnostics = true;
173
- else if (a === '--probe-keychain') out.probeKeychain = true;
174
- else if (a === '--probe-keychain-details') {
179
+ if (a === "--diagnostics" || a === "--json") out.diagnostics = true;
180
+ else if (a === "--probe-keychain") out.probeKeychain = true;
181
+ else if (a === "--probe-keychain-details") {
175
182
  out.probeKeychainDetails = true;
176
183
  out.probeKeychain = true;
177
- }
178
- else throw new Error(`Unknown option: ${a}`);
184
+ } else throw new Error(`Unknown option: ${a}`);
179
185
  }
180
186
 
181
187
  return out;
@@ -192,7 +198,7 @@ async function safeStatSize(p) {
192
198
 
193
199
  async function safeReadText(p) {
194
200
  try {
195
- return await fs.readFile(p, 'utf8');
201
+ return await fs.readFile(p, "utf8");
196
202
  } catch (_e) {
197
203
  return null;
198
204
  }