@vike-io/cli 0.7.1 → 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/package.json +4 -4
- package/src/index.js +20 -0
- package/src/telemetry.js +17 -11
- package/src/update-check.js +1 -10
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.7.
|
|
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": "^
|
|
68
|
+
"commander": "^14.0.3"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@changesets/cli": "^2.27.9",
|
|
72
|
-
"eslint": "^
|
|
73
|
-
"vitest": "^
|
|
72
|
+
"eslint": "^10.4.0",
|
|
73
|
+
"vitest": "^4.1.7"
|
|
74
74
|
}
|
|
75
75
|
}
|
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
|
|
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
|
-
//
|
|
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
|
|
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: {
|
|
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)
|
|
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 } = {}) {
|
package/src/update-check.js
CHANGED
|
@@ -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 {
|
|
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 = `
|