ai-cc-router 0.2.5 → 0.2.6

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.
@@ -4,6 +4,7 @@ import { fileURLToPath } from "url";
4
4
  import { join, dirname } from "path";
5
5
  import chalk from "chalk";
6
6
  import { detectPlatform } from "../utils/platform.js";
7
+ import { showTelemetryDisclosureIfNeeded } from "../utils/telemetry.js";
7
8
  const execFileAsync = promisify(execFile);
8
9
  // Resolve the path to the compiled CLI entry point
9
10
  const __filename = fileURLToPath(import.meta.url);
@@ -18,6 +19,9 @@ export function registerService(program) {
18
19
  .description("Register cc-router to start automatically on system boot")
19
20
  .action(async () => {
20
21
  console.log(chalk.cyan("\nInstalling cc-router as a system service...\n"));
22
+ // Show telemetry disclosure once before the service takes over — after
23
+ // this point output goes to PM2 logs, not the user's terminal.
24
+ showTelemetryDisclosureIfNeeded();
21
25
  // 1. Verify PM2 is installed
22
26
  const pm2Version = await getPm2Version();
23
27
  if (!pm2Version) {
@@ -13,8 +13,7 @@ import { DEFAULT_RATE_LIMITS } from "../proxy/types.js";
13
13
  import { existsSync } from "fs";
14
14
  import { checkMitmproxyInstalled, isCaCertInstalled, generateCaCert, installCaCert, writeAddonScript, getNetworkExtensionStatus, openNetworkExtensionSettings, } from "../interceptor/mitmproxy-manager.js";
15
15
  import { printDesktopSupportExplainer, printNetworkExtensionInstructions } from "./cmd-client.js";
16
- import { loadTelemetryState, writeTelemetryState } from "../config/telemetry.js";
17
- import { trackEvent } from "../utils/telemetry.js";
16
+ import { trackEvent, showTelemetryDisclosureIfNeeded } from "../utils/telemetry.js";
18
17
  const execFileAsync = promisify(execFile);
19
18
  // ─── Public registration ──────────────────────────────────────────────────────
20
19
  export function registerSetup(program) {
@@ -219,33 +218,6 @@ async function runSetupWizard({ addMode }) {
219
218
  // ─── Post-setup interactive flow ─────────────────────────────────────────
220
219
  await runPostSetupFlow(merged.length);
221
220
  }
222
- // Anonymous telemetry disclosure, shown exactly once after a successful setup.
223
- // Controlled by telemetry.disclosureShown in ~/.cc-router/telemetry.json.
224
- function showTelemetryDisclosureIfNeeded() {
225
- try {
226
- const state = loadTelemetryState();
227
- if (state.disclosureShown)
228
- return;
229
- console.log();
230
- console.log(chalk.dim("─".repeat(60)));
231
- console.log(chalk.bold(" Anonymous usage analytics"));
232
- console.log();
233
- console.log(" CC-Router sends anonymous lifecycle events (version, OS,");
234
- console.log(" startup, heartbeat) to help us understand usage and prioritize");
235
- console.log(" improvements. No IPs, no tokens, no prompts, no request content.");
236
- console.log();
237
- console.log(` Disable: ${chalk.cyan("cc-router telemetry off")}`);
238
- console.log(` Or set: ${chalk.cyan("DO_NOT_TRACK=1")} | ${chalk.cyan("CC_ROUTER_TELEMETRY=0")}`);
239
- console.log(` Source: ${chalk.dim("src/utils/telemetry.ts")}`);
240
- console.log(chalk.dim("─".repeat(60)));
241
- console.log();
242
- state.disclosureShown = true;
243
- writeTelemetryState(state);
244
- }
245
- catch {
246
- // never block setup on telemetry errors
247
- }
248
- }
249
221
  // ─── Post-setup interactive flow ─────────────────────────────────────────────
250
222
  async function runPostSetupFlow(accountCount) {
251
223
  console.log(chalk.bold(`\n${"━".repeat(40)}\n Configure this machine\n${"━".repeat(40)}\n`));
@@ -2,6 +2,7 @@ import { execFile } from "child_process";
2
2
  import { promisify } from "util";
3
3
  import chalk from "chalk";
4
4
  import { PROXY_PORT, LITELLM_PORT, ACCOUNTS_PATH } from "../config/paths.js";
5
+ import { showTelemetryDisclosureIfNeeded } from "../utils/telemetry.js";
5
6
  const execFileAsync = promisify(execFile);
6
7
  export function registerStart(program) {
7
8
  program
@@ -13,6 +14,9 @@ export function registerStart(program) {
13
14
  .option("--accounts <path>", "Path to accounts.json", ACCOUNTS_PATH)
14
15
  .action(async (opts) => {
15
16
  if (opts.daemon) {
17
+ // Show telemetry disclosure in the user's terminal before handing off
18
+ // to PM2 — once the daemon starts, its stdout goes to PM2 logs.
19
+ showTelemetryDisclosureIfNeeded();
16
20
  await startDaemon();
17
21
  return;
18
22
  }
@@ -6,7 +6,7 @@ import { TokenPool } from "./token-pool.js";
6
6
  import { needsRefresh, refreshAccountToken, saveAccounts, startRefreshLoop } from "./token-refresher.js";
7
7
  import { loadAccounts, accountsFileExists, readAccountsFromPath, readConfig } from "../config/manager.js";
8
8
  import { checkForUpdate, performUpdate, restartSelf } from "../utils/self-update.js";
9
- import { trackEvent, startHeartbeat } from "../utils/telemetry.js";
9
+ import { trackEvent, startHeartbeat, showTelemetryDisclosureIfNeeded } from "../utils/telemetry.js";
10
10
  import { loadTelemetryState } from "../config/telemetry.js";
11
11
  import { logRoute, logError, logStartup } from "./logger.js";
12
12
  import { stats } from "./stats.js";
@@ -385,8 +385,11 @@ export async function startServer(opts = {}) {
385
385
  logStartup(port, host, mode, target, accounts.length);
386
386
  if (autoUpdate)
387
387
  console.log(chalk.gray(" Auto-update: enabled (patch/minor)"));
388
- // Anonymous telemetry — fire-and-forget, never blocks proxy startup
388
+ // Anonymous telemetry — fire-and-forget, never blocks proxy startup.
389
+ // Show the disclosure on the very first start (covers existing users
390
+ // upgrading from versions before telemetry existed) before sending anything.
389
391
  try {
392
+ showTelemetryDisclosureIfNeeded();
390
393
  const telemetryState = loadTelemetryState();
391
394
  // First-run detection: if the install is brand new, emit app_started too
392
395
  const firstRunAge = Date.now() - new Date(telemetryState.firstRunAt).getTime();
@@ -1,5 +1,6 @@
1
1
  import os from "os";
2
- import { isTelemetryEnabled, loadTelemetryState } from "../config/telemetry.js";
2
+ import chalk from "chalk";
3
+ import { isTelemetryEnabled, loadTelemetryState, writeTelemetryState } from "../config/telemetry.js";
3
4
  import { detectPlatform } from "./platform.js";
4
5
  import { getCurrentVersion } from "./self-update.js";
5
6
  // ─── Aptabase configuration ──────────────────────────────────────────────────
@@ -84,3 +85,33 @@ export function startHeartbeat(accountCount) {
84
85
  }, 6 * 60 * 60 * 1000);
85
86
  timer.unref();
86
87
  }
88
+ // One-time disclosure shown the very first time CC-Router runs after install
89
+ // or upgrade. Idempotent — gated by telemetry.disclosureShown so it's safe to
90
+ // call from multiple entry points (setup wizard, foreground start, daemon
91
+ // start, service install). Returns true if the disclosure was just shown.
92
+ export function showTelemetryDisclosureIfNeeded() {
93
+ try {
94
+ const state = loadTelemetryState();
95
+ if (state.disclosureShown)
96
+ return false;
97
+ console.log();
98
+ console.log(chalk.dim("─".repeat(60)));
99
+ console.log(chalk.bold(" Anonymous usage analytics"));
100
+ console.log();
101
+ console.log(" CC-Router sends anonymous lifecycle events (version, OS,");
102
+ console.log(" startup, heartbeat) to help us understand usage and prioritize");
103
+ console.log(" improvements. No IPs, no tokens, no prompts, no request content.");
104
+ console.log();
105
+ console.log(` Disable: ${chalk.cyan("cc-router telemetry off")}`);
106
+ console.log(` Or set: ${chalk.cyan("DO_NOT_TRACK=1")} | ${chalk.cyan("CC_ROUTER_TELEMETRY=0")}`);
107
+ console.log(` Source: ${chalk.dim("src/utils/telemetry.ts")}`);
108
+ console.log(chalk.dim("─".repeat(60)));
109
+ console.log();
110
+ state.disclosureShown = true;
111
+ writeTelemetryState(state);
112
+ return true;
113
+ }
114
+ catch {
115
+ return false;
116
+ }
117
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-cc-router",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Round-robin proxy for Claude Max OAuth tokens — use multiple Claude Max accounts with Claude Code",
5
5
  "type": "module",
6
6
  "bin": {