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
package/package.json CHANGED
@@ -1,55 +1,57 @@
1
1
  {
2
2
  "name": "vibeusage",
3
- "version": "0.2.20",
3
+ "version": "0.2.22",
4
4
  "description": "Codex CLI token usage tracker (macOS-first, notify-driven).",
5
5
  "license": "MIT",
6
+ "bin": {
7
+ "tracker": "bin/tracker.js",
8
+ "vibeusage": "bin/tracker.js",
9
+ "vibeusage-tracker": "bin/tracker.js"
10
+ },
11
+ "files": [
12
+ "bin/",
13
+ "src/",
14
+ "LICENSE",
15
+ "README.md"
16
+ ],
17
+ "type": "commonjs",
6
18
  "publishConfig": {
7
19
  "access": "public"
8
20
  },
9
- "type": "commonjs",
10
21
  "scripts": {
11
- "test": "node --test test/*.test.js",
12
- "smoke": "node scripts/smoke/insforge-smoke.cjs",
22
+ "architecture:canvas": "node scripts/ops/architecture-canvas.cjs",
23
+ "architecture:canvas:focus": "node scripts/ops/architecture-canvas.cjs --focus",
24
+ "architecture:canvas:list-modules": "node scripts/ops/architecture-canvas.cjs --list-modules",
13
25
  "build:insforge": "node scripts/build-insforge-functions.cjs",
14
26
  "build:insforge:check": "node scripts/build-insforge-functions.cjs --check",
15
- "dashboard:dev": "npm --prefix dashboard run dev",
27
+ "ci:local": "npm test && npm run validate:copy && npm run validate:ui-hardcode && npm run validate:guardrails && node --test test/architecture-guardrails.test.js && npm run build:insforge:check && npm --prefix dashboard run build",
28
+ "copy:pull": "node scripts/copy-sync.cjs pull",
29
+ "copy:push": "node scripts/copy-sync.cjs push",
16
30
  "dashboard:build": "npm --prefix dashboard run build",
31
+ "dashboard:dev": "npm --prefix dashboard run dev",
17
32
  "dashboard:preview": "npm --prefix dashboard run preview",
18
33
  "dev:shim": "node scripts/dev-bin-shim.cjs",
34
+ "graph:auto-index": "node scripts/graph/auto-index.cjs",
35
+ "graph:scip": "node scripts/graph/generate-scip.cjs",
36
+ "smoke": "node scripts/smoke/insforge-smoke.cjs",
37
+ "test": "node --test test/*.test.js",
19
38
  "validate:copy": "node scripts/validate-copy-registry.cjs",
20
- "validate:ui-hardcode": "node scripts/ops/validate-ui-hardcode.cjs",
21
- "copy:pull": "node scripts/copy-sync.cjs pull",
22
- "copy:push": "node scripts/copy-sync.cjs push",
23
- "architecture:canvas": "node scripts/ops/architecture-canvas.cjs",
24
- "architecture:canvas:focus": "node scripts/ops/architecture-canvas.cjs --focus",
25
- "architecture:canvas:list-modules": "node scripts/ops/architecture-canvas.cjs --list-modules",
26
39
  "validate:guardrails": "node scripts/validate-architecture-guardrails.cjs",
27
40
  "validate:insforge2-db": "node scripts/ops/insforge2-db-validate.cjs",
28
- "graph:scip": "node scripts/graph/generate-scip.cjs",
29
- "graph:auto-index": "node scripts/graph/auto-index.cjs"
41
+ "validate:retros": "node scripts/validate-retros.cjs",
42
+ "validate:ui-hardcode": "node scripts/ops/validate-ui-hardcode.cjs"
30
43
  },
31
- "bin": {
32
- "tracker": "bin/tracker.js",
33
- "vibeusage": "bin/tracker.js",
34
- "vibeusage-tracker": "bin/tracker.js"
35
- },
36
- "files": [
37
- "bin/",
38
- "src/",
39
- "LICENSE",
40
- "README.md"
41
- ],
42
- "engines": {
43
- "node": "20.x"
44
+ "dependencies": {
45
+ "@insforge/sdk": "^1.0.4"
44
46
  },
45
47
  "devDependencies": {
46
48
  "@sourcegraph/scip-typescript": "^0.3.6",
47
49
  "esbuild": "0.27.2"
48
50
  },
49
- "dependencies": {
50
- "@insforge/sdk": "^1.0.4"
51
- },
52
51
  "bundledDependencies": [
53
52
  "@insforge/sdk"
54
- ]
53
+ ],
54
+ "engines": {
55
+ "node": "20.x"
56
+ }
55
57
  }
package/src/cli.js CHANGED
@@ -1,37 +1,41 @@
1
- const { cmdInit } = require('./commands/init');
2
- const { cmdSync } = require('./commands/sync');
3
- const { cmdStatus } = require('./commands/status');
4
- const { cmdDiagnostics } = require('./commands/diagnostics');
5
- const { cmdDoctor } = require('./commands/doctor');
6
- const { cmdUninstall } = require('./commands/uninstall');
1
+ const { cmdInit } = require("./commands/init");
2
+ const { cmdSync } = require("./commands/sync");
3
+ const { cmdStatus } = require("./commands/status");
4
+ const { cmdDiagnostics } = require("./commands/diagnostics");
5
+ const { cmdDoctor } = require("./commands/doctor");
6
+ const { cmdUninstall } = require("./commands/uninstall");
7
+ const { cmdActivateIfNeeded } = require("./commands/activate-if-needed");
7
8
 
8
9
  async function run(argv) {
9
10
  const [command, ...rest] = argv;
10
11
 
11
- if (!command || command === '-h' || command === '--help') {
12
+ if (!command || command === "-h" || command === "--help") {
12
13
  printHelp();
13
14
  return;
14
15
  }
15
16
 
16
17
  switch (command) {
17
- case 'init':
18
+ case "init":
18
19
  await cmdInit(rest);
19
20
  return;
20
- case 'sync':
21
+ case "sync":
21
22
  await cmdSync(rest);
22
23
  return;
23
- case 'status':
24
+ case "status":
24
25
  await cmdStatus(rest);
25
26
  return;
26
- case 'diagnostics':
27
+ case "diagnostics":
27
28
  await cmdDiagnostics(rest);
28
29
  return;
29
- case 'doctor':
30
+ case "doctor":
30
31
  await cmdDoctor(rest);
31
32
  return;
32
- case 'uninstall':
33
+ case "uninstall":
33
34
  await cmdUninstall(rest);
34
35
  return;
36
+ case "activate-if-needed":
37
+ await cmdActivateIfNeeded(rest);
38
+ return;
35
39
  default:
36
40
  throw new Error(`Unknown command: ${command}`);
37
41
  }
@@ -41,30 +45,30 @@ function printHelp() {
41
45
  // Keep this short; npx users want quick guidance.
42
46
  process.stdout.write(
43
47
  [
44
- 'vibeusage',
45
- '',
46
- 'Usage:',
47
- ' npx vibeusage [--debug] init [--yes] [--dry-run] [--no-open] [--link-code <code>]',
48
- ' npx vibeusage [--debug] sync [--auto] [--drain] [--from-openclaw]',
49
- ' npx vibeusage [--debug] status [--probe-keychain] [--probe-keychain-details]',
50
- ' npx vibeusage [--debug] diagnostics [--out diagnostics.json]',
51
- ' npx vibeusage [--debug] doctor [--json] [--out doctor.json] [--base-url <url>]',
52
- ' npx vibeusage [--debug] uninstall [--purge]',
53
- '',
54
- 'Notes:',
55
- ' - init: consent first, local setup next, browser sign-in last.',
56
- ' - --yes skips the consent menu (non-interactive safe).',
57
- ' - --dry-run previews changes without writing files.',
58
- ' - optional: --link-code <code> skips browser login when provided by Dashboard.',
59
- ' - Every Code notify installs when ~/.code/config.toml exists.',
60
- ' - OpenClaw hook auto-links when OpenClaw is installed (requires gateway restart).',
61
- ' - auto sync waits for a device token.',
62
- ' - optional: VIBEUSAGE_DASHBOARD_URL or --dashboard-url for hosted landing.',
63
- ' - sync parses ~/.codex/sessions/**/rollout-*.jsonl and ~/.code/sessions/**/rollout-*.jsonl, then uploads token deltas.',
64
- ' - --from-openclaw marks sync runs triggered by OpenClaw hooks.',
65
- ' - --debug shows original backend errors.',
66
- ''
67
- ].join('\n')
48
+ "vibeusage",
49
+ "",
50
+ "Usage:",
51
+ " npx vibeusage [--debug] init [--yes] [--dry-run] [--no-open] [--link-code <code>]",
52
+ " npx vibeusage [--debug] sync [--auto] [--drain] [--from-openclaw]",
53
+ " npx vibeusage [--debug] status [--probe-keychain] [--probe-keychain-details]",
54
+ " npx vibeusage [--debug] diagnostics [--out diagnostics.json]",
55
+ " npx vibeusage [--debug] doctor [--json] [--out doctor.json] [--base-url <url>]",
56
+ " npx vibeusage [--debug] uninstall [--purge]",
57
+ "",
58
+ "Notes:",
59
+ " - init: consent first, local setup next, browser sign-in last.",
60
+ " - --yes skips the consent menu (non-interactive safe).",
61
+ " - --dry-run previews changes without writing files.",
62
+ " - optional: --link-code <code> skips browser login when provided by Dashboard.",
63
+ " - Every Code notify installs when ~/.code/config.toml exists.",
64
+ " - OpenClaw hook auto-links when OpenClaw is installed (requires gateway restart).",
65
+ " - auto sync waits for a device token.",
66
+ " - optional: VIBEUSAGE_DASHBOARD_URL or --dashboard-url for hosted landing.",
67
+ " - sync parses ~/.codex/sessions/**/rollout-*.jsonl and ~/.code/sessions/**/rollout-*.jsonl, then uploads token deltas.",
68
+ " - --from-openclaw marks sync runs triggered by OpenClaw hooks.",
69
+ " - --debug shows original backend errors.",
70
+ "",
71
+ ].join("\n"),
68
72
  );
69
73
  }
70
74
 
@@ -0,0 +1,41 @@
1
+ const { checkAndActivate } = require("../lib/activation-check");
2
+
3
+ /**
4
+ * 检测并激活未配置的 AI CLI 集成
5
+ * 用于 hooks 或其他触发器调用
6
+ */
7
+ async function cmdActivateIfNeeded(argv) {
8
+ const opts = parseArgs(argv);
9
+
10
+ const results = await checkAndActivate({
11
+ silent: opts.silent,
12
+ autoConfigure: true,
13
+ });
14
+
15
+ if (!opts.silent) {
16
+ if (results.length === 0) {
17
+ console.log("所有 AI CLI 集成已配置完成");
18
+ } else {
19
+ for (const r of results) {
20
+ const icon = r.action === "configured" ? "✅" : "❌";
21
+ console.log(`${icon} ${r.displayName}: ${r.action}`);
22
+ }
23
+ }
24
+ }
25
+
26
+ // 如果有任何配置成功,返回 0,否则返回 1
27
+ const hasSuccess = results.some(r => r.action === "configured");
28
+ process.exitCode = hasSuccess ? 0 : 0; // 始终返回 0,不阻塞调用方
29
+ }
30
+
31
+ function parseArgs(argv) {
32
+ const out = {
33
+ silent: false,
34
+ };
35
+ for (const a of argv) {
36
+ if (a === "--silent") out.silent = true;
37
+ }
38
+ return out;
39
+ }
40
+
41
+ module.exports = { cmdActivateIfNeeded };
@@ -1,12 +1,12 @@
1
- const path = require('node:path');
1
+ const path = require("node:path");
2
2
 
3
- const { writeFileAtomic, chmod600IfPossible } = require('../lib/fs');
4
- const { collectTrackerDiagnostics } = require('../lib/diagnostics');
3
+ const { writeFileAtomic, chmod600IfPossible } = require("../lib/fs");
4
+ const { collectTrackerDiagnostics } = require("../lib/diagnostics");
5
5
 
6
6
  async function cmdDiagnostics(argv = []) {
7
7
  const opts = parseArgs(argv);
8
8
  const diagnostics = await collectTrackerDiagnostics();
9
- const json = JSON.stringify(diagnostics, null, opts.compact ? 0 : 2) + '\n';
9
+ const json = JSON.stringify(diagnostics, null, opts.compact ? 0 : 2) + "\n";
10
10
 
11
11
  if (opts.out) {
12
12
  const outPath = path.resolve(process.cwd(), opts.out);
@@ -21,14 +21,14 @@ async function cmdDiagnostics(argv = []) {
21
21
  function parseArgs(argv) {
22
22
  const out = {
23
23
  out: null,
24
- compact: false
24
+ compact: false,
25
25
  };
26
26
 
27
27
  for (let i = 0; i < argv.length; i++) {
28
28
  const a = argv[i];
29
- if (a === '--out') out.out = argv[++i] || null;
30
- else if (a === '--compact') out.compact = true;
31
- else if (a === '--pretty') out.compact = false;
29
+ if (a === "--out") out.out = argv[++i] || null;
30
+ else if (a === "--compact") out.compact = true;
31
+ else if (a === "--pretty") out.compact = false;
32
32
  else throw new Error(`Unknown option: ${a}`);
33
33
  }
34
34
 
@@ -36,4 +36,3 @@ function parseArgs(argv) {
36
36
  }
37
37
 
38
38
  module.exports = { cmdDiagnostics };
39
-
@@ -1,21 +1,26 @@
1
- const os = require('node:os');
2
- const path = require('node:path');
1
+ const os = require("node:os");
2
+ const path = require("node:path");
3
3
 
4
- const { readJsonStrict, writeFileAtomic, chmod600IfPossible } = require('../lib/fs');
5
- const { resolveTrackerPaths } = require('../lib/tracker-paths');
6
- const { collectTrackerDiagnostics } = require('../lib/diagnostics');
7
- const { resolveRuntimeConfig } = require('../lib/runtime-config');
8
- const { buildDoctorReport } = require('../lib/doctor');
4
+ const { readJsonStrict, writeFileAtomic, chmod600IfPossible } = require("../lib/fs");
5
+ const { resolveTrackerPaths } = require("../lib/tracker-paths");
6
+ const { collectTrackerDiagnostics } = require("../lib/diagnostics");
7
+ const { resolveRuntimeConfig } = require("../lib/runtime-config");
8
+ const { buildDoctorReport } = require("../lib/doctor");
9
9
 
10
10
  async function cmdDoctor(argv = []) {
11
11
  const opts = parseArgs(argv);
12
12
  const home = os.homedir();
13
13
  const { trackerDir } = await resolveTrackerPaths({ home });
14
- const configPath = path.join(trackerDir, 'config.json');
14
+ const configPath = path.join(trackerDir, "config.json");
15
15
 
16
16
  const configStatus = await readJsonStrict(configPath);
17
- const config = configStatus.status === 'ok' && isPlainObject(configStatus.value) ? configStatus.value : {};
18
- const runtime = resolveRuntimeConfig({ cli: { baseUrl: opts.baseUrl }, config, env: process.env });
17
+ const config =
18
+ configStatus.status === "ok" && isPlainObject(configStatus.value) ? configStatus.value : {};
19
+ const runtime = resolveRuntimeConfig({
20
+ cli: { baseUrl: opts.baseUrl },
21
+ config,
22
+ env: process.env,
23
+ });
19
24
  const diagnostics = await collectTrackerDiagnostics({ home });
20
25
  const cliPath = process.argv[1] ? path.resolve(process.argv[1]) : null;
21
26
 
@@ -26,12 +31,12 @@ async function cmdDoctor(argv = []) {
26
31
  paths: {
27
32
  trackerDir,
28
33
  configPath,
29
- cliPath
30
- }
34
+ cliPath,
35
+ },
31
36
  });
32
37
 
33
38
  const jsonOutput = opts.json || Boolean(opts.out);
34
- const payload = JSON.stringify(report, null, jsonOutput ? 2 : 0) + '\n';
39
+ const payload = JSON.stringify(report, null, jsonOutput ? 2 : 0) + "\n";
35
40
 
36
41
  if (opts.out) {
37
42
  const outPath = path.resolve(process.cwd(), opts.out);
@@ -55,9 +60,9 @@ function parseArgs(argv) {
55
60
  const out = { json: false, out: null, baseUrl: null };
56
61
  for (let i = 0; i < argv.length; i += 1) {
57
62
  const arg = argv[i];
58
- if (arg === '--json') out.json = true;
59
- else if (arg === '--out') out.out = argv[++i] || null;
60
- else if (arg === '--base-url') out.baseUrl = argv[++i] || null;
63
+ if (arg === "--json") out.json = true;
64
+ else if (arg === "--out") out.out = argv[++i] || null;
65
+ else if (arg === "--base-url") out.baseUrl = argv[++i] || null;
61
66
  else throw new Error(`Unknown option: ${arg}`);
62
67
  }
63
68
  return out;
@@ -65,27 +70,27 @@ function parseArgs(argv) {
65
70
 
66
71
  function renderHumanReport(report) {
67
72
  const lines = [];
68
- lines.push('Doctor report');
69
- lines.push('');
73
+ lines.push("Doctor report");
74
+ lines.push("");
70
75
  for (const check of report.checks || []) {
71
76
  lines.push(formatCheckLine(check));
72
77
  }
73
- lines.push('');
78
+ lines.push("");
74
79
  lines.push(
75
- `Summary: ok ${report.summary.ok} | warn ${report.summary.warn} | fail ${report.summary.fail} | critical ${report.summary.critical}`
80
+ `Summary: ok ${report.summary.ok} | warn ${report.summary.warn} | fail ${report.summary.fail} | critical ${report.summary.critical}`,
76
81
  );
77
- lines.push('');
78
- return lines.join('\n');
82
+ lines.push("");
83
+ return lines.join("\n");
79
84
  }
80
85
 
81
86
  function formatCheckLine(check = {}) {
82
- const status = String(check.status || 'unknown').toUpperCase();
83
- const detail = check.detail ? ` - ${check.detail}` : '';
84
- return `- [${status}] ${check.id || 'unknown'}${detail}`;
87
+ const status = String(check.status || "unknown").toUpperCase();
88
+ const detail = check.detail ? ` - ${check.detail}` : "";
89
+ return `- [${status}] ${check.id || "unknown"}${detail}`;
85
90
  }
86
91
 
87
92
  function isPlainObject(value) {
88
- return Boolean(value && typeof value === 'object' && !Array.isArray(value));
93
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
89
94
  }
90
95
 
91
96
  module.exports = { cmdDoctor };