code-abyss 1.7.0 → 1.7.2
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 +8 -6
- package/bin/install.js +59 -163
- package/bin/lib/ccline.js +82 -0
- package/bin/lib/utils.js +61 -0
- package/package.json +5 -2
- package/skills/domains/ai/SKILL.md +2 -0
- package/skills/domains/architecture/SKILL.md +2 -0
- package/skills/domains/data-engineering/SKILL.md +2 -0
- package/skills/domains/development/SKILL.md +2 -0
- package/skills/domains/devops/SKILL.md +2 -0
- package/skills/domains/frontend-design/SKILL.md +1 -0
- package/skills/domains/frontend-design/claymorphism/SKILL.md +2 -0
- package/skills/domains/frontend-design/glassmorphism/SKILL.md +2 -0
- package/skills/domains/frontend-design/liquid-glass/SKILL.md +2 -0
- package/skills/domains/frontend-design/neubrutalism/SKILL.md +2 -0
- package/skills/domains/infrastructure/SKILL.md +2 -0
- package/skills/domains/mobile/SKILL.md +2 -0
- package/skills/domains/orchestration/SKILL.md +2 -1
- package/skills/domains/security/SKILL.md +2 -0
- package/skills/orchestration/multi-agent/SKILL.md +2 -0
- package/skills/run_skill.js +14 -9
- package/skills/tools/gen-docs/scripts/doc_generator.js +21 -7
- package/skills/tools/lib/shared.js +98 -0
- package/skills/tools/verify-change/scripts/change_analyzer.js +73 -54
- package/skills/tools/verify-module/scripts/module_scanner.js +63 -37
- package/skills/tools/verify-quality/scripts/quality_checker.js +134 -73
- package/skills/tools/verify-security/scripts/security_scanner.js +212 -62
package/README.md
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
**邪修红尘仙 · 宿命深渊**
|
|
6
6
|
|
|
7
|
-
*一键为 Claude Code / Codex CLI 注入邪修人格与
|
|
7
|
+
*一键为 Claude Code / Codex CLI 注入邪修人格与 56 篇安全工程秘典*
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/code-abyss)
|
|
10
|
+
[](https://github.com/telagod/code-abyss/actions/workflows/ci.yml)
|
|
10
11
|
[](https://opensource.org/licenses/MIT)
|
|
11
12
|
[]()
|
|
12
13
|
[]()
|
|
@@ -24,7 +25,7 @@ npx code-abyss
|
|
|
24
25
|
交互式菜单(方向键选择,回车确认):
|
|
25
26
|
|
|
26
27
|
```
|
|
27
|
-
☠️ Code Abyss v1.
|
|
28
|
+
☠️ Code Abyss v1.7.2
|
|
28
29
|
|
|
29
30
|
? 请选择操作 (Use arrow keys)
|
|
30
31
|
❯ 安装到 Claude Code (~/.claude/)
|
|
@@ -98,8 +99,9 @@ node ~/.codex/.sage-uninstall.js # Codex CLI
|
|
|
98
99
|
Code Abyss 是一套 **Claude Code / Codex CLI 个性化配置包**,一条命令注入:
|
|
99
100
|
|
|
100
101
|
- 🔥 **邪修人格** — 宿命压迫叙事 + 道语标签 + 渡劫协议
|
|
101
|
-
- ⚔️ **安全工程知识体系** — 红队/蓝队/紫队三脉道统,11 领域
|
|
102
|
+
- ⚔️ **安全工程知识体系** — 红队/蓝队/紫队三脉道统,11 领域 56 篇专业秘典
|
|
102
103
|
- ⚖️ **5 个校验关卡** — 安全扫描、模块完整性、变更分析、代码质量、文档生成
|
|
104
|
+
- ✅ **66 单元测试** — Jest 框架,GitHub Actions CI (Node 18/20/22)
|
|
103
105
|
- ⚡ **三级授权** — T1/T2/T3 分级,零确认直接执行
|
|
104
106
|
|
|
105
107
|
---
|
|
@@ -110,9 +112,9 @@ Code Abyss 是一套 **Claude Code / Codex CLI 个性化配置包**,一条命
|
|
|
110
112
|
~/.claude/(Claude Code) ~/.codex/(Codex CLI)
|
|
111
113
|
├── CLAUDE.md 道典 ├── AGENTS.md 道典+风格
|
|
112
114
|
├── output-styles/ 输出风格 ├── settings.json
|
|
113
|
-
│ └── abyss-cultivator.md └── skills/
|
|
115
|
+
│ └── abyss-cultivator.md └── skills/ 56 篇秘典
|
|
114
116
|
├── settings.json
|
|
115
|
-
└── skills/
|
|
117
|
+
└── skills/ 56 篇秘典
|
|
116
118
|
|
|
117
119
|
可选:
|
|
118
120
|
├── ccline/ 状态栏 (npm install -g @cometix/ccline)
|
|
@@ -121,7 +123,7 @@ Code Abyss 是一套 **Claude Code / Codex CLI 个性化配置包**,一条命
|
|
|
121
123
|
|
|
122
124
|
---
|
|
123
125
|
|
|
124
|
-
## 🛠️ 内置 Skills(11 领域
|
|
126
|
+
## 🛠️ 内置 Skills(11 领域 56 篇秘典)
|
|
125
127
|
|
|
126
128
|
### 校验关卡(`/` 直接调用)
|
|
127
129
|
|
package/bin/install.js
CHANGED
|
@@ -14,8 +14,10 @@ if (parseInt(process.versions.node) < parseInt(MIN_NODE)) {
|
|
|
14
14
|
console.error(`\x1b[31m✘ 需要 Node.js >= ${MIN_NODE},当前: ${process.versions.node}\x1b[0m`);
|
|
15
15
|
process.exit(1);
|
|
16
16
|
}
|
|
17
|
-
const SKIP = ['__pycache__', '.pyc', '.pyo', '.egg-info', '.DS_Store', 'Thumbs.db', '.git'];
|
|
18
17
|
const PKG_ROOT = fs.realpathSync(path.join(__dirname, '..'));
|
|
18
|
+
const { shouldSkip, copyRecursive, rmSafe, deepMergeNew, printMergeLog } =
|
|
19
|
+
require(path.join(__dirname, 'lib', 'utils.js'));
|
|
20
|
+
const { detectCclineBin, installCcline: _installCcline } = require(path.join(__dirname, 'lib', 'ccline.js'));
|
|
19
21
|
|
|
20
22
|
// ── ANSI ──
|
|
21
23
|
|
|
@@ -49,7 +51,10 @@ function banner() {
|
|
|
49
51
|
|
|
50
52
|
function divider(title) {
|
|
51
53
|
const line = '─'.repeat(44);
|
|
52
|
-
|
|
54
|
+
const pad = ' '.repeat(Math.max(0, 43 - title.length));
|
|
55
|
+
console.log(`\n${c.d('┌' + line + '┐')}`);
|
|
56
|
+
console.log(`${c.d('│')} ${c.b(title)}${pad}${c.d('│')}`);
|
|
57
|
+
console.log(`${c.d('└' + line + '┘')}`);
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
function step(n, total, msg) { console.log(`\n ${c.cyn(`[${n}/${total}]`)} ${c.b(msg)}`); }
|
|
@@ -58,69 +63,15 @@ function warn(msg) { console.log(` ${c.ylw('⚠')} ${msg}`); }
|
|
|
58
63
|
function info(msg) { console.log(` ${c.blu('ℹ')} ${msg}`); }
|
|
59
64
|
function fail(msg) { console.log(` ${c.red('✘')} ${msg}`); }
|
|
60
65
|
|
|
61
|
-
// ── 工具 ──
|
|
62
|
-
|
|
63
|
-
function shouldSkip(name) { return SKIP.some(p => name.includes(p)); }
|
|
64
|
-
|
|
65
|
-
function copyRecursive(src, dest) {
|
|
66
|
-
const stat = fs.statSync(src);
|
|
67
|
-
if (stat.isDirectory()) {
|
|
68
|
-
if (shouldSkip(path.basename(src))) return;
|
|
69
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
70
|
-
fs.readdirSync(src).forEach(f => {
|
|
71
|
-
if (!shouldSkip(f)) copyRecursive(path.join(src, f), path.join(dest, f));
|
|
72
|
-
});
|
|
73
|
-
} else {
|
|
74
|
-
if (shouldSkip(path.basename(src))) return;
|
|
75
|
-
fs.copyFileSync(src, dest);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function rmSafe(p) {
|
|
80
|
-
if (fs.existsSync(p)) fs.rmSync(p, { recursive: true, force: true });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function deepMergeNew(target, source, prefix, log) {
|
|
84
|
-
for (const key of Object.keys(source)) {
|
|
85
|
-
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
86
|
-
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
|
|
87
|
-
if (!target[key] || typeof target[key] !== 'object') {
|
|
88
|
-
target[key] = {};
|
|
89
|
-
log.push({ k: fullKey, a: 'new', v: '{}' });
|
|
90
|
-
}
|
|
91
|
-
deepMergeNew(target[key], source[key], fullKey, log);
|
|
92
|
-
} else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
|
|
93
|
-
const added = source[key].filter(v => !target[key].includes(v));
|
|
94
|
-
if (added.length > 0) {
|
|
95
|
-
target[key] = [...target[key], ...added];
|
|
96
|
-
log.push({ k: fullKey, a: 'add', v: `+${added.length}` });
|
|
97
|
-
} else {
|
|
98
|
-
log.push({ k: fullKey, a: 'keep', v: '完整' });
|
|
99
|
-
}
|
|
100
|
-
} else if (key in target) {
|
|
101
|
-
log.push({ k: fullKey, a: 'keep', v: JSON.stringify(target[key]) });
|
|
102
|
-
} else {
|
|
103
|
-
target[key] = source[key];
|
|
104
|
-
log.push({ k: fullKey, a: 'set', v: JSON.stringify(source[key]) });
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return target;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function printMergeLog(log) {
|
|
111
|
-
log.forEach(({ k, a, v }) => {
|
|
112
|
-
if (a === 'keep') console.log(` ${c.d('·')} ${c.d(`${k} (保留: ${v})`)}`);
|
|
113
|
-
else console.log(` ${c.grn('+')} ${c.cyn(k)} = ${v}`);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
66
|
// ── 认证 ──
|
|
118
67
|
|
|
119
68
|
function detectClaudeAuth(settings) {
|
|
120
69
|
const env = settings.env || {};
|
|
121
70
|
if (env.ANTHROPIC_BASE_URL && env.ANTHROPIC_AUTH_TOKEN) return { type: 'custom', detail: env.ANTHROPIC_BASE_URL };
|
|
122
71
|
if (process.env.ANTHROPIC_API_KEY) return { type: 'env', detail: 'ANTHROPIC_API_KEY' };
|
|
123
|
-
if (process.env.ANTHROPIC_BASE_URL && process.env.ANTHROPIC_AUTH_TOKEN)
|
|
72
|
+
if (process.env.ANTHROPIC_BASE_URL && process.env.ANTHROPIC_AUTH_TOKEN) {
|
|
73
|
+
return { type: 'env-custom', detail: process.env.ANTHROPIC_BASE_URL };
|
|
74
|
+
}
|
|
124
75
|
const cred = path.join(HOME, '.claude', '.credentials.json');
|
|
125
76
|
if (fs.existsSync(cred)) {
|
|
126
77
|
try {
|
|
@@ -257,13 +208,19 @@ function installCore(tgt) {
|
|
|
257
208
|
{ src: 'skills', dest: 'skills' }
|
|
258
209
|
].filter(f => f.dest !== null);
|
|
259
210
|
|
|
260
|
-
const manifest = {
|
|
211
|
+
const manifest = {
|
|
212
|
+
manifest_version: 1, version: VERSION, target: tgt,
|
|
213
|
+
timestamp: new Date().toISOString(), installed: [], backups: []
|
|
214
|
+
};
|
|
261
215
|
|
|
262
216
|
filesToInstall.forEach(({ src, dest }) => {
|
|
263
217
|
const srcPath = path.join(PKG_ROOT, src);
|
|
264
218
|
const destPath = path.join(targetDir, dest);
|
|
265
219
|
if (!fs.existsSync(srcPath)) {
|
|
266
|
-
if (src === 'skills') {
|
|
220
|
+
if (src === 'skills') {
|
|
221
|
+
fail(`核心文件缺失: ${srcPath}\n 请尝试: npm cache clean --force && npx code-abyss`);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
267
224
|
warn(`跳过: ${src}`); return;
|
|
268
225
|
}
|
|
269
226
|
if (fs.existsSync(destPath)) {
|
|
@@ -278,7 +235,12 @@ function installCore(tgt) {
|
|
|
278
235
|
const settingsPath = path.join(targetDir, 'settings.json');
|
|
279
236
|
let settings = {};
|
|
280
237
|
if (fs.existsSync(settingsPath)) {
|
|
281
|
-
try {
|
|
238
|
+
try {
|
|
239
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
240
|
+
} catch (e) {
|
|
241
|
+
warn(`settings.json 解析失败,将使用空配置`);
|
|
242
|
+
settings = {};
|
|
243
|
+
}
|
|
282
244
|
fs.copyFileSync(settingsPath, path.join(backupDir, 'settings.json'));
|
|
283
245
|
manifest.backups.push('settings.json');
|
|
284
246
|
}
|
|
@@ -299,9 +261,28 @@ function installCore(tgt) {
|
|
|
299
261
|
|
|
300
262
|
// ── Claude 后续 ──
|
|
301
263
|
|
|
302
|
-
async function
|
|
303
|
-
const {
|
|
264
|
+
async function configureCustomProvider(ctx) {
|
|
265
|
+
const { confirm, input } = await import('@inquirer/prompts');
|
|
266
|
+
const doCfg = await confirm({ message: '配置自定义 provider?', default: false });
|
|
267
|
+
if (!doCfg) return;
|
|
268
|
+
if (!ctx.settings.env) ctx.settings.env = {};
|
|
269
|
+
const url = await input({ message: 'ANTHROPIC_BASE_URL:' });
|
|
270
|
+
const token = await input({ message: 'ANTHROPIC_AUTH_TOKEN:' });
|
|
271
|
+
if (url) ctx.settings.env.ANTHROPIC_BASE_URL = url;
|
|
272
|
+
if (token) ctx.settings.env.ANTHROPIC_AUTH_TOKEN = token;
|
|
273
|
+
fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
|
|
274
|
+
ok('provider 已配置');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function mergeSettings(ctx) {
|
|
278
|
+
const log = [];
|
|
279
|
+
deepMergeNew(ctx.settings, SETTINGS_TEMPLATE, '', log);
|
|
280
|
+
printMergeLog(log, c);
|
|
281
|
+
fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
|
|
282
|
+
ok('settings.json 合并完成');
|
|
283
|
+
}
|
|
304
284
|
|
|
285
|
+
async function postClaude(ctx) {
|
|
305
286
|
step(2, 3, '认证检测');
|
|
306
287
|
const auth = detectClaudeAuth(ctx.settings);
|
|
307
288
|
if (auth) {
|
|
@@ -309,32 +290,18 @@ async function postClaude(ctx) {
|
|
|
309
290
|
} else {
|
|
310
291
|
warn('未检测到 API 认证');
|
|
311
292
|
info(`支持: ${c.cyn('claude login')} | ${c.cyn('ANTHROPIC_API_KEY')} | ${c.cyn('自定义 provider')}`);
|
|
312
|
-
if (!autoYes)
|
|
313
|
-
const doCfg = await confirm({ message: '配置自定义 provider?', default: false });
|
|
314
|
-
if (doCfg) {
|
|
315
|
-
if (!ctx.settings.env) ctx.settings.env = {};
|
|
316
|
-
const url = await input({ message: 'ANTHROPIC_BASE_URL:' });
|
|
317
|
-
const token = await input({ message: 'ANTHROPIC_AUTH_TOKEN:' });
|
|
318
|
-
if (url) ctx.settings.env.ANTHROPIC_BASE_URL = url;
|
|
319
|
-
if (token) ctx.settings.env.ANTHROPIC_AUTH_TOKEN = token;
|
|
320
|
-
fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
|
|
321
|
-
ok('provider 已配置');
|
|
322
|
-
}
|
|
323
|
-
}
|
|
293
|
+
if (!autoYes) await configureCustomProvider(ctx);
|
|
324
294
|
}
|
|
325
295
|
|
|
326
296
|
step(3, 3, '可选配置');
|
|
327
297
|
if (autoYes) {
|
|
328
298
|
info('自动模式: 合并推荐配置');
|
|
329
|
-
|
|
330
|
-
deepMergeNew(ctx.settings, SETTINGS_TEMPLATE, '', log);
|
|
331
|
-
printMergeLog(log);
|
|
332
|
-
fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
|
|
333
|
-
ok('settings.json 合并完成');
|
|
299
|
+
mergeSettings(ctx);
|
|
334
300
|
await installCcline(ctx);
|
|
335
301
|
return;
|
|
336
302
|
}
|
|
337
303
|
|
|
304
|
+
const { checkbox } = await import('@inquirer/prompts');
|
|
338
305
|
const choices = await checkbox({
|
|
339
306
|
message: '选择要安装的配置 (空格选择, 回车确认)',
|
|
340
307
|
choices: [
|
|
@@ -343,90 +310,12 @@ async function postClaude(ctx) {
|
|
|
343
310
|
],
|
|
344
311
|
});
|
|
345
312
|
|
|
346
|
-
if (choices.includes('settings'))
|
|
347
|
-
|
|
348
|
-
deepMergeNew(ctx.settings, SETTINGS_TEMPLATE, '', log);
|
|
349
|
-
printMergeLog(log);
|
|
350
|
-
fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
|
|
351
|
-
ok('settings.json 合并完成');
|
|
352
|
-
}
|
|
353
|
-
if (choices.includes('ccline')) {
|
|
354
|
-
await installCcline(ctx);
|
|
355
|
-
}
|
|
313
|
+
if (choices.includes('settings')) mergeSettings(ctx);
|
|
314
|
+
if (choices.includes('ccline')) await installCcline(ctx);
|
|
356
315
|
}
|
|
357
316
|
|
|
358
317
|
async function installCcline(ctx) {
|
|
359
|
-
|
|
360
|
-
info('安装 ccline 状态栏...');
|
|
361
|
-
const { execSync } = require('child_process');
|
|
362
|
-
const cclineDir = path.join(HOME, '.claude', 'ccline');
|
|
363
|
-
const cclineBin = path.join(cclineDir, process.platform === 'win32' ? 'ccline.exe' : 'ccline');
|
|
364
|
-
const errors = [];
|
|
365
|
-
|
|
366
|
-
// 1. 检测是否已有二进制
|
|
367
|
-
let hasBin = fs.existsSync(cclineBin);
|
|
368
|
-
if (!hasBin) {
|
|
369
|
-
try { execSync('ccline --version', { stdio: 'pipe' }); hasBin = true; } catch (e) {}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// 2. 未安装则通过 npm 安装(postinstall 自动下载原生二进制)
|
|
373
|
-
if (!hasBin) {
|
|
374
|
-
info('ccline 未检测到,正在安装...');
|
|
375
|
-
try {
|
|
376
|
-
execSync('npm install -g @cometix/ccline', { stdio: 'inherit' });
|
|
377
|
-
hasBin = fs.existsSync(cclineBin);
|
|
378
|
-
if (hasBin) ok('ccline 二进制安装成功');
|
|
379
|
-
else {
|
|
380
|
-
try { execSync('ccline --version', { stdio: 'pipe' }); hasBin = true; ok('ccline 安装成功 (全局)'); } catch (e) {}
|
|
381
|
-
}
|
|
382
|
-
if (!hasBin) errors.push('ccline 二进制安装后仍未检测到');
|
|
383
|
-
} catch (e) {
|
|
384
|
-
errors.push(`npm install -g @cometix/ccline 失败: ${e.message}`);
|
|
385
|
-
info(`手动安装: ${c.cyn('npm install -g @cometix/ccline')}`);
|
|
386
|
-
info(`或下载: ${c.cyn('https://github.com/Haleclipse/CCometixLine/releases')}`);
|
|
387
|
-
}
|
|
388
|
-
} else {
|
|
389
|
-
ok('ccline 二进制已存在');
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// 3. 部署打包的 config.toml(覆盖默认配置)
|
|
393
|
-
const bundledConfig = path.join(PKG_ROOT, 'config', 'ccline', 'config.toml');
|
|
394
|
-
const targetConfig = path.join(cclineDir, 'config.toml');
|
|
395
|
-
if (fs.existsSync(bundledConfig)) {
|
|
396
|
-
fs.mkdirSync(cclineDir, { recursive: true });
|
|
397
|
-
if (fs.existsSync(targetConfig)) {
|
|
398
|
-
info(`备份: ${c.d('ccline/config.toml')}`);
|
|
399
|
-
const backupDir = path.join(HOME, '.claude', '.sage-backup');
|
|
400
|
-
fs.mkdirSync(backupDir, { recursive: true });
|
|
401
|
-
fs.copyFileSync(targetConfig, path.join(backupDir, 'ccline-config.toml'));
|
|
402
|
-
}
|
|
403
|
-
fs.copyFileSync(bundledConfig, targetConfig);
|
|
404
|
-
ok('ccline/config.toml 已部署 (Code Abyss 定制版)');
|
|
405
|
-
} else {
|
|
406
|
-
// 无打包配置,回退到 ccline --init
|
|
407
|
-
if (hasBin && !fs.existsSync(targetConfig)) {
|
|
408
|
-
try { execSync('ccline --init', { stdio: 'inherit' }); ok('ccline 默认配置已生成'); }
|
|
409
|
-
catch (e) { errors.push(`ccline --init 失败: ${e.message}`); }
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// 4. 合并 statusLine 到 settings.json
|
|
414
|
-
ctx.settings.statusLine = CCLINE_STATUS_LINE.statusLine;
|
|
415
|
-
ok(`statusLine → ${c.cyn(CCLINE_STATUS_LINE.statusLine.command)}`);
|
|
416
|
-
fs.writeFileSync(ctx.settingsPath, JSON.stringify(ctx.settings, null, 2) + '\n');
|
|
417
|
-
|
|
418
|
-
// 5. 汇总报告
|
|
419
|
-
if (errors.length > 0) {
|
|
420
|
-
console.log('');
|
|
421
|
-
warn(c.b(`ccline 安装有 ${errors.length} 个问题:`));
|
|
422
|
-
errors.forEach(e => fail(` ${e}`));
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
console.log('');
|
|
426
|
-
warn(`需要 ${c.b('Nerd Font')} 字体才能正确显示图标`);
|
|
427
|
-
info(`推荐: FiraCode Nerd Font / JetBrainsMono Nerd Font`);
|
|
428
|
-
info(`下载: ${c.cyn('https://www.nerdfonts.com/')}`);
|
|
429
|
-
ok('ccline 配置完成');
|
|
318
|
+
await _installCcline(ctx, { HOME, PKG_ROOT, CCLINE_STATUS_LINE, ok, warn, info, fail, c });
|
|
430
319
|
}
|
|
431
320
|
|
|
432
321
|
// ── Codex 后续 ──
|
|
@@ -531,4 +420,11 @@ function finish(ctx) {
|
|
|
531
420
|
console.log(c.mag(` ⚚ 劫——破——了——!!!\n`));
|
|
532
421
|
}
|
|
533
422
|
|
|
534
|
-
|
|
423
|
+
if (require.main === module) {
|
|
424
|
+
main().catch(err => { fail(err.message); process.exit(1); });
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
module.exports = {
|
|
428
|
+
deepMergeNew, detectClaudeAuth, detectCodexAuth,
|
|
429
|
+
detectCclineBin, copyRecursive, shouldSkip, SETTINGS_TEMPLATE
|
|
430
|
+
};
|
|
@@ -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 已部署 (Code Abyss 定制版)');
|
|
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
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
const stat = fs.statSync(src);
|
|
11
|
+
if (stat.isDirectory()) {
|
|
12
|
+
if (shouldSkip(path.basename(src))) return;
|
|
13
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
14
|
+
fs.readdirSync(src).forEach(f => {
|
|
15
|
+
if (!shouldSkip(f)) copyRecursive(path.join(src, f), path.join(dest, f));
|
|
16
|
+
});
|
|
17
|
+
} else {
|
|
18
|
+
if (shouldSkip(path.basename(src))) return;
|
|
19
|
+
fs.copyFileSync(src, dest);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function rmSafe(p) {
|
|
24
|
+
if (fs.existsSync(p)) fs.rmSync(p, { recursive: true, force: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function deepMergeNew(target, source, prefix, log) {
|
|
28
|
+
for (const key of Object.keys(source)) {
|
|
29
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
30
|
+
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
|
|
31
|
+
if (!target[key] || typeof target[key] !== 'object') {
|
|
32
|
+
target[key] = {};
|
|
33
|
+
log.push({ k: fullKey, a: 'new', v: '{}' });
|
|
34
|
+
}
|
|
35
|
+
deepMergeNew(target[key], source[key], fullKey, log);
|
|
36
|
+
} else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
|
|
37
|
+
const added = source[key].filter(v => !target[key].includes(v));
|
|
38
|
+
if (added.length > 0) {
|
|
39
|
+
target[key] = [...target[key], ...added];
|
|
40
|
+
log.push({ k: fullKey, a: 'add', v: `+${added.length}` });
|
|
41
|
+
} else {
|
|
42
|
+
log.push({ k: fullKey, a: 'keep', v: '完整' });
|
|
43
|
+
}
|
|
44
|
+
} else if (key in target) {
|
|
45
|
+
log.push({ k: fullKey, a: 'keep', v: JSON.stringify(target[key]) });
|
|
46
|
+
} else {
|
|
47
|
+
target[key] = source[key];
|
|
48
|
+
log.push({ k: fullKey, a: 'set', v: JSON.stringify(source[key]) });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return target;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function printMergeLog(log, c) {
|
|
55
|
+
log.forEach(({ k, a, v }) => {
|
|
56
|
+
if (a === 'keep') console.log(` ${c.d('·')} ${c.d(`${k} (保留: ${v})`)}`);
|
|
57
|
+
else console.log(` ${c.grn('+')} ${c.cyn(k)} = ${v}`);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = { shouldSkip, copyRecursive, rmSafe, deepMergeNew, printMergeLog, SKIP };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-abyss",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "邪修红尘仙·宿命深渊 - 一键为 Claude Code / Codex CLI 注入邪修人格与安全工程知识体系",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -36,9 +36,12 @@
|
|
|
36
36
|
"node": ">=18.0.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
-
"test": "
|
|
39
|
+
"test": "jest"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@inquirer/prompts": "^7.10.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"jest": "^30.2.0"
|
|
43
46
|
}
|
|
44
47
|
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
name: claymorphism
|
|
3
3
|
description: Claymorphism design system skill. Use when building soft, puffy, clay-like UI components with large radii, dual inner shadows, and offset outer shadows.
|
|
4
4
|
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Claymorphism Design Spec
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
name: glassmorphism
|
|
3
3
|
description: Glassmorphism design system skill. Use when building frosted-glass UI components with blur, transparency, and layered depth effects.
|
|
4
4
|
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Glassmorphism Design Spec
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
name: liquid-glass
|
|
3
3
|
description: Apple Liquid Glass design system. Use when building UI with translucent, depth-aware glass morphism following Apple's design language. Provides CSS tokens, component patterns, dark/light mode, and animation specs.
|
|
4
4
|
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Liquid Glass Design System
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
name: neubrutalism
|
|
3
3
|
description: Neubrutalism design system skill. Use when building bold UI with thick borders, offset solid shadows, high saturation colors, and minimal border radius.
|
|
4
4
|
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Neubrutalism Design Spec
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
name: infrastructure
|
|
3
3
|
description: 云原生基础设施。Kubernetes、Helm、Kustomize、Operator、CRD、GitOps、ArgoCD、Flux、IaC、Terraform、Pulumi、CDK。当用户提到 K8s、Helm、GitOps、IaC 时路由到此。
|
|
4
4
|
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# 云原生基础设施 · Infrastructure
|