vibeusage 0.2.21 → 0.2.23

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 +37 -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 +178 -130
  12. package/src/commands/uninstall.js +66 -62
  13. package/src/lib/activation-check.js +341 -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,22 +1,22 @@
1
- const os = require('node:os');
2
- const path = require('node:path');
3
- const fs = require('node:fs/promises');
4
- const fssync = require('node:fs');
5
- const cp = require('node:child_process');
1
+ const os = require("node:os");
2
+ const path = require("node:path");
3
+ const fs = require("node:fs/promises");
4
+ const fssync = require("node:fs");
5
+ const cp = require("node:child_process");
6
6
 
7
- const OPENCLAW_HOOK_NAME = 'vibeusage-openclaw-sync';
8
- const OPENCLAW_HOOK_DIRNAME = 'openclaw-hook';
7
+ const OPENCLAW_HOOK_NAME = "vibeusage-openclaw-sync";
8
+ const OPENCLAW_HOOK_DIRNAME = "openclaw-hook";
9
9
 
10
10
  function resolveOpenclawHookPaths({ home = os.homedir(), trackerDir, env = process.env } = {}) {
11
- if (!trackerDir) throw new Error('trackerDir is required');
11
+ if (!trackerDir) throw new Error("trackerDir is required");
12
12
 
13
13
  const openclawConfigPath =
14
- normalizeString(env.OPENCLAW_CONFIG_PATH) || path.join(home, '.openclaw', 'openclaw.json');
14
+ normalizeString(env.OPENCLAW_CONFIG_PATH) || path.join(home, ".openclaw", "openclaw.json");
15
15
 
16
16
  const openclawHome =
17
17
  normalizeString(env.VIBEUSAGE_OPENCLAW_HOME) ||
18
18
  normalizeString(env.OPENCLAW_STATE_DIR) ||
19
- path.join(home, '.openclaw');
19
+ path.join(home, ".openclaw");
20
20
 
21
21
  const hookDir = path.join(trackerDir, OPENCLAW_HOOK_DIRNAME);
22
22
  const hookEntryDir = path.join(hookDir, OPENCLAW_HOOK_NAME);
@@ -26,21 +26,26 @@ function resolveOpenclawHookPaths({ home = os.homedir(), trackerDir, env = proce
26
26
  hookDir,
27
27
  hookEntryDir,
28
28
  openclawConfigPath,
29
- openclawHome
29
+ openclawHome,
30
30
  };
31
31
  }
32
32
 
33
- async function installOpenclawHook({ home = os.homedir(), trackerDir, packageName = 'vibeusage', env = process.env } = {}) {
33
+ async function installOpenclawHook({
34
+ home = os.homedir(),
35
+ trackerDir,
36
+ packageName = "vibeusage",
37
+ env = process.env,
38
+ } = {}) {
34
39
  const paths = resolveOpenclawHookPaths({ home, trackerDir, env });
35
40
 
36
41
  await ensureOpenclawHookFiles({
37
42
  hookDir: paths.hookDir,
38
43
  trackerDir,
39
44
  packageName,
40
- openclawHome: paths.openclawHome
45
+ openclawHome: paths.openclawHome,
41
46
  });
42
47
 
43
- const installResult = runOpenclawCli(['hooks', 'install', '--link', paths.hookDir], env);
48
+ const installResult = runOpenclawCli(["hooks", "install", "--link", paths.hookDir], env);
44
49
  if (installResult.skippedReason) {
45
50
  return { configured: false, ...paths, ...installResult };
46
51
  }
@@ -48,28 +53,37 @@ async function installOpenclawHook({ home = os.homedir(), trackerDir, packageNam
48
53
  const state = await probeOpenclawHookState({ home, trackerDir, env });
49
54
  return {
50
55
  configured: state.configured,
51
- changed: /Linked hook path:/i.test(installResult.stdout || ''),
56
+ changed: /Linked hook path:/i.test(installResult.stdout || ""),
52
57
  ...paths,
53
58
  stdout: installResult.stdout,
54
59
  stderr: installResult.stderr,
55
- code: installResult.code
60
+ code: installResult.code,
56
61
  };
57
62
  }
58
63
 
59
- async function ensureOpenclawHookFiles({ hookDir, trackerDir, packageName = 'vibeusage', openclawHome } = {}) {
60
- if (!hookDir || !trackerDir) throw new Error('hookDir and trackerDir are required');
64
+ async function ensureOpenclawHookFiles({
65
+ hookDir,
66
+ trackerDir,
67
+ packageName = "vibeusage",
68
+ openclawHome,
69
+ } = {}) {
70
+ if (!hookDir || !trackerDir) throw new Error("hookDir and trackerDir are required");
61
71
 
62
72
  const hookEntryDir = path.join(hookDir, OPENCLAW_HOOK_NAME);
63
73
  await fs.mkdir(hookEntryDir, { recursive: true });
64
74
 
65
- const hookMdPath = path.join(hookEntryDir, 'HOOK.md');
66
- const handlerPath = path.join(hookEntryDir, 'handler.js');
75
+ const hookMdPath = path.join(hookEntryDir, "HOOK.md");
76
+ const handlerPath = path.join(hookEntryDir, "handler.js");
67
77
 
68
- await fs.writeFile(hookMdPath, buildHookMarkdown(), 'utf8');
78
+ await fs.writeFile(hookMdPath, buildHookMarkdown(), "utf8");
69
79
  await fs.writeFile(
70
80
  handlerPath,
71
- buildHookHandler({ trackerDir, packageName, openclawHome: openclawHome || path.join(os.homedir(), '.openclaw') }),
72
- 'utf8'
81
+ buildHookHandler({
82
+ trackerDir,
83
+ packageName,
84
+ openclawHome: openclawHome || path.join(os.homedir(), ".openclaw"),
85
+ }),
86
+ "utf8",
73
87
  );
74
88
  }
75
89
 
@@ -78,21 +92,22 @@ async function probeOpenclawHookState({ home = os.homedir(), trackerDir, env = p
78
92
  const { openclawConfigPath, hookDir, hookEntryDir, hookName } = paths;
79
93
 
80
94
  const hookFilesReady =
81
- fssync.existsSync(path.join(hookEntryDir, 'HOOK.md')) && fssync.existsSync(path.join(hookEntryDir, 'handler.js'));
95
+ fssync.existsSync(path.join(hookEntryDir, "HOOK.md")) &&
96
+ fssync.existsSync(path.join(hookEntryDir, "handler.js"));
82
97
 
83
98
  let cfg = null;
84
99
  try {
85
- const raw = await fs.readFile(openclawConfigPath, 'utf8');
100
+ const raw = await fs.readFile(openclawConfigPath, "utf8");
86
101
  cfg = JSON.parse(raw);
87
102
  } catch (err) {
88
- if (err?.code === 'ENOENT' || err?.code === 'ENOTDIR') {
103
+ if (err?.code === "ENOENT" || err?.code === "ENOTDIR") {
89
104
  return {
90
105
  configured: false,
91
106
  enabled: false,
92
107
  linked: false,
93
108
  hookFilesReady,
94
- skippedReason: 'openclaw-config-missing',
95
- ...paths
109
+ skippedReason: "openclaw-config-missing",
110
+ ...paths,
96
111
  };
97
112
  }
98
113
  return {
@@ -100,42 +115,48 @@ async function probeOpenclawHookState({ home = os.homedir(), trackerDir, env = p
100
115
  enabled: false,
101
116
  linked: false,
102
117
  hookFilesReady,
103
- skippedReason: 'openclaw-config-unreadable',
118
+ skippedReason: "openclaw-config-unreadable",
104
119
  error: err?.message || String(err),
105
- ...paths
120
+ ...paths,
106
121
  };
107
122
  }
108
123
 
109
124
  const enabled = Boolean(cfg?.hooks?.internal?.entries?.[hookName]?.enabled);
110
- const extraDirs = Array.isArray(cfg?.hooks?.internal?.load?.extraDirs) ? cfg.hooks.internal.load.extraDirs : [];
125
+ const extraDirs = Array.isArray(cfg?.hooks?.internal?.load?.extraDirs)
126
+ ? cfg.hooks.internal.load.extraDirs
127
+ : [];
111
128
  const normalizedHookDir = path.resolve(hookDir);
112
- const linked = extraDirs.some((entry) => path.resolve(String(entry || '')) === normalizedHookDir);
129
+ const linked = extraDirs.some((entry) => path.resolve(String(entry || "")) === normalizedHookDir);
113
130
 
114
131
  return {
115
132
  configured: enabled && linked,
116
133
  enabled,
117
134
  linked,
118
135
  hookFilesReady,
119
- ...paths
136
+ ...paths,
120
137
  };
121
138
  }
122
139
 
123
- async function removeOpenclawHookConfig({ home = os.homedir(), trackerDir, env = process.env } = {}) {
140
+ async function removeOpenclawHookConfig({
141
+ home = os.homedir(),
142
+ trackerDir,
143
+ env = process.env,
144
+ } = {}) {
124
145
  const paths = resolveOpenclawHookPaths({ home, trackerDir, env });
125
146
  const { openclawConfigPath, hookDir, hookName } = paths;
126
147
 
127
148
  let cfg;
128
149
  try {
129
- cfg = JSON.parse(await fs.readFile(openclawConfigPath, 'utf8'));
150
+ cfg = JSON.parse(await fs.readFile(openclawConfigPath, "utf8"));
130
151
  } catch (err) {
131
- if (err?.code === 'ENOENT' || err?.code === 'ENOTDIR') {
132
- return { removed: false, skippedReason: 'openclaw-config-missing', ...paths };
152
+ if (err?.code === "ENOENT" || err?.code === "ENOTDIR") {
153
+ return { removed: false, skippedReason: "openclaw-config-missing", ...paths };
133
154
  }
134
155
  return {
135
156
  removed: false,
136
- skippedReason: 'openclaw-config-unreadable',
157
+ skippedReason: "openclaw-config-unreadable",
137
158
  error: err?.message || String(err),
138
- ...paths
159
+ ...paths,
139
160
  };
140
161
  }
141
162
 
@@ -152,7 +173,7 @@ async function removeOpenclawHookConfig({ home = os.homedir(), trackerDir, env =
152
173
  if (internal?.load && Array.isArray(internal.load.extraDirs)) {
153
174
  const before = internal.load.extraDirs;
154
175
  const target = path.resolve(hookDir);
155
- const after = before.filter((entry) => path.resolve(String(entry || '')) !== target);
176
+ const after = before.filter((entry) => path.resolve(String(entry || "")) !== target);
156
177
  if (after.length !== before.length) {
157
178
  internal.load.extraDirs = after;
158
179
  changed = true;
@@ -161,7 +182,7 @@ async function removeOpenclawHookConfig({ home = os.homedir(), trackerDir, env =
161
182
  }
162
183
  }
163
184
 
164
- if (internal?.installs && typeof internal.installs === 'object') {
185
+ if (internal?.installs && typeof internal.installs === "object") {
165
186
  const installs = internal.installs;
166
187
  if (Object.prototype.hasOwnProperty.call(installs, hookName)) {
167
188
  delete installs[hookName];
@@ -194,7 +215,7 @@ async function removeOpenclawHookConfig({ home = os.homedir(), trackerDir, env =
194
215
  }
195
216
 
196
217
  if (changed) {
197
- await fs.writeFile(openclawConfigPath, `${JSON.stringify(cfg, null, 2)}\n`, 'utf8');
218
+ await fs.writeFile(openclawConfigPath, `${JSON.stringify(cfg, null, 2)}\n`, "utf8");
198
219
  }
199
220
 
200
221
  await fs.rm(hookDir, { recursive: true, force: true }).catch(() => {});
@@ -205,45 +226,45 @@ async function removeOpenclawHookConfig({ home = os.homedir(), trackerDir, env =
205
226
  function runOpenclawCli(args, env = process.env) {
206
227
  let res;
207
228
  try {
208
- res = cp.spawnSync('openclaw', args, {
229
+ res = cp.spawnSync("openclaw", args, {
209
230
  env,
210
- encoding: 'utf8',
211
- timeout: 30_000
231
+ encoding: "utf8",
232
+ timeout: 30_000,
212
233
  });
213
234
  } catch (err) {
214
235
  return {
215
236
  code: 1,
216
- skippedReason: err?.code === 'ENOENT' ? 'openclaw-cli-missing' : 'openclaw-cli-error',
237
+ skippedReason: err?.code === "ENOENT" ? "openclaw-cli-missing" : "openclaw-cli-error",
217
238
  error: err?.message || String(err),
218
- stdout: '',
219
- stderr: ''
239
+ stdout: "",
240
+ stderr: "",
220
241
  };
221
242
  }
222
243
 
223
- if (res.error?.code === 'ENOENT') {
244
+ if (res.error?.code === "ENOENT") {
224
245
  return {
225
246
  code: 1,
226
- skippedReason: 'openclaw-cli-missing',
247
+ skippedReason: "openclaw-cli-missing",
227
248
  error: res.error.message,
228
- stdout: res.stdout || '',
229
- stderr: res.stderr || ''
249
+ stdout: res.stdout || "",
250
+ stderr: res.stderr || "",
230
251
  };
231
252
  }
232
253
 
233
254
  if ((res.status || 0) !== 0) {
234
255
  return {
235
256
  code: Number(res.status || 1),
236
- skippedReason: 'openclaw-hooks-install-failed',
237
- error: (res.stderr || res.stdout || '').trim() || 'openclaw hooks install failed',
238
- stdout: res.stdout || '',
239
- stderr: res.stderr || ''
257
+ skippedReason: "openclaw-hooks-install-failed",
258
+ error: (res.stderr || res.stdout || "").trim() || "openclaw hooks install failed",
259
+ stdout: res.stdout || "",
260
+ stderr: res.stderr || "",
240
261
  };
241
262
  }
242
263
 
243
264
  return {
244
265
  code: 0,
245
- stdout: res.stdout || '',
246
- stderr: res.stderr || ''
266
+ stdout: res.stdout || "",
267
+ stderr: res.stderr || "",
247
268
  };
248
269
  }
249
270
 
@@ -261,12 +282,13 @@ Triggers non-blocking 'vibeusage sync --auto --from-openclaw' runs when OpenClaw
261
282
  `;
262
283
  }
263
284
 
264
- function buildHookHandler({ trackerDir, packageName = 'vibeusage', openclawHome }) {
265
- const trackerBinPath = path.join(trackerDir, 'app', 'bin', 'tracker.js');
266
- const fallbackPkg = packageName || 'vibeusage';
267
- const safeOpenclawHome = openclawHome || path.join(os.homedir(), '.openclaw');
285
+ function buildHookHandler({ trackerDir, packageName = "vibeusage", openclawHome }) {
286
+ const trackerBinPath = path.join(trackerDir, "app", "bin", "tracker.js");
287
+ const fallbackPkg = packageName || "vibeusage";
288
+ const safeOpenclawHome = openclawHome || path.join(os.homedir(), ".openclaw");
268
289
 
269
- return `'use strict';\n` +
290
+ return (
291
+ `'use strict';\n` +
270
292
  `const fs = require('node:fs');\n` +
271
293
  `const path = require('node:path');\n` +
272
294
  `const cp = require('node:child_process');\n` +
@@ -377,11 +399,12 @@ function buildHookHandler({ trackerDir, packageName = 'vibeusage', openclawHome
377
399
  ` normalize(ctx.sessionEntry && ctx.sessionEntry.sessionId) ||\n` +
378
400
  ` normalize(ctx.sessionId)\n` +
379
401
  ` );\n` +
380
- `}\n`;
402
+ `}\n`
403
+ );
381
404
  }
382
405
 
383
406
  function normalizeString(value) {
384
- if (typeof value !== 'string') return null;
407
+ if (typeof value !== "string") return null;
385
408
  const trimmed = value.trim();
386
409
  return trimmed.length > 0 ? trimmed : null;
387
410
  }
@@ -393,5 +416,5 @@ module.exports = {
393
416
  ensureOpenclawHookFiles,
394
417
  installOpenclawHook,
395
418
  probeOpenclawHookState,
396
- removeOpenclawHookConfig
419
+ removeOpenclawHookConfig,
397
420
  };