ccjk 13.4.0 → 13.5.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.
@@ -1,6 +1,6 @@
1
1
  import a from './index2.mjs';
2
2
  import { c as consola, a as analyzeProject } from '../shared/ccjk.DypYla6I.mjs';
3
- import { c as createCompleteCloudClient } from '../shared/ccjk.BNVSnyu0.mjs';
3
+ import { c as createCompleteCloudClient } from '../shared/ccjk.C3YuTovw.mjs';
4
4
  import { i18n, ensureI18nInitialized } from './index5.mjs';
5
5
  import { createHash } from 'node:crypto';
6
6
  import { promises, readFileSync } from 'node:fs';
@@ -1,3 +1,3 @@
1
- const version = "13.4.0";
1
+ const version = "13.5.0";
2
2
 
3
3
  export { version };
package/dist/index.d.mts CHANGED
@@ -579,7 +579,7 @@ interface BatchTemplateResponse$1 {
579
579
  /**
580
580
  * Usage metric type
581
581
  */
582
- type MetricType = 'template_download' | 'recommendation_shown' | 'recommendation_accepted' | 'analysis_completed' | 'error_occurred';
582
+ type MetricType = 'template_download' | 'recommendation_shown' | 'recommendation_accepted' | 'analysis_completed' | 'error_occurred' | 'command_run' | (string & {});
583
583
  /**
584
584
  * Usage report payload
585
585
  */
@@ -596,6 +596,10 @@ interface UsageReport {
596
596
  nodeVersion: string;
597
597
  /** Operating system */
598
598
  platform: string;
599
+ /** Stable device identifier */
600
+ deviceId?: string;
601
+ /** Client version reported to analytics endpoints */
602
+ clientVersion?: string;
599
603
  /** Project language if applicable */
600
604
  language?: string;
601
605
  /** Additional context data - use TelemetryEventData from dto.ts for strict typing */
@@ -679,10 +683,22 @@ interface CloudClientConfig {
679
683
  maxRetries?: number;
680
684
  /** Enable telemetry reporting */
681
685
  enableTelemetry?: boolean;
686
+ /** Enable client usage analytics endpoints */
687
+ enableUsageAnalytics?: boolean;
682
688
  /** API key if required */
683
689
  apiKey?: string;
684
690
  /** Language for API responses */
685
691
  language?: string;
692
+ /** Stable device token for analytics/auth headers */
693
+ deviceToken?: string;
694
+ /** Stable device ID for usage analytics dedupe */
695
+ deviceId?: string;
696
+ /** Stable anonymous installation/user ID */
697
+ anonymousUserId?: string;
698
+ /** Override analytics platform label */
699
+ platform?: string;
700
+ /** Automatically send startup handshake on initialization */
701
+ autoHandshake?: boolean;
686
702
  }
687
703
  /**
688
704
  * Cache entry metadata
@@ -723,6 +739,43 @@ interface TelemetryConfig {
723
739
  /** Anonymous user ID */
724
740
  userId?: string;
725
741
  }
742
+ interface ClientIdentity {
743
+ deviceId: string;
744
+ anonymousUserId: string;
745
+ clientVersion: string;
746
+ platform: string;
747
+ deviceToken?: string;
748
+ }
749
+ interface DeviceRegistrationRequest {
750
+ deviceId: string;
751
+ platform: string;
752
+ clientVersion: string;
753
+ }
754
+ interface DeviceRegistrationResponse {
755
+ success: boolean;
756
+ requestId?: string;
757
+ message?: string;
758
+ }
759
+ interface HandshakeRequest {
760
+ deviceId: string;
761
+ platform: string;
762
+ clientVersion: string;
763
+ }
764
+ interface HandshakeResponse {
765
+ success: boolean;
766
+ requestId?: string;
767
+ message?: string;
768
+ }
769
+ interface SyncRequest {
770
+ deviceId: string;
771
+ platform: string;
772
+ clientVersion: string;
773
+ }
774
+ interface SyncResponse {
775
+ success: boolean;
776
+ requestId?: string;
777
+ message?: string;
778
+ }
726
779
 
727
780
  /**
728
781
  * Cloud Client Implementation
@@ -739,7 +792,14 @@ interface TelemetryConfig {
739
792
  declare class CloudClient {
740
793
  private fetch;
741
794
  private config;
795
+ private identity;
742
796
  constructor(config: CloudClientConfig);
797
+ private getDefaultHeaders;
798
+ private resolveIdentity;
799
+ private loadOrCreateStoredIdentity;
800
+ private buildAnalyticsPayload;
801
+ private canSendUsageAnalytics;
802
+ getIdentity(): ClientIdentity;
743
803
  /**
744
804
  * Calculate retry delay with exponential backoff
745
805
  */
@@ -812,6 +872,9 @@ declare class CloudClient {
812
872
  * Get current configuration
813
873
  */
814
874
  getConfig(): CloudClientConfig;
875
+ registerDevice(payload?: Partial<DeviceRegistrationRequest>): Promise<DeviceRegistrationResponse>;
876
+ handshake(payload?: Partial<HandshakeRequest>): Promise<HandshakeResponse>;
877
+ syncClientUsage(payload?: Partial<SyncRequest>): Promise<SyncResponse>;
815
878
  }
816
879
  /**
817
880
  * Create a default cloud client instance
@@ -2595,6 +2658,9 @@ declare class FallbackCloudClient {
2595
2658
  * Report usage (no fallback)
2596
2659
  */
2597
2660
  reportUsage(report: UsageReport): Promise<UsageReportResponse>;
2661
+ registerDevice(payload?: Partial<DeviceRegistrationRequest>): Promise<DeviceRegistrationResponse>;
2662
+ handshake(payload?: Partial<HandshakeRequest>): Promise<HandshakeResponse>;
2663
+ syncClientUsage(payload?: Partial<SyncRequest>): Promise<SyncResponse>;
2598
2664
  /**
2599
2665
  * Health check (no fallback)
2600
2666
  */
package/dist/index.d.ts CHANGED
@@ -579,7 +579,7 @@ interface BatchTemplateResponse$1 {
579
579
  /**
580
580
  * Usage metric type
581
581
  */
582
- type MetricType = 'template_download' | 'recommendation_shown' | 'recommendation_accepted' | 'analysis_completed' | 'error_occurred';
582
+ type MetricType = 'template_download' | 'recommendation_shown' | 'recommendation_accepted' | 'analysis_completed' | 'error_occurred' | 'command_run' | (string & {});
583
583
  /**
584
584
  * Usage report payload
585
585
  */
@@ -596,6 +596,10 @@ interface UsageReport {
596
596
  nodeVersion: string;
597
597
  /** Operating system */
598
598
  platform: string;
599
+ /** Stable device identifier */
600
+ deviceId?: string;
601
+ /** Client version reported to analytics endpoints */
602
+ clientVersion?: string;
599
603
  /** Project language if applicable */
600
604
  language?: string;
601
605
  /** Additional context data - use TelemetryEventData from dto.ts for strict typing */
@@ -679,10 +683,22 @@ interface CloudClientConfig {
679
683
  maxRetries?: number;
680
684
  /** Enable telemetry reporting */
681
685
  enableTelemetry?: boolean;
686
+ /** Enable client usage analytics endpoints */
687
+ enableUsageAnalytics?: boolean;
682
688
  /** API key if required */
683
689
  apiKey?: string;
684
690
  /** Language for API responses */
685
691
  language?: string;
692
+ /** Stable device token for analytics/auth headers */
693
+ deviceToken?: string;
694
+ /** Stable device ID for usage analytics dedupe */
695
+ deviceId?: string;
696
+ /** Stable anonymous installation/user ID */
697
+ anonymousUserId?: string;
698
+ /** Override analytics platform label */
699
+ platform?: string;
700
+ /** Automatically send startup handshake on initialization */
701
+ autoHandshake?: boolean;
686
702
  }
687
703
  /**
688
704
  * Cache entry metadata
@@ -723,6 +739,43 @@ interface TelemetryConfig {
723
739
  /** Anonymous user ID */
724
740
  userId?: string;
725
741
  }
742
+ interface ClientIdentity {
743
+ deviceId: string;
744
+ anonymousUserId: string;
745
+ clientVersion: string;
746
+ platform: string;
747
+ deviceToken?: string;
748
+ }
749
+ interface DeviceRegistrationRequest {
750
+ deviceId: string;
751
+ platform: string;
752
+ clientVersion: string;
753
+ }
754
+ interface DeviceRegistrationResponse {
755
+ success: boolean;
756
+ requestId?: string;
757
+ message?: string;
758
+ }
759
+ interface HandshakeRequest {
760
+ deviceId: string;
761
+ platform: string;
762
+ clientVersion: string;
763
+ }
764
+ interface HandshakeResponse {
765
+ success: boolean;
766
+ requestId?: string;
767
+ message?: string;
768
+ }
769
+ interface SyncRequest {
770
+ deviceId: string;
771
+ platform: string;
772
+ clientVersion: string;
773
+ }
774
+ interface SyncResponse {
775
+ success: boolean;
776
+ requestId?: string;
777
+ message?: string;
778
+ }
726
779
 
727
780
  /**
728
781
  * Cloud Client Implementation
@@ -739,7 +792,14 @@ interface TelemetryConfig {
739
792
  declare class CloudClient {
740
793
  private fetch;
741
794
  private config;
795
+ private identity;
742
796
  constructor(config: CloudClientConfig);
797
+ private getDefaultHeaders;
798
+ private resolveIdentity;
799
+ private loadOrCreateStoredIdentity;
800
+ private buildAnalyticsPayload;
801
+ private canSendUsageAnalytics;
802
+ getIdentity(): ClientIdentity;
743
803
  /**
744
804
  * Calculate retry delay with exponential backoff
745
805
  */
@@ -812,6 +872,9 @@ declare class CloudClient {
812
872
  * Get current configuration
813
873
  */
814
874
  getConfig(): CloudClientConfig;
875
+ registerDevice(payload?: Partial<DeviceRegistrationRequest>): Promise<DeviceRegistrationResponse>;
876
+ handshake(payload?: Partial<HandshakeRequest>): Promise<HandshakeResponse>;
877
+ syncClientUsage(payload?: Partial<SyncRequest>): Promise<SyncResponse>;
815
878
  }
816
879
  /**
817
880
  * Create a default cloud client instance
@@ -2595,6 +2658,9 @@ declare class FallbackCloudClient {
2595
2658
  * Report usage (no fallback)
2596
2659
  */
2597
2660
  reportUsage(report: UsageReport): Promise<UsageReportResponse>;
2661
+ registerDevice(payload?: Partial<DeviceRegistrationRequest>): Promise<DeviceRegistrationResponse>;
2662
+ handshake(payload?: Partial<HandshakeRequest>): Promise<HandshakeResponse>;
2663
+ syncClientUsage(payload?: Partial<SyncRequest>): Promise<SyncResponse>;
2598
2664
  /**
2599
2665
  * Health check (no fallback)
2600
2666
  */
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  export { P as ProjectAnalyzer, T as TemplatesClient, d as analyzeDependencies, a as analyzeProject, h as batchAnalyze, b as createTemplatesClient, e as detectProject, f as detectProjectType, g as getTemplatesClient } from './shared/ccjk.DypYla6I.mjs';
2
- import { a as createCloudClient } from './shared/ccjk.BNVSnyu0.mjs';
3
- export { C as CachedCloudClient, b as CloudCache, d as CloudClient, F as FallbackCloudClient, R as RetryableCloudClient, T as TelemetryReporter, c as createCompleteCloudClient, g as getTelemetry, i as initializeTelemetry, r as retryUtils, s as stopTelemetry, t as telemetryUtils, e as trackEvent, w as withRetry } from './shared/ccjk.BNVSnyu0.mjs';
2
+ import { a as createCloudClient } from './shared/ccjk.C3YuTovw.mjs';
3
+ export { C as CachedCloudClient, b as CloudCache, d as CloudClient, F as FallbackCloudClient, R as RetryableCloudClient, T as TelemetryReporter, c as createCompleteCloudClient, g as getTelemetry, i as initializeTelemetry, r as retryUtils, s as stopTelemetry, t as telemetryUtils, e as trackEvent, w as withRetry } from './shared/ccjk.C3YuTovw.mjs';
4
4
  import { CLOUD_ENDPOINTS } from './chunks/constants.mjs';
5
5
  export { C as CloudError, a as CloudErrorCode, b as CloudErrorFactory, f as formatErrorForLogging, g as getRetryDelay, h as handleCloudError, i as isAuthError, c as isRateLimitError, d as isRetryableError, e as isRetryableErrorCode } from './shared/ccjk.D8ZLYSZZ.mjs';
6
6
  import { e as extractString } from './shared/ccjk.C2jHOZVP.mjs';
@@ -270,15 +270,8 @@ function validateUsageReport(report) {
270
270
  const errors = [];
271
271
  if (!report.reportId || typeof report.reportId !== "string")
272
272
  errors.push("reportId is required and must be a string");
273
- const validMetricTypes = [
274
- "template_download",
275
- "recommendation_shown",
276
- "recommendation_accepted",
277
- "analysis_completed",
278
- "error_occurred"
279
- ];
280
- if (!validMetricTypes.includes(report.metricType))
281
- errors.push(`metricType must be one of: ${validMetricTypes.join(", ")}`);
273
+ if (!report.metricType || typeof report.metricType !== "string")
274
+ errors.push("metricType is required and must be a string");
282
275
  if (!report.timestamp || typeof report.timestamp !== "string")
283
276
  errors.push("timestamp is required and must be a string");
284
277
  if (!report.ccjkVersion || typeof report.ccjkVersion !== "string")
@@ -287,6 +280,10 @@ function validateUsageReport(report) {
287
280
  errors.push("nodeVersion is required and must be a string");
288
281
  if (!report.platform || typeof report.platform !== "string")
289
282
  errors.push("platform is required and must be a string");
283
+ if (report.deviceId !== void 0 && typeof report.deviceId !== "string")
284
+ errors.push("deviceId must be a string when provided");
285
+ if (report.clientVersion !== void 0 && typeof report.clientVersion !== "string")
286
+ errors.push("clientVersion must be a string when provided");
290
287
  return {
291
288
  valid: errors.length === 0,
292
289
  errors
@@ -1,9 +1,10 @@
1
1
  import { c as consola, o as ofetch } from './ccjk.DypYla6I.mjs';
2
- import fs__default, { readFileSync } from 'node:fs';
3
- import path__default, { dirname, join } from 'node:path';
2
+ import fs__default, { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
3
+ import path__default, { join, dirname } from 'node:path';
4
+ import { homedir } from 'node:os';
4
5
  import { fileURLToPath } from 'node:url';
5
- import { CLOUD_ENDPOINTS } from '../chunks/constants.mjs';
6
6
  import { randomUUID } from 'node:crypto';
7
+ import { CLOUD_ENDPOINTS } from '../chunks/constants.mjs';
7
8
 
8
9
  const defaults = Object.freeze({
9
10
  ignoreUnknown: false,
@@ -926,28 +927,96 @@ try {
926
927
  }
927
928
  const API_PREFIX = "/api/v1";
928
929
  const HEALTH_PATH = `${API_PREFIX}/health`;
930
+ const CLIENT_USAGE_STATE_DIR = join(homedir(), ".ccjk");
931
+ const CLIENT_USAGE_STATE_FILE = join(CLIENT_USAGE_STATE_DIR, "cloud-client-identity.json");
929
932
  class CloudClient {
930
933
  fetch;
931
934
  config;
935
+ identity;
932
936
  constructor(config) {
933
937
  this.config = {
934
938
  timeout: 1e4,
935
939
  enableRetry: true,
936
940
  maxRetries: 3,
937
941
  enableTelemetry: true,
942
+ enableUsageAnalytics: true,
943
+ autoHandshake: true,
938
944
  ...config
939
945
  };
946
+ this.identity = this.resolveIdentity();
940
947
  this.fetch = ofetch.create({
941
948
  baseURL: this.config.baseURL,
942
949
  timeout: this.config.timeout,
943
- headers: {
944
- "User-Agent": `CCJK/${this.config.version || CCJK_VERSION}`,
945
- ...this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }
946
- },
950
+ headers: this.getDefaultHeaders(),
947
951
  retry: this.config.enableRetry ? this.config.maxRetries : 0,
948
952
  retryDelay: (context) => this.calculateRetryDelay(context.options.retry || 0)
949
953
  });
950
954
  }
955
+ getDefaultHeaders() {
956
+ const headers = {
957
+ "User-Agent": `CCJK/${this.identity.clientVersion}`,
958
+ "X-CCJK-Version": this.identity.clientVersion,
959
+ "X-Anonymous-User-Id": this.identity.anonymousUserId
960
+ };
961
+ if (this.config.apiKey) {
962
+ headers.Authorization = `Bearer ${this.config.apiKey}`;
963
+ }
964
+ if (this.identity.deviceToken) {
965
+ headers["X-Device-Token"] = this.identity.deviceToken;
966
+ }
967
+ return headers;
968
+ }
969
+ resolveIdentity() {
970
+ const storedIdentity = this.loadOrCreateStoredIdentity();
971
+ const clientVersion = this.config.version || CCJK_VERSION;
972
+ return {
973
+ anonymousUserId: this.config.anonymousUserId || storedIdentity.anonymousUserId,
974
+ deviceId: this.config.deviceId || storedIdentity.deviceId,
975
+ clientVersion,
976
+ platform: this.config.platform || process.platform,
977
+ deviceToken: this.config.deviceToken
978
+ };
979
+ }
980
+ loadOrCreateStoredIdentity() {
981
+ try {
982
+ if (existsSync(CLIENT_USAGE_STATE_FILE)) {
983
+ const stored = JSON.parse(readFileSync(CLIENT_USAGE_STATE_FILE, "utf-8"));
984
+ if (stored.anonymousUserId && stored.deviceId) {
985
+ return {
986
+ anonymousUserId: stored.anonymousUserId,
987
+ deviceId: stored.deviceId
988
+ };
989
+ }
990
+ }
991
+ } catch (error) {
992
+ consola.debug("Failed to read stored cloud client identity:", error);
993
+ }
994
+ const generated = {
995
+ anonymousUserId: process.env.CCJK_ANONYMOUS_USER_ID || randomUUID(),
996
+ deviceId: process.env.CCJK_DEVICE_ID || randomUUID()
997
+ };
998
+ try {
999
+ mkdirSync(CLIENT_USAGE_STATE_DIR, { recursive: true });
1000
+ writeFileSync(CLIENT_USAGE_STATE_FILE, JSON.stringify(generated, null, 2));
1001
+ } catch (error) {
1002
+ consola.debug("Failed to persist cloud client identity:", error);
1003
+ }
1004
+ return generated;
1005
+ }
1006
+ buildAnalyticsPayload(payload) {
1007
+ return {
1008
+ deviceId: payload?.deviceId || this.identity.deviceId,
1009
+ platform: payload?.platform || this.identity.platform,
1010
+ clientVersion: payload?.clientVersion || this.identity.clientVersion,
1011
+ ...payload
1012
+ };
1013
+ }
1014
+ canSendUsageAnalytics() {
1015
+ return this.config.enableUsageAnalytics !== false;
1016
+ }
1017
+ getIdentity() {
1018
+ return { ...this.identity };
1019
+ }
951
1020
  /**
952
1021
  * Calculate retry delay with exponential backoff
953
1022
  */
@@ -1102,11 +1171,24 @@ class CloudClient {
1102
1171
  * @returns Usage report response
1103
1172
  */
1104
1173
  async reportUsage(report) {
1174
+ if (!this.canSendUsageAnalytics()) {
1175
+ return {
1176
+ success: false,
1177
+ requestId: "",
1178
+ message: "Usage analytics disabled"
1179
+ };
1180
+ }
1105
1181
  try {
1106
1182
  consola.debug("Reporting usage:", report.metricType);
1183
+ const payload = {
1184
+ ...report,
1185
+ deviceId: report.deviceId || this.identity.deviceId,
1186
+ platform: report.platform || this.identity.platform,
1187
+ clientVersion: report.clientVersion || report.ccjkVersion || this.identity.clientVersion
1188
+ };
1107
1189
  const response = await this.fetch(`${API_PREFIX}/usage/current`, {
1108
1190
  method: "POST",
1109
- body: report,
1191
+ body: payload,
1110
1192
  timeout: 5e3
1111
1193
  // 5s timeout - telemetry should be fast
1112
1194
  });
@@ -1147,14 +1229,12 @@ class CloudClient {
1147
1229
  */
1148
1230
  updateConfig(config) {
1149
1231
  this.config = { ...this.config, ...config };
1150
- if (config.baseURL || config.timeout || config.apiKey) {
1232
+ this.identity = this.resolveIdentity();
1233
+ if (config.baseURL || config.timeout || config.apiKey || config.version || config.deviceToken || config.anonymousUserId || config.deviceId || config.platform) {
1151
1234
  this.fetch = ofetch.create({
1152
1235
  baseURL: this.config.baseURL,
1153
1236
  timeout: this.config.timeout,
1154
- headers: {
1155
- "User-Agent": `CCJK/${this.config.version || CCJK_VERSION}`,
1156
- ...this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }
1157
- },
1237
+ headers: this.getDefaultHeaders(),
1158
1238
  retry: this.config.enableRetry ? this.config.maxRetries : 0,
1159
1239
  retryDelay: (context) => this.calculateRetryDelay(context.options.retry || 0)
1160
1240
  });
@@ -1166,6 +1246,72 @@ class CloudClient {
1166
1246
  getConfig() {
1167
1247
  return { ...this.config };
1168
1248
  }
1249
+ async registerDevice(payload) {
1250
+ if (!this.canSendUsageAnalytics()) {
1251
+ return {
1252
+ success: false,
1253
+ message: "Usage analytics disabled"
1254
+ };
1255
+ }
1256
+ try {
1257
+ return await this.fetch("/device/register", {
1258
+ method: "POST",
1259
+ body: this.buildAnalyticsPayload(payload),
1260
+ timeout: 5e3
1261
+ });
1262
+ } catch (error) {
1263
+ consola.debug("Failed to register device (non-blocking):", error);
1264
+ return {
1265
+ success: false,
1266
+ requestId: "",
1267
+ message: error instanceof Error ? error.message : "Unknown error"
1268
+ };
1269
+ }
1270
+ }
1271
+ async handshake(payload) {
1272
+ if (!this.canSendUsageAnalytics()) {
1273
+ return {
1274
+ success: false,
1275
+ message: "Usage analytics disabled"
1276
+ };
1277
+ }
1278
+ try {
1279
+ return await this.fetch(`${API_PREFIX}/handshake`, {
1280
+ method: "POST",
1281
+ body: this.buildAnalyticsPayload(payload),
1282
+ timeout: 5e3
1283
+ });
1284
+ } catch (error) {
1285
+ consola.debug("Failed to send handshake (non-blocking):", error);
1286
+ return {
1287
+ success: false,
1288
+ requestId: "",
1289
+ message: error instanceof Error ? error.message : "Unknown error"
1290
+ };
1291
+ }
1292
+ }
1293
+ async syncClientUsage(payload) {
1294
+ if (!this.canSendUsageAnalytics()) {
1295
+ return {
1296
+ success: false,
1297
+ message: "Usage analytics disabled"
1298
+ };
1299
+ }
1300
+ try {
1301
+ return await this.fetch(`${API_PREFIX}/sync`, {
1302
+ method: "POST",
1303
+ body: this.buildAnalyticsPayload(payload),
1304
+ timeout: 5e3
1305
+ });
1306
+ } catch (error) {
1307
+ consola.debug("Failed to sync client usage (non-blocking):", error);
1308
+ return {
1309
+ success: false,
1310
+ requestId: "",
1311
+ message: error instanceof Error ? error.message : "Unknown error"
1312
+ };
1313
+ }
1314
+ }
1169
1315
  }
1170
1316
  function createCloudClient(config) {
1171
1317
  return new CloudClient({
@@ -1337,7 +1483,7 @@ class TelemetryReporter {
1337
1483
  constructor(client, config = {}) {
1338
1484
  this.client = client;
1339
1485
  this.config = { ...DEFAULT_TELEMETRY_CONFIG, ...config };
1340
- this.userId = this.config.userId || this.generateUserId();
1486
+ this.userId = this.config.userId || this.client.getIdentity().anonymousUserId || this.generateUserId();
1341
1487
  if (this.config.enabled) {
1342
1488
  this.startFlushTimer();
1343
1489
  }
@@ -1578,6 +1724,11 @@ function initializeTelemetry(client, config) {
1578
1724
  });
1579
1725
  }
1580
1726
  globalTelemetry = new TelemetryReporter(client, config);
1727
+ if (client.getConfig().autoHandshake !== false && client.getConfig().enableUsageAnalytics !== false) {
1728
+ client.handshake().catch((error) => {
1729
+ consola.debug("Failed to send startup handshake (non-blocking):", error);
1730
+ });
1731
+ }
1581
1732
  return globalTelemetry;
1582
1733
  }
1583
1734
  function getTelemetry() {
@@ -1680,6 +1831,15 @@ class FallbackCloudClient {
1680
1831
  async reportUsage(report) {
1681
1832
  return this.client.reportUsage(report);
1682
1833
  }
1834
+ async registerDevice(payload) {
1835
+ return this.client.registerDevice(payload);
1836
+ }
1837
+ async handshake(payload) {
1838
+ return this.client.handshake(payload);
1839
+ }
1840
+ async syncClientUsage(payload) {
1841
+ return this.client.syncClientUsage(payload);
1842
+ }
1683
1843
  /**
1684
1844
  * Health check (no fallback)
1685
1845
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ccjk",
3
3
  "type": "module",
4
- "version": "13.4.0",
4
+ "version": "13.5.0",
5
5
  "packageManager": "pnpm@10.17.1",
6
6
  "description": "Turn Claude Code into a production-ready AI dev environment with one-command setup, persistent memory, MCP automation, cloud sync, and zero-config browser workflows.",
7
7
  "author": {