@code-insights/cli 3.2.0 → 3.3.0
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 +29 -0
- package/dashboard-dist/assets/index-cAfuFBOl.js +552 -0
- package/dashboard-dist/index.html +1 -1
- package/dist/commands/config.js +2 -2
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install-hook.js +1 -1
- package/dist/commands/install-hook.js.map +1 -1
- package/dist/commands/open.js +2 -2
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/reset.js +1 -1
- package/dist/commands/reset.js.map +1 -1
- package/dist/commands/stats/actions/cost.d.ts.map +1 -1
- package/dist/commands/stats/actions/cost.js +6 -3
- package/dist/commands/stats/actions/cost.js.map +1 -1
- package/dist/commands/stats/actions/models.d.ts.map +1 -1
- package/dist/commands/stats/actions/models.js +6 -3
- package/dist/commands/stats/actions/models.js.map +1 -1
- package/dist/commands/stats/actions/overview.d.ts.map +1 -1
- package/dist/commands/stats/actions/overview.js +6 -3
- package/dist/commands/stats/actions/overview.js.map +1 -1
- package/dist/commands/stats/actions/projects.d.ts.map +1 -1
- package/dist/commands/stats/actions/projects.js +6 -3
- package/dist/commands/stats/actions/projects.js.map +1 -1
- package/dist/commands/stats/actions/today.d.ts.map +1 -1
- package/dist/commands/stats/actions/today.js +6 -3
- package/dist/commands/stats/actions/today.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +33 -4
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/telemetry.d.ts.map +1 -1
- package/dist/commands/telemetry.js +10 -14
- package/dist/commands/telemetry.js.map +1 -1
- package/dist/utils/telemetry.d.ts +36 -31
- package/dist/utils/telemetry.d.ts.map +1 -1
- package/dist/utils/telemetry.js +136 -188
- package/dist/utils/telemetry.js.map +1 -1
- package/package.json +3 -2
- package/server-dist/index.d.ts.map +1 -1
- package/server-dist/index.js +13 -6
- package/server-dist/index.js.map +1 -1
- package/server-dist/routes/analysis.d.ts.map +1 -1
- package/server-dist/routes/analysis.js +72 -9
- package/server-dist/routes/analysis.js.map +1 -1
- package/server-dist/routes/export.js +1 -1
- package/server-dist/routes/export.js.map +1 -1
- package/server-dist/routes/telemetry.d.ts +4 -0
- package/server-dist/routes/telemetry.d.ts.map +1 -0
- package/server-dist/routes/telemetry.js +21 -0
- package/server-dist/routes/telemetry.js.map +1 -0
- package/dashboard-dist/assets/index-DzBnL32c.js +0 -549
package/dist/utils/telemetry.js
CHANGED
|
@@ -3,16 +3,18 @@ import * as path from 'path';
|
|
|
3
3
|
import * as os from 'os';
|
|
4
4
|
import * as crypto from 'crypto';
|
|
5
5
|
import { createRequire } from 'module';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
// Touch file path that tracks whether the one-time disclosure has been shown
|
|
6
|
+
import { PostHog } from 'posthog-node';
|
|
7
|
+
import { loadConfig, getConfigDir } from './config.js';
|
|
8
|
+
// PostHog write-only API key (public — this is the standard PostHog pattern;
|
|
9
|
+
// write-only keys can only ingest events, not read data).
|
|
10
|
+
const POSTHOG_API_KEY = 'phc_552ZSApq5xuagswylfdw2vx8nckm31jn6LCpTVyVn8j';
|
|
11
|
+
const POSTHOG_HOST = 'https://us.i.posthog.com';
|
|
12
|
+
// Touch file path that tracks whether the disclosure has been shown.
|
|
13
|
+
// Content is the CLI version — if version doesn't match current, notice is re-shown.
|
|
15
14
|
const NOTICE_FILE = path.join(getConfigDir(), '.telemetry-notice-shown');
|
|
15
|
+
// PostHog client — lazily initialized on first trackEvent call.
|
|
16
|
+
// null when telemetry is disabled or init hasn't happened yet.
|
|
17
|
+
let client = null;
|
|
16
18
|
/**
|
|
17
19
|
* Check if telemetry is enabled.
|
|
18
20
|
*
|
|
@@ -28,123 +30,180 @@ export function isTelemetryEnabled() {
|
|
|
28
30
|
if (process.env.DO_NOT_TRACK === '1')
|
|
29
31
|
return false;
|
|
30
32
|
const config = loadConfig();
|
|
31
|
-
// If explicitly set in config, respect it
|
|
32
33
|
if (config !== null && typeof config.telemetry === 'boolean') {
|
|
33
34
|
return config.telemetry;
|
|
34
35
|
}
|
|
35
|
-
// Default: enabled (opt-out model)
|
|
36
36
|
return true;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Get (or lazily create) the PostHog client.
|
|
40
|
+
* Returns null when telemetry is disabled.
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
42
|
+
* flushAt: 1 — flush immediately after each capture(); CLI is short-lived
|
|
43
|
+
* flushInterval: 0 — no background timer; avoids keeping process alive
|
|
44
|
+
*/
|
|
45
|
+
function getPostHogClient() {
|
|
46
|
+
if (!isTelemetryEnabled())
|
|
47
|
+
return null;
|
|
48
|
+
if (!client) {
|
|
49
|
+
client = new PostHog(POSTHOG_API_KEY, {
|
|
50
|
+
host: POSTHOG_HOST,
|
|
51
|
+
flushAt: 1,
|
|
52
|
+
flushInterval: 0,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return client;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Flush and shut down the PostHog client.
|
|
59
|
+
* Call this in server SIGINT/SIGTERM handlers before process.exit().
|
|
60
|
+
* No-op if telemetry is disabled or client was never initialized.
|
|
61
|
+
*/
|
|
62
|
+
export async function shutdownTelemetry() {
|
|
63
|
+
if (client) {
|
|
64
|
+
await client.shutdown();
|
|
65
|
+
client = null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Show the telemetry disclosure notice if it hasn't been shown for this CLI version.
|
|
43
70
|
*
|
|
44
|
-
*
|
|
71
|
+
* Uses a version-stamped touch file at ~/.code-insights/.telemetry-notice-shown.
|
|
72
|
+
* Re-shown when the CLI version changes (catches existing users on upgrades).
|
|
73
|
+
* Only displays if telemetry is enabled.
|
|
74
|
+
*
|
|
75
|
+
* Returns true if the notice was shown.
|
|
45
76
|
*/
|
|
46
77
|
export function showTelemetryNoticeIfNeeded() {
|
|
47
78
|
if (!isTelemetryEnabled())
|
|
48
79
|
return false;
|
|
49
|
-
|
|
80
|
+
const currentVersion = getCliVersion();
|
|
81
|
+
let shownVersion = null;
|
|
82
|
+
if (fs.existsSync(NOTICE_FILE)) {
|
|
83
|
+
try {
|
|
84
|
+
shownVersion = fs.readFileSync(NOTICE_FILE, 'utf-8').trim();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Can't read — treat as not shown
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (shownVersion === currentVersion)
|
|
50
91
|
return false;
|
|
51
|
-
// Show the disclosure banner
|
|
92
|
+
// Show the updated disclosure banner
|
|
52
93
|
console.log('');
|
|
53
|
-
console.log(' Code Insights collects anonymous usage data to improve the CLI.');
|
|
54
|
-
console.log(' Includes:
|
|
55
|
-
console.log('
|
|
94
|
+
console.log(' Code Insights collects anonymous usage data to improve the CLI and dashboard.');
|
|
95
|
+
console.log(' Includes: commands, page views, OS, CLI version, AI tool types, session counts,');
|
|
96
|
+
console.log(' LLM provider, performance timing.');
|
|
97
|
+
console.log(' Never includes: file paths, project names, session content, API keys, or personal data.');
|
|
56
98
|
console.log('');
|
|
57
99
|
console.log(' Disable: code-insights telemetry disable');
|
|
58
100
|
console.log(' Details: code-insights telemetry status');
|
|
59
101
|
console.log('');
|
|
60
|
-
//
|
|
102
|
+
// Write the current version as content — best-effort, non-fatal
|
|
61
103
|
try {
|
|
62
|
-
// Ensure config dir exists before writing touch file
|
|
63
104
|
const configDir = getConfigDir();
|
|
64
105
|
if (!fs.existsSync(configDir)) {
|
|
65
106
|
fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
66
107
|
}
|
|
67
|
-
fs.writeFileSync(NOTICE_FILE,
|
|
108
|
+
fs.writeFileSync(NOTICE_FILE, currentVersion, { encoding: 'utf-8', mode: 0o600 });
|
|
68
109
|
}
|
|
69
110
|
catch {
|
|
70
|
-
// Non-fatal — if we can't write
|
|
71
|
-
// next time. That's acceptable; we don't want to break the CLI over this.
|
|
111
|
+
// Non-fatal — if we can't write, we'll show the notice again next time
|
|
72
112
|
}
|
|
73
113
|
return true;
|
|
74
114
|
}
|
|
75
115
|
/**
|
|
76
|
-
*
|
|
116
|
+
* Send a telemetry event. Never throws — telemetry must never break the CLI.
|
|
77
117
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* - 2s AbortController timeout: we don't hang if the endpoint is slow
|
|
81
|
-
* - Swallows ALL errors: network failures, JSON errors, anything — telemetry
|
|
82
|
-
* must never cause a CLI command to fail
|
|
83
|
-
* - No retries: if it fails, it fails. Reliability of individual events
|
|
84
|
-
* matters less than not disrupting the user's workflow.
|
|
118
|
+
* @param event - Event name from TelemetryEventName union
|
|
119
|
+
* @param properties - Arbitrary event properties (success, duration_ms, etc.)
|
|
85
120
|
*/
|
|
86
|
-
export function trackEvent(
|
|
87
|
-
|
|
121
|
+
export function trackEvent(event, properties) {
|
|
122
|
+
const ph = getPostHogClient();
|
|
123
|
+
if (!ph)
|
|
88
124
|
return;
|
|
89
|
-
// Build the event synchronously — filesystem reads happen here
|
|
90
|
-
let event;
|
|
91
125
|
try {
|
|
92
|
-
|
|
126
|
+
ph.capture({
|
|
127
|
+
distinctId: getStableMachineId(),
|
|
128
|
+
event,
|
|
129
|
+
properties: properties ?? {},
|
|
130
|
+
});
|
|
93
131
|
}
|
|
94
132
|
catch {
|
|
95
|
-
//
|
|
96
|
-
return;
|
|
133
|
+
// Swallow all errors — telemetry failures are silent
|
|
97
134
|
}
|
|
98
|
-
// Fire-and-forget: intentionally not awaited
|
|
99
|
-
// The void cast suppresses the "floating promise" lint warning
|
|
100
|
-
void sendEvent(event);
|
|
101
135
|
}
|
|
102
136
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
137
|
+
* Set person-level properties via PostHog identify().
|
|
138
|
+
* Call once after the DB is open (so total_sessions can be queried).
|
|
139
|
+
*
|
|
140
|
+
* Commands that never open the DB (init, config, telemetry) can skip this —
|
|
141
|
+
* PostHog retains person properties from previous calls.
|
|
105
142
|
*/
|
|
106
|
-
export function
|
|
107
|
-
|
|
143
|
+
export async function identifyUser() {
|
|
144
|
+
const ph = getPostHogClient();
|
|
145
|
+
if (!ph)
|
|
146
|
+
return;
|
|
147
|
+
try {
|
|
148
|
+
const { getDb } = await import('../db/client.js');
|
|
149
|
+
const db = getDb();
|
|
150
|
+
const row = db.prepare('SELECT COUNT(*) as count FROM sessions').get();
|
|
151
|
+
ph.identify({
|
|
152
|
+
distinctId: getStableMachineId(),
|
|
153
|
+
properties: {
|
|
154
|
+
cli_version: getCliVersion(),
|
|
155
|
+
node_version: process.version.replace('v', ''),
|
|
156
|
+
os: process.platform,
|
|
157
|
+
arch: process.arch,
|
|
158
|
+
installed_providers: detectProviders(),
|
|
159
|
+
has_hook: detectHook(),
|
|
160
|
+
total_sessions: row.count,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Non-fatal — identify failure doesn't affect event tracking
|
|
166
|
+
}
|
|
108
167
|
}
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
// Internal helpers
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
168
|
/**
|
|
113
|
-
* Build a
|
|
114
|
-
*
|
|
169
|
+
* Build a preview of what would be collected and sent.
|
|
170
|
+
* Used by `code-insights telemetry status` to show users what is collected.
|
|
115
171
|
*/
|
|
116
|
-
function
|
|
172
|
+
export function buildEventPreview() {
|
|
117
173
|
return {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
success,
|
|
122
|
-
cliVersion: getCliVersion(),
|
|
123
|
-
nodeVersion: process.version.replace('v', ''),
|
|
174
|
+
distinct_id: getStableMachineId(),
|
|
175
|
+
cli_version: getCliVersion(),
|
|
176
|
+
node_version: process.version.replace('v', ''),
|
|
124
177
|
os: process.platform,
|
|
125
178
|
arch: process.arch,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
179
|
+
installed_providers: detectProviders(),
|
|
180
|
+
has_hook: detectHook(),
|
|
181
|
+
total_sessions: '(queried from SQLite when DB is open)',
|
|
182
|
+
sample_event: {
|
|
183
|
+
event: 'cli_sync',
|
|
184
|
+
properties: {
|
|
185
|
+
duration_ms: 1234,
|
|
186
|
+
sessions_synced: 5,
|
|
187
|
+
sessions_by_provider: { 'claude-code': 4, cursor: 1 },
|
|
188
|
+
errors: 0,
|
|
189
|
+
source_filter: null,
|
|
190
|
+
success: true,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
132
193
|
};
|
|
133
194
|
}
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Internal helpers
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
134
198
|
/**
|
|
135
|
-
*
|
|
199
|
+
* Stable machine ID — does NOT rotate monthly.
|
|
136
200
|
*
|
|
137
|
-
* Format: SHA-256(hostname:username:code-insights
|
|
201
|
+
* Format: SHA-256(hostname:username:code-insights).slice(0, 16)
|
|
138
202
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* - Events within a month can be correlated for "unique users" metrics
|
|
142
|
-
* - No PII: hostname and username are never sent, only their hash
|
|
203
|
+
* No PII: hostname and username are never transmitted, only their hash.
|
|
204
|
+
* Deterministic: same machine always produces the same ID (survives reinstalls).
|
|
143
205
|
*/
|
|
144
|
-
function
|
|
145
|
-
const now = new Date();
|
|
146
|
-
// YYYY-MM format for monthly rotation
|
|
147
|
-
const monthSalt = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
|
|
206
|
+
export function getStableMachineId() {
|
|
148
207
|
let username;
|
|
149
208
|
try {
|
|
150
209
|
username = os.userInfo().username;
|
|
@@ -153,18 +212,15 @@ function getMachineId() {
|
|
|
153
212
|
// os.userInfo() throws in Docker/CI when UID has no /etc/passwd entry
|
|
154
213
|
username = `uid-${process.getuid?.() ?? 'unknown'}`;
|
|
155
214
|
}
|
|
156
|
-
const input = [os.hostname(), username,
|
|
215
|
+
const input = [os.hostname(), username, 'code-insights'].join(':');
|
|
157
216
|
return crypto.createHash('sha256').update(input).digest('hex').slice(0, 16);
|
|
158
217
|
}
|
|
159
218
|
/**
|
|
160
219
|
* Read CLI version from package.json.
|
|
161
|
-
* Uses createRequire for JSON imports since this is ESM and JSON imports
|
|
162
|
-
* have inconsistent support across Node versions and bundlers.
|
|
163
220
|
*/
|
|
164
221
|
function getCliVersion() {
|
|
165
222
|
try {
|
|
166
223
|
const require = createRequire(import.meta.url);
|
|
167
|
-
// package.json is two levels up from src/utils/ -> src/ -> cli/
|
|
168
224
|
const pkg = require('../../package.json');
|
|
169
225
|
return pkg.version;
|
|
170
226
|
}
|
|
@@ -174,96 +230,32 @@ function getCliVersion() {
|
|
|
174
230
|
}
|
|
175
231
|
/**
|
|
176
232
|
* Detect which AI coding tool data directories exist on this machine.
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* Returns only the tools that are actually present. This tells us which tools
|
|
180
|
-
* users are running alongside code-insights, helping us prioritize provider support.
|
|
233
|
+
* Checks directory existence only — never reads file contents.
|
|
181
234
|
*/
|
|
182
235
|
function detectProviders() {
|
|
183
236
|
const home = os.homedir();
|
|
184
237
|
const detected = [];
|
|
185
|
-
// Claude Code: ~/.claude/projects/
|
|
186
238
|
if (fs.existsSync(path.join(home, '.claude', 'projects'))) {
|
|
187
239
|
detected.push('claude-code');
|
|
188
240
|
}
|
|
189
|
-
// Cursor: workspace storage directory (cross-platform path)
|
|
190
241
|
const cursorStoragePaths = [
|
|
191
|
-
// macOS
|
|
192
242
|
path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'workspaceStorage'),
|
|
193
|
-
// Linux
|
|
194
243
|
path.join(home, '.config', 'Cursor', 'User', 'workspaceStorage'),
|
|
195
|
-
// Windows
|
|
196
244
|
path.join(home, 'AppData', 'Roaming', 'Cursor', 'User', 'workspaceStorage'),
|
|
197
245
|
];
|
|
198
246
|
if (cursorStoragePaths.some((p) => fs.existsSync(p))) {
|
|
199
247
|
detected.push('cursor');
|
|
200
248
|
}
|
|
201
|
-
// Codex CLI: ~/.codex/sessions
|
|
202
249
|
if (fs.existsSync(path.join(home, '.codex', 'sessions'))) {
|
|
203
250
|
detected.push('codex-cli');
|
|
204
251
|
}
|
|
205
|
-
// GitHub Copilot CLI: ~/.copilot/session-state
|
|
206
252
|
if (fs.existsSync(path.join(home, '.copilot', 'session-state'))) {
|
|
207
253
|
detected.push('copilot-cli');
|
|
208
254
|
}
|
|
209
255
|
return detected;
|
|
210
256
|
}
|
|
211
|
-
/**
|
|
212
|
-
* Count .jsonl files under ~/.claude/projects/ and bucket the count.
|
|
213
|
-
*
|
|
214
|
-
* Buckets are intentionally coarse — we want to understand "heavy vs light"
|
|
215
|
-
* usage without counting exact files, which could vary wildly and feels more
|
|
216
|
-
* private than a range.
|
|
217
|
-
*/
|
|
218
|
-
function getSessionCountBucket() {
|
|
219
|
-
try {
|
|
220
|
-
const claudeDir = getClaudeDir();
|
|
221
|
-
if (!fs.existsSync(claudeDir))
|
|
222
|
-
return '0';
|
|
223
|
-
// Count all .jsonl files recursively under the Claude projects directory
|
|
224
|
-
let count = 0;
|
|
225
|
-
const walk = (dir) => {
|
|
226
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
227
|
-
for (const entry of entries) {
|
|
228
|
-
if (entry.isDirectory()) {
|
|
229
|
-
walk(path.join(dir, entry.name));
|
|
230
|
-
}
|
|
231
|
-
else if (entry.name.endsWith('.jsonl')) {
|
|
232
|
-
count++;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
walk(claudeDir);
|
|
237
|
-
// Coarse buckets for privacy — exact session counts are never sent
|
|
238
|
-
if (count === 0)
|
|
239
|
-
return '0';
|
|
240
|
-
if (count <= 10)
|
|
241
|
-
return '1-10';
|
|
242
|
-
if (count <= 50)
|
|
243
|
-
return '11-50';
|
|
244
|
-
if (count <= 200)
|
|
245
|
-
return '51-200';
|
|
246
|
-
return '200+';
|
|
247
|
-
}
|
|
248
|
-
catch {
|
|
249
|
-
return 'unknown';
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Determine the configured data source.
|
|
254
|
-
* Always 'local' in Phase 2+ (SQLite-only).
|
|
255
|
-
*/
|
|
256
|
-
function getDataSource() {
|
|
257
|
-
const config = loadConfig();
|
|
258
|
-
if (!config)
|
|
259
|
-
return 'none';
|
|
260
|
-
return 'local';
|
|
261
|
-
}
|
|
262
257
|
/**
|
|
263
258
|
* Check if code-insights is registered as a Claude Code hook.
|
|
264
|
-
*
|
|
265
|
-
* Reads ~/.claude/settings.json and looks for 'code-insights' anywhere in the
|
|
266
|
-
* file content. A hook registration means the user has automated sync on session end.
|
|
267
259
|
*/
|
|
268
260
|
function detectHook() {
|
|
269
261
|
try {
|
|
@@ -277,48 +269,4 @@ function detectHook() {
|
|
|
277
269
|
return false;
|
|
278
270
|
}
|
|
279
271
|
}
|
|
280
|
-
/**
|
|
281
|
-
* Sign the request body with HMAC-SHA256.
|
|
282
|
-
* Returns the hex digest prefixed with 'sha256=' for the X-Signature header.
|
|
283
|
-
*
|
|
284
|
-
* Note: the key is public (extractable from the npm package) — this is a deterrent
|
|
285
|
-
* against casual data poisoning, not a cryptographic secret. Security is enforced
|
|
286
|
-
* server-side in the Edge Function using constant-time comparison.
|
|
287
|
-
*/
|
|
288
|
-
function signPayload(body) {
|
|
289
|
-
const digest = crypto.createHmac('sha256', HMAC_KEY).update(body).digest('hex');
|
|
290
|
-
return `sha256=${digest}`;
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Internal: Send the event to the telemetry endpoint.
|
|
294
|
-
* AbortController ensures we don't hang longer than 2 seconds.
|
|
295
|
-
* All errors are swallowed — telemetry failures must never propagate.
|
|
296
|
-
*/
|
|
297
|
-
async function sendEvent(event) {
|
|
298
|
-
const controller = new AbortController();
|
|
299
|
-
// 2s timeout — enough for a healthy network, short enough to not delay anything
|
|
300
|
-
const timer = setTimeout(() => controller.abort(), 2000);
|
|
301
|
-
try {
|
|
302
|
-
const body = JSON.stringify(event);
|
|
303
|
-
await fetch(TELEMETRY_ENDPOINT, {
|
|
304
|
-
method: 'POST',
|
|
305
|
-
headers: {
|
|
306
|
-
'Content-Type': 'application/json',
|
|
307
|
-
// HMAC signature — lets the Edge Function verify the payload wasn't tampered.
|
|
308
|
-
// The v2 endpoint accepts but does not require this header initially, allowing
|
|
309
|
-
// older CLI versions (which don't send it) to continue working.
|
|
310
|
-
'X-Signature': signPayload(body),
|
|
311
|
-
},
|
|
312
|
-
body,
|
|
313
|
-
signal: controller.signal,
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
catch {
|
|
317
|
-
// Swallow everything: network errors, AbortError, JSON serialization errors.
|
|
318
|
-
// Telemetry failures are silent — the CLI command already completed.
|
|
319
|
-
}
|
|
320
|
-
finally {
|
|
321
|
-
clearTimeout(timer);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
272
|
//# sourceMappingURL=telemetry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/utils/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/utils/telemetry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-insights/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "AI coding session analytics with built-in dashboard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -72,7 +72,8 @@
|
|
|
72
72
|
"commander": "^12.1.0",
|
|
73
73
|
"hono": "^4.7.4",
|
|
74
74
|
"inquirer": "^12.6.1",
|
|
75
|
-
"ora": "^8.2.0"
|
|
75
|
+
"ora": "^8.2.0",
|
|
76
|
+
"posthog-node": "^4.18.0"
|
|
76
77
|
},
|
|
77
78
|
"devDependencies": {
|
|
78
79
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAe5B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IAEb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,IAAI,CAiChC;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDvE"}
|
package/server-dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Hono } from 'hono';
|
|
|
4
4
|
import { existsSync, readFileSync } from 'fs';
|
|
5
5
|
import { relative, join } from 'path';
|
|
6
6
|
import { openUrl } from '@code-insights/cli/utils/browser';
|
|
7
|
+
import { shutdownTelemetry } from '@code-insights/cli/utils/telemetry';
|
|
7
8
|
import projectsRouter from './routes/projects.js';
|
|
8
9
|
import sessionsRouter from './routes/sessions.js';
|
|
9
10
|
import messagesRouter from './routes/messages.js';
|
|
@@ -12,6 +13,7 @@ import analysisRouter from './routes/analysis.js';
|
|
|
12
13
|
import analyticsRouter from './routes/analytics.js';
|
|
13
14
|
import configRouter from './routes/config.js';
|
|
14
15
|
import exportRouter from './routes/export.js';
|
|
16
|
+
import telemetryRouter from './routes/telemetry.js';
|
|
15
17
|
/**
|
|
16
18
|
* Create the Hono app with all API routes mounted.
|
|
17
19
|
* Does NOT add static file serving or call serve() — that's startServer's job.
|
|
@@ -37,6 +39,7 @@ export function createApp() {
|
|
|
37
39
|
app.route('/api/analytics', analyticsRouter);
|
|
38
40
|
app.route('/api/config', configRouter);
|
|
39
41
|
app.route('/api/export', exportRouter);
|
|
42
|
+
app.route('/api/telemetry', telemetryRouter);
|
|
40
43
|
// Health check
|
|
41
44
|
app.get('/api/health', (c) => c.json({ ok: true, version: '0.1.0' }));
|
|
42
45
|
// API 404 catch-all — must come AFTER all /api sub-routers and BEFORE static serving.
|
|
@@ -83,14 +86,18 @@ export async function startServer(options) {
|
|
|
83
86
|
</body></html>
|
|
84
87
|
`));
|
|
85
88
|
}
|
|
86
|
-
// Graceful shutdown:
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
const shutdown = () => {
|
|
89
|
+
// Graceful shutdown: flush PostHog events before exit, then let the process
|
|
90
|
+
// 'exit' handler in cli/src/db/client.ts run WAL checkpoint via closeDb().
|
|
91
|
+
// 3s timeout guards against PostHog SDK stalling on network issues.
|
|
92
|
+
const shutdown = async () => {
|
|
93
|
+
await Promise.race([
|
|
94
|
+
shutdownTelemetry(),
|
|
95
|
+
new Promise((resolve) => setTimeout(resolve, 3000)),
|
|
96
|
+
]);
|
|
90
97
|
process.exit(0);
|
|
91
98
|
};
|
|
92
|
-
process.on('SIGINT', shutdown);
|
|
93
|
-
process.on('SIGTERM', shutdown);
|
|
99
|
+
process.on('SIGINT', () => { void shutdown(); });
|
|
100
|
+
process.on('SIGTERM', () => { void shutdown(); });
|
|
94
101
|
serve({ fetch: app.fetch, port }, (info) => {
|
|
95
102
|
const url = `http://localhost:${info.port}`;
|
|
96
103
|
console.log(` Code Insights dashboard running at ${url}`);
|
package/server-dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAC3D,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,eAAe,MAAM,uBAAuB,CAAC;AACpD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,YAAY,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../src/routes/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,QAAA,MAAM,GAAG,4EAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../src/routes/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,QAAA,MAAM,GAAG,4EAAa,CAAC;AAkWvB,eAAe,GAAG,CAAC"}
|