ccbot-cli 2.0.1 → 2.2.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/LICENSE +21 -0
- package/bin/adapters/claude.js +150 -0
- package/bin/adapters/codex.js +439 -0
- package/bin/install.js +583 -349
- package/bin/lib/ccline.js +82 -0
- package/bin/lib/utils.js +87 -34
- package/bin/uninstall.js +48 -0
- package/config/AGENTS.md +630 -0
- package/config/CLAUDE.md +229 -20
- package/config/ccline/config.toml +161 -0
- package/config/codex-config.example.toml +22 -0
- package/config/settings.example.json +32 -0
- package/output-styles/abyss-cultivator.md +399 -0
- package/package.json +14 -5
- package/skills/SKILL.md +159 -0
- package/skills/domains/ai/SKILL.md +34 -0
- package/skills/domains/ai/agent-dev.md +242 -0
- package/skills/domains/ai/llm-security.md +288 -0
- package/skills/domains/ai/prompt-and-eval.md +279 -0
- package/skills/domains/ai/rag-system.md +542 -0
- package/skills/domains/architecture/SKILL.md +42 -0
- package/skills/domains/architecture/api-design.md +225 -0
- package/skills/domains/architecture/caching.md +299 -0
- package/skills/domains/architecture/cloud-native.md +285 -0
- package/skills/domains/architecture/message-queue.md +329 -0
- package/skills/domains/architecture/security-arch.md +297 -0
- package/skills/domains/data-engineering/SKILL.md +207 -0
- package/skills/domains/development/SKILL.md +46 -0
- package/skills/domains/development/cpp.md +246 -0
- package/skills/domains/development/go.md +323 -0
- package/skills/domains/development/java.md +277 -0
- package/skills/domains/development/python.md +288 -0
- package/skills/domains/development/rust.md +313 -0
- package/skills/domains/development/shell.md +313 -0
- package/skills/domains/development/typescript.md +277 -0
- package/skills/domains/devops/SKILL.md +39 -0
- package/skills/domains/devops/cost-optimization.md +272 -0
- package/skills/domains/devops/database.md +217 -0
- package/skills/domains/devops/devsecops.md +198 -0
- package/skills/domains/devops/git-workflow.md +181 -0
- package/skills/domains/devops/observability.md +280 -0
- package/skills/domains/devops/performance.md +336 -0
- package/skills/domains/devops/testing.md +283 -0
- package/skills/domains/frontend-design/SKILL.md +38 -0
- package/skills/domains/frontend-design/claymorphism/SKILL.md +119 -0
- package/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
- package/skills/domains/frontend-design/component-patterns.md +202 -0
- package/skills/domains/frontend-design/engineering.md +287 -0
- package/skills/domains/frontend-design/glassmorphism/SKILL.md +140 -0
- package/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
- package/skills/domains/frontend-design/liquid-glass/SKILL.md +137 -0
- package/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
- package/skills/domains/frontend-design/neubrutalism/SKILL.md +143 -0
- package/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
- package/skills/domains/frontend-design/state-management.md +680 -0
- package/skills/domains/frontend-design/ui-aesthetics.md +110 -0
- package/skills/domains/frontend-design/ux-principles.md +156 -0
- package/skills/domains/infrastructure/SKILL.md +200 -0
- package/skills/domains/mobile/SKILL.md +224 -0
- package/skills/domains/orchestration/SKILL.md +29 -0
- package/skills/domains/orchestration/multi-agent.md +263 -0
- package/skills/domains/security/SKILL.md +54 -0
- package/skills/domains/security/blue-team.md +436 -0
- package/skills/domains/security/code-audit.md +265 -0
- package/skills/domains/security/pentest.md +226 -0
- package/skills/domains/security/red-team.md +375 -0
- package/skills/domains/security/threat-intel.md +372 -0
- package/skills/domains/security/vuln-research.md +369 -0
- package/skills/orchestration/multi-agent/SKILL.md +493 -0
- package/skills/run_skill.js +129 -0
- package/skills/tools/gen-docs/SKILL.md +116 -0
- package/skills/tools/gen-docs/scripts/doc_generator.js +435 -0
- package/skills/tools/lib/shared.js +98 -0
- package/skills/tools/verify-change/SKILL.md +140 -0
- package/skills/tools/verify-change/scripts/change_analyzer.js +289 -0
- package/skills/tools/verify-module/SKILL.md +127 -0
- package/skills/tools/verify-module/scripts/module_scanner.js +171 -0
- package/skills/tools/verify-quality/SKILL.md +160 -0
- package/skills/tools/verify-quality/scripts/quality_checker.js +337 -0
- package/skills/tools/verify-security/SKILL.md +143 -0
- package/skills/tools/verify-security/scripts/security_scanner.js +283 -0
- package/bin/lib/registry.js +0 -61
- package/config/.claudeignore +0 -11
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
function detectCclineBin(cclineBin) {
|
|
6
|
+
if (fs.existsSync(cclineBin)) return true;
|
|
7
|
+
try {
|
|
8
|
+
require('child_process').execSync('ccline --version', { stdio: 'pipe' });
|
|
9
|
+
return true;
|
|
10
|
+
} catch { return false; }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function installCclineBin(cclineBin, errors, { info, ok }) {
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
info('ccline 未检测到,正在安装...');
|
|
16
|
+
try {
|
|
17
|
+
execSync('npm install -g @cometix/ccline@1', { stdio: 'inherit' });
|
|
18
|
+
if (fs.existsSync(cclineBin)) { ok('ccline 二进制安装成功'); return true; }
|
|
19
|
+
try {
|
|
20
|
+
execSync('ccline --version', { stdio: 'pipe' });
|
|
21
|
+
ok('ccline 安装成功 (全局)');
|
|
22
|
+
return true;
|
|
23
|
+
} catch {}
|
|
24
|
+
errors.push('ccline 二进制安装后仍未检测到');
|
|
25
|
+
return false;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
errors.push(`npm install -g @cometix/ccline 失败: ${e.message}`);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function deployCclineConfig(cclineDir, errors, { HOME, PKG_ROOT, ok }) {
|
|
33
|
+
const { execSync } = require('child_process');
|
|
34
|
+
const bundledConfig = path.join(PKG_ROOT, 'config', 'ccline', 'config.toml');
|
|
35
|
+
const targetConfig = path.join(cclineDir, 'config.toml');
|
|
36
|
+
if (fs.existsSync(bundledConfig)) {
|
|
37
|
+
fs.mkdirSync(cclineDir, { recursive: true });
|
|
38
|
+
if (fs.existsSync(targetConfig)) {
|
|
39
|
+
const backupDir = path.join(HOME, '.claude', '.sage-backup');
|
|
40
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
41
|
+
fs.copyFileSync(targetConfig, path.join(backupDir, 'ccline-config.toml'));
|
|
42
|
+
}
|
|
43
|
+
fs.copyFileSync(bundledConfig, targetConfig);
|
|
44
|
+
ok('ccline/config.toml 已部署 (ccbot-cli 定制版)');
|
|
45
|
+
} else if (!fs.existsSync(targetConfig)) {
|
|
46
|
+
try { execSync('ccline --init', { stdio: 'inherit' }); ok('ccline 默认配置已生成'); }
|
|
47
|
+
catch (e) { errors.push(`ccline --init 失败: ${e.message}`); }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function installCcline(ctx, deps) {
|
|
52
|
+
const { HOME, PKG_ROOT, CCLINE_STATUS_LINE, ok, warn, info, fail, c } = deps;
|
|
53
|
+
console.log('');
|
|
54
|
+
info('安装 ccline 状态栏...');
|
|
55
|
+
const cclineDir = path.join(HOME, '.claude', 'ccline');
|
|
56
|
+
const cclineBin = path.join(cclineDir, process.platform === 'win32' ? 'ccline.exe' : 'ccline');
|
|
57
|
+
const errors = [];
|
|
58
|
+
|
|
59
|
+
let hasBin = detectCclineBin(cclineBin);
|
|
60
|
+
if (!hasBin) hasBin = installCclineBin(cclineBin, errors, { info, ok });
|
|
61
|
+
else ok('ccline 二进制已存在');
|
|
62
|
+
|
|
63
|
+
deployCclineConfig(cclineDir, errors, { HOME, PKG_ROOT, ok });
|
|
64
|
+
|
|
65
|
+
ctx.settings.statusLine = CCLINE_STATUS_LINE.statusLine;
|
|
66
|
+
ok(`statusLine → ${c.cyn(CCLINE_STATUS_LINE.statusLine.command)}`);
|
|
67
|
+
fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
|
|
68
|
+
|
|
69
|
+
if (errors.length > 0) {
|
|
70
|
+
console.log('');
|
|
71
|
+
warn(c.b(`ccline 安装有 ${errors.length} 个问题:`));
|
|
72
|
+
errors.forEach(e => fail(` ${e}`));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log('');
|
|
76
|
+
warn(`需要 ${c.b('Nerd Font')} 字体才能正确显示图标`);
|
|
77
|
+
info(`推荐: FiraCode Nerd Font / JetBrainsMono Nerd Font`);
|
|
78
|
+
info(`下载: ${c.cyn('https://www.nerdfonts.com/')}`);
|
|
79
|
+
ok('ccline 配置完成');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = { detectCclineBin, installCclineBin, deployCclineConfig, installCcline };
|
package/bin/lib/utils.js
CHANGED
|
@@ -1,34 +1,87 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const SKIP = ['__pycache__', '.pyc', '.pyo', '.egg-info', '.DS_Store', 'Thumbs.db', '.git'];
|
|
6
|
+
|
|
7
|
+
function shouldSkip(name) { return SKIP.some(p => name.includes(p)); }
|
|
8
|
+
|
|
9
|
+
function copyRecursive(src, dest) {
|
|
10
|
+
let stat;
|
|
11
|
+
try { stat = fs.statSync(src); } catch (e) {
|
|
12
|
+
throw new Error(`复制失败: 源路径不存在 ${src} (${e.code})`);
|
|
13
|
+
}
|
|
14
|
+
if (stat.isDirectory()) {
|
|
15
|
+
if (shouldSkip(path.basename(src))) return;
|
|
16
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
17
|
+
for (const f of fs.readdirSync(src)) {
|
|
18
|
+
if (!shouldSkip(f)) {
|
|
19
|
+
try { copyRecursive(path.join(src, f), path.join(dest, f)); }
|
|
20
|
+
catch (e) { console.error(` ⚠ 跳过: ${path.join(src, f)} (${e.message})`); }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
if (shouldSkip(path.basename(src))) return;
|
|
25
|
+
const destDir = path.dirname(dest);
|
|
26
|
+
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
|
|
27
|
+
fs.copyFileSync(src, dest);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function rmSafe(p) {
|
|
32
|
+
if (fs.existsSync(p)) fs.rmSync(p, { recursive: true, force: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function deepMergeNew(target, source, prefix, log) {
|
|
36
|
+
for (const key of Object.keys(source)) {
|
|
37
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
38
|
+
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
|
|
39
|
+
if (!target[key] || typeof target[key] !== 'object') {
|
|
40
|
+
target[key] = {};
|
|
41
|
+
log.push({ k: fullKey, a: 'new', v: '{}' });
|
|
42
|
+
}
|
|
43
|
+
deepMergeNew(target[key], source[key], fullKey, log);
|
|
44
|
+
} else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
|
|
45
|
+
const added = source[key].filter(v => !target[key].includes(v));
|
|
46
|
+
if (added.length > 0) {
|
|
47
|
+
target[key] = [...target[key], ...added];
|
|
48
|
+
log.push({ k: fullKey, a: 'add', v: `+${added.length}` });
|
|
49
|
+
} else {
|
|
50
|
+
log.push({ k: fullKey, a: 'keep', v: '完整' });
|
|
51
|
+
}
|
|
52
|
+
} else if (key in target) {
|
|
53
|
+
log.push({ k: fullKey, a: 'keep', v: JSON.stringify(target[key]) });
|
|
54
|
+
} else {
|
|
55
|
+
target[key] = source[key];
|
|
56
|
+
log.push({ k: fullKey, a: 'set', v: JSON.stringify(source[key]) });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return target;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function printMergeLog(log, c) {
|
|
63
|
+
log.forEach(({ k, a, v }) => {
|
|
64
|
+
if (a === 'keep') console.log(` ${c.d('·')} ${c.d(`${k} (保留: ${v})`)}`);
|
|
65
|
+
else console.log(` ${c.grn('+')} ${c.cyn(k)} = ${v}`);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 解析 Markdown 文件的 YAML frontmatter
|
|
71
|
+
* @param {string} content - 文件内容
|
|
72
|
+
* @returns {Object|null} 解析后的键值对,无 frontmatter 返回 null
|
|
73
|
+
*/
|
|
74
|
+
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
75
|
+
|
|
76
|
+
function parseFrontmatter(content) {
|
|
77
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
78
|
+
if (!match) return null;
|
|
79
|
+
const meta = Object.create(null);
|
|
80
|
+
match[1].split('\n').forEach(line => {
|
|
81
|
+
const m = line.match(/^([\w][\w-]*)\s*:\s*(.+)/);
|
|
82
|
+
if (m && !UNSAFE_KEYS.has(m[1])) meta[m[1]] = m[2].trim().replace(/^["']|["']$/g, '');
|
|
83
|
+
});
|
|
84
|
+
return meta;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { shouldSkip, copyRecursive, rmSafe, deepMergeNew, printMergeLog, parseFrontmatter, SKIP };
|
package/bin/uninstall.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const targetDir = path.dirname(__filename);
|
|
7
|
+
const backupDir = path.join(targetDir, '.sage-backup');
|
|
8
|
+
const manifestPath = path.join(backupDir, 'manifest.json');
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(manifestPath)) {
|
|
11
|
+
console.error('❌ 未找到安装记录 (manifest.json)');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let manifest;
|
|
16
|
+
try {
|
|
17
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
18
|
+
} catch (e) {
|
|
19
|
+
console.error('❌ manifest.json 解析失败:', e.message);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log(`\n🗑️ 卸载 ccbot-cli v${manifest.version}...\n`);
|
|
24
|
+
|
|
25
|
+
// 1. 删除安装的文件
|
|
26
|
+
(manifest.installed || []).forEach(f => {
|
|
27
|
+
const p = path.join(targetDir, f);
|
|
28
|
+
if (fs.existsSync(p)) {
|
|
29
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
30
|
+
console.log(`🗑️ 删除: ${f}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// 2. 恢复备份
|
|
35
|
+
(manifest.backups || []).forEach(f => {
|
|
36
|
+
const bp = path.join(backupDir, f);
|
|
37
|
+
const tp = path.join(targetDir, f);
|
|
38
|
+
if (fs.existsSync(bp)) {
|
|
39
|
+
fs.renameSync(bp, tp);
|
|
40
|
+
console.log(`✅ 恢复: ${f}`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 3. 清理备份目录和卸载脚本自身
|
|
45
|
+
fs.rmSync(backupDir, { recursive: true, force: true });
|
|
46
|
+
fs.unlinkSync(__filename);
|
|
47
|
+
|
|
48
|
+
console.log('\n✅ 卸载完成\n');
|