ccjk 2.3.1 → 2.3.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.
@@ -0,0 +1,358 @@
1
+ import { randomUUID, createHash } from 'node:crypto';
2
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
3
+ import { release, platform, type, homedir, hostname } from 'node:os';
4
+ import { join } from 'pathe';
5
+ import { CCJK_CONFIG_DIR } from './constants.mjs';
6
+ import './index2.mjs';
7
+ import 'node:process';
8
+ import 'node:url';
9
+ import 'i18next';
10
+ import 'i18next-fs-backend';
11
+
12
+ const CLOUD_CONFIG_DIR = join(CCJK_CONFIG_DIR, "cloud");
13
+ const DEVICE_CONFIG_FILE = join(CLOUD_CONFIG_DIR, "device.json");
14
+ const CLOUD_STATE_FILE = join(CLOUD_CONFIG_DIR, "state.json");
15
+ const CLOUD_API_ENDPOINT = "https://api.ccjk.dev/v1";
16
+ const AUTO_SYNC_INTERVAL = 30 * 60 * 1e3;
17
+ const AUTO_UPGRADE_CHECK_INTERVAL = 6 * 60 * 60 * 1e3;
18
+ function generateDeviceFingerprint() {
19
+ const data = [
20
+ platform(),
21
+ type(),
22
+ homedir().split("/").length.toString(),
23
+ // 只用路径深度,不用实际路径
24
+ hostname().length.toString()
25
+ // 只用主机名长度,不用实际名称
26
+ ].join("|");
27
+ return createHash("sha256").update(data).digest("hex").substring(0, 32);
28
+ }
29
+ function getOrCreateDeviceInfo() {
30
+ ensureCloudConfigDir();
31
+ if (existsSync(DEVICE_CONFIG_FILE)) {
32
+ try {
33
+ const data = readFileSync(DEVICE_CONFIG_FILE, "utf-8");
34
+ const device2 = JSON.parse(data);
35
+ device2.lastActiveAt = (/* @__PURE__ */ new Date()).toISOString();
36
+ writeFileSync(DEVICE_CONFIG_FILE, JSON.stringify(device2, null, 2));
37
+ return device2;
38
+ } catch {
39
+ }
40
+ }
41
+ const device = {
42
+ deviceId: randomUUID(),
43
+ fingerprint: generateDeviceFingerprint(),
44
+ registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
45
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
46
+ osType: platform(),
47
+ osVersion: release(),
48
+ ccjkVersion: getCcjkVersion()
49
+ };
50
+ writeFileSync(DEVICE_CONFIG_FILE, JSON.stringify(device, null, 2));
51
+ return device;
52
+ }
53
+ function getCcjkVersion() {
54
+ try {
55
+ const packagePath = join(__dirname, "../../../package.json");
56
+ if (existsSync(packagePath)) {
57
+ const pkg = JSON.parse(readFileSync(packagePath, "utf-8"));
58
+ return pkg.version || "unknown";
59
+ }
60
+ } catch {
61
+ }
62
+ return "unknown";
63
+ }
64
+ function ensureCloudConfigDir() {
65
+ if (!existsSync(CLOUD_CONFIG_DIR)) {
66
+ mkdirSync(CLOUD_CONFIG_DIR, { recursive: true });
67
+ }
68
+ }
69
+ function getCloudState() {
70
+ ensureCloudConfigDir();
71
+ if (existsSync(CLOUD_STATE_FILE)) {
72
+ try {
73
+ const data = readFileSync(CLOUD_STATE_FILE, "utf-8");
74
+ return JSON.parse(data);
75
+ } catch {
76
+ }
77
+ }
78
+ return {
79
+ initialized: false,
80
+ autoSyncEnabled: true,
81
+ silentUpgradeEnabled: true,
82
+ lastSyncAt: null,
83
+ lastUpgradeCheckAt: null,
84
+ lastUpgradedAt: null,
85
+ syncStats: {
86
+ totalSyncs: 0,
87
+ successfulSyncs: 0,
88
+ failedSyncs: 0
89
+ },
90
+ upgradeStats: {
91
+ totalChecks: 0,
92
+ upgradesApplied: 0,
93
+ upgradesFailed: 0
94
+ }
95
+ };
96
+ }
97
+ function saveCloudState(state) {
98
+ ensureCloudConfigDir();
99
+ writeFileSync(CLOUD_STATE_FILE, JSON.stringify(state, null, 2));
100
+ }
101
+ function updateCloudState(updates) {
102
+ const state = getCloudState();
103
+ const newState = { ...state, ...updates };
104
+ saveCloudState(newState);
105
+ return newState;
106
+ }
107
+ async function autoBootstrap() {
108
+ try {
109
+ const state = getCloudState();
110
+ if (!state.initialized) {
111
+ await initializeCloudServices();
112
+ }
113
+ await performHandshake();
114
+ if (state.silentUpgradeEnabled) {
115
+ await checkAndPerformSilentUpgrade();
116
+ }
117
+ if (state.autoSyncEnabled) {
118
+ await performAutoSync();
119
+ }
120
+ } catch {
121
+ }
122
+ }
123
+ async function initializeCloudServices() {
124
+ const device = getOrCreateDeviceInfo();
125
+ updateCloudState({
126
+ initialized: true,
127
+ autoSyncEnabled: true,
128
+ silentUpgradeEnabled: true
129
+ });
130
+ try {
131
+ await registerDevice(device);
132
+ } catch {
133
+ }
134
+ }
135
+ async function registerDevice(device) {
136
+ const controller = new AbortController();
137
+ const timeoutId = setTimeout(() => controller.abort(), 5e3);
138
+ try {
139
+ await fetch(`${CLOUD_API_ENDPOINT}/devices/register`, {
140
+ method: "POST",
141
+ headers: {
142
+ "Content-Type": "application/json",
143
+ "User-Agent": `CCJK/${device.ccjkVersion}`
144
+ },
145
+ body: JSON.stringify({
146
+ deviceId: device.deviceId,
147
+ fingerprint: device.fingerprint,
148
+ osType: device.osType,
149
+ osVersion: device.osVersion,
150
+ ccjkVersion: device.ccjkVersion
151
+ }),
152
+ signal: controller.signal
153
+ });
154
+ } finally {
155
+ clearTimeout(timeoutId);
156
+ }
157
+ }
158
+ async function performHandshake() {
159
+ const device = getOrCreateDeviceInfo();
160
+ const controller = new AbortController();
161
+ const timeoutId = setTimeout(() => controller.abort(), 5e3);
162
+ try {
163
+ const response = await fetch(`${CLOUD_API_ENDPOINT}/handshake`, {
164
+ method: "POST",
165
+ headers: {
166
+ "Content-Type": "application/json",
167
+ "User-Agent": `CCJK/${device.ccjkVersion}`,
168
+ "X-Device-ID": device.deviceId
169
+ },
170
+ body: JSON.stringify({
171
+ deviceId: device.deviceId,
172
+ ccjkVersion: device.ccjkVersion
173
+ }),
174
+ signal: controller.signal
175
+ });
176
+ if (response.ok) {
177
+ return await response.json();
178
+ }
179
+ } catch {
180
+ } finally {
181
+ clearTimeout(timeoutId);
182
+ }
183
+ return null;
184
+ }
185
+ async function checkAndPerformSilentUpgrade() {
186
+ const state = getCloudState();
187
+ const now = Date.now();
188
+ if (state.lastUpgradeCheckAt) {
189
+ const lastCheck = new Date(state.lastUpgradeCheckAt).getTime();
190
+ if (now - lastCheck < AUTO_UPGRADE_CHECK_INTERVAL) {
191
+ return { success: true, upgraded: false };
192
+ }
193
+ }
194
+ updateCloudState({
195
+ lastUpgradeCheckAt: (/* @__PURE__ */ new Date()).toISOString(),
196
+ upgradeStats: {
197
+ ...state.upgradeStats,
198
+ totalChecks: state.upgradeStats.totalChecks + 1
199
+ }
200
+ });
201
+ try {
202
+ const updateInfo = await checkForUpdates();
203
+ if (updateInfo.hasUpdate) {
204
+ const result = await performSilentUpgrade(updateInfo.latestVersion);
205
+ if (result.success && result.upgraded) {
206
+ updateCloudState({
207
+ lastUpgradedAt: (/* @__PURE__ */ new Date()).toISOString(),
208
+ upgradeStats: {
209
+ ...getCloudState().upgradeStats,
210
+ upgradesApplied: getCloudState().upgradeStats.upgradesApplied + 1
211
+ }
212
+ });
213
+ }
214
+ return result;
215
+ }
216
+ return { success: true, upgraded: false };
217
+ } catch (error) {
218
+ updateCloudState({
219
+ upgradeStats: {
220
+ ...getCloudState().upgradeStats,
221
+ upgradesFailed: getCloudState().upgradeStats.upgradesFailed + 1
222
+ }
223
+ });
224
+ return {
225
+ success: false,
226
+ upgraded: false,
227
+ error: error instanceof Error ? error.message : "Unknown error"
228
+ };
229
+ }
230
+ }
231
+ async function checkForUpdates() {
232
+ const currentVersion = getCcjkVersion();
233
+ const controller = new AbortController();
234
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
235
+ try {
236
+ const response = await fetch("https://registry.npmjs.org/ccjk/latest", {
237
+ signal: controller.signal
238
+ });
239
+ if (response.ok) {
240
+ const data = await response.json();
241
+ const latestVersion = data.version;
242
+ return {
243
+ hasUpdate: isNewerVersion(latestVersion, currentVersion),
244
+ latestVersion,
245
+ currentVersion
246
+ };
247
+ }
248
+ } catch {
249
+ } finally {
250
+ clearTimeout(timeoutId);
251
+ }
252
+ return { hasUpdate: false, latestVersion: currentVersion, currentVersion };
253
+ }
254
+ function isNewerVersion(latest, current) {
255
+ const latestParts = latest.split(".").map(Number);
256
+ const currentParts = current.split(".").map(Number);
257
+ for (let i = 0; i < 3; i++) {
258
+ const l = latestParts[i] || 0;
259
+ const c = currentParts[i] || 0;
260
+ if (l > c)
261
+ return true;
262
+ if (l < c)
263
+ return false;
264
+ }
265
+ return false;
266
+ }
267
+ async function performSilentUpgrade(targetVersion) {
268
+ const currentVersion = getCcjkVersion();
269
+ try {
270
+ const { exec } = await import('tinyexec');
271
+ const result = await exec("npm", ["update", "-g", "ccjk"], {
272
+ timeout: 6e4
273
+ // 60 秒超时
274
+ });
275
+ if (result.exitCode === 0) {
276
+ return {
277
+ success: true,
278
+ upgraded: true,
279
+ fromVersion: currentVersion,
280
+ toVersion: targetVersion
281
+ };
282
+ }
283
+ return {
284
+ success: false,
285
+ upgraded: false,
286
+ error: result.stderr || "Upgrade failed"
287
+ };
288
+ } catch (error) {
289
+ return {
290
+ success: false,
291
+ upgraded: false,
292
+ error: error instanceof Error ? error.message : "Unknown error"
293
+ };
294
+ }
295
+ }
296
+ async function performAutoSync() {
297
+ const state = getCloudState();
298
+ const now = Date.now();
299
+ if (state.lastSyncAt) {
300
+ const lastSync = new Date(state.lastSyncAt).getTime();
301
+ if (now - lastSync < AUTO_SYNC_INTERVAL) {
302
+ return;
303
+ }
304
+ }
305
+ try {
306
+ await syncToCloud();
307
+ updateCloudState({
308
+ lastSyncAt: (/* @__PURE__ */ new Date()).toISOString(),
309
+ syncStats: {
310
+ ...state.syncStats,
311
+ totalSyncs: state.syncStats.totalSyncs + 1,
312
+ successfulSyncs: state.syncStats.successfulSyncs + 1
313
+ }
314
+ });
315
+ } catch {
316
+ updateCloudState({
317
+ syncStats: {
318
+ ...state.syncStats,
319
+ totalSyncs: state.syncStats.totalSyncs + 1,
320
+ failedSyncs: state.syncStats.failedSyncs + 1
321
+ }
322
+ });
323
+ }
324
+ }
325
+ async function syncToCloud() {
326
+ const device = getOrCreateDeviceInfo();
327
+ const controller = new AbortController();
328
+ const timeoutId = setTimeout(() => controller.abort(), 3e4);
329
+ try {
330
+ const syncData = await collectSyncData();
331
+ await fetch(`${CLOUD_API_ENDPOINT}/sync`, {
332
+ method: "POST",
333
+ headers: {
334
+ "Content-Type": "application/json",
335
+ "User-Agent": `CCJK/${device.ccjkVersion}`,
336
+ "X-Device-ID": device.deviceId
337
+ },
338
+ body: JSON.stringify(syncData),
339
+ signal: controller.signal
340
+ });
341
+ } finally {
342
+ clearTimeout(timeoutId);
343
+ }
344
+ }
345
+ async function collectSyncData() {
346
+ const device = getOrCreateDeviceInfo();
347
+ return {
348
+ deviceId: device.deviceId,
349
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
350
+ // 只同步匿名化的使用统计
351
+ stats: {
352
+ osType: device.osType,
353
+ ccjkVersion: device.ccjkVersion
354
+ }
355
+ };
356
+ }
357
+
358
+ export { AUTO_SYNC_INTERVAL, AUTO_UPGRADE_CHECK_INTERVAL, CLOUD_API_ENDPOINT, CLOUD_CONFIG_DIR, CLOUD_STATE_FILE, DEVICE_CONFIG_FILE, autoBootstrap, autoBootstrap as bootstrap, checkAndPerformSilentUpgrade as checkUpgrade, getCloudState, getOrCreateDeviceInfo, saveCloudState, performAutoSync as sync, updateCloudState };
@@ -1,4 +1,4 @@
1
- const version = "2.3.1";
1
+ const version = "2.3.2";
2
2
  const homepage = "https://github.com/miounet11/ccjk";
3
3
 
4
4
  export { homepage, version };
@@ -0,0 +1,396 @@
1
+ import { existsSync, readFileSync, writeFileSync, appendFileSync, unlinkSync, mkdirSync } from 'node:fs';
2
+ import { platform } from 'node:os';
3
+ import process__default from 'node:process';
4
+ import { join } from 'pathe';
5
+ import { CCJK_CONFIG_DIR } from './constants.mjs';
6
+ import { getCloudState, updateCloudState } from './auto-bootstrap.mjs';
7
+ import './index2.mjs';
8
+ import 'node:url';
9
+ import 'i18next';
10
+ import 'i18next-fs-backend';
11
+ import 'node:crypto';
12
+
13
+ const UPGRADE_LOG_DIR = join(CCJK_CONFIG_DIR, "cloud", "logs");
14
+ const UPGRADE_LOG_FILE = join(UPGRADE_LOG_DIR, "upgrades.log");
15
+ const UPGRADE_LOCK_FILE = join(CCJK_CONFIG_DIR, "cloud", ".upgrade.lock");
16
+ const UPGRADE_CHECK_INTERVAL = 6 * 60 * 60 * 1e3;
17
+ const UPGRADE_TIMEOUT = 5 * 60 * 1e3;
18
+ async function checkAllToolVersions() {
19
+ const results = [];
20
+ const [ccjk, claudeCode, ccr] = await Promise.all([
21
+ checkCcjkVersion(),
22
+ checkClaudeCodeVersion(),
23
+ checkCcrVersion()
24
+ ]);
25
+ results.push(ccjk, claudeCode, ccr);
26
+ return results;
27
+ }
28
+ async function checkCcjkVersion() {
29
+ try {
30
+ const currentVersion = getCurrentCcjkVersion();
31
+ const latestVersion = await fetchLatestNpmVersion("ccjk");
32
+ return {
33
+ tool: "ccjk",
34
+ installed: true,
35
+ currentVersion,
36
+ latestVersion,
37
+ needsUpdate: latestVersion ? isNewerVersion(latestVersion, currentVersion) : false,
38
+ installMethod: "npm"
39
+ };
40
+ } catch {
41
+ return {
42
+ tool: "ccjk",
43
+ installed: true,
44
+ currentVersion: getCurrentCcjkVersion(),
45
+ latestVersion: null,
46
+ needsUpdate: false,
47
+ installMethod: "npm"
48
+ };
49
+ }
50
+ }
51
+ async function checkClaudeCodeVersion() {
52
+ try {
53
+ const { exec } = await import('tinyexec');
54
+ const result = await exec("claude", ["--version"], { timeout: 5e3 });
55
+ if (result.exitCode !== 0) {
56
+ return {
57
+ tool: "claude-code",
58
+ installed: false,
59
+ currentVersion: null,
60
+ latestVersion: null,
61
+ needsUpdate: false,
62
+ installMethod: "unknown"
63
+ };
64
+ }
65
+ const currentVersion = result.stdout.trim().replace(/^v/, "");
66
+ const latestVersion = await fetchLatestNpmVersion("@anthropic-ai/claude-code");
67
+ const installMethod = await detectClaudeCodeInstallMethod();
68
+ return {
69
+ tool: "claude-code",
70
+ installed: true,
71
+ currentVersion,
72
+ latestVersion,
73
+ needsUpdate: latestVersion ? isNewerVersion(latestVersion, currentVersion) : false,
74
+ installMethod
75
+ };
76
+ } catch {
77
+ return {
78
+ tool: "claude-code",
79
+ installed: false,
80
+ currentVersion: null,
81
+ latestVersion: null,
82
+ needsUpdate: false,
83
+ installMethod: "unknown"
84
+ };
85
+ }
86
+ }
87
+ async function checkCcrVersion() {
88
+ try {
89
+ const { exec } = await import('tinyexec');
90
+ const result = await exec("ccr", ["--version"], { timeout: 5e3 });
91
+ if (result.exitCode !== 0) {
92
+ return {
93
+ tool: "ccr",
94
+ installed: false,
95
+ currentVersion: null,
96
+ latestVersion: null,
97
+ needsUpdate: false,
98
+ installMethod: "unknown"
99
+ };
100
+ }
101
+ const currentVersion = result.stdout.trim().replace(/^v/, "");
102
+ const latestVersion = await fetchLatestNpmVersion("@musistudio/claude-code-router");
103
+ return {
104
+ tool: "ccr",
105
+ installed: true,
106
+ currentVersion,
107
+ latestVersion,
108
+ needsUpdate: latestVersion ? isNewerVersion(latestVersion, currentVersion) : false,
109
+ installMethod: "npm"
110
+ };
111
+ } catch {
112
+ return {
113
+ tool: "ccr",
114
+ installed: false,
115
+ currentVersion: null,
116
+ latestVersion: null,
117
+ needsUpdate: false,
118
+ installMethod: "unknown"
119
+ };
120
+ }
121
+ }
122
+ function getCurrentCcjkVersion() {
123
+ try {
124
+ const packagePath = join(__dirname, "../../../package.json");
125
+ if (existsSync(packagePath)) {
126
+ const pkg = JSON.parse(readFileSync(packagePath, "utf-8"));
127
+ return pkg.version || "unknown";
128
+ }
129
+ } catch {
130
+ }
131
+ return "unknown";
132
+ }
133
+ async function fetchLatestNpmVersion(packageName) {
134
+ const controller = new AbortController();
135
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
136
+ try {
137
+ const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
138
+ signal: controller.signal
139
+ });
140
+ if (response.ok) {
141
+ const data = await response.json();
142
+ return data.version;
143
+ }
144
+ } catch {
145
+ } finally {
146
+ clearTimeout(timeoutId);
147
+ }
148
+ return null;
149
+ }
150
+ async function detectClaudeCodeInstallMethod() {
151
+ try {
152
+ const { exec } = await import('tinyexec');
153
+ if (platform() === "darwin") {
154
+ const brewResult = await exec("brew", ["list", "--cask", "claude-code"], { timeout: 5e3 });
155
+ if (brewResult.exitCode === 0) {
156
+ return "homebrew";
157
+ }
158
+ }
159
+ const npmResult = await exec("npm", ["list", "-g", "@anthropic-ai/claude-code"], { timeout: 5e3 });
160
+ if (npmResult.exitCode === 0 && npmResult.stdout.includes("@anthropic-ai/claude-code")) {
161
+ return "npm";
162
+ }
163
+ return "curl";
164
+ } catch {
165
+ return "unknown";
166
+ }
167
+ }
168
+ function isNewerVersion(latest, current) {
169
+ if (!latest || !current || current === "unknown")
170
+ return false;
171
+ const latestParts = latest.split(".").map(Number);
172
+ const currentParts = current.split(".").map(Number);
173
+ for (let i = 0; i < 3; i++) {
174
+ const l = latestParts[i] || 0;
175
+ const c = currentParts[i] || 0;
176
+ if (l > c)
177
+ return true;
178
+ if (l < c)
179
+ return false;
180
+ }
181
+ return false;
182
+ }
183
+ async function performSilentUpgradeAll() {
184
+ const startTime = Date.now();
185
+ const results = [];
186
+ if (isUpgradeLocked()) {
187
+ return {
188
+ success: false,
189
+ results: [],
190
+ totalDuration: 0,
191
+ upgradedCount: 0,
192
+ failedCount: 0
193
+ };
194
+ }
195
+ try {
196
+ createUpgradeLock();
197
+ const versions = await checkAllToolVersions();
198
+ const toolsToUpgrade = versions.filter((v) => v.needsUpdate && v.installed);
199
+ for (const tool of toolsToUpgrade) {
200
+ const result = await upgradeTool(tool);
201
+ results.push(result);
202
+ logUpgrade({
203
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
204
+ tool: tool.tool,
205
+ fromVersion: tool.currentVersion || "unknown",
206
+ toVersion: tool.latestVersion || "unknown",
207
+ success: result.success,
208
+ error: result.error,
209
+ duration: result.duration
210
+ });
211
+ }
212
+ const totalDuration = Date.now() - startTime;
213
+ const upgradedCount = results.filter((r) => r.upgraded).length;
214
+ const failedCount = results.filter((r) => !r.success).length;
215
+ const state = getCloudState();
216
+ updateCloudState({
217
+ lastUpgradeCheckAt: (/* @__PURE__ */ new Date()).toISOString(),
218
+ upgradeStats: {
219
+ totalChecks: state.upgradeStats.totalChecks + 1,
220
+ upgradesApplied: state.upgradeStats.upgradesApplied + upgradedCount,
221
+ upgradesFailed: state.upgradeStats.upgradesFailed + failedCount
222
+ }
223
+ });
224
+ return {
225
+ success: failedCount === 0,
226
+ results,
227
+ totalDuration,
228
+ upgradedCount,
229
+ failedCount
230
+ };
231
+ } finally {
232
+ releaseUpgradeLock();
233
+ }
234
+ }
235
+ async function upgradeTool(info) {
236
+ const startTime = Date.now();
237
+ try {
238
+ switch (info.tool) {
239
+ case "ccjk":
240
+ return await upgradeCcjk(info, startTime);
241
+ case "claude-code":
242
+ return await upgradeClaudeCode(info, startTime);
243
+ case "ccr":
244
+ return await upgradeCcr(info, startTime);
245
+ default:
246
+ return {
247
+ tool: info.tool,
248
+ success: false,
249
+ upgraded: false,
250
+ error: "Unknown tool",
251
+ duration: Date.now() - startTime
252
+ };
253
+ }
254
+ } catch (error) {
255
+ return {
256
+ tool: info.tool,
257
+ success: false,
258
+ upgraded: false,
259
+ error: error instanceof Error ? error.message : "Unknown error",
260
+ duration: Date.now() - startTime
261
+ };
262
+ }
263
+ }
264
+ async function upgradeCcjk(info, startTime) {
265
+ const { exec } = await import('tinyexec');
266
+ const result = await exec("npm", ["update", "-g", "ccjk"], {
267
+ timeout: UPGRADE_TIMEOUT
268
+ });
269
+ return {
270
+ tool: "ccjk",
271
+ success: result.exitCode === 0,
272
+ upgraded: result.exitCode === 0,
273
+ fromVersion: info.currentVersion || void 0,
274
+ toVersion: info.latestVersion || void 0,
275
+ error: result.exitCode !== 0 ? result.stderr : void 0,
276
+ duration: Date.now() - startTime
277
+ };
278
+ }
279
+ async function upgradeClaudeCode(info, startTime) {
280
+ const { exec } = await import('tinyexec');
281
+ let result;
282
+ switch (info.installMethod) {
283
+ case "homebrew":
284
+ result = await exec("brew", ["upgrade", "--cask", "claude-code"], {
285
+ timeout: UPGRADE_TIMEOUT
286
+ });
287
+ break;
288
+ case "npm":
289
+ result = await exec("npm", ["update", "-g", "@anthropic-ai/claude-code"], {
290
+ timeout: UPGRADE_TIMEOUT
291
+ });
292
+ break;
293
+ case "curl":
294
+ default:
295
+ result = await exec("claude", ["update"], {
296
+ timeout: UPGRADE_TIMEOUT
297
+ });
298
+ break;
299
+ }
300
+ return {
301
+ tool: "claude-code",
302
+ success: result.exitCode === 0,
303
+ upgraded: result.exitCode === 0,
304
+ fromVersion: info.currentVersion || void 0,
305
+ toVersion: info.latestVersion || void 0,
306
+ error: result.exitCode !== 0 ? result.stderr : void 0,
307
+ duration: Date.now() - startTime
308
+ };
309
+ }
310
+ async function upgradeCcr(info, startTime) {
311
+ const { exec } = await import('tinyexec');
312
+ const result = await exec("npm", ["update", "-g", "@musistudio/claude-code-router"], {
313
+ timeout: UPGRADE_TIMEOUT
314
+ });
315
+ return {
316
+ tool: "ccr",
317
+ success: result.exitCode === 0,
318
+ upgraded: result.exitCode === 0,
319
+ fromVersion: info.currentVersion || void 0,
320
+ toVersion: info.latestVersion || void 0,
321
+ error: result.exitCode !== 0 ? result.stderr : void 0,
322
+ duration: Date.now() - startTime
323
+ };
324
+ }
325
+ function isUpgradeLocked() {
326
+ if (!existsSync(UPGRADE_LOCK_FILE)) {
327
+ return false;
328
+ }
329
+ try {
330
+ const lockData = JSON.parse(readFileSync(UPGRADE_LOCK_FILE, "utf-8"));
331
+ const lockTime = new Date(lockData.timestamp).getTime();
332
+ const now = Date.now();
333
+ if (now - lockTime > 10 * 60 * 1e3) {
334
+ releaseUpgradeLock();
335
+ return false;
336
+ }
337
+ return true;
338
+ } catch {
339
+ return false;
340
+ }
341
+ }
342
+ function createUpgradeLock() {
343
+ ensureLogDir();
344
+ writeFileSync(UPGRADE_LOCK_FILE, JSON.stringify({
345
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
346
+ pid: process__default.pid
347
+ }));
348
+ }
349
+ function releaseUpgradeLock() {
350
+ try {
351
+ if (existsSync(UPGRADE_LOCK_FILE)) {
352
+ unlinkSync(UPGRADE_LOCK_FILE);
353
+ }
354
+ } catch {
355
+ }
356
+ }
357
+ function ensureLogDir() {
358
+ if (!existsSync(UPGRADE_LOG_DIR)) {
359
+ mkdirSync(UPGRADE_LOG_DIR, { recursive: true });
360
+ }
361
+ }
362
+ function logUpgrade(entry) {
363
+ ensureLogDir();
364
+ const logLine = [
365
+ entry.timestamp,
366
+ entry.tool,
367
+ entry.fromVersion,
368
+ "->",
369
+ entry.toVersion,
370
+ entry.success ? "SUCCESS" : "FAILED",
371
+ entry.error || "",
372
+ `${entry.duration}ms`
373
+ ].join(" | ");
374
+ appendFileSync(UPGRADE_LOG_FILE, `${logLine}
375
+ `);
376
+ }
377
+ function shouldCheckForUpgrades() {
378
+ const state = getCloudState();
379
+ if (!state.silentUpgradeEnabled) {
380
+ return false;
381
+ }
382
+ if (!state.lastUpgradeCheckAt) {
383
+ return true;
384
+ }
385
+ const lastCheck = new Date(state.lastUpgradeCheckAt).getTime();
386
+ const now = Date.now();
387
+ return now - lastCheck >= UPGRADE_CHECK_INTERVAL;
388
+ }
389
+ async function checkAndUpgradeIfNeeded() {
390
+ if (!shouldCheckForUpgrades()) {
391
+ return null;
392
+ }
393
+ return performSilentUpgradeAll();
394
+ }
395
+
396
+ export { UPGRADE_CHECK_INTERVAL, UPGRADE_LOCK_FILE, UPGRADE_LOG_DIR, UPGRADE_LOG_FILE, UPGRADE_TIMEOUT, checkAndUpgradeIfNeeded as autoUpgrade, checkAllToolVersions, checkAndUpgradeIfNeeded, checkAllToolVersions as checkVersions, performSilentUpgradeAll, shouldCheckForUpgrades, performSilentUpgradeAll as upgradeAll };
package/dist/cli.mjs CHANGED
@@ -877,10 +877,22 @@ function customizeHelpLazy(_sections, version) {
877
877
  return newSections;
878
878
  }
879
879
  async function runLazyCli() {
880
+ bootstrapCloudServices();
880
881
  const cac = (await import('cac')).default;
881
882
  const cli = cac("ccjk");
882
883
  await setupCommandsLazy(cli);
883
884
  cli.parse();
884
885
  }
886
+ function bootstrapCloudServices() {
887
+ setImmediate(async () => {
888
+ try {
889
+ const { autoBootstrap } = await import('./chunks/auto-bootstrap.mjs');
890
+ await autoBootstrap();
891
+ const { autoUpgrade } = await import('./chunks/silent-updater.mjs');
892
+ await autoUpgrade();
893
+ } catch {
894
+ }
895
+ });
896
+ }
885
897
 
886
898
  runLazyCli().catch(console.error);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ccjk",
3
3
  "type": "module",
4
- "version": "2.3.1",
4
+ "version": "2.3.2",
5
5
  "packageManager": "pnpm@10.17.1",
6
6
  "description": "Claude Code JinKu - Advanced AI-powered development assistant with skills, agents, and LLM-driven audit",
7
7
  "author": {