@vike-io/cli 0.7.0 → 0.7.2

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes are documented here. Entries follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
4
 
5
+ ## 0.7.1 — eval harness v2 + help tweaks + SQL fix
6
+
7
+ - **Eval schema upgraded** (`evals/questions.yaml`): multi-command list, per-skill tag, multi-step flag, word-boundary forbidden matching. Per-skill scoring breakdown + single-vs-multi-step split in the runner output.
8
+ - **10 new multi-step questions** exercising composite playbook skills (smart-money-discovery, wallet-portfolio, polymarket-screener, perp-screener, hl-trader-profile, alerts-setup, etc.) — 32 questions total.
9
+ - **Help discoverability tweaks**: `wallet counterparties --limit` and `wallet balances --min-usd` descriptions improved (eval surfaced both as commonly-missed flags).
10
+ - **Backend bug fix shipped (server-side)**: `wallet_transactions` returned 0 rows due to ClickHouse SELECT-alias shadowing — fixed in monorepo, deployed to prod.
11
+
5
12
  ## 0.7.0 — 5 new commands (transactions, compare, trace, batch, screener)
6
13
 
7
14
  - **`vike wallet transactions <address>`** (alias `txs`) — raw per-wallet transfer list with `--direction in|out|all`, `--days`, `--min-usd`, `--token` filters.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.7.0",
6
+ "version": "0.7.2",
7
7
  "description": "AI-agent CLI for vike.io on-chain analytics, perps, options, and prediction markets across 11 chains",
8
8
  "type": "module",
9
9
  "main": "src/index.js",
@@ -65,11 +65,11 @@
65
65
  "node": ">=20.0.0"
66
66
  },
67
67
  "dependencies": {
68
- "commander": "^12.1.0"
68
+ "commander": "^14.0.3"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@changesets/cli": "^2.27.9",
72
- "eslint": "^9.15.0",
73
- "vitest": "^2.1.5"
72
+ "eslint": "^10.4.0",
73
+ "vitest": "^4.1.7"
74
74
  }
75
75
  }
@@ -104,7 +104,7 @@ export function registerWallet(program) {
104
104
  .description('Top trading partners of a wallet by combined transfer volume')
105
105
  .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
106
106
  .option('--window <w>', '24h | 7d | 30d | 90d | 180d | all', '30d')
107
- .option('--limit <n>', 'Max counterparties (max 50)', '10')
107
+ .option('--limit <n>', 'Max counterparties returned (default 10, max 50)', '10')
108
108
  .option('--json', 'Emit JSON')
109
109
  .action(async (address, opts) => {
110
110
  try {
@@ -139,7 +139,7 @@ export function registerWallet(program) {
139
139
  .command('balances <address>')
140
140
  .description('Current ERC-20 holdings across major EVM chains')
141
141
  .option('--chains <list>', 'Comma-separated chains (eth,bsc,base,arbitrum,polygon,optimism)')
142
- .option('--min-usd <n>', 'Filter dust below this USD value', '1')
142
+ .option('--min-usd <n>', 'Filter dust below this USD value (default $1; recommend $100+ for noisy wallets)', '1')
143
143
  .option('--json', 'Emit JSON')
144
144
  .action(async (address, opts) => {
145
145
  try {
package/src/index.js CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  getUpgradeNotice,
22
22
  scheduleUpdateCheck,
23
23
  } from './update-check.js';
24
+ import { trackCommandSucceeded, trackCommandFailed } from './telemetry.js';
24
25
 
25
26
  const version = readPackageVersion();
26
27
 
@@ -38,6 +39,19 @@ program
38
39
  .description('AI-agent CLI for vike.io on-chain analytics')
39
40
  .version(version, '-v, --version', 'Show CLI version');
40
41
 
42
+ // Telemetry: time each command from preAction to postAction; failure path is
43
+ // caught below via parseAsync().catch().
44
+ const _cmdStart = new WeakMap();
45
+ program.hook('preAction', (_thisCmd, actionCmd) => {
46
+ _cmdStart.set(actionCmd, Date.now());
47
+ });
48
+ program.hook('postAction', (_thisCmd, actionCmd) => {
49
+ const t0 = _cmdStart.get(actionCmd);
50
+ trackCommandSucceeded(actionCmd.name(), actionCmd.opts(), {
51
+ durationMs: t0 ? Date.now() - t0 : null,
52
+ });
53
+ });
54
+
41
55
  registerLogin(program);
42
56
  registerLogout(program);
43
57
  registerInit(program);
@@ -52,10 +66,16 @@ registerPolymarket(program);
52
66
  registerLabels(program);
53
67
  registerWeb(program);
54
68
 
69
+ const _parseT0 = Date.now();
55
70
  program.parseAsync(process.argv)
56
71
  .catch((err) => {
57
72
  console.error(`vike: ${err.message ?? err}`);
58
73
  process.exitCode = 1;
74
+ const cmd = program.args[0] || 'unknown';
75
+ trackCommandFailed(cmd, {}, {
76
+ errorCode: err?.code || err?.name || 'error',
77
+ durationMs: Date.now() - _parseT0,
78
+ });
59
79
  })
60
80
  .finally(() => {
61
81
  // Fire-and-forget background check, detached subprocess. Survives our exit.
package/src/telemetry.js CHANGED
@@ -1,4 +1,4 @@
1
- // Anonymous, opt-out telemetry skeleton.
1
+ // Anonymous, opt-out telemetry.
2
2
  //
3
3
  // Design decisions:
4
4
  // - Honors DO_NOT_TRACK=1 (industry standard) AND VIKE_NO_TELEMETRY=1
@@ -7,25 +7,24 @@
7
7
  // - Rolling 30-min session ID — same session_id within a 30-min window
8
8
  // - AbortController + 1000ms timeout, timer.unref() so we can't keep
9
9
  // the process alive
10
- // - Payload includes: flag NAMES (no values), latency, success/error_code,
11
- // chain (if relevant). NEVER the actual data the user queried.
10
+ // - Payload includes: flag NAMES (no values), latency, success/error_code.
11
+ // NEVER the actual data the user queried (no addresses, no symbols).
12
12
  // - Fire-and-forget: errors are swallowed
13
- //
14
- // THE SINK IS NOT YET WIRED. `_send()` is a no-op until we have an
15
- // endpoint. Keeping the API shape stable now so we can flip the switch
16
- // later without a refactor.
17
13
 
18
- import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from 'node:fs';
14
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
19
15
  import { homedir } from 'node:os';
20
16
  import { join } from 'node:path';
21
17
  import { randomUUID } from 'node:crypto';
18
+ import { readPackageVersion } from './util.js';
22
19
 
23
20
  const CONFIG_DIR = join(homedir(), '.vike');
24
21
  const ID_FILE = join(CONFIG_DIR, 'telemetry-id');
25
22
  const SESSION_FILE = join(CONFIG_DIR, 'session');
26
23
  const SESSION_TTL_MS = 30 * 60 * 1000;
27
- const ENDPOINT = process.env.VIKE_TELEMETRY_ENDPOINT || '';
24
+ const ENDPOINT = process.env.VIKE_TELEMETRY_ENDPOINT
25
+ || 'https://vike.io/api/cli-telemetry';
28
26
  const REQUEST_TIMEOUT_MS = 1000;
27
+ const CLI_VERSION = (() => { try { return readPackageVersion(); } catch { return ''; } })();
29
28
 
30
29
  function disabled() {
31
30
  return process.env.DO_NOT_TRACK === '1' ||
@@ -82,9 +81,13 @@ function _send(event, payload) {
82
81
  if (typeof timer.unref === 'function') timer.unref();
83
82
  fetch(ENDPOINT, {
84
83
  method: 'POST',
85
- headers: { 'Content-Type': 'application/json' },
84
+ headers: {
85
+ 'Content-Type': 'application/json',
86
+ 'User-Agent': `vike-cli/${CLI_VERSION}`,
87
+ },
86
88
  body: JSON.stringify({
87
89
  event,
90
+ cli_version: CLI_VERSION,
88
91
  device_id: getDeviceId(),
89
92
  session_id: getSessionId(),
90
93
  ts: Date.now(),
@@ -98,8 +101,11 @@ function _send(event, payload) {
98
101
 
99
102
  function flagNames(opts) {
100
103
  // Extract flag names from a commander options object. Values stripped.
104
+ // Convert camelCase to kebab-case for readability in analytics.
101
105
  if (!opts || typeof opts !== 'object') return [];
102
- return Object.keys(opts).filter((k) => !k.startsWith('_') && k !== 'parent');
106
+ return Object.keys(opts)
107
+ .filter((k) => !k.startsWith('_') && k !== 'parent')
108
+ .map((k) => '--' + k.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()));
103
109
  }
104
110
 
105
111
  export function trackCommandSucceeded(command, opts, { durationMs } = {}) {
@@ -11,8 +11,7 @@
11
11
  import { spawn } from 'node:child_process';
12
12
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
13
13
  import { homedir } from 'node:os';
14
- import { dirname, join } from 'node:path';
15
- import { fileURLToPath } from 'node:url';
14
+ import { join } from 'node:path';
16
15
 
17
16
  const CONFIG_DIR = join(homedir(), '.vike');
18
17
  const CHECK_FILE = join(CONFIG_DIR, 'update-check.json');
@@ -33,13 +32,6 @@ function readCache() {
33
32
  try { return JSON.parse(readFileSync(CHECK_FILE, 'utf8')); } catch { return null; }
34
33
  }
35
34
 
36
- function writeCache(latest) {
37
- try {
38
- if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
39
- writeFileSync(CHECK_FILE, JSON.stringify({ latest, checkedAt: Date.now() }, null, 2));
40
- } catch { /* ignore */ }
41
- }
42
-
43
35
  function cmpSemver(a, b) {
44
36
  const pa = a.split('.').map(Number);
45
37
  const pb = b.split('.').map(Number);
@@ -73,7 +65,6 @@ export function scheduleUpdateCheck() {
73
65
  const cache = readCache();
74
66
  if (cache && Date.now() - (cache.checkedAt || 0) < CHECK_INTERVAL_MS) return;
75
67
 
76
- const __filename = fileURLToPath(import.meta.url);
77
68
  // Inline child script — no separate file needed, no dependency on
78
69
  // package layout, survives `npm install -g` symlinking.
79
70
  const code = `