ccjk 10.2.0 → 11.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.
- package/README.md +28 -0
- package/dist/chunks/auto-init.mjs +7585 -0
- package/dist/chunks/ccr.mjs +2 -1
- package/dist/chunks/check-updates.mjs +1 -0
- package/dist/chunks/claude-code-config-manager.mjs +1 -0
- package/dist/chunks/claude-code-incremental-manager.mjs +2 -1
- package/dist/chunks/codex-config-switch.mjs +1 -0
- package/dist/chunks/codex-provider-manager.mjs +1 -0
- package/dist/chunks/config-switch.mjs +1 -0
- package/dist/chunks/config.mjs +2 -94
- package/dist/chunks/config2.mjs +1 -0
- package/dist/chunks/config3.mjs +1 -0
- package/dist/chunks/evolution.mjs +383 -0
- package/dist/chunks/features.mjs +2 -1
- package/dist/chunks/init.mjs +1 -1
- package/dist/chunks/mcp.mjs +1 -0
- package/dist/chunks/menu.mjs +7 -1
- package/dist/chunks/package.mjs +1 -1
- package/dist/chunks/quick-provider.mjs +3 -0
- package/dist/chunks/quick-setup.mjs +2 -1
- package/dist/chunks/remote.mjs +166 -0
- package/dist/chunks/simple-config.mjs +1 -6
- package/dist/chunks/update.mjs +2 -1
- package/dist/chunks/zero-config.mjs +359 -0
- package/dist/cli.mjs +107 -0
- package/dist/i18n/locales/en/configuration.json +33 -0
- package/dist/i18n/locales/en/evolution.json +54 -0
- package/dist/i18n/locales/en/remote.json +39 -0
- package/dist/i18n/locales/zh-CN/configuration.json +33 -0
- package/dist/i18n/locales/zh-CN/evolution.json +54 -0
- package/dist/i18n/locales/zh-CN/remote.json +39 -0
- package/dist/index.mjs +3 -73
- package/dist/shared/ccjk.BiCrMV5O.mjs +94 -0
- package/dist/shared/ccjk.Cu_R2MbQ.mjs +75 -0
- package/dist/shared/{ccjk.IbImMVWM.mjs → ccjk.DVBW2wxp.mjs} +2 -1
- package/package.json +7 -1
|
@@ -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",
|
|
@@ -600,6 +602,7 @@ const KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
600
602
|
"status",
|
|
601
603
|
"st",
|
|
602
604
|
"boost",
|
|
605
|
+
"evolution",
|
|
603
606
|
// CCJK v8 commands
|
|
604
607
|
"ccjk:mcp",
|
|
605
608
|
"ccjk-mcp",
|
|
@@ -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.
|
|
36
|
+
import '../shared/ccjk.DVBW2wxp.mjs';
|
|
36
37
|
import './banner.mjs';
|
|
37
38
|
import './config2.mjs';
|
|
38
39
|
import 'node:util';
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { l as logger } from '../shared/ccjk.Cu_R2MbQ.mjs';
|
|
2
|
+
import { i18n } from './index2.mjs';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import 'ansis';
|
|
10
|
+
import 'node:fs';
|
|
11
|
+
import 'node:process';
|
|
12
|
+
import 'node:url';
|
|
13
|
+
import 'i18next';
|
|
14
|
+
import 'i18next-fs-backend';
|
|
15
|
+
import 'pathe';
|
|
16
|
+
|
|
17
|
+
const DAEMON_CONFIG_PATH = join(homedir(), ".ccjk", "daemon.json");
|
|
18
|
+
async function enableRemote() {
|
|
19
|
+
console.log(i18n.t("remote:enable.title"));
|
|
20
|
+
const config = loadDaemonConfig();
|
|
21
|
+
if (config.enabled) {
|
|
22
|
+
console.log(i18n.t("remote:enable.already_enabled"));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const { serverUrl } = await inquirer.prompt([
|
|
26
|
+
{
|
|
27
|
+
type: "input",
|
|
28
|
+
name: "serverUrl",
|
|
29
|
+
message: i18n.t("remote:enable.server_url"),
|
|
30
|
+
default: "https://ccjk-server.example.com"
|
|
31
|
+
}
|
|
32
|
+
]);
|
|
33
|
+
const machineId = `machine-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
34
|
+
const newConfig = {
|
|
35
|
+
enabled: true,
|
|
36
|
+
serverUrl,
|
|
37
|
+
machineId
|
|
38
|
+
};
|
|
39
|
+
saveDaemonConfig(newConfig);
|
|
40
|
+
console.log(i18n.t("remote:enable.success"));
|
|
41
|
+
console.log(i18n.t("remote:enable.next_steps"));
|
|
42
|
+
}
|
|
43
|
+
async function disableRemote() {
|
|
44
|
+
console.log(i18n.t("remote:disable.title"));
|
|
45
|
+
const config = loadDaemonConfig();
|
|
46
|
+
if (!config.enabled) {
|
|
47
|
+
console.log(i18n.t("remote:disable.already_disabled"));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
await stopDaemon();
|
|
51
|
+
config.enabled = false;
|
|
52
|
+
saveDaemonConfig(config);
|
|
53
|
+
console.log(i18n.t("remote:disable.success"));
|
|
54
|
+
}
|
|
55
|
+
async function remoteStatus() {
|
|
56
|
+
const config = loadDaemonConfig();
|
|
57
|
+
console.log(i18n.t("remote:status.title"));
|
|
58
|
+
console.log(` ${i18n.t("remote:status.enabled")}: ${config.enabled ? "\u2705" : "\u274C"}`);
|
|
59
|
+
if (config.enabled) {
|
|
60
|
+
console.log(` ${i18n.t("remote:status.server")}: ${config.serverUrl}`);
|
|
61
|
+
console.log(` ${i18n.t("remote:status.machine_id")}: ${config.machineId}`);
|
|
62
|
+
const daemonRunning = await isDaemonRunning();
|
|
63
|
+
console.log(` ${i18n.t("remote:status.daemon")}: ${daemonRunning ? "\u{1F7E2} Running" : "\u{1F534} Stopped"}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function showQRCode() {
|
|
67
|
+
const config = loadDaemonConfig();
|
|
68
|
+
if (!config.enabled) {
|
|
69
|
+
console.log(i18n.t("remote:qr.not_enabled"));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const pairingData = {
|
|
73
|
+
serverUrl: config.serverUrl,
|
|
74
|
+
machineId: config.machineId,
|
|
75
|
+
timestamp: Date.now()
|
|
76
|
+
};
|
|
77
|
+
const pairingUrl = `ccjk://pair?data=${encodeURIComponent(JSON.stringify(pairingData))}`;
|
|
78
|
+
console.log(i18n.t("remote:qr.title"));
|
|
79
|
+
console.log(i18n.t("remote:qr.instructions"));
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(` ${pairingUrl}`);
|
|
82
|
+
console.log();
|
|
83
|
+
console.log(i18n.t("remote:qr.manual_entry"));
|
|
84
|
+
console.log(` Server: ${config.serverUrl}`);
|
|
85
|
+
console.log(` Machine ID: ${config.machineId}`);
|
|
86
|
+
}
|
|
87
|
+
async function startDaemon() {
|
|
88
|
+
const spinner = ora(i18n.t("remote:daemon.starting")).start();
|
|
89
|
+
try {
|
|
90
|
+
if (await isDaemonRunning()) {
|
|
91
|
+
spinner.warn(i18n.t("remote:daemon.already_running"));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const daemon = spawn("ccjk-daemon", ["start"], {
|
|
95
|
+
detached: true,
|
|
96
|
+
stdio: "ignore"
|
|
97
|
+
});
|
|
98
|
+
daemon.unref();
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
100
|
+
if (await isDaemonRunning()) {
|
|
101
|
+
spinner.succeed(i18n.t("remote:daemon.started"));
|
|
102
|
+
} else {
|
|
103
|
+
spinner.fail(i18n.t("remote:daemon.start_failed"));
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
spinner.fail(i18n.t("remote:daemon.start_error"));
|
|
107
|
+
logger.error("Failed to start daemon:", error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function stopDaemon() {
|
|
111
|
+
const spinner = ora(i18n.t("remote:daemon.stopping")).start();
|
|
112
|
+
try {
|
|
113
|
+
if (!await isDaemonRunning()) {
|
|
114
|
+
spinner.warn(i18n.t("remote:daemon.not_running"));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const response = await fetch("http://127.0.0.1:37821/stop", {
|
|
118
|
+
method: "POST"
|
|
119
|
+
});
|
|
120
|
+
if (response.ok) {
|
|
121
|
+
spinner.succeed(i18n.t("remote:daemon.stopped"));
|
|
122
|
+
} else {
|
|
123
|
+
spinner.fail(i18n.t("remote:daemon.stop_failed"));
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
spinner.fail(i18n.t("remote:daemon.stop_error"));
|
|
127
|
+
logger.error("Failed to stop daemon:", error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function isDaemonRunning() {
|
|
131
|
+
try {
|
|
132
|
+
const response = await fetch("http://127.0.0.1:37821/health", {
|
|
133
|
+
signal: AbortSignal.timeout(1e3)
|
|
134
|
+
});
|
|
135
|
+
return response.ok;
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function loadDaemonConfig() {
|
|
141
|
+
try {
|
|
142
|
+
if (existsSync(DAEMON_CONFIG_PATH)) {
|
|
143
|
+
return JSON.parse(readFileSync(DAEMON_CONFIG_PATH, "utf-8"));
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.error("Failed to load daemon config:", error);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
enabled: false,
|
|
150
|
+
serverUrl: ""
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function saveDaemonConfig(config) {
|
|
154
|
+
try {
|
|
155
|
+
const dir = join(homedir(), ".ccjk");
|
|
156
|
+
if (!existsSync(dir)) {
|
|
157
|
+
require("fs").mkdirSync(dir, { recursive: true });
|
|
158
|
+
}
|
|
159
|
+
writeFileSync(DAEMON_CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
160
|
+
} catch (error) {
|
|
161
|
+
logger.error("Failed to save daemon config:", error);
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export { disableRemote, enableRemote, remoteStatus, showQRCode, startDaemon, stopDaemon };
|
|
@@ -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 '
|
|
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() {
|
package/dist/chunks/update.mjs
CHANGED
|
@@ -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.
|
|
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 };
|