ccjk 9.0.3 → 9.1.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.
@@ -629,6 +629,8 @@ async function validateGitTrigger(pattern, condition, projectInfo) {
629
629
  const validGitHooks = [
630
630
  "pre-commit",
631
631
  "post-commit",
632
+ "commit-msg",
633
+ "prepare-commit-msg",
632
634
  "pre-push",
633
635
  "post-push",
634
636
  "pre-merge",
@@ -636,7 +638,13 @@ async function validateGitTrigger(pattern, condition, projectInfo) {
636
638
  "pre-rebase",
637
639
  "post-rebase",
638
640
  "pre-checkout",
639
- "post-checkout"
641
+ "post-checkout",
642
+ "pre-receive",
643
+ "post-receive",
644
+ "update",
645
+ "pre-applypatch",
646
+ "post-applypatch",
647
+ "applypatch-msg"
640
648
  ];
641
649
  if (!validGitHooks.includes(pattern)) {
642
650
  throw new Error(`Invalid git hook: ${pattern}`);
@@ -106,6 +106,18 @@ function readJsonFile(path) {
106
106
  );
107
107
  }
108
108
  }
109
+ function writeJsonFile(path, data, pretty = true) {
110
+ try {
111
+ const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
112
+ writeFile(path, content, "utf-8");
113
+ } catch (error) {
114
+ throw new FileSystemError(
115
+ `Failed to write JSON file: ${path}`,
116
+ path,
117
+ error
118
+ );
119
+ }
120
+ }
109
121
  function copyFile(src, dest) {
110
122
  try {
111
123
  ensureFileDir(dest);
@@ -177,4 +189,4 @@ function copyDir(src, dest, options = {}) {
177
189
  }
178
190
  }
179
191
 
180
- export { FileSystemError, copyDir, copyFile, ensureDir, ensureFileDir, exists, getStatsSafe, readDir, readFile, readJsonFile, removeFile, writeFile, writeFileAtomic, writeFileAtomicAsync };
192
+ export { FileSystemError, copyDir, copyFile, ensureDir, ensureFileDir, exists, getStatsSafe, readDir, readFile, readJsonFile, removeFile, writeFile, writeFileAtomic, writeFileAtomicAsync, writeJsonFile };
@@ -1,4 +1,4 @@
1
- const version = "9.0.3";
1
+ const version = "9.1.0";
2
2
  const homepage = "https://github.com/miounet11/ccjk";
3
3
 
4
4
  export { homepage, version };
@@ -0,0 +1,899 @@
1
+ import ansis from 'ansis';
2
+ import inquirer from 'inquirer';
3
+ import ora from 'ora';
4
+
5
+ function isValidApiUrl(url) {
6
+ try {
7
+ const parsed = new URL(url);
8
+ return parsed.protocol === "https:" || parsed.protocol === "http:";
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+
14
+ const DEFAULT_TIMEOUT = 3e4;
15
+ const DEFAULT_RETRY_ATTEMPTS = 3;
16
+ const DEFAULT_RETRY_DELAY = 1e3;
17
+ class CloudApiClient {
18
+ baseUrl;
19
+ timeout;
20
+ authToken;
21
+ userAgent;
22
+ retry;
23
+ /**
24
+ * Create a new CloudApiClient instance
25
+ *
26
+ * @param config - Client configuration
27
+ */
28
+ constructor(config) {
29
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
30
+ this.timeout = config.timeout || DEFAULT_TIMEOUT;
31
+ this.authToken = config.authToken;
32
+ this.userAgent = config.userAgent || "CCJK-Client/1.0";
33
+ this.retry = config.retry || {
34
+ maxAttempts: DEFAULT_RETRY_ATTEMPTS,
35
+ delay: DEFAULT_RETRY_DELAY
36
+ };
37
+ }
38
+ // ==========================================================================
39
+ // Configuration Methods
40
+ // ==========================================================================
41
+ /**
42
+ * Set authentication token
43
+ *
44
+ * @param token - Authentication token
45
+ */
46
+ setAuthToken(token) {
47
+ this.authToken = token;
48
+ }
49
+ /**
50
+ * Clear authentication token
51
+ */
52
+ clearAuthToken() {
53
+ this.authToken = void 0;
54
+ }
55
+ /**
56
+ * Get current base URL
57
+ */
58
+ getBaseUrl() {
59
+ return this.baseUrl;
60
+ }
61
+ /**
62
+ * Update base URL
63
+ *
64
+ * @param url - New base URL
65
+ */
66
+ setBaseUrl(url) {
67
+ this.baseUrl = url.replace(/\/$/, "");
68
+ }
69
+ // ==========================================================================
70
+ // Request Methods
71
+ // ==========================================================================
72
+ /**
73
+ * Make an HTTP request to the cloud service
74
+ *
75
+ * @param path - API endpoint path (e.g., '/plugins/recommend')
76
+ * @param options - Request options
77
+ * @returns API response
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * const response = await client.request<{ data: string }>('/api/endpoint', {
82
+ * method: 'POST',
83
+ * body: { key: 'value' },
84
+ * timeout: 5000
85
+ * })
86
+ * ```
87
+ */
88
+ async request(path, options) {
89
+ const maxAttempts = options.retry?.maxAttempts || this.retry.maxAttempts;
90
+ const retryDelay = options.retry?.delay || this.retry.delay;
91
+ let lastError = null;
92
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
93
+ try {
94
+ return await this.executeRequest(path, options);
95
+ } catch (error) {
96
+ lastError = error instanceof Error ? error : new Error(String(error));
97
+ if (attempt === maxAttempts || this.isClientError(lastError)) {
98
+ break;
99
+ }
100
+ await this.sleep(retryDelay * attempt);
101
+ }
102
+ }
103
+ return {
104
+ success: false,
105
+ error: lastError?.message || "Request failed",
106
+ code: "REQUEST_FAILED"
107
+ };
108
+ }
109
+ /**
110
+ * Execute a single HTTP request
111
+ *
112
+ * @private
113
+ */
114
+ async executeRequest(path, options) {
115
+ const url = this.buildUrl(path, options.query);
116
+ const timeout = options.timeout || this.timeout;
117
+ const controller = new AbortController();
118
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
119
+ try {
120
+ const headers = this.buildHeaders(options);
121
+ const response = await fetch(url, {
122
+ method: options.method,
123
+ headers,
124
+ body: options.body ? JSON.stringify(options.body) : void 0,
125
+ signal: controller.signal
126
+ });
127
+ clearTimeout(timeoutId);
128
+ const data = await response.json();
129
+ if (!response.ok) {
130
+ return {
131
+ success: false,
132
+ error: data.error || `HTTP ${response.status}: ${response.statusText}`,
133
+ code: data.code || `HTTP_${response.status}`
134
+ };
135
+ }
136
+ return {
137
+ ...data,
138
+ success: true
139
+ };
140
+ } catch (error) {
141
+ clearTimeout(timeoutId);
142
+ if (error instanceof Error) {
143
+ if (error.name === "AbortError") {
144
+ return {
145
+ success: false,
146
+ error: "Request timeout",
147
+ code: "TIMEOUT"
148
+ };
149
+ }
150
+ return {
151
+ success: false,
152
+ error: error.message,
153
+ code: "NETWORK_ERROR"
154
+ };
155
+ }
156
+ return {
157
+ success: false,
158
+ error: String(error),
159
+ code: "UNKNOWN_ERROR"
160
+ };
161
+ }
162
+ }
163
+ // ==========================================================================
164
+ // Convenience Methods
165
+ // ==========================================================================
166
+ /**
167
+ * Make a GET request
168
+ *
169
+ * @param path - API endpoint path
170
+ * @param query - Query parameters
171
+ * @param options - Additional request options
172
+ * @returns API response
173
+ */
174
+ async get(path, query, options) {
175
+ return this.request(path, {
176
+ method: "GET",
177
+ query,
178
+ ...options
179
+ });
180
+ }
181
+ /**
182
+ * Make a POST request
183
+ *
184
+ * @param path - API endpoint path
185
+ * @param body - Request body
186
+ * @param options - Additional request options
187
+ * @returns API response
188
+ */
189
+ async post(path, body, options) {
190
+ return this.request(path, {
191
+ method: "POST",
192
+ body,
193
+ ...options
194
+ });
195
+ }
196
+ /**
197
+ * Make a PUT request
198
+ *
199
+ * @param path - API endpoint path
200
+ * @param body - Request body
201
+ * @param options - Additional request options
202
+ * @returns API response
203
+ */
204
+ async put(path, body, options) {
205
+ return this.request(path, {
206
+ method: "PUT",
207
+ body,
208
+ ...options
209
+ });
210
+ }
211
+ /**
212
+ * Make a DELETE request
213
+ *
214
+ * @param path - API endpoint path
215
+ * @param options - Additional request options
216
+ * @returns API response
217
+ */
218
+ async delete(path, options) {
219
+ return this.request(path, {
220
+ method: "DELETE",
221
+ ...options
222
+ });
223
+ }
224
+ // ==========================================================================
225
+ // Helper Methods
226
+ // ==========================================================================
227
+ /**
228
+ * Build full URL with query parameters
229
+ *
230
+ * @private
231
+ */
232
+ buildUrl(path, query) {
233
+ const url = `${this.baseUrl}${path}`;
234
+ if (!query || Object.keys(query).length === 0) {
235
+ return url;
236
+ }
237
+ const params = new URLSearchParams();
238
+ for (const [key, value] of Object.entries(query)) {
239
+ params.append(key, String(value));
240
+ }
241
+ return `${url}?${params.toString()}`;
242
+ }
243
+ /**
244
+ * Build request headers
245
+ *
246
+ * @private
247
+ */
248
+ buildHeaders(options) {
249
+ const headers = {
250
+ "Content-Type": "application/json",
251
+ "User-Agent": this.userAgent,
252
+ ...options.headers
253
+ };
254
+ const token = options.authToken || this.authToken;
255
+ if (token) {
256
+ headers.Authorization = `Bearer ${token}`;
257
+ }
258
+ return headers;
259
+ }
260
+ /**
261
+ * Check if error is a client error (4xx)
262
+ *
263
+ * @private
264
+ */
265
+ isClientError(error) {
266
+ return error.message.includes("HTTP 4");
267
+ }
268
+ /**
269
+ * Sleep for specified milliseconds
270
+ *
271
+ * @private
272
+ */
273
+ sleep(ms) {
274
+ return new Promise((resolve) => setTimeout(resolve, ms));
275
+ }
276
+ }
277
+ function createApiClient(config) {
278
+ return new CloudApiClient(config);
279
+ }
280
+
281
+ const CLOUD_API_BASE_URL = "https://api.claudehome.cn/v1";
282
+ const REQUEST_TIMEOUT = 1e4;
283
+ const BUILTIN_PROVIDERS = {
284
+ "302": {
285
+ shortcode: "302",
286
+ name: "302.AI",
287
+ apiUrl: "https://api.302.ai",
288
+ description: "302.AI \u4E2D\u8F6C\u670D\u52A1 - \u652F\u6301\u591A\u79CD\u6A21\u578B",
289
+ models: ["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo", "claude-3-opus", "claude-3-sonnet"],
290
+ verified: true,
291
+ category: "relay",
292
+ status: "active",
293
+ createdAt: "2024-01-01T00:00:00Z"
294
+ },
295
+ "glm": {
296
+ shortcode: "glm",
297
+ name: "\u667A\u8C31AI",
298
+ apiUrl: "https://open.bigmodel.cn/api/paas/v4",
299
+ description: "\u667A\u8C31 GLM \u5927\u6A21\u578B",
300
+ models: ["glm-4", "glm-4-plus", "glm-3-turbo"],
301
+ verified: true,
302
+ category: "domestic",
303
+ status: "active",
304
+ createdAt: "2024-01-01T00:00:00Z"
305
+ },
306
+ "kimi": {
307
+ shortcode: "kimi",
308
+ name: "\u6708\u4E4B\u6697\u9762 Kimi",
309
+ apiUrl: "https://api.moonshot.cn/v1",
310
+ description: "Moonshot Kimi \u5927\u6A21\u578B",
311
+ models: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],
312
+ verified: true,
313
+ category: "domestic",
314
+ status: "active",
315
+ createdAt: "2024-01-01T00:00:00Z"
316
+ },
317
+ "minimax": {
318
+ shortcode: "minimax",
319
+ name: "MiniMax",
320
+ apiUrl: "https://api.minimax.chat/v1",
321
+ description: "MiniMax \u5927\u6A21\u578B",
322
+ models: ["abab5.5-chat", "abab6-chat", "abab6.5-chat"],
323
+ verified: true,
324
+ category: "domestic",
325
+ status: "active",
326
+ createdAt: "2024-01-01T00:00:00Z"
327
+ },
328
+ "deepseek": {
329
+ shortcode: "deepseek",
330
+ name: "DeepSeek",
331
+ apiUrl: "https://api.deepseek.com/v1",
332
+ description: "DeepSeek \u5927\u6A21\u578B",
333
+ models: ["deepseek-chat", "deepseek-coder"],
334
+ verified: true,
335
+ category: "domestic",
336
+ status: "active",
337
+ createdAt: "2024-01-01T00:00:00Z"
338
+ },
339
+ "qwen": {
340
+ shortcode: "qwen",
341
+ name: "\u901A\u4E49\u5343\u95EE",
342
+ apiUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
343
+ description: "\u963F\u91CC\u901A\u4E49\u5343\u95EE\u5927\u6A21\u578B",
344
+ models: ["qwen-turbo", "qwen-plus", "qwen-max"],
345
+ verified: true,
346
+ category: "domestic",
347
+ status: "active",
348
+ createdAt: "2024-01-01T00:00:00Z"
349
+ }
350
+ };
351
+ class ProviderRegistryService {
352
+ client;
353
+ useCloud = true;
354
+ constructor(options) {
355
+ this.client = createApiClient({
356
+ baseUrl: options?.baseUrl || CLOUD_API_BASE_URL,
357
+ timeout: REQUEST_TIMEOUT,
358
+ userAgent: "CCJK-QuickLaunch/1.0"
359
+ });
360
+ this.useCloud = options?.useCloud ?? true;
361
+ }
362
+ // ==========================================================================
363
+ // Query Methods
364
+ // ==========================================================================
365
+ /**
366
+ * Get provider by shortcode
367
+ *
368
+ * First tries cloud registry, falls back to built-in providers.
369
+ *
370
+ * @param shortcode - Provider shortcode (e.g., "302", "glm")
371
+ * @returns Provider info or null if not found
372
+ */
373
+ async getProvider(shortcode) {
374
+ const normalizedCode = shortcode.toLowerCase().trim();
375
+ if (this.useCloud) {
376
+ try {
377
+ const response = await this.client.get(
378
+ `/providers/${encodeURIComponent(normalizedCode)}`
379
+ );
380
+ if (response.success && response.data?.data) {
381
+ return response.data.data;
382
+ }
383
+ } catch {
384
+ }
385
+ }
386
+ return BUILTIN_PROVIDERS[normalizedCode] || null;
387
+ }
388
+ /**
389
+ * Check if shortcode exists
390
+ *
391
+ * @param shortcode - Provider shortcode to check
392
+ * @returns true if exists, false otherwise
393
+ */
394
+ async exists(shortcode) {
395
+ const provider = await this.getProvider(shortcode);
396
+ return provider !== null;
397
+ }
398
+ /**
399
+ * Check if shortcode is available for registration
400
+ *
401
+ * @param shortcode - Provider shortcode to check
402
+ * @returns true if available, false if taken
403
+ */
404
+ async isAvailable(shortcode) {
405
+ return !await this.exists(shortcode);
406
+ }
407
+ // ==========================================================================
408
+ // Registration Methods
409
+ // ==========================================================================
410
+ /**
411
+ * Create a new provider in the cloud registry
412
+ *
413
+ * @param input - Provider creation data
414
+ * @returns Created provider or error
415
+ */
416
+ async createProvider(input) {
417
+ if (!this.useCloud) {
418
+ return {
419
+ success: false,
420
+ error: {
421
+ code: "CLOUD_DISABLED",
422
+ message: "Cloud service is disabled"
423
+ }
424
+ };
425
+ }
426
+ try {
427
+ const response = await this.client.post(
428
+ "/providers",
429
+ input
430
+ );
431
+ if (response.success && response.data) {
432
+ return response.data;
433
+ }
434
+ return {
435
+ success: false,
436
+ error: {
437
+ code: response.code || "CREATE_FAILED",
438
+ message: response.error || "Failed to create provider"
439
+ }
440
+ };
441
+ } catch (error) {
442
+ return {
443
+ success: false,
444
+ error: {
445
+ code: "NETWORK_ERROR",
446
+ message: error instanceof Error ? error.message : "Network error"
447
+ }
448
+ };
449
+ }
450
+ }
451
+ // ==========================================================================
452
+ // List Methods
453
+ // ==========================================================================
454
+ /**
455
+ * List all available providers
456
+ *
457
+ * @param options - List options
458
+ * @returns List of providers
459
+ */
460
+ async listProviders(options) {
461
+ if (this.useCloud) {
462
+ try {
463
+ const query = {};
464
+ if (options?.category) query.category = options.category;
465
+ if (options?.verified !== void 0) query.verified = options.verified;
466
+ if (options?.limit) query.limit = options.limit;
467
+ const response = await this.client.get(
468
+ "/providers",
469
+ query
470
+ );
471
+ if (response.success && response.data?.data?.providers) {
472
+ return response.data.data.providers;
473
+ }
474
+ } catch {
475
+ }
476
+ }
477
+ let providers = Object.values(BUILTIN_PROVIDERS);
478
+ if (options?.category) {
479
+ providers = providers.filter((p) => p.category === options.category);
480
+ }
481
+ if (options?.verified !== void 0) {
482
+ providers = providers.filter((p) => p.verified === options.verified);
483
+ }
484
+ if (options?.limit) {
485
+ providers = providers.slice(0, options.limit);
486
+ }
487
+ return providers;
488
+ }
489
+ /**
490
+ * Get built-in provider (always available, no network)
491
+ *
492
+ * @param shortcode - Provider shortcode
493
+ * @returns Built-in provider or null
494
+ */
495
+ getBuiltinProvider(shortcode) {
496
+ return BUILTIN_PROVIDERS[shortcode.toLowerCase()] || null;
497
+ }
498
+ /**
499
+ * List all built-in providers
500
+ *
501
+ * @returns Array of built-in providers
502
+ */
503
+ listBuiltinProviders() {
504
+ return Object.values(BUILTIN_PROVIDERS);
505
+ }
506
+ // ==========================================================================
507
+ // Configuration
508
+ // ==========================================================================
509
+ /**
510
+ * Enable or disable cloud service
511
+ */
512
+ setUseCloud(enabled) {
513
+ this.useCloud = enabled;
514
+ }
515
+ /**
516
+ * Check if cloud service is enabled
517
+ */
518
+ isCloudEnabled() {
519
+ return this.useCloud;
520
+ }
521
+ }
522
+ let _instance = null;
523
+ function getProviderRegistry() {
524
+ if (!_instance) {
525
+ _instance = new ProviderRegistryService();
526
+ }
527
+ return _instance;
528
+ }
529
+
530
+ const KNOWN_COMMANDS = /* @__PURE__ */ new Set([
531
+ // Core commands
532
+ "",
533
+ "init",
534
+ "update",
535
+ "doctor",
536
+ "help",
537
+ // Extended commands
538
+ "serve",
539
+ "mcp",
540
+ "browser",
541
+ "interview",
542
+ "commit",
543
+ "config",
544
+ "daemon",
545
+ "providers",
546
+ "task",
547
+ "tasks",
548
+ "keybinding",
549
+ "kb",
550
+ "history",
551
+ "hist",
552
+ "ccr",
553
+ "vim",
554
+ "permissions",
555
+ "perm",
556
+ "skills",
557
+ "sk",
558
+ "skill",
559
+ "agent",
560
+ "ag",
561
+ "ccu",
562
+ "stats",
563
+ "uninstall",
564
+ "check-updates",
565
+ "check",
566
+ "config-switch",
567
+ "cs",
568
+ "workflows",
569
+ "wf",
570
+ "notification",
571
+ "notify",
572
+ "session",
573
+ "context",
574
+ "ctx",
575
+ "api",
576
+ "team",
577
+ "thinking",
578
+ "think",
579
+ "postmortem",
580
+ "pm",
581
+ "claude",
582
+ "monitor",
583
+ // CCJK v8 commands
584
+ "ccjk:mcp",
585
+ "ccjk-mcp",
586
+ "ccjk:skills",
587
+ "ccjk-skills",
588
+ "ccjk:agents",
589
+ "ccjk-agents",
590
+ "ccjk:hooks",
591
+ "ccjk-hooks",
592
+ "ccjk:all",
593
+ "ccjk-all",
594
+ "ccjk:setup",
595
+ "ccjk-setup",
596
+ // Special commands
597
+ "cloud",
598
+ "system",
599
+ "sys",
600
+ "plugin",
601
+ "completion",
602
+ // Deprecated but still recognized
603
+ "skills-sync",
604
+ "agents-sync",
605
+ "marketplace",
606
+ "quick",
607
+ "deep",
608
+ "setup",
609
+ "sync",
610
+ "versions",
611
+ "upgrade",
612
+ "config-scan",
613
+ "workspace"
614
+ ]);
615
+ function isKnownCommand(arg) {
616
+ if (!arg) return true;
617
+ if (arg.startsWith("-")) return true;
618
+ return KNOWN_COMMANDS.has(arg.toLowerCase());
619
+ }
620
+ function couldBeShortcode(arg) {
621
+ if (!arg) return false;
622
+ if (arg.startsWith("-")) return false;
623
+ if (isKnownCommand(arg)) return false;
624
+ return /^[a-z0-9][a-z0-9-]{0,18}[a-z0-9]?$/i.test(arg);
625
+ }
626
+ async function quickProviderLaunch(shortcode, options = {}) {
627
+ const registry = getProviderRegistry();
628
+ const normalizedCode = shortcode.toLowerCase().trim();
629
+ console.log();
630
+ const spinner = ora({
631
+ text: ansis.gray(`\u6B63\u5728\u67E5\u8BE2\u4F9B\u5E94\u5546 "${normalizedCode}"...`),
632
+ color: "cyan"
633
+ }).start();
634
+ try {
635
+ const provider = await registry.getProvider(normalizedCode);
636
+ spinner.stop();
637
+ if (provider) {
638
+ return await handleExistingProvider(provider, options);
639
+ } else {
640
+ return await handleNewProvider(normalizedCode, options);
641
+ }
642
+ } catch (error) {
643
+ spinner.fail(ansis.red("\u67E5\u8BE2\u5931\u8D25"));
644
+ console.error(ansis.gray(error instanceof Error ? error.message : "\u7F51\u7EDC\u9519\u8BEF"));
645
+ return false;
646
+ }
647
+ }
648
+ async function handleExistingProvider(provider, options) {
649
+ console.log(ansis.cyan.bold(`
650
+ \u{1F680} \u5FEB\u901F\u914D\u7F6E: ${provider.name}`));
651
+ console.log(ansis.gray("\u2500".repeat(40)));
652
+ console.log(` ${ansis.yellow("\u77ED\u7801:")} ${provider.shortcode}`);
653
+ console.log(` ${ansis.yellow("API URL:")} ${provider.apiUrl}`);
654
+ if (provider.description) {
655
+ console.log(` ${ansis.yellow("\u63CF\u8FF0:")} ${provider.description}`);
656
+ }
657
+ if (provider.verified) {
658
+ console.log(` ${ansis.green("\u2713")} \u5B98\u65B9\u9A8C\u8BC1`);
659
+ }
660
+ console.log();
661
+ const { confirmed } = await inquirer.prompt([
662
+ {
663
+ type: "confirm",
664
+ name: "confirmed",
665
+ message: `\u662F\u5426\u4F7F\u7528 ${ansis.cyan(provider.name)} \u4F5C\u4E3A API \u4F9B\u5E94\u5546?`,
666
+ default: true
667
+ }
668
+ ]);
669
+ if (!confirmed) {
670
+ console.log(ansis.gray("\n\u5DF2\u53D6\u6D88\uFF0C\u8FDB\u5165\u4E3B\u83DC\u5355...\n"));
671
+ return false;
672
+ }
673
+ const config = await configureProvider(provider);
674
+ if (config) {
675
+ await saveProviderConfig(config);
676
+ showSuccessMessage(config);
677
+ return true;
678
+ }
679
+ return false;
680
+ }
681
+ async function handleNewProvider(shortcode, options) {
682
+ console.log(ansis.yellow(`
683
+ \u26A0\uFE0F \u4F9B\u5E94\u5546 "${shortcode}" \u5C1A\u672A\u6CE8\u518C`));
684
+ console.log(ansis.gray("\u8BE5\u77ED\u7801\u5728\u4E91\u7AEF\u6CE8\u518C\u8868\u4E2D\u4E0D\u5B58\u5728\n"));
685
+ const { createNew } = await inquirer.prompt([
686
+ {
687
+ type: "confirm",
688
+ name: "createNew",
689
+ message: "\u662F\u5426\u521B\u5EFA\u8BE5\u4F9B\u5E94\u5546?",
690
+ default: false
691
+ }
692
+ ]);
693
+ if (!createNew) {
694
+ console.log(ansis.gray("\n\u5DF2\u53D6\u6D88\uFF0C\u8FDB\u5165\u4E3B\u83DC\u5355...\n"));
695
+ return false;
696
+ }
697
+ const { name, apiUrl } = await inquirer.prompt([
698
+ {
699
+ type: "input",
700
+ name: "name",
701
+ message: "\u4F9B\u5E94\u5546\u540D\u79F0:",
702
+ default: shortcode.toUpperCase(),
703
+ validate: (value) => {
704
+ if (!value.trim()) return "\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
705
+ if (value.length > 50) return "\u540D\u79F0\u8FC7\u957F\uFF08\u6700\u591A50\u5B57\u7B26\uFF09";
706
+ return true;
707
+ }
708
+ },
709
+ {
710
+ type: "input",
711
+ name: "apiUrl",
712
+ message: "API URL (\u5982 https://api.example.com/v1):",
713
+ validate: (value) => {
714
+ if (!value.trim()) return "URL \u4E0D\u80FD\u4E3A\u7A7A";
715
+ if (!isValidApiUrl(value)) return "\u8BF7\u8F93\u5165\u6709\u6548\u7684 URL\uFF08http:// \u6216 https://\uFF09";
716
+ return true;
717
+ }
718
+ }
719
+ ]);
720
+ const spinner = ora("\u6B63\u5728\u6CE8\u518C\u4F9B\u5E94\u5546...").start();
721
+ try {
722
+ const registry = getProviderRegistry();
723
+ const result = await registry.createProvider({
724
+ shortcode,
725
+ name: name.trim(),
726
+ apiUrl: apiUrl.trim()
727
+ });
728
+ if (result.success && result.data) {
729
+ spinner.succeed(ansis.green("\u4F9B\u5E94\u5546\u6CE8\u518C\u6210\u529F!"));
730
+ const config = await configureProvider(result.data, options);
731
+ if (config) {
732
+ await saveProviderConfig(config);
733
+ showSuccessMessage(config);
734
+ return true;
735
+ }
736
+ } else {
737
+ spinner.fail(ansis.red("\u6CE8\u518C\u5931\u8D25"));
738
+ console.error(ansis.gray(result.error?.message || "\u672A\u77E5\u9519\u8BEF"));
739
+ const { continueLocal } = await inquirer.prompt([
740
+ {
741
+ type: "confirm",
742
+ name: "continueLocal",
743
+ message: "\u662F\u5426\u4ECD\u7136\u4F7F\u7528\u6B64\u914D\u7F6E\uFF08\u4EC5\u672C\u5730\uFF09?",
744
+ default: true
745
+ }
746
+ ]);
747
+ if (continueLocal) {
748
+ const localProvider = {
749
+ shortcode,
750
+ name: name.trim(),
751
+ apiUrl: apiUrl.trim(),
752
+ verified: false,
753
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
754
+ };
755
+ const config = await configureProvider(localProvider, options);
756
+ if (config) {
757
+ await saveProviderConfig(config);
758
+ showSuccessMessage(config);
759
+ return true;
760
+ }
761
+ }
762
+ }
763
+ } catch (error) {
764
+ spinner.fail(ansis.red("\u6CE8\u518C\u5931\u8D25"));
765
+ console.error(ansis.gray(error instanceof Error ? error.message : "\u7F51\u7EDC\u9519\u8BEF"));
766
+ }
767
+ return false;
768
+ }
769
+ async function configureProvider(provider, _options) {
770
+ console.log(ansis.cyan("\n\u{1F4DD} \u914D\u7F6E API \u51ED\u8BC1"));
771
+ console.log(ansis.gray("\u2500".repeat(40)));
772
+ const { apiKey } = await inquirer.prompt([
773
+ {
774
+ type: "password",
775
+ name: "apiKey",
776
+ message: "API Key:",
777
+ mask: "*",
778
+ validate: (value) => {
779
+ if (!value.trim()) return "API Key \u4E0D\u80FD\u4E3A\u7A7A";
780
+ if (value.length < 10) return "API Key \u683C\u5F0F\u4E0D\u6B63\u786E";
781
+ return true;
782
+ }
783
+ }
784
+ ]);
785
+ let model;
786
+ if (provider.models && provider.models.length > 0) {
787
+ const { modelChoice } = await inquirer.prompt([
788
+ {
789
+ type: "list",
790
+ name: "modelChoice",
791
+ message: "\u9009\u62E9\u6A21\u578B:",
792
+ choices: [
793
+ ...provider.models.map((m) => ({
794
+ name: m,
795
+ value: m
796
+ })),
797
+ {
798
+ name: ansis.gray("\u81EA\u5B9A\u4E49..."),
799
+ value: "__custom__"
800
+ }
801
+ ]
802
+ }
803
+ ]);
804
+ if (modelChoice === "__custom__") {
805
+ const { customModel } = await inquirer.prompt([
806
+ {
807
+ type: "input",
808
+ name: "customModel",
809
+ message: "\u8F93\u5165\u6A21\u578B\u540D\u79F0:",
810
+ validate: (value) => {
811
+ if (!value.trim()) return "\u6A21\u578B\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
812
+ return true;
813
+ }
814
+ }
815
+ ]);
816
+ model = customModel;
817
+ } else {
818
+ model = modelChoice;
819
+ }
820
+ } else {
821
+ const { inputModel } = await inquirer.prompt([
822
+ {
823
+ type: "input",
824
+ name: "inputModel",
825
+ message: "\u6A21\u578B\u540D\u79F0 (\u5982 gpt-4, claude-3-opus):",
826
+ default: "gpt-4",
827
+ validate: (value) => {
828
+ if (!value.trim()) return "\u6A21\u578B\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
829
+ return true;
830
+ }
831
+ }
832
+ ]);
833
+ model = inputModel;
834
+ }
835
+ return {
836
+ shortcode: provider.shortcode,
837
+ provider,
838
+ apiKey: apiKey.trim(),
839
+ model: model.trim()
840
+ };
841
+ }
842
+ async function saveProviderConfig(config) {
843
+ const spinner = ora("\u6B63\u5728\u4FDD\u5B58\u914D\u7F6E...").start();
844
+ try {
845
+ const { readJsonFile, writeJsonFile } = await import('./fs-operations.mjs');
846
+ const { join } = await import('pathe');
847
+ const { homedir } = await import('node:os');
848
+ const { existsSync, mkdirSync } = await import('node:fs');
849
+ const claudeDir = join(homedir(), ".claude");
850
+ const settingsPath = join(claudeDir, "settings.json");
851
+ if (!existsSync(claudeDir)) {
852
+ mkdirSync(claudeDir, { recursive: true });
853
+ }
854
+ let settings = {};
855
+ try {
856
+ if (existsSync(settingsPath)) {
857
+ settings = readJsonFile(settingsPath) || {};
858
+ }
859
+ } catch {
860
+ }
861
+ settings.apiProvider = "custom";
862
+ settings.apiUrl = config.provider.apiUrl;
863
+ settings.apiKey = config.apiKey;
864
+ settings.model = config.model;
865
+ const envConfig = {
866
+ ANTHROPIC_BASE_URL: config.provider.apiUrl,
867
+ ANTHROPIC_API_KEY: config.apiKey,
868
+ ANTHROPIC_MODEL: config.model
869
+ };
870
+ settings.env = {
871
+ ...settings.env || {},
872
+ ...envConfig
873
+ };
874
+ writeJsonFile(settingsPath, settings);
875
+ spinner.succeed(ansis.green("\u914D\u7F6E\u5DF2\u4FDD\u5B58"));
876
+ } catch (error) {
877
+ spinner.fail(ansis.red("\u4FDD\u5B58\u5931\u8D25"));
878
+ console.log(ansis.yellow("\n\u8BF7\u624B\u52A8\u914D\u7F6E:"));
879
+ console.log(ansis.gray("\u2500".repeat(40)));
880
+ console.log(`${ansis.cyan("API URL:")} ${config.provider.apiUrl}`);
881
+ console.log(`${ansis.cyan("Model:")} ${config.model}`);
882
+ console.log(ansis.gray('\n\u8FD0\u884C "ccjk api" \u8FDB\u884C\u624B\u52A8\u914D\u7F6E'));
883
+ throw error;
884
+ }
885
+ }
886
+ function showSuccessMessage(config) {
887
+ console.log();
888
+ console.log(ansis.green.bold("\u2705 \u914D\u7F6E\u5B8C\u6210!"));
889
+ console.log(ansis.gray("\u2500".repeat(40)));
890
+ console.log(` ${ansis.yellow("\u4F9B\u5E94\u5546:")} ${config.provider.name}`);
891
+ console.log(` ${ansis.yellow("API URL:")} ${config.provider.apiUrl}`);
892
+ console.log(` ${ansis.yellow("\u6A21\u578B:")} ${config.model}`);
893
+ console.log();
894
+ console.log(ansis.gray("\u73B0\u5728\u53EF\u4EE5\u5F00\u59CB\u4F7F\u7528 Claude Code \u4E86"));
895
+ console.log(ansis.gray('\u8FD0\u884C "claude" \u542F\u52A8\u5BF9\u8BDD'));
896
+ console.log();
897
+ }
898
+
899
+ export { configureProvider, couldBeShortcode, handleExistingProvider, handleNewProvider, isKnownCommand, quickProviderLaunch, saveProviderConfig };
package/dist/cli.mjs CHANGED
@@ -1635,11 +1635,41 @@ function customizeHelpLazy(_sections, version) {
1635
1635
  }
1636
1636
  async function runLazyCli() {
1637
1637
  bootstrapCloudServices();
1638
+ const handled = await tryQuickProviderLaunch();
1639
+ if (handled) {
1640
+ return;
1641
+ }
1638
1642
  const cac = (await import('cac')).default;
1639
1643
  const cli = cac("ccjk");
1640
1644
  await setupCommandsLazy(cli);
1641
1645
  cli.parse();
1642
1646
  }
1647
+ async function tryQuickProviderLaunch() {
1648
+ const args = process__default.argv.slice(2);
1649
+ if (args.length === 0 || args[0].startsWith("-")) {
1650
+ return false;
1651
+ }
1652
+ const firstArg = args[0].toLowerCase();
1653
+ const { couldBeShortcode, isKnownCommand } = await import('./chunks/quick-provider.mjs');
1654
+ if (isKnownCommand(firstArg)) {
1655
+ return false;
1656
+ }
1657
+ if (!couldBeShortcode(firstArg)) {
1658
+ return false;
1659
+ }
1660
+ const { quickProviderLaunch } = await import('./chunks/quick-provider.mjs');
1661
+ try {
1662
+ const handled = await quickProviderLaunch(firstArg, {
1663
+ lang: process__default.env.CCJK_LANG
1664
+ });
1665
+ if (handled) {
1666
+ return true;
1667
+ }
1668
+ return false;
1669
+ } catch {
1670
+ return false;
1671
+ }
1672
+ }
1643
1673
  function bootstrapCloudServices() {
1644
1674
  setImmediate(async () => {
1645
1675
  try {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ccjk",
3
3
  "type": "module",
4
- "version": "9.0.3",
4
+ "version": "9.1.0",
5
5
  "packageManager": "pnpm@10.17.1",
6
6
  "description": "CCJK v9.0.0 - Revolutionary AI Development Platform with Enterprise Security, Streaming Cloud Sync, CRDT Conflict Resolution, and Unified V3 Architecture",
7
7
  "author": {