ccjk 2.5.0 → 2.6.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.
@@ -299,6 +299,9 @@ async function configCommand(action, args, options = {}) {
299
299
  }
300
300
  }
301
301
  }
302
+ function getClaudeConfigPath() {
303
+ return SETTINGS_FILE;
304
+ }
302
305
  function readClaudeConfig() {
303
306
  if (!existsSync(SETTINGS_FILE)) {
304
307
  return null;
@@ -36,6 +36,8 @@ const NAMESPACES = [
36
36
  // Permission system for API providers, models, and tools
37
37
  "plugins",
38
38
  // Cloud plugins management
39
+ "registry",
40
+ // Version checking, China detection, and multiple installations
39
41
  "sandbox",
40
42
  // Sandbox mode for secure request/response handling
41
43
  "shencha",
@@ -1,4 +1,4 @@
1
- const version = "2.5.0";
1
+ const version = "2.6.0";
2
2
  const homepage = "https://github.com/miounet11/ccjk";
3
3
 
4
4
  export { homepage, version };
@@ -226,12 +226,19 @@ class PermissionManager {
226
226
  }
227
227
  }
228
228
  }
229
+ let instance = null;
230
+ function getPermissionManager(configPath) {
231
+ if (!instance) {
232
+ instance = new PermissionManager(configPath);
233
+ }
234
+ return instance;
235
+ }
229
236
 
230
- const permissionManager = PermissionManager.getInstance();
237
+ const permissionManager = getPermissionManager();
231
238
  async function listPermissions(options) {
232
239
  const format = options.format || "table";
233
240
  const verbose = options.verbose || false;
234
- const permissions = permissionManager.getAllPermissions();
241
+ const permissions = permissionManager.listPermissions();
235
242
  if (format === "json") {
236
243
  console.log(JSON.stringify(permissions, null, 2));
237
244
  return;
@@ -243,23 +250,23 @@ async function listPermissions(options) {
243
250
  }
244
251
  if (format === "list") {
245
252
  for (const perm of permissions) {
246
- const levelColor = getLevelColor(perm.level);
247
- console.log(`${chalk.cyan(perm.resource)}: ${levelColor(perm.level)}`);
248
- if (verbose && perm.metadata) {
249
- console.log(chalk.gray(` Metadata: ${JSON.stringify(perm.metadata)}`));
253
+ const typeColor = getTypeColor(perm.type);
254
+ console.log(`${chalk.cyan(perm.pattern)}: ${typeColor(perm.type)}`);
255
+ if (verbose && perm.description) {
256
+ console.log(chalk.gray(` Description: ${perm.description}`));
250
257
  }
251
258
  }
252
259
  } else {
253
- console.log(chalk.bold("Resource".padEnd(40)) + chalk.bold("Level".padEnd(15)) + chalk.bold("Granted At"));
260
+ console.log(chalk.bold("Pattern".padEnd(40)) + chalk.bold("Type".padEnd(15)) + chalk.bold("Scope"));
254
261
  console.log("\u2500".repeat(70));
255
262
  for (const perm of permissions) {
256
- const levelColor = getLevelColor(perm.level);
257
- const resource = perm.resource.padEnd(40);
258
- const level = levelColor(perm.level.padEnd(15));
259
- const grantedAt = new Date(perm.grantedAt).toLocaleString();
260
- console.log(`${resource}${level}${grantedAt}`);
261
- if (verbose && perm.metadata) {
262
- console.log(chalk.gray(` Metadata: ${JSON.stringify(perm.metadata)}`));
263
+ const typeColor = getTypeColor(perm.type);
264
+ const pattern = perm.pattern.padEnd(40);
265
+ const type = typeColor(perm.type.padEnd(15));
266
+ const scope = perm.scope;
267
+ console.log(`${pattern}${type}${scope}`);
268
+ if (verbose && perm.description) {
269
+ console.log(chalk.gray(` Description: ${perm.description}`));
263
270
  }
264
271
  }
265
272
  }
@@ -271,24 +278,22 @@ async function checkPermission(resource, options) {
271
278
  console.log("Usage: ccjk permissions check <resource>");
272
279
  process__default.exit(1);
273
280
  }
281
+ const action = options.action || "read";
274
282
  const verbose = options.verbose || false;
275
283
  console.log(chalk.bold(`
276
284
  \u{1F50D} Checking permission for: ${chalk.cyan(resource)}
277
285
  `));
278
- const hasPermission = await permissionManager.checkPermission(resource, "read");
279
- const permission = permissionManager.getPermission(resource);
280
- if (hasPermission) {
286
+ const result = permissionManager.checkPermission(action, resource);
287
+ if (result.allowed) {
281
288
  console.log(chalk.green("\u2713 Permission granted"));
282
- if (permission) {
283
- const levelColor = getLevelColor(permission.level);
284
- console.log(` Level: ${levelColor(permission.level)}`);
285
- console.log(` Granted at: ${new Date(permission.grantedAt).toLocaleString()}`);
286
- if (verbose && permission.metadata) {
287
- console.log(` Metadata: ${JSON.stringify(permission.metadata, null, 2)}`);
288
- }
289
+ console.log(` Reason: ${result.reason}`);
290
+ if (verbose && result.matchedRule) {
291
+ console.log(` Matched rule: ${result.matchedRule.pattern}`);
292
+ console.log(` Rule type: ${result.matchedRule.type}`);
289
293
  }
290
294
  } else {
291
295
  console.log(chalk.red("\u2717 Permission denied"));
296
+ console.log(` Reason: ${result.reason}`);
292
297
  console.log(chalk.yellow(' Use "ccjk permissions grant" to grant permission'));
293
298
  }
294
299
  console.log();
@@ -302,10 +307,13 @@ async function grantPermission(resource, _options) {
302
307
  console.log(chalk.bold(`
303
308
  \u2713 Granting permission for: ${chalk.cyan(resource)}
304
309
  `));
305
- await permissionManager.grantPermission(resource, "full", {
306
- grantedBy: "cli",
307
- grantedAt: (/* @__PURE__ */ new Date()).toISOString()
308
- });
310
+ const permission = {
311
+ type: "allow",
312
+ pattern: resource,
313
+ scope: "global",
314
+ description: "Granted via CLI"
315
+ };
316
+ permissionManager.addPermission(permission);
309
317
  console.log(chalk.green("Permission granted successfully!"));
310
318
  console.log();
311
319
  }
@@ -318,8 +326,12 @@ async function revokePermission(resource, _options) {
318
326
  console.log(chalk.bold(`
319
327
  \u2717 Revoking permission for: ${chalk.cyan(resource)}
320
328
  `));
321
- await permissionManager.revokePermission(resource);
322
- console.log(chalk.green("Permission revoked successfully!"));
329
+ const removed = permissionManager.removePermission(resource);
330
+ if (removed > 0) {
331
+ console.log(chalk.green(`Permission revoked successfully! (${removed} rule(s) removed)`));
332
+ } else {
333
+ console.log(chalk.yellow("No matching permission found."));
334
+ }
323
335
  console.log();
324
336
  }
325
337
  async function resetPermissions(_options) {
@@ -337,7 +349,7 @@ async function resetPermissions(_options) {
337
349
  console.log(chalk.gray("Operation cancelled."));
338
350
  return;
339
351
  }
340
- await permissionManager.clearAllPermissions();
352
+ permissionManager.clearPermissions();
341
353
  console.log(chalk.green("All permissions have been reset!"));
342
354
  console.log();
343
355
  }
@@ -348,9 +360,10 @@ async function exportPermissions(filePath, _options) {
348
360
  console.log(chalk.bold(`
349
361
  \u{1F4E4} Exporting permissions to: ${chalk.cyan(outputPath)}
350
362
  `));
351
- const permissions = permissionManager.getAllPermissions();
363
+ const permissions = permissionManager.exportPermissions();
352
364
  await fs.writeFile(outputPath, JSON.stringify(permissions, null, 2), "utf-8");
353
- console.log(chalk.green(`Exported ${permissions.length} permissions successfully!`));
365
+ const totalCount = permissions.allow.length + permissions.deny.length;
366
+ console.log(chalk.green(`Exported ${totalCount} permissions successfully!`));
354
367
  console.log();
355
368
  }
356
369
  async function importPermissions(filePath, _options) {
@@ -365,15 +378,13 @@ async function importPermissions(filePath, _options) {
365
378
  `));
366
379
  try {
367
380
  const content = await fs.readFile(filePath, "utf-8");
368
- const permissions = JSON.parse(content);
369
- if (!Array.isArray(permissions)) {
370
- throw new TypeError("Invalid permissions file format");
371
- }
372
- await permissionManager.clearAllPermissions();
373
- for (const perm of permissions) {
374
- await permissionManager.grantPermission(perm.resource, perm.level, perm.metadata);
381
+ const config = JSON.parse(content);
382
+ if (!config.allow && !config.deny) {
383
+ throw new TypeError("Invalid permissions file format. Expected { allow: [], deny: [] }");
375
384
  }
376
- console.log(chalk.green(`Imported ${permissions.length} permissions successfully!`));
385
+ permissionManager.importPermissions(config, false);
386
+ const totalCount = (config.allow?.length || 0) + (config.deny?.length || 0);
387
+ console.log(chalk.green(`Imported ${totalCount} permissions successfully!`));
377
388
  } catch (error) {
378
389
  console.error(chalk.red("Error importing permissions:"), error);
379
390
  process__default.exit(1);
@@ -394,24 +405,21 @@ function permissionsHelp(_options) {
394
405
  console.log(" import <file> Import permissions from a file\n");
395
406
  console.log(chalk.bold("Options:"));
396
407
  console.log(" --format, -f Output format (table|json|list)");
397
- console.log(" --verbose, -v Verbose output\n");
408
+ console.log(" --verbose, -v Verbose output");
409
+ console.log(" --action, -a Action to check (read|write|admin)\n");
398
410
  console.log(chalk.bold("Examples:"));
399
411
  console.log(" ccjk permissions list");
400
- console.log(" ccjk permissions check file:///path/to/file");
401
- console.log(" ccjk permissions grant mcp://server-name");
412
+ console.log(' ccjk permissions check "Provider(302ai):*"');
413
+ console.log(' ccjk permissions grant "Provider(302ai):*"');
402
414
  console.log(" ccjk permissions export permissions.json");
403
415
  console.log(" ccjk permissions import permissions.json\n");
404
416
  }
405
- function getLevelColor(level) {
406
- switch (level) {
407
- case "none":
408
- return chalk.red;
409
- case "read":
410
- return chalk.yellow;
411
- case "write":
412
- return chalk.blue;
413
- case "full":
417
+ function getTypeColor(type) {
418
+ switch (type) {
419
+ case "allow":
414
420
  return chalk.green;
421
+ case "deny":
422
+ return chalk.red;
415
423
  default:
416
424
  return chalk.gray;
417
425
  }
@@ -338,8 +338,8 @@ Create a new session with: ${ansis.cyan("ccjk session create")}`));
338
338
  }
339
339
  console.log(ansis.cyan.bold("\n\u{1F4CB} Saved Sessions:\n"));
340
340
  const sortedSessions = [...sessions].sort((a, b) => {
341
- const aTime = a.lastAccessedAt?.getTime() || a.createdAt.getTime();
342
- const bTime = b.lastAccessedAt?.getTime() || b.createdAt.getTime();
341
+ const aTime = a.lastUsedAt?.getTime() || a.createdAt.getTime();
342
+ const bTime = b.lastUsedAt?.getTime() || b.createdAt.getTime();
343
343
  return bTime - aTime;
344
344
  });
345
345
  for (const session of sortedSessions) {
@@ -351,8 +351,8 @@ Create a new session with: ${ansis.cyan("ccjk session create")}`));
351
351
  }
352
352
  const createdDate = session.createdAt.toLocaleString();
353
353
  console.log(ansis.gray(` Created: ${createdDate}`));
354
- if (session.lastAccessedAt) {
355
- const accessedDate = session.lastAccessedAt.toLocaleString();
354
+ if (session.lastUsedAt) {
355
+ const accessedDate = session.lastUsedAt.toLocaleString();
356
356
  console.log(ansis.gray(` Last accessed: ${accessedDate}`));
357
357
  }
358
358
  if (session.history.length > 0) {
package/dist/cli.mjs CHANGED
@@ -326,34 +326,18 @@ const COMMANDS = [
326
326
  tier: "extended",
327
327
  options: [
328
328
  { flags: "--format, -f <format>", description: "Output format (table|json)" },
329
- { flags: "--code-type, -T <type>", description: "Code tool type" }
329
+ { flags: "--code-type, -T <type>", description: "Code tool type" },
330
+ { flags: "--verbose, -v", description: "Verbose output" }
330
331
  ],
331
332
  loader: async () => {
332
- return async (options, action, args) => {
333
+ return async (options, action) => {
333
334
  const actionStr = action;
334
- const argsArr = args;
335
- if (!actionStr || actionStr === "list") {
336
- const { listProviders } = await import('./chunks/providers.mjs');
337
- await listProviders(options);
338
- } else if (actionStr === "add") {
339
- const { addProvider } = await import('./chunks/providers.mjs');
340
- await addProvider(options);
341
- } else if (actionStr === "remove") {
342
- const { removeProvider } = await import('./chunks/providers.mjs');
343
- await removeProvider(argsArr[0] || "", options);
344
- } else if (actionStr === "edit") {
345
- const { editProvider } = await import('./chunks/providers.mjs');
346
- await editProvider(argsArr[0] || "", options);
347
- } else if (actionStr === "test") {
348
- const { testProvider } = await import('./chunks/providers.mjs');
349
- await testProvider(argsArr[0] || "", options);
350
- } else if (actionStr === "health") {
351
- const { checkProviderHealth } = await import('./chunks/providers.mjs');
352
- await checkProviderHealth(options);
353
- } else {
354
- console.error(`Unknown providers action: ${actionStr}`);
355
- console.log("Available actions: list, add, remove, edit, test, health");
356
- }
335
+ const { providersCommand } = await import('./chunks/providers.mjs');
336
+ await providersCommand(actionStr || "list", {
337
+ lang: options.lang,
338
+ codeType: options.codeType,
339
+ verbose: options.verbose
340
+ });
357
341
  };
358
342
  }
359
343
  },
@@ -897,21 +881,6 @@ ${chalk.yellow("By Status:")}`);
897
881
  };
898
882
  }
899
883
  },
900
- // ==================== API Provider Management ====================
901
- {
902
- name: "providers [action]",
903
- description: "Manage API providers",
904
- tier: "extended",
905
- options: [
906
- { flags: "--json", description: "Output in JSON format" }
907
- ],
908
- loader: async () => {
909
- const { providersCommand } = await import('./chunks/providers.mjs');
910
- return async (options, action) => {
911
- await providersCommand(action, options);
912
- };
913
- }
914
- },
915
884
  // ==================== Configuration Management ====================
916
885
  {
917
886
  name: "config [action] [key] [value]",
@@ -928,7 +897,12 @@ ${chalk.yellow("By Status:")}`);
928
897
  args.push(key);
929
898
  if (value !== void 0)
930
899
  args.push(value);
931
- await configCommand(action, args, options);
900
+ await configCommand(action || "list", args, {
901
+ lang: options.lang,
902
+ codeType: options.codeType,
903
+ global: options.global,
904
+ json: options.json
905
+ });
932
906
  };
933
907
  }
934
908
  }
@@ -0,0 +1,54 @@
1
+ {
2
+ "versionCheck.checking": "Checking version...",
3
+ "versionCheck.usingSource": "Using source: {{source}}",
4
+ "versionCheck.usingMirror": "Using mirror: {{source}}",
5
+ "versionCheck.fallbackToGitHub": "npm source unavailable, using GitHub API",
6
+ "versionCheck.usingCache": "Using cached version info ({{age}} ago)",
7
+ "versionCheck.cacheExpired": "Cache expired, fetching again",
8
+ "versionCheck.networkError": "Network error, please check connection",
9
+ "versionCheck.timeout": "Request timeout, trying next source",
10
+ "versionCheck.success": "Successfully fetched version: {{version}}",
11
+ "versionCheck.failed": "Unable to fetch latest version",
12
+ "chinaDetector.detected": "China user detected, prioritizing domestic mirrors",
13
+ "chinaDetector.envOverride": "Environment variable override: CCJK_CHINA_MODE={{mode}}",
14
+ "chinaDetector.usingDefault": "Using default source order",
15
+ "queryingVersion": "Querying latest version for {{package}}",
16
+ "tryingSource": "Trying registry source: {{source}}",
17
+ "sourceSuccess": "Successfully got version {{version}} from {{source}}",
18
+ "sourceFailed": "Registry source {{source}} failed, trying next",
19
+ "allSourcesFailed": "All registry sources failed for {{package}}",
20
+ "cacheHit": "Using cached version for {{package}}",
21
+ "chinaUserDetected": "China user detected, prioritizing domestic mirrors",
22
+ "globalUserDetected": "Global user detected, prioritizing npm registry",
23
+ "queryFailed": "Query to {{registry}} failed with status {{status}}",
24
+ "timeout": "Query to {{registry}} timed out after {{timeout}}ms",
25
+ "error": "Query to {{registry}} failed: {{error}}",
26
+ "githubNoMapping": "No GitHub repository mapping for package {{package}}",
27
+ "githubQueryFailed": "GitHub API query failed with status {{status}}",
28
+ "githubError": "GitHub API error: {{error}}",
29
+ "registryReachable": "Registry {{source}} is reachable",
30
+ "registryUnreachable": "Registry {{source}} is not reachable",
31
+ "checkingReachability": "Checking registry reachability...",
32
+ "multipleInstallations.detected": "⚠️ Multiple Claude Code installations detected",
33
+ "multipleInstallations.count": "Found {{count}} installations",
34
+ "multipleInstallations.installation": "Installation {{index}}",
35
+ "multipleInstallations.source": "Source: {{source}}",
36
+ "multipleInstallations.path": "Path: {{path}}",
37
+ "multipleInstallations.version": "Version: {{version}}",
38
+ "multipleInstallations.active": "(currently active)",
39
+ "multipleInstallations.inactive": "(inactive)",
40
+ "multipleInstallations.action": "How to proceed?",
41
+ "multipleInstallations.options.cleanup": "Keep recommended version and remove others",
42
+ "multipleInstallations.options.keep": "Keep current state",
43
+ "multipleInstallations.options.details": "View details",
44
+ "multipleInstallations.cleaning": "Cleaning up duplicate installations...",
45
+ "multipleInstallations.cleaned": "Cleanup completed",
46
+ "multipleInstallations.kept": "Keeping existing installations unchanged",
47
+ "multipleInstallations.recommendation": "Recommended: Keep {{source}} installation",
48
+ "sources.npm": "npm official registry",
49
+ "sources.taobao": "Taobao mirror",
50
+ "sources.huawei": "Huawei Cloud mirror",
51
+ "sources.github": "GitHub API",
52
+ "sources.homebrew-cask": "Homebrew Cask",
53
+ "sources.curl": "Official script installation"
54
+ }
@@ -0,0 +1,54 @@
1
+ {
2
+ "versionCheck.checking": "正在检查版本...",
3
+ "versionCheck.usingSource": "使用源: {{source}}",
4
+ "versionCheck.usingMirror": "使用镜像源: {{source}}",
5
+ "versionCheck.fallbackToGitHub": "npm 源不可用,使用 GitHub API",
6
+ "versionCheck.usingCache": "使用缓存版本信息 ({{age}}前)",
7
+ "versionCheck.cacheExpired": "缓存已过期,重新获取",
8
+ "versionCheck.networkError": "网络错误,请检查连接",
9
+ "versionCheck.timeout": "请求超时,尝试下一个源",
10
+ "versionCheck.success": "成功获取版本: {{version}}",
11
+ "versionCheck.failed": "无法获取最新版本",
12
+ "chinaDetector.detected": "检测到中国用户,优先使用国内镜像",
13
+ "chinaDetector.envOverride": "环境变量覆盖: CCJK_CHINA_MODE={{mode}}",
14
+ "chinaDetector.usingDefault": "使用默认源顺序",
15
+ "queryingVersion": "正在查询 {{package}} 的最新版本",
16
+ "tryingSource": "正在尝试镜像源: {{source}}",
17
+ "sourceSuccess": "成功从 {{source}} 获取版本 {{version}}",
18
+ "sourceFailed": "镜像源 {{source}} 失败,尝试下一个",
19
+ "allSourcesFailed": "所有镜像源均无法获取 {{package}} 的版本",
20
+ "cacheHit": "使用 {{package}} 的缓存版本",
21
+ "chinaUserDetected": "检测到中国用户,优先使用国内镜像",
22
+ "globalUserDetected": "检测到海外用户,优先使用 npm 官方源",
23
+ "queryFailed": "查询 {{registry}} 失败,状态码 {{status}}",
24
+ "timeout": "查询 {{registry}} 超时 ({{timeout}}ms)",
25
+ "error": "查询 {{registry}} 出错: {{error}}",
26
+ "githubNoMapping": "包 {{package}} 没有对应的 GitHub 仓库映射",
27
+ "githubQueryFailed": "GitHub API 查询失败,状态码 {{status}}",
28
+ "githubError": "GitHub API 错误: {{error}}",
29
+ "registryReachable": "镜像源 {{source}} 可访问",
30
+ "registryUnreachable": "镜像源 {{source}} 不可访问",
31
+ "checkingReachability": "正在检查镜像源可用性...",
32
+ "multipleInstallations.detected": "⚠️ 检测到多个 Claude Code 安装",
33
+ "multipleInstallations.count": "发现 {{count}} 个安装",
34
+ "multipleInstallations.installation": "安装 {{index}}",
35
+ "multipleInstallations.source": "来源: {{source}}",
36
+ "multipleInstallations.path": "路径: {{path}}",
37
+ "multipleInstallations.version": "版本: {{version}}",
38
+ "multipleInstallations.active": "(当前活跃)",
39
+ "multipleInstallations.inactive": "(未激活)",
40
+ "multipleInstallations.action": "如何处理?",
41
+ "multipleInstallations.options.cleanup": "保留推荐版本并移除其他",
42
+ "multipleInstallations.options.keep": "保持现状",
43
+ "multipleInstallations.options.details": "查看详细信息",
44
+ "multipleInstallations.cleaning": "正在清理重复安装...",
45
+ "multipleInstallations.cleaned": "已清理完成",
46
+ "multipleInstallations.kept": "保持现有安装不变",
47
+ "multipleInstallations.recommendation": "推荐: 保留 {{source}} 安装",
48
+ "sources.npm": "npm 官方源",
49
+ "sources.taobao": "淘宝镜像",
50
+ "sources.huawei": "华为云镜像",
51
+ "sources.github": "GitHub API",
52
+ "sources.homebrew-cask": "Homebrew Cask",
53
+ "sources.curl": "官方脚本安装"
54
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ccjk",
3
3
  "type": "module",
4
- "version": "2.5.0",
4
+ "version": "2.6.0",
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": {