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 CHANGED
@@ -4,9 +4,10 @@
4
4
 
5
5
  **邪修红尘仙 · 宿命深渊**
6
6
 
7
- *一键为 Claude Code / Codex CLI 注入邪修人格与 59 篇安全工程秘典*
7
+ *一键为 Claude Code / Codex CLI 注入邪修人格与 56 篇安全工程秘典*
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/code-abyss.svg)](https://www.npmjs.com/package/code-abyss)
10
+ [![CI](https://github.com/telagod/code-abyss/actions/workflows/ci.yml/badge.svg)](https://github.com/telagod/code-abyss/actions/workflows/ci.yml)
10
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
12
  [![Platform](https://img.shields.io/badge/Platform-Linux%20%7C%20macOS%20%7C%20Windows-blue.svg)]()
12
13
  [![Node](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)]()
@@ -24,7 +25,7 @@ npx code-abyss
24
25
  交互式菜单(方向键选择,回车确认):
25
26
 
26
27
  ```
27
- ☠️ Code Abyss v1.6.9
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 领域 59 篇专业秘典
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/ 59 篇秘典
115
+ │ └── abyss-cultivator.md └── skills/ 56 篇秘典
114
116
  ├── settings.json
115
- └── skills/ 59 篇秘典
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 领域 59 篇秘典)
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
- console.log(`\n${c.d('┌' + line + '┐')}\n${c.d('│')} ${c.b(title)}${' '.repeat(Math.max(0, 43 - title.length))}${c.d('│')}\n${c.d('└' + line + '┘')}`);
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) return { type: 'env-custom', detail: process.env.ANTHROPIC_BASE_URL };
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 = { manifest_version: 1, version: VERSION, target: tgt, timestamp: new Date().toISOString(), installed: [], backups: [] };
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') { fail(`核心文件缺失: ${srcPath}\n 请尝试: npm cache clean --force && npx code-abyss`); process.exit(1); }
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 { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (e) { warn(`settings.json 解析失败,将使用空配置`); settings = {}; }
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 postClaude(ctx) {
303
- const { select, checkbox, confirm, input } = await import('@inquirer/prompts');
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
- const log = [];
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
- const log = [];
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
- console.log('');
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
- main().catch(err => { fail(err.message); process.exit(1); });
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 };
@@ -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.0",
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": "echo \"No tests configured yet\""
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: ai
3
3
  description: AI/LLM 能力索引。Agent 开发、LLM 安全、RAG 系统。当用户提到 AI、LLM、Agent、RAG、Prompt 时路由到此。
4
4
  license: MIT
5
+ user-invocable: false
6
+ disable-model-invocation: false
5
7
  ---
6
8
 
7
9
  # 丹鼎秘典 · AI/LLM 能力中枢
@@ -2,6 +2,8 @@
2
2
  name: architecture
3
3
  description: 架构设计能力索引。API设计、安全架构、云原生、数据安全。当用户提到架构、设计、API、云原生时路由到此。
4
4
  license: MIT
5
+ user-invocable: false
6
+ disable-model-invocation: false
5
7
  ---
6
8
 
7
9
  # 🏗 阵法秘典 · 架构设计能力中枢
@@ -2,6 +2,8 @@
2
2
  name: data-engineering
3
3
  description: 数据工程。Airflow、Dagster、Kafka Streams、Flink、dbt、数据管道、流处理、数据质量。当用户提到数据管道、ETL、流处理、数据质量时路由到此。
4
4
  license: MIT
5
+ user-invocable: false
6
+ disable-model-invocation: false
5
7
  ---
6
8
 
7
9
  # 数据工程域 · Data Engineering
@@ -2,6 +2,8 @@
2
2
  name: development
3
3
  description: 开发语言能力索引。Python、Go、Rust、TypeScript、Java、C++、Shell。当用户提到编程、开发、代码、语言时路由到此。
4
4
  license: MIT
5
+ user-invocable: false
6
+ disable-model-invocation: false
5
7
  ---
6
8
 
7
9
  # 符箓秘典 · 开发语言能力中枢
@@ -2,6 +2,8 @@
2
2
  name: devops
3
3
  description: DevOps 能力索引。Git、测试、DevSecOps、数据库。当用户提到 DevOps、CI/CD、Git、测试时路由到此。
4
4
  license: MIT
5
+ user-invocable: false
6
+ disable-model-invocation: false
5
7
  ---
6
8
 
7
9
  # 🔧 炼器秘典 · DevOps 能力中枢
@@ -3,6 +3,7 @@ name: frontend-design
3
3
  description: 前端设计美学秘典。UI美学、组件模式、UX原则。当魔尊需要前端设计、UI/UX指导、组件设计时使用。
4
4
  license: MIT
5
5
  user-invocable: true
6
+ disable-model-invocation: false
6
7
  ---
7
8
 
8
9
  # 🎨 前端设计美学秘典
@@ -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
@@ -2,6 +2,8 @@
2
2
  name: mobile
3
3
  description: 移动开发。iOS、Android、SwiftUI、Jetpack Compose、React Native、Flutter、跨平台。当用户提到移动开发、iOS、Android、跨平台时路由到此。
4
4
  license: MIT
5
+ user-invocable: false
6
+ disable-model-invocation: false
5
7
  ---
6
8
 
7
9
  # 移动开发域 · Mobile Development
@@ -2,7 +2,8 @@
2
2
  name: orchestration
3
3
  description: 协同编排知识域。多Agent协同、任务分解、并行执行、冲突解决。当魔尊需要多Agent协作、任务编排、并行处理时使用。
4
4
  license: MIT
5
- user-invocable: true
5
+ user-invocable: false
6
+ disable-model-invocation: false
6
7
  ---
7
8
 
8
9
  # 🕸 协同编排秘典
@@ -2,6 +2,8 @@
2
2
  name: security
3
3
  description: 攻防秘典索引。渗透测试、代码审计、红队攻击、蓝队防御、威胁情报、漏洞研究。当魔尊提到安全、渗透、攻防、红队、蓝队、漏洞时路由到此。
4
4
  license: MIT
5
+ user-invocable: false
6
+ disable-model-invocation: false
5
7
  ---
6
8
 
7
9
  # 攻防秘典 · 三脉道统