ccjk 10.2.0 → 10.3.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.
package/README.md CHANGED
@@ -133,6 +133,26 @@ ccjk mcp install filesystem puppeteer postgres
133
133
  # Done. No manual config.
134
134
  ```
135
135
 
136
+ ### 🔓 Zero-Config Permission Presets (NEW)
137
+ One-click permission configuration for different use cases:
138
+ ```bash
139
+ ccjk zc --list # View available presets
140
+ ccjk zc --preset max # Maximum permissions (all commands)
141
+ ccjk zc --preset dev # Developer preset (build tools, git, npm)
142
+ ccjk zc --preset safe # Safe preset (read-only operations)
143
+ ```
144
+
145
+ **Available Presets:**
146
+ - **max** — All common commands, file operations, and MCP servers (100+ permissions)
147
+ - **dev** — Build tools, git, package managers, and file operations (50+ permissions)
148
+ - **safe** — Read-only commands, no file modifications (20+ permissions)
149
+
150
+ Each preset automatically:
151
+ - ✅ Backs up your current settings
152
+ - ✅ Merges with existing permissions (no data loss)
153
+ - ✅ Removes invalid/dangerous patterns
154
+ - ✅ Shows exactly what will be added
155
+
136
156
  ## 📖 Essential Commands
137
157
 
138
158
  ```bash
@@ -158,6 +178,14 @@ ccjk mcp list
158
178
  # Memory & Context
159
179
  ccjk memory --enable
160
180
  ccjk compact # Clean up conversation
181
+
182
+ # Zero-Config Permission Presets (NEW)
183
+ ccjk zc --list # List available presets
184
+ ccjk zc --preset max # Apply maximum permissions
185
+ ccjk zc --preset dev # Apply developer preset
186
+ ccjk zc --preset safe # Apply safe (read-only) preset
187
+
188
+ # Other Commands
161
189
  npx ccjk u # Update workflows
162
190
  npx ccjk sync # Cloud sync
163
191
  npx ccjk doctor # Health check
@@ -27,6 +27,7 @@ import './json-config.mjs';
27
27
  import './config.mjs';
28
28
  import './claude-config.mjs';
29
29
  import './platform.mjs';
30
+ import '../shared/ccjk.BiCrMV5O.mjs';
30
31
  import '../shared/ccjk.BFQ7yr5S.mjs';
31
32
  import './prompts.mjs';
32
33
  import '../shared/ccjk.DHbrGcgg.mjs';
@@ -39,7 +40,7 @@ import './features.mjs';
39
40
  import './config2.mjs';
40
41
  import 'node:util';
41
42
  import './init.mjs';
42
- import '../shared/ccjk.IbImMVWM.mjs';
43
+ import '../shared/ccjk.DVBW2wxp.mjs';
43
44
  import './auto-updater.mjs';
44
45
  import './version-checker.mjs';
45
46
  import 'node:path';
@@ -33,6 +33,7 @@ import 'semver';
33
33
  import 'inquirer';
34
34
  import './config.mjs';
35
35
  import './claude-config.mjs';
36
+ import '../shared/ccjk.BiCrMV5O.mjs';
36
37
  import '../shared/ccjk.BFQ7yr5S.mjs';
37
38
  import './prompts.mjs';
38
39
  import './package.mjs';
@@ -20,6 +20,7 @@ import 'inquirer';
20
20
  import './claude-config.mjs';
21
21
  import './platform.mjs';
22
22
  import 'tinyexec';
23
+ import '../shared/ccjk.BiCrMV5O.mjs';
23
24
 
24
25
  class ClaudeCodeConfigManager {
25
26
  static CONFIG_FILE = ZCF_CONFIG_FILE;
@@ -4,7 +4,7 @@ import { ensureI18nInitialized, i18n } from './index2.mjs';
4
4
  import { ClaudeCodeConfigManager } from './claude-code-config-manager.mjs';
5
5
  import { a as addNumbersToChoices } from '../shared/ccjk.BFQ7yr5S.mjs';
6
6
  import { p as promptBoolean } from '../shared/ccjk.DHbrGcgg.mjs';
7
- import { v as validateApiKey } from '../shared/ccjk.IbImMVWM.mjs';
7
+ import { v as validateApiKey } from '../shared/ccjk.DVBW2wxp.mjs';
8
8
  import 'node:fs';
9
9
  import 'node:process';
10
10
  import 'node:url';
@@ -24,6 +24,7 @@ import './config.mjs';
24
24
  import './claude-config.mjs';
25
25
  import './platform.mjs';
26
26
  import 'tinyexec';
27
+ import '../shared/ccjk.BiCrMV5O.mjs';
27
28
  import 'inquirer-toggle';
28
29
 
29
30
  function getAuthTypeLabel(authType) {
@@ -27,6 +27,7 @@ import './ccjk-config.mjs';
27
27
  import './config.mjs';
28
28
  import './claude-config.mjs';
29
29
  import './platform.mjs';
30
+ import '../shared/ccjk.BiCrMV5O.mjs';
30
31
  import './prompts.mjs';
31
32
  import './package.mjs';
32
33
  import 'node:child_process';
@@ -23,6 +23,7 @@ import './json-config.mjs';
23
23
  import './config.mjs';
24
24
  import './claude-config.mjs';
25
25
  import './platform.mjs';
26
+ import '../shared/ccjk.BiCrMV5O.mjs';
26
27
  import '../shared/ccjk.BFQ7yr5S.mjs';
27
28
  import './prompts.mjs';
28
29
  import './package.mjs';
@@ -24,6 +24,7 @@ import './config.mjs';
24
24
  import './claude-config.mjs';
25
25
  import './platform.mjs';
26
26
  import 'tinyexec';
27
+ import '../shared/ccjk.BiCrMV5O.mjs';
27
28
  import 'ora';
28
29
  import 'semver';
29
30
  import './prompts.mjs';
@@ -8,6 +8,7 @@ import { ensureI18nInitialized, i18n } from './index2.mjs';
8
8
  import { s as setPrimaryApiKey, c as addCompletedOnboarding, d as deepMerge } from './claude-config.mjs';
9
9
  import { exists, ensureDir, copyDir, writeFileAtomic, copyFile } from './fs-operations.mjs';
10
10
  import { readJsonConfig, writeJsonConfig } from './json-config.mjs';
11
+ import { m as mergeAndCleanPermissions } from '../shared/ccjk.BiCrMV5O.mjs';
11
12
 
12
13
  const MODEL_ENV_KEYS = [
13
14
  "ANTHROPIC_MODEL",
@@ -23,99 +24,6 @@ function clearModelEnv(env) {
23
24
  }
24
25
  }
25
26
 
26
- const INVALID_PERMISSION_NAMES = /* @__PURE__ */ new Set([
27
- "AllowEdit",
28
- "AllowWrite",
29
- "AllowRead",
30
- "AllowExec",
31
- "AllowCreateProcess",
32
- "AllowKillProcess",
33
- "AllowNetworkAccess",
34
- "AllowFileSystemAccess",
35
- "AllowShellAccess",
36
- "AllowHttpAccess"
37
- ]);
38
- const DANGEROUS_BASH_PATTERNS = /* @__PURE__ */ new Set([
39
- "Bash(passwd *)",
40
- "Bash(reboot *)",
41
- "Bash(shutdown *)",
42
- "Bash(halt *)",
43
- "Bash(poweroff *)",
44
- "Bash(init *)",
45
- "Bash(telinit *)",
46
- "Bash(rm *)",
47
- "Bash(kill *)",
48
- "Bash(pkill *)",
49
- "Bash(killall *)",
50
- "Bash(su *)",
51
- "Bash(sudo *)",
52
- "Bash(visudo *)",
53
- "Bash(useradd *)",
54
- "Bash(userdel *)",
55
- "Bash(usermod *)",
56
- "Bash(groupadd *)",
57
- "Bash(groupdel *)",
58
- "Bash(groupmod *)",
59
- "Bash(modprobe *)",
60
- "Bash(insmod *)",
61
- "Bash(rmmod *)"
62
- ]);
63
- function isValidPermission(perm) {
64
- if (INVALID_PERMISSION_NAMES.has(perm)) {
65
- return false;
66
- }
67
- if (["mcp__.*", "mcp__*", "mcp__(*)"].includes(perm)) {
68
- return false;
69
- }
70
- if (/^[a-z]/.test(perm) && !perm.startsWith("mcp__")) {
71
- return false;
72
- }
73
- return true;
74
- }
75
- function isCoveredByWildcard(perm, wildcardPerm) {
76
- const wildcardMatch = wildcardPerm.match(/^(\w+)\((.+)\)$/);
77
- if (!wildcardMatch) return false;
78
- const [, tool, wildcardArg] = wildcardMatch;
79
- if (!wildcardArg.includes("*")) return false;
80
- const permMatch = perm.match(/^(\w+)\((.+)\)$/);
81
- if (!permMatch) return false;
82
- const [, permTool, permArg] = permMatch;
83
- if (tool !== permTool) return false;
84
- const regexStr = wildcardArg.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".+");
85
- return new RegExp(`^${regexStr}$`).test(permArg);
86
- }
87
- function mergeAndCleanPermissions(templatePermissions, userPermissions) {
88
- const template = templatePermissions || [];
89
- const user = userPermissions || [];
90
- const result = [...template];
91
- for (const perm of user) {
92
- if (result.includes(perm)) {
93
- continue;
94
- }
95
- if (!isValidPermission(perm)) {
96
- continue;
97
- }
98
- if (DANGEROUS_BASH_PATTERNS.has(perm)) {
99
- continue;
100
- }
101
- let isRedundant = false;
102
- for (const templatePerm of template) {
103
- if (perm.startsWith(`${templatePerm}(`)) {
104
- isRedundant = true;
105
- break;
106
- }
107
- if (isCoveredByWildcard(perm, templatePerm)) {
108
- isRedundant = true;
109
- break;
110
- }
111
- }
112
- if (!isRedundant) {
113
- result.push(perm);
114
- }
115
- }
116
- return result;
117
- }
118
-
119
27
  function ensureClaudeDir() {
120
28
  ensureDir(CLAUDE_DIR);
121
29
  }
@@ -468,4 +376,4 @@ const config = {
468
376
  updateDefaultModel: updateDefaultModel
469
377
  };
470
378
 
471
- export { applyAiLanguageDirective as a, backupExistingConfig as b, copyConfigFiles as c, updateDefaultModel as d, getExistingApiConfig as e, configureApi as f, getExistingModelConfig as g, clearModelEnv as h, ensureClaudeDir as i, config as j, mergeAndCleanPermissions as m, promptApiConfigurationAction as p, switchToOfficialLogin as s, updateCustomModel as u };
379
+ export { applyAiLanguageDirective as a, backupExistingConfig as b, copyConfigFiles as c, updateDefaultModel as d, getExistingApiConfig as e, configureApi as f, getExistingModelConfig as g, clearModelEnv as h, ensureClaudeDir as i, config as j, promptApiConfigurationAction as p, switchToOfficialLogin as s, updateCustomModel as u };
@@ -21,6 +21,7 @@ import 'tinyexec';
21
21
  import './fs-operations.mjs';
22
22
  import 'node:crypto';
23
23
  import 'node:fs/promises';
24
+ import '../shared/ccjk.BiCrMV5O.mjs';
24
25
  import 'inquirer-toggle';
25
26
 
26
27
  const PROVIDER_PRESETS_URL = "https://pub-0dc3e1677e894f07bbea11b17a29e032.r2.dev/providers.json";
@@ -19,6 +19,7 @@ import 'node:crypto';
19
19
  import 'node:fs/promises';
20
20
  import './platform.mjs';
21
21
  import 'tinyexec';
22
+ import '../shared/ccjk.BiCrMV5O.mjs';
22
23
 
23
24
  async function getConfig(key, options = {}) {
24
25
  const isZh = i18n.language === "zh-CN";
@@ -12,7 +12,7 @@ import { setupCcrConfiguration } from './config2.mjs';
12
12
  import { a as isCcrInstalled, b as installCcr } from './init.mjs';
13
13
  import { r as readMcpConfig, f as fixWindowsMcpConfig, w as writeMcpConfig, b as backupMcpConfig, a as buildMcpServerConfig, m as mergeMcpServers } from './claude-config.mjs';
14
14
  import { a as applyAiLanguageDirective, g as getExistingModelConfig, u as updateCustomModel, d as updateDefaultModel, e as getExistingApiConfig, p as promptApiConfigurationAction, f as configureApi, s as switchToOfficialLogin } from './config.mjs';
15
- import { c as configureOutputStyle, a as modifyApiConfigPartially, v as validateApiKey, f as formatApiKeyDisplay } from '../shared/ccjk.IbImMVWM.mjs';
15
+ import { c as configureOutputStyle, a as modifyApiConfigPartially, v as validateApiKey, f as formatApiKeyDisplay } from '../shared/ccjk.DVBW2wxp.mjs';
16
16
  import { i as isWindows } from './platform.mjs';
17
17
  import { a as addNumbersToChoices } from '../shared/ccjk.BFQ7yr5S.mjs';
18
18
  import { openSettingsJson, importRecommendedPermissions, importRecommendedEnv } from './simple-config.mjs';
@@ -43,6 +43,7 @@ import '../shared/ccjk.DKojSRzw.mjs';
43
43
  import '../shared/ccjk.DrMygfCF.mjs';
44
44
  import './installer.mjs';
45
45
  import '../shared/ccjk.BKoi8-Hy.mjs';
46
+ import '../shared/ccjk.BiCrMV5O.mjs';
46
47
  import 'inquirer-toggle';
47
48
 
48
49
  async function handleCancellation() {
@@ -4,7 +4,7 @@ import ansis from 'ansis';
4
4
  import inquirer from 'inquirer';
5
5
  import { version } from './package.mjs';
6
6
  import { m as runCodexFullInit, d as selectMcpServices, g as getMcpServices, M as MCP_SERVICE_CONFIGS } from './codex.mjs';
7
- import { a as modifyApiConfigPartially, b as configureApiCompletely, n as needsMigration, m as migrateSettingsForTokenRetrieval, d as displayMigrationResult, p as promptMigration, s as selectAndInstallWorkflows, c as configureOutputStyle, f as formatApiKeyDisplay, W as WORKFLOW_CONFIG_BASE } from '../shared/ccjk.IbImMVWM.mjs';
7
+ import { a as modifyApiConfigPartially, b as configureApiCompletely, n as needsMigration, m as migrateSettingsForTokenRetrieval, d as displayMigrationResult, p as promptMigration, s as selectAndInstallWorkflows, c as configureOutputStyle, f as formatApiKeyDisplay, W as WORKFLOW_CONFIG_BASE } from '../shared/ccjk.DVBW2wxp.mjs';
8
8
  import { SETTINGS_FILE, DEFAULT_CODE_TOOL_TYPE, CODE_TOOL_BANNERS, API_DEFAULT_URL } from './constants.mjs';
9
9
  import { ensureI18nInitialized, i18n } from './index2.mjs';
10
10
  import { displayBannerWithInfo, padToDisplayWidth } from './banner.mjs';
@@ -26,6 +26,7 @@ import 'semver';
26
26
  import 'smol-toml';
27
27
  import './ccjk-config.mjs';
28
28
  import './config.mjs';
29
+ import '../shared/ccjk.BiCrMV5O.mjs';
29
30
  import '../shared/ccjk.BFQ7yr5S.mjs';
30
31
  import './prompts.mjs';
31
32
  import './package.mjs';
@@ -363,6 +363,7 @@ async function showSimplifiedMenu() {
363
363
  console.log(` ${ansis.green("5.")} ${isZh ? "\u914D\u7F6E\u9ED8\u8BA4\u6A21\u578B" : "Configure Default Model"} ${ansis.dim(isZh ? "- \u8BBE\u7F6E\u9ED8\u8BA4\u6A21\u578B\uFF08opus/sonnet/sonnet 1m/\u81EA\u5B9A\u4E49\uFF09" : "- Set default model (opus/sonnet/sonnet 1m/custom)")}`);
364
364
  console.log(` ${ansis.green("6.")} ${isZh ? "\u914D\u7F6E Claude \u5168\u5C40\u8BB0\u5FC6" : "Configure Claude Memory"} ${ansis.dim(isZh ? "- \u914D\u7F6E AI \u8F93\u51FA\u8BED\u8A00\u548C\u8F93\u51FA\u98CE\u683C" : "- Configure AI output language and style")}`);
365
365
  console.log(` ${ansis.green("7.")} ${isZh ? "\u5BFC\u5165\u63A8\u8350\u73AF\u5883\u53D8\u91CF\u548C\u6743\u9650\u914D\u7F6E" : "Import Recommended Env & Permissions"} ${ansis.dim(isZh ? "- \u5BFC\u5165\u9690\u79C1\u4FDD\u62A4\u73AF\u5883\u53D8\u91CF\u548C\u7CFB\u7EDF\u6743\u9650\u914D\u7F6E" : "- Import privacy env vars and system permissions")}`);
366
+ console.log(` ${ansis.green("8.")} ${isZh ? "\u96F6\u914D\u7F6E\u6743\u9650\u9884\u8BBE" : "Zero-Config Permission Presets"} ${ansis.dim(isZh ? "- \u4E00\u952E\u5E94\u7528\u6743\u9650\u9884\u8BBE\uFF08\u6700\u5927/\u5F00\u53D1\u8005/\u5B89\u5168\uFF09" : "- One-click permission presets (max/dev/safe)")}`);
366
367
  console.log("");
367
368
  console.log(ansis.dim(` --------- ${isZh ? "\u5176\u4ED6\u5DE5\u5177" : "Other Tools"} ----------`));
368
369
  console.log(` ${ansis.green("K.")} ${isZh ? "Skills \u7BA1\u7406" : "Skills Manager"} ${ansis.dim(isZh ? "- \u5B89\u88C5/\u66F4\u65B0/\u5220\u9664\u5DE5\u4F5C\u6D41\u6280\u80FD" : "- Install/update/remove workflow skills")}`);
@@ -387,7 +388,7 @@ async function showSimplifiedMenu() {
387
388
  message: isZh ? "\u8BF7\u8F93\u5165\u9009\u9879:" : "Enter option:",
388
389
  validate: (value) => {
389
390
  const normalized2 = normalizeMenuInput(value);
390
- const valid = ["0", "1", "2", "3", "4", "5", "6", "7", "k", "m", "a", "p", "r", "b", "s", "-", "+", "d", "h", "q"];
391
+ const valid = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "k", "m", "a", "p", "r", "b", "s", "-", "+", "d", "h", "q"];
391
392
  return valid.includes(normalized2) || (isZh ? "\u8BF7\u8F93\u5165\u6709\u6548\u9009\u9879" : "Please enter a valid option");
392
393
  }
393
394
  });
@@ -426,6 +427,11 @@ async function showSimplifiedMenu() {
426
427
  await configureEnvPermissionFeature();
427
428
  break;
428
429
  }
430
+ case "8": {
431
+ const { zeroConfig } = await import('./zero-config.mjs');
432
+ await zeroConfig();
433
+ break;
434
+ }
429
435
  // --------- 其他工具 ----------
430
436
  case "k": {
431
437
  await ccjkSkills({});
@@ -1,4 +1,4 @@
1
- const version = "10.2.0";
1
+ const version = "10.3.0";
2
2
  const homepage = "https://github.com/miounet11/ccjk";
3
3
 
4
4
  export { homepage, version };
@@ -566,6 +566,8 @@ const KNOWN_COMMANDS = /* @__PURE__ */ new Set([
566
566
  "vim",
567
567
  "permissions",
568
568
  "perm",
569
+ "zero-config",
570
+ "zc",
569
571
  "skills",
570
572
  "sk",
571
573
  "skill",
@@ -28,11 +28,12 @@ import 'ora';
28
28
  import 'semver';
29
29
  import './config.mjs';
30
30
  import './claude-config.mjs';
31
+ import '../shared/ccjk.BiCrMV5O.mjs';
31
32
  import '../shared/ccjk.BFQ7yr5S.mjs';
32
33
  import './prompts.mjs';
33
34
  import '../shared/ccjk.DHbrGcgg.mjs';
34
35
  import 'inquirer-toggle';
35
- import '../shared/ccjk.IbImMVWM.mjs';
36
+ import '../shared/ccjk.DVBW2wxp.mjs';
36
37
  import './banner.mjs';
37
38
  import './config2.mjs';
38
39
  import 'node:util';
@@ -4,7 +4,7 @@ import { join, dirname } from 'pathe';
4
4
  import { exec } from 'tinyexec';
5
5
  import { SETTINGS_FILE, CLAUDE_DIR } from './constants.mjs';
6
6
  import { ensureDir, writeFileAtomic } from './fs-operations.mjs';
7
- import { m as mergeAndCleanPermissions } from './config.mjs';
7
+ import { m as mergeAndCleanPermissions } from '../shared/ccjk.BiCrMV5O.mjs';
8
8
  import { g as getPlatform } from './platform.mjs';
9
9
  import 'node:os';
10
10
  import './index2.mjs';
@@ -13,11 +13,6 @@ import 'i18next';
13
13
  import 'i18next-fs-backend';
14
14
  import 'node:crypto';
15
15
  import 'node:fs/promises';
16
- import 'ansis';
17
- import 'dayjs';
18
- import 'inquirer';
19
- import './claude-config.mjs';
20
- import './json-config.mjs';
21
16
 
22
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
23
18
  function getTemplateSettings() {
@@ -9,7 +9,7 @@ import { displayBanner } from './banner.mjs';
9
9
  import { readZcfConfig, updateZcfConfig } from './ccjk-config.mjs';
10
10
  import { r as readMcpConfig } from './claude-config.mjs';
11
11
  import { c as copyConfigFiles } from './config.mjs';
12
- import { n as needsMigration, m as migrateSettingsForTokenRetrieval, d as displayMigrationResult, p as promptMigration, u as updatePromptOnly, s as selectAndInstallWorkflows } from '../shared/ccjk.IbImMVWM.mjs';
12
+ import { n as needsMigration, m as migrateSettingsForTokenRetrieval, d as displayMigrationResult, p as promptMigration, u as updatePromptOnly, s as selectAndInstallWorkflows } from '../shared/ccjk.DVBW2wxp.mjs';
13
13
  import { h as handleExitPromptError, a as handleGeneralError } from '../shared/ccjk.DrMygfCF.mjs';
14
14
  import { i as installMcpServices } from '../shared/ccjk.DB2UYcq0.mjs';
15
15
  import { resolveAiOutputLanguage } from './prompts.mjs';
@@ -34,6 +34,7 @@ import 'inquirer-toggle';
34
34
  import 'node:child_process';
35
35
  import 'i18next';
36
36
  import 'i18next-fs-backend';
37
+ import '../shared/ccjk.BiCrMV5O.mjs';
37
38
  import 'node:path';
38
39
  import 'node:util';
39
40
 
@@ -0,0 +1,359 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import ansis from 'ansis';
3
+ import inquirer from 'inquirer';
4
+ import { SETTINGS_FILE, CLAUDE_DIR } from './constants.mjs';
5
+ import { i18n } from './index2.mjs';
6
+ import { ensureDir, writeFileAtomic } from './fs-operations.mjs';
7
+ import { m as mergeAndCleanPermissions } from '../shared/ccjk.BiCrMV5O.mjs';
8
+ import { a as addNumbersToChoices } from '../shared/ccjk.BFQ7yr5S.mjs';
9
+ import 'node:os';
10
+ import 'pathe';
11
+ import 'node:process';
12
+ import 'node:url';
13
+ import 'i18next';
14
+ import 'i18next-fs-backend';
15
+ import 'node:crypto';
16
+ import 'node:fs/promises';
17
+
18
+ const MAX_PRESET = {
19
+ id: "max",
20
+ name: "Maximum Permissions",
21
+ description: "All common commands, file operations, and MCP servers",
22
+ permissions: [
23
+ // Package managers
24
+ "Bash(pnpm *)",
25
+ "Bash(npm *)",
26
+ "Bash(npx *)",
27
+ "Bash(NODE_ENV=* pnpm *)",
28
+ "Bash(yarn *)",
29
+ "Bash(bun *)",
30
+ "Bash(deno *)",
31
+ // Version control
32
+ "Bash(git *)",
33
+ // Build tools
34
+ "Bash(make *)",
35
+ "Bash(cmake *)",
36
+ "Bash(cargo *)",
37
+ "Bash(go *)",
38
+ "Bash(rustc *)",
39
+ // Container tools
40
+ "Bash(docker *)",
41
+ "Bash(docker-compose *)",
42
+ "Bash(podman *)",
43
+ // Programming languages
44
+ "Bash(python *)",
45
+ "Bash(python3 *)",
46
+ "Bash(node *)",
47
+ "Bash(ruby *)",
48
+ "Bash(php *)",
49
+ "Bash(java *)",
50
+ "Bash(javac *)",
51
+ // Shell utilities
52
+ "Bash(which *)",
53
+ "Bash(cat *)",
54
+ "Bash(ls *)",
55
+ "Bash(echo *)",
56
+ "Bash(grep *)",
57
+ "Bash(find *)",
58
+ "Bash(head *)",
59
+ "Bash(tail *)",
60
+ "Bash(wc *)",
61
+ "Bash(sort *)",
62
+ "Bash(uniq *)",
63
+ "Bash(cut *)",
64
+ "Bash(sed *)",
65
+ "Bash(awk *)",
66
+ "Bash(tr *)",
67
+ "Bash(xargs *)",
68
+ // File operations
69
+ "Bash(mkdir *)",
70
+ "Bash(touch *)",
71
+ "Bash(cp *)",
72
+ "Bash(mv *)",
73
+ "Bash(chmod *)",
74
+ "Bash(chown *)",
75
+ "Bash(ln *)",
76
+ // Network tools
77
+ "Bash(curl *)",
78
+ "Bash(wget *)",
79
+ "Bash(ping *)",
80
+ "Bash(netstat *)",
81
+ "Bash(ss *)",
82
+ // System info
83
+ "Bash(ps *)",
84
+ "Bash(top *)",
85
+ "Bash(htop *)",
86
+ "Bash(df *)",
87
+ "Bash(du *)",
88
+ "Bash(free *)",
89
+ "Bash(uname *)",
90
+ // Text editors
91
+ "Bash(vim *)",
92
+ "Bash(nano *)",
93
+ "Bash(emacs *)",
94
+ "Bash(code *)",
95
+ // Compression
96
+ "Bash(tar *)",
97
+ "Bash(gzip *)",
98
+ "Bash(gunzip *)",
99
+ "Bash(zip *)",
100
+ "Bash(unzip *)",
101
+ // Package managers (system)
102
+ "Bash(brew *)",
103
+ "Bash(apt *)",
104
+ "Bash(apt-get *)",
105
+ "Bash(yum *)",
106
+ "Bash(dnf *)",
107
+ "Bash(pacman *)",
108
+ // File operations (Claude Code tools)
109
+ "Read(*)",
110
+ "Edit(*)",
111
+ "Write(*)",
112
+ "NotebookEdit(*)",
113
+ // Web access
114
+ "WebFetch(*)",
115
+ // MCP servers (wildcard for all)
116
+ "MCP(*)"
117
+ ],
118
+ env: {
119
+ ANTHROPIC_MODEL: "",
120
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "",
121
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "",
122
+ ANTHROPIC_DEFAULT_OPUS_MODEL: ""
123
+ }
124
+ };
125
+ const DEV_PRESET = {
126
+ id: "dev",
127
+ name: "Developer Preset",
128
+ description: "Build tools, git, package managers, and file operations",
129
+ permissions: [
130
+ // Package managers
131
+ "Bash(pnpm *)",
132
+ "Bash(npm *)",
133
+ "Bash(npx *)",
134
+ "Bash(NODE_ENV=* pnpm *)",
135
+ "Bash(yarn *)",
136
+ "Bash(bun *)",
137
+ // Version control
138
+ "Bash(git *)",
139
+ // Build tools
140
+ "Bash(make *)",
141
+ "Bash(cargo *)",
142
+ "Bash(go *)",
143
+ // Programming languages
144
+ "Bash(python *)",
145
+ "Bash(python3 *)",
146
+ "Bash(node *)",
147
+ // Shell utilities
148
+ "Bash(which *)",
149
+ "Bash(cat *)",
150
+ "Bash(ls *)",
151
+ "Bash(echo *)",
152
+ "Bash(grep *)",
153
+ "Bash(find *)",
154
+ "Bash(head *)",
155
+ "Bash(tail *)",
156
+ "Bash(wc *)",
157
+ "Bash(sort *)",
158
+ // File operations
159
+ "Bash(mkdir *)",
160
+ "Bash(touch *)",
161
+ "Bash(cp *)",
162
+ "Bash(mv *)",
163
+ "Bash(chmod *)",
164
+ // File operations (Claude Code tools)
165
+ "Read(*)",
166
+ "Edit(*)",
167
+ "Write(*)",
168
+ "NotebookEdit(*)",
169
+ // Web access for docs
170
+ "WebFetch(*)"
171
+ ],
172
+ env: {
173
+ ANTHROPIC_MODEL: ""
174
+ }
175
+ };
176
+ const SAFE_PRESET = {
177
+ id: "safe",
178
+ name: "Safe Preset",
179
+ description: "Read-only commands, no file modifications",
180
+ permissions: [
181
+ // Read-only shell utilities
182
+ "Bash(which *)",
183
+ "Bash(cat *)",
184
+ "Bash(ls *)",
185
+ "Bash(echo *)",
186
+ "Bash(grep *)",
187
+ "Bash(find *)",
188
+ "Bash(head *)",
189
+ "Bash(tail *)",
190
+ "Bash(wc *)",
191
+ "Bash(sort *)",
192
+ "Bash(uniq *)",
193
+ "Bash(cut *)",
194
+ // System info (read-only)
195
+ "Bash(ps *)",
196
+ "Bash(df *)",
197
+ "Bash(du *)",
198
+ "Bash(uname *)",
199
+ // Git read operations
200
+ "Bash(git status *)",
201
+ "Bash(git log *)",
202
+ "Bash(git diff *)",
203
+ "Bash(git show *)",
204
+ "Bash(git branch *)",
205
+ // File operations (read-only)
206
+ "Read(*)",
207
+ // Web access
208
+ "WebFetch(*)"
209
+ ]
210
+ };
211
+ const PRESETS = [MAX_PRESET, DEV_PRESET, SAFE_PRESET];
212
+ function loadCurrentSettings() {
213
+ if (!existsSync(SETTINGS_FILE)) {
214
+ return {};
215
+ }
216
+ try {
217
+ const content = readFileSync(SETTINGS_FILE, "utf-8");
218
+ return JSON.parse(content);
219
+ } catch {
220
+ return {};
221
+ }
222
+ }
223
+ function saveSettings(settings) {
224
+ ensureDir(CLAUDE_DIR);
225
+ writeFileAtomic(SETTINGS_FILE, JSON.stringify(settings, null, 2));
226
+ }
227
+ function backupSettings() {
228
+ if (!existsSync(SETTINGS_FILE)) {
229
+ return null;
230
+ }
231
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, -5);
232
+ const backupDir = `${CLAUDE_DIR}/backup`;
233
+ ensureDir(backupDir);
234
+ const backupPath = `${backupDir}/settings-${timestamp}.json`;
235
+ const content = readFileSync(SETTINGS_FILE, "utf-8");
236
+ writeFileAtomic(backupPath, content);
237
+ return backupPath;
238
+ }
239
+ function applyPreset(preset, currentSettings) {
240
+ const newSettings = { ...currentSettings };
241
+ if (!newSettings.permissions) {
242
+ newSettings.permissions = { allow: [] };
243
+ }
244
+ newSettings.permissions.allow = mergeAndCleanPermissions(
245
+ preset.permissions,
246
+ newSettings.permissions.allow || []
247
+ );
248
+ if (preset.env) {
249
+ newSettings.env = {
250
+ ...newSettings.env,
251
+ ...preset.env
252
+ };
253
+ }
254
+ return newSettings;
255
+ }
256
+ function showPresetDiff(preset, currentSettings) {
257
+ const isZh = i18n.language === "zh-CN";
258
+ const currentPermissions = new Set(currentSettings.permissions?.allow || []);
259
+ const newPermissions = preset.permissions.filter((p) => !currentPermissions.has(p));
260
+ console.log("");
261
+ console.log(ansis.bold.cyan(isZh ? "\u{1F4CB} \u9884\u8BBE\u8BE6\u60C5" : "\u{1F4CB} Preset Details"));
262
+ console.log(ansis.dim("\u2500".repeat(60)));
263
+ console.log(`${ansis.green("Name:")} ${preset.name}`);
264
+ console.log(`${ansis.green("Description:")} ${preset.description}`);
265
+ console.log("");
266
+ if (newPermissions.length > 0) {
267
+ console.log(ansis.bold.yellow(isZh ? "\u2728 \u5C06\u6DFB\u52A0\u7684\u6743\u9650:" : "\u2728 Permissions to be added:"));
268
+ console.log(ansis.dim(` ${isZh ? "\u603B\u8BA1" : "Total"}: ${newPermissions.length} ${isZh ? "\u9879" : "items"}`));
269
+ const bashPerms = newPermissions.filter((p) => p.startsWith("Bash("));
270
+ const filePerms = newPermissions.filter((p) => ["Read", "Edit", "Write", "NotebookEdit"].some((t) => p.startsWith(t)));
271
+ const otherPerms = newPermissions.filter((p) => !bashPerms.includes(p) && !filePerms.includes(p));
272
+ if (bashPerms.length > 0) {
273
+ console.log(` ${ansis.cyan("Bash:")} ${bashPerms.length} ${isZh ? "\u4E2A\u547D\u4EE4" : "commands"}`);
274
+ }
275
+ if (filePerms.length > 0) {
276
+ console.log(` ${ansis.cyan("File:")} ${filePerms.length} ${isZh ? "\u4E2A\u64CD\u4F5C" : "operations"}`);
277
+ }
278
+ if (otherPerms.length > 0) {
279
+ console.log(` ${ansis.cyan("Other:")} ${otherPerms.length} ${isZh ? "\u9879" : "items"}`);
280
+ }
281
+ } else {
282
+ console.log(ansis.yellow(isZh ? "\u2713 \u6240\u6709\u6743\u9650\u5DF2\u5B58\u5728" : "\u2713 All permissions already exist"));
283
+ }
284
+ console.log(ansis.dim("\u2500".repeat(60)));
285
+ console.log("");
286
+ }
287
+ async function zeroConfig(options = {}) {
288
+ const isZh = i18n.language === "zh-CN";
289
+ if (options.list) {
290
+ console.log("");
291
+ console.log(ansis.bold.cyan(isZh ? "\u{1F4E6} \u53EF\u7528\u7684\u6743\u9650\u9884\u8BBE" : "\u{1F4E6} Available Permission Presets"));
292
+ console.log(ansis.dim("\u2500".repeat(60)));
293
+ for (const preset of PRESETS) {
294
+ console.log(` ${ansis.green(preset.id.padEnd(8))} - ${preset.name}`);
295
+ console.log(` ${ansis.dim(" ".repeat(10))}${preset.description}`);
296
+ console.log(` ${ansis.dim(" ".repeat(10))}${preset.permissions.length} ${isZh ? "\u9879\u6743\u9650" : "permissions"}`);
297
+ console.log("");
298
+ }
299
+ console.log(ansis.dim("\u2500".repeat(60)));
300
+ console.log(ansis.gray(isZh ? "\u4F7F\u7528: npx ccjk zc --preset=<id>" : "Usage: npx ccjk zc --preset=<id>"));
301
+ console.log("");
302
+ return;
303
+ }
304
+ let selectedPreset;
305
+ if (options.preset) {
306
+ selectedPreset = PRESETS.find((p) => p.id === options.preset);
307
+ if (!selectedPreset) {
308
+ console.error(ansis.red(isZh ? `\u9519\u8BEF: \u672A\u627E\u5230\u9884\u8BBE "${options.preset}"` : `Error: Preset "${options.preset}" not found`));
309
+ console.log(ansis.gray(isZh ? "\u4F7F\u7528 --list \u67E5\u770B\u53EF\u7528\u9884\u8BBE" : "Use --list to see available presets"));
310
+ return;
311
+ }
312
+ } else {
313
+ const { presetId } = await inquirer.prompt({
314
+ type: "list",
315
+ name: "presetId",
316
+ message: isZh ? "\u9009\u62E9\u6743\u9650\u9884\u8BBE:" : "Select permission preset:",
317
+ choices: addNumbersToChoices(
318
+ PRESETS.map((p) => ({
319
+ name: `${p.name} - ${ansis.gray(p.description)}`,
320
+ value: p.id,
321
+ short: p.name
322
+ }))
323
+ )
324
+ });
325
+ selectedPreset = PRESETS.find((p) => p.id === presetId);
326
+ if (!selectedPreset) {
327
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
328
+ return;
329
+ }
330
+ }
331
+ const currentSettings = loadCurrentSettings();
332
+ showPresetDiff(selectedPreset, currentSettings);
333
+ if (!options.preset) {
334
+ const { confirm } = await inquirer.prompt({
335
+ type: "confirm",
336
+ name: "confirm",
337
+ message: isZh ? "\u786E\u8BA4\u5E94\u7528\u6B64\u9884\u8BBE?" : "Confirm applying this preset?",
338
+ default: true
339
+ });
340
+ if (!confirm) {
341
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
342
+ return;
343
+ }
344
+ }
345
+ if (!options.skipBackup) {
346
+ const backupPath = backupSettings();
347
+ if (backupPath) {
348
+ console.log(ansis.gray(`\u2714 ${isZh ? "\u5DF2\u5907\u4EFD\u5230" : "Backed up to"}: ${backupPath}`));
349
+ }
350
+ }
351
+ const newSettings = applyPreset(selectedPreset, currentSettings);
352
+ saveSettings(newSettings);
353
+ console.log("");
354
+ console.log(ansis.green(`\u2705 ${isZh ? "\u6743\u9650\u9884\u8BBE\u5DF2\u5E94\u7528" : "Permission preset applied"}: ${selectedPreset.name}`));
355
+ console.log(ansis.gray(` ${isZh ? "\u914D\u7F6E\u6587\u4EF6" : "Config file"}: ${SETTINGS_FILE}`));
356
+ console.log("");
357
+ }
358
+
359
+ export { zeroConfig };
package/dist/cli.mjs CHANGED
@@ -382,6 +382,27 @@ const COMMANDS = [
382
382
  };
383
383
  }
384
384
  },
385
+ {
386
+ name: "zero-config [preset]",
387
+ description: "Apply zero-config permission presets (max, dev, safe)",
388
+ aliases: ["zc"],
389
+ tier: "extended",
390
+ options: [
391
+ { flags: "--preset, -p <preset>", description: "Preset to apply (max, dev, safe)" },
392
+ { flags: "--list, -l", description: "List available presets" },
393
+ { flags: "--skip-backup", description: "Skip backup before applying" }
394
+ ],
395
+ loader: async () => {
396
+ const { zeroConfig } = await import('./chunks/zero-config.mjs');
397
+ return async (options, preset) => {
398
+ await zeroConfig({
399
+ preset: preset || options.preset,
400
+ list: options.list,
401
+ skipBackup: options.skipBackup
402
+ });
403
+ };
404
+ }
405
+ },
385
406
  {
386
407
  name: "vim",
387
408
  description: "Vim mode configuration and keybindings",
@@ -103,6 +103,39 @@
103
103
  "validationErrors": "Configuration validation errors",
104
104
  "configUpToDate": "Configuration is up to date"
105
105
  },
106
+ "zeroConfig": {
107
+ "title": "Zero-Config Permission Presets",
108
+ "selectPreset": "Select permission preset",
109
+ "confirmApply": "Confirm applying this preset?",
110
+ "presetApplied": "Permission preset applied",
111
+ "backedUpTo": "Backed up to",
112
+ "configFile": "Config file",
113
+ "presetNotFound": "Error: Preset not found",
114
+ "useListToSee": "Use --list to see available presets",
115
+ "availablePresets": "Available Permission Presets",
116
+ "presetDetails": "Preset Details",
117
+ "permissionsToAdd": "Permissions to be added",
118
+ "total": "Total",
119
+ "items": "items",
120
+ "commands": "commands",
121
+ "operations": "operations",
122
+ "allPermissionsExist": "All permissions already exist",
123
+ "usage": "Usage: npx ccjk zc --preset=<id>",
124
+ "presets": {
125
+ "max": {
126
+ "name": "Maximum Permissions",
127
+ "description": "All common commands, file operations, and MCP servers"
128
+ },
129
+ "dev": {
130
+ "name": "Developer Preset",
131
+ "description": "Build tools, git, package managers, and file operations"
132
+ },
133
+ "safe": {
134
+ "name": "Safe Preset",
135
+ "description": "Read-only commands, no file modifications"
136
+ }
137
+ }
138
+ },
106
139
  "fields": {
107
140
  "language": {
108
141
  "label": "Response Language",
@@ -101,6 +101,39 @@
101
101
  "validationErrors": "配置验证错误",
102
102
  "configUpToDate": "配置已是最新版本"
103
103
  },
104
+ "zeroConfig": {
105
+ "title": "零配置权限预设",
106
+ "selectPreset": "选择权限预设",
107
+ "confirmApply": "确认应用此预设?",
108
+ "presetApplied": "权限预设已应用",
109
+ "backedUpTo": "已备份到",
110
+ "configFile": "配置文件",
111
+ "presetNotFound": "错误: 未找到预设",
112
+ "useListToSee": "使用 --list 查看可用预设",
113
+ "availablePresets": "可用的权限预设",
114
+ "presetDetails": "预设详情",
115
+ "permissionsToAdd": "将添加的权限",
116
+ "total": "总计",
117
+ "items": "项",
118
+ "commands": "个命令",
119
+ "operations": "个操作",
120
+ "allPermissionsExist": "所有权限已存在",
121
+ "usage": "使用: npx ccjk zc --preset=<id>",
122
+ "presets": {
123
+ "max": {
124
+ "name": "最大权限",
125
+ "description": "所有常用命令、文件操作和 MCP 服务"
126
+ },
127
+ "dev": {
128
+ "name": "开发者预设",
129
+ "description": "构建工具、git、包管理器和文件操作"
130
+ },
131
+ "safe": {
132
+ "name": "安全预设",
133
+ "description": "只读命令,不修改文件"
134
+ }
135
+ }
136
+ },
104
137
  "fields": {
105
138
  "language": {
106
139
  "label": "响应语言",
package/dist/index.mjs CHANGED
@@ -25,6 +25,7 @@ import './chunks/json-config.mjs';
25
25
  import './chunks/fs-operations.mjs';
26
26
  import 'node:crypto';
27
27
  import 'node:fs/promises';
28
+ import './shared/ccjk.BiCrMV5O.mjs';
28
29
  import 'tinyexec';
29
30
 
30
31
  const execAsync$1 = promisify(exec);
@@ -0,0 +1,94 @@
1
+ const INVALID_PERMISSION_NAMES = /* @__PURE__ */ new Set([
2
+ "AllowEdit",
3
+ "AllowWrite",
4
+ "AllowRead",
5
+ "AllowExec",
6
+ "AllowCreateProcess",
7
+ "AllowKillProcess",
8
+ "AllowNetworkAccess",
9
+ "AllowFileSystemAccess",
10
+ "AllowShellAccess",
11
+ "AllowHttpAccess"
12
+ ]);
13
+ const DANGEROUS_BASH_PATTERNS = /* @__PURE__ */ new Set([
14
+ "Bash(passwd *)",
15
+ "Bash(reboot *)",
16
+ "Bash(shutdown *)",
17
+ "Bash(halt *)",
18
+ "Bash(poweroff *)",
19
+ "Bash(init *)",
20
+ "Bash(telinit *)",
21
+ "Bash(rm *)",
22
+ "Bash(kill *)",
23
+ "Bash(pkill *)",
24
+ "Bash(killall *)",
25
+ "Bash(su *)",
26
+ "Bash(sudo *)",
27
+ "Bash(visudo *)",
28
+ "Bash(useradd *)",
29
+ "Bash(userdel *)",
30
+ "Bash(usermod *)",
31
+ "Bash(groupadd *)",
32
+ "Bash(groupdel *)",
33
+ "Bash(groupmod *)",
34
+ "Bash(modprobe *)",
35
+ "Bash(insmod *)",
36
+ "Bash(rmmod *)"
37
+ ]);
38
+ function isValidPermission(perm) {
39
+ if (INVALID_PERMISSION_NAMES.has(perm)) {
40
+ return false;
41
+ }
42
+ if (["mcp__.*", "mcp__*", "mcp__(*)"].includes(perm)) {
43
+ return false;
44
+ }
45
+ if (/^[a-z]/.test(perm) && !perm.startsWith("mcp__")) {
46
+ return false;
47
+ }
48
+ return true;
49
+ }
50
+ function isCoveredByWildcard(perm, wildcardPerm) {
51
+ const wildcardMatch = wildcardPerm.match(/^(\w+)\((.+)\)$/);
52
+ if (!wildcardMatch) return false;
53
+ const [, tool, wildcardArg] = wildcardMatch;
54
+ if (!wildcardArg.includes("*")) return false;
55
+ const permMatch = perm.match(/^(\w+)\((.+)\)$/);
56
+ if (!permMatch) return false;
57
+ const [, permTool, permArg] = permMatch;
58
+ if (tool !== permTool) return false;
59
+ const regexStr = wildcardArg.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".+");
60
+ return new RegExp(`^${regexStr}$`).test(permArg);
61
+ }
62
+ function mergeAndCleanPermissions(templatePermissions, userPermissions) {
63
+ const template = templatePermissions || [];
64
+ const user = userPermissions || [];
65
+ const result = [...template];
66
+ for (const perm of user) {
67
+ if (result.includes(perm)) {
68
+ continue;
69
+ }
70
+ if (!isValidPermission(perm)) {
71
+ continue;
72
+ }
73
+ if (DANGEROUS_BASH_PATTERNS.has(perm)) {
74
+ continue;
75
+ }
76
+ let isRedundant = false;
77
+ for (const templatePerm of template) {
78
+ if (perm.startsWith(`${templatePerm}(`)) {
79
+ isRedundant = true;
80
+ break;
81
+ }
82
+ if (isCoveredByWildcard(perm, templatePerm)) {
83
+ isRedundant = true;
84
+ break;
85
+ }
86
+ }
87
+ if (!isRedundant) {
88
+ result.push(perm);
89
+ }
90
+ }
91
+ return result;
92
+ }
93
+
94
+ export { mergeAndCleanPermissions as m };
@@ -2,12 +2,13 @@ import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
3
  import { CLAUDE_DIR, SETTINGS_FILE } from '../chunks/constants.mjs';
4
4
  import { ensureI18nInitialized, i18n } from '../chunks/index2.mjs';
5
- import { m as mergeAndCleanPermissions, e as getExistingApiConfig, f as configureApi, s as switchToOfficialLogin, b as backupExistingConfig, a as applyAiLanguageDirective } from '../chunks/config.mjs';
5
+ import { e as getExistingApiConfig, f as configureApi, s as switchToOfficialLogin, b as backupExistingConfig, a as applyAiLanguageDirective } from '../chunks/config.mjs';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { join, dirname } from 'pathe';
8
8
  import { updateZcfConfig } from '../chunks/ccjk-config.mjs';
9
9
  import { exists, removeFile, ensureDir, copyFile } from '../chunks/fs-operations.mjs';
10
10
  import { readJsonConfig, writeJsonConfig } from '../chunks/json-config.mjs';
11
+ import { m as mergeAndCleanPermissions } from './ccjk.BiCrMV5O.mjs';
11
12
  import { a as addNumbersToChoices } from './ccjk.BFQ7yr5S.mjs';
12
13
  import { p as promptBoolean } from './ccjk.DHbrGcgg.mjs';
13
14
  import { existsSync } from 'node:fs';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ccjk",
3
3
  "type": "module",
4
- "version": "10.2.0",
4
+ "version": "10.3.0",
5
5
  "packageManager": "pnpm@10.17.1",
6
6
  "description": "CLI toolkit for Claude Code and Codex setup. Simplifies MCP service installation, API configuration, workflow management, and multi-provider support with guided interactive setup.",
7
7
  "author": {