vibeusage 0.2.21 → 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 -32
  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 +285 -218
  10. package/src/commands/status.js +86 -83
  11. package/src/commands/sync.js +182 -130
  12. package/src/commands/uninstall.js +66 -62
  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 +70 -57
  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 +89 -66
  27. package/src/lib/openclaw-session-plugin.js +116 -92
  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,52 +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 { probeOpenclawSessionPluginState } = require('../lib/openclaw-session-plugin');
20
- 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");
21
21
 
22
22
  async function cmdStatus(argv = []) {
23
23
  const opts = parseArgs(argv);
24
24
  if (opts.diagnostics) {
25
25
  const diagnostics = await collectTrackerDiagnostics();
26
- process.stdout.write(JSON.stringify(diagnostics, null, 2) + '\n');
26
+ process.stdout.write(JSON.stringify(diagnostics, null, 2) + "\n");
27
27
  return;
28
28
  }
29
29
 
30
30
  const home = os.homedir();
31
31
  const { trackerDir, binDir } = await resolveTrackerPaths({ home });
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');
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");
46
46
  const geminiConfigDir = resolveGeminiConfigDir({ home, env: process.env });
47
47
  const geminiSettingsPath = resolveGeminiSettingsPath({ configDir: geminiConfigDir });
48
48
  const opencodeConfigDir = resolveOpencodeConfigDir({ home, env: process.env });
49
- const notifyPath = path.join(binDir, 'notify.cjs');
49
+ const notifyPath = path.join(binDir, "notify.cjs");
50
50
  const claudeHookCommand = buildClaudeHookCommand(notifyPath);
51
51
  const geminiHookCommand = buildGeminiHookCommand(notifyPath);
52
52
 
@@ -69,30 +69,36 @@ async function cmdStatus(argv = []) {
69
69
  const everyCodeConfigured = Array.isArray(everyCodeNotify) && everyCodeNotify.length > 0;
70
70
  const claudeHookConfigured = await isClaudeHookConfigured({
71
71
  settingsPath: claudeSettingsPath,
72
- hookCommand: claudeHookCommand
72
+ hookCommand: claudeHookCommand,
73
73
  });
74
74
  const geminiHookConfigured = await isGeminiHookConfigured({
75
75
  settingsPath: geminiSettingsPath,
76
- 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,
77
85
  });
78
- const opencodePluginConfigured = await isOpencodePluginInstalled({ configDir: opencodeConfigDir });
79
- const openclawSessionPluginState = await probeOpenclawSessionPluginState({ home, trackerDir, env: process.env });
80
86
  const openclawHookState = await probeOpenclawHookState({ home, trackerDir, env: process.env });
81
87
 
82
88
  const lastUpload = uploadThrottle.lastSuccessMs
83
89
  ? parseEpochMsToIso(uploadThrottle.lastSuccessMs)
84
- : typeof queueState.updatedAt === 'string'
90
+ : typeof queueState.updatedAt === "string"
85
91
  ? queueState.updatedAt
86
92
  : null;
87
93
  const nextUpload = parseEpochMsToIso(uploadThrottle.nextAllowedAtMs || null);
88
94
  const backoffUntil = parseEpochMsToIso(uploadThrottle.backoffUntilMs || null);
89
95
  const lastUploadError = uploadThrottle.lastError
90
- ? `${uploadThrottle.lastErrorAt || 'unknown'} ${uploadThrottle.lastError}`
96
+ ? `${uploadThrottle.lastErrorAt || "unknown"} ${uploadThrottle.lastError}`
91
97
  : null;
92
98
  const autoRetryAt = parseEpochMsToIso(autoRetry?.retryAtMs || null);
93
99
  const autoRetryLine = autoRetryAt
94
- ? `- Auto retry after: ${autoRetryAt} (${autoRetry?.reason || 'scheduled'}, pending ${Number(
95
- autoRetry?.pendingBytes || 0
100
+ ? `- Auto retry after: ${autoRetryAt} (${autoRetry?.reason || "scheduled"}, pending ${Number(
101
+ autoRetry?.pendingBytes || 0,
96
102
  )} bytes)`
97
103
  : null;
98
104
 
@@ -100,70 +106,68 @@ async function cmdStatus(argv = []) {
100
106
  home,
101
107
  env: process.env,
102
108
  probeKeychain: opts.probeKeychain,
103
- probeKeychainDetails: opts.probeKeychainDetails
109
+ probeKeychainDetails: opts.probeKeychainDetails,
104
110
  });
105
111
  const subscriptionLines =
106
- subscriptions.length > 0
107
- ? subscriptions.map(formatSubscriptionLine)
108
- : [];
112
+ subscriptions.length > 0 ? subscriptions.map(formatSubscriptionLine) : [];
109
113
 
110
114
  process.stdout.write(
111
115
  [
112
- 'Status:',
113
- `- Base URL: ${config?.baseUrl || 'unset'}`,
114
- `- Device token: ${config?.deviceToken ? 'set' : 'unset'}`,
116
+ "Status:",
117
+ `- Base URL: ${config?.baseUrl || "unset"}`,
118
+ `- Device token: ${config?.deviceToken ? "set" : "unset"}`,
115
119
  `- Queue: ${pendingBytes} bytes pending`,
116
- `- Last parse: ${cursors?.updatedAt || 'never'}`,
117
- `- Last notify: ${lastNotify || 'never'}`,
118
- `- Last OpenClaw-triggered sync: ${lastOpenclawSync || 'never'}`,
119
- `- Last notify-triggered sync: ${lastNotifySpawn || 'never'}`,
120
- `- Last upload: ${lastUpload || 'never'}`,
121
- `- Next upload after: ${nextUpload || 'never'}`,
122
- `- 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"}`,
123
127
  lastUploadError ? `- Last upload error: ${lastUploadError}` : null,
124
128
  autoRetryLine,
125
- `- Codex notify: ${notifyConfigured ? JSON.stringify(codexNotify) : 'unset'}`,
126
- `- Every Code notify: ${everyCodeConfigured ? JSON.stringify(everyCodeNotify) : 'unset'}`,
127
- `- Claude hooks: ${claudeHookConfigured ? 'set' : 'unset'}`,
128
- `- Gemini hooks: ${geminiHookConfigured ? 'set' : 'unset'}`,
129
- `- Opencode plugin: ${opencodePluginConfigured ? 'set' : 'unset'}`,
130
- `- OpenClaw session plugin: ${openclawSessionPluginState?.configured ? 'set' : 'unset'}`,
131
- `- OpenClaw hook (legacy): ${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"}`,
132
136
  ...subscriptionLines,
133
- ''
137
+ "",
134
138
  ]
135
139
  .filter(Boolean)
136
- .join('\n')
140
+ .join("\n"),
137
141
  );
138
142
  }
139
143
 
140
144
  function formatSubscriptionLine(entry = {}) {
141
- const tool = String(entry.tool || '');
142
- const provider = String(entry.provider || '');
143
- const product = String(entry.product || '');
144
- const planType = String(entry.planType || '');
145
- 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 || "");
146
150
  const toolLabel =
147
- tool === 'codex'
148
- ? 'Codex'
149
- : tool === 'opencode'
150
- ? 'OpenCode'
151
- : tool === 'claude'
152
- ? 'Claude Code'
151
+ tool === "codex"
152
+ ? "Codex"
153
+ : tool === "opencode"
154
+ ? "OpenCode"
155
+ : tool === "claude"
156
+ ? "Claude Code"
153
157
  : tool;
154
158
 
155
159
  if (!planType) return null;
156
160
 
157
- if (tool === 'claude' && provider === 'anthropic' && product === 'subscription') {
158
- const suffix = rateLimitTier ? ` (rate limit tier: ${rateLimitTier})` : '';
161
+ if (tool === "claude" && provider === "anthropic" && product === "subscription") {
162
+ const suffix = rateLimitTier ? ` (rate limit tier: ${rateLimitTier})` : "";
159
163
  return `- ${toolLabel} subscription: ${planType}${suffix}`;
160
164
  }
161
165
 
162
- if (provider === 'openai' && product === 'chatgpt') {
166
+ if (provider === "openai" && product === "chatgpt") {
163
167
  return `- ${toolLabel} ChatGPT plan: ${planType}`;
164
168
  }
165
169
 
166
- const productLabel = product ? product.replace(/_/g, ' ') : 'subscription';
170
+ const productLabel = product ? product.replace(/_/g, " ") : "subscription";
167
171
  return `- ${toolLabel} ${productLabel}: ${planType}`;
168
172
  }
169
173
 
@@ -172,13 +176,12 @@ function parseArgs(argv) {
172
176
 
173
177
  for (let i = 0; i < argv.length; i++) {
174
178
  const a = argv[i];
175
- if (a === '--diagnostics' || a === '--json') out.diagnostics = true;
176
- else if (a === '--probe-keychain') out.probeKeychain = true;
177
- 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") {
178
182
  out.probeKeychainDetails = true;
179
183
  out.probeKeychain = true;
180
- }
181
- else throw new Error(`Unknown option: ${a}`);
184
+ } else throw new Error(`Unknown option: ${a}`);
182
185
  }
183
186
 
184
187
  return out;
@@ -195,7 +198,7 @@ async function safeStatSize(p) {
195
198
 
196
199
  async function safeReadText(p) {
197
200
  try {
198
- return await fs.readFile(p, 'utf8');
201
+ return await fs.readFile(p, "utf8");
199
202
  } catch (_e) {
200
203
  return null;
201
204
  }